use of net.morimekta.providence.model.ProgramType in project providence by morimekta.
the class CServiceTest method setUp.
@Before
public void setUp() throws IOException {
File numeric = ResourceUtils.copyResourceTo("/parser/calculator/number.thrift", tmp.getRoot());
File calculator = ResourceUtils.copyResourceTo("/parser/calculator/calculator.thrift", tmp.getRoot());
ProgramRegistry registry = new ProgramRegistry();
ThriftProgramParser parser = new ThriftProgramParser();
ProgramConverter converter = new ProgramConverter(registry);
ProgramType program = parser.parse(new FileInputStream(numeric), numeric, ImmutableList.of(tmp.getRoot()));
registry.putProgram(numeric.getCanonicalPath(), converter.convert(numeric.getCanonicalPath(), program));
program = parser.parse(new FileInputStream(calculator), calculator, ImmutableList.of(tmp.getRoot()));
registry.putProgram(calculator.getCanonicalPath(), converter.convert(calculator.getCanonicalPath(), program));
this.registry = registry.registryForPath(calculator.getCanonicalPath());
}
use of net.morimekta.providence.model.ProgramType in project providence by morimekta.
the class ThriftProgramParserTest method testParse_calculator.
@Test
public void testParse_calculator() throws IOException, ParseException {
copyResourceTo("/parser/calculator/number.thrift", tmp.getRoot());
copyResourceTo("/parser/calculator/calculator.thrift", tmp.getRoot());
File calculator = new File(tmp.getRoot(), "calculator.thrift");
ThriftProgramParser parser = new ThriftProgramParser();
ProgramType program = parser.parse(new FileInputStream(calculator), calculator, new TreeSet<>());
assertThat(debugString(program), is(equalToLines("{\n" + " program_name = \"calculator\"\n" + " includes = [\n" + " \"number.thrift\"\n" + " ]\n" + " namespaces = {\n" + " \"java\": \"net.morimekta.test.calculator\"\n" + " }\n" + " decl = [\n" + " {\n" + " decl_enum = {\n" + " documentation = \"Block comment on type.\"\n" + " name = \"Operator\"\n" + " values = [\n" + " {\n" + " documentation = \"line comment on enum\"\n" + " name = \"IDENTITY\"\n" + " id = 1\n" + " },\n" + " {\n" + " documentation = \"Block comment on enum.\"\n" + " name = \"ADD\"\n" + " id = 2\n" + " },\n" + " {\n" + " name = \"SUBTRACT\"\n" + " id = 3\n" + " },\n" + " {\n" + " name = \"MULTIPLY\"\n" + " id = 4\n" + " },\n" + " {\n" + " name = \"DIVIDE\"\n" + " id = 5\n" + " }\n" + " ]\n" + " }\n" + " },\n" + " {\n" + " decl_struct = {\n" + " documentation = \"Line comment on type.\"\n" + " variant = UNION\n" + " name = \"Operand\"\n" + " fields = [\n" + " {\n" + " documentation = \"Double line\\ncomment on field.\"\n" + " id = 1\n" + " type = \"Operation\"\n" + " name = \"operation\"\n" + " },\n" + " {\n" + " documentation = \"Block comment\\n - with formatting.\\nOn field.\"\n" + " id = 2\n" + " type = \"double\"\n" + " name = \"number\"\n" + " },\n" + " {\n" + " id = 3\n" + " type = \"number.Imaginary\"\n" + " name = \"imaginary\"\n" + " }\n" + " ]\n" + " }\n" + " },\n" + " {\n" + " decl_struct = {\n" + " name = \"Operation\"\n" + " fields = [\n" + " {\n" + " id = 1\n" + " type = \"Operator\"\n" + " name = \"operator\"\n" + " },\n" + " {\n" + " id = 2\n" + " type = \"list<Operand>\"\n" + " name = \"operands\"\n" + " }\n" + " ]\n" + " annotations = {\n" + " \"compact\": \"\"\n" + " }\n" + " }\n" + " },\n" + " {\n" + " decl_struct = {\n" + " variant = EXCEPTION\n" + " name = \"CalculateException\"\n" + " fields = [\n" + " {\n" + " id = 1\n" + " requirement = REQUIRED\n" + " type = \"string\"\n" + " name = \"message\"\n" + " },\n" + " {\n" + " id = 2\n" + " type = \"Operation\"\n" + " name = \"operation\"\n" + " }\n" + " ]\n" + " }\n" + " },\n" + " {\n" + " decl_service = {\n" + " name = \"BaseCalculator\"\n" + " methods = [\n" + " {\n" + " documentation = \"line comment on method.\"\n" + " one_way = true\n" + " name = \"iamalive\"\n" + " params = []\n" + " },\n" + " {\n" + " return_type = \"i32\"\n" + " name = \"numCalls\"\n" + " params = [\n" + " {\n" + " id = 1\n" + " requirement = REQUIRED\n" + " type = \"i32\"\n" + " name = \"minus\"\n" + " },\n" + " {\n" + " id = 2\n" + " requirement = OPTIONAL\n" + " type = \"i32\"\n" + " name = \"inAdditionTo\"\n" + " }\n" + " ]\n" + " }\n" + " ]\n" + " annotations = {\n" + " \"deprecated\": \"Because reasons\"\n" + " }\n" + " }\n" + " },\n" + " {\n" + " decl_service = {\n" + " documentation = \"Block comment on service\"\n" + " name = \"Calculator\"\n" + " extend = \"BaseCalculator\"\n" + " methods = [\n" + " {\n" + " documentation = \"Block comment on method.\"\n" + " return_type = \"Operand\"\n" + " name = \"calculate\"\n" + " params = [\n" + " {\n" + " id = 1\n" + " type = \"Operation\"\n" + " name = \"op\"\n" + " }\n" + " ]\n" + " exceptions = [\n" + " {\n" + " id = 1\n" + " type = \"CalculateException\"\n" + " name = \"ce\"\n" + " }\n" + " ]\n" + " }\n" + " ]\n" + " }\n" + " },\n" + " {\n" + " decl_const = {\n" + " documentation = \"Block comment on constant.\"\n" + " type = \"Operand\"\n" + " name = \"PI\"\n" + " value = \"{\\n \\\"number\\\": 3.141592\\n}\"\n" + " start_line_no = 63\n" + " start_line_pos = 20\n" + " }\n" + " },\n" + " {\n" + " decl_const = {\n" + " documentation = \"Line comment on constant.\"\n" + " type = \"set<Operator>\"\n" + " name = \"kComplexOperands\"\n" + " value = \"[\\n Operator.MULTIPLY,\\n Operator.DIVIDE\\n]\"\n" + " start_line_no = 68\n" + " start_line_pos = 40\n" + " }\n" + " }\n" + " ]\n" + "}")));
}
use of net.morimekta.providence.model.ProgramType in project providence by morimekta.
the class ThriftProgramParserTest method testParse_number.
@Test
public void testParse_number() throws IOException {
copyResourceTo("/parser/calculator/number.thrift", tmp.getRoot());
File number = new File(tmp.getRoot(), "number.thrift");
ThriftProgramParser parser = new ThriftProgramParser();
ProgramType program = parser.parse(new FileInputStream(number), number, new TreeSet<>());
assertThat(debugString(program), is(equalToLines("{\n" + " program_name = \"number\"\n" + " namespaces = {\n" + " \"java\": \"net.morimekta.test.number\"\n" + " }\n" + " decl = [\n" + " {\n" + " decl_typedef = {\n" + " type = \"double\"\n" + " name = \"real\"\n" + " }\n" + " },\n" + " {\n" + " decl_struct = {\n" + " name = \"Imaginary\"\n" + " fields = [\n" + " {\n" + " id = 1\n" + " requirement = REQUIRED\n" + " type = \"real\"\n" + " name = \"v\"\n" + " },\n" + " {\n" + " id = 2\n" + " type = \"double\"\n" + " name = \"i\"\n" + " default_value = \"0.0\"\n" + " start_line_no = 8\n" + " start_line_pos = 19\n" + " }\n" + " ]\n" + " annotations = {\n" + " \"compact\": \"true\"\n" + " }\n" + " }\n" + " },\n" + " {\n" + " decl_typedef = {\n" + " type = \"Imaginary\"\n" + " name = \"I\"\n" + " }\n" + " },\n" + " {\n" + " decl_const = {\n" + " type = \"Imaginary\"\n" + " name = \"kSqrtMinusOne\"\n" + " value = \"{\\n \\\"v\\\": 0.0,\\n \\\"i\\\": -1.0\\n}\"\n" + " start_line_no = 13\n" + " start_line_pos = 33\n" + " }\n" + " }\n" + " ]\n" + "}")));
}
use of net.morimekta.providence.model.ProgramType in project providence by morimekta.
the class ThriftProgramParserTest method testRegression.
@Test
public void testRegression() throws IOException {
File regressed = copyResourceTo("/idl/backend-libraries/common_fileserver.thrift", tmp.getRoot());
ThriftProgramParser parser = new ThriftProgramParser();
ProgramType program = parser.parse(new FileInputStream(regressed), regressed, new TreeSet<>());
assertEquals("{\n" + " program_name = \"common_fileserver\"\n" + " namespaces = {}\n" + " decl = [\n" + " {\n" + " decl_struct = {\n" + " name = \"FileServerConfig\"\n" + " fields = [\n" + " {\n" + " documentation = \"Configuration for the /download… URL.\\nSee https://wiki.trd.zedge.net/operations:cdn:cloudflare\"\n" + " id = 3\n" + " requirement = OPTIONAL\n" + " type = \"i32\"\n" + " name = \"download_url\"\n" + " }\n" + " ]\n" + " }\n" + " }\n" + " ]\n" + "}", debugString(program));
}
use of net.morimekta.providence.model.ProgramType in project providence by morimekta.
the class ThriftProgramParser method parseInternal.
private ProgramType parseInternal(InputStream in, File file, Collection<File> includeDirs) throws IOException {
ProgramType._Builder program = ProgramType.builder();
String programName = ReflectionUtils.programNameFromPath(file.getName());
if (!VALID_PROGRAM_NAME.matcher(programName).matches()) {
throw new ParseException("Program name \"%s\" derived from filename \"%s\" is not valid.", Strings.escape(programName), Strings.escape(file.getName()));
}
program.setProgramName(programName);
List<String> include_files = new ArrayList<>();
Set<String> includedPrograms = new HashSet<>();
Map<String, String> namespaces = new LinkedHashMap<>();
List<Declaration> declarations = new ArrayList<>();
ThriftTokenizer tokenizer = new ThriftTokenizer(in);
boolean has_header = false;
boolean hasDeclaration = false;
String doc_string = null;
Token token;
while ((token = tokenizer.next()) != null) {
if (token.strEquals(kLineCommentStart)) {
doc_string = parseDocLine(tokenizer, doc_string);
continue;
} else if (token.strEquals(kBlockCommentStart)) {
doc_string = tokenizer.parseDocBlock();
continue;
}
String keyword = token.asString();
if (!Model_Constants.kThriftKeywords.contains(keyword)) {
throw tokenizer.failure(token, "Unexpected token \'%s\'", token.asString());
}
switch(keyword) {
case kNamespace:
if (hasDeclaration) {
throw tokenizer.failure(token, "Unexpected token 'namespace', expected type declaration");
}
if (doc_string != null && !has_header) {
program.setDocumentation(doc_string);
}
doc_string = null;
has_header = true;
parseNamespace(tokenizer, namespaces);
break;
case kInclude:
if (hasDeclaration) {
throw tokenizer.failure(token, "Unexpected token 'include', expected type declaration");
}
if (doc_string != null && !has_header) {
program.setDocumentation(doc_string);
}
doc_string = null;
has_header = true;
parseIncludes(tokenizer, include_files, file, includedPrograms, includeDirs);
break;
case kTypedef:
has_header = true;
hasDeclaration = true;
parseTypedef(tokenizer, doc_string, declarations, includedPrograms);
doc_string = null;
break;
case kEnum:
has_header = true;
hasDeclaration = true;
EnumType et = parseEnum(tokenizer, doc_string);
declarations.add(Declaration.withDeclEnum(et));
doc_string = null;
break;
case kStruct:
case kUnion:
case kException:
has_header = true;
hasDeclaration = true;
MessageType st = parseMessage(tokenizer, token.asString(), doc_string, includedPrograms);
declarations.add(Declaration.withDeclStruct(st));
doc_string = null;
break;
case kService:
has_header = true;
hasDeclaration = true;
ServiceType srv = parseService(tokenizer, doc_string, includedPrograms);
declarations.add(Declaration.withDeclService(srv));
doc_string = null;
break;
case kConst:
has_header = true;
hasDeclaration = true;
ConstType cnst = parseConst(tokenizer, doc_string, includedPrograms);
declarations.add(Declaration.withDeclConst(cnst));
doc_string = null;
break;
default:
throw tokenizer.failure(token, "Unexpected token \'%s\'", Strings.escape(token.asString()));
}
}
if (namespaces.size() > 0) {
program.setNamespaces(namespaces);
}
if (include_files.size() > 0) {
program.setIncludes(include_files);
}
if (declarations.size() > 0) {
program.setDecl(declarations);
}
return program.build();
}
Aggregations