- 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:
brendan%mozilla.org 1999-09-21 00:13:48 +00:00
Родитель 2d9d8238ec
Коммит 4ec954edb0
20 изменённых файлов: 935 добавлений и 396 удалений

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

@ -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_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_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_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; cx->globalObject = obj;
#if JS_HAS_UNDEFINED #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.) * (proposed ECMA v2.)
*/ */
if (!OBJ_DEFINE_PROPERTY(cx, obj, if (!OBJ_DEFINE_PROPERTY(cx, obj,
@ -1515,7 +1516,6 @@ JS_DefineProperties(JSContext *cx, JSObject *obj, JSPropertySpec *ps)
if (OBJ_IS_NATIVE(obj)) { if (OBJ_IS_NATIVE(obj)) {
sprop = (JSScopeProperty *)prop; sprop = (JSScopeProperty *)prop;
sprop->id = INT_TO_JSVAL(ps->tinyid); sprop->id = INT_TO_JSVAL(ps->tinyid);
sprop->attrs |= JSPROP_TINYIDHACK;
} }
OBJ_DROP_PROPERTY(cx, obj, prop); OBJ_DROP_PROPERTY(cx, obj, prop);
} }
@ -1547,7 +1547,6 @@ JS_DefinePropertyWithTinyId(JSContext *cx, JSObject *obj, const char *name,
if (OBJ_IS_NATIVE(obj)) { if (OBJ_IS_NATIVE(obj)) {
sprop = (JSScopeProperty *)prop; sprop = (JSScopeProperty *)prop;
sprop->id = INT_TO_JSVAL(tinyid); sprop->id = INT_TO_JSVAL(tinyid);
sprop->attrs |= JSPROP_TINYIDHACK;
} }
OBJ_DROP_PROPERTY(cx, obj, prop); OBJ_DROP_PROPERTY(cx, obj, prop);
} }
@ -1819,7 +1818,6 @@ JS_DefineUCPropertyWithTinyId(JSContext *cx, JSObject *obj,
if (OBJ_IS_NATIVE(obj)) { if (OBJ_IS_NATIVE(obj)) {
sprop = (JSScopeProperty *)prop; sprop = (JSScopeProperty *)prop;
sprop->id = INT_TO_JSVAL(tinyid); sprop->id = INT_TO_JSVAL(tinyid);
sprop->attrs |= JSPROP_TINYIDHACK;
} }
OBJ_DROP_PROPERTY(cx, obj, prop); OBJ_DROP_PROPERTY(cx, obj, prop);
} }
@ -2488,7 +2486,9 @@ JS_DecompileScript(JSContext *cx, JSScript *script, const char *name,
JSString *str; JSString *str;
CHECK_REQUEST(cx); 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) if (!jp)
return NULL; return NULL;
if (js_DecompileScript(jp, script)) if (js_DecompileScript(jp, script))
@ -2506,10 +2506,12 @@ JS_DecompileFunction(JSContext *cx, JSFunction *fun, uintN indent)
JSString *str; JSString *str;
CHECK_REQUEST(cx); 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) if (!jp)
return NULL; return NULL;
if (js_DecompileFunction(jp, fun, JS_TRUE)) if (js_DecompileFunction(jp, fun))
str = js_GetPrinterOutput(jp); str = js_GetPrinterOutput(jp);
else else
str = NULL; str = NULL;
@ -2524,10 +2526,12 @@ JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, uintN indent)
JSString *str; JSString *str;
CHECK_REQUEST(cx); 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) if (!jp)
return NULL; return NULL;
if (js_DecompileFunctionBody(jp, fun, JS_TRUE)) if (js_DecompileFunctionBody(jp, fun))
str = js_GetPrinterOutput(jp); str = js_GetPrinterOutput(jp);
else else
str = NULL; str = NULL;

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

@ -95,14 +95,16 @@ JS_BEGIN_EXTERN_C
#define JSPROP_READONLY 0x02 /* not settable: assignment is no-op */ #define JSPROP_READONLY 0x02 /* not settable: assignment is no-op */
#define JSPROP_PERMANENT 0x04 /* property cannot be deleted */ #define JSPROP_PERMANENT 0x04 /* property cannot be deleted */
#define JSPROP_EXPORTED 0x08 /* property is exported from object */ #define JSPROP_EXPORTED 0x08 /* property is exported from object */
#define JSPROP_INDEX 0x20 /* name is actually (jsint) index */ #define JSPROP_GETTER 0x10 /* property holds getter function */
#define JSPROP_ASSIGNHACK 0x40 /* property set by its assign method */ #define JSPROP_SETTER 0x20 /* property holds setter function */
#define JSPROP_TINYIDHACK 0x80 /* prop->id is tinyid, not index */ #define JSPROP_INDEX 0x80 /* name is actually (jsint) index */
/* Function flags, set in JSFunctionSpec and passed to JS_NewFunction etc. */ /* 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_BOUND_METHOD 0x40 /* bind this to fun->object's parent */
#define JSFUN_GLOBAL_PARENT 0x80 /* reparent calls to cx->globalObject */ #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 * 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, JS_DecompileScript(JSContext *cx, JSScript *script, const char *name,
uintN indent); 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 *) extern JS_PUBLIC_API(JSString *)
JS_DecompileFunction(JSContext *cx, JSFunction *fun, uintN indent); 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_constructor_str[] = "constructor";
char js_count_str[] = "__count__"; char js_count_str[] = "__count__";
char js_eval_str[] = "eval"; char js_eval_str[] = "eval";
char js_getter_str[] = "getter";
char js_index_str[] = "index"; char js_index_str[] = "index";
char js_input_str[] = "input"; char js_input_str[] = "input";
char js_length_str[] = "length"; char js_length_str[] = "length";
char js_name_str[] = "name"; char js_name_str[] = "name";
char js_parent_str[] = "__parent__"; char js_parent_str[] = "__parent__";
char js_proto_str[] = "__proto__"; char js_proto_str[] = "__proto__";
char js_setter_str[] = "setter";
char js_toSource_str[] = "toSource"; char js_toSource_str[] = "toSource";
char js_toString_str[] = "toString"; char js_toString_str[] = "toString";
char js_valueOf_str[] = "valueOf"; char js_valueOf_str[] = "valueOf";
@ -228,12 +230,14 @@ js_InitAtomState(JSContext *cx, JSAtomState *state)
FROB(classPrototypeAtom, js_class_prototype_str); FROB(classPrototypeAtom, js_class_prototype_str);
FROB(constructorAtom, js_constructor_str); FROB(constructorAtom, js_constructor_str);
FROB(countAtom, js_count_str); FROB(countAtom, js_count_str);
FROB(getterAtom, js_getter_str);
FROB(indexAtom, js_index_str); FROB(indexAtom, js_index_str);
FROB(inputAtom, js_input_str); FROB(inputAtom, js_input_str);
FROB(lengthAtom, js_length_str); FROB(lengthAtom, js_length_str);
FROB(nameAtom, js_name_str); FROB(nameAtom, js_name_str);
FROB(parentAtom, js_parent_str); FROB(parentAtom, js_parent_str);
FROB(protoAtom, js_proto_str); FROB(protoAtom, js_proto_str);
FROB(setterAtom, js_setter_str);
FROB(toSourceAtom, js_toSource_str); FROB(toSourceAtom, js_toSource_str);
FROB(toStringAtom, js_toString_str); FROB(toStringAtom, js_toString_str);
FROB(valueOfAtom, js_valueOf_str); FROB(valueOfAtom, js_valueOf_str);

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

