Skip to content

Commit

Permalink
BPML: grok 2 start events from pizza example
Browse files Browse the repository at this point in the history
  - pizza-collaboration.bpmn resource (symlink WIP)
  - add XML dependency
  - start porting RhoBuilder to scala
    - add Json dependency
  • Loading branch information
dckc committed Apr 19, 2020
1 parent 98214ba commit 68bac6e
Show file tree
Hide file tree
Showing 4 changed files with 357 additions and 0 deletions.
5 changes: 5 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,8 @@ scalaVersion := "2.12.8"
libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.5" % Test
libraryDependencies += "org.scala-lang.modules" %% "scala-parser-combinators" % "1.1.2"
// libraryDependencies += "de.srtobi" %%% "escalima" % "0.5"

// https://github.com/scala/scala-xml/wiki/Getting-started
libraryDependencies += "org.scala-lang.modules" %% "scala-xml" % "1.2.0"
// https://github.com/spray/spray-json
libraryDependencies += "io.spray" %% "spray-json" % "1.3.5"
1 change: 1 addition & 0 deletions src/main/resources/pizza-collaboration.bpmn
43 changes: 43 additions & 0 deletions src/main/scala/bpmn2rho/PizzaOrderTest.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package bpmn2rho

import js2rho.{RhoBuilder, Name, Process, Printer, RhoPrinter}

import scala.xml.XML
import scala.xml.Node

object PizzaOrderTest {
def main(args: Array[String]) = {
println("Hello, world!")
// https://github.com/bpmn-io/bpmn-js-examples/blob/master/bundling/resources/pizza-collaboration.bpmn
val pizzaModelRes = getClass.getResource("/pizza-collaboration.bpmn")

println(pizzaModelRes)

val doc = XML.load(pizzaModelRes)
// println(doc \\ "task")
println(doc \\ "startEvent")

val printer = Printer.fromPrintStream(System.out)
val bld = new RhoPrinter()

toRho(doc, bld)._printOn(printer)

}

// TODO: monadic style instead of Builder?
def toRho(bpml: Node, bld: RhoBuilder): Process = {
val nil = bld.Nil()
def par(ps: Seq[Process]): Process = ps match {
case Seq() => nil
case Seq(first) => first
case first :: rest => bld.Par(first, par(rest))
}
// xmlns:semantic="http://www.omg.org/spec/BPMN/20100524/MODEL"
val starts =
for (startEvent <- bpml \\ "startEvent";
id = bld.Var((startEvent \ "@id") text);
name = bld.primitive((startEvent \ "@name") text))
yield bld.receiving(List((List(bld.Quote(name)), id)), nil)
par(starts)
}
}
308 changes: 308 additions & 0 deletions src/main/scala/js2rho/RhoBuilder.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,308 @@
package js2rho

import java.io.PrintStream

import spray.json._
import DefaultJsonProtocol._

/**
* https://github.com/rchain/rchain/blob/dev/rholang/src/main/bnfc/rholang_mercury.cf
*/
trait Miranda {
def _printOn(p: Printer): Unit
}

trait Printer {
def print(s: String): Unit
def begin(s: String): Unit
def newline(): Unit
def end(s: String): Unit
}

object Printer {
def fromPrintStream(out: PrintStream): Printer = {
var indent = 0;
return new Printer {
def print(txt: String) { out.print(txt) }
def begin(txt: String) { out.print(txt); indent += 1; this.newline() }
def newline() { out.print("\n" + " ".repeat(indent)) }
def end(txt: String) {
this.newline(); out.print(txt); indent -= 1; this.newline()
}
}
}
}

trait Process extends Miranda {
def quote(): Name
}

trait Name extends Miranda {
def deref(): Process
}

trait RhoBuilder {
def Nil(): Process
def primitive(value: Boolean): Process
def primitive(value: Int): Process
def primitive(value: String): Process

def Var(id: String): Name
def Quote(p: Process): Name
def Drop(n: Name): Process

def Par(p: Process, q: Process): Process
// TODO: join
def receiving(rx: Seq[(Seq[Name], Name)], body: Process): Process

/*
* @property {(procs: Process[]) => Process} listExpr
* @property {(procs: Process[]) => Process} tupleExpr
* @property {(entries: Array<{ key: string, value: Process }>) => Process} mapExpr
* @property {(specimen: Process, cases: { lhs: Process, rhs: Process }) => Process } match
* @property {(dest: Name, procs: Array<Process>) => Process} send
* @property {(op: BinOp, lhs: Process, rhs: Process) => Process} binop
* @property {(op: UnOp, arg: Process) => Process} unary
* @property {(name: Name, args: Array<Name>, body: Process) => Process} contract
* @property {(n: Name) => Process} Drop
* @property {(p: Process, q: Process) => Process} Par
* @property {(p: Process) => Name} Quote
* @property {(vars: Array<vdecl>, body: Process) => Process} new_
*
* @typedef {{ lhs: Name[], rhs: Name}[]} Receipt
*/
}

