src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSONFunctions.java
Print this page
*** 23,47 ****
* questions.
*/
package jdk.nashorn.internal.runtime;
- import static jdk.nashorn.internal.runtime.Source.sourceFor;
-
import java.lang.invoke.MethodHandle;
import java.util.Iterator;
import java.util.concurrent.Callable;
! import jdk.nashorn.internal.ir.LiteralNode;
! import jdk.nashorn.internal.ir.Node;
! import jdk.nashorn.internal.ir.ObjectNode;
! import jdk.nashorn.internal.ir.PropertyNode;
! import jdk.nashorn.internal.ir.UnaryNode;
import jdk.nashorn.internal.objects.Global;
import jdk.nashorn.internal.parser.JSONParser;
! import jdk.nashorn.internal.parser.TokenType;
import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
/**
* Utilities used by "JSON" object implementation.
*/
public final class JSONFunctions {
--- 23,45 ----
* questions.
*/
package jdk.nashorn.internal.runtime;
import java.lang.invoke.MethodHandle;
+ import java.util.ArrayList;
import java.util.Iterator;
+ import java.util.List;
+ import java.util.Map;
import java.util.concurrent.Callable;
! import jdk.nashorn.internal.codegen.ObjectClassGenerator;
import jdk.nashorn.internal.objects.Global;
import jdk.nashorn.internal.parser.JSONParser;
! import jdk.nashorn.internal.runtime.arrays.ArrayData;
import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
+ import jdk.nashorn.internal.scripts.JO;
/**
* Utilities used by "JSON" object implementation.
*/
public final class JSONFunctions {
*** 77,98 ****
* @param reviver optional value: function that takes two parameters (key, value)
* @return Object representation of JSON text given
*/
public static Object parse(final Object text, final Object reviver) {
final String str = JSType.toString(text);
! final JSONParser parser = new JSONParser(sourceFor("<json>", str), new Context.ThrowErrorManager());
!
! Node node;
try {
! node = parser.parse();
} catch (final ParserException e) {
throw ECMAErrors.syntaxError(e, "invalid.json", e.getMessage());
}
! final Global global = Context.getGlobal();
! final Object unfiltered = convertNode(global, node);
return applyReviver(global, unfiltered, reviver);
}
// -- Internals only below this point
--- 75,95 ----
* @param reviver optional value: function that takes two parameters (key, value)
* @return Object representation of JSON text given
*/
public static Object parse(final Object text, final Object reviver) {
final String str = JSType.toString(text);
! final Global global = Context.getGlobal();
! final JSONParser parser = new JSONParser(str);
! final Object value;
try {
! value = parser.parse();
} catch (final ParserException e) {
throw ECMAErrors.syntaxError(e, "invalid.json", e.getMessage());
}
! final Object unfiltered = convert(global, Global.objectPrototype(), value);
return applyReviver(global, unfiltered, reviver);
}
// -- Internals only below this point
*** 135,196 ****
} catch(final Throwable t) {
throw new RuntimeException(t);
}
}
! // Converts IR node to runtime value
! private static Object convertNode(final Global global, final Node node) {
! if (node instanceof LiteralNode) {
! // check for array literal
! if (node.tokenType() == TokenType.ARRAY) {
! assert node instanceof LiteralNode.ArrayLiteralNode;
! final Node[] elements = ((LiteralNode.ArrayLiteralNode)node).getValue();
!
! // NOTE: We cannot use LiteralNode.isNumericArray() here as that
! // method uses symbols of element nodes. Since we don't do lower
! // pass, there won't be any symbols!
! if (isNumericArray(elements)) {
! final double[] values = new double[elements.length];
int index = 0;
! for (final Node elem : elements) {
! values[index++] = JSType.toNumber(convertNode(global, elem));
}
return global.wrapAsObject(values);
}
! final Object[] values = new Object[elements.length];
int index = 0;
! for (final Node elem : elements) {
! values[index++] = convertNode(global, elem);
}
return global.wrapAsObject(values);
}
! return ((LiteralNode<?>)node).getValue();
!
! } else if (node instanceof ObjectNode) {
! final ObjectNode objNode = (ObjectNode) node;
! final ScriptObject object = global.newObject();
!
! for (final PropertyNode pNode: objNode.getElements()) {
! final Node valueNode = pNode.getValue();
!
! final String name = pNode.getKeyName();
! final Object value = convertNode(global, valueNode);
! setPropertyValue(object, name, value);
}
! return object;
! } else if (node instanceof UnaryNode) {
! // UnaryNode used only to represent negative number JSON value
! final UnaryNode unaryNode = (UnaryNode)node;
! return -((LiteralNode<?>)unaryNode.getExpression()).getNumber();
} else {
! return null;
}
}
// add a new property if does not exist already, or else set old property
private static void setPropertyValue(final ScriptObject sobj, final String name, final Object value) {
--- 132,229 ----
} catch(final Throwable t) {
throw new RuntimeException(t);
}
}
! // Converts collections to JS objects
! @SuppressWarnings("unchecked")
! private static Object convert(final Global global, final ScriptObject objectProto, final Object value) {
! if (value instanceof Map) {
!
! final Map<String, Object> map = (Map) value;
! final int length = map.size();
! final List<Property> properties = new ArrayList<>(length);
! final Object[] objectSpill = new Object[length];
! final long[] primitiveSpill = new long[length];
! ArrayData arrayData = ArrayData.EMPTY_ARRAY;
! int slot = 0;
!
! for (final Map.Entry<String, Object> entry : map.entrySet()) {
! final String name = entry.getKey();
! final Object convertedValue = convert(global, objectProto, entry.getValue());
! final int index = ArrayIndex.getArrayIndex(name);
! if (ArrayIndex.isValidArrayIndex(index)) {
! // array index key
! final long oldLength = arrayData.length();
! final long longIndex = ArrayIndex.toLongIndex(index);
! if (longIndex > oldLength) {
! if (arrayData.canDelete(oldLength, longIndex - 1, false)) {
! arrayData = arrayData.delete(oldLength, longIndex - 1);
! }
! }
! arrayData = arrayData.ensure(longIndex).set(index, convertedValue, false);
! } else {
! // ordinary property key
! final Class<?> type;
! if (ObjectClassGenerator.OBJECT_FIELDS_ONLY) {
! objectSpill[slot] = convertedValue;
! type = Object.class;
! } else {
! type = getType(convertedValue);
! if (type == Object.class) {
! objectSpill[slot] = convertedValue;
! } else {
! primitiveSpill[slot] = ObjectClassGenerator.pack((Number) convertedValue);
! }
! }
! final Property property = new SpillProperty(name, 0, slot++);
! property.setType(type);
! properties.add(property);
! }
! }
!
! final ScriptObject result = new JO(PropertyMap.newMap(properties), primitiveSpill, objectSpill);
! result.setInitialProto(objectProto);
! result.setArray(arrayData);
! return result;
!
! } else if (value instanceof List) {
!
! final List<Object> list = (List) value;
! if (isNumericArray(list)) {
! final double[] values = new double[list.size()];
int index = 0;
! for (final Object obj : list) {
! values[index++] = JSType.toNumber(obj);
}
return global.wrapAsObject(values);
}
! final Object[] values = new Object[list.size()];
int index = 0;
! for (final Object elem : list) {
! values[index++] = convert(global, objectProto, elem);
}
return global.wrapAsObject(values);
}
! return value;
}
!
! private static Class<?> getType(final Object value) {
! if (value instanceof Integer) {
! return int.class;
! } else if (value instanceof Long) {
! return long.class;
! } else if (value instanceof Double) {
! return double.class;
} else {
! return Object.class;
}
}
// add a new property if does not exist already, or else set old property
private static void setPropertyValue(final ScriptObject sobj, final String name, final Object value) {
*** 205,220 ****
// add new property
sobj.addOwnProperty(name, Property.WRITABLE_ENUMERABLE_CONFIGURABLE, value);
}
}
! // does the given IR node represent a numeric array?
! private static boolean isNumericArray(final Node[] values) {
! for (final Node node : values) {
! if (node instanceof LiteralNode && ((LiteralNode<?>)node).getValue() instanceof Number) {
! continue;
! }
return false;
}
return true;
}
}
--- 238,252 ----
// add new property
sobj.addOwnProperty(name, Property.WRITABLE_ENUMERABLE_CONFIGURABLE, value);
}
}
! // does the given list represent a numeric array?
! private static boolean isNumericArray(final List<Object> list) {
! for (final Object obj : list) {
! if (!(obj instanceof Number)) {
return false;
}
+ }
return true;
}
}