Is there syntax for rules such as:
P => P'
-----------
P + Q => P'
Or would I need to redefine the semantics with evaluation contexts?
There is a book on Big-Step SOS from 2010 on the Kframework website using old syntax:
crl < A1 / A2,Sigma > => < I1 /Int I2 >
if < A1,Sigma > => < I1 > /\ < A2,Sigma > => < I2 > /\ I2 =/= 0 .
It appears to do what I'm looking for, but I'm not sure if new syntax exists for it.
You could do something like this (psuedocode):
configuration <k> $PGM </k>
<state> WHATEVER_YOUR_STATE_IS </state>
syntax KItem ::= evaluateInContext ( Exp , StateCell )
syntax Exp ::= Exp "/" Exp | "HOLE1" | "HOLE2" | Value
syntax Value ::= Int
rule <k> A1 / A2 => evaluateInContext(A1, <state> STATE </state>) ~> evaluateInContext(A2, <state> STATE </state>) ~> HOLE1 / HOLE2 ... </k>
<state> STATE </state>
rule <k> evaluateInContext(A, <state> STATE </state>) => A ... </k>
<state> _ => STATE </state>
rule <k> V:Value ~> evaluateInContext(A, S) => evaluateInContext(A, S) ~> V ... </k>
rule <k> V:Value ~> V':Value ~> HOLE1 / HOLE2 => V' /Int V ... </k>
So you can always pass around configurations as first-class citizens.
An example of this is in KEVM, where we use this sort of mechanism to save/retrieve a list of callstacks.
Update to address comment.
If you want to check that a subterm makes a state transition, you can change it to something like this (psuedo-code again):
syntax KItem ::= "evaluated?" "(" Exp "," State ")"
rule <k> evaluateInContext(A, <state> STATE </state>) => A ~> evaluated?(A, <state> STATE </state> ... </k>
<state> _ => STATE </state>
rule <k> V:Value ~> evaluated?(A, <state> STATE </state>) => DO_SOMETHING_WHEN_EVALUATED ... </k>
rule <k> NOT_VALUE:Exp ~> evaluated?(A, <state> STATE </state>) => DO_SOMETHING_WHEN_NOT_EVALUATED ... </k>
Note that here I'm using "has reduced to sort Value" to determine if it's "evaluated", but you can of course have any side-condition you like for determining that.
Related
I'm attempting to implement an evaluation stack as a list of KItems.
I have a rule that adds evaluation contexts into the stack:
rule <k> X:KVar V:Val ~> E => !DOSOMETHING! </k>
<stack> ES => E ~> ES </stack>
However, I encounter a bug when adding an empty E to the stack.
I attempted to extend KItem with a constructor:
syntax KItem ::= "MyContext" KItem
However, this causes rules of the form
rule <k> !DOSOMETHING! => !V:KVar ~> E </k>
<stack> MyContext E ~> ES => ES </stack>
to fail pattern matching.
Is there a correct way of implementing a stack of evaluation contexts like I'm trying to do?
EDIT:
syntax Exp ::= Int | KVar | Exp "+" Exp [seqstrict(1,2), left]
| "!DOSOMETHING!"
| "(" Exp ")" [bracket]
syntax KResult ::= Int
configuration
<T>
<k> $PGM:Exp </k>
<stack> .K </stack>
</T>
syntax KItem ::= "MyContext" KItem
rule I1:Int + I2:Int => I1 +Int I2
rule <k> X:KVar + V ~> E:KItem => !DOSOMETHING! </k>
<stack> ES => MyContext E ~> ES </stack>
rule <k> V + X:KVar ~> E:KItem => !DOSOMETHING! </k>
<stack> ES => MyContext E ~> ES </stack>
rule <k> !DOSOMETHING! => 0 ~> E </k>
<stack> MyContext E:KItem ~> ES => ES </stack>
would immediately get stuck on a file:
1 + X + 3 + X + 5
If we remove the MyContext,
rule <k> X:KVar + V ~> E:KItem => !DOSOMETHING! </k>
<stack> ES => E ~> ES </stack>
rule <k> V + X:KVar ~> E:KItem => !DOSOMETHING! </k>
<stack> ES => E ~> ES </stack>
rule <k> !DOSOMETHING! => 0 ~> E </k>
<stack> E:KItem ~> ES => ES </stack>
the semantics gets stuck with x + 1.
I suspect I'm actually talking about different issues here. But how does one pattern match the evaluation context correctly?
It looks like your k cell contains a single KItem, which is the addition expression, but the only rules that match addition at the top of the k cell require a second KItem to be present and thus do not apply if there is only one KItem. Did you mean to match a variable of sort K instead? The k cell normally contains a term of sort K, which is a sort representing a cons list of KItem of which ~> is the concatenation operator and .K is the list unit. For convenience, the user can write terms of sort K as if it is an associative list so long as they don't actually match a term of sort K on top of another term, but the rules that you wrote only match a list with exactly two elements. If you intend for E to match the tail of the list, you need to change the sort of E to K.
Assuming a right-linear grammar is given how would you show the steps to derive a word? For example if I had the grammer:
S -> aA
A -> bA
A -> aB
B -> cB
B -> a
And I wanted to constuct the word abbbacca. How would I show my step derivertation? Would it be:
S => A => A => A => A => B => B => B
or somethiong more akin to:
aA => abA => abbA => abbbA => abbbaB => abbbacB => abbbaccB => abbbacca
Converting comments to an answer so the question can disappear from the unanswered lists ...
The form
S => aA => abA => abbA => abbbA => abbbaB => abbbacB => abbbaccB => abbbacca
is the more usual, and preferable, way to show the derivation. For extra credit, especially so with larger grammars, it may also be useful to show the label of the rule applied on the derivation arrow, something like
S =(1)=> aA
Of course, for this to be really useful the rules have to have labels !
I'm currently working through the ubiquitous process ring in elixir.
The ring is linked, but in the following fashion:
iex(1)> Ring.Worker.create_ring_of_linked_processes(3)
Ring.Worker.create_ring_of_linked_processes(3)
[%{"links" => [#PID<0.121.0>, #PID<0.120.0>], "pid" => #PID<0.122.0>},
%{"links" => [#PID<0.120.0>, #PID<0.122.0>], "pid" => #PID<0.121.0>},
%{"links" => [#PID<0.121.0>], "pid" => #PID<0.120.0>}]
I've noticed an asymmetry in the links here - should #PID<0.120.0> have the mapping "links" => [#PID<0.121.0>,#PID<0.122.0>] rather than just "links" => [#PID<0.121.0>] ?
The code is as follows:
def loop() do
receive do
{:link, pid} when is_pid(pid) ->
Process.link(pid)
loop()
end
end
def create_ring_of_linked_processes(num_of_processes) do
num_of_processes
|> create_processes
|> link_processes([])
end
def link_processes([pid1, pid2 | rest], linked_processes) do
send(pid1, {:link, pid2})
:timer.sleep(1)
{:links, links} = Process.info(pid1, :links)
link_processes(
[pid2 | rest], [%{"pid" => pid1, "links" => links} | linked_processes]
)
end
def link_processes([pid | []], linked_processes) do
%{"pid" => first_pid, "links" => _} = List.last(linked_processes)
send(pid, {:link, first_pid})
:timer.sleep(1)
{:links, links} = Process.info(pid, :links)
[%{"pid" => pid, "links" => links} | linked_processes]
end
#spec create_processes(integer) :: [pid]
def create_processes(num_of_processes) do
for _ <- 1..num_of_processes, do: spawn(__MODULE__, :loop, [])
end
This is because you're linking the processes at the same time as collecting its :links, but some links for that process are being created after you collect its links.
For example, if you spawn a process a, and then collect its links, it'll be an empty list.
iex(1)> a = spawn(fn -> :timer.sleep(:infinity) end)
#PID<0.82.0>
iex(2)> Process.info(a, :links)
{:links, []}
If you spawn b now and link it to a, b will have [a] in its links and a will have [b].
iex(3)> b = spawn(fn -> Process.link(a); :timer.sleep(:infinity) end)
#PID<0.85.0>
iex(4)> Process.info(b, :links)
{:links, [#PID<0.82.0>]}
iex(5)> Process.info(a, :links)
{:links, [#PID<0.85.0>]}
So, you need to collect the links for each process after all the linking is complete if you want the final links for each process.
Let's say I am attempting to test an api that is supposed to handle presence or absence of certain object fields.
Let's say I have tests like so:
(def without-foo
{:bar "17"})
(def base-request
{:foo "12"
:bar "17"})
(def without-bar
{:foo "12"})
(def response
{:foo "12"
:bar "17"
:name "Bob"})
(def response-without-bar
{:foo "12"
:bar ""
:name "Bob"})
(def response-without-foo
{:bar "17"
:foo ""
:name "Bob"})
(facts "blah"
(against-background [(external-api-call anything) => {:name => "Bob"})
(fact "base"
(method-under-test base-request) => response)
(fact "without-foo"
(method-under-test without-foo) => response-without-foo)
(fact "without-bar"
(method-under-test without-bar) => response-without-bar))
This works as you would expect and the tests pass. Now I am attempting to refactor this using tabular like so:
(def request
{:foo "12"
:bar "17"})
(def response
{:foo "12"
:bar "17"
:name "Bob"})
(tabular
(against-background [(external-api-call anything) => {:name "Bob"})]
(fact
(method-under-test (merge request ?diff) => (merge response ?rdiff))
?diff ?rdiff ?description
{:foo nil} {:foo ""} "without foo"
{} {} "base case"
{:bar nil} {bar ""} "without bar")
Which results in:
FAIL at (test.clj:123)
Midje could not understand something you wrote:
It looks like the table has no headings, or perhaps you
tried to use a non-literal string for the doc-string?
Ultimately I ended up with:
(tabular
(fact
(method-under-test (merge request ?diff) => (merge response ?rdiff) (provided(external-api-call anything) => {:name "Bob"}))
?diff ?rdiff ?description
{:foo nil} {:foo ""} "without foo"
{} {} "base case"
{:bar nil} {bar ""} "without bar")
Which passes. My question is. How does the tabular function differ from the facts function, and why does one of them accept an against-background while the other blows up?
You need to have following nesting if you want to establish background prerequisites for all your tabular based facts:
(against-background [...]
(tabular
(fact ...)
?... ?...))
For example:
(require '[midje.repl :refer :all])
(defn fn-a []
(throw (RuntimeException. "Not implemented")))
(defn fn-b [k]
(-> (fn-a) (get k)))
(against-background
[(fn-a) => {:a 1 :b 2 :c 3}]
(tabular
(fact
(fn-b ?k) => ?v)
?k ?v
:a 1
:b 3
:c 3))
(check-facts)
;; => All checks (3) succeeded.
If you want to have a background prerequisite per each tabular case you need to nest it as following:
(tabular
(against-background [...]
(fact ...))
?... ?...)
It's important to have the table just under tabular level, not nested in against-background or fact.
For example:
(require '[midje.repl :refer :all])
(defn fn-a []
(throw (RuntimeException. "Not implemented")))
(defn fn-b [k]
(-> (fn-a) (get k)))
(tabular
(against-background
[(fn-a) => {?k ?v}]
(fact
(fn-b ?k) => ?v))
?k ?v
:a 1
:b 2
:c 3)
(check-facts)
;; => All checks (3) succeeded.
In your code it looks like the tabular data is not positioned correctly (parentheses, brackets and curly braces are not balanced correctly so it's impossible to say what exactly is incorrect).
Say I have a function
(defn extenal_api_fn [stuff]
... do things....
)
(defn register_user [stuff]
(external_api_fn stuff))
And then a test
(def stuff1
{:user_id 123 })
(def stuff2
{:user_id 234})
(background (external_api_fn stuff1) => true
(with-redefs [external_api_fn (fn [data] (println "mocked function"))]
(register_user stuff1) => true)
(register_user stuff2) => true)
(facts "stuff goes here"
(fact "user that registers correctly
(= 1 1) => truthy)
(fact "user that has a registration failure"
(= 1 2) => falsy))
This fails with
"you never said #'external_api_fn" would be called with these arguments:
contents of stuff1
What would be a good way to stub this function call (in only some cases) in order to simulate an internal transaction failure.
You could use Midje's provided:
(fact
(register_user stuff1) => :registered
(provided
(extenal_api_fn stuff1) => :registered))
(fact
(register_user stuff2) => :error
(provided
(external_api_fn stuff2) => :error))
You can also stub a function to return a value no matter input parameters by using anything in place of the function argument:
(fact
(register_user stuff2) => :error
(provided
(external_api_fn anything) => :error))