JSBool js_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp) { JSBool b; jsdouble d; #if defined XP_PC && defined _MSC_VER && _MSC_VER <= 800 /* MSVC1.5 coredumps */ if (!bp) return JS_TRUE; /* This should be an if-else chain, but MSVC1.5 crashes if it is. */ #define ELSE #else #define ELSE else #endif if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) { /* Must return early to avoid falling thru to JSVAL_IS_OBJECT case. */ *bp = JS_FALSE; return JS_TRUE; } if (JSVAL_IS_OBJECT(v)) { if (!JSVERSION_IS_ECMA(cx->version)) { if (!OBJ_DEFAULT_VALUE(cx, JSVAL_TO_OBJECT(v), JSTYPE_BOOLEAN, &v)) return JS_FALSE; if (!JSVAL_IS_BOOLEAN(v)) v = JSVAL_TRUE; /* non-null object is true */ b = JSVAL_TO_BOOLEAN(v); } else { b = JS_TRUE; } } ELSE if (JSVAL_IS_STRING(v)) { b = JSSTRING_LENGTH(JSVAL_TO_STRING(v)) ? JS_TRUE : JS_FALSE; } ELSE if (JSVAL_IS_INT(v)) { b = JSVAL_TO_INT(v) ? JS_TRUE : JS_FALSE; } ELSE if (JSVAL_IS_DOUBLE(v)) { d = *JSVAL_TO_DOUBLE(v); b = (!JSDOUBLE_IS_NaN(d) && d != 0) ? JS_TRUE : JS_FALSE; } ELSE #if defined XP_PC && defined _MSC_VER && _MSC_VER <= 800 if (JSVAL_IS_BOOLEAN(v)) { b = JSVAL_TO_BOOLEAN(v); } #else { JS_ASSERT(JSVAL_IS_BOOLEAN(v)); b = JSVAL_TO_BOOLEAN(v); } #endif #undef ELSE *bp = b; return JS_TRUE; }
JavaClass_deleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { JSVersion version = JS_GetVersion(cx); *vp = JSVAL_FALSE; if (!JSVERSION_IS_ECMA(version)) { JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL, JSJMSG_JCLASS_PROP_DELETE); return JS_FALSE; } else { /* Attempts to delete permanent properties are silently ignored by ECMAScript. */ return JS_TRUE; } }
static JSBool access_java_array_element(JSContext *cx, JNIEnv *jEnv, JSObject *obj, jsid id, jsval *vp, JSBool do_assignment) { jsval idval; jarray java_array; JavaClassDescriptor *class_descriptor; JavaObjectWrapper *java_wrapper; jsize array_length, index; JavaSignature *array_component_signature; /* printf("In JavaArray_getProperty\n"); */ java_wrapper = JS_GetPrivate(cx, obj); if (!java_wrapper) { const char *property_name; if (JS_IdToValue(cx, id, &idval) && JSVAL_IS_STRING(idval) && (property_name = JS_GetStringBytes(JSVAL_TO_STRING(idval))) != NULL) { if (!strcmp(property_name, "constructor")) { if (vp) *vp = JSVAL_VOID; return JS_TRUE; } } JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL, JSJMSG_BAD_OP_JARRAY); return JS_FALSE; } class_descriptor = java_wrapper->class_descriptor; java_array = java_wrapper->java_obj; JS_ASSERT(class_descriptor->type == JAVA_SIGNATURE_ARRAY); JS_IdToValue(cx, id, &idval); if (!JSVAL_IS_INT(idval)) idval = try_convert_to_jsint(cx, idval); if (!JSVAL_IS_INT(idval)) { /* * Usually, properties of JavaArray objects are indexed by integers, but * Java arrays also inherit all the methods of java.lang.Object, so a * string-valued property is also possible. */ if (JSVAL_IS_STRING(idval)) { const char *member_name; member_name = JS_GetStringBytes(JSVAL_TO_STRING(idval)); if (do_assignment) { JSVersion version = JS_GetVersion(cx); if (!JSVERSION_IS_ECMA(version)) { JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL, JSJMSG_CANT_WRITE_JARRAY, member_name); return JS_FALSE; } else { if (vp) *vp = JSVAL_VOID; return JS_TRUE; } } else { if (!strcmp(member_name, "length")) { array_length = jsj_GetJavaArrayLength(cx, jEnv, java_array); if (array_length < 0) return JS_FALSE; if (vp) *vp = INT_TO_JSVAL(array_length); return JS_TRUE; } /* Check to see if we're reflecting a Java array method */ return JavaObject_getPropertyById(cx, obj, id, vp); } } JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL, JSJMSG_BAD_INDEX_EXPR); return JS_FALSE; } index = JSVAL_TO_INT(idval); #if 0 array_length = jsj_GetJavaArrayLength(cx, jEnv, java_array); if (array_length < 0) return JS_FALSE; /* Just let Java throw an exception instead of checking array bounds here */ if (index < 0 || index >= array_length) { char numBuf[12]; sprintf(numBuf, "%d", index); JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL, JSJMSG_BAD_JARRAY_INDEX, numBuf); return JS_FALSE; } #endif array_component_signature = class_descriptor->array_component_signature; if (!vp) return JS_TRUE; if (do_assignment) { return jsj_SetJavaArrayElement(cx, jEnv, java_array, index, array_component_signature, *vp); } else { return jsj_GetJavaArrayElement(cx, jEnv, java_array, index, array_component_signature, vp); } }
JSBool js_DeleteProperty2(JSContext *cx, JSObject *obj, JSProperty *prop, jsval id, jsval *rval) { #if JS_HAS_PROP_DELETE JSRuntime *rt; JSString *str; JSScope *scope; JSObject *proto; PRHashNumber hash; JSSymbol *sym; rt = cx->runtime; PR_ASSERT(JS_IS_RUNTIME_LOCKED(rt)); *rval = JSVERSION_IS_ECMA(cx->version) ? JSVAL_TRUE : JSVAL_VOID; if (prop->flags & JSPROP_PERMANENT) { if (JSVERSION_IS_ECMA(cx->version)) { *rval = JSVAL_FALSE; return JS_TRUE; } str = js_ValueToSource(cx, js_IdToValue(id)); if (str) JS_ReportError(cx, "%s is permanent", JS_GetStringBytes(str)); return JS_FALSE; } if (!obj->map->clasp->delProperty(cx, obj, prop->id, &prop->object->slots[prop->slot])) { return JS_FALSE; } /* Handle old bug that treated empty string as zero index. */ CHECK_FOR_FUNNY_INDEX(id); GC_POKE(cx, prop->object->slots[prop->slot]); scope = (JSScope *)obj->map; proto = scope->object; if (proto == obj) { /* The object has its own scope, so remove id if it was found here. */ if (prop->object == obj) { /* Purge cache only if prop is not about to be destroyed. */ if (prop->nrefs != 1) { PROPERTY_CACHE_FILL(cx, &rt->propertyCache, obj, id, PROP_NOT_FOUND); } #if JS_HAS_OBJ_WATCHPOINT if (prop->setter == js_watch_set) { /* * Keep the symbol around with null value in case of re-set. * The watchpoint will hold the "deleted" property until it * is removed by obj_unwatch or a native JS_ClearWatchPoint. * See js_SetProperty for the re-set logic. */ for (sym = prop->symbols; sym; sym = sym->next) { if (sym_id(sym) == id) { sym->entry.value = NULL; prop = js_DropProperty(cx, prop); PR_ASSERT(prop); return JS_TRUE; } } } #endif scope->ops->remove(cx, scope, id); } proto = OBJ_GET_PROTO(obj); if (!proto) return JS_TRUE; } /* Search shared prototype scopes for an inherited property to hide. */ hash = js_HashValue(id); do { scope = (JSScope *)proto->map; sym = scope->ops->lookup(cx, scope, id, hash); if (sym) { /* Add a null-valued symbol to hide the prototype property. */ scope = js_GetMutableScope(cx, obj); if (!scope) return JS_FALSE; if (!scope->ops->add(cx, scope, id, NULL)) return JS_FALSE; PROPERTY_CACHE_FILL(cx, &rt->propertyCache, obj, id, PROP_NOT_FOUND); return JS_TRUE; } proto = OBJ_GET_PROTO(proto); } while (proto); return JS_TRUE; #else jsval null = JSVAL_NULL; return (js_SetProperty(cx, obj, id, &null) != NULL); #endif }
JSProperty * js_SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { JSRuntime *rt; JSScope *scope, *protoScope; JSProperty *prop, *protoProp; PRHashNumber hash; JSSymbol *sym, *protoSym; JSObject *proto, *assignobj; jsval pval, aval, rval; jsint slot; JSErrorReporter older; JSString *str; rt = cx->runtime; PR_ASSERT(JS_IS_RUNTIME_LOCKED(rt)); #ifdef SCOPE_TABLE_NOTYET /* XXX hash recompute */ /* XXX protoProp->getter, protoProp->setter, protoProp->flags */ scope = js_MutateScope(cx, obj, id, getter, setter, flags, &prop); #endif scope = js_GetMutableScope(cx, obj); if (!scope) return NULL; /* Handle old bug that treated empty string as zero index. */ CHECK_FOR_FUNNY_INDEX(id); hash = js_HashValue(id); sym = scope->ops->lookup(cx, scope, id, hash); if (sym) { prop = sym_property(sym); #if JS_HAS_OBJ_WATCHPOINT if (!prop) { /* * Deleted property place-holder, could have a watchpoint that * holds the deleted-but-watched property. */ prop = js_FindWatchPoint(rt, obj, js_IdToValue(id)); } #endif } else { prop = NULL; } if (!prop) { /* Find a prototype property with the same id. */ proto = OBJ_GET_PROTO(obj); protoProp = NULL; while (proto) { protoScope = (JSScope *)proto->map; protoSym = protoScope->ops->lookup(cx, protoScope, id, hash); if (protoSym) { protoProp = sym_property(protoSym); if (protoProp) break; } proto = OBJ_GET_PROTO(proto); } /* Make a new property descriptor with the right heritage. */ if (protoProp) { prop = js_NewProperty(cx, scope, id, protoProp->getter, protoProp->setter, protoProp->flags | JSPROP_ENUMERATE); prop->id = protoProp->id; } else { prop = js_NewProperty(cx, scope, id, scope->map.clasp->getProperty, scope->map.clasp->setProperty, JSPROP_ENUMERATE); } if (!prop) return NULL; if (!obj->map->clasp->addProperty(cx, obj, prop->id, vp)) { js_DestroyProperty(cx, prop); return NULL; } /* Initialize new properties to undefined. */ obj->slots[prop->slot] = JSVAL_VOID; if (sym) { /* Null-valued symbol left behind from a delete operation. */ sym->entry.value = js_HoldProperty(cx, prop); } } if (!sym) { /* Need a new symbol as well as a new property. */ sym = scope->ops->add(cx, scope, id, prop); if (!sym) return NULL; #if JS_BUG_AUTO_INDEX_PROPS { jsval id2 = INT_TO_JSVAL(prop->slot - JSSLOT_START); if (!scope->ops->add(cx, scope, id2, prop)) { scope->ops->remove(cx, scope, id); return NULL; } PROPERTY_CACHE_FILL(cx, &rt->propertyCache, obj, id2, prop); } #endif PROPERTY_CACHE_FILL(cx, &rt->propertyCache, obj, id, prop); } /* Get the current property value from its slot. */ PR_ASSERT(prop->slot < obj->map->freeslot); slot = prop->slot; pval = obj->slots[slot]; /* Evil overloaded operator assign() hack. */ if (JSVAL_IS_OBJECT(pval)) { assignobj = JSVAL_TO_OBJECT(pval); if (assignobj) { older = JS_SetErrorReporter(cx, NULL); if (js_GetProperty(cx, assignobj, (jsval)rt->atomState.assignAtom, &aval) && JSVAL_IS_FUNCTION(aval) && js_Call(cx, assignobj, aval, 1, vp, &rval)) { *vp = rval; JS_SetErrorReporter(cx, older); prop->flags |= JSPROP_ASSIGNHACK; return prop; } JS_SetErrorReporter(cx, older); } } /* Check for readonly *after* the assign() hack. */ if (prop->flags & JSPROP_READONLY) { if (!JSVERSION_IS_ECMA(cx->version)) { str = js_ValueToSource(cx, js_IdToValue(id)); if (str) { JS_ReportError(cx, "%s is read-only", JS_GetStringBytes(str)); } } return NULL; } /* Let the setter modify vp before copying from it to obj->slots[slot]. */ if (!prop->setter(cx, obj, prop->id, vp)) return NULL; GC_POKE(cx, pval); obj->slots[slot] = *vp; /* Setting a property makes it enumerable. */ prop->flags |= JSPROP_ENUMERATE; return prop; }
JSTokenType js_GetToken(JSContext *cx, JSTokenStream *ts) { JSTokenType tt; JSToken *tp; int32 c; JSAtom *atom; JSBool hadUnicodeEscape; #define INIT_TOKENBUF(tb) ((tb)->ptr = (tb)->base) #define FINISH_TOKENBUF(tb) if (!AddToTokenBuf(cx, tb, 0)) RETURN(TOK_ERROR) #define TOKEN_LENGTH(tb) ((tb)->ptr - (tb)->base - 1) #define RETURN(tt) { if (tt == TOK_ERROR) ts->flags |= TSF_ERROR; \ tp->pos.end.index = ts->linepos + \ (ts->linebuf.ptr - ts->linebuf.base) - \ ts->ungetpos; \ return (tp->type = tt); } /* If there was a fatal error, keep returning TOK_ERROR. */ if (ts->flags & TSF_ERROR) return TOK_ERROR; /* Check for a pushed-back token resulting from mismatching lookahead. */ while (ts->lookahead != 0) { ts->lookahead--; ts->cursor = (ts->cursor + 1) & NTOKENS_MASK; tt = CURRENT_TOKEN(ts).type; if (tt != TOK_EOL || (ts->flags & TSF_NEWLINES)) return tt; } retry: do { c = GetChar(ts); if (c == '\n') { ts->flags &= ~TSF_DIRTYLINE; if (ts->flags & TSF_NEWLINES) break; } } while (JS_ISSPACE(c)); ts->cursor = (ts->cursor + 1) & NTOKENS_MASK; tp = &CURRENT_TOKEN(ts); tp->ptr = ts->linebuf.ptr - 1; tp->pos.begin.index = ts->linepos + (tp->ptr - ts->linebuf.base); tp->pos.begin.lineno = tp->pos.end.lineno = ts->lineno; if (c == EOF) RETURN(TOK_EOF); if (c != '-' && c != '\n') ts->flags |= TSF_DIRTYLINE; hadUnicodeEscape = JS_FALSE; if (JS_ISIDENT_START(c) || (c == '\\' && (c = GetUnicodeEscape(ts), hadUnicodeEscape = JS_ISIDENT_START(c)))) { INIT_TOKENBUF(&ts->tokenbuf); for (;;) { if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c)) RETURN(TOK_ERROR); c = GetChar(ts); if (c == '\\') { c = GetUnicodeEscape(ts); if (!JS_ISIDENT(c)) break; hadUnicodeEscape = JS_TRUE; } else { if (!JS_ISIDENT(c)) break; } } UngetChar(ts, c); FINISH_TOKENBUF(&ts->tokenbuf); atom = js_AtomizeChars(cx, ts->tokenbuf.base, TOKEN_LENGTH(&ts->tokenbuf), 0); if (!atom) RETURN(TOK_ERROR); if (!hadUnicodeEscape && ATOM_KEYWORD(atom)) { struct keyword *kw = ATOM_KEYWORD(atom); if (JSVERSION_IS_ECMA(cx->version) || kw->version <= cx->version) { tp->t_op = (JSOp) kw->op; RETURN(kw->tokentype); } } tp->t_op = JSOP_NAME; tp->t_atom = atom; RETURN(TOK_NAME); } if (JS7_ISDEC(c) || (c == '.' && JS7_ISDEC(PeekChar(ts)))) { jsint radix; const jschar *endptr; jsdouble dval; radix = 10; INIT_TOKENBUF(&ts->tokenbuf); if (c == '0') { if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c)) RETURN(TOK_ERROR); c = GetChar(ts); if (JS_TOLOWER(c) == 'x') { if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c)) RETURN(TOK_ERROR); c = GetChar(ts); radix = 16; } else if (JS7_ISDEC(c)) { radix = 8; } } while (JS7_ISHEX(c)) { if (radix < 16) { if (JS7_ISLET(c)) break; /* * We permit 08 and 09 as decimal numbers, which makes our * behaviour a superset of the ECMA numeric grammar. We might * not always be so permissive, so we warn about it. */ if (radix == 8 && c >= '8') { if (!js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_WARNING, JSMSG_BAD_OCTAL, c == '8' ? "08" : "09")) { RETURN(TOK_ERROR); } radix = 10; } } if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c)) RETURN(TOK_ERROR); c = GetChar(ts); } if (radix == 10 && (c == '.' || JS_TOLOWER(c) == 'e')) { if (c == '.') { do { if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c)) RETURN(TOK_ERROR); c = GetChar(ts); } while (JS7_ISDEC(c)); } if (JS_TOLOWER(c) == 'e') { if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c)) RETURN(TOK_ERROR); c = GetChar(ts); if (c == '+' || c == '-') { if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c)) RETURN(TOK_ERROR); c = GetChar(ts); } if (!JS7_ISDEC(c)) { js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_MISSING_EXPONENT); RETURN(TOK_ERROR); } do { if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c)) RETURN(TOK_ERROR); c = GetChar(ts); } while (JS7_ISDEC(c)); } } UngetChar(ts, c); FINISH_TOKENBUF(&ts->tokenbuf); if (radix == 10) { if (!js_strtod(cx, ts->tokenbuf.base, &endptr, &dval)) { js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_OUT_OF_MEMORY); RETURN(TOK_ERROR); } } else { if (!js_strtointeger(cx, ts->tokenbuf.base, &endptr, radix, &dval)) { js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_OUT_OF_MEMORY); RETURN(TOK_ERROR); } } tp->t_dval = dval; RETURN(TOK_NUMBER); } if (c == '"' || c == '\'') { int32 val, qc = c; INIT_TOKENBUF(&ts->tokenbuf); while ((c = GetChar(ts)) != qc) { if (c == '\n' || c == EOF) { UngetChar(ts, c); js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_UNTERMINATED_STRING); RETURN(TOK_ERROR); } if (c == '\\') { switch (c = GetChar(ts)) { case 'b': c = '\b'; break; case 'f': c = '\f'; break; case 'n': c = '\n'; break; case 'r': c = '\r'; break; case 't': c = '\t'; break; case 'v': c = '\v'; break; default: if ('0' <= c && c < '8') { val = JS7_UNDEC(c); c = PeekChar(ts); if ('0' <= c && c < '8') { val = 8 * val + JS7_UNDEC(c); GetChar(ts); c = PeekChar(ts); if ('0' <= c && c < '8') { int32 save = val; val = 8 * val + JS7_UNDEC(c); if (val <= 0377) GetChar(ts); else val = save; } } c = (jschar)val; } else if (c == 'u') { jschar cp[4]; if (PeekChars(ts, 4, cp) && JS7_ISHEX(cp[0]) && JS7_ISHEX(cp[1]) && JS7_ISHEX(cp[2]) && JS7_ISHEX(cp[3])) { c = (((((JS7_UNHEX(cp[0]) << 4) + JS7_UNHEX(cp[1])) << 4) + JS7_UNHEX(cp[2])) << 4) + JS7_UNHEX(cp[3]); SkipChars(ts, 4); } } else if (c == 'x') { jschar cp[2]; if (PeekChars(ts, 2, cp) && JS7_ISHEX(cp[0]) && JS7_ISHEX(cp[1])) { c = (JS7_UNHEX(cp[0]) << 4) + JS7_UNHEX(cp[1]); SkipChars(ts, 2); } } else if (c == '\n' && JSVERSION_IS_ECMA(cx->version)) { /* ECMA follows C by removing escaped newlines. */ continue; } break; } } if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c)) RETURN(TOK_ERROR); } FINISH_TOKENBUF(&ts->tokenbuf); atom = js_AtomizeChars(cx, ts->tokenbuf.base, TOKEN_LENGTH(&ts->tokenbuf), 0); if (!atom) RETURN(TOK_ERROR); tp->pos.end.lineno = ts->lineno; tp->t_op = JSOP_STRING; tp->t_atom = atom; RETURN(TOK_STRING); } switch (c) { case '\n': c = TOK_EOL; break; case ';': c = TOK_SEMI; break; case '.': c = TOK_DOT; break; case '[': c = TOK_LB; break; case ']': c = TOK_RB; break; case '{': c = TOK_LC; break; case '}': c = TOK_RC; break; case '(': c = TOK_LP; break; case ')': c = TOK_RP; break; case ',': c = TOK_COMMA; break; case '?': c = TOK_HOOK; break; case ':': /* * Default so compiler can modify to JSOP_GETTER if 'p getter: v' in an * object initializer, likewise for setter. */ tp->t_op = JSOP_NOP; c = TOK_COLON; break; case '|': if (MatchChar(ts, c)) { c = TOK_OR; } else if (MatchChar(ts, '=')) { tp->t_op = JSOP_BITOR; c = TOK_ASSIGN; } else { c = TOK_BITOR; } break; case '^': if (MatchChar(ts, '=')) { tp->t_op = JSOP_BITXOR; c = TOK_ASSIGN; } else { c = TOK_BITXOR; } break; case '&': if (MatchChar(ts, c)) { c = TOK_AND; } else if (MatchChar(ts, '=')) { tp->t_op = JSOP_BITAND; c = TOK_ASSIGN; } else { c = TOK_BITAND; } break; case '=': if (MatchChar(ts, c)) { #if JS_HAS_TRIPLE_EQOPS tp->t_op = MatchChar(ts, c) ? JSOP_NEW_EQ : (JSOp)cx->jsop_eq; #else tp->t_op = cx->jsop_eq; #endif c = TOK_EQOP; } else { tp->t_op = JSOP_NOP; c = TOK_ASSIGN; } break; case '!': if (MatchChar(ts, '=')) { #if JS_HAS_TRIPLE_EQOPS tp->t_op = MatchChar(ts, '=') ? JSOP_NEW_NE : (JSOp)cx->jsop_ne; #else tp->t_op = cx->jsop_ne; #endif c = TOK_EQOP; } else { tp->t_op = JSOP_NOT; c = TOK_UNARYOP; } break; case '<': /* NB: treat HTML begin-comment as comment-till-end-of-line */ if (MatchChar(ts, '!')) { if (MatchChar(ts, '-')) { if (MatchChar(ts, '-')) goto skipline; UngetChar(ts, '-'); } UngetChar(ts, '!'); } if (MatchChar(ts, c)) { tp->t_op = JSOP_LSH; c = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_SHOP; } else { tp->t_op = MatchChar(ts, '=') ? JSOP_LE : JSOP_LT; c = TOK_RELOP; } break; case '>': if (MatchChar(ts, c)) { tp->t_op = MatchChar(ts, c) ? JSOP_URSH : JSOP_RSH; c = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_SHOP; } else { tp->t_op = MatchChar(ts, '=') ? JSOP_GE : JSOP_GT; c = TOK_RELOP; } break; case '*': tp->t_op = JSOP_MUL; c = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_STAR; break; case '/': if (MatchChar(ts, '/')) { skipline: while ((c = GetChar(ts)) != EOF && c != '\n') /* skip to end of line */; UngetChar(ts, c); goto retry; } if (MatchChar(ts, '*')) { while ((c = GetChar(ts)) != EOF && !(c == '*' && MatchChar(ts, '/'))) { /* Ignore all characters until comment close. */ } if (c == EOF) { js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_UNTERMINATED_COMMENT); RETURN(TOK_ERROR); } goto retry; } #if JS_HAS_REGEXPS if (ts->flags & TSF_REGEXP) { JSObject *obj; uintN flags; INIT_TOKENBUF(&ts->tokenbuf); while ((c = GetChar(ts)) != '/') { if (c == '\n' || c == EOF) { UngetChar(ts, c); js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_UNTERMINATED_REGEXP); RETURN(TOK_ERROR); } if (c == '\\') { if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c)) RETURN(TOK_ERROR); c = GetChar(ts); } if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c)) RETURN(TOK_ERROR); } FINISH_TOKENBUF(&ts->tokenbuf); for (flags = 0; ; ) { if (MatchChar(ts, 'g')) flags |= JSREG_GLOB; else if (MatchChar(ts, 'i')) flags |= JSREG_FOLD; else if (MatchChar(ts, 'm')) flags |= JSREG_MULTILINE; else break; } c = PeekChar(ts); if (JS7_ISLET(c)) { tp->ptr = ts->linebuf.ptr - 1; js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_BAD_REGEXP_FLAG); (void) GetChar(ts); RETURN(TOK_ERROR); } obj = js_NewRegExpObject(cx, ts, ts->tokenbuf.base, TOKEN_LENGTH(&ts->tokenbuf), flags); if (!obj) RETURN(TOK_ERROR); atom = js_AtomizeObject(cx, obj, 0); if (!atom) RETURN(TOK_ERROR); tp->t_op = JSOP_OBJECT; tp->t_atom = atom; RETURN(TOK_OBJECT); } #endif /* JS_HAS_REGEXPS */ tp->t_op = JSOP_DIV; c = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_DIVOP; break; case '%': tp->t_op = JSOP_MOD; c = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_DIVOP; break; case '~': tp->t_op = JSOP_BITNOT; c = TOK_UNARYOP; break; case '+': if (MatchChar(ts, '=')) { tp->t_op = JSOP_ADD; c = TOK_ASSIGN; } else if (MatchChar(ts, c)) { c = TOK_INC; } else { tp->t_op = JSOP_POS; c = TOK_PLUS; } break; case '-': if (MatchChar(ts, '=')) { tp->t_op = JSOP_SUB; c = TOK_ASSIGN; } else if (MatchChar(ts, c)) { if (PeekChar(ts) == '>' && !(ts->flags & TSF_DIRTYLINE)) goto skipline; c = TOK_DEC; } else { tp->t_op = JSOP_NEG; c = TOK_MINUS; } ts->flags |= TSF_DIRTYLINE; break; #if JS_HAS_SHARP_VARS case '#': { uint32 n; c = GetChar(ts); if (!JS7_ISDEC(c)) { UngetChar(ts, c); goto badchar; } n = (uint32)JS7_UNDEC(c); for (;;) { c = GetChar(ts); if (!JS7_ISDEC(c)) break; n = 10 * n + JS7_UNDEC(c); if (n >= ATOM_INDEX_LIMIT) { js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_SHARPVAR_TOO_BIG); RETURN(TOK_ERROR); } } tp->t_dval = (jsdouble) n; if (JS_HAS_STRICT_OPTION(cx) && (c == '=' || c == '#')) { char buf[20]; JS_snprintf(buf, sizeof buf, "#%u%c", n, c); if (!js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_WARNING | JSREPORT_STRICT, JSMSG_DEPRECATED_USAGE, buf)) { RETURN(TOK_ERROR); } } if (c == '=') RETURN(TOK_DEFSHARP); if (c == '#') RETURN(TOK_USESHARP); goto badchar; } badchar: #endif /* JS_HAS_SHARP_VARS */ default: js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_ILLEGAL_CHARACTER); RETURN(TOK_ERROR); } JS_ASSERT(c < TOK_LIMIT); RETURN((JSTokenType)c); #undef INIT_TOKENBUF #undef FINISH_TOKENBUF #undef TOKEN_LENGTH #undef RETURN }