package org.scribble.codegen.java.endpointapi.ioifaces; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.IntStream; import org.scribble.codegen.java.endpointapi.SessionApiGenerator; import org.scribble.codegen.java.endpointapi.StateChannelApiGenerator; import org.scribble.codegen.java.util.FieldBuilder; import org.scribble.codegen.java.util.InterfaceBuilder; import org.scribble.codegen.java.util.JavaBuilder; import org.scribble.codegen.java.util.TypeBuilder; import org.scribble.main.RuntimeScribbleException; import org.scribble.main.ScribbleException; import org.scribble.model.endpoint.EState; import org.scribble.model.endpoint.actions.EAction; import org.scribble.sesstype.name.GProtocolName; import org.scribble.sesstype.name.Role; // Cf. ScribSocketGenerator // Partial I/O State I/f generator -- Successor Interfaces and cast methods added later public abstract class IOStateInterfaceGenerator extends IOInterfaceGenerator { public static final Comparator<EAction> IOACTION_COMPARATOR = new Comparator<EAction>() { @Override public int compare(EAction a1, EAction a2) { return ActionInterfaceGenerator.getActionInterfaceName(a1).compareTo(ActionInterfaceGenerator.getActionInterfaceName(a2)); } }; protected final Map<EAction, InterfaceBuilder> actions; protected final InterfaceBuilder ib = new InterfaceBuilder(); // Preds can be null public IOStateInterfaceGenerator(StateChannelApiGenerator apigen, Map<EAction, InterfaceBuilder> actions, EState curr) { super(apigen, curr); this.actions = Collections.unmodifiableMap(actions); } @Override public InterfaceBuilder generateType() throws ScribbleException { constructInterface(); return this.ib; } protected void constructInterface() throws ScribbleException { addHeader(); addSuccessorParamsAndActionInterfaces(); //addSuccessorInterfaces(); // Do later (different states may share the same IO State I/f, don't know all successors for this I/f yet (only this state) addCastField(); } protected void addHeader() { GProtocolName gpn = this.apigen.getGProtocolName(); Role self = this.apigen.getSelf(); String packname = IOInterfacesGenerator.getIOInterfacePackageName(gpn, self); String ifname = getIOStateInterfaceName(self, this.curr); this.ib.setName(ifname); this.ib.setPackage(packname); this.ib.addImports(SessionApiGenerator.getRolesPackageName(gpn) + ".*"); this.ib.addModifiers(JavaBuilder.PUBLIC); } protected void addCastField() { String ifname = getIOStateInterfaceName(this.apigen.getSelf(), this.curr); //Set<EAction> as = this.curr.getActions(); List<EAction> as = this.curr.getActions(); FieldBuilder cast = this.ib.newField("cast"); cast.addModifiers(TypeBuilder.PUBLIC, TypeBuilder.STATIC, TypeBuilder.FINAL); cast.setType(ifname + "<" + IntStream.range(1, as.size()+1).mapToObj((i) -> "?").collect(Collectors.joining(", ")) + ">"); // FIXME: factor out cast.setExpression("null"); } protected void addSuccessorParamsAndActionInterfaces() { int i = 1; for (EAction a : this.curr.getActions().stream().sorted(IOACTION_COMPARATOR).collect(Collectors.toList())) { if (a.isSend() || a.isReceive()) // HACK FIXME { String actif = this.actions.get(a).getName(); this.ib.addParameters("__Succ" + i + " extends " + SuccessorInterfaceGenerator.getSuccessorInterfaceName(a)); this.ib.addInterfaces(actif + "<__Succ" + i + ">"); i++; } } } /*protected void addSuccessorInterfaces() { if (this.preds != null) { System.out.println("AA: " + this.ib.getName() + ", " + this.preds.stream().map((p) -> p.getName()).collect(Collectors.toList())); for (InterfaceBuilder pred : this.preds) { this.ib.addInterfaces(pred.getName()); // Adds Successor Interfaces to this I/O State Interface } } }*/ // Pre: s non-terminal public static String getIOStateInterfaceName(Role self, EState s) { String name = null; switch (s.getStateKind()) { case OUTPUT: name = "Select"; break; case UNARY_INPUT: name = "Receive"; break; case POLY_INPUT: name = "Branch"; break; case TERMINAL: throw new RuntimeScribbleException("Shouldn't get in here: " + s); default: throw new RuntimeException("(TODO) I/O interface generation: " + s.getStateKind()); } name = name + "_" + self + "_" + s.getActions().stream().sorted(IOACTION_COMPARATOR) .map((a) -> ActionInterfaceGenerator.getActionString(a)).collect(Collectors.joining("__")); checkIOStateInterfaceNameLength(name); return name; } // 255 is Linux, Windows, etc max file name length (Java is 65535) public static void checkIOStateInterfaceNameLength(String name) throws RuntimeScribbleException { if (name.length() > 250) // .java { throw new RuntimeScribbleException("I/O Interface name too long (max 255): " + name); } } }