inline bool JSONParser::finishArray(MutableHandleValue vp, ElementVector &elements) { JS_ASSERT(&elements == &stack.back().elements()); JSObject *obj = NewDenseCopiedArray(cx, elements.length(), elements.begin()); if (!obj) return false; /* Try to assign a new type to the array according to its elements. */ cx->compartment()->types.fixArrayType(cx, obj); vp.setObject(*obj); if (!freeElements.append(&elements)) return false; stack.popBack(); return true; }
inline bool JSONParserBase::finishArray(MutableHandleValue vp, ElementVector& elements) { MOZ_ASSERT(&elements == &stack.back().elements()); JSObject* obj = ObjectGroup::newArrayObject(cx, elements.begin(), elements.length(), GenericObject); if (!obj) return false; vp.setObject(*obj); if (!freeElements.append(&elements)) return false; stack.popBack(); if (!stack.empty() && stack.back().state == FinishArrayElement) { const ElementVector& elements = stack.back().elements(); if (!CombineArrayElementTypes(cx, obj, elements.begin(), elements.length())) return false; } return true; }
bool JSONParser::parse(MutableHandleValue vp) { RootedValue value(cx); JS_ASSERT(stack.empty()); vp.setUndefined(); Token token; ParserState state = JSONValue; while (true) { switch (state) { case FinishObjectMember: { PropertyVector &properties = stack.back().properties(); properties.back().value = value; token = advanceAfterProperty(); if (token == ObjectClose) { if (!finishObject(&value, properties)) return false; break; } if (token != Comma) { if (token == OOM) return false; if (token != Error) error("expected ',' or '}' after property-value pair in object literal"); return errorReturn(); } token = advancePropertyName(); /* FALL THROUGH */ } JSONMember: if (token == String) { jsid id = AtomToId(atomValue()); PropertyVector &properties = stack.back().properties(); if (!properties.append(IdValuePair(id))) return false; token = advancePropertyColon(); if (token != Colon) { JS_ASSERT(token == Error); return errorReturn(); } goto JSONValue; } if (token == OOM) return false; if (token != Error) error("property names must be double-quoted strings"); return errorReturn(); case FinishArrayElement: { ElementVector &elements = stack.back().elements(); if (!elements.append(value.get())) return false; token = advanceAfterArrayElement(); if (token == Comma) goto JSONValue; if (token == ArrayClose) { if (!finishArray(&value, elements)) return false; break; } JS_ASSERT(token == Error); return errorReturn(); } JSONValue: case JSONValue: token = advance(); JSONValueSwitch: switch (token) { case String: value = stringValue(); break; case Number: value = numberValue(); break; case True: value = BooleanValue(true); break; case False: value = BooleanValue(false); break; case Null: value = NullValue(); break; case ArrayOpen: { ElementVector *elements; if (!freeElements.empty()) { elements = freeElements.popCopy(); elements->clear(); } else { elements = cx->new_<ElementVector>(cx); if (!elements) return false; } if (!stack.append(elements)) return false; token = advance(); if (token == ArrayClose) { if (!finishArray(&value, *elements)) return false; break; } goto JSONValueSwitch; } case ObjectOpen: { PropertyVector *properties; if (!freeProperties.empty()) { properties = freeProperties.popCopy(); properties->clear(); } else { properties = cx->new_<PropertyVector>(cx); if (!properties) return false; } if (!stack.append(properties)) return false; token = advanceAfterObjectOpen(); if (token == ObjectClose) { if (!finishObject(&value, *properties)) return false; break; } goto JSONMember; } case ArrayClose: case ObjectClose: case Colon: case Comma: // Move the current pointer backwards so that the position // reported in the error message is correct. --current; error("unexpected character"); return errorReturn(); case OOM: return false; case Error: return errorReturn(); } break; } if (stack.empty()) break; state = stack.back().state; } for (; current < end; current++) { if (!IsJSONWhitespace(*current)) { error("unexpected non-whitespace character after JSON data"); return errorReturn(); } } JS_ASSERT(end == current); JS_ASSERT(stack.empty()); vp.set(value); return true; }