Updated Grammar for matching JsonArray to be left-associative rather than right-associative. Gson can now parse arrays of size over 11MB instead of 80KB which was the prior limit. Thanks for the tip, kenotron.

This commit is contained in:
Inderjeet Singh 2009-08-22 01:03:27 +00:00
parent c13fc568c7
commit cbcf7defa3
12 changed files with 1037 additions and 905 deletions

View File

@ -19,9 +19,9 @@ package com.google.gson;
import java.io.IOException; import java.io.IOException;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList;
import java.util.List; import java.util.List;
/** /**
@ -39,7 +39,7 @@ public final class JsonArray extends JsonElement implements Iterable<JsonElement
* Creates an empty JsonArray. * Creates an empty JsonArray.
*/ */
public JsonArray() { public JsonArray() {
elements = new LinkedList<JsonElement>(); elements = new ArrayList<JsonElement>();
} }
/** /**

View File

@ -138,6 +138,10 @@ final class JsonParserJavacc implements JsonParserJavaccConstants {
JsonArray array = new JsonArray(); JsonArray array = new JsonArray();
jj_consume_token(31); jj_consume_token(31);
switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
case 32:
array = JsonArrayEmpty(array);
{if (true) return array;}
break;
case DIGITS: case DIGITS:
case NULL: case NULL:
case NAN: case NAN:
@ -148,31 +152,51 @@ final class JsonParserJavacc implements JsonParserJavaccConstants {
case 27: case 27:
case 31: case 31:
case 33: case 33:
Elements(array); JsonArrayElement(array);
label_1:
while (true) {
switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
case 29:
;
break;
default:
jj_la1[6] = jj_gen;
break label_1;
}
JsonArrayNextElement(array);
}
jj_consume_token(32);
{if (true) return array;}
break; break;
default: default:
jj_la1[6] = jj_gen; jj_la1[7] = jj_gen;
; jj_consume_token(-1);
throw new ParseException();
} }
throw new Error("Missing return statement in function");
}
final private JsonArray JsonArrayEmpty(JsonArray array) throws ParseException {
jj_consume_token(32); jj_consume_token(32);
array.reverse(); {if (true) return array;}
throw new Error("Missing return statement in function");
}
final private JsonArray JsonArrayElement(JsonArray array) throws ParseException {
JsonElement element = null;
element = JsonValue();
array.add(element);
{if (true) return array;} {if (true) return array;}
throw new Error("Missing return statement in function"); throw new Error("Missing return statement in function");
} }
final private void Elements(JsonArray array) throws ParseException { final private JsonArray JsonArrayNextElement(JsonArray array) throws ParseException {
JsonElement element; JsonElement element = null;
jj_consume_token(29);
element = JsonValue(); element = JsonValue();
switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { array.add(element);
case 29: {if (true) return array;}
jj_consume_token(29); throw new Error("Missing return statement in function");
Elements(array);
break;
default:
jj_la1[7] = jj_gen;
;
}
array.add(element);
} }
final private JsonElement JsonValue() throws ParseException { final private JsonElement JsonValue() throws ParseException {
@ -406,36 +430,36 @@ final class JsonParserJavacc implements JsonParserJavaccConstants {
finally { jj_save(0, xla); } finally { jj_save(0, xla); }
} }
private boolean jj_3R_4() { private boolean jj_3R_3() {
if (jj_scan_token(NAN)) return true;
return false;
}
private boolean jj_3R_2() {
Token xsp;
xsp = jj_scanpos;
if (jj_3R_3()) {
jj_scanpos = xsp;
if (jj_3R_4()) return true;
}
return false;
}
private boolean jj_3R_5() {
if (jj_scan_token(33)) return true; if (jj_scan_token(33)) return true;
return false; return false;
} }
private boolean jj_3R_3() { private boolean jj_3R_4() {
Token xsp; Token xsp;
xsp = jj_scanpos; xsp = jj_scanpos;
if (jj_3R_4()) jj_scanpos = xsp; if (jj_3R_5()) jj_scanpos = xsp;
if (jj_scan_token(INFINITY)) return true; if (jj_scan_token(INFINITY)) return true;
return false; return false;
} }
private boolean jj_3_1() { private boolean jj_3_1() {
if (jj_3R_1()) return true; if (jj_3R_2()) return true;
return false;
}
private boolean jj_3R_2() {
if (jj_scan_token(NAN)) return true;
return false;
}
private boolean jj_3R_1() {
Token xsp;
xsp = jj_scanpos;
if (jj_3R_2()) {
jj_scanpos = xsp;
if (jj_3R_3()) return true;
}
return false; return false;
} }
@ -458,10 +482,10 @@ final class JsonParserJavacc implements JsonParserJavaccConstants {
jj_la1_init_1(); jj_la1_init_1();
} }
private static void jj_la1_init_0() { private static void jj_la1_init_0() {
jj_la1_0 = new int[] {0x4000000,0x880307c0,0x8c0307c1,0x31800,0x20000000,0x31800,0x880307c0,0x20000000,0x880307c0,0x30740,0x0,0x20,0x40,0x0,0x300,0x0,0x1800,0x30000,}; jj_la1_0 = new int[] {0x4000000,0x880307c0,0x8c0307c1,0x31800,0x20000000,0x31800,0x20000000,0x880307c0,0x880307c0,0x30740,0x0,0x20,0x40,0x0,0x300,0x0,0x1800,0x30000,};
} }
private static void jj_la1_init_1() { private static void jj_la1_init_1() {
jj_la1_1 = new int[] {0x0,0x2,0x2,0x0,0x0,0x0,0x2,0x0,0x2,0x2,0x4,0x0,0x2,0x2,0x2,0x2,0x0,0x0,}; jj_la1_1 = new int[] {0x0,0x2,0x2,0x0,0x0,0x0,0x0,0x3,0x2,0x2,0x4,0x0,0x2,0x2,0x2,0x2,0x0,0x0,};
} }
final private JJCalls[] jj_2_rtns = new JJCalls[1]; final private JJCalls[] jj_2_rtns = new JJCalls[1];
private boolean jj_rescan = false; private boolean jj_rescan = false;

View File

@ -6,7 +6,6 @@ package com.google.gson;
* Token literal values and constants. * Token literal values and constants.
* Generated by org.javacc.parser.OtherFilesGen#start() * Generated by org.javacc.parser.OtherFilesGen#start()
*/ */
@SuppressWarnings("all")
interface JsonParserJavaccConstants { interface JsonParserJavaccConstants {
/** End of File. */ /** End of File. */

View File

@ -1077,9 +1077,7 @@ protected Token jjFillToken()
beginColumn = input_stream.getBeginColumn(); beginColumn = input_stream.getBeginColumn();
endLine = input_stream.getEndLine(); endLine = input_stream.getEndLine();
endColumn = input_stream.getEndColumn(); endColumn = input_stream.getEndColumn();
t = Token.newToken(jjmatchedKind); t = Token.newToken(jjmatchedKind, curTokenImage);
t.kind = jjmatchedKind;
t.image = curTokenImage;
t.beginLine = beginLine; t.beginLine = beginLine;
t.endLine = endLine; t.endLine = endLine;

View File

@ -1,4 +1,5 @@
/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 3.0 */ /* Generated By:JavaCC: Do not edit this line. ParseException.java Version 4.1 */
/* JavaCCOptions:KEEP_LINE_COL=null */
package com.google.gson; package com.google.gson;
/** /**
@ -13,25 +14,25 @@ package com.google.gson;
@SuppressWarnings("all") @SuppressWarnings("all")
final class ParseException extends Exception { final class ParseException extends Exception {
/**
* The version identifier for this Serializable class.
* Increment only if the <i>serialized</i> form of the
* class changes.
*/
private static final long serialVersionUID = 1L;
/** /**
* This constructor is used by the method "generateParseException" * This constructor is used by the method "generateParseException"
* in the generated parser. Calling this constructor generates * in the generated parser. Calling this constructor generates
* a new object of this type with the fields "currentToken", * a new object of this type with the fields "currentToken",
* "expectedTokenSequences", and "tokenImage" set. The boolean * "expectedTokenSequences", and "tokenImage" set.
* flag "specialConstructor" is also set to true to indicate that
* this constructor was used to create this object.
* This constructor calls its super class with the empty string
* to force the "toString" method of parent class "Throwable" to
* print the error message in the form:
* ParseException: <result of getMessage>
*/ */
public ParseException(Token currentTokenVal, public ParseException(Token currentTokenVal,
int[][] expectedTokenSequencesVal, int[][] expectedTokenSequencesVal,
String[] tokenImageVal String[] tokenImageVal
) )
{ {
super(""); super(initialise(currentTokenVal, expectedTokenSequencesVal, tokenImageVal));
specialConstructor = true;
currentToken = currentTokenVal; currentToken = currentTokenVal;
expectedTokenSequences = expectedTokenSequencesVal; expectedTokenSequences = expectedTokenSequencesVal;
tokenImage = tokenImageVal; tokenImage = tokenImageVal;
@ -49,20 +50,13 @@ final class ParseException extends Exception {
public ParseException() { public ParseException() {
super(); super();
specialConstructor = false;
} }
/** Constructor with message. */
public ParseException(String message) { public ParseException(String message) {
super(message); super(message);
specialConstructor = false;
} }
/**
* This variable determines which constructor was used to create
* this object and thereby affects the semantics of the
* "getMessage" method (see below).
*/
protected boolean specialConstructor;
/** /**
* This is the last token that has been consumed successfully. If * This is the last token that has been consumed successfully. If
@ -86,19 +80,16 @@ final class ParseException extends Exception {
public String[] tokenImage; public String[] tokenImage;
/** /**
* This method has the standard behavior when this object has been * It uses "currentToken" and "expectedTokenSequences" to generate a parse
* created using the standard constructors. Otherwise, it uses
* "currentToken" and "expectedTokenSequences" to generate a parse
* error message and returns it. If this object has been created * error message and returns it. If this object has been created
* due to a parse error, and you do not catch it (it gets thrown * due to a parse error, and you do not catch it (it gets thrown
* from the parser), then this method is called during the printing * from the parser) the correct error message
* of the final stack trace, and hence the correct error message
* gets displayed. * gets displayed.
*/ */
public String getMessage() { private static String initialise(Token currentToken,
if (!specialConstructor) { int[][] expectedTokenSequences,
return super.getMessage(); String[] tokenImage) {
} String eol = System.getProperty("line.separator", "\n");
StringBuffer expected = new StringBuffer(); StringBuffer expected = new StringBuffer();
int maxSize = 0; int maxSize = 0;
for (int i = 0; i < expectedTokenSequences.length; i++) { for (int i = 0; i < expectedTokenSequences.length; i++) {
@ -106,7 +97,7 @@ final class ParseException extends Exception {
maxSize = expectedTokenSequences[i].length; maxSize = expectedTokenSequences[i].length;
} }
for (int j = 0; j < expectedTokenSequences[i].length; j++) { for (int j = 0; j < expectedTokenSequences[i].length; j++) {
expected.append(tokenImage[expectedTokenSequences[i][j]]).append(" "); expected.append(tokenImage[expectedTokenSequences[i][j]]).append(' ');
} }
if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) { if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) {
expected.append("..."); expected.append("...");
@ -121,7 +112,10 @@ final class ParseException extends Exception {
retval += tokenImage[0]; retval += tokenImage[0];
break; break;
} }
retval += " " + tokenImage[tok.kind];
retval += " \"";
retval += add_escapes(tok.image); retval += add_escapes(tok.image);
retval += " \"";
tok = tok.next; tok = tok.next;
} }
retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn; retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn;
@ -145,7 +139,7 @@ final class ParseException extends Exception {
* when these raw version cannot be used as part of an ASCII * when these raw version cannot be used as part of an ASCII
* string literal. * string literal.
*/ */
protected String add_escapes(String str) { static String add_escapes(String str) {
StringBuffer retval = new StringBuffer(); StringBuffer retval = new StringBuffer();
char ch; char ch;
for (int i = 0; i < str.length(); i++) { for (int i = 0; i < str.length(); i++) {
@ -191,3 +185,4 @@ final class ParseException extends Exception {
} }
} }
/* JavaCC - OriginalChecksum=bf6325585417e7bd5d488795e151433b (do not edit this line) */

View File

@ -1,18 +1,20 @@
/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 4.0 */ /* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 4.1 */
/* JavaCCOptions:STATIC=false,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
package com.google.gson; package com.google.gson;
/** /**
* An implementation of interface CharStream, where the stream is assumed to * An implementation of interface CharStream, where the stream is assumed to
* contain only ASCII characters (without unicode processing). * contain only ASCII characters (without unicode processing).
*/ */
@SuppressWarnings("all") @SuppressWarnings("all")
final class SimpleCharStream final class SimpleCharStream
{ {
/** Whether parser is static. */
public static final boolean staticFlag = false; public static final boolean staticFlag = false;
int bufsize; int bufsize;
int available; int available;
int tokenBegin; int tokenBegin;
/** Position in buffer. */
public int bufpos = -1; public int bufpos = -1;
protected int bufline[]; protected int bufline[];
protected int bufcolumn[]; protected int bufcolumn[];
@ -36,167 +38,167 @@ final class SimpleCharStream
protected void ExpandBuff(boolean wrapAround) protected void ExpandBuff(boolean wrapAround)
{ {
char[] newbuffer = new char[bufsize + 2048]; char[] newbuffer = new char[bufsize + 2048];
int newbufline[] = new int[bufsize + 2048]; int newbufline[] = new int[bufsize + 2048];
int newbufcolumn[] = new int[bufsize + 2048]; int newbufcolumn[] = new int[bufsize + 2048];
try try
{ {
if (wrapAround) if (wrapAround)
{ {
System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
System.arraycopy(buffer, 0, newbuffer, System.arraycopy(buffer, 0, newbuffer, bufsize - tokenBegin, bufpos);
bufsize - tokenBegin, bufpos); buffer = newbuffer;
buffer = newbuffer;
System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos); System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos);
bufline = newbufline; bufline = newbufline;
System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos); System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos);
bufcolumn = newbufcolumn; bufcolumn = newbufcolumn;
maxNextCharInd = (bufpos += (bufsize - tokenBegin)); maxNextCharInd = (bufpos += (bufsize - tokenBegin));
} }
else else
{ {
System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
buffer = newbuffer; buffer = newbuffer;
System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
bufline = newbufline; bufline = newbufline;
System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
bufcolumn = newbufcolumn; bufcolumn = newbufcolumn;
maxNextCharInd = (bufpos -= tokenBegin); maxNextCharInd = (bufpos -= tokenBegin);
} }
} }
catch (Throwable t) catch (Throwable t)
{ {
throw new Error(t.getMessage()); throw new Error(t.getMessage());
} }
bufsize += 2048; bufsize += 2048;
available = bufsize; available = bufsize;
tokenBegin = 0; tokenBegin = 0;
} }
protected void FillBuff() throws java.io.IOException protected void FillBuff() throws java.io.IOException
{ {
if (maxNextCharInd == available) if (maxNextCharInd == available)
{ {
if (available == bufsize) if (available == bufsize)
{
if (tokenBegin > 2048)
{ {
if (tokenBegin > 2048) bufpos = maxNextCharInd = 0;
{ available = tokenBegin;
bufpos = maxNextCharInd = 0;
available = tokenBegin;
}
else if (tokenBegin < 0)
bufpos = maxNextCharInd = 0;
else
ExpandBuff(false);
} }
else if (available > tokenBegin) else if (tokenBegin < 0)
available = bufsize; bufpos = maxNextCharInd = 0;
else if ((tokenBegin - available) < 2048)
ExpandBuff(true);
else else
available = tokenBegin; ExpandBuff(false);
} }
else if (available > tokenBegin)
available = bufsize;
else if ((tokenBegin - available) < 2048)
ExpandBuff(true);
else
available = tokenBegin;
}
int i; int i;
try { try {
if ((i = inputStream.read(buffer, maxNextCharInd, if ((i = inputStream.read(buffer, maxNextCharInd, available - maxNextCharInd)) == -1)
available - maxNextCharInd)) == -1) {
{ inputStream.close();
inputStream.close(); throw new java.io.IOException();
throw new java.io.IOException(); }
} else
else maxNextCharInd += i;
maxNextCharInd += i; return;
return; }
} catch(java.io.IOException e) {
catch(java.io.IOException e) { --bufpos;
--bufpos; backup(0);
backup(0); if (tokenBegin == -1)
if (tokenBegin == -1) tokenBegin = bufpos;
tokenBegin = bufpos; throw e;
throw e; }
}
} }
/** Start. */
public char BeginToken() throws java.io.IOException public char BeginToken() throws java.io.IOException
{ {
tokenBegin = -1; tokenBegin = -1;
char c = readChar(); char c = readChar();
tokenBegin = bufpos; tokenBegin = bufpos;
return c; return c;
} }
protected void UpdateLineColumn(char c) protected void UpdateLineColumn(char c)
{ {
column++; column++;
if (prevCharIsLF) if (prevCharIsLF)
{ {
prevCharIsLF = false; prevCharIsLF = false;
line += (column = 1);
}
else if (prevCharIsCR)
{
prevCharIsCR = false;
if (c == '\n')
{
prevCharIsLF = true;
}
else
line += (column = 1); line += (column = 1);
} }
else if (prevCharIsCR)
{
prevCharIsCR = false;
if (c == '\n')
{
prevCharIsLF = true;
}
else
line += (column = 1);
}
switch (c) switch (c)
{ {
case '\r' : case '\r' :
prevCharIsCR = true; prevCharIsCR = true;
break; break;
case '\n' : case '\n' :
prevCharIsLF = true; prevCharIsLF = true;
break; break;
case '\t' : case '\t' :
column--; column--;
column += (tabSize - (column % tabSize)); column += (tabSize - (column % tabSize));
break; break;
default : default :
break; break;
} }
bufline[bufpos] = line; bufline[bufpos] = line;
bufcolumn[bufpos] = column; bufcolumn[bufpos] = column;
} }
/** Read a character. */
public char readChar() throws java.io.IOException public char readChar() throws java.io.IOException
{ {
if (inBuf > 0) if (inBuf > 0)
{ {
--inBuf; --inBuf;
if (++bufpos == bufsize) if (++bufpos == bufsize)
bufpos = 0; bufpos = 0;
return buffer[bufpos]; return buffer[bufpos];
} }
if (++bufpos >= maxNextCharInd) if (++bufpos >= maxNextCharInd)
FillBuff(); FillBuff();
char c = buffer[bufpos]; char c = buffer[bufpos];
UpdateLineColumn(c); UpdateLineColumn(c);
return (c); return c;
} }
/** /**
@ -205,7 +207,7 @@ final class SimpleCharStream
*/ */
public int getColumn() { public int getColumn() {
return bufcolumn[bufpos]; return bufcolumn[bufpos];
} }
/** /**
@ -214,32 +216,38 @@ final class SimpleCharStream
*/ */
public int getLine() { public int getLine() {
return bufline[bufpos]; return bufline[bufpos];
} }
/** Get token end column number. */
public int getEndColumn() { public int getEndColumn() {
return bufcolumn[bufpos]; return bufcolumn[bufpos];
} }
/** Get token end line number. */
public int getEndLine() { public int getEndLine() {
return bufline[bufpos]; return bufline[bufpos];
} }
/** Get token beginning column number. */
public int getBeginColumn() { public int getBeginColumn() {
return bufcolumn[tokenBegin]; return bufcolumn[tokenBegin];
} }
/** Get token beginning line number. */
public int getBeginLine() { public int getBeginLine() {
return bufline[tokenBegin]; return bufline[tokenBegin];
} }
/** Backup a number of characters. */
public void backup(int amount) { public void backup(int amount) {
inBuf += amount; inBuf += amount;
if ((bufpos -= amount) < 0) if ((bufpos -= amount) < 0)
bufpos += bufsize; bufpos += bufsize;
} }
/** Constructor. */
public SimpleCharStream(java.io.Reader dstream, int startline, public SimpleCharStream(java.io.Reader dstream, int startline,
int startcolumn, int buffersize) int startcolumn, int buffersize)
{ {
@ -253,16 +261,20 @@ final class SimpleCharStream
bufcolumn = new int[buffersize]; bufcolumn = new int[buffersize];
} }
/** Constructor. */
public SimpleCharStream(java.io.Reader dstream, int startline, public SimpleCharStream(java.io.Reader dstream, int startline,
int startcolumn) int startcolumn)
{ {
this(dstream, startline, startcolumn, 4096); this(dstream, startline, startcolumn, 4096);
} }
/** Constructor. */
public SimpleCharStream(java.io.Reader dstream) public SimpleCharStream(java.io.Reader dstream)
{ {
this(dstream, 1, 1, 4096); this(dstream, 1, 1, 4096);
} }
/** Reinitialise. */
public void ReInit(java.io.Reader dstream, int startline, public void ReInit(java.io.Reader dstream, int startline,
int startcolumn, int buffersize) int startcolumn, int buffersize)
{ {
@ -282,111 +294,128 @@ final class SimpleCharStream
bufpos = -1; bufpos = -1;
} }
/** Reinitialise. */
public void ReInit(java.io.Reader dstream, int startline, public void ReInit(java.io.Reader dstream, int startline,
int startcolumn) int startcolumn)
{ {
ReInit(dstream, startline, startcolumn, 4096); ReInit(dstream, startline, startcolumn, 4096);
} }
/** Reinitialise. */
public void ReInit(java.io.Reader dstream) public void ReInit(java.io.Reader dstream)
{ {
ReInit(dstream, 1, 1, 4096); ReInit(dstream, 1, 1, 4096);
} }
/** Constructor. */
public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline, public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
{ {
this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize); this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
} }
/** Constructor. */
public SimpleCharStream(java.io.InputStream dstream, int startline, public SimpleCharStream(java.io.InputStream dstream, int startline,
int startcolumn, int buffersize) int startcolumn, int buffersize)
{ {
this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize); this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
} }
/** Constructor. */
public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline, public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
int startcolumn) throws java.io.UnsupportedEncodingException int startcolumn) throws java.io.UnsupportedEncodingException
{ {
this(dstream, encoding, startline, startcolumn, 4096); this(dstream, encoding, startline, startcolumn, 4096);
} }
/** Constructor. */
public SimpleCharStream(java.io.InputStream dstream, int startline, public SimpleCharStream(java.io.InputStream dstream, int startline,
int startcolumn) int startcolumn)
{ {
this(dstream, startline, startcolumn, 4096); this(dstream, startline, startcolumn, 4096);
} }
/** Constructor. */
public SimpleCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException public SimpleCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
{ {
this(dstream, encoding, 1, 1, 4096); this(dstream, encoding, 1, 1, 4096);
} }
/** Constructor. */
public SimpleCharStream(java.io.InputStream dstream) public SimpleCharStream(java.io.InputStream dstream)
{ {
this(dstream, 1, 1, 4096); this(dstream, 1, 1, 4096);
} }
/** Reinitialise. */
public void ReInit(java.io.InputStream dstream, String encoding, int startline, public void ReInit(java.io.InputStream dstream, String encoding, int startline,
int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
{ {
ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize); ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
} }
/** Reinitialise. */
public void ReInit(java.io.InputStream dstream, int startline, public void ReInit(java.io.InputStream dstream, int startline,
int startcolumn, int buffersize) int startcolumn, int buffersize)
{ {
ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize); ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
} }
/** Reinitialise. */
public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
{ {
ReInit(dstream, encoding, 1, 1, 4096); ReInit(dstream, encoding, 1, 1, 4096);
} }
/** Reinitialise. */
public void ReInit(java.io.InputStream dstream) public void ReInit(java.io.InputStream dstream)
{ {
ReInit(dstream, 1, 1, 4096); ReInit(dstream, 1, 1, 4096);
} }
/** Reinitialise. */
public void ReInit(java.io.InputStream dstream, String encoding, int startline, public void ReInit(java.io.InputStream dstream, String encoding, int startline,
int startcolumn) throws java.io.UnsupportedEncodingException int startcolumn) throws java.io.UnsupportedEncodingException
{ {
ReInit(dstream, encoding, startline, startcolumn, 4096); ReInit(dstream, encoding, startline, startcolumn, 4096);
} }
/** Reinitialise. */
public void ReInit(java.io.InputStream dstream, int startline, public void ReInit(java.io.InputStream dstream, int startline,
int startcolumn) int startcolumn)
{ {
ReInit(dstream, startline, startcolumn, 4096); ReInit(dstream, startline, startcolumn, 4096);
} }
/** Get token literal value. */
public String GetImage() public String GetImage()
{ {
if (bufpos >= tokenBegin) if (bufpos >= tokenBegin)
return new String(buffer, tokenBegin, bufpos - tokenBegin + 1); return new String(buffer, tokenBegin, bufpos - tokenBegin + 1);
else else
return new String(buffer, tokenBegin, bufsize - tokenBegin) + return new String(buffer, tokenBegin, bufsize - tokenBegin) +
new String(buffer, 0, bufpos + 1); new String(buffer, 0, bufpos + 1);
} }
/** Get the suffix. */
public char[] GetSuffix(int len) public char[] GetSuffix(int len)
{ {
char[] ret = new char[len]; char[] ret = new char[len];
if ((bufpos + 1) >= len) if ((bufpos + 1) >= len)
System.arraycopy(buffer, bufpos - len + 1, ret, 0, len); System.arraycopy(buffer, bufpos - len + 1, ret, 0, len);
else else
{ {
System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0, System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0,
len - bufpos - 1); len - bufpos - 1);
System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1); System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1);
} }
return ret; return ret;
} }
/** Reset buffer when finished. */
public void Done() public void Done()
{ {
buffer = null; buffer = null;
bufline = null; bufline = null;
bufcolumn = null; bufcolumn = null;
} }
/** /**
@ -394,47 +423,47 @@ final class SimpleCharStream
*/ */
public void adjustBeginLineColumn(int newLine, int newCol) public void adjustBeginLineColumn(int newLine, int newCol)
{ {
int start = tokenBegin; int start = tokenBegin;
int len; int len;
if (bufpos >= tokenBegin) if (bufpos >= tokenBegin)
{ {
len = bufpos - tokenBegin + inBuf + 1; len = bufpos - tokenBegin + inBuf + 1;
} }
else else
{ {
len = bufsize - tokenBegin + bufpos + 1 + inBuf; len = bufsize - tokenBegin + bufpos + 1 + inBuf;
} }
int i = 0, j = 0, k = 0; int i = 0, j = 0, k = 0;
int nextColDiff = 0, columnDiff = 0; int nextColDiff = 0, columnDiff = 0;
while (i < len && while (i < len && bufline[j = start % bufsize] == bufline[k = ++start % bufsize])
bufline[j = start % bufsize] == bufline[k = ++start % bufsize]) {
{ bufline[j] = newLine;
bufline[j] = newLine; nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j];
nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j]; bufcolumn[j] = newCol + columnDiff;
bufcolumn[j] = newCol + columnDiff; columnDiff = nextColDiff;
columnDiff = nextColDiff; i++;
i++; }
}
if (i < len) if (i < len)
{ {
bufline[j] = newLine++; bufline[j] = newLine++;
bufcolumn[j] = newCol + columnDiff; bufcolumn[j] = newCol + columnDiff;
while (i++ < len) while (i++ < len)
{ {
if (bufline[j = start % bufsize] != bufline[++start % bufsize]) if (bufline[j = start % bufsize] != bufline[++start % bufsize])
bufline[j] = newLine++; bufline[j] = newLine++;
else else
bufline[j] = newLine; bufline[j] = newLine;
} }
} }
line = bufline[j]; line = bufline[j];
column = bufcolumn[j]; column = bufcolumn[j];
} }
} }
/* JavaCC - OriginalChecksum=351e3d8e62614bff24f1b9ba2fd77764 (do not edit this line) */