class RhoPrinter extends RhoBuilder {
def aNil(): Process = new Process {
def _printOn(out: Printer) = out.print("Nil")
def quote() = Quote(aNil())
}
val theNil = aNil()
def Nil() = theNil

def primitive(v: String) = new Process {
def _printOn(out: Printer) = out.print(v.toJson.toString())
def quote() = Quote(primitive(v))
}
def primitive(v: Int) = new Process {
def _printOn(out: Printer) = out.print(v.toJson.toString())
def quote() = Quote(primitive(v))
}
def primitive(v: Boolean) = new Process {
def _printOn(out: Printer) = out.print(v.toJson.toString())
def quote() = Quote(primitive(v))
}

def Quote(p: Process) = new Name {
def _printOn(out: Printer) = {
out.print("@{ ")
p._printOn(out)
out.print(" }")
}
def deref() = p
}
def Drop(name: Name) = new Process {
def _printOn(out: Printer) = {
out.print("*")
name._printOn(out)
}
def quote() = name
}
def Var(v: String) = new Name {
def _printOn(out: Printer) = out.print(v)
def deref() = Drop(Var(v))
}

def Par(p: Process, q: Process) =
if (p == theNil) { q }
else if (q == theNil) { p }
else
new Process {
def _printOn(out: Printer) = {
p._printOn(out)
out.newline()
out.print("|")
out.newline()
q._printOn(out)
}
def quote() = Quote(Par(p, q))
}

def receiving(rx: Seq[(Seq[Name], Name)], proc: Process) = new Process {
def _printOn(out: Printer) = {
out.print("for(")
var first = true;
for ((lhs, rhs) <- rx) {
if (!first) {
out.print("; ")
}
printList(out, lhs)
out.print(" <- ")
rhs._printOn(out)
first = false;
}
out.begin(") {")
proc._printOn(out)
out.end("}")
}
def quote() = Quote(receiving(rx, proc))
}
def printList(out: Printer, items: Iterable[Miranda]) = {
var first = true;
for (item <- items) {
if (!first) {
out.print(", ")
}
item._printOn(out)
first = false
}
}
/*
const listExpr = (procs) => harden({
_printOn(out) {
out.print('[');
printList(out, procs);
out.print(']');
},
quote: () => Quote(listExpr(procs))
});
const tupleExpr = (procs) => harden({
_printOn(out) {
out.print('(');
printList(out, procs);
out.print(')');
},
quote: () => Quote(tupleExpr(procs))
});
const mapExpr = (entries) => harden({
_printOn(out) {
let first = true;
out.print('{');
for (const { key, value } of entries) {
if (!first) {
out.print(', ')
}
out.print(JSON.stringify(key));
out.print(': ');
value._printOn(out);
first = false;
}
out.print('}');
},
quote: () => Quote(mapExpr(entries))
});
const match = (specimen, cases) => harden({
_printOn(out) {
out.newline();
out.print("match (");
specimen._printOn(out);
out.begin(") {");
for (const { lhs, rhs } of cases) {
lhs._printOn(out);
out.begin(" => {");
rhs._printOn(out);
out.end("}");
}
out.end("}");
}
});
const printList = (out, items) => {
let first = true;
for (const item of items) {
if (!first) {
out.print(", ")
}
item._printOn(out)
first = false
}
}
const send = (dest, procs) => harden({
_printOn: (out) => {
dest._printOn(out)
out.print(`!(`) // TODO: !!
printList(out, procs)
out.print(")")
},
quote: () => Quote(send(dest, procs))
});
const binop = (op, lhs, rhs) => harden({
_printOn: (out) => {
lhs._printOn(out)
out.print(" " + op + " ")
rhs._printOn(out)
},
quote: () => Quote(binop(op, lhs, rhs))
})
const unary = (op, arg) => harden({
_printOn: (out) => {
out.print(op);
out.print('{');
arg._printOn(out);
out.print('}')
},
quote: () => Quote(unary(op, arg))
})
const contract = (name, args, body) => harden({
_printOn: (out) => {
out.print("contract ")
name._printOn(out)
out.print(`(`)
printList(out, args)
out.begin(`) = {`);
body._printOn(out);
out.end("}")
},
quote: () => Quote(contract(name, args, body))
})
const fmtvdecl = (vd) => typeof vd === 'string' ? vd : `${vd[0]}(\`${vd[1]}\`)`;
/** @type {(vlist: vdecl[], body: Process) => Process} */
const new_ = (vlist, body) => harden({
_printOn: (out) => {
out.newline();
out.print("new ")
let first = true;
for (const item of vlist) {
if (!first) {
if (typeof item === 'string') {
out.print(', ');
} else {
out.print(',');
out.newline();
}
}
out.print(fmtvdecl(item));
first = false;
}
out.newline();
out.begin("in {")
body._printOn(out)
out.end("}");
},
quote: () => Quote(new_(vlist, body))
})
return harden({
Nil,
primitive,
listExpr,
tupleExpr,
mapExpr,
match,
send,
binop,
unary,
receiving,
contract,
Drop,
Var,
Quote,
Par,
new_,
});
}
*/
}

0 comments on commit 68bac6e

Please sign in to comment.