diff --git a/src/main/java/com/annimon/ownlang/lib/ValueUtils.java b/src/main/java/com/annimon/ownlang/lib/ValueUtils.java index 016315c..ef379a6 100644 --- a/src/main/java/com/annimon/ownlang/lib/ValueUtils.java +++ b/src/main/java/com/annimon/ownlang/lib/ValueUtils.java @@ -1,133 +1,133 @@ -package com.annimon.ownlang.lib; - -import com.annimon.ownlang.exceptions.TypeException; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.Iterator; -import java.util.Map; -import org.json.JSONArray; -import org.json.JSONObject; - -public final class ValueUtils { - - private ValueUtils() { } - - public static Object toObject(Value val) { - switch (val.type()) { - case Types.ARRAY: - return toObject((ArrayValue) val); - case Types.MAP: - return toObject((MapValue) val); - case Types.NUMBER: - return val.raw(); - case Types.STRING: - return val.asString(); - default: - return JSONObject.NULL; - } - } - - public static Object toObject(MapValue map) { - final JSONObject result = new JSONObject(); - for (Map.Entry entry : map) { - final String key = entry.getKey().asString(); - final Object value = toObject(entry.getValue()); - result.put(key, value); - } - return result; - } - - public static Object toObject(ArrayValue array) { - final JSONArray result = new JSONArray(); - for (Value value : array) { - result.put(toObject(value)); - } - return result; - } - - public static Value toValue(Object obj) { - if (obj instanceof JSONObject) { - return toValue((JSONObject) obj); - } - if (obj instanceof JSONArray) { - return toValue((JSONArray) obj); - } - if (obj instanceof String) { - return new StringValue((String) obj); - } - if (obj instanceof Number) { - return NumberValue.of(((Number) obj)); - } - if (obj instanceof Boolean) { - return NumberValue.fromBoolean((Boolean) obj); - } - // NULL or other - return NumberValue.ZERO; - } - - public static MapValue toValue(JSONObject json) { - final MapValue result = new MapValue(json.length()); - final Iterator it = json.keys(); - while(it.hasNext()) { - final String key = it.next(); - final Value value = toValue(json.get(key)); - result.set(new StringValue(key), value); - } - return result; - } - - public static ArrayValue toValue(JSONArray json) { - final int length = json.length(); - final ArrayValue result = new ArrayValue(length); - for (int i = 0; i < length; i++) { - final Value value = toValue(json.get(i)); - result.set(i, value); - } - return result; - } - - public static Number getNumber(Value value) { - if (value.type() == Types.NUMBER) return ((NumberValue) value).raw(); - return value.asInt(); - } - - public static float getFloatNumber(Value value) { - if (value.type() == Types.NUMBER) return ((NumberValue) value).raw().floatValue(); - return (float) value.asNumber(); - } - - public static byte[] toByteArray(ArrayValue array) { - final int size = array.size(); - final byte[] result = new byte[size]; - for (int i = 0; i < size; i++) { - result[i] = (byte) array.get(i).asInt(); - } - return result; - } - - public static Function consumeFunction(Value value, int argumentNumber) { - return consumeFunction(value, " at argument " + (argumentNumber + 1)); - } - - public static Function consumeFunction(Value value, String errorMessage) { - final int type = value.type(); - if (type != Types.FUNCTION) { - throw new TypeException("Function expected" + errorMessage - + ", but found " + Types.typeToString(type)); - } - return ((FunctionValue) value).getValue(); - } - - public static MapValue collectNumberConstants(Class clazz, Class type) { - MapValue result = new MapValue(20); - for (Field field : clazz.getDeclaredFields()) { - if (!Modifier.isStatic(field.getModifiers())) continue; - if (!field.getType().equals(type)) continue; - try { - result.set(field.getName(), NumberValue.of((T) field.get(type))); - } catch (IllegalAccessException ignore) { - } - } - return result; - } -} +package com.annimon.ownlang.lib; + +import com.annimon.ownlang.exceptions.TypeException; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Iterator; +import java.util.Map; +import org.json.JSONArray; +import org.json.JSONObject; + +public final class ValueUtils { + + private ValueUtils() { } + + public static Object toObject(Value val) { + switch (val.type()) { + case Types.ARRAY: + return toObject((ArrayValue) val); + case Types.MAP: + return toObject((MapValue) val); + case Types.NUMBER: + return val.raw(); + case Types.STRING: + return val.asString(); + default: + return JSONObject.NULL; + } + } + + public static JSONObject toObject(MapValue map) { + final JSONObject result = new JSONObject(); + for (Map.Entry entry : map) { + final String key = entry.getKey().asString(); + final Object value = toObject(entry.getValue()); + result.put(key, value); + } + return result; + } + + public static JSONArray toObject(ArrayValue array) { + final JSONArray result = new JSONArray(); + for (Value value : array) { + result.put(toObject(value)); + } + return result; + } + + public static Value toValue(Object obj) { + if (obj instanceof JSONObject) { + return toValue((JSONObject) obj); + } + if (obj instanceof JSONArray) { + return toValue((JSONArray) obj); + } + if (obj instanceof String) { + return new StringValue((String) obj); + } + if (obj instanceof Number) { + return NumberValue.of(((Number) obj)); + } + if (obj instanceof Boolean) { + return NumberValue.fromBoolean((Boolean) obj); + } + // NULL or other + return NumberValue.ZERO; + } + + public static MapValue toValue(JSONObject json) { + final MapValue result = new MapValue(json.length()); + final Iterator it = json.keys(); + while(it.hasNext()) { + final String key = it.next(); + final Value value = toValue(json.get(key)); + result.set(new StringValue(key), value); + } + return result; + } + + public static ArrayValue toValue(JSONArray json) { + final int length = json.length(); + final ArrayValue result = new ArrayValue(length); + for (int i = 0; i < length; i++) { + final Value value = toValue(json.get(i)); + result.set(i, value); + } + return result; + } + + public static Number getNumber(Value value) { + if (value.type() == Types.NUMBER) return ((NumberValue) value).raw(); + return value.asInt(); + } + + public static float getFloatNumber(Value value) { + if (value.type() == Types.NUMBER) return ((NumberValue) value).raw().floatValue(); + return (float) value.asNumber(); + } + + public static byte[] toByteArray(ArrayValue array) { + final int size = array.size(); + final byte[] result = new byte[size]; + for (int i = 0; i < size; i++) { + result[i] = (byte) array.get(i).asInt(); + } + return result; + } + + public static Function consumeFunction(Value value, int argumentNumber) { + return consumeFunction(value, " at argument " + (argumentNumber + 1)); + } + + public static Function consumeFunction(Value value, String errorMessage) { + final int type = value.type(); + if (type != Types.FUNCTION) { + throw new TypeException("Function expected" + errorMessage + + ", but found " + Types.typeToString(type)); + } + return ((FunctionValue) value).getValue(); + } + + public static MapValue collectNumberConstants(Class clazz, Class type) { + MapValue result = new MapValue(20); + for (Field field : clazz.getDeclaredFields()) { + if (!Modifier.isStatic(field.getModifiers())) continue; + if (!field.getType().equals(type)) continue; + try { + result.set(field.getName(), NumberValue.of((T) field.get(type))); + } catch (IllegalAccessException ignore) { + } + } + return result; + } +} diff --git a/src/main/java/com/annimon/ownlang/modules/json/json_encode.java b/src/main/java/com/annimon/ownlang/modules/json/json_encode.java index 7222124..a7b4e64 100644 --- a/src/main/java/com/annimon/ownlang/modules/json/json_encode.java +++ b/src/main/java/com/annimon/ownlang/modules/json/json_encode.java @@ -1,25 +1,57 @@ package com.annimon.ownlang.modules.json; import com.annimon.ownlang.lib.Arguments; +import com.annimon.ownlang.lib.ArrayValue; import com.annimon.ownlang.lib.Function; +import com.annimon.ownlang.lib.MapValue; import com.annimon.ownlang.lib.StringValue; +import com.annimon.ownlang.lib.Types; import com.annimon.ownlang.lib.Value; import com.annimon.ownlang.lib.ValueUtils; import org.json.JSONException; import org.json.JSONObject; +import org.json.JSONWriter; public final class json_encode implements Function { @Override - public Value execute(Value... args) { - Arguments.check(1, args.length); + public Value execute(Value[] args) { + Arguments.checkOrOr(1, 2, args.length); try { - final Object root = ValueUtils.toObject(args[0]); - final String jsonRaw = JSONObject.valueToString(root); + final int indent; + if (args.length == 2) { + indent = args[1].asInt(); + } else { + indent = 0; + } + + final String jsonRaw; + if (indent > 0) { + jsonRaw = format(args[0], indent); + } else { + final Object root = ValueUtils.toObject(args[0]); + jsonRaw = JSONWriter.valueToString(root); + } return new StringValue(jsonRaw); + } catch (JSONException ex) { throw new RuntimeException("Error while creating json", ex); } } + + private String format(Value val, int indent) { + switch (val.type()) { + case Types.ARRAY: + return ValueUtils.toObject((ArrayValue) val).toString(indent); + case Types.MAP: + return ValueUtils.toObject((MapValue) val).toString(indent); + case Types.NUMBER: + return JSONWriter.valueToString(val.raw()); + case Types.STRING: + return JSONWriter.valueToString(val.asString()); + default: + return JSONWriter.valueToString(JSONObject.NULL); + } + } } \ No newline at end of file