package org.scribble.ast.global; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; import org.antlr.runtime.tree.CommonTree; import org.scribble.ast.AstFactoryImpl; import org.scribble.ast.Choice; import org.scribble.ast.ProtocolBlock; import org.scribble.ast.ScribNodeBase; import org.scribble.ast.local.LChoice; import org.scribble.ast.local.LProtocolBlock; import org.scribble.ast.name.simple.RoleNode; import org.scribble.del.ScribDel; import org.scribble.main.RuntimeScribbleException; import org.scribble.main.ScribbleException; import org.scribble.sesstype.kind.Global; import org.scribble.sesstype.name.Role; import org.scribble.util.ScribUtil; public class GChoice extends Choice<Global> implements GCompoundInteractionNode { public GChoice(CommonTree source, RoleNode subj, List<GProtocolBlock> blocks) { super(source, subj, blocks); } public LChoice project(Role self, List<LProtocolBlock> blocks) { LChoice projection = null; // Individual GlobalInteractionNodes become null if not projected -- projected seqs and blocks are never null though /*if (blocks.size() == 1) { if (!blocks.get(0).isEmpty()) // WF allows empty (blocks/seq are never null) { RoleNode subj = AstFactoryImpl.FACTORY.DummyProjectionRoleNode(); projection = AstFactoryImpl.FACTORY.LChoice(subj, blocks); } } else //if (blocks.size() > 1)*/ blocks = blocks.stream().filter((b) -> !b.isEmpty()).collect(Collectors.toList()); if (!blocks.isEmpty()) { // FIXME? initially keep global subject, and later overwrite as necessary in projections? (algorithm currently checks for DUMMY) RoleNode subj = self.equals(this.subj.toName()) ? this.subj.clone() : AstFactoryImpl.FACTORY.DummyProjectionRoleNode(); List<LChoice> cs = blocks.stream().map((b) -> AstFactoryImpl.FACTORY.LChoice(this.source, subj, Arrays.asList(b))).collect(Collectors.toList()); // Hacky: keeping this.source for each LChoice (will end up as the source for the final merged LChoice) LChoice merged = cs.get(0); try { for (int i = 1; i < cs.size(); i++) { merged = merged.merge(cs.get(i)); // Merge currently does "nothing"; validation takes direct non-deterministic interpretation -- purpose of syntactic merge is to convert non-det to "equivalent" safe det in certain sitations } } catch (ScribbleException e) // HACK { throw new RuntimeScribbleException(e); } projection = merged; } return projection; } @Override protected ScribNodeBase copy() { return new GChoice(this.source, this.subj, getBlocks()); } @Override public GChoice clone() { RoleNode subj = this.subj.clone(); List<GProtocolBlock> blocks = ScribUtil.cloneList(getBlocks()); return AstFactoryImpl.FACTORY.GChoice(this.source, subj, blocks); } @Override public GChoice reconstruct(RoleNode subj, List<? extends ProtocolBlock<Global>> blocks) { ScribDel del = del(); GChoice gc = new GChoice(this.source, subj, castBlocks(blocks)); gc = (GChoice) gc.del(del); return gc; } @Override public List<GProtocolBlock> getBlocks() { return castBlocks(super.getBlocks()); } private static List<GProtocolBlock> castBlocks(List<? extends ProtocolBlock<Global>> blocks) { return blocks.stream().map((b) -> (GProtocolBlock) b).collect(Collectors.toList()); } // FIXME: shouldn't be needed, but here due to Eclipse bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=436350 @Override public Global getKind() { return GCompoundInteractionNode.super.getKind(); } }