package org.scribble.del.global;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.stream.Collectors;
import org.scribble.ast.AstFactoryImpl;
import org.scribble.ast.MessageTransfer;
import org.scribble.ast.ProtocolDecl;
import org.scribble.ast.ScribNode;
import org.scribble.ast.context.ModuleContext;
import org.scribble.ast.global.GDelegationElem;
import org.scribble.ast.name.qualified.GProtocolNameNode;
import org.scribble.del.ScribDelBase;
import org.scribble.main.ScribbleException;
import org.scribble.sesstype.kind.Global;
import org.scribble.sesstype.name.GProtocolName;
import org.scribble.sesstype.name.ProtocolName;
import org.scribble.sesstype.name.Role;
import org.scribble.visit.context.ProtocolDeclContextBuilder;
import org.scribble.visit.wf.DelegationProtocolRefChecker;
import org.scribble.visit.wf.NameDisambiguator;
public class GDelegationElemDel extends ScribDelBase
{
public GDelegationElemDel()
{
}
// Duplicated from DoDel
@Override
public void enterDisambiguation(ScribNode parent, ScribNode child, NameDisambiguator disamb) throws ScribbleException
{
ModuleContext mc = disamb.getModuleContext();
GDelegationElem de = (GDelegationElem) child;
GProtocolName gpn = de.proto.toName();
if (!mc.isVisibleProtocolDeclName(gpn))
{
throw new ScribbleException(de.proto.getSource(), "Protocol decl not visible: " + gpn);
}
}
// Duplicated from DoDel
//@Override
//public ScribNode leaveDisambiguation(ScribNode parent, ScribNode child, NameDisambiguator disamb, ScribNode visited) throws ScribbleException
public GDelegationElem visitForNameDisambiguation(NameDisambiguator disamb, GDelegationElem de) throws ScribbleException
{
//DelegationElem de = (DelegationElem) visited;
ModuleContext mc = disamb.getModuleContext();
GProtocolName fullname = (GProtocolName) mc.getVisibleProtocolDeclFullName(de.proto.toName());
Role rn = de.role.toName();
ProtocolDecl<Global> gpd = disamb.job.getContext().getModule(fullname.getPrefix()).getProtocolDecl(fullname.getSimpleName());
if (!gpd.header.roledecls.getRoles().contains(rn))
{
throw new ScribbleException(de.role.getSource(), "Invalid delegation role: " + de);
}
GProtocolNameNode pnn = (GProtocolNameNode) AstFactoryImpl.FACTORY.QualifiedNameNode(de.proto.getSource(), fullname.getKind(), fullname.getElements()); // Not keeping original namenode del
return de.reconstruct(pnn, de.role);
}
/*// Is this needed? Or DataTypeNodes always created from AmbigNameNode? (in this same pass)
@Override
public ScribNode leaveDisambiguation(ScribNode parent, ScribNode child, NameDisambiguator disamb, ScribNode visited)
throws ScribbleException
{
ModuleContext mc = disamb.getModuleContext();
DataTypeNode dtn = (DataTypeNode) visited;
DataType fullname = mc.getVisibleDataTypeFullName(dtn.toName());
return (DataTypeNode)
AstFactoryImpl.FACTORY.QualifiedNameNode(DataTypeKind.KIND, fullname.getElements()); // Didn't keep original del
}*/
//@Override
//public DelegationElem leaveProtocolDeclContextBuilding(ScribNodeScribNode parent, ScribNode child, ProtocolDeclContextBuilder builder, ScribNode visited) throws ScribbleException // FIXME: cannot access MessageTransfer roles from here
// FIXME: apply this pattern (delegate from parent back to child class) to all other existing instances
// FIXME: should always be GMessageTransfer
public void leaveMessageTransferInProtocolDeclContextBuilding(MessageTransfer<?> mt, GDelegationElem de, ProtocolDeclContextBuilder builder) throws ScribbleException
{
GProtocolName gpn = de.proto.toName(); // leaveDisambiguation has fully qualified the target name
builder.addGlobalProtocolDependency(mt.src.toName(), gpn, de.role.toName()); // FIXME: does it make sense to use projection role as dependency target role? (seems to be used for Job.getProjections)
mt.getDestinationRoles().forEach((r) -> builder.addGlobalProtocolDependency(r, gpn, de.role.toName()));
}
@Override
public void enterDelegationProtocolRefCheck(ScribNode parent, ScribNode child, DelegationProtocolRefChecker checker) throws ScribbleException
{
GDelegationElem de = (GDelegationElem) child;
ModuleContext mc = checker.getModuleContext();
GProtocolName targetfullname = (GProtocolName) mc.getVisibleProtocolDeclFullName(de.proto.toName());
GProtocolName rootfullname = (GProtocolName) mc.getVisibleProtocolDeclFullName(checker.getProtocolDeclOnEntry().header.getDeclName());
if (targetfullname.equals(rootfullname)) // Explicit check here because ProtocolDeclContextBuilder dependencies explicitly include self protocoldecl dependencies (cf. GProtocolDeclDel.addSelfDependency)
{
throw new ScribbleException(de.getSource(), "Recursive protocol dependencies not supported for delegation types: " + de);
}
Set<GProtocolName> todo = new LinkedHashSet<GProtocolName>();
ProtocolDecl<Global> targetgpd = checker.job.getContext().getModule(targetfullname.getPrefix()).getProtocolDecl(targetfullname.getSimpleName()); // target
// FIXME: does this already contain transitive do-dependencies? But doesn't contain transitive delegation-dependencies..?
Set<GProtocolName> init =
((GProtocolDeclDel) targetgpd.del()).getProtocolDeclContext().getDependencyMap().getDependencies()
.values().stream().flatMap((v) -> v.keySet().stream()).collect(Collectors.toSet());
todo.addAll(init);
Set<GProtocolName> seen = new HashSet<>();
while (!todo.isEmpty())
{
Iterator<GProtocolName> it = todo.iterator();
GProtocolName next = it.next();
it.remove();
seen.add(next);
ProtocolName<Global> nextfullname = mc.getVisibleProtocolDeclFullName(next);
if (rootfullname.equals(nextfullname))
{
throw new ScribbleException(de.getSource(), "Recursive protocol dependencies not supported for delegation types: " + de);
}
ProtocolDecl<Global> nextgpd = checker.job.getContext().getModule(targetfullname.getPrefix()).getProtocolDecl(nextfullname.getSimpleName());
Set<GProtocolName> tmp =
((GProtocolDeclDel) nextgpd.del()).getProtocolDeclContext().getDependencyMap().getDependencies()
.values().stream().flatMap((v) -> v.keySet().stream())
.filter((n) -> !seen.contains(n))
.collect(Collectors.toSet());
todo.addAll(tmp);
}
}
}