/** * Returns the declaration constraints. * * @return declaration constraints */ public final Formula decls() { // File and Dir partition object final Formula f0 = Obj.eq(File.union(Dir)).and(File.intersection(Dir).no()); // Root and Cur are in Dir and do not intersect final Formula f1 = Root.in(Dir).and(Cur.in(Dir)).and(Root.intersection(Cur).no()); // don't need to specify that Dir, Name, and DirEntry are disjoint; implied by bounds final Formula f2 = entries.in(Dir.product(DirEntry)); final Formula f3 = parent.partialFunction(Dir, Dir); final Formula f4 = name.function(DirEntry, Name); final Formula f5 = contents.function(DirEntry, Obj); return f0.and(f1).and(f2).and(f3).and(f4).and(f5); }
/** Allocate relations for SubsetSig top-down. */ private Expression allocateSubsetSig(SubsetSig sig) throws Err { // We must not visit the same SubsetSig more than once, so if we've been here already, then // return the old value right away Expression sum = sol.a2k(sig); if (sum != null && sum != Expression.NONE) return sum; // Recursively form the union of all parent expressions TupleSet ts = factory.noneOf(1); for (Sig parent : sig.parents) { Expression p = (parent instanceof PrimSig) ? sol.a2k(parent) : allocateSubsetSig((SubsetSig) parent); ts.addAll(sol.query(true, p, false)); if (sum == null) sum = p; else sum = sum.union(p); } // If subset is exact, then just use the "sum" as is if (sig.exact) { sol.addSig(sig, sum); return sum; } // Allocate a relation for this subset sig, then bound it rep.bound("Sig " + sig + " in " + ts + "\n"); Relation r = sol.addRel(sig.label, null, ts); sol.addSig(sig, r); // Add a constraint that it is INDEED a subset of the union of its parents sol.addFormula(r.in(sum), sig.isSubset); return r; }
/** * Returns all facts in the model. * * @return the facts. */ public final Formula facts() { // sig File extends Object {} { some d: Dir | this in d.entries.contents } final Variable file = Variable.unary("this"); final Variable d = Variable.unary("d"); final Formula f0 = file.in(d.join(entries).join(contents)).forSome(d.oneOf(Dir)).forAll(file.oneOf(File)); // sig Dir extends Object { // entries: set DirEntry, // parent: lone Dir // } { // parent = this.~@contents.~@entries // all e1, e2 : entries | e1.name = e2.name => e1 = e2 // this !in this.^@parent // this != Root => Root in this.^@parent // } final Variable dir = Variable.unary("this"); final Variable e1 = Variable.unary("e1"), e2 = Variable.unary("e2"); final Formula f1 = (dir.join(parent)).eq(dir.join(contents.transpose()).join(entries.transpose())); final Expression e0 = dir.join(entries); final Formula f2 = e1.join(name).eq(e2.join(name)).implies(e1.eq(e2)).forAll(e1.oneOf(e0).and(e2.oneOf(e0))); final Formula f3 = dir.in(dir.join(parent.closure())).not(); final Formula f4 = dir.eq(Root).not().implies(Root.in(dir.join(parent.closure()))); final Formula f5 = f1.and(f2).and(f3).and(f4).forAll(dir.oneOf(Dir)); // one sig Root extends Dir {} { no parent } final Formula f6 = Root.join(parent).no(); // sig DirEntry { // name: Name, // contents: Object // } { one this.~entries } final Variable entry = Variable.unary("this"); final Formula f7 = entry.join(entries.transpose()).one().forAll(entry.oneOf(DirEntry)); // fact OneParent { // // all directories besides root xhave one parent // all d: Dir - Root | one d.parent // } final Formula f8 = d.join(parent).one().forAll(d.oneOf(Dir.difference(Root))); return f0.and(f5).and(f6).and(f7).and(f8); }