tay10r.github.io

View on GitHub

Requirements

First, the requirements of the library should be laid out. I’m going to keep them extremely limited in scope until there’s a minimal working example.

Each error instance contains the minimal set of information in order to replicate existing error messages generated by the current lexer and parser./

Which is relatively simple.

In considering the current state of upstream ISPC, the sensible set of declarations are these:

#include <memory>
#include <vector>

#include <cstdio>

namespace ispc {

class AST { /* Implementation details */ };

struct Error final { /* Implementation details */ };

auto Parse(const std::string &) -> std::pair<AST, std::vector<Error>>;

auto Parse(FILE *) -> std::pair<AST, std::vector<Error>>;

} // namespace ispc

Setting Up TDD

It needs to be verified that, when using the new lexer and parser, that the compiler will generate the same output as the old lexer and parser. Thankfully, ISPC can already dump AST nodes with the --debug option. All that really needs to be done is to add a --parser-impl option for choosing which parsing implementation to use. For example:

ispc --debug --parser-impl=bison ./input.ispc
ispc --debug --parser-impl=recursive-descent ./input.ispc

If the exit code, output content, or error content differ between these two commands, then there’s a test failure.

The first test is just a simple function:

void func() { }

Running it is automated via CMake, using a standalone CMake script with -P script.cmake.

From CMakeLists.txt:

add_test(NAME "libispc-test-${path}" COMMAND ${CMAKE_COMMAND} -DISPC_EXECUTABLE=$<TARGET_FILE:ispc> -P run_test.cmake)

Where run_test.cmake executes ISPC with both algorithms and compares the exit code, output, and error.

Conclusion

Now the project is properly setup for testing and development! With easy-to-write tests, the rest of the development should be a breeze (knock on wood).