Search in sources :

Example 11 with ProgramType

use of net.morimekta.providence.model.ProgramType in project providence by morimekta.

the class TypeLoader method loadInternal.

private ProgramTypeRegistry loadInternal(File file, List<String> loadStack) throws IOException {
    loadStack = new ArrayList<>(loadStack);
    file = file.getCanonicalFile();
    if (!file.exists()) {
        throw new IllegalArgumentException("No such file " + file);
    }
    if (!file.isFile()) {
        throw new IllegalArgumentException("Unable to load thrift program: " + file + " is not a file.");
    }
    file = file.getAbsoluteFile();
    String path = file.getPath();
    if (loadStack.contains(path)) {
        // Only show the circular includes, not the path to get there.
        while (!loadStack.get(0).equals(path)) {
            loadStack.remove(0);
        }
        loadStack.add(path);
        String prefix = longestCommonPrefixPath(loadStack);
        if (prefix.length() > 0) {
            loadStack = stripCommonPrefix(loadStack);
            throw new IllegalArgumentException("Circular includes detected: " + prefix + "... " + String.join(" -> ", loadStack));
        }
        throw new IllegalArgumentException("Circular includes detected: " + String.join(" -> ", loadStack));
    }
    loadStack.add(path);
    ProgramTypeRegistry registry = this.programRegistry.registryForPath(path);
    if (programRegistry.containsProgramPath(path)) {
        return registry;
    }
    InputStream in = new BufferedInputStream(new FileInputStream(file));
    ProgramType doc = parser.parse(in, file, includes);
    ArrayList<File> queue = new ArrayList<>();
    if (doc.hasIncludes()) {
        for (String include : doc.getIncludes()) {
            File location = new File(file.getParent(), include).getCanonicalFile();
            if (!location.exists()) {
                if (include.startsWith(".") || include.startsWith(File.separator)) {
                    throw new ParseException("No such file \"" + include + "\" to include from " + file.getName());
                }
                for (File inc : includes) {
                    File i = new File(inc, include);
                    if (i.exists()) {
                        location = i.getCanonicalFile();
                        break;
                    }
                }
            }
            if (location.exists() && !queue.contains(location)) {
                queue.add(location.getAbsoluteFile());
            }
        }
    }
    // Load includes in reverse order, in case of serial dependencies.
    Collections.reverse(queue);
    loadedDocuments.put(path, doc);
    for (File include : queue) {
        registry.registerInclude(programNameFromPath(include.getPath()), loadInternal(include, ImmutableList.copyOf(loadStack)));
    }
    // Now everything it depends on is loaded.
    CProgram program = converter.convert(path, doc);
    programRegistry.putProgram(path, program);
    programRegistry.putProgramType(path, doc);
    return registry;
}
Also used : BufferedInputStream(java.io.BufferedInputStream) FileInputStream(java.io.FileInputStream) InputStream(java.io.InputStream) ArrayList(java.util.ArrayList) FileInputStream(java.io.FileInputStream) ProgramTypeRegistry(net.morimekta.providence.reflect.util.ProgramTypeRegistry) BufferedInputStream(java.io.BufferedInputStream) CProgram(net.morimekta.providence.reflect.contained.CProgram) ProgramType(net.morimekta.providence.model.ProgramType) ParseException(net.morimekta.providence.reflect.parser.ParseException) File(java.io.File)

Example 12 with ProgramType

use of net.morimekta.providence.model.ProgramType in project providence by morimekta.

the class JsonGenerator method generate.

@Override
public void generate(ProgramTypeRegistry registry) throws IOException, GeneratorException {
    ProgramType doc = registry.getProgramType();
    if (doc.hasIncludes()) {
        doc = doc.mutate().setIncludes(doc.getIncludes().stream().map(path -> path.replaceAll("(\\.thrift)$", ".json")).collect(Collectors.toList())).build();
    }
    OutputStream out = getFileManager().create(null, doc.getProgramName() + ".json");
    try {
        serializer.serialize(out, doc);
        out.write('\n');
    } catch (SerializerException e) {
        throw new GeneratorException("Unable to serialize document.", e);
    }
    getFileManager().finalize(out);
}
Also used : OutputStream(java.io.OutputStream) ProgramType(net.morimekta.providence.model.ProgramType) GeneratorException(net.morimekta.providence.generator.GeneratorException) SerializerException(net.morimekta.providence.serializer.SerializerException)

Example 13 with ProgramType

use of net.morimekta.providence.model.ProgramType in project providence by morimekta.

the class MessageProgramParserTest method testParse.

