Package edu.mit.csail.sdg.alloy4viz

Source Code of edu.mit.csail.sdg.alloy4viz.StaticInstanceReader

/* Alloy Analyzer 4 -- Copyright (c) 2006-2009, Felix Chang
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify,
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

package edu.mit.csail.sdg.alloy4viz;

import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import edu.mit.csail.sdg.alloy4.Err;
import edu.mit.csail.sdg.alloy4.ErrorFatal;
import edu.mit.csail.sdg.alloy4.ErrorSyntax;
import edu.mit.csail.sdg.alloy4.Util;
import edu.mit.csail.sdg.alloy4.XMLNode;
import edu.mit.csail.sdg.alloy4compiler.ast.Expr;
import edu.mit.csail.sdg.alloy4compiler.ast.ExprVar;
import edu.mit.csail.sdg.alloy4compiler.ast.Sig;
import edu.mit.csail.sdg.alloy4compiler.ast.Sig.Field;
import edu.mit.csail.sdg.alloy4compiler.ast.Sig.PrimSig;
import edu.mit.csail.sdg.alloy4compiler.ast.Sig.SubsetSig;
import edu.mit.csail.sdg.alloy4compiler.translator.A4Solution;
import edu.mit.csail.sdg.alloy4compiler.translator.A4SolutionReader;
import edu.mit.csail.sdg.alloy4compiler.translator.A4Tuple;
import edu.mit.csail.sdg.alloy4compiler.translator.A4TupleSet;

/** This utility class parses an XML file into an AlloyInstance object.
*
* <p><b>Thread Safety:</b> Can be called only by the AWT event thread.
*/

public final class StaticInstanceReader {

   /** The resulting AlloyInstance object. */
   private final AlloyInstance ans;

   /** This is the list of toplevel sigs. */
   private final List<PrimSig> toplevels = new ArrayList<PrimSig>();

   /** This maps each Sig to its corresponding Visualizer AlloyType. */
   private final LinkedHashMap<Sig,AlloyType> sig2type = new LinkedHashMap<Sig,AlloyType>();

   /** This maps each Sig ot its corresponding unique VIsualizer AlloyAtom (if isMeta is true). */
   private final LinkedHashMap<Sig,AlloyAtom> sig2atom = new LinkedHashMap<Sig,AlloyAtom>();

   /** This stores the "extends" relationship among sigs (if isMeta is true). */
   private final LinkedHashSet<AlloyTuple> exts = new LinkedHashSet<AlloyTuple>();

   /** This stores the "in" relationship among sigs (if isMeta is true). */
   private final LinkedHashSet<AlloyTuple> ins  = new LinkedHashSet<AlloyTuple>();

   /** This stores the set of Visualizer AlloySet objects we created. */
   private final Set<AlloySet> sets = new LinkedHashSet<AlloySet>();

   /** This maps each Visualizer AlloyRelation to its set of (possibly 0) tuples. */
   private final Map<AlloyRelation,Set<AlloyTuple>> rels = new LinkedHashMap<AlloyRelation,Set<AlloyTuple>>();

   /** For each sig A and B, if A extends B, and B is not univ, then (A,B) will be in this map. */
   private final Map<AlloyType,AlloyType> ts = new LinkedHashMap<AlloyType,AlloyType>();

   /** This maps each Visualizer AlloyAtom to its set of (possibly 0) AlloySet that contains it. */
   private final Map<AlloyAtom,Set<AlloySet>> atom2sets = new LinkedHashMap<AlloyAtom,Set<AlloySet>>();

   /** This maps each AlloyAtom label to the AlloyAtom we created for it. */
   private final Map<String,AlloyAtom> string2atom = new LinkedHashMap<String,AlloyAtom>();

   /** Create a new AlloyType whose label is unambiguous with any existing one. */
   private AlloyType makeType(String label, boolean isOne, boolean isAbstract, boolean isBuiltin, boolean isPrivate, boolean isMeta, boolean isEnum) {
      if (label.startsWith("this/")) label = label.substring(5);
      while(true) {
         AlloyType ans = new AlloyType(label, isOne, isAbstract, isBuiltin, isPrivate, isMeta, isEnum);
         if (!sig2type.values().contains(ans)) return ans;
         label=label+"'";
      }
   }