View File

@ -1,12 +1,19 @@
/* Generated By:JavaCC: Do not edit this line. Token.java Version 3.0 */ /* Generated By:JavaCC: Do not edit this line. Token.java Version 4.1 */
/* JavaCCOptions:TOKEN_EXTENDS=,KEEP_LINE_COL=null,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
package com.google.gson; package com.google.gson;
/** /**
* Describes the input token stream. * Describes the input token stream.
*/ */
@SuppressWarnings("all") @SuppressWarnings("all")
final class Token { final class Token implements java.io.Serializable {
/**
* The version identifier for this Serializable class.
* Increment only if the <i>serialized</i> form of the
* class changes.
*/
private static final long serialVersionUID = 1L;
/** /**
* An integer that describes the kind of this token. This numbering * An integer that describes the kind of this token. This numbering
@ -15,12 +22,14 @@ final class Token {
*/ */
public int kind; public int kind;
/** /** The line number of the first character of this Token. */
* beginLine and beginColumn describe the position of the first character public int beginLine;
* of this token; endLine and endColumn describe the position of the /** The column number of the first character of this Token. */
* last character of this token. public int beginColumn;
*/ /** The line number of the last character of this Token. */
public int beginLine, beginColumn, endLine, endColumn; public int endLine;
/** The column number of the last character of this Token. */
public int endColumn;
/** /**
* The string image of the token. * The string image of the token.
@ -51,12 +60,46 @@ final class Token {
*/ */
public Token specialToken; public Token specialToken;
/**
* An optional attribute value of the Token.
* Tokens which are not used as syntactic sugar will often contain
* meaningful values that will be used later on by the compiler or
* interpreter. This attribute value is often different from the image.
* Any subclass of Token that actually wants to return a non-null value can
* override this method as appropriate.
*/
public Object getValue() {
return null;
}
/**
* No-argument constructor
*/
public Token() {}
/**
* Constructs a new token for the specified Image.
*/
public Token(int kind)
{
this(kind, null);
}
/**
* Constructs a new token for the specified Image and Kind.
*/
public Token(int kind, String image)
{
this.kind = kind;
this.image = image;
}
/** /**
* Returns the image. * Returns the image.
*/ */
public String toString() public String toString()
{ {
return image; return image;
} }
/** /**
@ -64,19 +107,25 @@ final class Token {
* can create and return subclass objects based on the value of ofKind. * can create and return subclass objects based on the value of ofKind.
* Simply add the cases to the switch for all those special cases. * Simply add the cases to the switch for all those special cases.
* For example, if you have a subclass of Token called IDToken that * For example, if you have a subclass of Token called IDToken that
* you want to create if ofKind is ID, simlpy add something like : * you want to create if ofKind is ID, simply add something like :
* *
* case MyParserConstants.ID : return new IDToken(); * case MyParserConstants.ID : return new IDToken(ofKind, image);
* *
* to the following switch statement. Then you can cast matchedToken * to the following switch statement. Then you can cast matchedToken
* variable to the appropriate type and use it in your lexical actions. * variable to the appropriate type and use sit in your lexical actions.
*/ */
public static final Token newToken(int ofKind) public static Token newToken(int ofKind, String image)
{ {
switch(ofKind) switch(ofKind)
{ {
default : return new Token(); default : return new Token(ofKind, image);
} }
}
public static Token newToken(int ofKind)
{
return newToken(ofKind, null);
} }
} }
/* JavaCC - OriginalChecksum=f683548fa415467062989dfb10c566e6 (do not edit this line) */

