-
-
Save manuelleduc/2a719c26dfb3c19e8aa23e4007fc038c 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 | |
@Accessors Long value | |
} | |
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.value»] -- «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() | |
} | |
/** | |
* FSMLight is a child of FsmMT but is also a parent of FSM | |
*/ | |
class FsmLight { | |
@Accessors List<StateLight> states = newArrayList | |
} | |
class StateLight { | |
@Accessors String name | |
} | |
/** | |
* 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»'''] | |
} | |
} | |
interface FsmLightAlg<F, S> { | |
def F $(FsmLight f) | |
def S $(StateLight s) | |
} | |
class PrintLightAlg implements FsmLightAlg<IPrint, IPrint> { | |
override $(FsmLight f) { | |
[ | |
''' | |
PrintLightAlg «f.hashCode» | |
«f.states.map[$.print].join(System.lineSeparator)»''' | |
] | |
} | |
override $(StateLight s) { | |
['''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 | |
} | |
} | |
class FsmLightToFsmAlg implements FsmLightAlg<FSM, State> { | |
override $(FsmLight f) { | |
return AdaptersFactoryLight::instance.newAdapter(f) | |
} | |
override $(StateLight s) { | |
return AdaptersFactoryLight::instance.newAdapter(s) | |
} | |
} | |
/** | |
* 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 | |
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 | |
private new() { | |
} | |
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) | |
} | |
def static AdaptersFactory getInstance() { | |
if (instance === null) | |
instance = new AdaptersFactory | |
return instance | |
} | |
} | |
class AdaptersFactoryLight { | |
static AdaptersFactoryLight instance | |
@Accessors(PUBLIC_GETTER) Map<FsmLight, FSM> fsmCache = newHashMap | |
@Accessors(PUBLIC_GETTER) Map<oamt.StateLight, State> stateCache = newHashMap | |
private new() { | |
} | |
def FSM newAdapter(FsmLight f) { | |
if (!fsmCache.containsKey(f)) | |
fsmCache.put(f, new FSM() { | |
override getStates() { | |
return f.states.map[newAdapter(it)] | |
} | |
}) | |
return fsmCache.get(f) | |
} | |
def State newAdapter(StateLight s) { | |
if (!stateCache.containsKey(s)) | |
stateCache.put(s, new State() { | |
override getName() { | |
return s.name | |
} | |
override getValue() { | |
return -1L // arbitrary default value | |
} | |
}) | |
return stateCache.get(s) | |
} | |
def static AdaptersFactoryLight getInstance() { | |
if (instance === null) | |
instance = new AdaptersFactoryLight | |
return instance | |
} | |
} | |
/** | |
* Main | |
*/ | |
class OAMT { | |
def static void main(String[] args) { | |
val m = makeModel | |
val mlight = makeModelLight | |
// 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, wrap(new FsmToFsmMtAlg, m)) | |
// "Adapters" approach: | |
val c = wrap(new FsmToFsmMtAlg2(new PrintMtAlg), m) | |
val d = wrapLight(new PrintLightAlg, mlight) | |
val e = wrap(new PrintAlg, wrapLight(new FsmLightToFsmAlg, mlight)) | |
println(a.print) | |
println(b.print) | |
println(c.print) | |
println(d.print) | |
println(e.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 FSM downcast(FsmLight light) { | |
throw new UnsupportedOperationException("TODO: auto-generated method stub") | |
} | |
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> F wrapLight(FsmLightAlg<F, S> alg, FsmLight m) { | |
return alg.$(m) | |
} | |
def static FsmLight makeModelLight() { | |
return new FsmLight => [ | |
val s1 = new StateLight => [name = "s1l"] | |
val s2 = new StateLight => [name = "s2l"] | |
states += s1 | |
states += s2 | |
] | |
} | |
def static FSM makeModel() { | |
return new FSM => [ | |
val s1 = new State => [ | |
name = "s1" | |
value = 1L | |
] | |
val s2 = new State => [ | |
name = "s2" | |
value = 2L | |
] | |
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
La seule vraie différence c'est que impl est supprimé et wrap est utilisé à la place (puisque c'est la même méthode)