   /** Create a new AlloySet whose label is unambiguous with any existing one. */
   private AlloySet makeSet(String label, boolean isPrivate, boolean isMeta, AlloyType type) {
      while(label.equals(Sig.UNIV.label) || label.equals(Sig.SIGINT.label) || label.equals(Sig.SEQIDX.label) || label.equals(Sig.STRING.label)) label=label+"'";
      while(true) {
         AlloySet ans = new AlloySet(label, isPrivate, isMeta, type);
         if (!sets.contains(ans)) return ans;
         label=label+"'";
      }
   }

   /** Create a new AlloyRelation whose label is unambiguous with any existing one. */
   private AlloyRelation makeRel(String label, boolean isPrivate, boolean isMeta, List<AlloyType> types) {
      while(label.equals(Sig.UNIV.label) || label.equals(Sig.SIGINT.label) || label.equals(Sig.SEQIDX.label) || label.equals(Sig.STRING.label)) label=label+"'";
      while(true) {
         AlloyRelation ans = new AlloyRelation(label, isPrivate, isMeta, types);
         if (!rels.containsKey(ans)) return ans;
         label=label+"'";
      }
   }

   /** Returns the AlloyType corresponding to the given sig; create an AlloyType for it if none existed before. */
   private AlloyType sig(PrimSig s) throws Err {
      if (s==Sig.NONE) throw new ErrorFatal("Unexpected sig \"none\" encountered.");
      AlloyType ans = sig2type.get(s);
      if (ans == null) {
         ans = makeType(s.label, s.isOne!=null, s.isAbstract!=null, false, s.isPrivate!=null, s.isMeta!=null, s.isEnum!=null);
         sig2type.put(s, ans);
         if (s.parent!=Sig.UNIV) ts.put(ans, sig(s.parent));
      }
      return ans;
   }

   /** Returns the AlloyType corresponding to the given sig; create an AlloyType for it if none existed before. */
   private AlloyType sigMETA(PrimSig s) throws Err {
      if (s==Sig.NONE) throw new ErrorFatal("Unexpected sig \"none\" encountered.");
      AlloyType type = sig2type.get(s);
      if (type != null) return type;
      if (s==Sig.UNIV) type=AlloyType.UNIV;
      else if (s==Sig.SIGINT) type=AlloyType.INT;
      else if (s==Sig.SEQIDX) type=AlloyType.SEQINT;
      else if (s==Sig.STRING) type=AlloyType.STRING;
      else type = makeType(s.label, s.isOne!=null, s.isAbstract!=null, false, s.isPrivate!=null, s.isMeta!=null, s.isEnum!=null);
      sig2type.put(s, type);
      AlloyAtom atom = new AlloyAtom(type, (type==AlloyType.SEQINT ? Integer.MIN_VALUE : Integer.MAX_VALUE), s.label);
      atom2sets.put(atom, new LinkedHashSet<AlloySet>());
      sig2atom.put(s, atom);
      if (s.parent!=Sig.UNIV && s.parent!=null)
         ts.put(type, sigMETA(s.parent));
      if (s.parent!=null)
         exts.add(new AlloyTuple(atom, sig2atom.get(s.parent)));
      Iterable<PrimSig> children = (s==Sig.UNIV ? toplevels : s.children());
      for(PrimSig sub:children) sigMETA(sub);
      return type;
   }

   /** Returns the AlloyType corresponding to the given sig; create an AlloyType for it if none existed before. */
   private void sigMETA(SubsetSig s) throws Err {
      AlloyAtom atom;
      AlloyType type = sig2type.get(s);
      if (type != null) return;
      type = makeType(s.label, s.isOne!=null, s.isAbstract!=null, false, s.isPrivate!=null, s.isMeta!=null, s.isEnum!=null);
      atom = new AlloyAtom(type, Integer.MAX_VALUE, s.label);
      atom2sets.put(atom, new LinkedHashSet<AlloySet>());
      sig2atom.put(s, atom);
      sig2type.put(s, type);
      ts.put(type, AlloyType.SET);
      for(Sig p: ((SubsetSig)s).parents) {
         if (p instanceof SubsetSig) sigMETA((SubsetSig)p); else sigMETA((PrimSig)p);
         ins.add(new AlloyTuple(atom, sig2atom.get(p)));
      }
   }

