Skip to content

Commit

Permalink
[eclipse-ee4j#112]Deduplicate the Context code in the JsonParserImpl
Browse files Browse the repository at this point in the history
Signed-off-by: Anton Pinsky <anton.pinsky@ionos.com>
  • Loading branch information
api-from-the-ion committed Nov 14, 2023
1 parent c1a42cb commit 5c41302
Showing 1 changed file with 85 additions and 83 deletions.
168 changes: 85 additions & 83 deletions impl/src/main/java/org/eclipse/parsson/JsonParserImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.util.AbstractMap;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.Consumer;
Expand All @@ -43,6 +44,15 @@

import org.eclipse.parsson.JsonTokenizer.JsonToken;

import static org.eclipse.parsson.JsonTokenizer.JsonToken.COLON;
import static org.eclipse.parsson.JsonTokenizer.JsonToken.COMMA;
import static org.eclipse.parsson.JsonTokenizer.JsonToken.CURLYCLOSE;
import static org.eclipse.parsson.JsonTokenizer.JsonToken.CURLYOPEN;
import static org.eclipse.parsson.JsonTokenizer.JsonToken.EOF;
import static org.eclipse.parsson.JsonTokenizer.JsonToken.SQUARECLOSE;
import static org.eclipse.parsson.JsonTokenizer.JsonToken.SQUAREOPEN;
import static org.eclipse.parsson.JsonTokenizer.JsonToken.STRING;

/**
* JSON parser implementation. NoneContext, ArrayContext, ObjectContext is used
* to go to next parser state.
Expand Down Expand Up @@ -189,7 +199,7 @@ public Stream<JsonValue> getArrayStream() {
JsonMessages.PARSER_GETARRAY_ERR(currentEvent));
}
Spliterator<JsonValue> spliterator =
new Spliterators.AbstractSpliterator<>(Long.MAX_VALUE, Spliterator.ORDERED) {
new Spliterators.AbstractSpliterator<JsonValue>(Long.MAX_VALUE, Spliterator.ORDERED) {
@Override
public Spliterator<JsonValue> trySplit() {
return null;
Expand Down Expand Up @@ -220,7 +230,7 @@ public Stream<Map.Entry<String, JsonValue>> getObjectStream() {
JsonMessages.PARSER_GETOBJECT_ERR(currentEvent));
}
Spliterator<Map.Entry<String, JsonValue>> spliterator =
new Spliterators.AbstractSpliterator<>(Long.MAX_VALUE, Spliterator.ORDERED) {
new Spliterators.AbstractSpliterator<Map.Entry<String, JsonValue>>(Long.MAX_VALUE, Spliterator.ORDERED) {
@Override
public Spliterator<Map.Entry<String, JsonValue>> trySplit() {
return null;
Expand Down Expand Up @@ -261,7 +271,7 @@ public Stream<JsonValue> getValueStream() {
JsonMessages.PARSER_GETVALUESTREAM_ERR());
}
Spliterator<JsonValue> spliterator =
new Spliterators.AbstractSpliterator<>(Long.MAX_VALUE, Spliterator.ORDERED) {
new Spliterators.AbstractSpliterator<JsonValue>(Long.MAX_VALUE, Spliterator.ORDERED) {
@Override
public Spliterator<JsonValue> trySplit() {
return null;
Expand Down Expand Up @@ -309,7 +319,7 @@ private JsonArray getArray(JsonArrayBuilder builder) {
}
builder.add(getValue());
}
throw parsingException(JsonToken.EOF, "[CURLYOPEN, SQUAREOPEN, STRING, NUMBER, TRUE, FALSE, NULL, SQUARECLOSE]");
throw parsingException(EOF, "[CURLYOPEN, SQUAREOPEN, STRING, NUMBER, TRUE, FALSE, NULL, SQUARECLOSE]");
}

private CharSequence getCharSequence() {
Expand All @@ -330,7 +340,7 @@ private JsonObject getObject(JsonObjectBuilder builder) {
next();
builder.add(key, getValue());
}
throw parsingException(JsonToken.EOF, "[STRING, CURLYCLOSE]");
throw parsingException(EOF, "[STRING, CURLYCLOSE]");
}

@Override
Expand All @@ -346,7 +356,7 @@ public JsonLocation getLastCharLocation() {
public boolean hasNext() {
if (stack.isEmpty() && (currentEvent != null && currentEvent.compareTo(Event.KEY_NAME) > 0)) {
JsonToken token = tokenizer.nextToken();
if (token != JsonToken.EOF) {
if (token != EOF) {
throw new JsonParsingException(JsonMessages.PARSER_EXPECTED_EOF(token),
getLastCharLocation());
}
Expand Down Expand Up @@ -421,27 +431,35 @@ private boolean isEmpty() {
}
}

private abstract static class Context {
private abstract class Context {
Context next;
abstract Event getNextEvent();
abstract void skip();
}

private final class NoneContext extends Context {
@Override
public Event getNextEvent() {
// Handle 1. { 2. [ 3. value
JsonToken token = tokenizer.nextToken();
if (token == JsonToken.CURLYOPEN) {
protected Event nextEventIfValueOrObjectOrArrayStart(JsonToken token) {
if (token.isValue()) {
return token.getEvent();
} else if (token == CURLYOPEN) {
stack.push(currentContext);
currentContext = new ObjectContext();
return Event.START_OBJECT;
} else if (token == JsonToken.SQUAREOPEN) {
} else if (token == SQUAREOPEN) {
stack.push(currentContext);
currentContext = new ArrayContext();
return Event.START_ARRAY;
} else if (token.isValue()) {
return token.getEvent();
}
return null;
}
}

private final class NoneContext extends Context {
@Override
public Event getNextEvent() {
// Handle 1. { 2. [ 3. value
JsonToken token = tokenizer.nextToken();
Event event = nextEventIfValueOrObjectOrArrayStart(token);
if (event != null) {
return event;
}
throw parsingException(token, "[CURLYOPEN, SQUAREOPEN, STRING, NUMBER, TRUE, FALSE, NULL]");
}
Expand All @@ -458,9 +476,38 @@ private JsonParsingException parsingException(JsonToken token, String expectedTo
JsonMessages.PARSER_INVALID_TOKEN(token, location, expectedTokens), location);
}

private final class ObjectContext extends Context {
private abstract class SkippingContext extends Context {
private final JsonToken openToken;
private final JsonToken closeToken;

private SkippingContext(JsonToken openToken, JsonToken closeToken) {
this.openToken = Objects.requireNonNull(openToken);
this.closeToken = Objects.requireNonNull(closeToken);
}

@Override
void skip() {
JsonToken token;
int depth = 1;
do {
token = tokenizer.nextToken();
if (token == closeToken) {
depth--;
}
if (token == openToken) {
depth++;
}
} while (!(token == closeToken && depth == 0));
}
}

private final class ObjectContext extends SkippingContext {
private boolean firstValue = true;

private ObjectContext() {
super(CURLYOPEN, CURLYCLOSE);
}

/*
* Some more things could be optimized. For example, instead
* tokenizer.nextToken(), one could use tokenizer.matchColonToken() to
Expand All @@ -472,7 +519,7 @@ private final class ObjectContext extends Context {
public Event getNextEvent() {
// Handle 1. } 2. name:value 3. ,name:value
JsonToken token = tokenizer.nextToken();
if (token == JsonToken.EOF) {
if (token == EOF) {
switch (currentEvent) {
case START_OBJECT:
throw parsingException(token, "[STRING, CURLYCLOSE]");
Expand All @@ -483,119 +530,74 @@ public Event getNextEvent() {
}
} else if (currentEvent == Event.KEY_NAME) {
// Handle 1. :value
if (token != JsonToken.COLON) {
if (token != COLON) {
throw parsingException(token, "[COLON]");
}
token = tokenizer.nextToken();
if (token.isValue()) {
return token.getEvent();
} else if (token == JsonToken.CURLYOPEN) {
stack.push(currentContext);
currentContext = new ObjectContext();
return Event.START_OBJECT;
} else if (token == JsonToken.SQUAREOPEN) {
stack.push(currentContext);
currentContext = new ArrayContext();
return Event.START_ARRAY;
Event event = nextEventIfValueOrObjectOrArrayStart(token);
if (event != null) {
return event;
}
throw parsingException(token, "[CURLYOPEN, SQUAREOPEN, STRING, NUMBER, TRUE, FALSE, NULL]");
} else {
// Handle 1. } 2. name 3. ,name
if (token == JsonToken.CURLYCLOSE) {
if (token == CURLYCLOSE) {
currentContext = stack.pop();
return Event.END_OBJECT;
}
if (firstValue) {
firstValue = false;
} else {
if (token != JsonToken.COMMA) {
if (token != COMMA) {
throw parsingException(token, "[COMMA]");
}
token = tokenizer.nextToken();
}
if (token == JsonToken.STRING) {
if (token == STRING) {
return Event.KEY_NAME;
}
throw parsingException(token, "[STRING]");
}
}

@Override
void skip() {
JsonToken token;
int depth = 1;
do {
token = tokenizer.nextToken();
switch (token) {
case CURLYCLOSE:
depth--;
break;
case CURLYOPEN:
depth++;
break;
}
} while (!(token == JsonToken.CURLYCLOSE && depth == 0));
}

}

private final class ArrayContext extends Context {
private final class ArrayContext extends SkippingContext {
private boolean firstValue = true;

private ArrayContext() {
super(SQUAREOPEN, SQUARECLOSE);
}

// Handle 1. ] 2. value 3. ,value
@Override
public Event getNextEvent() {
JsonToken token = tokenizer.nextToken();
if (token == JsonToken.EOF) {
if (token == EOF) {
switch (currentEvent) {
case START_ARRAY:
throw parsingException(token, "[CURLYOPEN, SQUAREOPEN, STRING, NUMBER, TRUE, FALSE, NULL]");
default:
throw parsingException(token, "[COMMA, CURLYCLOSE]");
}
}
if (token == JsonToken.SQUARECLOSE) {
if (token == SQUARECLOSE) {
currentContext = stack.pop();
return Event.END_ARRAY;
}
if (firstValue) {
firstValue = false;
} else {
if (token != JsonToken.COMMA) {
if (token != COMMA) {
throw parsingException(token, "[COMMA]");
}
token = tokenizer.nextToken();
}
if (token.isValue()) {
return token.getEvent();
} else if (token == JsonToken.CURLYOPEN) {
stack.push(currentContext);
currentContext = new ObjectContext();
return Event.START_OBJECT;
} else if (token == JsonToken.SQUAREOPEN) {
stack.push(currentContext);
currentContext = new ArrayContext();
return Event.START_ARRAY;

Event event = nextEventIfValueOrObjectOrArrayStart(token);
if (event != null) {
return event;
}
throw parsingException(token, "[CURLYOPEN, SQUAREOPEN, STRING, NUMBER, TRUE, FALSE, NULL]");
}

@Override
void skip() {
JsonToken token;
int depth = 1;
do {
token = tokenizer.nextToken();
switch (token) {
case SQUARECLOSE:
depth--;
break;
case SQUAREOPEN:
depth++;
break;
}
} while (!(token == JsonToken.SQUARECLOSE && depth == 0));
}
}

}

0 comments on commit 5c41302

Please sign in to comment.