View File

@ -1,134 +1,148 @@
/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 3.0 */ /* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 4.1 */
/* JavaCCOptions: */
package com.google.gson; package com.google.gson;
/** Token Manager Error. */
@SuppressWarnings("all") @SuppressWarnings("all")
final class TokenMgrError extends Error final class TokenMgrError extends Error
{ {
/*
* Ordinals for various reasons why an Error of this type can be thrown.
*/
/** /**
* Lexical error occured. * The version identifier for this Serializable class.
*/ * Increment only if the <i>serialized</i> form of the
static final int LEXICAL_ERROR = 0; * class changes.
*/
private static final long serialVersionUID = 1L;
/** /*
* An attempt wass made to create a second instance of a static token manager. * Ordinals for various reasons why an Error of this type can be thrown.
*/ */
static final int STATIC_LEXER_ERROR = 1;
/** /**
* Tried to change to an invalid lexical state. * Lexical error occurred.
*/ */
static final int INVALID_LEXICAL_STATE = 2; static final int LEXICAL_ERROR = 0;
/** /**
* Detected (and bailed out of) an infinite loop in the token manager. * An attempt was made to create a second instance of a static token manager.
*/ */
static final int LOOP_DETECTED = 3; static final int STATIC_LEXER_ERROR = 1;
/** /**
* Indicates the reason why the exception is thrown. It will have * Tried to change to an invalid lexical state.
* one of the above 4 values. */
*/ static final int INVALID_LEXICAL_STATE = 2;
int errorCode;
/** /**
* Replaces unprintable characters by their espaced (or unicode escaped) * Detected (and bailed out of) an infinite loop in the token manager.
* equivalents in the given string */
*/ static final int LOOP_DETECTED = 3;
protected static final String addEscapes(String str) {
StringBuffer retval = new StringBuffer(); /**
char ch; * Indicates the reason why the exception is thrown. It will have
for (int i = 0; i < str.length(); i++) { * one of the above 4 values.
switch (str.charAt(i)) */
{ int errorCode;
case 0 :
continue; /**
case '\b': * Replaces unprintable characters by their escaped (or unicode escaped)
retval.append("\\b"); * equivalents in the given string
continue; */
case '\t': protected static final String addEscapes(String str) {
retval.append("\\t"); StringBuffer retval = new StringBuffer();
continue; char ch;
case '\n': for (int i = 0; i < str.length(); i++) {
retval.append("\\n"); switch (str.charAt(i))
continue; {
case '\f': case 0 :
retval.append("\\f"); continue;
continue; case '\b':
case '\r': retval.append("\\b");
retval.append("\\r"); continue;
continue; case '\t':
case '\"': retval.append("\\t");
retval.append("\\\""); continue;
continue; case '\n':
case '\'': retval.append("\\n");
retval.append("\\\'"); continue;
continue; case '\f':
case '\\': retval.append("\\f");
retval.append("\\\\"); continue;
continue; case '\r':
default: retval.append("\\r");
if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) { continue;
String s = "0000" + Integer.toString(ch, 16); case '\"':
retval.append("\\u" + s.substring(s.length() - 4, s.length())); retval.append("\\\"");
} else { continue;
retval.append(ch); case '\'':
} retval.append("\\\'");
continue; continue;
} case '\\':
retval.append("\\\\");
continue;
default:
if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
String s = "0000" + Integer.toString(ch, 16);
retval.append("\\u" + s.substring(s.length() - 4, s.length()));
} else {
retval.append(ch);
}
continue;
} }
return retval.toString(); }
} return retval.toString();
}
/** /**
* Returns a detailed message for the Error when it is thrown by the * Returns a detailed message for the Error when it is thrown by the
* token manager to indicate a lexical error. * token manager to indicate a lexical error.
* Parameters : * Parameters :
* EOFSeen : indicates if EOF caused the lexicl error * EOFSeen : indicates if EOF caused the lexical error
* curLexState : lexical state in which this error occured * curLexState : lexical state in which this error occurred
* errorLine : line number when the error occured * errorLine : line number when the error occurred
* errorColumn : column number when the error occured * errorColumn : column number when the error occurred
* errorAfter : prefix that was seen before this error occured * errorAfter : prefix that was seen before this error occurred
* curchar : the offending character * curchar : the offending character
* Note: You can customize the lexical error message by modifying this method. * Note: You can customize the lexical error message by modifying this method.
*/ */
protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) { protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) {
return("Lexical error at line " + return("Lexical error at line " +
errorLine + ", column " + errorLine + ", column " +
errorColumn + ". Encountered: " + errorColumn + ". Encountered: " +
(EOFSeen ? "<EOF> " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int)curChar + "), ") + (EOFSeen ? "<EOF> " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int)curChar + "), ") +
"after : \"" + addEscapes(errorAfter) + "\""); "after : \"" + addEscapes(errorAfter) + "\"");
} }
/** /**
* You can also modify the body of this method to customize your error messages. * You can also modify the body of this method to customize your error messages.
* For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not
* of end-users concern, so you can return something like : * of end-users concern, so you can return something like :
* *
* "Internal Error : Please file a bug report .... " * "Internal Error : Please file a bug report .... "
* *
* from this method for such cases in the release version of your parser. * from this method for such cases in the release version of your parser.
*/ */
public String getMessage() { public String getMessage() {
return super.getMessage(); return super.getMessage();
} }
/* /*
* Constructors of various flavors follow. * Constructors of various flavors follow.
*/ */
public TokenMgrError() { /** No arg constructor. */
} public TokenMgrError() {
}
public TokenMgrError(String message, int reason) { /** Constructor with message and reason. */
super(message); public TokenMgrError(String message, int reason) {
errorCode = reason; super(message);
} errorCode = reason;
}
public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) { /** Full Constructor. */
this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason); public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) {
} this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason);
}
} }
/* JavaCC - OriginalChecksum=f9c23e3fca926dbaf51c810110262be0 (do not edit this line) */

