Hi,
I'm trying to implement a Ceu DSL in Haskell, but I'm stuck on understanding the exact operational semantics described in the paper "A Memory-Bounded, Deterministic and Terminating Semantics for the Synchronous Programming Language Céu".
For example, let's take the following program:
par/and do
emit e;
with
await e;
_printf("here");
end
To my current understanding, this must always print the line "here", since `emit` in the second branch starts an internal reaction and thus awakes the `await` in the first branch.
So, applying the matching transitions in order:
// Apply and-expd (p. 7)
par/@and do
emit e;
with
@canrun(0);
await e;
_printf("here");
end
// Apply and-adv1 and emit-int, emiting the event e (p. 6/7)
par/@and do
@canrun(0);
with
@canrun(0);
await e;
_printf("here");
end
// Apply push (p. 6)
par/@and do
@canrun(0);
with
@canrun(0);
await e;
_printf("here");
end
Here lies the crux of the issue. The `push` transition applies `bcast` to the program description (and also increases the current stack frame and consumes the current event). `bcast` is defined as (p. 8):
bcast(p @and q, e) = bcast(p, e) @and bcast(q, e)
bcast(p; q, e) = bcast(p, e); q
bcast(@canrun(n), e) = @canrun(n)
...
Applying `bcast` to the above program yields:
// Apply @and rule
bcast(@canrun(0) @and @canrun(0); await e; _printf("here"), e) = bcast(@canrun(0), e) @and bcast(@canrun(0); await e; _printf("here"), e)
// Left @and branch
bcast(@canrun(0), e) = @canrun(0)
// Right @and branch
bcast(@canrun(0); await e; _printf("here"), e) = bcast(@canrun(0), e); await e; _printf("here")
bcast(@canrun(0); await e; _printf("here"), e) = @canrun(0); await e; _printf("here")
So, as it turns out, the @canrun primitive seems to prevent the application of the `bcast(await(e), e) = @nop` rule and thus the elimination of the `await`. Further applying the transition rules will reduce the program to:
await e;
_printf("here");
which will be forever blocked. What am I missing?