org.graalvm.util.json.JSONParser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of compiler Show documentation
Show all versions of compiler Show documentation
The GraalVM compiler and the Graal-truffle optimizer.
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.util.json;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
import org.graalvm.collections.EconomicMap;
public class JSONParser {
private final String source;
private final int length;
private int pos = 0;
private static final int EOF = -1;
private static final String TRUE = "true";
private static final String FALSE = "false";
private static final String NULL = "null";
private static final int STATE_EMPTY = 0;
private static final int STATE_ELEMENT_PARSED = 1;
private static final int STATE_COMMA_PARSED = 2;
public JSONParser(String source) {
this.source = source;
this.length = source.length();
}
public JSONParser(Reader source) throws IOException {
this(readFully(source));
}
/**
* Public parse method. Parse a string into a JSON object.
*
* @return the parsed JSON Object
*/
public Object parse() {
final Object value = parseLiteral();
skipWhiteSpace();
if (pos < length) {
throw expectedError(pos, "eof", toString(peek()));
}
return value;
}
/**
* Parses the source as a JSON map using a list of allowed keys. The returned map contains
* values for the allowed keys only but not necessarily all of them. The method returns as soon
* as all allowed keys are parsed, i.e., the rest of the JSON may be left unparsed and
* unchecked. This is useful to parse only few keys from the beginning of a large JSON object.
*
* @param allowedKeys the list of allowed keys
* @return the parsed JSON map containing only values for (not necessarily all) allowed keys
*/
public EconomicMap parseAllowedKeys(List allowedKeys) {
EconomicMap result = EconomicMap.create();
if (allowedKeys.isEmpty()) {
pos = length;
return result;
}
skipWhiteSpace();
int state = STATE_EMPTY;
int c = peek();
if (c == EOF) {
throw expectedError(pos, "json literal", "eof");
}
if (c != '{') {
throw expectedError(pos, "{", toString(c));
}
pos++;
while (pos < length) {
skipWhiteSpace();
c = peek();
switch (c) {
case '"':
if (state == STATE_ELEMENT_PARSED) {
throw expectedError(pos, ", or }", toString(c));
}
final String id = parseString();
expectColon();
final Object value = parseLiteral();
if (allowedKeys.contains(id)) {
result.put(id, value);
}
if (result.size() == allowedKeys.size()) {
pos = length;
return result;
}
state = STATE_ELEMENT_PARSED;
break;
case ',':
if (state != STATE_ELEMENT_PARSED) {
throw error("Trailing comma is not allowed in JSON", pos);
}
state = STATE_COMMA_PARSED;
pos++;
break;
case '}':
if (state == STATE_COMMA_PARSED) {
throw error("Trailing comma is not allowed in JSON", pos);
}
pos++;
return result;
default:
throw expectedError(pos, ", or }", toString(c));
}
}
throw expectedError(pos, ", or }", "eof");
}
@SuppressWarnings("unchecked")
public static EconomicMap parseDict(Reader input) throws IOException {
JSONParser parser = new JSONParser(input);
return (EconomicMap) parser.parse();
}
@SuppressWarnings("unchecked")
public static EconomicMap parseDict(String input) {
JSONParser parser = new JSONParser(input);
return (EconomicMap) parser.parse();
}
private Object parseLiteral() {
skipWhiteSpace();
final int c = peek();
if (c == EOF) {
throw expectedError(pos, "json literal", "eof");
}
switch (c) {
case '{':
return parseObject();
case '[':
return parseArray();
case '"':
return parseString();
case 'f':
return parseKeyword(FALSE, Boolean.FALSE);
case 't':
return parseKeyword(TRUE, Boolean.TRUE);
case 'n':
return parseKeyword(NULL, null);
default:
if (isDigit(c) || c == '-') {
return parseNumber();
} else if (c == '.') {
throw numberError(pos);
} else {
throw expectedError(pos, "json literal", toString(c));
}
}
}
private Object parseObject() {
EconomicMap result = EconomicMap.create();
int state = STATE_EMPTY;
assert peek() == '{';
pos++;
while (pos < length) {
skipWhiteSpace();
final int c = peek();
switch (c) {
case '"':
if (state == STATE_ELEMENT_PARSED) {
throw expectedError(pos, ", or }", toString(c));
}
final String id = parseString();
expectColon();
final Object value = parseLiteral();
final EconomicMap object = result;
object.put(id, value);
state = STATE_ELEMENT_PARSED;
break;
case ',':
if (state != STATE_ELEMENT_PARSED) {
throw error("Trailing comma is not allowed in JSON", pos);
}
state = STATE_COMMA_PARSED;
pos++;
break;
case '}':
if (state == STATE_COMMA_PARSED) {
throw error("Trailing comma is not allowed in JSON", pos);
}
pos++;
return result;
default:
throw expectedError(pos, ", or }", toString(c));
}
}
throw expectedError(pos, ", or }", "eof");
}
private void expectColon() {
skipWhiteSpace();
final int n = next();
if (n != ':') {
throw expectedError(pos - 1, ":", toString(n));
}
}
private Object parseArray() {
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy