
org.reploop.parser.json.JsonAstBuilder Maven / Gradle / Ivy
package org.reploop.parser.json;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.ParserRuleContext;
import org.reploop.parser.json.base.JsonBaseBaseVisitor;
import org.reploop.parser.json.base.JsonBaseParser;
import org.reploop.parser.json.tree.Number;
import org.reploop.parser.json.tree.*;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import static org.apache.commons.lang3.StringUtils.strip;
/**
* Json AST builder.
*
* @author George Cao([email protected])
* @since 2016-10-14 20
*/
public class JsonAstBuilder extends JsonBaseBaseVisitor {
private CommonTokenStream tokens;
public JsonAstBuilder() {
}
public JsonAstBuilder(CommonTokenStream tokens) {
this.tokens = tokens;
}
@Override
public Json visitJson(JsonBaseParser.JsonContext ctx) {
Value value = (Value) visit(ctx.value());
return new Json(value);
}
@Override
public Entity visitObj(JsonBaseParser.ObjContext ctx) {
return new Entity(visit(ctx.pair(), Pair.class));
}
private String stripQuotationMark(String text) {
return strip(text, "\"");
}
private String removeAllWhitespace(String text) {
return text.replaceAll("\\s+", "");
}
@Override
public Pair visitPair(JsonBaseParser.PairContext ctx) {
String text = removeAllWhitespace(stripQuotationMark(ctx.STRING().getText()));
return new Pair(text, visit(ctx.value(), Value.class));
}
@Override
public Array visitArr(JsonBaseParser.ArrContext ctx) {
return new Array(visit(ctx.value(), Value.class));
}
@Override
public Text visitStringValue(JsonBaseParser.StringValueContext ctx) {
return new Text(stripQuotationMark(ctx.STRING().getText()));
}
private , T, E> Optional castIf(D val, T min, T max, Function to, Function cast) {
D minVal = to.apply(min);
D maxVal = to.apply(max);
if (val.compareTo(minVal) >= 0 && val.compareTo(maxVal) <= 0) {
return Optional.of(cast.apply(val));
}
return Optional.empty();
}
@Override
public Number visitNumberValue(JsonBaseParser.NumberValueContext ctx) {
String val = ctx.NUMBER().getText();
try {
// Try integer first
return toNumber(val);
} catch (NumberFormatException e) {
try {
// Then it's must be floating-point number.
return toFloat(val);
} catch (NumberFormatException ex) {
throw new IllegalStateException(val, e);
}
}
}
/**
* Test number value by its legal range to tell its type.
*
* @param val value literal
* @return the type of the number
*/
private Number toNumber(String val) {
Long value = Long.valueOf(val);
Optional ob = castIf(value, Byte.MIN_VALUE, Byte.MAX_VALUE, Byte::longValue, vb -> new ByteVal(vb.byteValue()));
if (ob.isPresent()) {
return ob.get();
}
Optional os = castIf(value, Short.MIN_VALUE, Short.MAX_VALUE, Short::longValue, vs -> new ShortVal(vs.shortValue()));
if (os.isPresent()) {
return os.get();
}
Optional oi = castIf(value, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer::longValue, vi -> new IntVal(vi.intValue()));
if (oi.isPresent()) {
return oi.get();
}
return new LongVal(value);
}
private Number toFloat(String val) {
double value = Double.parseDouble(val);
Optional of = castIf(value, Float.MIN_VALUE, Float.MAX_VALUE, Float::doubleValue, vf -> new FloatVal(vf.floatValue()));
if (of.isPresent()) {
return of.get();
}
return new DoubleVal(value);
}
@Override
public Entity visitObjValue(JsonBaseParser.ObjValueContext ctx) {
return visitObj(ctx.obj());
}
@Override
public Array visitArrValue(JsonBaseParser.ArrValueContext ctx) {
return visitArr(ctx.arr());
}
@Override
public Bool visitTrueValue(JsonBaseParser.TrueValueContext ctx) {
return new Bool(Boolean.TRUE);
}
@Override
public Bool visitFalseValue(JsonBaseParser.FalseValueContext ctx) {
return new Bool(Boolean.FALSE);
}
@Override
public Null visitNullValue(JsonBaseParser.NullValueContext ctx) {
return new Null();
}
private R visit(ParserRuleContext context, Class clazz) {
return clazz.cast(visit(context));
}
private List visit(List contexts, Class clazz) {
if (null != contexts) {
return contexts.stream()
.map(this::visit)
.filter(Objects::nonNull)
.map(clazz::cast)
.collect(Collectors.toList());
}
return Collections.emptyList();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy