parserImport XOCL; /****************************************************************************** * * * Keyword Instantiation Patterns * * ------------------------------ * * * * A keyword instantiation pattern of the form C[x=P,y=Q,...] matches a value* * when the value is an instance of C and the slot values x and y etc match * * the patterns P and Q etc. * * * ******************************************************************************/ import OCL; context OCL @Class Keywordp extends Pattern @Attribute class : String end @Attribute names : Seq(String) end @Attribute keys : Seq(Keyp) end @Constructor(class,names,keys) ! end @Operation bind(value:Element,target:Element,env:Env::Env,imports:Seq(NameSpace)):Env::Env // Performs pattern matching for the evaluator... let c = if env.binds(class) then names->iterate(name nameSpace = env.lookup(class) | nameSpace.getElement(name)) else names->iterate(name nameSpace = @Find(nameSpace,imports) when nameSpace.hasElement(class) do nameSpace.getElement(class) else self.error("Cannot find name space " + class) end | nameSpace.getElement(name)) end in if value.isKindOf(c) then keys->iterate(key env = env | key.bind(value,target,env,imports)) else throw PatternFailed(self,value) end end end @Operation lift():Performable let nameExps = SetExp("Seq",names->collect(name | StrExp(name))); keyExps = SetExp("Seq",keys->collect(key | key.lift())) in Apply(self.typeExp(),Seq{StrExp(class),nameExps,keyExps}) end end @Operation matchCode(value:Performable,success:Performable,fail:Performable):Performable // Constructs pattern matching code... let matchClass = self.newVar(); matchCnstr = self.newVar(); classCode = names->iterate(n code = Var(class) | [| :: |]) in [| let = in // Check that the class exists... if = null or not .isKindOf(XCore::Class) then else // Check that the value is of the required class... if .isKindOf() then // Check each slot value in turn... else end end end |] end end @Operation matchKeys(keys:Seq(Keyp),value:Performable,success:Performable,fail:Performable):Performable // produces matching code for each of the slots... if keys->isEmpty then success else keys->head.matchCode(value,self.matchKeys(keys->tail,value,success,fail),fail) end end @Operation needsBacktrack():Boolean keys->exists(key | key.needsBacktrack()) end @Operation pprint(out) let index = 0 in format(out,"~S~{~;::~S~}[",Seq{class,names}); @For key in keys do key.pprint(out); if not isLast then format(out,",") end end; format(out,"]") end end @Operation toSig() NamedType(Seq{class | names}).toSig() end end