A "Do-It-Yourself" Specification Language with BeepBeep 3 (Talk @ Dagstuhl 2017)

22
A " Do-It-Yourself " Specification Language with Sylvain Hallé by CRSNG NSERC

Transcript of A "Do-It-Yourself" Specification Language with BeepBeep 3 (Talk @ Dagstuhl 2017)

A " Do-It-Yourself "Specification Language

with

Sylvain Halléby

CRSNGNSERC

EventsEvents are arbitrary dataelements produced in a sequencecalled a stream. Any Java object canbe used as an event.

23

4

π abc

3 8 a3 8 a

2 6 c

+⊇?

<a><a><a>

Numbers Strings XMLdocuments

Booleans

Tuples Functions Sets Plots

⊇?

34

FunctionsFunctions

1:1function

2:1function

6

6 0:1function

transform events into other events.

FunctionApplies a function toevery input event

CumulativeComputes theprogressive "sum" ofall input events

TrimRemoves the first ninput events

DecimateOutputs everyn-th event

GroupEncloses a group ofconnected processors

ForkDuplicates a streaminto multiple copies

SliceSplits a stram into multiplesub-streams

WindowApplies a function toa sliding window ofn events

ProcessorsProcessors are simple computingunits that transform input streams into outputstreams. BeepBeep's core is made of a handful ofgeneral purpose processors.

f

Σ f

n

FilterA first, Boolean stream, decides if each event of a second stream should be output

{

f

PipingPiping the output of processors to theinput of others creates a chain that producesthe desired computation.

Any output can be connected to any input,as long as they have the same type. Many typescan occur in the same chain. The final outputof the chain can be of any type, too.

Fork f = new Fork(2);FunctionProcessor sum =new FunctionProcessor(Addition.instance);

CountDecimate decimate = new CountDecimate(n);Connector.connect(fork, LEFT, sum, LEFT). connect(fork, RIGHT, decimate, INPUT). connect(decimate, OUTPUT, sum, RIGHT);Pullable p = sum.getOutputPullable(OUTPUT);while (p.hasNext() != NextStatus.NO) {Object o = p.next();

. ..}

n

+

f1 LOC per vertex1 LOC per edge

They can contain arbitrary Java code, memberfields, etc. "What happens in the box remains inthe box."

CustomCustom processors and functions canbe created by inheriting from the basic Processorand Function objects provided by BeepBeep.

class Counter extends UniformProcessor {

int cnt = 0;

public Counter() { super(1,1); }

public void compute(Object[] in, Queue<> out) { cnt++; out.add(new Object[]{cnt}); }}

PalettesPalettes are groups of functions andprocessors centered around a particular use case.They represent a simple, but powerful way ofextending BeepBeep to a user's needs. A few ofthe palettes available so far:

XML eventsPlotting

Finite-state machines

Temporal logicSignal processingVarious log formats

Networking

...create your own

1 2 3 4 5

Σ0

+6

...2 7 1 8 2

f

1

Σ0

+

Σ0

+

÷

1

x,y

x

+

t

+x

1 Σ0

+

½ s

x

4 {

4

4

A/a/b//character[status=Walker]/id/text()

→ p1

A

→ p2

→ →→

/a/b

→→

3

<?

→→

f1

f2

→ →

//character[status=Blocker]/id/text()

**

*

*

Create Auction=?0

@

Last PriceDays

0:=

3@Max. Days :=Min. Price 2@:=

Days :=Days 1

+

End of Day=?

0

@

>

<?Days

Last Price

2

@:=

Bid=?

0

@

>

Min. Price<?

2

@

Last Price>?

2

@

Bid=?

0

@

>

Last Price>?

2

@

Days :=Days 1

+

End of Day=?

0

@

Max. Days

End of Day *1@*

→→→ →

*Sold

=?0

@

Days

Days

+ | |.÷ →

→→

SELECT@0 AS x

@1 AS y

→→

+

0

Σ→ →1

→→

∅ +=Σ

→→

x

4

fΣ0

+

GroupGroup processors encapsulate a chainof processors; they can have arguments.

→→

x

4

fΣ0

+

GroupGroup processors encapsulate a chainof processors; they can have arguments.

→→

x

4

Σ0

+f

GroupGroup processors encapsulate a chainof processors; they can have arguments.

?

? ??

foo

GroupGroup processors encapsulate a chainof processors; they can have arguments.

BeepBeep provides a runtime parsercalled Bullwinkle.

It comes with no grammar!

You can define your own, alongwith a parse tree visitor, tocreate your own BeepBeepdomain-specific language.

<Processor> := <CountDecimate> | <CumulativeSum> | <Mutator> | <QueueSource> ;

<CountDecimate> := Take one every <Number> from <Processor> ;

<CumulativeSum> := Accumulate <Processor> ;

<Mutator> := Turn <Processor> into <Number> ;

<QueueSource> := [ <Number> , <Number> , <Number> ] ;

<Number> := ^[\\d]+;

Step 1Step 1Define a grammar in BNF.

class MyInterpreter extends ExpressionParser<Processor> {

public void doCountDecimate(Stack<Object> stack) { Processor p = (Processor) stack.pop(); stack.pop(); // from Constant n = (Constant) stack.pop(); stack.pop(); // every stack.pop(); // one stack.pop(); // Take CountDecimate dec = new CountDecimate( ((Number) n.getValue()).intValue()); Connector.connect(p, dec); m_builtObject.addProcessor(dec); stack.push(dec); } ...}

Step 2Step 2Create an ExpressionParser, with a methoddoXXX for every non-terminal symbol xxx youwant to handle.

MyInterpreter my_int = new MyInterpreter();Processor proc = my_int.parse( "Take one every 2 from The sum of [3, 4, 6]");

SomeOtherProcessor op = ..Connector.connect(proc, op);...

Step 3Step 3Enjoy!

3 4

Σ0

+6

2

Can be used to pipe together anyprocessor and/or function

...including those you define yourself

...(that may contain arbitrary Java code)

...and only those you want to include

...from any existing palette

...using a syntax you choose

An easy way to create simplelanguages that do complex things

https://liflab.github.io/beepbeep-3 .../beepbeep-3-examples