@Test
public void testParse() throws IOException {
    MessageProgramParser parser = new MessageProgramParser(new JsonSerializer());
    ByteArrayInputStream in = new ByteArrayInputStream(("{\n" + "  \"namespaces\": {\n" + "    \"java\": \"net.morimekta.providence\"\n" + "  }\n" + "}").getBytes(StandardCharsets.UTF_8));
    ProgramType program = parser.parse(in, new File("test.json"), ImmutableSet.of());
    assertThat(program.getNamespaces(), is(ImmutableMap.of("java", "net.morimekta.providence")));
}
Also used : ByteArrayInputStream(java.io.ByteArrayInputStream) JsonSerializer(net.morimekta.providence.serializer.JsonSerializer) ProgramType(net.morimekta.providence.model.ProgramType) File(java.io.File) Test(org.junit.Test)

Example 14 with ProgramType

use of net.morimekta.providence.model.ProgramType in project providence by morimekta.

the class ThriftProgramParserTest method testAutoValue.

@Test
public void testAutoValue() throws IOException {
    copyResourceTo("/parser/tests/autovalue.thrift", tmp.getRoot());
    File autovalue = new File(tmp.getRoot(), "autovalue.thrift");
    ThriftProgramParser parser = new ThriftProgramParser();
    ProgramType program = parser.parse(new FileInputStream(autovalue), autovalue, new TreeSet<>());
    assertEquals("{\n" + "  program_name = \"autovalue\"\n" + "  namespaces = {\n" + "    \"java\": \"net.morimekta.test.autoid\"\n" + "  }\n" + "  decl = [\n" + "    {\n" + "      decl_enum = {\n" + "        name = \"AutoValue\"\n" + "        values = [\n" + "          {\n" + "            name = \"FIRST\"\n" + "            id = 0\n" + "          },\n" + "          {\n" + "            name = \"SECOND\"\n" + "            id = 1\n" + "          },\n" + "          {\n" + "            name = \"THIRD\"\n" + "            id = 2\n" + "          }\n" + "        ]\n" + "      }\n" + "    },\n" + "    {\n" + "      decl_enum = {\n" + "        name = \"PartialAutoValue\"\n" + "        values = [\n" + "          {\n" + "            name = \"FIRST\"\n" + "            id = 5\n" + "          },\n" + "          {\n" + "            name = \"SECOND\"\n" + "            id = 6\n" + "          },\n" + "          {\n" + "            name = \"THIRD\"\n" + "            id = 7\n" + "          }\n" + "        ]\n" + "      }\n" + "    }\n" + "  ]\n" + "}", debugString(program));
}
Also used : ProgramType(net.morimekta.providence.model.ProgramType) File(java.io.File) FileInputStream(java.io.FileInputStream) Test(org.junit.Test)

Example 15 with ProgramType

use of net.morimekta.providence.model.ProgramType in project providence by morimekta.

the class ThriftProgramParserTest method testParse_calculator_strict.

@Test
public void testParse_calculator_strict() throws IOException {
    copyResourceTo("/parser/calculator/number.thrift", tmp.getRoot());
    copyResourceTo("/parser/calculator/calculator_strict.thrift", tmp.getRoot());
    File calculator = new File(tmp.getRoot(), "calculator_strict.thrift");
    ThriftProgramParser parser = new ThriftProgramParser(true, true);
    ProgramType program = parser.parse(new FileInputStream(calculator), calculator, new TreeSet<>());
    assertThat(debugString(program), is(equalToLines("{\n" + "  program_name = \"calculator_strict\"\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 = \"Calculator\"\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" + "            documentation = \"line comment on method.\"\n" + "            one_way = true\n" + "            name = \"iamalive\"\n" + "            params = []\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 = 56\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 = 61\n" + "        start_line_pos = 40\n" + "      }\n" + "    }\n" + "  ]\n" + "}")));
}
Also used : ProgramType(net.morimekta.providence.model.ProgramType) File(java.io.File) FileInputStream(java.io.FileInputStream) Test(org.junit.Test)

Aggregations

ProgramType (net.morimekta.providence.model.ProgramType)16 File (java.io.File)14 FileInputStream (java.io.FileInputStream)11 Test (org.junit.Test)8 ThriftProgramParser (net.morimekta.providence.reflect.parser.ThriftProgramParser)4 Before (org.junit.Before)4 ArrayList (java.util.ArrayList)3 ProgramConverter (net.morimekta.providence.reflect.util.ProgramConverter)3 ProgramRegistry (net.morimekta.providence.reflect.util.ProgramRegistry)3 ConstType (net.morimekta.providence.model.ConstType)2 Declaration (net.morimekta.providence.model.Declaration)2 EnumType (net.morimekta.providence.model.EnumType)2 MessageType (net.morimekta.providence.model.MessageType)2 ServiceType (net.morimekta.providence.model.ServiceType)2 CProgram (net.morimekta.providence.reflect.contained.CProgram)2 ImmutableList (com.google.common.collect.ImmutableList)1 ImmutableMap (com.google.common.collect.ImmutableMap)1 BufferedInputStream (java.io.BufferedInputStream)1 ByteArrayInputStream (java.io.ByteArrayInputStream)1 InputStream (java.io.InputStream)1