Skip to content
Rafal Zukowski edited this page Oct 3, 2016 · 14 revisions

Opel expression language documentation

Contents

What is Opel?

Opel is a simple asynchronous expression language - or rather - a library which allows creating simple custom secure asynchronous expression languages.

When it can be useful?

Opel can be useful when you need simple customizable expression language, and you want to give it to your users. It will be a nice fit when asynchronous expression evaluation is desirable as it uses CompletableFuture as output as well as input.

Why use Opel instead of other languages?

Opel was created with security and asynchronism in mind.

We needed to give our users a possibility to configure the system using expression language, but without possibility of making harm to our system. In Opel you can add custom functions and values and limit method calls, creating very small language (DSL?) that fits your domain and exposes no dangerous features to users.

Also, we wanted expression evaluation to be a part of CompletableFuture's processing, and with Opel it is natural.

Feature list

  • primary math and string operations (i.e. 2+2*2, 'Hello' + 'world !')
  • relational and equality operators (i.e. 2 == 3, 2 > 1 != false)
  • logic operators (i.e. true && false, false || true)
  • simple map element access (i.e. map.field or map['field'])
  • simple list element access (i.e. list[index])
  • object method calls (i.e. 'Hello, World!'.length())
  • if expressions (i.e. if (2 > 3) 'a' else 'b')
  • defining local constant values (i.e. val x = 2+2*2; x * x)
  • registrable implicit conversions (i.e. 2 + '2' or 'Hello, World!'.myMethod())
  • registrable functions (i.e. myFunction('Hello, World!'))
  • registrable constant values (i.e. 'Hello, ' + WORLD_VALUE)

A brief example

When evaluating simple expressions, opel uses only OpelEngine class and eval method. Remember that opel always returns CompletableFuture.

OpelEngine engine = OpelEngineBuilder.create().build();

String expression = "2 * 3 + 4";
engine.eval(expression)
	.whenComplete((result, error) -> System.out.println(result));

this expression is transformed to equivalent code:

CompletableFuture.completedFuture(2)
    .thenCombine(CompletableFuture.completedFuture(3), (l, r) -> l * r)
    .thenCombine(CompletableFuture.completedFuture(4), (l, r) -> l + r)
    .whenComplete((result, error) -> System.out.println(result));

As you see, opel efficiently hides boilerplate of the CompletableFuture API.