io.github.green4j.jelly.JsonParser Maven / Gradle / Ivy
Show all versions of green-jelly Show documentation
/**
* MIT License
*
* Copyright (c) 2018-2024 Anatoly Gudkov and others.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.green4j.jelly;
/**
* Parses JSON character sequence.
*/
public final class JsonParser {
public interface Next {
Next next();
}
private static final int LEXEMA_TRUE_STARTED_T = 1;
private static final int LEXEMA_TRUE_STARTED_TR = LEXEMA_TRUE_STARTED_T + 1;
private static final int LEXEMA_TRUE_STARTED_TRU = LEXEMA_TRUE_STARTED_TR + 1;
private static final int LEXEMA_FALSE_STARTED_F = LEXEMA_TRUE_STARTED_TRU + 1;
private static final int LEXEMA_FALSE_STARTED_FA = LEXEMA_FALSE_STARTED_F + 1;
private static final int LEXEMA_FALSE_STARTED_FAL = LEXEMA_FALSE_STARTED_FA + 1;
private static final int LEXEMA_FALSE_STARTED_FALS = LEXEMA_FALSE_STARTED_FAL + 1;
private static final int LEXEMA_NULL_STARTED_N = LEXEMA_FALSE_STARTED_FALS + 1;
private static final int LEXEMA_NULL_STARTED_NU = LEXEMA_NULL_STARTED_N + 1;
private static final int LEXEMA_NULL_STARTED_NUL = LEXEMA_NULL_STARTED_NU + 1;
private static final int LEXEMA_STRING_STARTED = LEXEMA_NULL_STARTED_NUL + 1;
private static final int LEXEMA_STRING_STARTED_ESCAPE = LEXEMA_STRING_STARTED + 1;
private static final int LEXEMA_STRING_STARTED_ESCAPE_UNICODE = LEXEMA_STRING_STARTED_ESCAPE + 1;
private static final int LEXEMA_STRING_STARTED_ESCAPE_UNICODE_1 = LEXEMA_STRING_STARTED_ESCAPE_UNICODE + 1;
private static final int LEXEMA_STRING_STARTED_ESCAPE_UNICODE_2 = LEXEMA_STRING_STARTED_ESCAPE_UNICODE_1 + 1;
private static final int LEXEMA_STRING_STARTED_ESCAPE_UNICODE_3 = LEXEMA_STRING_STARTED_ESCAPE_UNICODE_2 + 1;
private static final int LEXEMA_NUMBER_STARTED_MANTISSA_SIGN = LEXEMA_STRING_STARTED_ESCAPE_UNICODE_3 + 1;
private static final int LEXEMA_NUMBER_STARTED_MANTISSA_INTEGER_PART = LEXEMA_NUMBER_STARTED_MANTISSA_SIGN + 1;
private static final int LEXEMA_NUMBER_STARTED_MANTISSA_FRACTIONAL_PART
= LEXEMA_NUMBER_STARTED_MANTISSA_INTEGER_PART + 1;
private static final int LEXEMA_NUMBER_STARTED_E = LEXEMA_NUMBER_STARTED_MANTISSA_FRACTIONAL_PART + 1;
private static final int LEXEMA_NUMBER_STARTED_E_SIGN = LEXEMA_NUMBER_STARTED_E + 1;
private static final int LEXEMA_NUMBER_STARTED_E_VALUE = LEXEMA_NUMBER_STARTED_E_SIGN + 1;
private static final int LEXEMA_READY = LEXEMA_NUMBER_STARTED_E_VALUE + 1;
private static final int LEXEMA_CURLY_BRACKET_LEFT_READY = LEXEMA_READY + 1;
private static final int LEXEMA_CURLY_BRACKET_RIGHT_READY = LEXEMA_CURLY_BRACKET_LEFT_READY + 1;
private static final int LEXEMA_BOX_BRACKET_LEFT_READY = LEXEMA_CURLY_BRACKET_RIGHT_READY + 1;
private static final int LEXEMA_BOX_BRACKET_RIGHT_READY = LEXEMA_BOX_BRACKET_LEFT_READY + 1;
private static final int LEXEMA_COMMA_READY = LEXEMA_BOX_BRACKET_RIGHT_READY + 1;
private static final int LEXEMA_COLON_READY = LEXEMA_COMMA_READY + 1;
private static final int LEXEMA_STRING_READY = LEXEMA_COLON_READY + 1;
private static final int LEXEMA_NUMBER_READY = LEXEMA_STRING_READY + 1;
private static final int LEXEMA_TRUE_READY = LEXEMA_NUMBER_READY + 1;
private static final int LEXEMA_FALSE_READY = LEXEMA_TRUE_READY + 1;
private static final int LEXEMA_NULL_READY = LEXEMA_FALSE_READY + 1;
private static final int EXPRESSION_INITIAL = 0;
private static final int EXPRESSION_OBJECT_STARTED = EXPRESSION_INITIAL + 1;
private static final int EXPRESSION_OBJECT_STARTED_MEMBER_NAME = EXPRESSION_OBJECT_STARTED + 1;
private static final int EXPRESSION_OBJECT_STARTED_MEMBER_NAME_VALUE_COLON_DELIMITER =
EXPRESSION_OBJECT_STARTED_MEMBER_NAME + 1;
private static final int EXPRESSION_OBJECT_STARTED_MEMBER_VALUE =
EXPRESSION_OBJECT_STARTED_MEMBER_NAME_VALUE_COLON_DELIMITER + 1;
private static final int EXPRESSION_OBJECT_STARTED_MEMBER_COMMA_DELIMITER =
EXPRESSION_OBJECT_STARTED_MEMBER_VALUE + 1;
private static final int EXPRESSION_ARRAY_STARTED = EXPRESSION_OBJECT_STARTED_MEMBER_COMMA_DELIMITER + 1;
private static final int EXPRESSION_ARRAY_STARTED_VALUE = EXPRESSION_ARRAY_STARTED + 1;
private static final int EXPRESSION_ARRAY_STARTED_COMMA_DELIMITER = EXPRESSION_ARRAY_STARTED_VALUE + 1;
private static final String ERROR_INCORRECT_STRING_MESSAGE = "Incorrect string";
private static final String ERROR_INCORRECT_ESCAPING_MESSAGE = "Incorrect character escaping";
private static final String ERROR_MESSAGE_INCORRECT_UNICODE_ESCAPING = "Incorrect unicode escaping";
private static final String ERROR_INCORRECT_NUMBER_MESSAGE = "Incorrect number";
private static final String ERROR_TRUE_EXPECTED_MESSAGE = "'true' expected";
private static final String ERROR_FALSE_EXPECTED_MESSAGE = "'false' expected";
private static final String ERROR_NULL_EXPECTED_MESSAGE = "'null' expected";
private static final String ERROR_UNEXPECTED_CURLY_BRACKET_LEFT_MESSAGE = "Unexpected '{'";
private static final String ERROR_UNEXPECTED_CURLY_BRACKET_RIGHT_MESSAGE = "Unexpected '}'";
private static final String ERROR_UNEXPECTED_BOX_BRACKET_LEFT_MESSAGE = "Unexpected '['";
private static final String ERROR_UNEXPECTED_BOX_BRACKET_RIGHT_MESSAGE = "Unexpected ']'";
private static final String ERROR_UNEXPECTED_COMMA_MESSAGE = "Unexpected ','";
private static final String ERROR_UNEXPECTED_COLON_MESSAGE = "Unexpected ':'";
private static final String ERROR_UNEXPECTED_STRING_MESSAGE = "Unexpected string";
private static final String ERROR_UNEXPECTED_NUMBER_MESSAGE = "Unexpected number";
private static final String ERROR_UNEXPECTED_TRUE_MESSAGE = "Unexpected 'true'";
private static final String ERROR_UNEXPECTED_FALSE_MESSAGE = "Unexpected 'false'";
private static final String ERROR_UNEXPECTED_NULL_MESSAGE = "Unexpected 'null'";
private static final String ERROR_UNEXPECTED_CHAR_MESSAGE = "Unexpected char";
private static final String ERROR_INTERNAL_UNEXPECTED_LEXEMA_ERROR_MESSAGE = "Internal error. Unexpected lexema";
private static final int JSON_STARTED_NOTIFICATION_REQUIRED = -1;
private static final int RESET_REQUIRED = JSON_STARTED_NOTIFICATION_REQUIRED - 1;
private static final long MAX_MANTISSA_BASE = 922337203685477579L;
public static final long MAX_MANTISSA_VALUE = MAX_MANTISSA_BASE * 10 + 9;
public static boolean parseNumber(final CharSequence data, final MutableJsonNumber to) {
int currentLexState = LEXEMA_READY;
int numberMantissaExp = 0;
int numberMinuses = 0;
boolean numberOverflow = false;
final int len = data.length();
_end:
for (int pos = 0; pos < len; pos++) {
char c = data.charAt(pos);
_next_char:
switch (currentLexState) {
case LEXEMA_READY: {
switch (c) {
case '-': {
to.setMantissa(0);
to.setExp(0);
numberMantissaExp = 0;
numberMinuses = 2;
currentLexState = LEXEMA_NUMBER_STARTED_MANTISSA_SIGN;
break _next_char;
}
case '+': {
to.setMantissa(0);
to.setExp(0);
numberMantissaExp = 0;
numberMinuses = 0;
currentLexState = LEXEMA_NUMBER_STARTED_MANTISSA_SIGN;
break _next_char;
}
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9': {
to.setMantissa(c - '0');
to.setExp(0);
numberMantissaExp = 0;
numberMinuses = 0;
if (len - pos > 1) { // try to read available part of the number value's mantissa
pos++;
while (true) {
c = data.charAt(pos);
if (c >= '0' && c <= '9') {
final long m = to.mantissa();
numberOverflow |= m > MAX_MANTISSA_BASE;
if (!numberOverflow) {
to.setMantissa(m * 10 + (c - '0'));
} else {
numberMantissaExp++;
}
if (++pos == len) {
break _end;
}
continue;
}
switch (c) {
case '.':
currentLexState = LEXEMA_NUMBER_STARTED_MANTISSA_FRACTIONAL_PART;
break _next_char;
case 'e':
case 'E':
currentLexState = LEXEMA_NUMBER_STARTED_E;
break _next_char;
default:
throw new IllegalArgumentException(ERROR_INCORRECT_NUMBER_MESSAGE
+ ". Unexpected char '" + c + "' at the position " + pos);
}
}
}
break _end;
}
default:
throw new IllegalArgumentException(ERROR_INCORRECT_NUMBER_MESSAGE
+ ". Unexpected char '" + c + "' at the position " + pos);
}
}
case LEXEMA_NUMBER_STARTED_MANTISSA_INTEGER_PART: {
while (true) {
if (c >= '0' && c <= '9') {
final long m = to.mantissa();
numberOverflow |= m > MAX_MANTISSA_BASE;
if (!numberOverflow) {
to.setMantissa(m * 10 + (c - '0'));
} else {
numberMantissaExp++;
}
if (++pos == len) {
break _end;
}
c = data.charAt(pos);
continue;
}
switch (c) {
case '.':
currentLexState = LEXEMA_NUMBER_STARTED_MANTISSA_FRACTIONAL_PART;
break _next_char;
case 'e':
case 'E':
currentLexState = LEXEMA_NUMBER_STARTED_E;
break _next_char;
default:
throw new IllegalArgumentException(ERROR_INCORRECT_NUMBER_MESSAGE
+ ". Unexpected char '" + c + "' at the position " + pos);
}
}
}
case LEXEMA_NUMBER_STARTED_MANTISSA_SIGN: {
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
to.setMantissa(c - '0');
currentLexState = LEXEMA_NUMBER_STARTED_MANTISSA_INTEGER_PART;
break _next_char;
default:
throw new IllegalArgumentException(ERROR_INCORRECT_NUMBER_MESSAGE
+ ". Unexpected char '" + c + "' at the position " + pos);
}
}
case LEXEMA_NUMBER_STARTED_MANTISSA_FRACTIONAL_PART: {
while (true) {
if (c >= '0' && c <= '9') {
final long m = to.mantissa();
numberOverflow |= m > MAX_MANTISSA_BASE;
if (!numberOverflow) {
to.setMantissa(m * 10 + (c - '0'));
numberMantissaExp--;
}
if (++pos == len) {
break _end;
}
c = data.charAt(pos);
continue;
}
switch (c) {
case 'e':
case 'E':
currentLexState = LEXEMA_NUMBER_STARTED_E;
break _next_char;
default:
throw new IllegalArgumentException(ERROR_INCORRECT_NUMBER_MESSAGE
+ ". Unexpected char '" + c + "' at the position " + pos);
}
}
}
case LEXEMA_NUMBER_STARTED_E: {
switch (c) {
case '+':
currentLexState = LEXEMA_NUMBER_STARTED_E_SIGN;
break _next_char;
case '-':
numberMinuses = numberMinuses | 1;
currentLexState = LEXEMA_NUMBER_STARTED_E_SIGN;
break _next_char;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
to.setExp(to.exp() * 10 + (c - '0'));
currentLexState = LEXEMA_NUMBER_STARTED_E_VALUE;
break _next_char;
default:
throw new IllegalArgumentException(ERROR_INCORRECT_NUMBER_MESSAGE
+ ". Unexpected char '" + c + "' at the position " + pos);
}
}
case LEXEMA_NUMBER_STARTED_E_SIGN: {
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
to.setExp(to.exp() * 10 + (c - '0'));
currentLexState = LEXEMA_NUMBER_STARTED_E_VALUE;
break _next_char;
default:
throw new IllegalArgumentException(ERROR_INCORRECT_NUMBER_MESSAGE
+ ". Unexpected char '" + c + "' at the position " + pos);
}
}
case LEXEMA_NUMBER_STARTED_E_VALUE: {
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
to.setExp(to.exp() * 10 + (c - '0'));
break _next_char;
default:
throw new IllegalArgumentException(ERROR_INCORRECT_NUMBER_MESSAGE
+ ". Unexpected char '" + c + "' at the position " + pos);
}
}
default:
throw new IllegalStateException();
}
}
setNumber(to, numberMinuses, numberMantissaExp);
return numberOverflow;
}
private final Next next = () -> JsonParser.this.next();
private final MutableJsonNumber number = new MutableJsonNumber();
private final JsonStringBuilder string;
private JsonParserListener listener;
private boolean notifyObjectMemberNameString;
private CharSequence currentData;
private int currentLen;
private int currentStart;
private int currentPos;
private int currentLexemaState;
private int currentLexemaPosition;
private int numberMantissaExp;
private int numberMinuses;
private boolean numberOverflow;
private String error;
private int errorPosition;
private int[] scopeStack = new int[8];
private int scopeStackDepth;
public JsonParser() {
this(new CopyingStringBuilder());
}
public JsonParser(final JsonStringBuilder stringBuilder) {
string = stringBuilder;
currentLexemaPosition = RESET_REQUIRED;
currentLexemaState = LEXEMA_READY;
pushScope(EXPRESSION_INITIAL);
}
public boolean isNotifyObjectMemberNameString() {
return notifyObjectMemberNameString;
}
public JsonParser setNotifyObjectMemberNameString(final boolean notifyObjectMemberNameString) {
this.notifyObjectMemberNameString = notifyObjectMemberNameString;
return this;
}
public JsonParser setListener(final JsonParserListener listener) {
this.listener = listener;
return this;
}
public String getError() {
return error;
}
public int getErrorPosition() {
return errorPosition;
}
public boolean hasError() {
return error != null;
}
public void parseAndEoj(final CharSequence data) {
parse(data);
eoj();
}
public Next parse(final CharSequence data) {
return parse(data, 0, data.length());
}
public Next parse(final CharSequence data, final int start, final int len) {
this.currentData = data;
this.currentStart = start;
this.currentLen = len;
this.currentPos = 0;
return next();
}
private Next next() {
final JsonParserListener lnr = listener;
assert lnr != null;
int currentLexPos = currentLexemaPosition;
if (currentLexPos < 0) {
if (currentLexPos < JSON_STARTED_NOTIFICATION_REQUIRED) {
doReset();
}
lnr.onJsonStarted();
}
int currentLexState = currentLexemaState;
final JsonStringBuilder stringBuilder = this.string;
final CharSequence data = currentData;
final int start = currentStart;
final int len = currentLen;
int pos = currentPos;
try {
_end:
while (pos < len) {
char c = data.charAt(start + pos);
if (currentLexState >= LEXEMA_READY) {
_next_char:
switch (c) {
case 0x09:
case 0x0a:
case 0x0d:
case 0x20:
break;
case '{': {
currentLexPos = pos;
currentLexState = LEXEMA_CURLY_BRACKET_LEFT_READY;
final int r = onCurlyBracketLeft(lnr, currentLexPos);
if (r == 0) {
break;
}
if (r > 0) {
pos++;
break _end;
}
return null;
}
case '}': {
currentLexPos = pos;
currentLexState = LEXEMA_CURLY_BRACKET_RIGHT_READY;
final int r = onCurlyBracketRight(lnr, currentLexPos);
if (r == 0) {
break;
}
if (r > 0) {
pos++;
break _end;
}
return null;
}
case '[': {
currentLexPos = pos;
currentLexState = LEXEMA_BOX_BRACKET_LEFT_READY;
final int r = onBoxBracketLeft(lnr, currentLexPos);
if (r == 0) {
break;
}
if (r > 0) {
pos++;
break _end;
}
return null;
}
case ']': {
currentLexPos = pos;
currentLexState = LEXEMA_BOX_BRACKET_RIGHT_READY;
final int r = onBoxBracketRight(lnr, currentLexPos);
if (r == 0) {
break;
}
if (r > 0) {
pos++;
break _end;
}
return null;
}
case ',': {
currentLexPos = pos;
currentLexState = LEXEMA_COMMA_READY;
final int r = onComma(currentLexPos);
if (r == 0) {
break;
}
return null;
}
case ':': {
currentLexPos = pos;
currentLexState = LEXEMA_COLON_READY;
final int r = onColon(currentLexPos);
if (r == 0) {
break;
}
return null;
}
case 't': {
if (currentLexState > LEXEMA_NUMBER_READY) {
error(ERROR_TRUE_EXPECTED_MESSAGE, pos);
return null;
}
currentLexPos = pos;
if (len - pos > 3) { // try to read the whole 'true' value
if (data.charAt(++pos + start) == 'r'
&& data.charAt(++pos + start) == 'u'
&& data.charAt(++pos + start) == 'e') {
currentLexState = LEXEMA_TRUE_READY;
final int r = onTrue(lnr, currentLexPos);
if (r == 0) {
break _next_char;
}
if (r > 0) {
pos++;
break _end;
}
return null;
}
error(ERROR_TRUE_EXPECTED_MESSAGE, currentLexPos);
return null;
}
currentLexState = LEXEMA_TRUE_STARTED_T;
break;
}
case 'f': {
if (currentLexState > LEXEMA_NUMBER_READY) {
error(ERROR_FALSE_EXPECTED_MESSAGE, pos);
return null;
}
currentLexPos = pos;
if (len - pos > 4) { // try to read the whole 'false' value
if (data.charAt(++pos + start) == 'a'
&& data.charAt(++pos + start) == 'l'
&& data.charAt(++pos + start) == 's'
&& data.charAt(++pos + start) == 'e') {
currentLexState = LEXEMA_FALSE_READY;
final int r = onFalse(lnr, currentLexPos);
if (r == 0) {
break _next_char;
}
if (r > 0) {
pos++;
break _end;
}
return null;
}
error(ERROR_FALSE_EXPECTED_MESSAGE, currentLexPos);
return null;
}
currentLexState = LEXEMA_FALSE_STARTED_F;
break;
}
case 'n': {
if (currentLexState > LEXEMA_NUMBER_READY) {
error(ERROR_NULL_EXPECTED_MESSAGE, pos);
return null;
}
currentLexPos = pos;
if (len - pos > 3) { // try to read the whole 'null' value
if (data.charAt(++pos + start) == 'u'
&& data.charAt(++pos + start) == 'l'
&& data.charAt(++pos + start) == 'l') {
currentLexState = LEXEMA_NULL_READY;
final int r = onNull(lnr, currentLexPos);
if (r == 0) {
break _next_char;
}
if (r > 0) {
pos++;
break _end;
}
return null;
}
error(ERROR_NULL_EXPECTED_MESSAGE, currentLexPos);
return null;
}
currentLexState = LEXEMA_NULL_STARTED_N;
break;
}
case '"': {
stringBuilder.start(data, start + pos);
currentLexPos = pos;
if (len - pos > 1) { // try to read available part of the string value
pos++;
final int startStringPos = pos;
while (true) {
c = data.charAt(start + pos);
switch (c) {
case '"':
stringBuilder.append(data, start + startStringPos, pos - startStringPos);
currentLexState = LEXEMA_STRING_READY;
final int r = onStringReady(lnr, currentLexPos);
if (r == 0) {
break _next_char;
}
if (r > 0) {
pos++;
break _end;
}
return null;
case '\\':
stringBuilder.append(data, startStringPos, pos - startStringPos);
stringBuilder.appendEscape();
currentLexState = LEXEMA_STRING_STARTED_ESCAPE;
break _next_char;
default:
break;
}
if (++pos == len) {
stringBuilder.append(data, startStringPos, pos - startStringPos);
break;
}
}
}
currentLexState = LEXEMA_STRING_STARTED;
break;
}
case '-': {
number.setMantissa(0);
number.setExp(0);
numberMantissaExp = 0;
numberMinuses = 2;
numberOverflow = false;
currentLexPos = pos;
currentLexState = LEXEMA_NUMBER_STARTED_MANTISSA_SIGN;
break;
}
case '+': {
number.setMantissa(0);
number.setExp(0);
numberMantissaExp = 0;
numberMinuses = 0;
numberOverflow = false;
currentLexPos = pos;
currentLexState = LEXEMA_NUMBER_STARTED_MANTISSA_SIGN;
break;
}
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9': {
number.setMantissa(c - '0');
number.setExp(0);
numberMantissaExp = 0;
numberMinuses = 0;
numberOverflow = false;
currentLexPos = pos;
if (len - pos > 1) { // try to read available part of the number value's mantissa
pos++;
while (true) {
c = data.charAt(start + pos);
if (c >= '0' && c <= '9') {
final long m = number.mantissa();
numberOverflow |= m > MAX_MANTISSA_BASE;
if (!numberOverflow) {
number.setMantissa(m * 10 + (c - '0'));
} else {
numberMantissaExp++;
}
if (++pos == len) {
break;
}
continue;
}
switch (c) {
case '.':
currentLexState = LEXEMA_NUMBER_STARTED_MANTISSA_FRACTIONAL_PART;
break _next_char;
case 'e':
case 'E':
currentLexState = LEXEMA_NUMBER_STARTED_E;
break _next_char;
case 0x09:
case 0x0a:
case 0x0d:
case 0x20:
case '{':
case '}':
case '[':
case ']':
case ',':
case ':':
pos--;
currentLexState = LEXEMA_NUMBER_READY;
final int r = onNumber(lnr, currentLexPos);
if (r == 0) {
break _next_char;
}
if (r > 0) {
pos++;
break _end;
}
return null;
default:
error(ERROR_INCORRECT_NUMBER_MESSAGE, pos);
return null;
}
}
}
currentLexState = LEXEMA_NUMBER_STARTED_MANTISSA_INTEGER_PART;
break;
}
default:
error(ERROR_UNEXPECTED_CHAR_MESSAGE, pos);
return null;
}
} else {
_next_char:
switch (currentLexState) {
/* string value - the rest */
case LEXEMA_STRING_STARTED: {
final int startStringPos = pos;
while (true) {
switch (c) {
case '"':
stringBuilder.append(data, startStringPos, pos - startStringPos);
currentLexState = LEXEMA_STRING_READY;
final int r = onStringReady(lnr, currentLexPos);
if (r == 0) {
break _next_char;
}
if (r > 0) {
pos++;
break _end;
}
return null;
case '\\':
stringBuilder.append(data, startStringPos, pos - startStringPos);
stringBuilder.appendEscape();
currentLexState = LEXEMA_STRING_STARTED_ESCAPE;
break _next_char;
default:
break;
}
if (++pos == len) {
stringBuilder.append(data, startStringPos, pos - startStringPos);
break;
}
c = data.charAt(start + pos);
}
break;
}
case LEXEMA_STRING_STARTED_ESCAPE: {
switch (c) {
case '"':
stringBuilder.appendEscapedQuotationMark();
currentLexState = LEXEMA_STRING_STARTED;
break _next_char;
case '\\':
stringBuilder.appendEscapedReverseSolidus();
currentLexState = LEXEMA_STRING_STARTED;
break _next_char;
case '/':
stringBuilder.appendEscapedSolidus();
currentLexState = LEXEMA_STRING_STARTED;
break _next_char;
case 'b':
stringBuilder.appendEscapedBackspace();
currentLexState = LEXEMA_STRING_STARTED;
break _next_char;
case 'f':
stringBuilder.appendEscapedFormfeed();
currentLexState = LEXEMA_STRING_STARTED;
break _next_char;
case 'n':
stringBuilder.appendEscapedNewLine();
currentLexState = LEXEMA_STRING_STARTED;
break _next_char;
case 'r':
stringBuilder.appendEscapedCarriageReturn();
currentLexState = LEXEMA_STRING_STARTED;
break _next_char;
case 't':
stringBuilder.appendEscapedHorisontalTab();
currentLexState = LEXEMA_STRING_STARTED;
break _next_char;
case 'u':
stringBuilder.appendEscapedUnicodeU();
currentLexState = LEXEMA_STRING_STARTED_ESCAPE_UNICODE;
break _next_char;
default:
error(ERROR_INCORRECT_ESCAPING_MESSAGE, pos);
return null;
}
}
case LEXEMA_STRING_STARTED_ESCAPE_UNICODE: {
if (stringBuilder.appendEscapedUnicodeChar1(c)) {
currentLexState = LEXEMA_STRING_STARTED_ESCAPE_UNICODE_1;
break;
} else {
error(ERROR_MESSAGE_INCORRECT_UNICODE_ESCAPING, pos);
return null;
}
}
case LEXEMA_STRING_STARTED_ESCAPE_UNICODE_1: {
if (stringBuilder.appendEscapedUnicodeChar2(c)) {
currentLexState = LEXEMA_STRING_STARTED_ESCAPE_UNICODE_2;
break;
} else {
error(ERROR_MESSAGE_INCORRECT_UNICODE_ESCAPING, pos);
return null;
}
}
case LEXEMA_STRING_STARTED_ESCAPE_UNICODE_2: {
if (stringBuilder.appendEscapedUnicodeChar3(c)) {
currentLexState = LEXEMA_STRING_STARTED_ESCAPE_UNICODE_3;
break;
} else {
error(ERROR_MESSAGE_INCORRECT_UNICODE_ESCAPING, pos);
return null;
}
}
case LEXEMA_STRING_STARTED_ESCAPE_UNICODE_3: {
if (stringBuilder.appendEscapedUnicodeChar4(c)) {
currentLexState = LEXEMA_STRING_STARTED;
break;
} else {
error(ERROR_MESSAGE_INCORRECT_UNICODE_ESCAPING, pos);
return null;
}
}
/* number value - the rest */
case LEXEMA_NUMBER_STARTED_MANTISSA_INTEGER_PART: {
while (true) {
if (c >= '0' && c <= '9') {
final long m = number.mantissa();
numberOverflow |= m > MAX_MANTISSA_BASE;
if (!numberOverflow) {
number.setMantissa(m * 10 + (c - '0'));
} else {
numberMantissaExp++;
}
if (++pos == len) {
break _end;
}
c = data.charAt(start + pos);
continue;
}
switch (c) {
case '.':
currentLexState = LEXEMA_NUMBER_STARTED_MANTISSA_FRACTIONAL_PART;
break _next_char;
case 'e':
case 'E':
currentLexState = LEXEMA_NUMBER_STARTED_E;
break _next_char;
case 0x09:
case 0x0a:
case 0x0d:
case 0x20:
case '{':
case '}':
case '[':
case ']':
case ',':
case ':':
pos--;
currentLexState = LEXEMA_NUMBER_READY;
final int r = onNumber(lnr, currentLexPos);
if (r == 0) {
break _next_char;
}
if (r > 0) {
pos++;
break _end;
}
return null;
default:
error(ERROR_INCORRECT_NUMBER_MESSAGE, pos);
return null;
}
}
}
case LEXEMA_NUMBER_STARTED_MANTISSA_SIGN: {
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
number.setMantissa(c - '0');
currentLexState = LEXEMA_NUMBER_STARTED_MANTISSA_INTEGER_PART;
break _next_char;
default:
error(ERROR_INCORRECT_NUMBER_MESSAGE, pos);
return null;
}
}
case LEXEMA_NUMBER_STARTED_MANTISSA_FRACTIONAL_PART: {
while (true) {
if (c >= '0' && c <= '9') {
final long m = number.mantissa();
numberOverflow |= m > MAX_MANTISSA_BASE;
if (!numberOverflow) {
number.setMantissa(m * 10 + (c - '0'));
numberMantissaExp--;
}
if (++pos == len) {
break _end;
}
c = data.charAt(start + pos);
continue;
}
switch (c) {
case 'e':
case 'E':
currentLexState = LEXEMA_NUMBER_STARTED_E;
break _next_char;
case 0x09:
case 0x0a:
case 0x0d:
case 0x20:
case '{':
case '}':
case '[':
case ']':
case ',':
case ':':
pos--;
currentLexState = LEXEMA_NUMBER_READY;
final int r = onNumber(lnr, currentLexPos);
if (r == 0) {
break _next_char;
}
if (r > 0) {
pos++;
break _end;
}
return null;
default:
error(ERROR_INCORRECT_NUMBER_MESSAGE, pos);
return null;
}
}
}
case LEXEMA_NUMBER_STARTED_E: {
switch (c) {
case '+':
currentLexState = LEXEMA_NUMBER_STARTED_E_SIGN;
break _next_char;
case '-':
numberMinuses = numberMinuses | 1;
currentLexState = LEXEMA_NUMBER_STARTED_E_SIGN;
break _next_char;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
number.setExp(number.exp() * 10 + (c - '0'));
currentLexState = LEXEMA_NUMBER_STARTED_E_VALUE;
break _next_char;
default:
error(ERROR_INCORRECT_NUMBER_MESSAGE, pos);
return null;
}
}
case LEXEMA_NUMBER_STARTED_E_SIGN: {
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
number.setExp(number.exp() * 10 + (c - '0'));
currentLexState = LEXEMA_NUMBER_STARTED_E_VALUE;
break _next_char;
default:
error(ERROR_INCORRECT_NUMBER_MESSAGE, pos);
return null;
}
}
case LEXEMA_NUMBER_STARTED_E_VALUE: {
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
number.setExp(number.exp() * 10 + (c - '0'));
currentLexState = LEXEMA_NUMBER_STARTED_E_VALUE;
break _next_char;
case 0x09:
case 0x0a:
case 0x0d:
case 0x20:
case '{':
case '}':
case '[':
case ']':
case ',':
case ':':
pos--;
currentLexState = LEXEMA_NUMBER_READY;
final int r = onNumber(lnr, currentLexPos);
if (r == 0) {
break _next_char;
}
if (r > 0) {
pos++;
break _end;
}
return null;
default:
error(ERROR_INCORRECT_NUMBER_MESSAGE, pos);
return null;
}
}
/* 'true' value - the rest */
case LEXEMA_TRUE_STARTED_T: {
switch (c) {
case 'r':
currentLexState = LEXEMA_TRUE_STARTED_TR;
break _next_char;
default:
error(ERROR_TRUE_EXPECTED_MESSAGE, pos);
return null;
}
}
case LEXEMA_TRUE_STARTED_TR: {
switch (c) {
case 'u':
currentLexState = LEXEMA_TRUE_STARTED_TRU;
break _next_char;
default:
error(ERROR_TRUE_EXPECTED_MESSAGE, pos);
return null;
}
}
case LEXEMA_TRUE_STARTED_TRU: {
switch (c) {
case 'e':
currentLexState = LEXEMA_TRUE_READY;
final int r = onTrue(lnr, currentLexPos);
if (r == 0) {
break _next_char;
}
if (r > 0) {
pos++;
break _end;
}
return null;
default:
error(ERROR_TRUE_EXPECTED_MESSAGE, pos);
return null;
}
}
/* 'false' value - the rest */
case LEXEMA_FALSE_STARTED_F: {
switch (c) {
case 'a':
currentLexState = LEXEMA_FALSE_STARTED_FA;
break _next_char;
default:
error(ERROR_FALSE_EXPECTED_MESSAGE, pos);
return null;
}
}
case LEXEMA_FALSE_STARTED_FA: {
switch (c) {
case 'l':
currentLexState = LEXEMA_FALSE_STARTED_FAL;
break _next_char;
default:
error(ERROR_FALSE_EXPECTED_MESSAGE, pos);
return null;
}
}
case LEXEMA_FALSE_STARTED_FAL: {
switch (c) {
case 's':
currentLexState = LEXEMA_FALSE_STARTED_FALS;
break _next_char;
default:
error(ERROR_FALSE_EXPECTED_MESSAGE, pos);
return null;
}
}
case LEXEMA_FALSE_STARTED_FALS: {
switch (c) {
case 'e':
currentLexState = LEXEMA_FALSE_READY;
final int r = onFalse(lnr, currentLexPos);
if (r == 0) {
break _next_char;
}
if (r > 0) {
pos++;
break _end;
}
return null;
default:
error(ERROR_FALSE_EXPECTED_MESSAGE, pos);
return null;
}
}
/* 'null' value - the rest */
case LEXEMA_NULL_STARTED_N: {
switch (c) {
case 'u':
currentLexState = LEXEMA_NULL_STARTED_NU;
break _next_char;
default:
error(ERROR_NULL_EXPECTED_MESSAGE, pos);
return null;
}
}
case LEXEMA_NULL_STARTED_NU: {
switch (c) {
case 'l':
currentLexState = LEXEMA_NULL_STARTED_NUL;
break _next_char;
default:
error(ERROR_NULL_EXPECTED_MESSAGE, pos);
return null;
}
}
case LEXEMA_NULL_STARTED_NUL: {
switch (c) {
case 'l':
currentLexState = LEXEMA_NULL_READY;
final int r = onNull(lnr, currentLexPos);
if (r == 0) {
break _next_char;
}
if (r > 0) {
pos++;
break _end;
}
return null;
default:
error(ERROR_NULL_EXPECTED_MESSAGE, pos);
return null;
}
}
/* unknown state */
default:
error(ERROR_INTERNAL_UNEXPECTED_LEXEMA_ERROR_MESSAGE, pos);
return null;
}
}
pos++;
}
return pos < len ? next : null;
} finally {
currentPos = pos;
currentLexemaState = currentLexState;
currentLexemaPosition = currentLexPos;
}
}
/**
* End of JSON
*
* @return this
*/
public JsonParser eoj() {
final JsonParserListener lnr = listener;
if (lnr != null) {
if (error == null) {
onEoj(lnr, currentLexemaPosition);
}
lnr.onJsonEnded();
}
currentLexemaPosition = RESET_REQUIRED;
return this;
}
public JsonParser reset() {
doReset();
currentLexemaPosition = JSON_STARTED_NOTIFICATION_REQUIRED;
return this;
}
private void doReset() {
currentLexemaState = LEXEMA_READY;
clearScope();
pushScope(EXPRESSION_INITIAL);
error = null;
}
private void error(final String error, final int position) {
final JsonParserListener lnr = listener;
assert lnr != null;
this.error = error;
this.errorPosition = position;
lnr.onError(error, position);
}
private static void setNumber(
final MutableJsonNumber number,
final int numberMinuses,
final int numberMantissaExp) {
if ((numberMinuses & 2) != 0) {
number.setMantissa(-number.mantissa());
}
if ((numberMinuses & 1) != 0) {
number.setExp(-number.exp());
}
number.setExp(number.exp() + numberMantissaExp);
}
private int onCurlyBracketLeft(final JsonParserListener lnr, final int lexemaPosition) {
final int currentScope = peekScope();
switch (currentScope) {
case EXPRESSION_INITIAL: {
final boolean r = lnr.onObjectStarted();
replaceScope(EXPRESSION_OBJECT_STARTED);
if (r) {
break;
}
return 1;
}
case EXPRESSION_OBJECT_STARTED_MEMBER_NAME_VALUE_COLON_DELIMITER: {
final boolean r = lnr.onObjectStarted();
replaceScope(EXPRESSION_OBJECT_STARTED_MEMBER_VALUE);
pushScope(EXPRESSION_OBJECT_STARTED);
if (r) {
break;
}
return 1;
}
case EXPRESSION_ARRAY_STARTED:
case EXPRESSION_ARRAY_STARTED_COMMA_DELIMITER: {
final boolean r = lnr.onObjectStarted();
replaceScope(EXPRESSION_ARRAY_STARTED_VALUE);
pushScope(EXPRESSION_OBJECT_STARTED);
if (r) {
break;
}
return 1;
}
default:
error(ERROR_UNEXPECTED_CURLY_BRACKET_LEFT_MESSAGE, lexemaPosition);
return -1;
}
return 0;
}
private int onCurlyBracketRight(final JsonParserListener lnr, final int lexemaPosition) {
final int currentScope = peekScope();
switch (currentScope) {
case EXPRESSION_OBJECT_STARTED:
case EXPRESSION_OBJECT_STARTED_MEMBER_COMMA_DELIMITER: {
final boolean r = lnr.onObjectEnded();
popScope();
if (r) {
break;
}
return 1;
}
case EXPRESSION_OBJECT_STARTED_MEMBER_VALUE: {
final boolean r = lnr.onObjectEnded();
popScope();
if (r) {
break;
}
return 1;
}
default:
error(ERROR_UNEXPECTED_CURLY_BRACKET_RIGHT_MESSAGE, lexemaPosition);
return -1;
}
return 0;
}
private int onBoxBracketLeft(final JsonParserListener lnr, final int lexemaPosition) {
final int currentScope = peekScope();
switch (currentScope) {
case EXPRESSION_INITIAL: {
final boolean r = lnr.onArrayStarted();
replaceScope(EXPRESSION_ARRAY_STARTED);
if (r) {
break;
}
return 1;
}
case EXPRESSION_OBJECT_STARTED_MEMBER_NAME_VALUE_COLON_DELIMITER: {
final boolean r = lnr.onArrayStarted();
replaceScope(EXPRESSION_OBJECT_STARTED_MEMBER_VALUE);
pushScope(EXPRESSION_ARRAY_STARTED);
if (r) {
break;
}
return 1;
}
case EXPRESSION_ARRAY_STARTED:
case EXPRESSION_ARRAY_STARTED_COMMA_DELIMITER: {
final boolean r = lnr.onArrayStarted();
replaceScope(EXPRESSION_ARRAY_STARTED_VALUE);
pushScope(EXPRESSION_ARRAY_STARTED);
if (r) {
break;
}
return 1;
}
default:
error(ERROR_UNEXPECTED_BOX_BRACKET_LEFT_MESSAGE, lexemaPosition);
return -1;
}
return 0;
}
private int onBoxBracketRight(final JsonParserListener lnr, final int lexemaPosition) {
final int currentScope = peekScope();
switch (currentScope) {
case EXPRESSION_ARRAY_STARTED:
case EXPRESSION_ARRAY_STARTED_COMMA_DELIMITER: {
final boolean r = lnr.onArrayEnded();
popScope();
if (r) {
break;
}
return 1;
}
case EXPRESSION_ARRAY_STARTED_VALUE: {
final boolean r = lnr.onArrayEnded();
popScope();
if (r) {
break;
}
return 1;
}
default:
error(ERROR_UNEXPECTED_BOX_BRACKET_RIGHT_MESSAGE, lexemaPosition);
return -1;
}
return 0;
}
private int onComma(final int lexemaPosition) {
final int currentScope = peekScope();
switch (currentScope) {
case EXPRESSION_OBJECT_STARTED_MEMBER_VALUE:
replaceScope(EXPRESSION_OBJECT_STARTED_MEMBER_COMMA_DELIMITER);
break;
case EXPRESSION_ARRAY_STARTED_VALUE:
replaceScope(EXPRESSION_ARRAY_STARTED_COMMA_DELIMITER);
break;
default:
error(ERROR_UNEXPECTED_COMMA_MESSAGE, lexemaPosition);
return -1;
}
return 0;
}
private int onColon(final int lexemaPosition) {
final int currentScope = peekScope();
switch (currentScope) {
case EXPRESSION_OBJECT_STARTED_MEMBER_NAME:
replaceScope(EXPRESSION_OBJECT_STARTED_MEMBER_NAME_VALUE_COLON_DELIMITER);
break;
default:
error(ERROR_UNEXPECTED_COLON_MESSAGE, lexemaPosition);
return -1;
}
return 0;
}
private int onStringReady(final JsonParserListener lnr, final int lexemaPosition) {
final int currentScope = peekScope();
final JsonStringBuilder value = string;
switch (currentScope) {
case EXPRESSION_INITIAL: {
final boolean r = lnr.onStringValue(value);
popScope();
if (r) {
break;
}
return 1;
}
case EXPRESSION_OBJECT_STARTED:
case EXPRESSION_OBJECT_STARTED_MEMBER_COMMA_DELIMITER: {
final boolean r = lnr.onObjectMember(value);
if (notifyObjectMemberNameString) {
lnr.onStringValue(value);
}
replaceScope(EXPRESSION_OBJECT_STARTED_MEMBER_NAME);
if (r) {
break;
}
return 1;
}
case EXPRESSION_OBJECT_STARTED_MEMBER_NAME_VALUE_COLON_DELIMITER: {
final boolean r = lnr.onStringValue(value);
replaceScope(EXPRESSION_OBJECT_STARTED_MEMBER_VALUE);
if (r) {
break;
}
return 1;
}
case EXPRESSION_ARRAY_STARTED:
case EXPRESSION_ARRAY_STARTED_COMMA_DELIMITER: {
final boolean r = lnr.onStringValue(value);
replaceScope(EXPRESSION_ARRAY_STARTED_VALUE);
if (r) {
break;
}
return 1;
}
default:
error(ERROR_UNEXPECTED_STRING_MESSAGE, lexemaPosition);
return -1;
}
return 0;
}
private int onNumber(final JsonParserListener lnr, final int lexemaPosition) {
setNumber(number, numberMinuses, numberMantissaExp);
final int currentScope = peekScope();
switch (currentScope) {
case EXPRESSION_INITIAL: {
final boolean r = lnr.onNumberValue(number, numberOverflow);
popScope();
if (r) {
break;
}
return 1;
}
case EXPRESSION_OBJECT_STARTED_MEMBER_NAME_VALUE_COLON_DELIMITER: {
final boolean r = lnr.onNumberValue(number, numberOverflow);
replaceScope(EXPRESSION_OBJECT_STARTED_MEMBER_VALUE);
if (r) {
break;
}
return 1;
}
case EXPRESSION_ARRAY_STARTED:
case EXPRESSION_ARRAY_STARTED_COMMA_DELIMITER: {
final boolean r = lnr.onNumberValue(number, numberOverflow);
replaceScope(EXPRESSION_ARRAY_STARTED_VALUE);
if (r) {
break;
}
return 1;
}
default:
error(ERROR_UNEXPECTED_NUMBER_MESSAGE, lexemaPosition);
return -1;
}
return 0;
}
private int onTrue(final JsonParserListener lnr, final int lexemaPosition) {
final int currentScope = peekScope();
switch (currentScope) {
case EXPRESSION_INITIAL: {
final boolean r = lnr.onTrueValue();
popScope();
if (r) {
break;
}
return 1;
}
case EXPRESSION_OBJECT_STARTED_MEMBER_NAME_VALUE_COLON_DELIMITER: {
final boolean r = lnr.onTrueValue();
replaceScope(EXPRESSION_OBJECT_STARTED_MEMBER_VALUE);
if (r) {
break;
}
return 1;
}
case EXPRESSION_ARRAY_STARTED:
case EXPRESSION_ARRAY_STARTED_COMMA_DELIMITER: {
final boolean r = lnr.onTrueValue();
replaceScope(EXPRESSION_ARRAY_STARTED_VALUE);
if (r) {
break;
}
return 1;
}
default:
error(ERROR_UNEXPECTED_TRUE_MESSAGE, lexemaPosition);
return -1;
}
return 0;
}
private int onFalse(final JsonParserListener lnr, final int lexemaPosition) {
final int currentScope = peekScope();
switch (currentScope) {
case EXPRESSION_INITIAL: {
final boolean r = lnr.onFalseValue();
popScope();
if (r) {
break;
}
return 1;
}
case EXPRESSION_OBJECT_STARTED_MEMBER_NAME_VALUE_COLON_DELIMITER: {
final boolean r = lnr.onFalseValue();
replaceScope(EXPRESSION_OBJECT_STARTED_MEMBER_VALUE);
if (r) {
break;
}
return 1;
}
case EXPRESSION_ARRAY_STARTED:
case EXPRESSION_ARRAY_STARTED_COMMA_DELIMITER: {
final boolean r = lnr.onFalseValue();
replaceScope(EXPRESSION_ARRAY_STARTED_VALUE);
if (r) {
break;
}
return 1;
}
default:
error(ERROR_UNEXPECTED_FALSE_MESSAGE, lexemaPosition);
return -1;
}
return 0;
}
private int onNull(final JsonParserListener lnr, final int lexemaPosition) {
final int currentScope = peekScope();
switch (currentScope) {
case EXPRESSION_INITIAL: {
final boolean r = lnr.onNullValue();
popScope();
if (r) {
break;
}
return 1;
}
case EXPRESSION_OBJECT_STARTED_MEMBER_NAME_VALUE_COLON_DELIMITER: {
final boolean r = lnr.onNullValue();
replaceScope(EXPRESSION_OBJECT_STARTED_MEMBER_VALUE);
if (r) {
break;
}
return 1;
}
case EXPRESSION_ARRAY_STARTED:
case EXPRESSION_ARRAY_STARTED_COMMA_DELIMITER: {
final boolean r = lnr.onNullValue();
replaceScope(EXPRESSION_ARRAY_STARTED_VALUE);
if (r) {
break;
}
return 1;
}
default:
error(ERROR_UNEXPECTED_NULL_MESSAGE, lexemaPosition);
return -1;
}
return 0;
}
private int onEoj(final JsonParserListener lnr, final int lexemaPosition) {
final int currentScope = peekScope();
switch (currentScope) {
case -1: // no scope
break;
case EXPRESSION_INITIAL:
/* check we are in progress of parsing of the first lexema */
switch (currentLexemaState) {
case LEXEMA_TRUE_STARTED_T:
case LEXEMA_TRUE_STARTED_TR:
case LEXEMA_TRUE_STARTED_TRU:
error(ERROR_TRUE_EXPECTED_MESSAGE, lexemaPosition);
return -1;
case LEXEMA_FALSE_STARTED_F:
case LEXEMA_FALSE_STARTED_FA:
case LEXEMA_FALSE_STARTED_FAL:
case LEXEMA_FALSE_STARTED_FALS:
error(ERROR_FALSE_EXPECTED_MESSAGE, lexemaPosition);
return -1;
case LEXEMA_NULL_STARTED_N:
case LEXEMA_NULL_STARTED_NU:
case LEXEMA_NULL_STARTED_NUL:
error(ERROR_NULL_EXPECTED_MESSAGE, lexemaPosition);
return -1;
case LEXEMA_STRING_STARTED:
case LEXEMA_STRING_STARTED_ESCAPE:
case LEXEMA_STRING_STARTED_ESCAPE_UNICODE:
case LEXEMA_STRING_STARTED_ESCAPE_UNICODE_1:
case LEXEMA_STRING_STARTED_ESCAPE_UNICODE_2:
case LEXEMA_STRING_STARTED_ESCAPE_UNICODE_3:
error(ERROR_INCORRECT_STRING_MESSAGE, lexemaPosition);
return -1;
case LEXEMA_NUMBER_STARTED_MANTISSA_SIGN:
case LEXEMA_NUMBER_STARTED_E:
case LEXEMA_NUMBER_STARTED_E_SIGN:
error(ERROR_INCORRECT_NUMBER_MESSAGE, lexemaPosition);
return -1;
case LEXEMA_NUMBER_STARTED_MANTISSA_INTEGER_PART:
case LEXEMA_NUMBER_STARTED_MANTISSA_FRACTIONAL_PART:
case LEXEMA_NUMBER_STARTED_E_VALUE:
setNumber(number, numberMinuses, numberMantissaExp); // try to apply the number
lnr.onNumberValue(number, numberOverflow);
popScope();
break;
}
break;
default:
error(ERROR_INTERNAL_UNEXPECTED_LEXEMA_ERROR_MESSAGE, lexemaPosition);
return -1;
}
return 0;
}
private void clearScope() {
scopeStackDepth = 0;
}
private void pushScope(final int expression) {
int[] stack = scopeStack;
int depth = scopeStackDepth;
if (depth == stack.length) {
stack = new int[stack.length << 1];
System.arraycopy(scopeStack, 0, stack, 0, scopeStack.length);
scopeStack = stack;
}
stack[depth++] = expression;
scopeStackDepth = depth;
}
private int popScope() {
assert scopeStackDepth > 0;
return scopeStack[--scopeStackDepth];
}
private int peekScope() {
if (scopeStackDepth < 1) {
return -1;
}
return scopeStack[scopeStackDepth - 1];
}
private void replaceScope(final int expression) {
assert scopeStackDepth > 0;
scopeStack[scopeStackDepth - 1] = expression;
}
}