package org.scribble.del.global; import org.antlr.runtime.tree.CommonTree; import org.scribble.ast.AstFactoryImpl; import org.scribble.ast.ScribNode; import org.scribble.ast.context.ModuleContext; import org.scribble.ast.global.GContinue; import org.scribble.ast.global.GDo; import org.scribble.ast.global.GInteractionSeq; import org.scribble.ast.global.GProtocolBlock; import org.scribble.ast.global.GRecursion; import org.scribble.ast.local.LDo; import org.scribble.ast.name.qualified.LProtocolNameNode; import org.scribble.ast.name.simple.RecVarNode; import org.scribble.del.DoDel; import org.scribble.main.ScribbleException; import org.scribble.sesstype.SubprotocolSig; import org.scribble.sesstype.kind.RecVarKind; import org.scribble.sesstype.name.GProtocolName; import org.scribble.sesstype.name.ProtocolName; import org.scribble.sesstype.name.Role; import org.scribble.visit.ProtocolDefInliner; import org.scribble.visit.context.Projector; import org.scribble.visit.context.ProtocolDeclContextBuilder; import org.scribble.visit.env.InlineProtocolEnv; public class GDoDel extends DoDel implements GSimpleInteractionNodeDel { // Part of context building @Override protected void addProtocolDependency(ProtocolDeclContextBuilder builder, Role self, ProtocolName<?> proto, Role target) { builder.addGlobalProtocolDependency(self, (GProtocolName) proto, target); } // Only called if cycle public GDo visitForSubprotocolInlining(ProtocolDefInliner builder, GDo child) { CommonTree blame = child.getSource(); SubprotocolSig subsig = builder.peekStack(); RecVarNode recvar = (RecVarNode) AstFactoryImpl.FACTORY.SimpleNameNode(blame, RecVarKind.KIND, builder.getSubprotocolRecVar(subsig).toString()); GContinue inlined = AstFactoryImpl.FACTORY.GContinue(blame, recvar); builder.pushEnv(builder.popEnv().setTranslation(inlined)); return child; } @Override public GDo leaveProtocolInlining(ScribNode parent, ScribNode child, ProtocolDefInliner inl, ScribNode visited) throws ScribbleException { CommonTree blame = visited.getSource(); SubprotocolSig subsig = inl.peekStack(); if (!inl.isCycle()) { RecVarNode recvar = (RecVarNode) AstFactoryImpl.FACTORY.SimpleNameNode(blame, RecVarKind.KIND, inl.getSubprotocolRecVar(subsig).toString()); GInteractionSeq gis = (GInteractionSeq) (((InlineProtocolEnv) inl.peekEnv()).getTranslation()); GProtocolBlock gb = AstFactoryImpl.FACTORY.GProtocolBlock(blame, gis); GRecursion inlined = AstFactoryImpl.FACTORY.GRecursion(blame, recvar, gb); inl.pushEnv(inl.popEnv().setTranslation(inlined)); inl.removeSubprotocolRecVar(subsig); } return (GDo) super.leaveProtocolInlining(parent, child, inl, visited); } @Override public void enterProjection(ScribNode parent, ScribNode child, Projector proj) throws ScribbleException { GSimpleInteractionNodeDel.super.enterProjection(parent, child, proj); GDo gd = (GDo) child; Role self = proj.peekSelf(); if (gd.roles.getRoles().contains(self)) { // For correct name mangling, need to use the parameter corresponding to the self argument // N.B. -- this depends on Projector not following the Subprotocol pattern, otherwise self is wrong Role param = gd.getTargetRoleParameter(proj.job.getContext(), proj.getModuleContext(), self); proj.pushSelf(param); } else { proj.pushSelf(self); // Dummy: just to make pop in leave work } } @Override public GDo leaveProjection(ScribNode parent, ScribNode child, Projector proj, ScribNode visited) throws ScribbleException //throws ScribbleException { GDo gd = (GDo) visited; Role popped = proj.popSelf(); Role self = proj.peekSelf(); LDo projection = null; if (gd.roles.getRoles().contains(self)) { ModuleContext mc = proj.getModuleContext(); LProtocolNameNode target = Projector.makeProjectedFullNameNode(gd.proto.getSource(), gd.getTargetProtocolDeclFullName(mc), popped); projection = gd.project(self, target); // FIXME: do guarded recursive subprotocol checking (i.e. role is used during chain) in reachability checking? -- required role-usage makes local choice subject inference easier, but is restrictive (e.g. proto(A, B, C) { choice at A {A->B.do Proto(A,B,C)} or {A->B.B->C} })) } proj.pushEnv(proj.popEnv().setProjection(projection)); return (GDo) GSimpleInteractionNodeDel.super.leaveProjection(parent, child, proj, gd); } }