@ -115,12 +115,14 @@ struct JSAtomState {
JSAtom *classPrototypeAtom; JSAtom *classPrototypeAtom;
JSAtom *constructorAtom; JSAtom *constructorAtom;
JSAtom *countAtom; JSAtom *countAtom;
JSAtom *getterAtom;
JSAtom *indexAtom; JSAtom *indexAtom;
JSAtom *inputAtom; JSAtom *inputAtom;
JSAtom *lengthAtom; JSAtom *lengthAtom;
JSAtom *nameAtom; JSAtom *nameAtom;
JSAtom *parentAtom; JSAtom *parentAtom;
JSAtom *protoAtom; JSAtom *protoAtom;
JSAtom *setterAtom;
JSAtom *toSourceAtom; JSAtom *toSourceAtom;
JSAtom *toStringAtom; JSAtom *toStringAtom;
JSAtom *valueOfAtom; JSAtom *valueOfAtom;
@ -149,12 +151,14 @@ extern char js_class_prototype_str[];
extern char js_constructor_str[]; extern char js_constructor_str[];
extern char js_count_str[]; extern char js_count_str[];
extern char js_eval_str[]; extern char js_eval_str[];
extern char js_getter_str[];
extern char js_index_str[]; extern char js_index_str[];
extern char js_input_str[]; extern char js_input_str[];
extern char js_length_str[]; extern char js_length_str[];
extern char js_name_str[]; extern char js_name_str[];
extern char js_parent_str[]; extern char js_parent_str[];
extern char js_proto_str[]; extern char js_proto_str[];
extern char js_setter_str[];
extern char js_toSource_str[]; extern char js_toSource_str[];
extern char js_toString_str[]; extern char js_toString_str[];
extern char js_valueOf_str[]; extern char js_valueOf_str[];

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

@ -20,7 +20,7 @@
* JS configuration macros. * JS configuration macros.
*/ */
#ifndef JS_VERSION #ifndef JS_VERSION
#define JS_VERSION 140 #define JS_VERSION 150
#endif #endif
#if JS_VERSION == 100 #if JS_VERSION == 100
@ -72,8 +72,9 @@
#define JS_HAS_CATCH_GUARD 0 /* has exception handling catch guard */ #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_NEW_OBJ_METHODS 0 /* has Object.prototype query methods */
#define JS_HAS_SPARSE_ARRAYS 0 /* array methods preserve empty elems */ #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_NUMBER_FORMATS 0 /* numbers have formatting methods */
#define JS_HAS_GETTER_SETTER 0 /* has JS2 getter/setter functions */
#elif JS_VERSION == 110 #elif JS_VERSION == 110
@ -124,8 +125,9 @@
#define JS_HAS_CATCH_GUARD 0 /* has exception handling catch guard */ #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_NEW_OBJ_METHODS 0 /* has Object.prototype query methods */
#define JS_HAS_SPARSE_ARRAYS 0 /* array methods preserve empty elems */ #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_NUMBER_FORMATS 0 /* numbers have formatting methods */
#define JS_HAS_GETTER_SETTER 0 /* has JS2 getter/setter functions */
#elif JS_VERSION == 120 #elif JS_VERSION == 120
@ -176,8 +178,9 @@
#define JS_HAS_CATCH_GUARD 0 /* has exception handling catch guard */ #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_NEW_OBJ_METHODS 0 /* has Object.prototype query methods */
#define JS_HAS_SPARSE_ARRAYS 0 /* array methods preserve empty elems */ #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_NUMBER_FORMATS 0 /* numbers have formatting methods */
#define JS_HAS_GETTER_SETTER 0 /* has JS2 getter/setter functions */
#elif JS_VERSION == 130 #elif JS_VERSION == 130
@ -228,8 +231,9 @@
#define JS_HAS_CATCH_GUARD 0 /* has exception handling catch guard */ #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_NEW_OBJ_METHODS 0 /* has Object.prototype query methods */
#define JS_HAS_SPARSE_ARRAYS 0 /* array methods preserve empty elems */ #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_NUMBER_FORMATS 0 /* numbers have formatting methods */
#define JS_HAS_GETTER_SETTER 0 /* has JS2 getter/setter functions */
#elif JS_VERSION == 140 #elif JS_VERSION == 140
@ -246,6 +250,58 @@
#define JS_BUG_WITH_CLOSURE 1 /* with(o)function f(){} sets o.f */ #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_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_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_CALL_OBJECT 1 /* fun.caller is stack frame obj */
#define JS_HAS_LABEL_STATEMENT 1 /* has break/continue to label: */ #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_SPARSE_ARRAYS 0 /* array methods preserve empty elems */
#define JS_HAS_DFLT_MSG_STRINGS 1 /* provides English error messages */ #define JS_HAS_DFLT_MSG_STRINGS 1 /* provides English error messages */
#define JS_HAS_NUMBER_FORMATS 1 /* numbers have formatting methods */ #define JS_HAS_NUMBER_FORMATS 1 /* numbers have formatting methods */
#define JS_HAS_GETTER_SETTER 1 /* has JS2 getter/setter functions */
#else #else

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

@ -1735,8 +1735,13 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
JS_ASSERT(0); JS_ASSERT(0);
} }
/* If += or similar, dup the left operand and get its value. */
op = pn->pn_op; 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) { if (op != JSOP_NOP) {
switch (pn2->pn_type) { switch (pn2->pn_type) {
case TOK_NAME: case TOK_NAME:
@ -2131,6 +2136,13 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
if (!js_EmitTree(cx, cg, pn2->pn_right)) if (!js_EmitTree(cx, cg, pn2->pn_right))
return JS_FALSE; 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. */ /* Annotate JSOP_INITELEM so we decompile 2:c and not just c. */
if (pn3->pn_type == TOK_NUMBER) { if (pn3->pn_type == TOK_NUMBER) {
if (js_NewSrcNote(cx, cg, SRC_LABEL) < 0) 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) if (js_Emit1(cx, cg, JSOP_INITELEM) < 0)
return JS_FALSE; return JS_FALSE;
} else { } 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 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; jsval fval;
JSFunction *fun; JSFunction *fun;
uint32 indent;
JSString *str; JSString *str;
fval = argv[-1]; fval = argv[-1];
@ -1178,7 +1178,6 @@ fun_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
fun = JS_GetPrivate(cx, obj); fun = JS_GetPrivate(cx, obj);
if (!fun) if (!fun)
return JS_TRUE; return JS_TRUE;
indent = 0;
if (argc && !js_ValueToECMAUint32(cx, argv[0], &indent)) if (argc && !js_ValueToECMAUint32(cx, argv[0], &indent))
return JS_FALSE; return JS_FALSE;
str = JS_DecompileFunction(cx, fun, (uintN)indent); 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; 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 #if JS_HAS_CALL_FUNCTION
static JSBool static JSBool
fun_call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) fun_call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
@ -1314,7 +1327,7 @@ out:
static JSFunctionSpec function_methods[] = { static JSFunctionSpec function_methods[] = {
#if JS_HAS_TOSOURCE #if JS_HAS_TOSOURCE
{js_toSource_str, fun_toString, 0}, {js_toSource_str, fun_toSource, 0},
#endif #endif
{js_toString_str, fun_toString, 1}, {js_toString_str, fun_toString, 1},
#if JS_HAS_APPLY_FUNCTION #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; * Get the atom corresponding to the name from the tokenstream;
* we're assured at this point that it's a valid identifier. * 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, if (!js_LookupProperty(cx, obj, (jsid)atom, &obj2,
(JSProperty **)&sprop)) { (JSProperty **)&sprop)) {
goto bad_formal; goto bad_formal;

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

@ -36,6 +36,7 @@
#include "jsapi.h" #include "jsapi.h"
#include "jsatom.h" #include "jsatom.h"
#include "jscntxt.h" #include "jscntxt.h"
#include "jsconfig.h"
#include "jsfun.h" #include "jsfun.h"
#include "jsgc.h" #include "jsgc.h"
#include "jsinterp.h" #include "jsinterp.h"
@ -517,6 +518,38 @@ gc_mark(JSRuntime *rt, void *thing)
continue; continue;
GC_MARK_ATOM(rt, sym_atom(sym), prev); 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) if (!scope || scope->object == obj)

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

@ -499,7 +499,7 @@ have_fun:
if (fun->flags) { if (fun->flags) {
if (fun->flags & JSFUN_BOUND_METHOD) if (fun->flags & JSFUN_BOUND_METHOD)
thisp = parent; thisp = parent;
else if (fun->flags & JSFUN_GLOBAL_PARENT)
parent = NULL; parent = NULL;
} }
} }
@ -528,8 +528,9 @@ have_fun:
* "Call" objects with private data) may not be referred to by 'this' * "Call" objects with private data) may not be referred to by 'this'
* as dictated by ECMA. * as dictated by ECMA.
*/ */
if (thisp && !(OBJ_GET_CLASS(cx, thisp) == &js_CallClass && if (thisp &&
JS_GetPrivate(cx, thisp) != NULL)) !(OBJ_GET_CLASS(cx, thisp) == &js_CallClass &&
JS_GetPrivate(cx, thisp) != NULL))
{ {
/* Some objects (e.g., With) delegate 'this' to another object. */ /* Some objects (e.g., With) delegate 'this' to another object. */
thisp = OBJ_THIS_OBJECT(cx, thisp); thisp = OBJ_THIS_OBJECT(cx, thisp);
@ -941,7 +942,7 @@ ImportProperty(JSContext *cx, JSObject *obj, jsid id)
} else { } else {
prop = NULL; prop = NULL;
} }
if (prop && (target == obj2)) { if (prop && target == obj2) {
ok = OBJ_SET_PROPERTY(cx, target, id, &value); ok = OBJ_SET_PROPERTY(cx, target, id, &value);
} else { } else {
ok = OBJ_DEFINE_PROPERTY(cx, target, id, value, NULL, NULL, ok = OBJ_DEFINE_PROPERTY(cx, target, id, value, NULL, NULL,
@ -1011,9 +1012,12 @@ js_Interpret(JSContext *cx, jsval *result)
JSFunction *fun2; JSFunction *fun2;
JSObject *closure; JSObject *closure;
#endif #endif
#if JS_HAS_EXPORT_IMPORT #if JS_HAS_EXPORT_IMPORT || JS_HAS_GETTER_SETTER
uintN attrs; uintN attrs;
#endif #endif
#if JS_HAS_GETTER_SETTER
JSPropertyOp getter, setter;
#endif
#if JS_HAS_EXCEPTIONS #if JS_HAS_EXCEPTIONS
JSTryNote *tn; JSTryNote *tn;
ptrdiff_t offset; ptrdiff_t offset;
@ -1505,7 +1509,7 @@ js_Interpret(JSContext *cx, jsval *result)
PROPERTY_CACHE_TEST(&rt->propertyCache, obj, id, prop); \ PROPERTY_CACHE_TEST(&rt->propertyCache, obj, id, prop); \
if (PROP_FOUND(prop) && \ if (PROP_FOUND(prop) && \
!(sprop = (JSScopeProperty *)prop, \ !(sprop = (JSScopeProperty *)prop, \
sprop->attrs & (JSPROP_READONLY | JSPROP_ASSIGNHACK))) { \ sprop->attrs & JSPROP_READONLY)) { \
ok = SPROP_SET(cx, sprop, obj, obj, &rval); \ ok = SPROP_SET(cx, sprop, obj, obj, &rval); \
if (ok) { \ if (ok) { \
SET_ENUMERATE_ATTR(sprop); \ SET_ENUMERATE_ATTR(sprop); \
@ -2476,10 +2480,16 @@ js_Interpret(JSContext *cx, jsval *result)
*/ */
if (fun2->atom) { if (fun2->atom) {
SAVE_SP(fp); SAVE_SP(fp);
ok = OBJ_DEFINE_PROPERTY(cx, obj, (jsid)fun2->atom, ok = OBJ_DEFINE_PROPERTY(cx, obj, (jsid)fun2->atom,
OBJECT_TO_JSVAL(closure), OBJECT_TO_JSVAL(closure),
NULL, NULL, JSPROP_ENUMERATE, (fun2->flags & JSFUN_GETTER)
NULL); ? (JSPropertyOp) closure
: NULL,
(fun2->flags & JSFUN_SETTER)
? (JSPropertyOp) closure
: NULL,
fun2->flags | JSPROP_ENUMERATE,
NULL);
if (!ok) { if (!ok) {
cx->newborn[GCX_OBJECT] = NULL; cx->newborn[GCX_OBJECT] = NULL;
goto out; goto out;
@ -2619,6 +2629,79 @@ js_Interpret(JSContext *cx, jsval *result)
*vp = sp[-1]; *vp = sp[-1];
break; 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 #if JS_HAS_INITIALIZERS
case JSOP_NEWINIT: case JSOP_NEWINIT:
argc = 0; argc = 0;

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

@ -195,6 +195,10 @@ MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap)
JSIdArray *ida; JSIdArray *ida;
JSBool ok; JSBool ok;
jsint i, length; jsint i, length;
jsid id;
JSObject *obj2;
JSProperty *prop;
uintN attrs;
jsval val; jsval val;
map = &cx->sharpObjectMap; map = &cx->sharpObjectMap;
@ -214,9 +218,39 @@ MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap)
return NULL; return NULL;
ok = JS_TRUE; ok = JS_TRUE;
for (i = 0, length = ida->length; i < length; i++) { for (i = 0, length = ida->length; i < length; i++) {
ok = OBJ_GET_PROPERTY(cx, obj, ida->vector[i], &val); id = ida->vector[i];
if (!ok) #if JS_HAS_GETTER_SETTER
break; 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) && if (!JSVAL_IS_PRIMITIVE(val) &&
!MarkSharpObjects(cx, JSVAL_TO_OBJECT(val), NULL)) { !MarkSharpObjects(cx, JSVAL_TO_OBJECT(val), NULL)) {
ok = JS_FALSE; 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 #if JS_HAS_INITIALIZERS || JS_HAS_TOSOURCE
JSBool JSBool
@ -366,9 +400,15 @@ js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
size_t nchars, vlength, vsharplength; size_t nchars, vlength, vsharplength;
JSBool ok; JSBool ok;
char *comma; char *comma;
jsint i, length; jsint i, j, length, valcnt;
jsid id; 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; JSString *idstr, *valstr, *str;
he = js_EnterSharpObject(cx, obj, &ida, &chars); he = js_EnterSharpObject(cx, obj, &ida, &chars);
@ -409,11 +449,44 @@ js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
comma = NULL; comma = NULL;
for (i = 0, length = ida->length; i < length; i++) { 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]; 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) if (!ok)
goto error; 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. */ /* Convert id to a jsval and then to a string. */
id = js_IdToValue(id); 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); argv[0] = STRING_TO_JSVAL(idstr);
/* If id is a non-identifier string, it needs to be quoted. */ /* If id is a non-identifier string, it needs to be quoted. */
if (JSVAL_IS_STRING(id) && !js_IsIdentifier(idstr)) { if (JSVAL_IS_STRING(id) && !js_IsIdentifier(idstr)) {
idstr = js_QuoteString(cx, idstr, (jschar)'\''); idstr = js_QuoteString(cx, idstr, (jschar)'\'');
if (!idstr) { if (!idstr) {
ok = JS_FALSE; ok = JS_FALSE;
goto error; goto error;
} }
argv[0] = STRING_TO_JSVAL(idstr); argv[0] = STRING_TO_JSVAL(idstr);
} }
/* Convert val to its canonical source form. */ for (j = 0; j < valcnt; j++) {
valstr = js_ValueToSource(cx, val); /* Convert val[j] to its canonical source form. */
if (!valstr) { valstr = js_ValueToSource(cx, val[j]);
ok = JS_FALSE; if (!valstr) {
goto error; ok = JS_FALSE;
} goto error;
argv[1] = STRING_TO_JSVAL(valstr); }
vchars = valstr->chars; argv[1+j] = STRING_TO_JSVAL(valstr);
vlength = valstr->length; vchars = valstr->chars;
vlength = valstr->length;
/* If val is a non-sharp object, consider sharpening it. */ /* If val[j] is a non-sharp object, consider sharpening it. */
vsharp = NULL; vsharp = NULL;
vsharplength = 0; vsharplength = 0;
#if JS_HAS_SHARP_VARS #if JS_HAS_SHARP_VARS
if (!JSVAL_IS_PRIMITIVE(val) && vchars[0] != '#') { if (!JSVAL_IS_PRIMITIVE(val[j]) && vchars[0] != '#') {
he = js_EnterSharpObject(cx, JSVAL_TO_OBJECT(val), NULL, &vsharp); he = js_EnterSharpObject(cx, JSVAL_TO_OBJECT(val[j]), NULL,
if (!he) { &vsharp);
ok = JS_FALSE; if (!he) {
goto error; ok = JS_FALSE;
} goto error;
if (IS_SHARP(he)) { }
vchars = vsharp; if (IS_SHARP(he)) {
vlength = js_strlen(vchars); vchars = vsharp;
} else { vlength = js_strlen(vchars);
if (vsharp) { } else {
vsharplength = js_strlen(vsharp); if (vsharp) {
MAKE_SHARP(he); vsharplength = js_strlen(vsharp);
} MAKE_SHARP(he);
js_LeaveSharpObject(cx, NULL); }
} js_LeaveSharpObject(cx, NULL);
} }
}
#endif #endif
/* Allocate 1 + 1 at end for closing brace and terminating 0. */ /* Allocate 1 + 1 at end for closing brace and terminating 0. */
chars = realloc((ochars = chars), chars = realloc((ochars = chars),
(nchars + (comma ? 2 : 0) + (nchars + (comma ? 2 : 0) +
idstr->length + 1 + vsharplength + vlength + idstr->length + 1 +
1 + 1) * sizeof(jschar)); #if JS_HAS_GETTER_SETTER
if (!chars) { (gsop[j] ? 1 + gsop[j]->length : 0) +
/* Save code space on error: let JS_free ignore null vsharp. */ #endif
JS_free(cx, vsharp); vsharplength + vlength +
free(ochars); 1 + 1) * sizeof(jschar));
goto error; if (!chars) {
} /* Save code space on error: let JS_free ignore null vsharp. */
JS_free(cx, vsharp);
free(ochars);
goto error;
}
if (comma) { if (comma) {
chars[nchars++] = comma[0]; chars[nchars++] = comma[0];
chars[nchars++] = comma[1]; chars[nchars++] = comma[1];
} }
comma = ", "; comma = ", ";
js_strncpy(&chars[nchars], idstr->chars, idstr->length); js_strncpy(&chars[nchars], idstr->chars, idstr->length);
nchars += idstr->length; nchars += idstr->length;
chars[nchars++] = ':'; #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) { if (vsharplength) {
js_strncpy(&chars[nchars], vsharp, vsharplength); js_strncpy(&chars[nchars], vsharp, vsharplength);
nchars += vsharplength; nchars += vsharplength;
} }
js_strncpy(&chars[nchars], vchars, vlength); js_strncpy(&chars[nchars], vchars, vlength);
nchars += vlength; nchars += vlength;
if (vsharp) if (vsharp)
JS_free(cx, vsharp); JS_free(cx, vsharp);
}
} }
if (chars) { 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. */ /* Lock if object locking is required by this implementation. */
JS_LOCK_OBJ(cx, obj); 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. */ /* Use the object's class getter and setter by default. */
clasp = LOCKED_OBJ_GET_CLASS(obj); clasp = LOCKED_OBJ_GET_CLASS(obj);
if (!getter) if (!getter)
@ -1480,7 +1601,7 @@ js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
if (!sym) { if (!sym) {
clasp = LOCKED_OBJ_GET_CLASS(obj); clasp = LOCKED_OBJ_GET_CLASS(obj);
resolve = clasp->resolve; resolve = clasp->resolve;
if (resolve && resolve != JS_ResolveStub) { if (resolve != JS_ResolveStub) {
if (clasp->flags & JSCLASS_NEW_RESOLVE) { if (clasp->flags & JSCLASS_NEW_RESOLVE) {
newresolve = (JSNewResolveOp)resolve; newresolve = (JSNewResolveOp)resolve;
flags = 0; flags = 0;
@ -1793,10 +1914,30 @@ js_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
if (protosym) { if (protosym) {
protosprop = sym_property(protosym); protosprop = sym_property(protosym);
if (protosprop) { 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; protoid = protosprop->id;
protogetter = protosprop->getter; protogetter = protosprop->getter;
protosetter = protosprop->setter; protosetter = protosprop->setter;
protoattrs = protosprop->attrs;
JS_UNLOCK_OBJ(cx, proto); JS_UNLOCK_OBJ(cx, proto);
break; break;
} }

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

@ -47,6 +47,7 @@
#include "jsscript.h" #include "jsscript.h"
#include "jsstr.h" #include "jsstr.h"
char js_function_str[] = "function";
char js_in_str[] = "in"; char js_in_str[] = "in";
char js_instanceof_str[] = "instanceof"; char js_instanceof_str[] = "instanceof";
char js_new_str[] = "new"; char js_new_str[] = "new";
@ -408,12 +409,13 @@ struct JSPrinter {
Sprinter sprinter; /* base class state */ Sprinter sprinter; /* base class state */
JSArenaPool pool; /* string allocation pool */ JSArenaPool pool; /* string allocation pool */
uintN indent; /* indentation in spaces */ uintN indent; /* indentation in spaces */
JSBool pretty; /* pretty-print, indent, add newlines */
JSScript *script; /* script being printed */ JSScript *script; /* script being printed */
JSScope *scope; /* script function scope */ JSScope *scope; /* script function scope */
}; };
JSPrinter * JSPrinter *
js_NewPrinter(JSContext *cx, const char *name, uintN indent) js_NewPrinter(JSContext *cx, const char *name, uintN indent, JSBool pretty)
{ {
JSPrinter *jp; JSPrinter *jp;
JSStackFrame *fp; JSStackFrame *fp;
@ -426,6 +428,7 @@ js_NewPrinter(JSContext *cx, const char *name, uintN indent)
INIT_SPRINTER(cx, &jp->sprinter, &jp->pool, 0); INIT_SPRINTER(cx, &jp->sprinter, &jp->pool, 0);
JS_InitArenaPool(&jp->pool, name, 256, 1); JS_InitArenaPool(&jp->pool, name, 256, 1);
jp->indent = indent; jp->indent = indent;
jp->pretty = pretty;
jp->script = NULL; jp->script = NULL;
jp->scope = NULL; jp->scope = NULL;
fp = cx->fp; fp = cx->fp;
@ -469,27 +472,45 @@ js_GetPrinterOutput(JSPrinter *jp)
} }
int int
js_printf(JSPrinter *jp, char *format, ...) js_printf(JSPrinter *jp, const char *format, ...)
{ {
va_list ap; va_list ap;
char *bp; char *bp, *fp;
int cc; int cc;
if (*format == '\0')
return 0;
va_start(ap, format); 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 (*format == '\t') {
if (Sprint(&jp->sprinter, "%*s", jp->indent, "") < 0) if (jp->pretty && Sprint(&jp->sprinter, "%*s", jp->indent, "") < 0)
return -1; return -1;
format++; 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. */ /* Allocate temp space, convert format, and put. */
bp = JS_vsmprintf(format, ap); /* XXX vsaprintf */ bp = JS_vsmprintf(format, ap); /* XXX vsaprintf */
if (fp) {
JS_free(jp->sprinter.context, fp);
format = NULL;
}
if (!bp) { if (!bp) {
JS_ReportOutOfMemory(jp->sprinter.context); JS_ReportOutOfMemory(jp->sprinter.context);
return -1; return -1;
} }
cc = strlen(bp); cc = strlen(bp);
if (SprintPut(&jp->sprinter, bp, (size_t)cc) < 0) if (SprintPut(&jp->sprinter, bp, (size_t)cc) < 0)
cc = -1; cc = -1;
@ -500,7 +521,7 @@ js_printf(JSPrinter *jp, char *format, ...)
} }
JSBool JSBool
js_puts(JSPrinter *jp, char *s) js_puts(JSPrinter *jp, const char *s)
{ {
return SprintPut(&jp->sprinter, s, strlen(s)) >= 0; return SprintPut(&jp->sprinter, s, strlen(s)) >= 0;
} }
@ -786,6 +807,12 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
break; break;
case 0: 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)); todo = SprintPut(&ss->sprinter, cs->token, strlen(cs->token));
break; break;
@ -929,11 +956,11 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
obj = ATOM_TO_OBJECT(atom); obj = ATOM_TO_OBJECT(atom);
fun = JS_GetPrivate(cx, obj); fun = JS_GetPrivate(cx, obj);
jp2 = js_NewPrinter(cx, JS_GetFunctionName(fun), jp2 = js_NewPrinter(cx, JS_GetFunctionName(fun),
jp->indent); jp->indent, jp->pretty);
if (!jp2) if (!jp2)
return JS_FALSE; return JS_FALSE;
jp2->scope = jp->scope; jp2->scope = jp->scope;
if (js_DecompileFunction(jp2, fun, JS_TRUE)) { if (js_DecompileFunction(jp2, fun)) {
str = js_GetPrinterOutput(jp2); str = js_GetPrinterOutput(jp2);
if (str) if (str)
js_printf(jp, "%s\n", JS_GetStringBytes(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 && if ((sn = js_GetSrcNote(jp->script, pc - 1)) != NULL &&
SN_TYPE(sn) == SRC_ASSIGNOP) { SN_TYPE(sn) == SRC_ASSIGNOP) {
todo = Sprint(&ss->sprinter, "%s %s= %s", todo = Sprint(&ss->sprinter, "%s %s= %s",
lval, js_CodeSpec[pc[-1]].token, rval); lval, js_CodeSpec[lastop].token, rval);
} else { } else {
sn = js_GetSrcNote(jp->script, pc); sn = js_GetSrcNote(jp->script, pc);
todo = Sprint(&ss->sprinter, "%s%s = %s", todo = Sprint(&ss->sprinter, "%s%s = %s",
@ -1544,7 +1571,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
SN_TYPE(sn) == SRC_ASSIGNOP) { SN_TYPE(sn) == SRC_ASSIGNOP) {
todo = Sprint(&ss->sprinter, "%s.%s %s= %s", todo = Sprint(&ss->sprinter, "%s.%s %s= %s",
lval, ATOM_BYTES(atom), lval, ATOM_BYTES(atom),
js_CodeSpec[pc[-1]].token, rval); js_CodeSpec[lastop].token, rval);
} else { } else {
todo = Sprint(&ss->sprinter, "%s.%s = %s", todo = Sprint(&ss->sprinter, "%s.%s = %s",
lval, ATOM_BYTES(atom), rval); lval, ATOM_BYTES(atom), rval);
@ -1574,7 +1601,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
SN_TYPE(sn) == SRC_ASSIGNOP) { SN_TYPE(sn) == SRC_ASSIGNOP) {
todo = Sprint(&ss->sprinter, "%s[%s] %s= %s", todo = Sprint(&ss->sprinter, "%s[%s] %s= %s",
lval, xval, lval, xval,
js_CodeSpec[pc[-1]].token, rval); js_CodeSpec[lastop].token, rval);
} else { } else {
todo = Sprint(&ss->sprinter, "%s[%s] = %s", todo = Sprint(&ss->sprinter, "%s[%s] = %s",
lval, xval, rval); lval, xval, rval);
@ -1615,7 +1642,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
todo = Sprint(&ss->sprinter, "%ld", ival); todo = Sprint(&ss->sprinter, "%ld", ival);
} else if (JSVAL_IS_DOUBLE(key)) { } else if (JSVAL_IS_DOUBLE(key)) {
char buf[DTOSTR_STANDARD_BUFFER_SIZE]; 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) { if (!numStr) {
JS_ReportOutOfMemory(cx); JS_ReportOutOfMemory(cx);
return JS_FALSE; return JS_FALSE;
@ -1838,12 +1866,13 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
do_closure: do_closure:
obj = ATOM_TO_OBJECT(atom); obj = ATOM_TO_OBJECT(atom);
fun = JS_GetPrivate(cx, obj); 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) if (!jp2)
return JS_FALSE; return JS_FALSE;
jp2->scope = jp->scope; jp2->scope = jp->scope;
todo = -1; todo = -1;
if (js_DecompileFunction(jp2, fun, JS_FALSE)) { if (js_DecompileFunction(jp2, fun)) {
str = js_GetPrinterOutput(jp2); str = js_GetPrinterOutput(jp2);
if (str) { if (str) {
todo = SprintPut(&ss->sprinter, todo = SprintPut(&ss->sprinter,
@ -1942,9 +1971,16 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
xval = ATOM_BYTES(atom); xval = ATOM_BYTES(atom);
lval = POP_STR(); lval = POP_STR();
do_initprop: do_initprop:
todo = Sprint(&ss->sprinter, "%s%s%s:%s", todo = Sprint(&ss->sprinter, "%s%s%s%s%s:%s",
lval, (lval[1] != '\0') ? ", " : "", lval,
xval, rval); (lval[1] != '\0') ? ", " : "",
xval,
(lastop == JSOP_GETTER || lastop == JSOP_SETTER)
? " " : "",
(lastop == JSOP_GETTER) ? js_getter_str :
(lastop == JSOP_SETTER) ? js_setter_str :
"",
rval);
break; break;
case JSOP_INITELEM: case JSOP_INITELEM:
@ -2062,28 +2098,30 @@ js_DecompileScript(JSPrinter *jp, JSScript *script)
return js_DecompileCode(jp, script, script->code, (uintN)script->length); return js_DecompileCode(jp, script, script->code, (uintN)script->length);
} }
static const char native_code_str[] = "\t[native code]\n";
JSBool JSBool
js_DecompileFunctionBody(JSPrinter *jp, JSFunction *fun, JSBool newlines) js_DecompileFunctionBody(JSPrinter *jp, JSFunction *fun)
{ {
JSScript *script = fun->script; JSScript *script;
if (script) { JSScope *scope, *save;
JSScope *oldScope, *scope = NULL; JSBool ok;
JSBool ok;
if (fun->object) scope = (JSScope *)fun->object->map; script = fun->script;
oldScope = jp->scope; if (!script) {
jp->scope = scope; js_printf(jp, native_code_str);
ok = js_DecompileCode(jp, script, script->code, (uintN)script->length);
jp->scope = oldScope;
return ok;
}
else {
js_printf(jp, "\t[native code]\n");
return JS_TRUE; 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 JSBool
js_DecompileFunction(JSPrinter *jp, JSFunction *fun, JSBool newlines) js_DecompileFunction(JSPrinter *jp, JSFunction *fun)
{ {
JSScope *scope, *oldscope; JSScope *scope, *oldscope;
JSScopeProperty *sprop, *snext; JSScopeProperty *sprop, *snext;
@ -2092,23 +2130,29 @@ js_DecompileFunction(JSPrinter *jp, JSFunction *fun, JSBool newlines)
uintN indent; uintN indent;
intN i; intN i;
if (newlines) { if (jp->pretty) {
js_puts(jp, "\n"); js_puts(jp, "\n");
js_printf(jp, "\t"); 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; scope = NULL;
if (fun->script && fun->object) { if (fun->script && fun->object) {
/* Print the parameters. /*
* Print the parameters.
* *
* This code is complicated by the need to handle duplicate parameter names. * This code is complicated by the need to handle duplicate parameter
* A duplicate parameter is stored as a property with id equal to the parameter * names. A duplicate parameter is stored as a property with id equal
* number, but will not be in order in the linked list of symbols. So for each * to the parameter number, but will not be in order in the linked list
* parameter we search the list of symbols for the appropriately numbered * of symbols. So for each parameter we search the list of symbols for
* parameter, which we can then print. * the appropriately numbered parameter, which we can then print.
*/ */
for (i=0;;i++) { for (i = 0; ; i++) {
jsid id; jsid id;
atom = NULL; atom = NULL;
scope = (JSScope *)fun->object->map; 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_printf(jp, (i > 0 ? ", %s" : "%s"), ATOM_BYTES(atom));
} }
} }
js_puts(jp, ") {\n"); js_printf(jp, ") {\n");
indent = jp->indent; indent = jp->indent;
jp->indent += 4; jp->indent += 4;
if (fun->script && fun->object) { if (fun->script && fun->object) {
@ -2144,11 +2188,11 @@ js_DecompileFunction(JSPrinter *jp, JSFunction *fun, JSBool newlines)
return JS_FALSE; return JS_FALSE;
} }
} else { } else {
js_printf(jp, "\t[native code]\n"); js_printf(jp, native_code_str);
} }
jp->indent -= 4; jp->indent -= 4;
js_printf(jp, "\t}"); js_printf(jp, "\t}");
if (newlines) if (jp->pretty)
js_puts(jp, "\n"); js_puts(jp, "\n");
return JS_TRUE; return JS_TRUE;
} }
@ -2303,7 +2347,7 @@ js_DecompileValueGenerator(JSContext *cx, JSBool checkStack, jsval v,
tmp = NULL; 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)) if (jp && js_DecompileCode(jp, script, begin, len))
name = js_GetPrinterOutput(jp); name = js_GetPrinterOutput(jp);
else else

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

@ -107,6 +107,7 @@ struct JSCodeSpec {
uint32 format; /* immediate operand format */ uint32 format; /* immediate operand format */
}; };
extern char js_function_str[];
extern char js_in_str[]; extern char js_in_str[];
extern char js_instanceof_str[]; extern char js_instanceof_str[];
extern char js_new_str[]; extern char js_new_str[];
@ -135,7 +136,7 @@ js_QuoteString(JSContext *cx, JSString *str, jschar quote);
* a GC'ed string. * a GC'ed string.
*/ */
extern JSPrinter * extern JSPrinter *
js_NewPrinter(JSContext *cx, const char *name, uintN indent); js_NewPrinter(JSContext *cx, const char *name, uintN indent, JSBool pretty);
extern void extern void
js_DestroyPrinter(JSPrinter *jp); js_DestroyPrinter(JSPrinter *jp);
@ -144,10 +145,10 @@ extern JSString *
js_GetPrinterOutput(JSPrinter *jp); js_GetPrinterOutput(JSPrinter *jp);
extern int extern int
js_printf(JSPrinter *jp, char *format, ...); js_printf(JSPrinter *jp, const char *format, ...);
extern JSBool extern JSBool
js_puts(JSPrinter *jp, char *s); js_puts(JSPrinter *jp, const char *s);
#ifdef DEBUG #ifdef DEBUG
/* /*
@ -173,10 +174,10 @@ extern JSBool
js_DecompileScript(JSPrinter *jp, JSScript *script); js_DecompileScript(JSPrinter *jp, JSScript *script);
extern JSBool extern JSBool
js_DecompileFunctionBody(JSPrinter *jp, JSFunction *fun, JSBool newlines); js_DecompileFunctionBody(JSPrinter *jp, JSFunction *fun);
extern JSBool 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 * 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. * 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) 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)

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

@ -64,6 +64,7 @@
typedef JSParseNode * typedef JSParseNode *
JSParser(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc); JSParser(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc);
typedef JSParseNode * typedef JSParseNode *
JSMemberParser(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, JSMemberParser(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
JSBool allowCallSyntax); JSBool allowCallSyntax);
@ -177,6 +178,39 @@ WellTerminated(JSContext *cx, JSTokenStream *ts, JSTokenType lastExprType)
return JS_TRUE; 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. * Parse a top-level JS script.
*/ */
@ -216,17 +250,23 @@ js_CompileTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts,
break; break;
} }
switch (tt) { #if JS_HAS_GETTER_SETTER
case TOK_FUNCTION: 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); pn = FunctionStmt(cx, ts, &cg->treeContext);
if (pn && pn->pn_pos.end.lineno == ts->lineno) { if (pn && pn->pn_pos.end.lineno == ts->lineno) {
ok = WellTerminated(cx, ts, TOK_FUNCTION); ok = WellTerminated(cx, ts, TOK_FUNCTION);
if (!ok) if (!ok)
goto out; goto out;
} }
break; } else {
default:
js_UngetToken(ts); js_UngetToken(ts);
pn = Statement(cx, ts, &cg->treeContext); pn = Statement(cx, ts, &cg->treeContext);
if (pn) { if (pn) {
@ -234,8 +274,8 @@ js_CompileTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts,
if (!ok) if (!ok)
goto out; goto out;
} }
break;
} }
if (pn) { if (pn) {
ok = js_AllocTryNotes(cx, cg); ok = js_AllocTryNotes(cx, cg);
if (ok) if (ok)
@ -249,8 +289,6 @@ out:
ts->flags &= ~TSF_BADCOMPILE; ts->flags &= ~TSF_BADCOMPILE;
cx->gcDisabled--; cx->gcDisabled--;
cx->fp = fp; cx->fp = fp;
if (!ok)
CLEAR_PUSHBACK(ts);
return ok; return ok;
} }
@ -360,10 +398,9 @@ js_CompileFunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun)
cx->gcDisabled++; cx->gcDisabled++;
/* Satisfy the assertion at the top of Statements. */ /* 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); pn = FunctionBody(cx, ts, fun, &funcg.treeContext);
if (!pn) { if (!pn) {
CLEAR_PUSHBACK(ts);
ok = JS_FALSE; ok = JS_FALSE;
} else { } else {
ok = js_FoldConstants(cx, pn); ok = js_FoldConstants(cx, pn);
@ -390,9 +427,10 @@ InWithStatement(JSTreeContext *tc)
static JSParseNode * static JSParseNode *
FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
JSBool lambda) JSBool lambda)
{ {
JSParseNode *pn, *pn2; JSParseNode *pn, *pn2;
JSOp op;
JSAtom *funAtom, *argAtom; JSAtom *funAtom, *argAtom;
JSObject *parent; JSObject *parent;
JSFunction *fun, *outerFun; JSFunction *fun, *outerFun;
@ -403,13 +441,14 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
jsval junk; jsval junk;
/* Make a TOK_FUNCTION node. */ /* Make a TOK_FUNCTION node. */
pn = NewParseNode(cx, &ts->token, PN_FUNC); pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_FUNC);
if (!pn) if (!pn)
return NULL; return NULL;
op = CURRENT_TOKEN(ts).t_op;
/* Scan the optional function name into funAtom. */ /* Scan the optional function name into funAtom. */
if (js_MatchToken(cx, ts, TOK_NAME)) if (js_MatchToken(cx, ts, TOK_NAME))
funAtom = ts->token.t_atom; funAtom = CURRENT_TOKEN(ts).t_atom;
else else
funAtom = NULL; funAtom = NULL;
@ -418,8 +457,36 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
if (!parent) if (!parent)
return NULL; 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 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. */ /* Don't name the function if enclosed by a with statement or equiv. */
fun = js_NewFunction(cx, NULL, NULL, 0, 0, cx->fp->scopeChain, fun = js_NewFunction(cx, NULL, NULL, 0, 0, cx->fp->scopeChain,
funAtom); funAtom);
@ -443,7 +510,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
do { do {
MUST_MATCH_TOKEN_THROW(TOK_NAME, JSMSG_MISSING_FORMAL, MUST_MATCH_TOKEN_THROW(TOK_NAME, JSMSG_MISSING_FORMAL,
ok = JS_FALSE; goto out); ok = JS_FALSE; goto out);
argAtom = ts->token.t_atom; argAtom = CURRENT_TOKEN(ts).t_atom;
pobj = NULL; pobj = NULL;
ok = js_LookupProperty(cx, fun->object, (jsid)argAtom, &pobj, ok = js_LookupProperty(cx, fun->object, (jsid)argAtom, &pobj,
(JSProperty **)&sprop); (JSProperty **)&sprop);
@ -501,7 +568,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
MUST_MATCH_TOKEN_THROW(TOK_LC, JSMSG_CURLY_BEFORE_BODY, MUST_MATCH_TOKEN_THROW(TOK_LC, JSMSG_CURLY_BEFORE_BODY,
ok = JS_FALSE; goto out); 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); TREE_CONTEXT_INIT(&funtc);
pn2 = FunctionBody(cx, ts, fun, &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, MUST_MATCH_TOKEN_THROW(TOK_RC, JSMSG_CURLY_AFTER_BODY,
ok = JS_FALSE; goto out); 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_fun = fun;
pn->pn_body = pn2; pn->pn_body = pn2;
@ -561,8 +628,8 @@ Statements(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
JSParseNode *pn, *pn2; JSParseNode *pn, *pn2;
JSTokenType tt; JSTokenType tt;
JS_ASSERT(ts->token.type == TOK_LC); JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_LC);
pn = NewParseNode(cx, &ts->token, PN_LIST); pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST);
if (!pn) if (!pn)
return NULL; return NULL;
PN_INIT_LIST(pn); PN_INIT_LIST(pn);
@ -574,7 +641,7 @@ Statements(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
PN_APPEND(pn, pn2); 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) if (tt == TOK_ERROR)
pn = NULL; pn = NULL;
return pn; return pn;
@ -641,7 +708,7 @@ MatchLabel(JSContext *cx, JSTokenStream *ts, JSParseNode *pn)
return JS_FALSE; return JS_FALSE;
if (tt == TOK_NAME) { if (tt == TOK_NAME) {
(void) js_GetToken(cx, ts); (void) js_GetToken(cx, ts);
label = ts->token.t_atom; label = CURRENT_TOKEN(ts).t_atom;
} else { } else {
label = NULL; label = NULL;
} }
@ -662,11 +729,11 @@ ImportExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
JSTokenType tt; JSTokenType tt;
MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_IMPORT_NAME); 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) if (!pn)
return NULL; return NULL;
pn->pn_op = JSOP_NAME; pn->pn_op = JSOP_NAME;
pn->pn_atom = ts->token.t_atom; pn->pn_atom = CURRENT_TOKEN(ts).t_atom;
pn->pn_slot = -1; pn->pn_slot = -1;
ts->flags |= TSF_REGEXP; ts->flags |= TSF_REGEXP;
@ -676,7 +743,7 @@ ImportExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
goto bad_import; goto bad_import;
if (tt == TOK_DOT) { if (tt == TOK_DOT) {
pn2 = NewParseNode(cx, &ts->token, PN_NAME); pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NAME);
if (!pn2) if (!pn2)
return NULL; return NULL;
pn2->pn_expr = pn; pn2->pn_expr = pn;
@ -686,14 +753,14 @@ ImportExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
} else { } else {
MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NAME_AFTER_DOT); MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NAME_AFTER_DOT);
pn2->pn_op = JSOP_GETPROP; 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_slot = -1;
} }
pn2->pn_pos.begin = pn->pn_pos.begin; 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 { } else {
/* Make a TOK_LB node. */ /* Make a TOK_LB node. */
pn2 = NewParseNode(cx, &ts->token, PN_BINARY); pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY);
if (!pn2) if (!pn2)
return NULL; return NULL;
pn3 = Expr(cx, ts, tc); 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); MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX);
pn2->pn_pos.begin = pn->pn_pos.begin; 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_op = JSOP_GETELEM;
pn2->pn_left = pn; pn2->pn_left = pn;
@ -752,23 +819,23 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
switch (tt) { switch (tt) {
#if JS_HAS_EXPORT_IMPORT #if JS_HAS_EXPORT_IMPORT
case TOK_EXPORT: case TOK_EXPORT:
pn = NewParseNode(cx, &ts->token, PN_LIST); pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST);
if (!pn) if (!pn)
return NULL; return NULL;
PN_INIT_LIST(pn); PN_INIT_LIST(pn);
if (js_MatchToken(cx, ts, TOK_STAR)) { if (js_MatchToken(cx, ts, TOK_STAR)) {
pn2 = NewParseNode(cx, &ts->token, PN_NULLARY); pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY);
if (!pn2) if (!pn2)
return NULL; return NULL;
PN_APPEND(pn, pn2); PN_APPEND(pn, pn2);
} else { } else {
do { do {
MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_EXPORT_NAME); 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) if (!pn2)
return NULL; return NULL;
pn2->pn_op = JSOP_NAME; pn2->pn_op = JSOP_NAME;
pn2->pn_atom = ts->token.t_atom; pn2->pn_atom = CURRENT_TOKEN(ts).t_atom;
pn2->pn_slot = -1; pn2->pn_slot = -1;
PN_APPEND(pn, pn2); PN_APPEND(pn, pn2);
} while (js_MatchToken(cx, ts, TOK_COMMA)); } while (js_MatchToken(cx, ts, TOK_COMMA));
@ -781,7 +848,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
break; break;
case TOK_IMPORT: case TOK_IMPORT:
pn = NewParseNode(cx, &ts->token, PN_LIST); pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST);
if (!pn) if (!pn)
return NULL; return NULL;
PN_INIT_LIST(pn); PN_INIT_LIST(pn);
@ -801,7 +868,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
case TOK_IF: case TOK_IF:
/* An IF node has three kids: condition, then, and optional else. */ /* 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) if (!pn)
return NULL; return NULL;
pn1 = Condition(cx, ts, tc); pn1 = Condition(cx, ts, tc);
@ -833,7 +900,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
JSParseNode *pn5; JSParseNode *pn5;
JSBool seenDefault = JS_FALSE; JSBool seenDefault = JS_FALSE;
pn = NewParseNode(cx, &ts->token, PN_BINARY); pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY);
if (!pn) if (!pn)
return NULL; return NULL;
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_SWITCH); 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); MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_SWITCH);
/* pn2 is a list of case nodes. The default case has pn_left == NULL */ /* 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) if (!pn2)
return NULL; return NULL;
PN_INIT_LIST(pn2); PN_INIT_LIST(pn2);
@ -866,7 +933,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
/* fall through */ /* fall through */
case TOK_CASE: case TOK_CASE:
pn3 = NewParseNode(cx, &ts->token, PN_BINARY); pn3 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY);
if (!pn3) if (!pn3)
return NULL; return NULL;
if (tt == TOK_DEFAULT) { if (tt == TOK_DEFAULT) {
@ -894,7 +961,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
} }
MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_AFTER_CASE); 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) if (!pn4)
return NULL; return NULL;
pn4->pn_type = TOK_LC; pn4->pn_type = TOK_LC;
@ -915,7 +982,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
js_PopStatement(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_kid1 = pn1;
pn->pn_kid2 = pn2; pn->pn_kid2 = pn2;
return pn; return pn;
@ -923,7 +990,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
#endif /* JS_HAS_SWITCH_STATEMENT */ #endif /* JS_HAS_SWITCH_STATEMENT */
case TOK_WHILE: case TOK_WHILE:
pn = NewParseNode(cx, &ts->token, PN_BINARY); pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY);
if (!pn) if (!pn)
return NULL; return NULL;
js_PushStatement(tc, &stmtInfo, STMT_WHILE_LOOP, -1); 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 #if JS_HAS_DO_WHILE_LOOP
case TOK_DO: case TOK_DO:
pn = NewParseNode(cx, &ts->token, PN_BINARY); pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY);
if (!pn) if (!pn)
return NULL; return NULL;
js_PushStatement(tc, &stmtInfo, STMT_DO_LOOP, -1); js_PushStatement(tc, &stmtInfo, STMT_DO_LOOP, -1);
@ -961,7 +1028,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
case TOK_FOR: case TOK_FOR:
/* A FOR node is binary, left is loop control and right is the body. */ /* 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) if (!pn)
return NULL; return NULL;
js_PushStatement(tc, &stmtInfo, STMT_FOR_LOOP, -1); 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. */ /* 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) if (!pn4)
return NULL; return NULL;
pn4->pn_type = TOK_RESERVED; pn4->pn_type = TOK_RESERVED;
@ -1088,7 +1155,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
* *
* finally nodes are unary (just the finally expression) * 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; pn->pn_op = JSOP_NOP;
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_TRY); MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_TRY);
@ -1110,14 +1177,14 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
*/ */
/* catch node */ /* catch node */
pn2 = NewParseNode(cx, &ts->token, PN_TERNARY); pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_TERNARY);
pn2->pn_op = JSOP_NOP; pn2->pn_op = JSOP_NOP;
/* /*
* We use a PN_NAME for the discriminant (catchguard) node * We use a PN_NAME for the discriminant (catchguard) node
* with the actual discriminant code in the initializer spot * 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) if (!pn2 || !pn3)
return NULL; 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_LP, JSMSG_PAREN_BEFORE_CATCH);
MUST_MATCH_TOKEN(TOK_NAME, JSMSG_CATCH_IDENTIFIER); 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; pn3->pn_expr = NULL;
#if JS_HAS_CATCH_GUARD #if JS_HAS_CATCH_GUARD
if (js_PeekToken(cx, ts) == TOK_COLON) { if (js_PeekToken(cx, ts) == TOK_COLON) {
@ -1168,7 +1235,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
return pn; return pn;
} }
case TOK_THROW: case TOK_THROW:
pn = NewParseNode(cx, &ts->token, PN_UNARY); pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY);
if (!pn) if (!pn)
return NULL; return NULL;
pn2 = Expr(cx, ts, tc); pn2 = Expr(cx, ts, tc);
@ -1197,7 +1264,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
#endif /* JS_HAS_EXCEPTIONS */ #endif /* JS_HAS_EXCEPTIONS */
case TOK_BREAK: case TOK_BREAK:
pn = NewParseNode(cx, &ts->token, PN_NULLARY); pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY);
if (!pn) if (!pn)
return NULL; return NULL;
if (!MatchLabel(cx, ts, pn)) if (!MatchLabel(cx, ts, pn))
@ -1226,11 +1293,11 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
} }
} }
if (label) if (label)
pn->pn_pos.end = ts->token.pos.end; pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
break; break;
case TOK_CONTINUE: case TOK_CONTINUE:
pn = NewParseNode(cx, &ts->token, PN_NULLARY); pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY);
if (!pn) if (!pn)
return NULL; return NULL;
if (!MatchLabel(cx, ts, pn)) if (!MatchLabel(cx, ts, pn))
@ -1269,11 +1336,11 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
} }
} }
if (label) if (label)
pn->pn_pos.end = ts->token.pos.end; pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
break; break;
case TOK_WITH: case TOK_WITH:
pn = NewParseNode(cx, &ts->token, PN_BINARY); pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY);
if (!pn) if (!pn)
return NULL; return NULL;
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_WITH); MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_WITH);
@ -1311,7 +1378,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
JSMSG_BAD_RETURN); JSMSG_BAD_RETURN);
return NULL; return NULL;
} }
pn = NewParseNode(cx, &ts->token, PN_UNARY); pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY);
if (!pn) if (!pn)
return NULL; return NULL;
@ -1360,7 +1427,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
case TOK_EOL: case TOK_EOL:
case TOK_SEMI: case TOK_SEMI:
pn = NewParseNode(cx, &ts->token, PN_UNARY); pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY);
if (!pn) if (!pn)
return NULL; return NULL;
pn->pn_type = TOK_SEMI; pn->pn_type = TOK_SEMI;
@ -1371,7 +1438,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
case TOK_DEBUGGER: case TOK_DEBUGGER:
if(!WellTerminated(cx, ts, TOK_ERROR)) if(!WellTerminated(cx, ts, TOK_ERROR))
return NULL; return NULL;
pn = NewParseNode(cx, &ts->token, PN_NULLARY); pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY);
if (!pn) if (!pn)
return NULL; return NULL;
pn->pn_type = TOK_DEBUGGER; pn->pn_type = TOK_DEBUGGER;
@ -1382,14 +1449,13 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
return NULL; return NULL;
default: default:
lastExprType = ts->token.type; lastExprType = CURRENT_TOKEN(ts).type;
js_UngetToken(ts); js_UngetToken(ts);
pn2 = Expr(cx, ts, tc); pn2 = Expr(cx, ts, tc);
if (!pn2) if (!pn2)
return NULL; return NULL;
tt = ts->pushback.type; if (js_PeekToken(cx, ts) == TOK_COLON) {
if (tt == TOK_COLON) {
if (pn2->pn_type != TOK_NAME) { if (pn2->pn_type != TOK_NAME) {
js_ReportCompileErrorNumber(cx, ts, JSREPORT_ERROR, js_ReportCompileErrorNumber(cx, ts, JSREPORT_ERROR,
JSMSG_BAD_LABEL); JSMSG_BAD_LABEL);
@ -1403,7 +1469,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
return NULL; return NULL;
} }
} }
js_GetToken(cx, ts); (void) js_GetToken(cx, ts);
/* Push a label struct and parse the statement. */ /* Push a label struct and parse the statement. */
js_PushStatement(tc, &stmtInfo, STMT_LABEL, -1); js_PushStatement(tc, &stmtInfo, STMT_LABEL, -1);
@ -1425,7 +1491,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
!WellTerminated(cx, ts, lastExprType)) { !WellTerminated(cx, ts, lastExprType)) {
return NULL; return NULL;
} }
pn = NewParseNode(cx, &ts->token, PN_UNARY); pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY);
if (!pn) if (!pn)
return NULL; return NULL;
pn->pn_type = TOK_SEMI; 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 * We determine this by looking up the variable id in the
* current variable scope. * current variable scope.
*/ */
JS_ASSERT(ts->token.type == TOK_VAR); JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_VAR);
pn = NewParseNode(cx, &ts->token, PN_LIST); pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST);
if (!pn) if (!pn)
return NULL; return NULL;
pn->pn_op = JSOP_NOP; pn->pn_op = JSOP_NOP;
@ -1490,9 +1556,9 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
currentGetter = getter; currentGetter = getter;
currentSetter = setter; currentSetter = setter;
MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_VARIABLE_NAME); 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) if (!pn2)
return NULL; return NULL;
pn2->pn_op = JSOP_NAME; pn2->pn_op = JSOP_NAME;
@ -1588,7 +1654,7 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
} }
if (js_MatchToken(cx, ts, TOK_ASSIGN)) { 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, js_ReportCompileErrorNumber(cx, ts,JSREPORT_ERROR,
JSMSG_BAD_VAR_INIT); JSMSG_BAD_VAR_INIT);
ok = JS_FALSE; ok = JS_FALSE;
@ -1642,7 +1708,7 @@ Expr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
pn = AssignExpr(cx, ts, tc); pn = AssignExpr(cx, ts, tc);
if (pn && js_MatchToken(cx, ts, TOK_COMMA)) { 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) if (!pn2)
return NULL; return NULL;
pn2->pn_pos.begin = pn->pn_pos.begin; pn2->pn_pos.begin = pn->pn_pos.begin;
@ -1699,38 +1765,53 @@ static JSParseNode *
AssignExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) AssignExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
{ {
JSParseNode *pn, *pn2; JSParseNode *pn, *pn2;
JSTokenType tt;
JSOp op; JSOp op;
pn = CondExpr(cx, ts, tc); pn = CondExpr(cx, ts, tc);
if (pn && js_MatchToken(cx, ts, TOK_ASSIGN)) { if (!pn)
op = ts->token.t_op; return NULL;
for (pn2 = pn; pn2->pn_type == TOK_RP; pn2 = pn2->pn_kid)
; tt = js_GetToken(cx, ts);
switch (pn2->pn_type) { #if JS_HAS_GETTER_SETTER
case TOK_NAME: if (tt == TOK_NAME) {
if (pn2->pn_slot >= 0) { tt = CheckGetterOrSetter(cx, ts, TOK_ASSIGN);
JS_ASSERT(pn2->pn_op == JSOP_GETARG || pn2->pn_op == JSOP_GETVAR); if (tt == TOK_ERROR)
if (pn2->pn_op == JSOP_GETARG) return NULL;
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));
} }
#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; return pn;
} }
@ -1745,7 +1826,7 @@ CondExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
pn = OrExpr(cx, ts, tc); pn = OrExpr(cx, ts, tc);
if (pn && js_MatchToken(cx, ts, TOK_HOOK)) { if (pn && js_MatchToken(cx, ts, TOK_HOOK)) {
pn1 = pn; pn1 = pn;
pn = NewParseNode(cx, &ts->token, PN_TERNARY); pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_TERNARY);
if (!pn) if (!pn)
return NULL; return NULL;
#if JS_HAS_IN_OPERATOR #if JS_HAS_IN_OPERATOR
@ -1840,7 +1921,7 @@ EqExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
pn = RelExpr(cx, ts, tc); pn = RelExpr(cx, ts, tc);
while (pn && js_MatchToken(cx, ts, TOK_EQOP)) { 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)); pn = NewBinary(cx, TOK_EQOP, op, pn, RelExpr(cx, ts, tc));
} }
return pn; return pn;
@ -1877,8 +1958,8 @@ RelExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|| js_MatchToken(cx, ts, TOK_INSTANCEOF) || js_MatchToken(cx, ts, TOK_INSTANCEOF)
#endif /* JS_HAS_INSTANCEOF */ #endif /* JS_HAS_INSTANCEOF */
)) { )) {
tt = ts->token.type; tt = CURRENT_TOKEN(ts).type;
op = ts->token.t_op; op = CURRENT_TOKEN(ts).t_op;
pn = NewBinary(cx, tt, op, pn, ShiftExpr(cx, ts, tc)); pn = NewBinary(cx, tt, op, pn, ShiftExpr(cx, ts, tc));
} }
#if JS_HAS_IN_OPERATOR #if JS_HAS_IN_OPERATOR
@ -1897,7 +1978,7 @@ ShiftExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
pn = AddExpr(cx, ts, tc); pn = AddExpr(cx, ts, tc);
while (pn && js_MatchToken(cx, ts, TOK_SHOP)) { 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)); pn = NewBinary(cx, TOK_SHOP, op, pn, AddExpr(cx, ts, tc));
} }
return pn; return pn;
@ -1914,7 +1995,7 @@ AddExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
while (pn && while (pn &&
(js_MatchToken(cx, ts, TOK_PLUS) || (js_MatchToken(cx, ts, TOK_PLUS) ||
js_MatchToken(cx, ts, TOK_MINUS))) { js_MatchToken(cx, ts, TOK_MINUS))) {
tt = ts->token.type; tt = CURRENT_TOKEN(ts).type;
op = (tt == TOK_PLUS) ? JSOP_ADD : JSOP_SUB; op = (tt == TOK_PLUS) ? JSOP_ADD : JSOP_SUB;
pn = NewBinary(cx, tt, op, pn, MulExpr(cx, ts, tc)); pn = NewBinary(cx, tt, op, pn, MulExpr(cx, ts, tc));
} }
@ -1932,8 +2013,8 @@ MulExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
while (pn && while (pn &&
(js_MatchToken(cx, ts, TOK_STAR) || (js_MatchToken(cx, ts, TOK_STAR) ||
js_MatchToken(cx, ts, TOK_DIVOP))) { js_MatchToken(cx, ts, TOK_DIVOP))) {
tt = ts->token.type; tt = CURRENT_TOKEN(ts).type;
op = ts->token.t_op; op = CURRENT_TOKEN(ts).t_op;
pn = NewBinary(cx, tt, op, pn, UnaryExpr(cx, ts, tc)); pn = NewBinary(cx, tt, op, pn, UnaryExpr(cx, ts, tc));
} }
return pn; return pn;
@ -2023,11 +2104,11 @@ UnaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
case TOK_UNARYOP: case TOK_UNARYOP:
case TOK_PLUS: case TOK_PLUS:
case TOK_MINUS: case TOK_MINUS:
pn = NewParseNode(cx, &ts->token, PN_UNARY); pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY);
if (!pn) if (!pn)
return NULL; return NULL;
pn->pn_type = TOK_UNARYOP; /* PLUS and MINUS are binary */ 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); pn2 = UnaryExpr(cx, ts, tc);
if (!pn2) if (!pn2)
return NULL; return NULL;
@ -2037,7 +2118,7 @@ UnaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
case TOK_INC: case TOK_INC:
case TOK_DEC: case TOK_DEC:
pn = NewParseNode(cx, &ts->token, PN_UNARY); pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY);
if (!pn) if (!pn)
return NULL; return NULL;
pn2 = MemberExpr(cx, ts, tc, JS_TRUE); pn2 = MemberExpr(cx, ts, tc, JS_TRUE);
@ -2049,7 +2130,7 @@ UnaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
break; break;
case TOK_DELETE: case TOK_DELETE:
pn = NewParseNode(cx, &ts->token, PN_UNARY); pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY);
if (!pn) if (!pn)
return NULL; return NULL;
pn2 = UnaryExpr(cx, ts, tc); pn2 = UnaryExpr(cx, ts, tc);
@ -2074,7 +2155,7 @@ UnaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
tt = js_PeekTokenSameLine(cx, ts); tt = js_PeekTokenSameLine(cx, ts);
if (tt == TOK_INC || tt == TOK_DEC) { if (tt == TOK_INC || tt == TOK_DEC) {
(void) js_GetToken(cx, ts); (void) js_GetToken(cx, ts);
pn2 = NewParseNode(cx, &ts->token, PN_UNARY); pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY);
if (!pn2) if (!pn2)
return NULL; return NULL;
if (!SetIncOpKid(cx, ts, tc, pn2, pn, tt, JS_FALSE)) 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) { if (tt == TOK_NEW) {
(void) js_GetToken(cx, ts); (void) js_GetToken(cx, ts);
pn = NewParseNode(cx, &ts->token, PN_LIST); pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST);
if (!pn) if (!pn)
return NULL; return NULL;
pn2 = MemberExpr(cx, ts, tc, JS_FALSE); 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) { while ((tt = js_GetToken(cx, ts)) > TOK_EOF) {
if (tt == TOK_DOT) { if (tt == TOK_DOT) {
pn2 = NewParseNode(cx, &ts->token, PN_NAME); pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NAME);
if (!pn2) if (!pn2)
return NULL; return NULL;
MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NAME_AFTER_DOT); MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NAME_AFTER_DOT);
pn2->pn_pos.begin = pn->pn_pos.begin; 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_op = JSOP_GETPROP;
pn2->pn_expr = pn; pn2->pn_expr = pn;
pn2->pn_atom = ts->token.t_atom; pn2->pn_atom = CURRENT_TOKEN(ts).t_atom;
} else if (tt == TOK_LB) { } else if (tt == TOK_LB) {
pn2 = NewParseNode(cx, &ts->token, PN_BINARY); pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY);
if (!pn2) if (!pn2)
return NULL; return NULL;
pn3 = Expr(cx, ts, tc); 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); MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX);
pn2->pn_pos.begin = pn->pn_pos.begin; 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_op = JSOP_GETELEM;
pn2->pn_left = pn; pn2->pn_left = pn;
pn2->pn_right = pn3; pn2->pn_right = pn3;
} else if (allowCallSyntax && tt == TOK_LP) { } else if (allowCallSyntax && tt == TOK_LP) {
pn2 = NewParseNode(cx, &ts->token, PN_LIST); pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST);
if (!pn2) if (!pn2)
return NULL; return NULL;
pn2->pn_op = JSOP_CALL; pn2->pn_op = JSOP_CALL;
@ -2228,6 +2309,14 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
tt = js_GetToken(cx, ts); tt = js_GetToken(cx, ts);
ts->flags &= ~TSF_REGEXP; 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) { switch (tt) {
#if JS_HAS_LEXICAL_CLOSURE #if JS_HAS_LEXICAL_CLOSURE
case TOK_FUNCTION: case TOK_FUNCTION:
@ -2243,7 +2332,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
JSBool matched; JSBool matched;
jsint atomIndex; jsint atomIndex;
pn = NewParseNode(cx, &ts->token, PN_LIST); pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST);
if (!pn) if (!pn)
return NULL; return NULL;
pn->pn_type = TOK_RB; pn->pn_type = TOK_RB;
@ -2271,7 +2360,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
} }
if (tt == TOK_COMMA) if (tt == TOK_COMMA)
pn2 = NewParseNode(cx, &ts->token, PN_NULLARY); pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY);
else else
pn2 = AssignExpr(cx, ts, tc); pn2 = AssignExpr(cx, ts, tc);
if (!pn2) if (!pn2)
@ -2284,12 +2373,12 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_AFTER_LIST); 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; return pn;
} }
case TOK_LC: case TOK_LC:
pn = NewParseNode(cx, &ts->token, PN_LIST); pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST);
if (!pn) if (!pn)
return NULL; return NULL;
pn->pn_type = TOK_RC; pn->pn_type = TOK_RC;
@ -2304,18 +2393,20 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
if (!js_MatchToken(cx, ts, TOK_RC)) { if (!js_MatchToken(cx, ts, TOK_RC)) {
do { do {
JSOp op;
tt = js_GetToken(cx, ts); tt = js_GetToken(cx, ts);
switch (tt) { switch (tt) {
case TOK_NUMBER: case TOK_NUMBER:
pn3 = NewParseNode(cx, &ts->token, PN_NULLARY); pn3 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY);
if (pn3) if (pn3)
pn3->pn_dval = ts->token.t_dval; pn3->pn_dval = CURRENT_TOKEN(ts).t_dval;
break; break;
case TOK_NAME: case TOK_NAME:
case TOK_STRING: case TOK_STRING:
pn3 = NewParseNode(cx, &ts->token, PN_NULLARY); pn3 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY);
if (pn3) if (pn3)
pn3->pn_atom = ts->token.t_atom; pn3->pn_atom = CURRENT_TOKEN(ts).t_atom;
break; break;
case TOK_RC: case TOK_RC:
goto end_obj_init; goto end_obj_init;
@ -2325,9 +2416,21 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
return NULL; return NULL;
} }
MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_AFTER_ID); tt = js_GetToken(cx, ts);
pn2 = NewBinary(cx, TOK_COLON, JSOP_INITPROP, pn3, #if JS_HAS_GETTER_SETTER
AssignExpr(cx, ts, tc)); 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) if (!pn2)
return NULL; return NULL;
PN_APPEND(pn, pn2); PN_APPEND(pn, pn2);
@ -2336,26 +2439,26 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_LIST); MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_LIST);
} }
end_obj_init: end_obj_init:
pn->pn_pos.end = ts->token.pos.end; pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
return pn; return pn;
#if JS_HAS_SHARP_VARS #if JS_HAS_SHARP_VARS
case TOK_DEFSHARP: case TOK_DEFSHARP:
if (defsharp) if (defsharp)
goto badsharp; goto badsharp;
defsharp = NewParseNode(cx, &ts->token, PN_UNARY); defsharp = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY);
if (!defsharp) if (!defsharp)
return NULL; return NULL;
defsharp->pn_num = (jsint) ts->token.t_dval; defsharp->pn_num = (jsint) CURRENT_TOKEN(ts).t_dval;
defsharp->pn_kid = NULL; defsharp->pn_kid = NULL;
goto again; goto again;
case TOK_USESHARP: case TOK_USESHARP:
/* Check for forward/dangling references at runtime, to allow eval. */ /* 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) if (!pn)
return NULL; return NULL;
pn->pn_num = (jsint) ts->token.t_dval; pn->pn_num = (jsint) CURRENT_TOKEN(ts).t_dval;
notsharp = JS_TRUE; notsharp = JS_TRUE;
break; break;
#endif /* JS_HAS_SHARP_VARS */ #endif /* JS_HAS_SHARP_VARS */
@ -2366,7 +2469,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
#if JS_HAS_IN_OPERATOR #if JS_HAS_IN_OPERATOR
uintN oldflags; uintN oldflags;
#endif #endif
pn = NewParseNode(cx, &ts->token, PN_UNARY); pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY);
if (!pn) if (!pn)
return NULL; return NULL;
#if JS_HAS_IN_OPERATOR #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); MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN);
pn->pn_type = TOK_RP; 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; pn->pn_kid = pn2;
break; break;
} }
@ -2399,11 +2502,11 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
/* FALL THROUGH */ /* FALL THROUGH */
case TOK_NAME: case TOK_NAME:
case TOK_OBJECT: case TOK_OBJECT:
pn = NewParseNode(cx, &ts->token, PN_NULLARY); pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY);
if (!pn) if (!pn)
return NULL; return NULL;
pn->pn_op = ts->token.t_op; pn->pn_op = CURRENT_TOKEN(ts).t_op;
pn->pn_atom = ts->token.t_atom; pn->pn_atom = CURRENT_TOKEN(ts).t_atom;
pn->pn_slot = -1; pn->pn_slot = -1;
if (tt == TOK_NAME) { if (tt == TOK_NAME) {
if (!LookupArgOrVar(cx, pn->pn_atom, tc, &pn->pn_op, &pn->pn_slot)) 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; break;
case TOK_NUMBER: case TOK_NUMBER:
pn = NewParseNode(cx, &ts->token, PN_NULLARY); pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY);
if (!pn) if (!pn)
return NULL; return NULL;
pn->pn_dval = ts->token.t_dval; pn->pn_dval = CURRENT_TOKEN(ts).t_dval;
#if JS_HAS_SHARP_VARS #if JS_HAS_SHARP_VARS
notsharp = JS_TRUE; notsharp = JS_TRUE;
#endif #endif
break; break;
case TOK_PRIMARY: case TOK_PRIMARY:
pn = NewParseNode(cx, &ts->token, PN_NULLARY); pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY);
if (!pn) if (!pn)
return NULL; return NULL;
pn->pn_op = ts->token.t_op; pn->pn_op = CURRENT_TOKEN(ts).t_op;
#if JS_HAS_SHARP_VARS #if JS_HAS_SHARP_VARS
notsharp = JS_TRUE; notsharp = JS_TRUE;
#endif #endif
@ -2438,10 +2541,11 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
case TOK_IMPORT: case TOK_IMPORT:
#endif #endif
case TOK_RESERVED: case TOK_RESERVED:
badWord = js_DeflateString(cx, ts->token.ptr, badWord = js_DeflateString(cx, CURRENT_TOKEN(ts).ptr,
(size_t) ts->token.pos.end.index - ts->token.pos.begin.index); (size_t) CURRENT_TOKEN(ts).pos.end.index
js_ReportCompileErrorNumber(cx, ts, JSREPORT_ERROR, - CURRENT_TOKEN(ts).pos.begin.index);
JSMSG_RESERVED_ID, badWord); js_ReportCompileErrorNumber(cx, ts, JSREPORT_ERROR, JSMSG_RESERVED_ID,
badWord);
JS_free(cx, badWord); JS_free(cx, badWord);
return NULL; return NULL;

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

