summaryrefslogtreecommitdiff
path: root/java/src/json/ext/Parser.rl
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/json/ext/Parser.rl')
-rw-r--r--java/src/json/ext/Parser.rl56
1 files changed, 42 insertions, 14 deletions
diff --git a/java/src/json/ext/Parser.rl b/java/src/json/ext/Parser.rl
index 00badc8..642e56c 100644
--- a/java/src/json/ext/Parser.rl
+++ b/java/src/json/ext/Parser.rl
@@ -18,6 +18,7 @@ import org.jruby.RubyNumeric;
import org.jruby.RubyObject;
import org.jruby.RubyString;
import org.jruby.anno.JRubyMethod;
+import org.jruby.exceptions.JumpException;
import org.jruby.exceptions.RaiseException;
import org.jruby.runtime.Block;
import org.jruby.runtime.ObjectAllocator;
@@ -44,11 +45,13 @@ public class Parser extends RubyObject {
private final RuntimeInfo info;
private RubyString vSource;
private RubyString createId;
+ private boolean createAdditions;
private int maxNesting;
private boolean allowNaN;
private boolean symbolizeNames;
private RubyClass objectClass;
private RubyClass arrayClass;
+ private RubyHash match;
private static final int DEFAULT_MAX_NESTING = 19;
@@ -139,20 +142,18 @@ public class Parser extends RubyObject {
@JRubyMethod(required = 1, optional = 1, visibility = Visibility.PRIVATE)
public IRubyObject initialize(ThreadContext context, IRubyObject[] args) {
- Ruby runtime = context.getRuntime();
+ Ruby runtime = context.getRuntime();
RubyString source = convertEncoding(context, args[0].convertToString());
- OptionsReader opts =
- new OptionsReader(context, args.length > 1 ? args[1] : null);
-
- this.maxNesting = opts.getInt("max_nesting", DEFAULT_MAX_NESTING);
- this.allowNaN = opts.getBool("allow_nan", false);
- this.symbolizeNames = opts.getBool("symbolize_names", false);
- this.createId =
- opts.getBool("create_additions", true) ? getCreateId(context)
- : null;
- this.objectClass = opts.getClass("object_class", runtime.getHash());
- this.arrayClass = opts.getClass("array_class", runtime.getArray());
+ OptionsReader opts = new OptionsReader(context, args.length > 1 ? args[1] : null);
+ this.maxNesting = opts.getInt("max_nesting", DEFAULT_MAX_NESTING);
+ this.allowNaN = opts.getBool("allow_nan", false);
+ this.symbolizeNames = opts.getBool("symbolize_names", false);
+ this.createId = opts.getString("create_id", getCreateId(context));
+ this.createAdditions = opts.getBool("create_additions", true);
+ this.objectClass = opts.getClass("object_class", runtime.getHash());
+ this.arrayClass = opts.getClass("array_class", runtime.getArray());
+ this.match = opts.getHash("match");
this.vSource = source;
return this;
@@ -545,12 +546,39 @@ public class Parser extends RubyObject {
ParserResult parseString(int p, int pe) {
int cs = EVIL;
- RubyString result = null;
+ IRubyObject result = null;
%% write init;
int memo = p;
%% write exec;
+ if (parser.createAdditions) {
+ RubyHash match = parser.match;
+ if (match != null) {
+ final RubyArray memoArray = RubyArray.newArray(context.getRuntime(), 2);
+ memoArray.add(result);
+ try {
+ match.visitAll(new RubyHash.Visitor() {
+ @Override
+ public void visit(IRubyObject pattern, IRubyObject klass) {
+ if (pattern.callMethod(context, "===", memoArray.entry(0)).isTrue()) {
+ memoArray.add(klass);
+ throw JumpException.SPECIAL_JUMP;
+ }
+ }
+ });
+ } catch (JumpException e) { }
+ IRubyObject matched = memoArray.entry(1);
+ if (!matched.isNil()) {
+ RubyClass klass = (RubyClass) matched;
+ if (klass.respondsTo("json_creatable?") &&
+ klass.callMethod(context, "json_creatable?").isTrue()) {
+ result = klass.callMethod(context, "json_create", result);
+ }
+ }
+ }
+ }
+
if (cs >= JSON_string_first_final && result != null) {
return new ParserResult(result, p + 1);
} else {
@@ -692,7 +720,7 @@ public class Parser extends RubyObject {
IRubyObject returnedResult = result;
// attempt to de-serialize object
- if (parser.createId != null) {
+ if (parser.createAdditions) {
IRubyObject vKlassName = result.op_aref(context, parser.createId);
if (!vKlassName.isNil()) {
// might throw ArgumentError, we let it propagate