View File

@ -116,20 +116,29 @@ private JsonPrimitive JsonMemberName() :
private JsonArray JsonArray() : private JsonArray JsonArray() :
{ JsonArray array = new JsonArray(); } { JsonArray array = new JsonArray(); }
{ {
"[" [ Elements(array) ] "]" "[" (
{ array=JsonArrayEmpty(array) {return array;} |
array.reverse(); JsonArrayElement(array) (JsonArrayNextElement(array))* "]" {return array; } )
return array;
}
} }
private void Elements(JsonArray array) : private JsonArray JsonArrayEmpty(JsonArray array) :
{ }
{ {
JsonElement element; "]" { return array; }
} }
private JsonArray JsonArrayElement(JsonArray array) :
{ JsonElement element = null; }
{ {
element=JsonValue() [ "," Elements(array) ] element=JsonValue() {array.add(element);}
{ array.add(element); } { return array; }
}
private JsonArray JsonArrayNextElement(JsonArray array) :
{ JsonElement element = null; }
{
"," element=JsonValue() {array.add(element);}
{ return array; }
} }
private JsonElement JsonValue() : private JsonElement JsonValue() :

View File

@ -18,6 +18,7 @@ package com.google.gson.functional;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import com.google.gson.JsonParseException;
import com.google.gson.common.MoreAsserts; import com.google.gson.common.MoreAsserts;
import com.google.gson.common.TestTypes.BagOfPrimitives; import com.google.gson.common.TestTypes.BagOfPrimitives;
import com.google.gson.common.TestTypes.CrazyLongTypeAdapter; import com.google.gson.common.TestTypes.CrazyLongTypeAdapter;
@ -55,6 +56,15 @@ public class ArrayTest extends TestCase {
MoreAsserts.assertEquals(expected, actual); MoreAsserts.assertEquals(expected, actual);
} }
public void testInvalidArrayDeserialization() {
String json = "[1, 2 3, 4, 5]";
try {
gson.fromJson(json, int[].class);
fail("Gson should not deserialize array elements with missing ,");
} catch (JsonParseException expected) {
}
}
public void testEmptyArraySerialization() { public void testEmptyArraySerialization() {
int[] target = {}; int[] target = {};
assertEquals("[]", gson.toJson(target)); assertEquals("[]", gson.toJson(target));
@ -66,7 +76,10 @@ public class ArrayTest extends TestCase {
Integer[] actualObject2 = gson.fromJson("[]", Integer[].class); Integer[] actualObject2 = gson.fromJson("[]", Integer[].class);
assertTrue(actualObject2.length == 0); assertTrue(actualObject2.length == 0);
}
actualObject = gson.fromJson("[ ]", int[].class);
assertTrue(actualObject.length == 0);
}
public void testNullsInArraySerialization() { public void testNullsInArraySerialization() {
String[] array = {"foo", null, "bar"}; String[] array = {"foo", null, "bar"};

View File

@ -117,16 +117,18 @@ public class ObjectTest extends TestCase {
} }
public void testClassWithTransientFieldsSerialization() throws Exception { public void testClassWithTransientFieldsSerialization() throws Exception {
ClassWithTransientFields target = new ClassWithTransientFields(1L); ClassWithTransientFields<Long> target = new ClassWithTransientFields<Long>(1L);
assertEquals(target.getExpectedJson(), gson.toJson(target)); assertEquals(target.getExpectedJson(), gson.toJson(target));
} }
@SuppressWarnings("unchecked")
public void testClassWithTransientFieldsDeserialization() throws Exception { public void testClassWithTransientFieldsDeserialization() throws Exception {
String json = "{\"longValue\":[1]}"; String json = "{\"longValue\":[1]}";
ClassWithTransientFields target = gson.fromJson(json, ClassWithTransientFields.class); ClassWithTransientFields target = gson.fromJson(json, ClassWithTransientFields.class);
assertEquals(json, target.getExpectedJson()); assertEquals(json, target.getExpectedJson());
} }
@SuppressWarnings("unchecked")
public void testClassWithTransientFieldsDeserializationTransientFieldsPassedInJsonAreIgnored() public void testClassWithTransientFieldsDeserializationTransientFieldsPassedInJsonAreIgnored()
throws Exception { throws Exception {
String json = "{\"transientLongValue\":1,\"longValue\":[1]}"; String json = "{\"transientLongValue\":1,\"longValue\":[1]}";

View File

@ -148,9 +148,9 @@ public class PerformanceTest extends TestCase {
/** /**
* Created in response to http://code.google.com/p/google-gson/issues/detail?id=96 * Created in response to http://code.google.com/p/google-gson/issues/detail?id=96
*/ */
// Last I tested, Gson was able to deserialize a byte array of 80KB // Last I tested, Gson was able to deserialize a byte array of 11MB
public void disable_testByteArrayDeserialization() { public void disable_testByteArrayDeserialization() {
for (int numElements = 32768; true; numElements += 4096) { for (int numElements = 10639296; true; numElements += 16384) {
StringBuilder sb = new StringBuilder(numElements*2); StringBuilder sb = new StringBuilder(numElements*2);
sb.append("["); sb.append("[");
boolean first = true; boolean first = true;