summaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
authorFlorian Frank <flori@ping.de>2010-10-05 18:56:08 +0200
committerFlorian Frank <flori@ping.de>2011-01-02 21:13:57 +0100
commit7d20dd9bce9f333c451d074cc0d2ac90560399e0 (patch)
treedaf2ecc5698df7348ca2b1fd7b4f24baaccc7bad /java
parent8714f0a88ccee67ea7ca1a9d5a40d9cf1c6dd5fb (diff)
downloadjson-7d20dd9bce9f333c451d074cc0d2ac90560399e0.tar.gz
implement string matching for java parser
Diffstat (limited to 'java')
-rw-r--r--java/src/json/ext/OptionsReader.java15
-rw-r--r--java/src/json/ext/Parser.java200
-rw-r--r--java/src/json/ext/Parser.rl56
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