   /** Constructs the atoms corresponding to the given sig. */
   private void atoms(A4Solution sol, PrimSig s) throws Err {
      Expr sum=Sig.NONE;
      for(PrimSig c:s.children()) { sum=sum.plus(c); atoms(sol, c); }
      A4TupleSet ts = (A4TupleSet) (sol.eval(s.minus(sum))); // This ensures that atoms will be associated with the most specific sig
      for(A4Tuple z: ts) {
         String atom = z.atom(0);
         int i, dollar = atom.lastIndexOf('$');
         try { i = Integer.parseInt(dollar>=0 ? atom.substring(dollar+1) : atom); } catch(NumberFormatException ex) { i = Integer.MAX_VALUE; }
         AlloyAtom at = new AlloyAtom(sig(s), ts.size()==1 ? Integer.MAX_VALUE : i, atom);
         atom2sets.put(at, new LinkedHashSet<AlloySet>());
         string2atom.put(atom, at);
      }
   }

   /** Construct an AlloySet or AlloyRelation corresponding to the given expression. */
   private void setOrRel(A4Solution sol, String label, Expr expr, boolean isPrivate, boolean isMeta) throws Err {
      for(List<PrimSig> ps:expr.type().fold()) {
         if (ps.size()==1) {
            PrimSig t = ps.get(0);
            AlloySet set = makeSet(label, isPrivate, isMeta, sig(t));
            sets.add(set);
            for(A4Tuple tp: (A4TupleSet)(sol.eval(expr.intersect(t)))) {
               atom2sets.get(string2atom.get(tp.atom(0))).add(set);
            }
         } else {
            Expr mask = null;
            List<AlloyType> types = new ArrayList<AlloyType>(ps.size());
            for(int i=0; i<ps.size(); i++) {
               types.add(sig(ps.get(i)));
               if (mask==null) mask=ps.get(i); else mask=mask.product(ps.get(i));
            }
            AlloyRelation rel = makeRel(label, isPrivate, isMeta, types);
            Set<AlloyTuple> ts = new LinkedHashSet<AlloyTuple>();
            for(A4Tuple tp: (A4TupleSet)(sol.eval(expr.intersect(mask)))) {
               AlloyAtom[] atoms = new AlloyAtom[tp.arity()];
               for(int i=0; i<tp.arity(); i++) {
                  atoms[i] = string2atom.get(tp.atom(i));
                  if (atoms[i]==null) throw new ErrorFatal("Unexpected XML inconsistency: cannot resolve atom "+tp.atom(i));
               }
               ts.add(new AlloyTuple(atoms));
            }
            rels.put(rel, ts);
         }
      }
   }

