All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
sk.uniq.protobuf.parser.impl.ProtoFileVisitor Maven / Gradle / Ivy
/*
* Copyright 2016 Jakub Herkel.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sk.uniq.protobuf.parser.impl;
import sk.uniq.protobuf.schema.ProtoRpc;
import sk.uniq.protobuf.schema.ProtoImport;
import sk.uniq.protobuf.schema.ProtoService;
import sk.uniq.protobuf.schema.ProtoPosition;
import sk.uniq.protobuf.schema.ProtoEnum;
import sk.uniq.protobuf.schema.ProtoOption;
import sk.uniq.protobuf.schema.ProtoMessage;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.antlr.v4.runtime.BufferedTokenStream;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.misc.Interval;
import org.antlr.v4.runtime.misc.ParseCancellationException;
import sk.uniq.protobuf.grammar.ProtoBaseVisitor;
import sk.uniq.protobuf.grammar.ProtoParser;
import sk.uniq.protobuf.parser.ProtoParserOptions;
import sk.uniq.protobuf.schema.*;
import sk.uniq.protobuf.schema.ProtoVersion.Version;
import sk.uniq.protobuf.schema.impl.*;
import static sk.uniq.protobuf.parser.impl.ProtoUtils.*;
/**
*
* @author jherkel
*/
class ProtoFileVisitor extends ProtoBaseVisitor {
private final ProtoFileImpl.Builder pfBuilder;
private final ProtoParserImpl parser;
private final ErrorListener errorListener;
private final BufferedTokenStream tokenStream;
/**
*
* @param filename
* @param parser
*/
public ProtoFileVisitor(String filename, ProtoParserImpl parser, BufferedTokenStream tokenStream, ErrorListener errorListener) {
pfBuilder = ProtoFileImpl.builder().filename(filename);
this.errorListener = errorListener;
this.parser = parser;
this.tokenStream = tokenStream;
}
@Override
public Object visitProto(ProtoParser.ProtoContext ctx) {
List elements = convertResultToList(super.visitProto(ctx));
for (Object obj : elements) {
if (obj instanceof ProtoSyntaxElement) {
pfBuilder.addNestedElement((ProtoSyntaxElement) obj);
} else {
throw new IllegalStateException("Unknown element obj:" + obj.getClass().getName());
}
}
return pfBuilder.build();
}
@Override
public ProtoImport visitImportPB(ProtoParser.ImportPBContext ctx) {
ProtoImport.Scope scope = ctx.WEAK_LITERAL() != null ? ProtoImport.Scope.WEAK : ProtoImport.Scope.PUBLIC;
ProtoImport importPB = ProtoImportImpl.builder().position(position(ctx)).scope(scope).protoFile(ctx.protoFile.getText()).build();
return importPB;
}
@Override
public Object visitConstant(ProtoParser.ConstantContext ctx) {
try {
if (ctx.BOOLEAN_LITERAL() != null) {
return ProtoBoolean.parse(ctx.BOOLEAN_LITERAL().getText());
} else if (ctx.INTEGER_LITERAL() != null) {
return ProtoInteger.parse(ctx.INTEGER_LITERAL().getText(), ctx.MINUS() != null);
} else if (ctx.FLOAT_LITERAL() != null) {
return ProtoFloat.parse(ctx.FLOAT_LITERAL().getText(), ctx.MINUS() != null);
} else if (ctx.STRING_LITERAL() != null) {
return ProtoString.parse(ProtoUtils.removeQuotes(ctx.STRING_LITERAL().getText()));
} else if (ctx.fullIdentifier() != null) {
return ProtoConstantIdentifier.parse(ctx.fullIdentifier().getText());
} else {
throw new IllegalArgumentException("Invalid constant value " + ctx.getText());
}
} catch (IllegalArgumentException ex) {
notifyErrorListeners(position(ctx), ex.getMessage());
}
return null;
}
@Override
public ProtoOption visitOption(ProtoParser.OptionContext ctx) {
try {
processComments(tokenStream, ctx, true);
List nestedElements = convertResultToList(super.visitOption(ctx));
ProtoOptionName optionName = this.findObject(nestedElements, ProtoOptionName.class);
ProtoConstant constant = this.findObject(nestedElements, ProtoConstant.class);
ProtoOption option = ProtoOptionImpl.builder()
.position(position(ctx))
.name(optionName)
.value(constant)
.build();
return option;
} catch (IllegalArgumentException ex) {
notifyErrorListeners(position(ctx), ex.getMessage());
}
return null;
}
@Override
public Object visitOptionName(ProtoParser.OptionNameContext ctx) {
try {
ProtoOptionNameImpl.Builder builder = ProtoOptionNameImpl.builder();
if (ctx.fullIdentifier() != null) {
builder.addIdentifier(ctx.fullIdentifier().getText());
builder.enclosed(true);
} else {
builder.addIdentifier(ctx.IDENTIFIER(0).getText());
}
for (int k = 1; k < ctx.IDENTIFIER().size(); k++) {
builder.addIdentifier(ctx.IDENTIFIER(k).getText());
}
return builder.build();
} catch (IllegalArgumentException ex) {
notifyErrorListeners(position(ctx), ex.getMessage());
}
return null;
}
@Override
public Object visitMessage(ProtoParser.MessageContext ctx) {
try {
List nestedElements = convertResultToList(super.visitMessage(ctx));
ProtoMessage message = ProtoMessageImpl.builder()
.position(position(ctx))
.name(ProtoIdentifierImpl.builder().position(position(ctx.messageName())).name(ctx.messageName().IDENTIFIER().getText()).build())
.addAllNestedElements(nestedElements)
.build();
return message;
} catch (ProtoSchemaException ex) {
notifyErrorListeners(ex.getElement().getPosition(), ex.getMessage());
} catch (IllegalArgumentException ex) {
notifyErrorListeners(position(ctx), ex.getMessage());
}
return null;
}
@Override
public Object visitField(ProtoParser.FieldContext ctx) {
try {
List nestedElements = convertResultToList(super.visitField(ctx));
ProtoMessageFieldImpl.Builder builder = ProtoMessageFieldImpl.builder();
builder.position(position(ctx))
.name(ProtoIdentifierImpl.builder().position(position(ctx.fieldName())).name(ctx.fieldName().IDENTIFIER().getText()).build())
.fieldNumber(Integer.parseInt(ctx.fieldNumber().INTEGER_LITERAL().getText()))
.repeated(ctx.REPEATED_LITERAL() != null)
.addAllNestedElements(nestedElements);
if (ctx.type().protoType() != null) {
builder.fieldType(ProtoType.basicType(ProtoBasicType.fromString(ctx.type().protoType().getText())));
} else if (ctx.type().messageOrEnumType() != null) {
builder.fieldType(ProtoType.messageOrEnumType(ctx.type().getText()));
} else {
notifyErrorListeners(position(ctx), "Unknown type " + ctx.type().getText());
}
return builder.build();
} catch (IllegalArgumentException ex) {
notifyErrorListeners(position(ctx), ex.getMessage());
}
return null;
}
@Override
public Object visitEnumPB(ProtoParser.EnumPBContext ctx) {
try {
List nestedElements = convertResultToList(super.visitEnumPB(ctx));
ProtoEnum enumPB = ProtoEnumImpl.builder()
.position(position(ctx))
.name(ProtoIdentifierImpl.builder().position(position(ctx.enumName())).name(ctx.enumName().IDENTIFIER().getText()).build())
.addAllNestedElements(nestedElements)
.build();
return enumPB;
} catch (IllegalArgumentException ex) {
notifyErrorListeners(position(ctx), ex.getMessage());
}
return null;
}
@Override
public Object visitEnumField(ProtoParser.EnumFieldContext ctx) {
try {
List nestedElements = convertResultToList(super.visitEnumField(ctx));
ProtoEnumFieldImpl.Builder builder = ProtoEnumFieldImpl.builder();
builder.position(position(ctx))
.name(ProtoIdentifierImpl.builder().position(position(ctx.name)).name(ctx.name.getText()).build())
.value(Integer.parseInt(ctx.value.getText()))
.addAllNestedElements(nestedElements);
return builder.build();
} catch (IllegalArgumentException ex) {
notifyErrorListeners(position(ctx), ex.getMessage());
}
return null;
}
@Override
public Object visitService(ProtoParser.ServiceContext ctx) {
Object obj = super.visitService(ctx);
ProtoService service = ProtoServiceImpl.builder()
.position(position(ctx))
.name(ProtoIdentifierImpl.builder().position(position(ctx.serviceName())).name(ctx.serviceName().IDENTIFIER().getText()).build())
.addAllNestedElements(convertResultToList(obj))
.build();
return service;
}
@Override
public Object visitRpc(ProtoParser.RpcContext ctx) {
ProtoRpc rpc = ProtoRpcImpl.builder()
.position(position(ctx))
.name(ProtoIdentifierImpl.builder().position(position(ctx.rpcName())).name(ctx.rpcName().IDENTIFIER().getText()).build())
.messageType(ProtoType.messageType(ctx.argType.getText()))
.messageTypeStream(ctx.argStream != null)
.returnType(ProtoType.messageType(ctx.retType.getText()))
.returnTypeStream(ctx.retStream != null)
.build();
return rpc;
}
@Override
public Object visitSyntax(ProtoParser.SyntaxContext ctx) {
processComments(tokenStream, ctx, true);
try {
Version version = Version.VERSION_3.getName().equals(ProtoUtils.removeQuotes(ctx.version.getText())) ? Version.VERSION_3 : null;
return ProtoVersionImpl.builder().version(version).build();
} catch (IllegalArgumentException ex) {
notifyErrorListeners(position(ctx), ex.getMessage());
}
return ProtoVersionImpl.builder().version(Version.VERSION_3).build();
}
@Override
public Object visitFieldOption(ProtoParser.FieldOptionContext ctx) {
try {
List nestedElements = convertResultToList(super.visitFieldOption(ctx));
ProtoOptionName optionName = this.findObject(nestedElements, ProtoOptionName.class);
ProtoConstant constant = this.findObject(nestedElements, ProtoConstant.class);
ProtoOptionImpl.Builder builder = ProtoOptionImpl.builder();
builder.position(position(ctx))
.name(optionName)
.value(constant);
return builder.build();
} catch (IllegalArgumentException ex) {
notifyErrorListeners(position(ctx), ex.getMessage());
}
return null;
}
@Override
public Object visitOneof(ProtoParser.OneofContext ctx) {
List nestedElements = convertResultToList(super.visitOneof(ctx));
ProtoOneOf message = ProtoOneOfImpl.builder()
.position(position(ctx))
.name(ProtoIdentifierImpl.builder().position(position(ctx.oneofName())).name(ctx.oneofName().IDENTIFIER().getText()).build())
.addAllNestedElements(nestedElements)
.build();
return message;
}
@Override
public Object visitOneofField(ProtoParser.OneofFieldContext ctx) {
try {
List nestedElements = convertResultToList(super.visitOneofField(ctx));
ProtoOneOfFieldImpl.Builder builder = ProtoOneOfFieldImpl.builder();
builder.position(position(ctx))
.name(ProtoIdentifierImpl.builder().position(position(ctx.fieldName())).name(ctx.fieldName().IDENTIFIER().getText()).build())
.fieldNumber(Integer.parseInt(ctx.fieldNumber().INTEGER_LITERAL().getText()))
.addAllNestedElements(nestedElements);
if (ctx.type().protoType() != null) {
builder.fieldType(ProtoType.basicType(ProtoBasicType.fromString(ctx.type().protoType().getText())));
} else if (ctx.type().messageOrEnumType() != null) {
builder.fieldType(ProtoType.messageOrEnumType(ctx.type().getText()));
} else {
notifyErrorListeners(position(ctx), "Unknown type " + ctx.type().getText());
}
return builder.build();
} catch (IllegalArgumentException ex) {
notifyErrorListeners(position(ctx), ex.getMessage());
}
return null;
}
@Override
public Object visitMapField(ProtoParser.MapFieldContext ctx) {
try {
ProtoMapImpl.Builder builder = ProtoMapImpl.builder();
builder.position(position(ctx))
.name(ProtoIdentifierImpl.builder().position(position(ctx.mapName())).name(ctx.mapName().IDENTIFIER().getText()).build())
.fieldNumber(Integer.parseInt(ctx.fieldNumber().INTEGER_LITERAL().getText()))
.keyType(ProtoType.basicType(ProtoBasicType.fromString(ctx.mapKeyType().getText())))
.valueType(ProtoType.basicType(ProtoBasicType.fromString(ctx.mapKeyType().getText())));
return builder.build();
} catch (IllegalArgumentException ex) {
notifyErrorListeners(position(ctx), ex.getMessage());
}
return null;
}
@Override
public Object visitReserved(ProtoParser.ReservedContext ctx) {
try {
List nestedElements = convertResultToList(super.visitReserved(ctx));
if (nestedElements.isEmpty() == false) {
ProtoReservedImpl.Builder builder = ProtoReservedImpl.builder();
builder.position(position(ctx));
if (ctx.fieldNames() != null) {
for (Object obj : nestedElements) {
builder.addName((String) obj);
}
} else {
for (Object obj : nestedElements) {
builder.addRange((ProtoRange) obj);
}
}
return builder.build();
}
} catch (IllegalArgumentException ex) {
notifyErrorListeners(position(ctx), ex.getMessage());
}
return null;
}
@Override
public Object visitReservedFieldName(ProtoParser.ReservedFieldNameContext ctx) {
String identifier = ProtoUtils.removeQuotes(ctx.getText());
if (ProtoIdentifier.isValidIdentifier(identifier) == false) {
throw new IllegalArgumentException("Invalid identifier " + identifier);
}
return ProtoUtils.removeQuotes(ctx.getText());
}
@Override
public Object visitRange(ProtoParser.RangeContext ctx) {
try {
ProtoInteger min = ProtoInteger.parse(ctx.INTEGER_LITERAL(0).getText());
ProtoInteger max = null;
if (ctx.EXTENSIONS_MAX_LITERAL() != null) {
max = new ProtoInteger(ProtoFieldNumber.MAX_NUMBER, ProtoInteger.Formatter.DECIMAL, "max");
} else if (ctx.EXTENSIONS_TO_LITERAL() != null) {
max = ProtoInteger.parse(ctx.INTEGER_LITERAL(1).getText());
}
if (ProtoFieldNumber.isValid(min.getValue()) == false) {
throw new IllegalArgumentException("Invalid range, min is invalid");
}
if (max != null && ProtoFieldNumber.isValid(max.getValue()) == false) {
throw new IllegalArgumentException("Invalid range, max is invalid");
}
if (max != null && min.getValue() > max.getValue()) {
throw new IllegalArgumentException("Invalid range, min > max");
}
return max != null ? new ProtoRange((int) (long) min.getValue(), (int) (long) max.getValue()) : new ProtoRange((int) (long) min.getValue());
} catch (IllegalArgumentException ex) {
notifyErrorListeners(position(ctx), ex.getMessage());
}
return null;
}
@Override
protected Object aggregateResult(Object aggregate, Object nextResult) {
if (nextResult == null) {
return aggregate;
} else if (aggregate == null) {
return nextResult;
} else {
if (aggregate instanceof AggregateArrayList == false) {
AggregateArrayList tmp = new AggregateArrayList<>();
tmp.add(aggregate);
tmp.add(nextResult);
return tmp;
} else {
((List) aggregate).add(nextResult);
return aggregate;
}
}
}
private static List convertResultToList(Object obj) {
if (obj == null) {
return Collections.EMPTY_LIST;
}
if (obj instanceof AggregateArrayList) {
return (List) obj;
} else {
List ret = new AggregateArrayList<>(1);
ret.add((T) obj);
return ret;
}
}
private static ProtoPosition position(Token token) {
int line = token.getLine();
int column = token.getCharPositionInLine();
int startIndex = token.getStartIndex();
int endIndex = token.getStopIndex();
return new ProtoPosition(startIndex, endIndex, line, column, column + token.getText().length());
}
private static ProtoPosition position(ParserRuleContext ctx) {
Interval interval = ctx.getSourceInterval();
Token firstToken = ctx.getStart();
int line = firstToken.getLine();
int column = firstToken.getCharPositionInLine();
int startIndex = firstToken.getStartIndex();
Token lastToken = ctx.getStop();
int endIndex = lastToken.getStopIndex();
return new ProtoPosition(startIndex, endIndex, line, column, column + interval.length());
}
private void notifyErrorListeners(ProtoPosition position, String message) {
errorListener.addError(position, message);
if (parser.getParserOptions().getParseCancellationMode() == ProtoParserOptions.ParserCancellationMode.CANCEL_AFTER_FIRST_ERROR) {
throw new ParseCancellationException(message);
}
}
private T findObject(List objects, Class clazz) {
if (objects == null) {
return null;
}
Optional ret = objects.stream().filter(o -> clazz.isInstance(o)).map(o -> (T) o).findFirst();
return ret.isPresent() == true ? ret.get() : null;
}
private List findObjects(List objects, Class clazz) {
if (objects == null) {
return Collections.EMPTY_LIST;
}
return objects.stream().filter(o -> clazz.isInstance(o)).map(o -> (T) o).collect(Collectors.toList());
}
}