• Stars
    star
    190
  • Rank 203,739 (Top 5 %)
  • Language
    Haskell
  • License
    BSD 3-Clause "New...
  • Created over 3 years ago
  • Updated 11 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A minimal, fast Datalog implementation in Haskell that compiles to LLVM IR
Logo for the Eclair programming language

An experimental and minimal Datalog implementation that compiles down to LLVM.

Build

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:

@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:

$ 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.

// Save this file as "main.c".
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>


struct 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

  • LSP support
  • Allow setting options on relations for performance finetuning
  • Comparison operators, != operator
  • Support arithmetic operators
  • Generic, extensible primops
  • 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. 😄

Contributing to Eclair

Contributions are welcome! Take a look at the getting started guide 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:

$ 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 for more information about Eclair.

Why the name?

Eclair is inspired by Soufflé, 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, with special thanks to the Fission team. Please contact Luc Tielen before using the logo for anything.

More Repositories

1

souffle-haskell

Haskell bindings for the Souffle datalog language
C++
97
star
2

Cure

Small library that interfaces C-code with Erlang/Elixir using Ports.
Elixir
76
star
3

llvm-codegen

LLVM code generation in Haskell
Haskell
46
star
4

telescope_hoogle

Hoogle search integration for Telescope
Lua
45
star
5

lua-quickcheck

Property based testing in Lua, inspired by the original QuickCheck.
Lua
38
star
6

debugger-hs

Write your GDB scripts in Haskell!
Haskell
27
star
7

typesystem

Experiments using a bidirectional typesystem
Haskell
16
star
8

bakery

Serving freshly baked Eclair programs over HTTP
JavaScript
8
star
9

besra-lang

Repository for the Besra programming language
Haskell
6
star
10

souffle-dsl

Haskell EDSL for Souffle Datalog
Haskell
6
star
11

playground

Nix
5
star
12

eclair-wasm-bindings

Typescript bindings for Eclair Datalog compiled to WebAssembly
TypeScript
4
star
13

validators

Composable validations for your Haskell data types
Haskell
4
star
14

eclair-rust-bindings

High level Rust bindings for Eclair Datalog
Rust
4
star
15

eclair-haskell

Haskell bindings for Eclair Datalog
Haskell
4
star
16

repo_analyzer

Small webapp for analyzing git diffs over time in a codebase.
Elm
3
star
17

xml_parsec

XML parser based on parser combinators, written in pure Elixir
Elixir
3
star
18

blog

My personal blog
HTML
2
star
19

dotfiles

My dot files collection
Lua
2
star
20

BF

A BF interpreter/compiler.
Haskell
2
star
21

tree-sitter-eclair

Tree sitter grammar for Eclair
C
2
star
22

vm

A bytecode interpreter for statically typed functional languages. "Fork" of https://gitlab.com/gilmi/vm
C
2
star
23

nep

Eclair parser written in C++ (as an experiment)
C++
1
star
24

souffle-haskell-example

An example of using souffle-haskell in a stack project
C++
1
star
25

Timing

Compact timing library written in Elixir
Elixir
1
star
26

codecation2019

Code I wrote during the Kabisa 2019 codecation
Haskell
1
star
27

Subtitlex

Elixir
1
star
28

eclair-build-rs

Rust library for building and linking Eclair Datalog with Rust code
Rust
1
star
29

fire-emblem-rs

My attempt at recreating the Fire Emblem GBA games, in Rust. WIP
Rust
1
star