   /** Parse the file into an AlloyInstance if possible. */
   private StaticInstanceReader(XMLNode root) throws Err {
      XMLNode inst = null;
      for(XMLNode sub: root) if (sub.is("instance")) { inst=sub; break; }
      if (inst==null) throw new ErrorSyntax("The XML file must contain an <instance> element.");
      boolean isMeta = "yes".equals(inst.getAttribute("metamodel"));
      A4Solution sol = A4SolutionReader.read(new ArrayList<Sig>(), root);
      for (Sig s:sol.getAllReachableSigs()) if (s instanceof PrimSig && ((PrimSig)s).parent==Sig.UNIV) toplevels.add((PrimSig)s);
      if (!isMeta) {
         sig2type.put(Sig.UNIV, AlloyType.UNIV);
         sig2type.put(Sig.SIGINT, AlloyType.INT);
         sig2type.put(Sig.SEQIDX, AlloyType.SEQINT);
         sig2type.put(Sig.STRING, AlloyType.STRING);
         ts.put(AlloyType.SEQINT, AlloyType.INT);
         for(int i=sol.min(), max=sol.max(), maxseq=sol.getMaxSeq(); i<=max; i++) {
            AlloyAtom at = new AlloyAtom(i>=0 && i<maxseq ? AlloyType.SEQINT : AlloyType.INT, i, ""+i);
            atom2sets.put(at, new LinkedHashSet<AlloySet>());
            string2atom.put(""+i, at);
         }
         for(Sig s:sol.getAllReachableSigs()) if (!s.builtin && s instanceof PrimSig) sig((PrimSig)s);
         for(Sig s:toplevels)                 if (!s.builtin || s==Sig.STRING)        atoms(sol, (PrimSig)s);
         for(Sig s:sol.getAllReachableSigs()) if (s instanceof SubsetSig)             setOrRel(sol, s.label, s, s.isPrivate!=null, s.isMeta!=null);
         for(Sig s:sol.getAllReachableSigs()) for(Field f:s.getFields())              setOrRel(sol, f.label, f, f.isPrivate!=null, f.isMeta!=null);
         for(ExprVar s:sol.getAllSkolems())   setOrRel(sol, s.label, s, false, false);
      }
      if (isMeta) {
         sigMETA(Sig.UNIV);
         for(Sig s:sol.getAllReachableSigs()) if (s instanceof SubsetSig) sigMETA((SubsetSig)s);
         for(Sig s:sol.getAllReachableSigs()) for(Field f:s.getFields()) {
            for(List<PrimSig> ps:f.type().fold()) {
               List<AlloyType> types = new ArrayList<AlloyType>(ps.size());
               AlloyAtom[] tuple = new AlloyAtom[ps.size()];
               for(int i=0; i<ps.size(); i++) {
                  types.add(sig(ps.get(i)));
                  tuple[i] = sig2atom.get(ps.get(i));
               }
               AlloyRelation rel = makeRel(f.label, f.isPrivate!=null, false, types);
               rels.put(rel, Util.asSet(new AlloyTuple(tuple)));
            }
         }
         if (ins.size()>0) { sig2type.put(null, AlloyType.SET); rels.put(AlloyRelation.IN, ins); }
         AlloyAtom univAtom = sig2atom.get(Sig.UNIV);
         AlloyAtom intAtom = sig2atom.get(Sig.SIGINT);
         AlloyAtom seqAtom = sig2atom.get(Sig.SEQIDX);
         AlloyAtom strAtom = sig2atom.get(Sig.STRING);
         for(Set<AlloyTuple> t: rels.values()) for(AlloyTuple at: t) if (at.getAtoms().contains(univAtom)) { univAtom=null; break; }
         for(Set<AlloyTuple> t: rels.values()) for(AlloyTuple at: t) if (at.getAtoms().contains(intAtom)) { intAtom=null; break; }
         for(Set<AlloyTuple> t: rels.values()) for(AlloyTuple at: t) if (at.getAtoms().contains(seqAtom)) { seqAtom=null; break; }
         for(Set<AlloyTuple> t: rels.values()) for(AlloyTuple at: t) if (at.getAtoms().contains(strAtom)) { strAtom=null; break; }
         if (univAtom!=null) {
            for(Iterator<AlloyTuple> it=exts.iterator(); it.hasNext();) {
               AlloyTuple at=it.next();
               if (at.getStart()==univAtom || at.getEnd()==univAtom) it.remove();
            }
            atom2sets.remove(univAtom);
         }
         if (strAtom!=null) {
            for(Iterator<AlloyTuple> it=exts.iterator(); it.hasNext();) {
               AlloyTuple at=it.next();
               if (at.getStart()==strAtom || at.getEnd()==strAtom) it.remove();
            }
            atom2sets.remove(strAtom);
         }
         if (intAtom!=null && seqAtom!=null) {
            for(Iterator<AlloyTuple> it=exts.iterator(); it.hasNext();) {
               AlloyTuple at=it.next();
               if (at.getStart()==intAtom || at.getEnd()==intAtom || at.getStart()==seqAtom || at.getEnd()==seqAtom) it.remove();
            }
            atom2sets.remove(intAtom);
            atom2sets.remove(seqAtom);
         }
         if (exts.size()>0) { rels.put(AlloyRelation.EXTENDS, exts); }
      }
      AlloyModel am = new AlloyModel(sig2type.values(), sets, rels.keySet(), ts);
      ans=new AlloyInstance(sol, sol.getOriginalFilename(), sol.getOriginalCommand(), am, atom2sets, rels, isMeta);
   }

   /** Parse the file into an AlloyInstance if possible. */
   public static AlloyInstance parseInstance(File file) throws Err {
      try {
         return (new StaticInstanceReader(new XMLNode(file))).ans;
      } catch(IOException ex) {
         throw new ErrorFatal("Error reading the XML file: " + ex, ex);
      }
   }

   /** Parse the file into an AlloyInstance if possible, then close the Reader afterwards. */
   public static AlloyInstance parseInstance(Reader reader) throws Err {
      try {
         return (new StaticInstanceReader(new XMLNode(reader))).ans;
      } catch(IOException ex) {
         throw new ErrorFatal("Error reading the XML file: " + ex, ex);
      }
   }
}
TOP

Related Classes of edu.mit.csail.sdg.alloy4viz.StaticInstanceReader

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.