org.mozilla.javascript.NativeJSON Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rhino Show documentation
Show all versions of rhino Show documentation
The Rhino JavaScript Engine for Java
The newest version!
/* -*- Mode: java; tab-width: 4; indent-tabs-mode: 1; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.javascript;
import org.mozilla.javascript.json.JsonParser;
import java.util.Stack;
import java.util.Collection;
import java.util.Iterator;
import java.util.Arrays;
import java.util.List;
import java.util.LinkedList;
/**
* This class implements the JSON native object.
* See ECMA 15.12.
* @author Matthew Crumley, Raphael Speyer
*/
public final class NativeJSON extends IdScriptableObject
{
static final long serialVersionUID = -4567599697595654984L;
private static final Object JSON_TAG = "JSON";
private static final int MAX_STRINGIFY_GAP_LENGTH = 10;
static void init(Scriptable scope, boolean sealed)
{
NativeJSON obj = new NativeJSON();
obj.activatePrototypeMap(MAX_ID);
obj.setPrototype(getObjectPrototype(scope));
obj.setParentScope(scope);
if (sealed) { obj.sealObject(); }
ScriptableObject.defineProperty(scope, "JSON", obj,
ScriptableObject.DONTENUM);
}
private NativeJSON()
{
}
@Override
public String getClassName() { return "JSON"; }
@Override
protected void initPrototypeId(int id)
{
if (id <= LAST_METHOD_ID) {
String name;
int arity;
switch (id) {
case Id_toSource: arity = 0; name = "toSource"; break;
case Id_parse: arity = 2; name = "parse"; break;
case Id_stringify: arity = 3; name = "stringify"; break;
default: throw new IllegalStateException(String.valueOf(id));
}
initPrototypeMethod(JSON_TAG, id, name, arity);
} else {
throw new IllegalStateException(String.valueOf(id));
}
}
@Override
public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope,
Scriptable thisObj, Object[] args)
{
if (!f.hasTag(JSON_TAG)) {
return super.execIdCall(f, cx, scope, thisObj, args);
}
int methodId = f.methodId();
switch (methodId) {
case Id_toSource:
return "JSON";
case Id_parse: {
String jtext = ScriptRuntime.toString(args, 0);
Object reviver = null;
if (args.length > 1) {
reviver = args[1];
}
if (reviver instanceof Callable) {
return parse(cx, scope, jtext, (Callable) reviver);
} else {
return parse(cx, scope, jtext);
}
}
case Id_stringify: {
Object value = null, replacer = null, space = null;
switch (args.length) {
default:
case 3: space = args[2];
case 2: replacer = args[1];
case 1: value = args[0];
case 0:
}
return stringify(cx, scope, value, replacer, space);
}
default: throw new IllegalStateException(String.valueOf(methodId));
}
}
private static Object parse(Context cx, Scriptable scope, String jtext) {
try {
return new JsonParser(cx, scope).parseValue(jtext);
} catch (JsonParser.ParseException ex) {
throw ScriptRuntime.constructError("SyntaxError", ex.getMessage());
}
}
public static Object parse(Context cx, Scriptable scope, String jtext,
Callable reviver)
{
Object unfiltered = parse(cx, scope, jtext);
Scriptable root = cx.newObject(scope);
root.put("", root, unfiltered);
return walk(cx, scope, reviver, root, "");
}
private static Object walk(Context cx, Scriptable scope, Callable reviver,
Scriptable holder, Object name)
{
final Object property;
if (name instanceof Number) {
property = holder.get( ((Number) name).intValue(), holder);
} else {
property = holder.get( ((String) name), holder);
}
if (property instanceof Scriptable) {
Scriptable val = ((Scriptable) property);
if (val instanceof NativeArray) {
long len = ((NativeArray) val).getLength();
for (long i = 0; i < len; i++) {
// indices greater than MAX_INT are represented as strings
if (i > Integer.MAX_VALUE) {
String id = Long.toString(i);
Object newElement = walk(cx, scope, reviver, val, id);
if (newElement == Undefined.instance) {
val.delete(id);
} else {
val.put(id, val, newElement);
}
} else {
int idx = (int) i;
Object newElement = walk(cx, scope, reviver, val, idx);
if (newElement == Undefined.instance) {
val.delete(idx);
} else {
val.put(idx, val, newElement);
}
}
}
} else {
Object[] keys = val.getIds();
for (Object p : keys) {
Object newElement = walk(cx, scope, reviver, val, p);
if (newElement == Undefined.instance) {
if (p instanceof Number)
val.delete(((Number) p).intValue());
else
val.delete((String) p);
} else {
if (p instanceof Number)
val.put(((Number) p).intValue(), val, newElement);
else
val.put((String) p, val, newElement);
}
}
}
}
return reviver.call(cx, scope, holder, new Object[] { name, property });
}
private static String repeat(char c, int count) {
char chars[] = new char[count];
Arrays.fill(chars, c);
return new String(chars);
}
private static class StringifyState {
StringifyState(Context cx, Scriptable scope, String indent, String gap,
Callable replacer, List
© 2015 - 2024 Weber Informatics LLC | Privacy Policy