diff options
author | Florian Frank <flori@ping.de> | 2010-10-05 18:56:08 +0200 |
---|---|---|
committer | Florian Frank <flori@ping.de> | 2011-01-02 21:13:57 +0100 |
commit | 7d20dd9bce9f333c451d074cc0d2ac90560399e0 (patch) | |
tree | daf2ecc5698df7348ca2b1fd7b4f24baaccc7bad /java | |
parent | 8714f0a88ccee67ea7ca1a9d5a40d9cf1c6dd5fb (diff) | |
download | json-7d20dd9bce9f333c451d074cc0d2ac90560399e0.tar.gz |
implement string matching for java parser
Diffstat (limited to 'java')
-rw-r--r-- | java/src/json/ext/OptionsReader.java | 15 | ||||
-rw-r--r-- | java/src/json/ext/Parser.java | 200 | ||||
-rw-r--r-- | java/src/json/ext/Parser.rl | 56 |
3 files changed, 169 insertions, 102 deletions
diff --git a/java/src/json/ext/OptionsReader.java b/java/src/json/ext/OptionsReader.java index 3bc8d5f..018ace4 100644 --- a/java/src/json/ext/OptionsReader.java +++ b/java/src/json/ext/OptionsReader.java @@ -74,15 +74,20 @@ final class OptionsReader { * converted to string */ ByteList getString(String key) { + RubyString str = getString(key, null); + return str == null ? null : str.getByteList().dup(); + } + + RubyString getString(String key, RubyString defaultValue) { IRubyObject value = get(key); - if (value == null || !value.isTrue()) return null; + if (value == null || !value.isTrue()) return defaultValue; RubyString str = value.convertToString(); RuntimeInfo info = getRuntimeInfo(); if (info.encodingsSupported() && str.encoding(context) != info.utf8) { str = (RubyString)str.encode(context, info.utf8); } - return str.getByteList().dup(); + return str; } /** @@ -105,4 +110,10 @@ final class OptionsReader { throw runtime.newTypeError(key + " option must be a subclass of " + defaultValue); } + + public RubyHash getHash(String key) { + IRubyObject value = get(key); + if (value == null || value.isNil()) return new RubyHash(runtime); + return (RubyHash) value; + } } diff --git a/java/src/json/ext/Parser.java b/java/src/json/ext/Parser.java index c8f6f3d..71e2c4a 100644 --- a/java/src/json/ext/Parser.java +++ b/java/src/json/ext/Parser.java @@ -20,6 +20,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; @@ -46,11 +47,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; @@ -141,20 +144,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; @@ -297,11 +298,11 @@ public class Parser extends RubyObject { } -// line 323 "Parser.rl" +// line 324 "Parser.rl" -// line 305 "Parser.java" +// line 306 "Parser.java" private static byte[] init__JSON_value_actions_0() { return new byte [] { @@ -415,7 +416,7 @@ static final int JSON_value_error = 0; static final int JSON_value_en_main = 1; -// line 429 "Parser.rl" +// line 430 "Parser.rl" ParserResult parseValue(int p, int pe) { @@ -423,14 +424,14 @@ static final int JSON_value_en_main = 1; IRubyObject result = null; -// line 427 "Parser.java" +// line 428 "Parser.java" { cs = JSON_value_start; } -// line 436 "Parser.rl" +// line 437 "Parser.rl" -// line 434 "Parser.java" +// line 435 "Parser.java" { int _klen; int _trans = 0; @@ -456,13 +457,13 @@ case 1: while ( _nacts-- > 0 ) { switch ( _JSON_value_actions[_acts++] ) { case 9: -// line 414 "Parser.rl" +// line 415 "Parser.rl" { p--; { p += 1; _goto_targ = 5; if (true) continue _goto;} } break; -// line 466 "Parser.java" +// line 467 "Parser.java" } } @@ -525,25 +526,25 @@ case 1: switch ( _JSON_value_actions[_acts++] ) { case 0: -// line 331 "Parser.rl" +// line 332 "Parser.rl" { result = getRuntime().getNil(); } break; case 1: -// line 334 "Parser.rl" +// line 335 "Parser.rl" { result = getRuntime().getFalse(); } break; case 2: -// line 337 "Parser.rl" +// line 338 "Parser.rl" { result = getRuntime().getTrue(); } break; case 3: -// line 340 "Parser.rl" +// line 341 "Parser.rl" { if (parser.allowNaN) { result = getConstant(CONST_NAN); @@ -553,7 +554,7 @@ case 1: } break; case 4: -// line 347 "Parser.rl" +// line 348 "Parser.rl" { if (parser.allowNaN) { result = getConstant(CONST_INFINITY); @@ -563,7 +564,7 @@ case 1: } break; case 5: -// line 354 "Parser.rl" +// line 355 "Parser.rl" { if (pe > p + 9 && absSubSequence(p, p + 9).toString().equals(JSON_MINUS_INFINITY)) { @@ -592,7 +593,7 @@ case 1: } break; case 6: -// line 380 "Parser.rl" +// line 381 "Parser.rl" { ParserResult res = parseString(p, pe); if (res == null) { @@ -605,7 +606,7 @@ case 1: } break; case 7: -// line 390 "Parser.rl" +// line 391 "Parser.rl" { currentNesting++; ParserResult res = parseArray(p, pe); @@ -620,7 +621,7 @@ case 1: } break; case 8: -// line 402 "Parser.rl" +// line 403 "Parser.rl" { currentNesting++; ParserResult res = parseObject(p, pe); @@ -634,7 +635,7 @@ case 1: } } break; -// line 638 "Parser.java" +// line 639 "Parser.java" } } } @@ -654,7 +655,7 @@ case 5: break; } } -// line 437 "Parser.rl" +// line 438 "Parser.rl" if (cs >= JSON_value_first_final && result != null) { return new ParserResult(result, p); @@ -664,7 +665,7 @@ case 5: } -// line 668 "Parser.java" +// line 669 "Parser.java" private static byte[] init__JSON_integer_actions_0() { return new byte [] { @@ -763,22 +764,22 @@ static final int JSON_integer_error = 0; static final int JSON_integer_en_main = 1; -// line 456 "Parser.rl" +// line 457 "Parser.rl" ParserResult parseInteger(int p, int pe) { int cs = EVIL; -// line 774 "Parser.java" +// line 775 "Parser.java" { cs = JSON_integer_start; } -// line 462 "Parser.rl" +// line 463 "Parser.rl" int memo = p; -// line 782 "Parser.java" +// line 783 "Parser.java" { int _klen; int _trans = 0; @@ -859,13 +860,13 @@ case 1: switch ( _JSON_integer_actions[_acts++] ) { case 0: -// line 450 "Parser.rl" +// line 451 "Parser.rl" { p--; { p += 1; _goto_targ = 5; if (true) continue _goto;} } break; -// line 869 "Parser.java" +// line 870 "Parser.java" } } } @@ -885,7 +886,7 @@ case 5: break; } } -// line 464 "Parser.rl" +// line 465 "Parser.rl" if (cs < JSON_integer_first_final) { return null; @@ -900,7 +901,7 @@ case 5: } -// line 904 "Parser.java" +// line 905 "Parser.java" private static byte[] init__JSON_float_actions_0() { return new byte [] { @@ -1002,22 +1003,22 @@ static final int JSON_float_error = 0; static final int JSON_float_en_main = 1; -// line 492 "Parser.rl" +// line 493 "Parser.rl" ParserResult parseFloat(int p, int pe) { int cs = EVIL; -// line 1013 "Parser.java" +// line 1014 "Parser.java" { cs = JSON_float_start; } -// line 498 "Parser.rl" +// line 499 "Parser.rl" int memo = p; -// line 1021 "Parser.java" +// line 1022 "Parser.java" { int _klen; int _trans = 0; @@ -1098,13 +1099,13 @@ case 1: switch ( _JSON_float_actions[_acts++] ) { case 0: -// line 483 "Parser.rl" +// line 484 "Parser.rl" { p--; { p += 1; _goto_targ = 5; if (true) continue _goto;} } break; -// line 1108 "Parser.java" +// line 1109 "Parser.java" } } } @@ -1124,7 +1125,7 @@ case 5: break; } } -// line 500 "Parser.rl" +// line 501 "Parser.rl" if (cs < JSON_float_first_final) { return null; @@ -1139,7 +1140,7 @@ case 5: } -// line 1143 "Parser.java" +// line 1144 "Parser.java" private static byte[] init__JSON_string_actions_0() { return new byte [] { @@ -1241,23 +1242,23 @@ static final int JSON_string_error = 0; static final int JSON_string_en_main = 1; -// line 544 "Parser.rl" +// line 545 "Parser.rl" ParserResult parseString(int p, int pe) { int cs = EVIL; - RubyString result = null; + IRubyObject result = null; -// line 1253 "Parser.java" +// line 1254 "Parser.java" { cs = JSON_string_start; } -// line 551 "Parser.rl" +// line 552 "Parser.rl" int memo = p; -// line 1261 "Parser.java" +// line 1262 "Parser.java" { int _klen; int _trans = 0; @@ -1338,7 +1339,7 @@ case 1: switch ( _JSON_string_actions[_acts++] ) { case 0: -// line 519 "Parser.rl" +// line 520 "Parser.rl" { int offset = byteList.begin(); ByteList decoded = decoder.decode(byteList, memo + 1 - offset, @@ -1353,13 +1354,13 @@ case 1: } break; case 1: -// line 532 "Parser.rl" +// line 533 "Parser.rl" { p--; { p += 1; _goto_targ = 5; if (true) continue _goto;} } break; -// line 1363 "Parser.java" +// line 1364 "Parser.java" } } } @@ -1379,7 +1380,34 @@ case 5: break; } } -// line 553 "Parser.rl" +// line 554 "Parser.rl" + + 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); @@ -1389,7 +1417,7 @@ case 5: } -// line 1393 "Parser.java" +// line 1421 "Parser.java" private static byte[] init__JSON_array_actions_0() { return new byte [] { @@ -1502,7 +1530,7 @@ static final int JSON_array_error = 0; static final int JSON_array_en_main = 1; -// line 594 "Parser.rl" +// line 622 "Parser.rl" ParserResult parseArray(int p, int pe) { @@ -1520,14 +1548,14 @@ static final int JSON_array_en_main = 1; IRubyObject.NULL_ARRAY, Block.NULL_BLOCK); -// line 1524 "Parser.java" +// line 1552 "Parser.java" { cs = JSON_array_start; } -// line 611 "Parser.rl" +// line 639 "Parser.rl" -// line 1531 "Parser.java" +// line 1559 "Parser.java" { int _klen; int _trans = 0; @@ -1608,7 +1636,7 @@ case 1: switch ( _JSON_array_actions[_acts++] ) { case 0: -// line 567 "Parser.rl" +// line 595 "Parser.rl" { ParserResult res = parseValue(p, pe); if (res == null) { @@ -1621,13 +1649,13 @@ case 1: } break; case 1: -// line 578 "Parser.rl" +// line 606 "Parser.rl" { p--; { p += 1; _goto_targ = 5; if (true) continue _goto;} } break; -// line 1631 "Parser.java" +// line 1659 "Parser.java" } } } @@ -1647,7 +1675,7 @@ case 5: break; } } -// line 612 "Parser.rl" +// line 640 "Parser.rl" if (cs >= JSON_array_first_final) { return new ParserResult(result, p + 1); @@ -1657,7 +1685,7 @@ case 5: } -// line 1661 "Parser.java" +// line 1689 "Parser.java" private static byte[] init__JSON_object_actions_0() { return new byte [] { @@ -1780,7 +1808,7 @@ static final int JSON_object_error = 0; static final int JSON_object_en_main = 1; -// line 668 "Parser.rl" +// line 696 "Parser.rl" ParserResult parseObject(int p, int pe) { @@ -1799,14 +1827,14 @@ static final int JSON_object_en_main = 1; IRubyObject.NULL_ARRAY, Block.NULL_BLOCK); -// line 1803 "Parser.java" +// line 1831 "Parser.java" { cs = JSON_object_start; } -// line 686 "Parser.rl" +// line 714 "Parser.rl" -// line 1810 "Parser.java" +// line 1838 "Parser.java" { int _klen; int _trans = 0; @@ -1887,7 +1915,7 @@ case 1: switch ( _JSON_object_actions[_acts++] ) { case 0: -// line 626 "Parser.rl" +// line 654 "Parser.rl" { ParserResult res = parseValue(p, pe); if (res == null) { @@ -1900,7 +1928,7 @@ case 1: } break; case 1: -// line 637 "Parser.rl" +// line 665 "Parser.rl" { ParserResult res = parseString(p, pe); if (res == null) { @@ -1920,13 +1948,13 @@ case 1: } break; case 2: -// line 655 "Parser.rl" +// line 683 "Parser.rl" { p--; { p += 1; _goto_targ = 5; if (true) continue _goto;} } break; -// line 1930 "Parser.java" +// line 1958 "Parser.java" } } } @@ -1946,7 +1974,7 @@ case 5: break; } } -// line 687 "Parser.rl" +// line 715 "Parser.rl" if (cs < JSON_object_first_final) { return null; @@ -1955,7 +1983,7 @@ case 5: 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 @@ -1972,7 +2000,7 @@ case 5: } -// line 1976 "Parser.java" +// line 2004 "Parser.java" private static byte[] init__JSON_actions_0() { return new byte [] { @@ -2076,7 +2104,7 @@ static final int JSON_error = 0; static final int JSON_en_main = 1; -// line 745 "Parser.rl" +// line 773 "Parser.rl" public IRubyObject parse() { @@ -2085,16 +2113,16 @@ static final int JSON_en_main = 1; IRubyObject result = null; -// line 2089 "Parser.java" +// line 2117 "Parser.java" { cs = JSON_start; } -// line 753 "Parser.rl" +// line 781 "Parser.rl" p = byteList.begin(); pe = p + byteList.length(); -// line 2098 "Parser.java" +// line 2126 "Parser.java" { int _klen; int _trans = 0; @@ -2175,7 +2203,7 @@ case 1: switch ( _JSON_actions[_acts++] ) { case 0: -// line 717 "Parser.rl" +// line 745 "Parser.rl" { currentNesting = 1; ParserResult res = parseObject(p, pe); @@ -2189,7 +2217,7 @@ case 1: } break; case 1: -// line 729 "Parser.rl" +// line 757 "Parser.rl" { currentNesting = 1; ParserResult res = parseArray(p, pe); @@ -2202,7 +2230,7 @@ case 1: } } break; -// line 2206 "Parser.java" +// line 2234 "Parser.java" } } } @@ -2222,7 +2250,7 @@ case 5: break; } } -// line 756 "Parser.rl" +// line 784 "Parser.rl" if (cs >= JSON_first_final && p == pe) { return result; 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 |