@ -86,6 +86,7 @@ JS_BEGIN_EXTERN_C
* <Expressions> * <Expressions>
* TOK_COMMA list pn_head: list of pn_count comma-separated exprs * TOK_COMMA list pn_head: list of pn_count comma-separated exprs
* TOK_ASSIGN binary pn_left: lvalue, pn_right: rvalue * 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_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_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 * 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_2 = 120,
JSVERSION_1_3 = 130, JSVERSION_1_3 = 130,
JSVERSION_1_4 = 140, JSVERSION_1_4 = 140,
JSVERSION_1_5 = 150,
JSVERSION_DEFAULT = 0, JSVERSION_DEFAULT = 0,
JSVERSION_UNKNOWN = -1 JSVERSION_UNKNOWN = -1
} JSVersion; } JSVersion;

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

@ -64,7 +64,7 @@ static struct keyword {
{"export", TOK_EXPORT, JSOP_NOP, JSVERSION_1_2}, {"export", TOK_EXPORT, JSOP_NOP, JSVERSION_1_2},
{js_false_str, TOK_PRIMARY, JSOP_FALSE}, {js_false_str, TOK_PRIMARY, JSOP_FALSE},
{"for", TOK_FOR, JSOP_NOP}, {"for", TOK_FOR, JSOP_NOP},
{"function", TOK_FUNCTION, JSOP_NOP}, {js_function_str, TOK_FUNCTION, JSOP_NOP},
{"if", TOK_IF, JSOP_NOP}, {"if", TOK_IF, JSOP_NOP},
{js_in_str, TOK_IN, JSOP_IN}, {js_in_str, TOK_IN, JSOP_IN},
{js_new_str, TOK_NEW, JSOP_NEW}, {js_new_str, TOK_NEW, JSOP_NEW},
@ -92,9 +92,9 @@ static struct keyword {
#endif #endif
#if JS_HAS_INSTANCEOF #if JS_HAS_INSTANCEOF
{js_instanceof_str, TOK_INSTANCEOF, JSOP_INSTANCEOF}, {js_instanceof_str, TOK_INSTANCEOF, JSOP_INSTANCEOF,JSVERSION_1_4},
#else #else
{js_instanceof_str, TOK_RESERVED, JSOP_NOP}, {js_instanceof_str, TOK_RESERVED, JSOP_NOP, JSVERSION_1_4},
#endif #endif
#ifdef RESERVE_JAVA_KEYWORDS #ifdef RESERVE_JAVA_KEYWORDS
@ -133,7 +133,7 @@ static struct keyword {
#endif #endif
#if JS_HAS_DEBUGGER_KEYWORD #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) #elif defined(RESERVE_ECMA_KEYWORDS)
{"debugger", TOK_RESERVED, JSOP_NOP, JSVERSION_1_3}, {"debugger", TOK_RESERVED, JSOP_NOP, JSVERSION_1_3},
#endif #endif
@ -150,8 +150,10 @@ js_InitScanner(JSContext *cx)
atom = js_Atomize(cx, kw->name, strlen(kw->name), ATOM_PINNED); atom = js_Atomize(cx, kw->name, strlen(kw->name), ATOM_PINNED);
if (!atom) if (!atom)
return JS_FALSE; return JS_FALSE;
atom->kwindex = (JSVERSION_IS_ECMA(cx->version) atom->kwindex = (JSVERSION_IS_ECMA(cx->version) ||
|| kw->version <= cx->version) ? kw - keywords : -1; kw->version <= cx->version)
? kw - keywords
: -1;
} }
return JS_TRUE; return JS_TRUE;
} }
@ -196,7 +198,6 @@ js_NewBufferTokenStream(JSContext *cx, const jschar *base, size_t length)
return NULL; return NULL;
} }
memset(ts, 0, nb); memset(ts, 0, nb);
CLEAR_PUSHBACK(ts);
ts->lineno = 1; ts->lineno = 1;
ts->linebuf.base = ts->linebuf.limit = ts->linebuf.ptr = (jschar *)(ts + 1); ts->linebuf.base = ts->linebuf.limit = ts->linebuf.ptr = (jschar *)(ts + 1);
ts->userbuf.base = (jschar *)base; ts->userbuf.base = (jschar *)base;
@ -448,6 +449,7 @@ js_ReportCompileError(JSContext *cx, JSTokenStream *ts, uintN flags,
jschar *limit, lastc; jschar *limit, lastc;
JSErrorReporter onError; JSErrorReporter onError;
JSErrorReport report; JSErrorReport report;
jschar *tokenptr;
JSString *linestr; JSString *linestr;
va_start(ap, format); va_start(ap, format);
@ -471,11 +473,12 @@ js_ReportCompileError(JSContext *cx, JSTokenStream *ts, uintN flags,
report.linebuf = linestr report.linebuf = linestr
? JS_GetStringBytes(linestr) ? JS_GetStringBytes(linestr)
: NULL; : NULL;
tokenptr = CURRENT_TOKEN(ts).ptr;
report.tokenptr = linestr report.tokenptr = linestr
? report.linebuf + (ts->token.ptr - ts->linebuf.base) ? report.linebuf + (tokenptr - ts->linebuf.base)
: NULL; : NULL;
report.uclinebuf = ts->linebuf.base; report.uclinebuf = ts->linebuf.base;
report.uctokenptr = ts->token.ptr; report.uctokenptr = tokenptr;
report.flags = flags; report.flags = flags;
report.errorNumber = 0; report.errorNumber = 0;
@ -505,6 +508,7 @@ js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts, uintN flags,
jschar *limit, lastc; jschar *limit, lastc;
JSErrorReporter onError; JSErrorReporter onError;
JSErrorReport report; JSErrorReport report;
jschar *tokenptr;
JSString *linestr; JSString *linestr;
char *message; char *message;
@ -533,11 +537,13 @@ js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts, uintN flags,
report.linebuf = linestr report.linebuf = linestr
? JS_GetStringBytes(linestr) ? JS_GetStringBytes(linestr)
: NULL; : NULL;
/* XXXbe this whole fn duplicates a lot of JS_ReportCompileError... */
tokenptr = CURRENT_TOKEN(ts).ptr;
report.tokenptr = linestr report.tokenptr = linestr
? report.linebuf + (ts->token.ptr - ts->linebuf.base) ? report.linebuf + (tokenptr - ts->linebuf.base)
: NULL; : NULL;
report.uclinebuf = ts->linebuf.base; report.uclinebuf = ts->linebuf.base;
report.uctokenptr = ts->token.ptr; report.uctokenptr = tokenptr;
report.flags = flags; report.flags = flags;
#if JS_HAS_ERROR_EXCEPTIONS #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 * exception is thrown, then the JSREPORT_EXCEPTION flag will be set in
* report.flags. Proper behavior for error reporters is probably to * report.flags. Proper behavior for error reporters is probably to
* ignore this for all but toplevel compilation errors. * ignore this for all but toplevel compilation errors.
*
* XXX it'd probably be best if there was only one call to this * 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. * 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, * otherwise the exception will describe only the last compile error,
* which is likely spurious. * which is likely spurious.
*/ */
if (!(ts->flags & TSF_BADCOMPILE)) if (!(ts->flags & TSF_BADCOMPILE)) {
if (js_ErrorToException(cx, message, &report)) { if (js_ErrorToException(cx, message, &report))
ts->flags |= TSF_BADCOMPILE; ts->flags |= TSF_BADCOMPILE;
} }
/* /*
* Suppress any compiletime errors that don't occur at the top level. * 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') if (lastc == '\n')
limit[-1] = lastc; limit[-1] = lastc;
if (message) JS_free(cx, message); if (message)
JS_free(cx, message);
if (report.messageArgs) { if (report.messageArgs) {
int i = 0; int i = 0;
while (report.messageArgs[i]) while (report.messageArgs[i])
JS_free(cx, (void *)report.messageArgs[i++]); JS_free(cx, (void *)report.messageArgs[i++]);
JS_free(cx, (void *)report.messageArgs); 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 JSTokenType
@ -612,8 +620,9 @@ js_PeekToken(JSContext *cx, JSTokenStream *ts)
{ {
JSTokenType tt; JSTokenType tt;
tt = ts->pushback.type; if (ts->lookahead != 0) {
if (tt == TOK_EOF) { tt = ts->tokens[(ts->cursor + ts->lookahead) & NTOKENS_MASK].type;
} else {
tt = js_GetToken(cx, ts); tt = js_GetToken(cx, ts);
js_UngetToken(ts); js_UngetToken(ts);
} }
@ -625,9 +634,11 @@ js_PeekTokenSameLine(JSContext *cx, JSTokenStream *ts)
{ {
JSTokenType tt; 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); tt = js_PeekToken(cx, ts);
HIDE_NEWLINES(ts); ts->flags &= ~TSF_NEWLINES;
return tt; return tt;
} }
@ -674,6 +685,8 @@ AddToTokenBuf(JSContext *cx, JSTokenBuf *tb, jschar c)
JSTokenType JSTokenType
js_GetToken(JSContext *cx, JSTokenStream *ts) js_GetToken(JSContext *cx, JSTokenStream *ts)
{ {
JSTokenType tt;
JSToken *tp;
int32 c; int32 c;
JSAtom *atom; 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 FINISH_TOKENBUF(tb) if (!AddToTokenBuf(cx, tb, 0)) RETURN(TOK_ERROR)
#define TOKEN_LENGTH(tb) ((tb)->ptr - (tb)->base - 1) #define TOKEN_LENGTH(tb) ((tb)->ptr - (tb)->base - 1)
#define RETURN(tt) { if (tt == TOK_ERROR) ts->flags |= TSF_ERROR; \ #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->linebuf.ptr - ts->linebuf.base) - \
ts->ungetpos; \ ts->ungetpos; \
return (ts->token.type = tt); } return (tp->type = tt); }
/* If there was a fatal error, keep returning TOK_ERROR. */ /* If there was a fatal error, keep returning TOK_ERROR. */
if (ts->flags & TSF_ERROR) if (ts->flags & TSF_ERROR)
return TOK_ERROR; return TOK_ERROR;
/* Check for a pushed-back token resulting from mismatching lookahead. */ /* Check for a pushed-back token resulting from mismatching lookahead. */
if (ts->pushback.type != TOK_EOF) { while (ts->lookahead != 0) {
ts->token = ts->pushback; ts->lookahead--;
CLEAR_PUSHBACK(ts); ts->cursor = (ts->cursor + 1) & NTOKENS_MASK;
return ts->token.type; tt = CURRENT_TOKEN(ts).type;
if (tt != TOK_EOL || (ts->flags & TSF_NEWLINES))
return tt;
} }
retry: retry:
@ -704,9 +719,11 @@ retry:
break; break;
} while (JS_ISSPACE(c)); } while (JS_ISSPACE(c));
ts->token.ptr = ts->linebuf.ptr - 1; ts->cursor = (ts->cursor + 1) & NTOKENS_MASK;
ts->token.pos.begin.index = ts->linepos + (ts->token.ptr-ts->linebuf.base); tp = &CURRENT_TOKEN(ts);
ts->token.pos.begin.lineno = ts->token.pos.end.lineno = ts->lineno; 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) if (c == EOF)
RETURN(TOK_EOF); RETURN(TOK_EOF);
@ -731,11 +748,11 @@ retry:
struct keyword *kw; struct keyword *kw;
kw = &keywords[atom->kwindex]; kw = &keywords[atom->kwindex];
ts->token.t_op = (JSOp) kw->op; tp->t_op = (JSOp) kw->op;
RETURN(kw->tokentype); RETURN(kw->tokentype);
} }
ts->token.t_op = JSOP_NAME; tp->t_op = JSOP_NAME;
ts->token.t_atom = atom; tp->t_atom = atom;
RETURN(TOK_NAME); RETURN(TOK_NAME);
} }
@ -827,7 +844,7 @@ retry:
RETURN(TOK_ERROR); RETURN(TOK_ERROR);
} }
} }
ts->token.t_dval = dval; tp->t_dval = dval;
RETURN(TOK_NUMBER); RETURN(TOK_NUMBER);
} }
@ -901,9 +918,9 @@ retry:
0); 0);
if (!atom) if (!atom)
RETURN(TOK_ERROR); RETURN(TOK_ERROR);
ts->token.pos.end.lineno = ts->lineno; tp->pos.end.lineno = ts->lineno;
ts->token.t_op = JSOP_STRING; tp->t_op = JSOP_STRING;
ts->token.t_atom = atom; tp->t_atom = atom;
RETURN(TOK_STRING); RETURN(TOK_STRING);
} }
@ -919,13 +936,21 @@ retry:
case ')': c = TOK_RP; break; case ')': c = TOK_RP; break;
case ',': c = TOK_COMMA; break; case ',': c = TOK_COMMA; break;
case '?': c = TOK_HOOK; 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 '|': case '|':
if (MatchChar(ts, c)) { if (MatchChar(ts, c)) {
c = TOK_OR; c = TOK_OR;
} else if (MatchChar(ts, '=')) { } else if (MatchChar(ts, '=')) {
ts->token.t_op = JSOP_BITOR; tp->t_op = JSOP_BITOR;
c = TOK_ASSIGN; c = TOK_ASSIGN;
} else { } else {
c = TOK_BITOR; c = TOK_BITOR;
@ -934,7 +959,7 @@ retry:
case '^': case '^':
if (MatchChar(ts, '=')) { if (MatchChar(ts, '=')) {
ts->token.t_op = JSOP_BITXOR; tp->t_op = JSOP_BITXOR;
c = TOK_ASSIGN; c = TOK_ASSIGN;
} else { } else {
c = TOK_BITXOR; c = TOK_BITXOR;
@ -945,7 +970,7 @@ retry:
if (MatchChar(ts, c)) { if (MatchChar(ts, c)) {
c = TOK_AND; c = TOK_AND;
} else if (MatchChar(ts, '=')) { } else if (MatchChar(ts, '=')) {
ts->token.t_op = JSOP_BITAND; tp->t_op = JSOP_BITAND;
c = TOK_ASSIGN; c = TOK_ASSIGN;
} else { } else {
c = TOK_BITAND; c = TOK_BITAND;
@ -955,13 +980,13 @@ retry:
case '=': case '=':
if (MatchChar(ts, c)) { if (MatchChar(ts, c)) {
#if JS_HAS_TRIPLE_EQOPS #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 #else
ts->token.t_op = cx->jsop_eq; tp->t_op = cx->jsop_eq;
#endif #endif
c = TOK_EQOP; c = TOK_EQOP;
} else { } else {
ts->token.t_op = JSOP_NOP; tp->t_op = JSOP_NOP;
c = TOK_ASSIGN; c = TOK_ASSIGN;
} }
break; break;
@ -969,13 +994,13 @@ retry:
case '!': case '!':
if (MatchChar(ts, '=')) { if (MatchChar(ts, '=')) {
#if JS_HAS_TRIPLE_EQOPS #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 #else
ts->token.t_op = cx->jsop_ne; tp->t_op = cx->jsop_ne;
#endif #endif
c = TOK_EQOP; c = TOK_EQOP;
} else { } else {
ts->token.t_op = JSOP_NOT; tp->t_op = JSOP_NOT;
c = TOK_UNARYOP; c = TOK_UNARYOP;
} }
break; break;
@ -991,26 +1016,26 @@ retry:
UngetChar(ts, '!'); UngetChar(ts, '!');
} }
if (MatchChar(ts, c)) { if (MatchChar(ts, c)) {
ts->token.t_op = JSOP_LSH; tp->t_op = JSOP_LSH;
c = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_SHOP; c = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_SHOP;
} else { } else {
ts->token.t_op = MatchChar(ts, '=') ? JSOP_LE : JSOP_LT; tp->t_op = MatchChar(ts, '=') ? JSOP_LE : JSOP_LT;
c = TOK_RELOP; c = TOK_RELOP;
} }
break; break;
case '>': case '>':
if (MatchChar(ts, c)) { 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; c = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_SHOP;
} else { } else {
ts->token.t_op = MatchChar(ts, '=') ? JSOP_GE : JSOP_GT; tp->t_op = MatchChar(ts, '=') ? JSOP_GE : JSOP_GT;
c = TOK_RELOP; c = TOK_RELOP;
} }
break; break;
case '*': case '*':
ts->token.t_op = JSOP_MUL; tp->t_op = JSOP_MUL;
c = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_STAR; c = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_STAR;
break; break;
@ -1074,7 +1099,7 @@ skipline:
} }
c = PeekChar(ts); c = PeekChar(ts);
if (JS7_ISLET(c)) { if (JS7_ISLET(c)) {
ts->token.ptr = ts->linebuf.ptr - 1; tp->ptr = ts->linebuf.ptr - 1;
js_ReportCompileErrorNumber(cx, ts,JSREPORT_ERROR, js_ReportCompileErrorNumber(cx, ts,JSREPORT_ERROR,
JSMSG_BAD_REGEXP_FLAG); JSMSG_BAD_REGEXP_FLAG);
(void) GetChar(ts); (void) GetChar(ts);
@ -1089,38 +1114,38 @@ skipline:
atom = js_AtomizeObject(cx, obj, 0); atom = js_AtomizeObject(cx, obj, 0);
if (!atom) if (!atom)
RETURN(TOK_ERROR); RETURN(TOK_ERROR);
ts->token.t_op = JSOP_OBJECT; tp->t_op = JSOP_OBJECT;
ts->token.t_atom = atom; tp->t_atom = atom;
RETURN(TOK_OBJECT); RETURN(TOK_OBJECT);
} }
#endif /* JS_HAS_REGEXPS */ #endif /* JS_HAS_REGEXPS */
ts->token.t_op = JSOP_DIV; tp->t_op = JSOP_DIV;
c = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_DIVOP; c = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_DIVOP;
break; break;
case '%': case '%':
ts->token.t_op = JSOP_MOD; tp->t_op = JSOP_MOD;
c = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_DIVOP; c = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_DIVOP;
break; break;
case '~': case '~':
ts->token.t_op = JSOP_BITNOT; tp->t_op = JSOP_BITNOT;
c = TOK_UNARYOP; c = TOK_UNARYOP;
break; break;
case '+': case '+':
case '-': case '-':
if (MatchChar(ts, '=')) { if (MatchChar(ts, '=')) {
ts->token.t_op = (c == '+') ? JSOP_ADD : JSOP_SUB; tp->t_op = (c == '+') ? JSOP_ADD : JSOP_SUB;
c = TOK_ASSIGN; c = TOK_ASSIGN;
} else if (MatchChar(ts, c)) { } else if (MatchChar(ts, c)) {
c = (c == '+') ? TOK_INC : TOK_DEC; c = (c == '+') ? TOK_INC : TOK_DEC;
} else if (c == '-') { } else if (c == '-') {
ts->token.t_op = JSOP_NEG; tp->t_op = JSOP_NEG;
c = TOK_MINUS; c = TOK_MINUS;
} else { } else {
ts->token.t_op = JSOP_POS; tp->t_op = JSOP_POS;
c = TOK_PLUS; c = TOK_PLUS;
} }
break; break;
@ -1147,7 +1172,7 @@ skipline:
RETURN(TOK_ERROR); RETURN(TOK_ERROR);
} }
} }
ts->token.t_dval = (jsdouble) n; tp->t_dval = (jsdouble) n;
if (c == '=') if (c == '=')
RETURN(TOK_DEFSHARP); RETURN(TOK_DEFSHARP);
if (c == '#') if (c == '#')
@ -1176,10 +1201,11 @@ skipline:
void void
js_UngetToken(JSTokenStream *ts) js_UngetToken(JSTokenStream *ts)
{ {
JS_ASSERT(ts->pushback.type == TOK_EOF); JS_ASSERT(ts->lookahead < NTOKENS_MASK);
if (ts->flags & TSF_ERROR) if (ts->flags & TSF_ERROR)
return; return;
ts->pushback = ts->token; ts->lookahead++;
ts->cursor = (ts->cursor - 1) & NTOKENS_MASK;
} }
JSBool JSBool

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

