Created
February 15, 2017 17:05
-
-
Save tdegueul/5d917e1936f570b94de74e7890ebdf8c to your computer and use it in GitHub Desktop.
Attempting to map OA and MT theories
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package oamt | |
import java.util.List | |
import java.util.Map | |
import org.eclipse.xtend.lib.annotations.Accessors | |
/** | |
* Fsm AS | |
*/ | |
class FSM { | |
@Accessors List<State> states = newArrayList | |
@Accessors List<Transition> trans = newArrayList | |
} | |
class State { | |
@Accessors String name | |
} | |
class Transition { | |
@Accessors String evt | |
@Accessors State src | |
@Accessors State tgt | |
} | |
/** | |
* Classic Fsm Algebra | |
*/ | |
interface FsmAlg<F, S, T> { | |
def F $(FSM f) | |
def S $(State s) | |
def T $(Transition t) | |
} | |
interface IPrint { | |
def String print() | |
} | |
class PrintAlg implements FsmAlg<IPrint, IPrint, IPrint> { | |
override $(FSM f) { | |
return [ | |
''' | |
PrintAlg: «f.hashCode» | |
«f.states.map[$.print].join(System::lineSeparator)» | |
«f.trans.map[$.print].join(System::lineSeparator)»''' | |
] | |
} | |
override $(State s) { | |
return ['''State «s.name» -- «s.hashCode»'''] | |
} | |
override $(Transition t) { | |
return ['''Trans «t.evt» («t.src.name» -> «t.tgt.name») -- «t.hashCode»'''] | |
} | |
} | |
/** | |
* FsmMT AS | |
* | |
* Just the same as Fsm, without transitions | |
*/ | |
interface FsmMT { | |
def List<StateMT> getStates() | |
} | |
interface StateMT { | |
def String getName() | |
} | |
/** | |
* FsmMT Algebra | |
* | |
* We use this one to write denotations (e.g. in PrintMtAlg) | |
* that can be reused for all the other algebras (e.g. FsmAlg) | |
* that "implement" it. | |
*/ | |
interface FsmMtAlg<F, S> { | |
def F $(FsmMT f) | |
def S $(StateMT s) | |
} | |
class PrintMtAlg implements FsmMtAlg<IPrint, IPrint> { | |
override $(FsmMT f) { | |
return [ | |
''' | |
PrintMtAlg: «f.hashCode» | |
«f.states.map[$.print].join(System::lineSeparator)»''' | |
] | |
} | |
override $(StateMT s) { | |
return ['''State «s.name» -- «s.hashCode»'''] | |
} | |
} | |
/** | |
* Fsm -> FsmMT (transfo) | |
* | |
* First way of making Fsm "implement" FsmMT: simply write | |
* denotations from Fsm to in FsmMT through a stupid adapter | |
* pattern. In the end, it's just a transfo Fsm -> FsmMT. | |
*/ | |
class FsmToFsmMtAlg implements FsmAlg<FsmMT, StateMT, Void> { | |
override $(FSM f) { | |
return AdaptersFactory::instance.newAdapter(f) | |
} | |
override $(State s) { | |
return AdaptersFactory::instance.newAdapter(s) | |
} | |
override $(Transition t) { | |
return null | |
} | |
} | |
/** | |
* Fsm -> FsmMT (adapters) | |
* | |
* Second way: we don't actually generate an output model | |
* in a "transfo" style, but just wrap Fsm's denotations | |
* into FsmMT's denotations. | |
*/ | |
class FsmToFsmMtAlg2<F, S> implements FsmAlg<F, S, Void> { | |
FsmMtAlg<F, S> alg | |
private new() {} | |
new(FsmMtAlg<F, S> alg) { this.alg = alg } | |
override $(FSM f) { | |
return alg.$(AdaptersFactory::instance.newAdapter(f)) | |
} | |
override $(State s) { | |
return alg.$(AdaptersFactory::instance.newAdapter(s)) | |
} | |
override $(Transition t) { | |
return null | |
} | |
} | |
/** | |
* We don't need to manage that if Melange is in the loop. | |
* It already generates the appropriate adapters, ensures | |
* identity, handles reflective calls, whole EMF API, etc. | |
*/ | |
class AdaptersFactory { | |
static AdaptersFactory instance | |
@Accessors(PUBLIC_GETTER) Map<FSM, FsmMT> fsmCache = newHashMap | |
@Accessors(PUBLIC_GETTER) Map<State, StateMT> stateCache = newHashMap | |
def FsmMT newAdapter(FSM f) { | |
if (!fsmCache.containsKey(f)) | |
fsmCache.put(f, new FsmMT() { | |
override getStates() { | |
return f.states.map[newAdapter(it)] | |
} | |
}) | |
return fsmCache.get(f) | |
} | |
def StateMT newAdapter(State s) { | |
if (!stateCache.containsKey(s)) | |
stateCache.put(s, new StateMT() { | |
override getName() { | |
return s.name | |
} | |
}) | |
return stateCache.get(s) | |
} | |
private new() {} | |
def static AdaptersFactory getInstance() { | |
if (instance === null) | |
instance = new AdaptersFactory | |
return instance | |
} | |
} | |
/** | |
* Main | |
*/ | |
class OAMT { | |
def static void main(String[] args) { | |
val m = makeModel | |
// Classic OA: apply IPrint on FsmAlg | |
val a = wrap(new PrintAlg, m) | |
// "Transfo" approach: first translate Fsm to FsmMT | |
// using impl(), then apply IPrint as usual | |
val b = wrapMT(new PrintMtAlg, impl(new FsmToFsmMtAlg, m)) | |
// "Adapters" approach: | |
val c = wrap(new FsmToFsmMtAlg2(new PrintMtAlg), m) | |
println(a.print) | |
println(b.print) | |
println(c.print) | |
println | |
println("fsmCache:") | |
AdaptersFactory::instance.fsmCache.forEach[ | |
println(''' «$0.hashCode» => «$1.hashCode»''') | |
] | |
println("stateCache:") | |
AdaptersFactory::instance.stateCache.forEach[ | |
println(''' «$0.hashCode» => «$1.hashCode»''') | |
] | |
} | |
def static <F, S, T> F wrap(FsmAlg<F, S, T> alg, FSM m) { | |
return alg.$(m) | |
} | |
def static <F, S> F wrapMT(FsmMtAlg<F, S> alg, FsmMT m) { | |
return alg.$(m) | |
} | |
def static <F, S, T> F impl(FsmAlg<F, S, T> alg, FSM m) { | |
return alg.$(m) | |
} | |
def static FSM makeModel() { | |
return new FSM => [ | |
val s1 = new State => [name = "s1"] | |
val s2 = new State => [name = "s2"] | |
val t1 = new Transition => [evt = "on"] | |
val t2 = new Transition => [evt = "off"] | |
t1.src = s1 ; t1.tgt = s2 | |
t2.src = s2 ; t2.tgt = s1 | |
states += s1 | |
states += s2 | |
trans += t1 | |
trans += t2 | |
] | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment