Skip to content

OriRoth/fling

Repository files navigation

Fling is the first general and practical solution of the fluent API problem. The implementation includes an algorithm that takes a deterministic context free language (equivalently, LR(k), k≥0 language) and encodes it in an unbounded parametric polymorphism type system employing only a polynomial number of types. The theoretical result is employed in an actual tool Fling—a fluent API compiler-compiler in the venue of YACC, tailored for embedding DSLs in polymorphic, object-oriented languages.

Fling

Fling (fluent interfaces generator) is a parser generator. Instead of generating the code of a real-time parser, Fling generates Java fluent interfaces, which implement a compile-time parser of the given language. Fling accepts either LL(1) grammar or DPDA specifications; If a grammar is given, Fling also generates the AST class definitions used to compile a fluent API INVOCATION into an abstract parse tree at run-time.

Download jar

Full release (includes examples)

Documentation

Example

Let us define the Datalog grammar, in Java, using Fling's interface:

// Datalog grammar defined in BNF
BNF bnf = bnf().
      start(Program).
      derive(Program).to(oneOrMore(Statement)).
      specialize(Statement).into(Fact, Rule, Query).
      derive(Fact).to(fact.with(S), of.many(S)).
      derive(Query).to(query.with(S), of.many(Term)).
      specialize(Rule).into(Bodyless, WithBody).
      derive(Bodyless).to(always.with(S), of.many(Term)).
      derive(WithBody).to(RuleHead, RuleBody).
      derive(RuleHead).to(infer.with(S), of.many(Term)).
      derive(RuleBody).to(FirstClause, noneOrMore(AdditionalClause)).
      derive(FirstClause).to(when.with(S), of.many(Term)).
      derive(AdditionalClause).to(and.with(S), of.many(Term)).
      derive(Term).to(l.with(S)).or(v.with(S)).
      build();

After Fling has created the fluent interfaces supporting Datalog, a simple Datalog program...

parent(john, bob)
parent(bob, donald)
ancestor(A, B) := parent(A, B)
ancestor(A, B) := parent(A, C), ancestor(C, B)
ancestor(john, X)?

...can be written in Java by method-chaining, as follows:

Program program =
  fact("parent").of("john", "bob").
  fact("parent").of("bob", "donald").
  always("ancestor").of(l("adam"), v("X")).
  infer("ancestor").of(v("A"), v("B")).
    when("parent").of(v("A"), v("B")).
  infer("ancestor").of(v("A"), v("B")).
    when("parent").of(v("A"), v("C")).
    and("ancestor").of(v("C"), v("B")).
  query("ancestor").of(l("john"), v("X")).$();

The produced program is represented in Java as an abstract syntax tree (AST) that can be traversed and analyzed by the client library.