@ -128,10 +128,13 @@ typedef struct JSTokenBuf {
#define JS_LINE_LIMIT 256 /* logical line buffer size limit -- #define JS_LINE_LIMIT 256 /* logical line buffer size limit --
physical line length is unlimited */ 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 { struct JSTokenStream {
JSToken token; /* last token scanned */ JSToken tokens[NTOKENS];/* circular token buffer */
JSToken pushback; /* pushed-back already-scanned token */ uintN cursor; /* index of last parsed token */
uintN lookahead; /* count of lookahead tokens */
uintN lineno; /* current line number */ uintN lineno; /* current line number */
uintN ungetpos; /* next free char slot in ungetbuf */ uintN ungetpos; /* next free char slot in ungetbuf */
jschar ungetbuf[4]; /* at most 4, for \uXXXX lookahead */ jschar ungetbuf[4]; /* at most 4, for \uXXXX lookahead */
@ -143,12 +146,14 @@ struct JSTokenStream {
JSTokenBuf tokenbuf; /* current token string buffer */ JSTokenBuf tokenbuf; /* current token string buffer */
const char *filename; /* input filename or null */ const char *filename; /* input filename or null */
FILE *file; /* stdio stream if reading from file */ 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 */ JSSourceHandler listener; /* callback for source; eg debugger */
void *listenerData; /* listener 'this' data */ void *listenerData; /* listener 'this' data */
void *listenerTSData;/* listener data for this TokenStream */ void *listenerTSData;/* listener data for this TokenStream */
}; };
#define CURRENT_TOKEN(ts) ((ts)->tokens[(ts)->cursor])
/* JSTokenStream flags */ /* JSTokenStream flags */
#define TSF_ERROR 0x01 /* fatal error while scanning */ #define TSF_ERROR 0x01 /* fatal error while scanning */
#define TSF_EOF 0x02 /* hit end of file */ #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_REGEXP 0x08 /* looking for a regular expression */
#define TSF_NLFLAG 0x20 /* last linebuf ended with \n */ #define TSF_NLFLAG 0x20 /* last linebuf ended with \n */
#define TSF_CRFLAG 0x40 /* linebuf would have ended with \r */ #define TSF_CRFLAG 0x40 /* linebuf would have ended with \r */
#define TSF_BADCOMPILE 0x80 /* compile failed, stop throwing exns */ #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)
/* /*
* Create a new token stream, either from an input buffer or from a file. * 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 * 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). * 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_GET(cx,sprop,obj,obj2,vp) \
#define SPROP_SET(cx,sprop,obj,obj2,vp) ((sprop)->setter(cx,OBJ_THIS_OBJECT(cx,obj),sprop->id,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 * extern JSScope *
js_GetMutableScope(JSContext *cx, JSObject *obj); js_GetMutableScope(JSContext *cx, JSObject *obj);