Haskell BNF Parser
This is a brief update about a project I have been working on lately. It’s my first bigger Haskell project, and about parsing a Backus-Naur form (BNF) expression and returning it in JSON format. More formally, this can be seen as compilation between two languages, namely BNF and JSON.
BNF — JSON
A Backus-Naur form is a way of writing down the rules of a context-free grammar. For instance, an integral value could be defined as follows:
<integer> ::= <digit>|<integer><digit> <digit> ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
The same content can be expressed in JSON as well:
{"rules":[{"name":"integer","expr":[[{"ref":"digit"}],[{"ref":"integer"},{"ref":"digit"}]]},{"name":"digit","expr":[[{"l":"0"}],[{"l":"1"}],[{"l":"2"}],[{"l":"3"}],[{"l":"4"}],[{"l":"5"}],[{"l":"6"}],[{"l":"7"}],[{"l":"8"}],[{"l":"9"}]]}]}
Even though the JSON looks more verbose than the BNF, it is easier to process in other programming languages.
Haskell Project
The Haskell project consists of three parts, namely app, src, and test. It was developed in IntelliJ using the plugin “IntelliJ-Haskell”.
Source
The project’s source (src folder) contains the actual parser library. That is Haskell functions, which parse a string and return it in an internal-type representation (BNFDefinition
). The internal types come along with an implementation of the instance ToJSON
. If another Haskell project was going to use the parser logic it could simply import this library and make use of the functions.
Application
The application (app folder) starts a scotty web server and parses the request body of incoming requests using the aforementioned library. The response is in JSON format. Alongside with the conversion API-endpoint comes a minimalistic HTML site for testing.
Tests
The tests (test folder) consist of three kinds of tests:
- Unit tests: The functionality of almost every piece of the parser is being tested with a set of multiple rules, which it must satisfy.
- Integration tests: The repository contains three examples of valid, more extended BNFs, and a few invalid ones. During integration testing, the parser library must accept the valid ones and reject the invalid samples.
- Property tests: The property testing validates that the parse function is inverse to show. That means, for any valid, randomly generated BNF $x$, the property$$\text{parse}\left(\text{show}\left(x\right)\right)=x$$ must hold.
Usage
The project can be found on GitHub https://github.com/Simsso/BNF-Parser. The repository contains a Dockerfile which starts the server. More details can be found in the repository’s README.md file.