Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/luc-tielen/eclair-lang
A minimal, fast Datalog implementation in Haskell that compiles to LLVM IR
https://github.com/luc-tielen/eclair-lang
compiler datalog haskell llvm logic-programming
Last synced: 10 days ago
JSON representation
A minimal, fast Datalog implementation in Haskell that compiles to LLVM IR
- Host: GitHub
- URL: https://github.com/luc-tielen/eclair-lang
- Owner: luc-tielen
- License: bsd-3-clause
- Created: 2021-06-19T14:46:24.000Z (over 3 years ago)
- Default Branch: main
- Last Pushed: 2024-01-22T09:15:36.000Z (10 months ago)
- Last Synced: 2024-10-13T14:13:26.466Z (23 days ago)
- Topics: compiler, datalog, haskell, llvm, logic-programming
- Language: Haskell
- Homepage:
- Size: 3.89 MB
- Stars: 203
- Watchers: 4
- Forks: 12
- Open Issues: 9
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Funding: .github/FUNDING.yml
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
_An experimental and minimal Datalog implementation that compiles down to LLVM._
[![Build](https://github.com/luc-tielen/eclair-lang/actions/workflows/build.yml/badge.svg)](https://github.com/luc-tielen/eclair-lang/actions/workflows/build.yml)
## Features
Eclair is a minimal Datalog (for now). It supports the following features:
- Facts containing literals
- Rules consisting of one or more clauses.
- Rules can be non-recursive, recursive or mutually recursive.Right now it compiles to LLVM but be aware there might still be bugs.
Some edge cases might not be handled yet.## Motivating example
Let's say we want to find out which points are reachable in a graph. We can
determine which points are reachable using the following two logical rules:1. One point is reachable from another point, iff there is a direct edge between
those two points.
2. One point is reachable from another point, iff there is a third point 'z' such
that there is a direct edge between 'x' and 'z', and between 'z' and 'y'.The Eclair code below can be used to calculate the solution:
```eclair
@def edge(u32, u32).
@def reachable(u32, u32).reachable(x, y) :-
edge(x, y).reachable(x, z) :-
edge(x, y),
reachable(y, z).
```The above code can be compiled to LLVM using the Docker image provided by this repo:
```bash
$ git clone [email protected]:luc-tielen/eclair-lang.git
$ cd eclair-lang
$ docker build . -t eclair
# The next line assumes the eclair code is saved as "example.dl" in the current directory
$ docker run -v $PWD:/code --rm -it eclair:latest compile /code/example.dl
# NOTE: output can be redirected to a file using standard shell functionality: docker run ... > example.ll
```This will emit the generated LLVM IR to the stdout of the terminal. If we save
this generated LLVM IR to a file (e.g. `example.ll`), we can link it with the
following C code that calls into Eclair, using the following command:
`clang -o program main.c example.ll`.```c
// Save this file as "main.c".
#include
#include
#include
#includestruct program;
extern struct program* eclair_program_init();
extern void eclair_program_destroy(struct program*);
extern void eclair_program_run(struct program*);
extern void eclair_add_facts(struct program*, uint16_t fact_type, uint32_t* data, size_t fact_count);
extern void eclair_add_fact(struct program*, uint16_t fact_type, uint32_t* data);
extern uint32_t* eclair_get_facts(struct program*, uint16_t fact_type);
extern void eclair_free_buffer(uint32_t* data);int main(int argc, char** argv)
{
struct program* prog = eclair_program_init();// edge(1,2), edge(2,3)
uint32_t data[] = {
1, 2,
2, 3
};
eclair_add_facts(prog, 0, data, 2);eclair_program_run(prog);
// NOTE: normally you call btree_size here to figure out the size, but I know there are only 3 facts
uint32_t* data_out = eclair_get_facts(prog, 1);
printf("REACHABLE: (%d, %d)\n", data_out[0], data_out[1]); // (1,2)
printf("REACHABLE: (%d, %d)\n", data_out[2], data_out[3]); // (2,3)
printf("REACHABLE: (%d, %d)\n", data_out[4], data_out[5]); // (1,3)eclair_free_buffer(data_out);
eclair_program_destroy(prog);
return 0;
}
```If you run the resulting program, this should print the reachable node pairs
`(1,2)`, `(2,3)` and `(1,3)` to the screen!## Roadmap
- [x] LSP support
- [x] Allow setting options on relations for performance finetuning
- [x] Comparison operators, != operator
- [x] Support arithmetic operators
- [x] Generic, extensible primops
- [x] Support logical negation
- [ ] Release 0.2.0
- [ ] Signed integer type (i32)
- [ ] Unary negation
- [ ] Optimizations on the AST / RA / LLVM level
- [ ] Support other underlying data structures than btree
- [ ] Syntactic sugar (disjunctions in rule bodies, multiple rule heads, ...)
- [ ] Support Datalog programs spanning multiple files
- [ ] ...This roadmap is not set in stone, but it gives an idea on the direction of the
project. :smile:## Contributing to Eclair
Contributions are welcome! Take a look at the
[getting started guide](./docs/getting_started.md) on how to set up your machine
to build, run and test the project. Once setup, the Makefile contains the most
commonly used commands needed during development.You can also use the `Dockerfile` in this repository if you want to experiment
with Eclair without installing the toolchain yourself. You can do that as
follows:```bash
$ docker build -f Dockerfile . -t eclair
$ touch test.eclair # Here you can put your Eclair code
$ docker run -v $PWD:/code --rm -it eclair eclair compile /code/test.eclair
```## Documentation
Take a look at our [docs folder](./docs/) for more information about Eclair.
## Why the name?
Eclair is inspired by [Soufflé](https://souffle-lang.github.io/), a high
performance Datalog that compiles to C++. Because of the similarities, I chose a
different kind of food that I like. I mean, an eclair contains _both_ chocolate and
pudding, what's not to like!?Logo art by [Bruno Monts](https://www.instagram.com/bruno_monts/),
with special thanks to the [Fission](https://fission.codes) team.
Please contact Luc Tielen before using the logo for anything.