/** Parse a named {@code .proto} schema. */ public static ProtoFileElement parse(Location location, String data) { return new ProtoParser(location, data.toCharArray()).readProtoFile(); }
/** * Returns Google's protobuf descriptor, which defines standard options like default, deprecated, * and java_package. If the user has provided their own version of the descriptor proto, that is * preferred. */ private ProtoFile loadDescriptorProto() throws IOException { InputStream resourceAsStream = SchemaLoader.class.getResourceAsStream("/" + DESCRIPTOR_PROTO); try (BufferedSource buffer = Okio.buffer(Okio.source(resourceAsStream))) { String data = buffer.readUtf8(); Location location = Location.get("", DESCRIPTOR_PROTO); ProtoFileElement element = ProtoParser.parse(location, data); return ProtoFile.get(element); } }
ProtoFileElement readProtoFile() { while (true) { String documentation = reader.readDocumentation(); if (reader.exhausted()) { return fileBuilder.syntax(syntax) .publicImports(publicImports.build()) .imports(imports.build()) .types(nestedTypes.build()) .services(services.build()) .extendDeclarations(extendsList.build()) .options(options.build()) .build(); } Object declaration = readDeclaration(documentation, Context.FILE); if (declaration instanceof TypeElement) { nestedTypes.add((TypeElement) declaration); } else if (declaration instanceof ServiceElement) { services.add((ServiceElement) declaration); } else if (declaration instanceof OptionElement) { options.add((OptionElement) declaration); } else if (declaration instanceof ExtendElement) { extendsList.add((ExtendElement) declaration); } } }
private OneOfElement readOneOf(String documentation) { OneOfElement.Builder builder = OneOfElement.builder() .name(reader.readName()) .documentation(documentation); ImmutableList.Builder<FieldElement> fields = ImmutableList.builder(); ImmutableList.Builder<GroupElement> groups = ImmutableList.builder(); reader.require('{'); while (true) { String nestedDocumentation = reader.readDocumentation(); if (reader.peekChar('}')) break; Location location = reader.location(); String type = reader.readDataType(); if (type.equals("group")) { groups.add(readGroup(location, nestedDocumentation, null)); } else { fields.add(readField(location, nestedDocumentation, null, type)); } } return builder.fields(fields.build()) .groups(groups.build()) .build(); }
return result; } else if (label.equals("reserved")) { return readReserved(location, documentation); } else if (label.equals("message")) { return readMessage(location, documentation); } else if (label.equals("enum")) { return readEnumElement(location, documentation); } else if (label.equals("service")) { return readService(location, documentation); } else if (label.equals("extend")) { return readExtend(location, documentation); } else if (label.equals("rpc")) { if (!context.permitsRpc()) throw reader.unexpected(location, "'rpc' in " + context); return readRpc(location, documentation); } else if (label.equals("oneof")) { if (!context.permitsOneOf()) { throw reader.unexpected(location, "'oneof' must be nested in message"); return readOneOf(documentation); } else if (label.equals("extensions")) { if (!context.permitsExtensions()) { throw reader.unexpected(location, "'extensions' must be nested"); return readExtensions(location, documentation); } else if (context == Context.MESSAGE || context == Context.EXTEND) { return readField(documentation, location, label); } else if (context == Context.ENUM) { return readEnumConstant(documentation, location, label); } else {
if (peekChar() == ';') { pos++; return null; Location location = location(); String label = readWord(); if (!context.permitsPackage()) throw unexpected(location, "'package' in " + context); if (packageName != null) throw unexpected(location, "too many package names"); packageName = readName(); fileBuilder.packageName(packageName); prefix = packageName + "."; if (readChar() != ';') throw unexpected("expected ';'"); return null; } else if (label.equals("import")) { if (!context.permitsImport()) throw unexpected(location, "'import' in " + context); String importString = readString(); if ("public".equals(importString)) { publicImports.add(readString()); } else { imports.add(importString); if (readChar() != ';') throw unexpected("expected ';'"); return null; } else if (label.equals("syntax")) { if (!context.permitsSyntax()) throw unexpected(location, "'syntax' in " + context); if (readChar() != '=') throw unexpected("expected '='"); if (index != 0) { throw unexpected(location, "'syntax' element must be the first declaration in a file");
private OneOfElement readOneOf(String documentation) { OneOfElement.Builder builder = OneOfElement.builder() .name(readName()) .documentation(documentation); ImmutableList.Builder<FieldElement> fields = ImmutableList.builder(); ImmutableList.Builder<GroupElement> groups = ImmutableList.builder(); if (readChar() != '{') throw unexpected("expected '{'"); while (true) { String nestedDocumentation = readDocumentation(); if (peekChar() == '}') { pos++; break; } Location location = location(); String type = readDataType(); if (type.equals("group")) { groups.add(readGroup(nestedDocumentation, null)); } else { fields.add(readField(location, nestedDocumentation, null, type)); } } return builder.fields(fields.build()) .groups(groups.build()) .build(); }
/** Reads an extend declaration. */ private ExtendElement readExtend(Location location, String documentation) { String name = readName(); ExtendElement.Builder builder = ExtendElement.builder(location) .name(name) .documentation(documentation); if (readChar() != '{') throw unexpected("expected '{'"); ImmutableList.Builder<FieldElement> fields = ImmutableList.builder(); while (true) { String nestedDocumentation = readDocumentation(); if (peekChar() == '}') { pos++; break; } Object declared = readDeclaration(nestedDocumentation, Context.EXTEND); if (declared instanceof FieldElement) { fields.add((FieldElement) declared); } } return builder.fields(fields.build()) .build(); }
private GroupElement readGroup(String documentation, Field.Label label) { String name = readWord(); if (readChar() != '=') { throw unexpected("expected '='"); } int tag = readInt(); GroupElement.Builder builder = GroupElement.builder() .label(label) .name(name) .tag(tag) .documentation(documentation); ImmutableList.Builder<FieldElement> fields = ImmutableList.builder(); if (readChar() != '{') throw unexpected("expected '{'"); while (true) { String nestedDocumentation = readDocumentation(); if (peekChar() == '}') { pos++; break; } Location location = location(); String fieldLabel = readWord(); Object field = readField(nestedDocumentation, location, fieldLabel); if (!(field instanceof FieldElement)) { throw unexpected("expected field declaration, was " + field); } fields.add((FieldElement) field); } return builder.fields(fields.build()) .build(); }
.name(readName()) .documentation(documentation); if (readChar() != '(') throw unexpected("expected '('"); String type; String word = readWord(); if (word.equals("stream")) { builder.requestStreaming(true); type = readDataType(); } else { type = readDataType(word); if (readChar() != ')') throw unexpected("expected ')'"); if (!readWord().equals("returns")) throw unexpected("expected 'returns'"); if (readChar() != '(') throw unexpected("expected '('"); word = readWord(); if (word.equals("stream")) { builder.responseStreaming(true); type = readDataType(); } else { type = readDataType(word); if (readChar() != ')') throw unexpected("expected ')'"); if (peekChar() == '{') { ImmutableList.Builder<OptionElement> options = ImmutableList.builder(); pos++;
case "required": if (syntax == ProtoFile.Syntax.PROTO_3) { throw unexpected(location, "'required' label forbidden in proto3 field declarations"); type = readDataType(); break; throw unexpected(location, "'optional' label forbidden in proto3 field declarations"); type = readDataType(); break; type = readDataType(); break; if (syntax != ProtoFile.Syntax.PROTO_3 && (!word.equals("map") || peekChar() != '<')) { throw unexpected(location, "unexpected label: " + word); type = readDataType(word); break; throw unexpected(location, "'map' type cannot have label"); return readGroup(documentation, label); return readField(location, documentation, label, type);
ProtoFileElement readProtoFile() { while (true) { String documentation = readDocumentation(); if (pos == data.length) { return fileBuilder.syntax(syntax) .publicImports(publicImports.build()) .imports(imports.build()) .types(nestedTypes.build()) .services(services.build()) .extendDeclarations(extendsList.build()) .options(options.build()) .build(); } Object declaration = readDeclaration(documentation, Context.FILE); if (declaration instanceof TypeElement) { nestedTypes.add((TypeElement) declaration); } else if (declaration instanceof ServiceElement) { services.add((ServiceElement) declaration); } else if (declaration instanceof OptionElement) { options.add((OptionElement) declaration); } else if (declaration instanceof ExtendElement) { extendsList.add((ExtendElement) declaration); } } }
private GroupElement readGroup(Location location, String documentation, Field.Label label) { String name = reader.readWord(); reader.require('='); int tag = reader.readInt(); GroupElement.Builder builder = GroupElement.builder(location) .label(label) .name(name) .tag(tag) .documentation(documentation); ImmutableList.Builder<FieldElement> fields = ImmutableList.builder(); reader.require('{'); while (true) { String nestedDocumentation = reader.readDocumentation(); if (reader.peekChar('}')) break; Location fieldLocation = reader.location(); String fieldLabel = reader.readWord(); Object field = readField(nestedDocumentation, fieldLocation, fieldLabel); if (!(field instanceof FieldElement)) { throw reader.unexpected("expected field declaration, was " + field); } fields.add((FieldElement) field); } return builder.fields(fields.build()) .build(); }
return null; } else if (label.equals("option")) { OptionElement result = readOption('='); reader.require(';'); return result; } else if (label.equals("reserved")) { return readReserved(location, documentation); } else if (label.equals("message")) { return readMessage(location, documentation); } else if (label.equals("enum")) { return readEnumElement(location, documentation); } else if (label.equals("service")) { return readService(location, documentation); } else if (label.equals("extend")) { return readExtend(location, documentation); } else if (label.equals("rpc")) { if (!context.permitsRpc()) throw reader.unexpected(location, "'rpc' in " + context); return readRpc(location, documentation); } else if (label.equals("oneof")) { if (!context.permitsOneOf()) { throw reader.unexpected(location, "'oneof' must be nested in message"); return readOneOf(documentation); } else if (label.equals("extensions")) { if (!context.permitsExtensions()) { throw reader.unexpected(location, "'extensions' must be nested"); return readExtensions(location, documentation); } else if (context == Context.MESSAGE || context == Context.EXTEND) {
/** Reads a service declaration and returns it. */ private ServiceElement readService(Location location, String documentation) { String name = readName(); ServiceElement.Builder builder = ServiceElement.builder(location) .name(name) .documentation(documentation); if (readChar() != '{') throw unexpected("expected '{'"); ImmutableList.Builder<RpcElement> rpcs = ImmutableList.builder(); ImmutableList.Builder<OptionElement> options = ImmutableList.builder(); while (true) { String rpcDocumentation = readDocumentation(); if (peekChar() == '}') { pos++; break; } Object declared = readDeclaration(rpcDocumentation, Context.SERVICE); if (declared instanceof RpcElement) { rpcs.add((RpcElement) declared); } else if (declared instanceof OptionElement) { options.add((OptionElement) declared); } } return builder.options(options.build()) .rpcs(rpcs.build()) .build(); }
private GroupElement readGroup(String documentation, Field.Label label) { String name = reader.readWord(); reader.require('='); int tag = reader.readInt(); GroupElement.Builder builder = GroupElement.builder() .label(label) .name(name) .tag(tag) .documentation(documentation); ImmutableList.Builder<FieldElement> fields = ImmutableList.builder(); reader.require('{'); while (true) { String nestedDocumentation = reader.readDocumentation(); if (reader.peekChar('}')) break; Location location = reader.location(); String fieldLabel = reader.readWord(); Object field = readField(nestedDocumentation, location, fieldLabel); if (!(field instanceof FieldElement)) { throw reader.unexpected("expected field declaration, was " + field); } fields.add((FieldElement) field); } return builder.fields(fields.build()) .build(); }
@Test public void invalidSyntaxValueThrows() throws Exception { String proto = "" + "syntax = \"proto4\";\n" + "message Foo {}"; try { ProtoParser.parse(location, proto); } catch (IllegalStateException e) { assertThat(e).hasMessage("Syntax error in file.proto at 1:1: unexpected syntax: proto4"); } }
public List<RpcMethodDefinition> getRpcMethods() throws IOException { List<RpcMethodDefinition> retval = new ArrayList<>(); ProtoParser parser = new ProtoParser(Location.get(input.getCanonicalPath()), gulpFile(input)); ProtoFileElement element = parser.readProtoFile(); if (protoFileMatchesPackage(element)) { List<ServiceElement> services = element.services(); if (services != null) { for (ServiceElement service : services) { String name = service.name(); List<RpcElement> rpcs = service.rpcs(); if (rpcs != null) { for (RpcElement rpc : rpcs) { RpcMethodDefinition def = new RpcMethodDefinition(name + "." + rpc.name(), rpc.requestType(), rpc.responseType(), element.packageName(), fileName ); retval.add(def); } } } } } return retval; }
/** Reads an enumerated type declaration and returns it. */ private EnumElement readEnumElement(Location location, String documentation) { String name = readName(); EnumElement.Builder builder = EnumElement.builder(location) .name(name) .documentation(documentation); if (readChar() != '{') throw unexpected("expected '{'"); ImmutableList.Builder<EnumConstantElement> constants = ImmutableList.builder(); ImmutableList.Builder<OptionElement> options = ImmutableList.builder(); while (true) { String valueDocumentation = readDocumentation(); if (peekChar() == '}') { pos++; break; } Object declared = readDeclaration(valueDocumentation, Context.ENUM); if (declared instanceof EnumConstantElement) { constants.add((EnumConstantElement) declared); } else if (declared instanceof OptionElement) { options.add((OptionElement) declared); } } return builder.options(options.build()) .constants(constants.build()) .build(); }