/** * Title: AGG<p> * Description: <p> * Copyright: Copyright (c) Michael Matz<p> * Company: TU Berlin<p> * @author Michael Matz * @version 1.0 */ package agg.cons; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.Vector; import agg.attribute.impl.TupleMapping; import agg.attribute.impl.ValueTuple; import agg.attribute.impl.ValueMember; import agg.attribute.impl.VarTuple; import agg.attribute.impl.VarMember; import agg.attribute.impl.CondTuple; import agg.attribute.impl.CondMember; import agg.attribute.impl.ContextView; import agg.attribute.handler.impl.javaExpr.JexExpr; import agg.attribute.parser.javaExpr.SimpleNode; import agg.attribute.parser.javaExpr.ASTPrimaryExpression; import agg.attribute.parser.javaExpr.ASTExpression; import agg.attribute.handler.SymbolTable; import agg.attribute.handler.HandlerType; import agg.attribute.handler.HandlerExpr; import agg.attribute.handler.AttrHandlerException; import agg.xt_basis.Arc; import agg.xt_basis.BaseFactory; import agg.xt_basis.Graph; import agg.xt_basis.GraphObject; import agg.xt_basis.MatchHelper; import agg.xt_basis.Node; import agg.xt_basis.OrdinaryMorphism; import agg.xt_basis.Rule; import agg.xt_basis.TypeException; import agg.xt_basis.BadMappingException; import agg.xt_basis.TypeSet; import agg.util.Pair; public class Convert { private Rule rule; private AtomConstraint atom; private String error = ""; private boolean setEnabledTG = false; public Convert(Rule r, AtomConstraint a) { this.rule = r; this.atom = a; if (this.atom.getSource().isEmpty()) { this.setEnabledTG = true; } } class Link { private Link up; private GraphObject o; public Link() { this.up = null; this.o = null; } public Link find() { Link l = this; while (l.up != null) l = l.up; Link m = this; while (m.up != null) { Link n = m.up; m.up = l; m = n; } return l; } public Link link(Link other) { Link po = other.find(); Link pt = find(); po.up = pt; return pt; } public GraphObject get() { return find().o; } public void set(GraphObject go) { find().o = go; } } /** * Calculates the pushout of two morphisms. Calculates this diagram: * P-----r----->G1 | | m | p2 | | v v G2---------->G3 p1 It returns the pair * (p1,p2) of the two resulting morphisms. I.e. the firs in the pair is * parallel to the first argument. Note, that the order of the two input * morphisms only matters if the nodes are attributed. In this case the * second morphism (m) is used for "setting" the free variables in r, and * applying them is done by the first morphism r. This resembles the use in * rules and matches, therefore the arguments are named such. Note further, * that otherwise the properties of the morphisms don't matter in any way. * The returned thing will be a pushout as much as possible (i.e. p2*r==p1*m * in any case). m and r can be partial. They can be broken (in the sense of * deleting nodes, while mapping edges), or they can identify nodes in one * while not in the other. */ private Pair<OrdinaryMorphism, OrdinaryMorphism> pushout( final OrdinaryMorphism r, final OrdinaryMorphism m) { this.error = ""; final BaseFactory bf = BaseFactory.theFactory(); final Graph P = r.getOriginal(); if (P != m.getOriginal()) { System.err .println("Failed! Convert.pushout() called with morphisms from different sources"); return null; } final Graph G3 = bf.createGraph(r.getImage().getTypeSet()); G3.setName(r.getName()); final OrdinaryMorphism p1 = bf.createMorphism(m.getImage(), G3); p1.setName("p1_morphism"); final OrdinaryMorphism p2 = bf.createMorphism(r.getImage(), G3); p2.setName("p2_morphism"); final HashMap<Object, Link> hash = new HashMap<Object, Link>(); Iterator<?> en = P.getNodesSet().iterator(); while (en.hasNext()) hash.put(en.next(), new Link()); en = P.getArcsSet().iterator(); while (en.hasNext()) hash.put(en.next(), new Link()); en = r.getImage().getNodesSet().iterator(); while (en.hasNext()) hash.put(en.next(), new Link()); en = r.getImage().getArcsSet().iterator(); while (en.hasNext()) hash.put(en.next(), new Link()); en = m.getImage().getNodesSet().iterator(); while (en.hasNext()) hash.put(en.next(), new Link()); en = m.getImage().getArcsSet().iterator(); while (en.hasNext()) hash.put(en.next(), new Link()); /* * Now we link together all graph objects which somehow are mapped to * each other. This UNION/FIND structure enables us to quickly find * nodes which must be identified. */ Link empty = new Link(); /* * This is used as target for linking, for * deleting unmapped objects. This makes it * simpler to link unmapped objects, instead * of testing for null of return value of * getImage(o). */ hash.put(null, empty); en = P.getNodesSet().iterator(); while (en.hasNext()) { GraphObject go = (GraphObject) en.next(); GraphObject img1 = r.getImage(go); GraphObject img2 = m.getImage(go); // img2 has to be always existent; check this ... if (img2 == null) { System.err .println("Argh! Convert.pushout() FAILED! (m match is corrupt)"); return null; } Link l = hash.get(go); /* * We don't need to test for img being null here, because at that * hash index the "empty" link is placed, which is the right thing * here. */ l.link(hash.get(img1)).link(hash.get(img2)); /* * Hmm, if we have a mapped edge, we also need to identify both * source and target nodes. This _should_ already be done, because a * valid morphism only maps an edge when also mapping both end * nodes. */ /* * But if we delete a nodes, also all incident edges need deletion, * which also should be done already, but we are not sure of this. * So we simply delete all those edges here (by linking them to * empty). This then also deletes all other strange edges mapped to * this one by the other morphism. */ if ((img1 == null) && go.isNode()) { Node n = (Node) go; Iterator<Arc> arcs = n.getIncomingArcsSet().iterator(); while (arcs.hasNext()) empty.link(hash.get(arcs.next())); arcs = n.getOutgoingArcsSet().iterator(); while (arcs.hasNext()) empty.link(hash.get(arcs.next())); } } en = P.getArcsSet().iterator(); while (en.hasNext()) { GraphObject go = (GraphObject) en.next(); GraphObject img1 = r.getImage(go); GraphObject img2 = m.getImage(go); // img2 has to be always existent; check this ... if (img2 == null) { System.err .println("Argh! Convert.pushout() FAILED! (m match is corrupt)"); return null; } Link l = hash.get(go); /* * We don't need to test for img being null here, because at that * hash index the "empty" link is placed, which is the right thing * here. */ l.link(hash.get(img1)).link(hash.get(img2)); /* * Hmm, if we have a mapped edge, we also need to identify both * source and target nodes. This _should_ already be done, because a * valid morphism only maps an edge when also mapping both end * nodes. */ /* * But if we delete a nodes, also all incident edges need deletion, * which also should be done already, but we are not sure of this. * So we simply delete all those edges here (by linking them to * empty). This then also deletes all other strange edges mapped to * this one by the other morphism. */ } empty = empty.find(); // before to compute PO, disable Multiplicity check for min and max, too int checkLevelTG = G3.getTypeSet().getLevelOfTypeGraphCheck(); if (this.setEnabledTG) G3.getTypeSet().setLevelOfTypeGraphCheck(TypeSet.ENABLED); /* Now we can create the objects in G3. We first create the nodes. */ for (int k = 0; k < 2; k++) { OrdinaryMorphism morph = (k == 0) ? p1 : p2; en = morph.getOriginal().getNodesSet().iterator(); while (en.hasNext()) { Node n = (Node) en.next(); Link l = (hash.get(n)).find(); if (l == empty) continue; /* This is a to be deleted node. */ /* * Otherwise in l.get() there is the node in G3, which should * this be mapped to. l.get() may still be null, which means, * that the node doesn't yet exist in G3, and has to be created * now (and placed into the link). */ Node n2 = (Node) l.get(); if (n2 == null) { try { n2 = G3.copyNode(n); n2.setContextUsage(n.getContextUsage()); if (checkAttributeValue(n, n2)) { try { morph.addMapping(n, n2); } catch (BadMappingException ex1) { this.error = ex1.getLocalizedMessage(); return null; } } l.set(n2); } catch (TypeException ex) { this.error = ex.getLocalizedMessage(); // System.out.println(this.getClass().getName()+".pushout: "+error); return null; } } else { if (checkAttributeValue(n, n2)) { try { morph.addMapping(n, n2); } catch (BadMappingException ex1) { this.error = ex1.getLocalizedMessage(); return null; } } } } } /* And now the arcs. */ for (int k = 0; k < 2; k++) { OrdinaryMorphism morph = (k == 0) ? p1 : p2; en = morph.getOriginal().getArcsSet().iterator(); while (en.hasNext()) { Arc a = (Arc) en.next(); Link l = (hash.get(a)).find(); if (l == empty) continue; Arc a2 = (Arc) l.get(); if (a2 == null) { GraphObject src = morph.getImage(a.getSource()); GraphObject tgt = morph.getImage(a.getTarget()); /* * Be sure to only create an arc in G3 if not source and * target are deleted. */ if (src == null || tgt == null) continue; try { a2 = G3.copyArc(a, (Node) src, (Node) tgt); a2.setContextUsage(a.getContextUsage()); if (checkAttributeValue(a, a2)) { try { morph.addMapping(a, a2); } catch (BadMappingException ex1) { this.error = ex1.getLocalizedMessage(); return null; } } l.set(a2); } catch (TypeException e) { this.error = e.getLocalizedMessage(); // System.out.println(this.getClass().getName()+".pushout: "+error); return null; } } else { if (checkAttributeValue(a, a2)) { try { morph.addMapping(a, a2); } catch (BadMappingException ex1) { this.error = ex1.getLocalizedMessage(); return null; } } } } } // enable Multiplicity check again G3.getTypeSet().setLevelOfTypeGraphCheck(checkLevelTG); return new Pair<OrdinaryMorphism, OrdinaryMorphism>(p1, p2); } public String getErrorMsg() { return this.error; } public Vector<Object> convert() { final Vector<Object> ret = new Vector<Object>(); if (!this.atom.isValid()) { return ret; } this.atom.adoptEntriesWhereEmpty(); renameVariables(this.rule, this.atom); final Graph R = this.rule.getRight(); /* .first corresponds to this.getSource(); .second with R */ /* * Wir brauchen auch disjunkte Vereinigung. Im Falle von attributierten * Graphen spielt das eine Rolle (siehe ensure_pred.ggx aus der * Diplomarbeit) */ boolean leftgraph = true; boolean disjunion = true; // Create S = R + P with disjunion Enumeration<Pair<OrdinaryMorphism, OrdinaryMorphism>> all_s = null; all_s = MatchHelper.getOverlappings(this.atom, R, leftgraph, disjunion); while (all_s.hasMoreElements()) { Pair<OrdinaryMorphism, OrdinaryMorphism> morphs = all_s.nextElement(); OrdinaryMorphism p = morphs.first; OrdinaryMorphism s = morphs.second; if (!p.isInjective()) { continue; } Enumeration<GraphObject> e = p.getDomain(); while (e.hasMoreElements()) { GraphObject o = e.nextElement(); if (o.getAttribute() == null) continue; GraphObject img = p.getImage(o); ValueTuple val = (ValueTuple) o.getAttribute(); ValueTuple valimg = (ValueTuple) img.getAttribute(); for (int i = 0; i < val.getSize(); i++) { ValueMember m = val.getValueMemberAt(i); ValueMember mimg = valimg.getValueMemberAt(i); if ((mimg.getExpr() != null) && mimg.getExpr().isComplex()) { if (m.getExpr() != null) { if (m.getExpr().isVariable() || m.getExpr().isConstant()) { mimg.setExprAsText(m.getExprAsText()); mimg.setTransient(true); } else if (m.getExpr().isComplex()) mimg.setExpr(null); } else mimg.setExpr(null); } } } e = s.getDomain(); while (e.hasMoreElements()) { GraphObject o = e.nextElement(); if (o.getAttribute() == null) { continue; } GraphObject img = s.getImage(o); ValueTuple val = (ValueTuple) o.getAttribute(); ValueTuple valimg = (ValueTuple) img.getAttribute(); for (int i = 0; i < val.getSize(); i++) { ValueMember m = val.getValueMemberAt(i); ValueMember mimg = valimg.getValueMemberAt(i); if ((mimg.getExpr() != null) && mimg.getExpr().isComplex()) { if (m.getExpr() != null) { if (m.getExpr().isVariable() || m.getExpr().isConstant()) mimg.setExprAsText(m.getExprAsText()); else if (m.getExpr().isComplex()) mimg.setExpr(null); } else mimg.setExpr(null); } } } OrdinaryMorphism pmatch = BaseFactory.theFactory() .createMorphfromMorph(p, this.atom.getAttrContext()); if (pmatch == null) { continue; } final Vector<Object> v = new Vector<Object>(); EvalSet set = null; final Enumeration<AtomConstraint> conclusions = this.atom.getConclusions(); while (conclusions.hasMoreElements()) { final AtomConstraint conclusion = conclusions.nextElement(); adoptEntriesWhereEmpty(pmatch); final Pair<OrdinaryMorphism, OrdinaryMorphism> po = pushout(conclusion, pmatch); if (po != null) { final OrdinaryMorphism t = po.first; final OrdinaryMorphism q = po.second; if (t.isTotal() && q.isTotal()) { t.setAttrContext(conclusion.getAttrContext()); adoptEntriesWhereEmpty(t); v.add(new AtomApplCond(conclusion, s, t, q)); } } } if (!v.isEmpty()) { set = new EvalSet(v); ret.add(set); } } return ret; } private boolean checkAttributeValue(GraphObject from, GraphObject to) { if (from.getAttribute() == null && to.getAttribute() == null) return true; else if (from.getAttribute() != null && to.getAttribute() != null) { ValueTuple valueFrom = (ValueTuple) from.getAttribute(); ValueTuple valueTo = (ValueTuple) to.getAttribute(); for (int i = 0; i < valueFrom.getSize(); i++) { ValueMember mFrom = valueFrom.getValueMemberAt(i); ValueMember mTo = valueTo.getValueMemberAt(i); if (mFrom.isSet() && mTo.isSet()) { if ((mFrom.getExpr().isConstant() || mTo.getExpr() .isConstant()) && !mFrom.getExprAsText().equals( mTo.getExprAsText())) return false; } } return true; } else return false; } private void adoptEntriesWhereEmpty(OrdinaryMorphism morph) { Enumeration<GraphObject> e = morph.getDomain(); while (e.hasMoreElements()) { GraphObject obj = e.nextElement(); GraphObject img = morph.getImage(obj); if (img.getAttribute() == null) continue; ContextView context = (ContextView) morph.getAttrContext(); Vector<TupleMapping> mappings = context.getMappingsToTarget((ValueTuple) img .getAttribute()); if (mappings != null) { mappings.elementAt(0).adoptEntriesWhereEmpty( (ValueTuple) obj.getAttribute(), (ValueTuple) img .getAttribute()); } } } private void renameVariables(Rule r, AtomConstraint atomic) { OrdinaryMorphism m1 = r; Enumeration<AtomConstraint> conclusions = atomic.getConclusions(); if (conclusions.hasMoreElements()) { OrdinaryMorphism m2 = conclusions.nextElement(); int index = 1; String mark = String.valueOf(index); VarTuple varsm1 = (VarTuple) m1.getAttrContext().getVariables(); VarTuple varsm2 = (VarTuple) m2.getAttrContext().getVariables(); for (int i = 0; i < varsm1.getSize(); i++) { VarMember vm1 = varsm1.getVarMemberAt(i); VarMember vm2 = varsm2.getVarMemberAt(vm1.getName()); if ((vm2 != null) && vm1.getDeclaration().getTypeName().equals( vm2.getDeclaration().getTypeName())) { String from = vm2.getName(); String to = vm2.getName() + mark; while (varsm2.getVarMemberAt(to) != null) { mark = String.valueOf(index++); to = vm2.getName() + mark; } vm2.getDeclaration().setName(to); // rename variables in left/right graphs of morphs setAttributeVariable(from, to, varsm2, m2.getSource().getNodesSet().iterator()); setAttributeVariable(from, to, varsm2, m2.getSource().getArcsSet().iterator()); setAttributeVariable(from, to, varsm2, m2.getTarget().getNodesSet().iterator()); setAttributeVariable(from, to, varsm2, m2.getTarget().getArcsSet().iterator()); CondTuple conds = (CondTuple) m2.getAttrContext() .getConditions(); renameVariableInCondition(conds, from, to); while (conclusions.hasMoreElements()) { OrdinaryMorphism mc = conclusions.nextElement(); VarTuple varsmc = (VarTuple) mc.getAttrContext() .getVariables(); setAttributeVariable(from, to, varsmc, mc.getTarget().getNodesSet().iterator()); setAttributeVariable(from, to, varsmc, mc.getTarget().getArcsSet().iterator()); conds = (CondTuple) mc.getAttrContext().getConditions(); renameVariableInCondition(conds, from, to); } } } } } private void renameVariableInCondition(CondTuple conds, String from, String to) { // rename variables in conditions for (int j = 0; j < conds.getSize(); j++) { CondMember cm = conds.getCondMemberAt(j); // String condStr = cm.getExprAsText(); Vector<String> v1 = cm.getAllVariables(); if (v1.contains(from)) { JexExpr oldExpr = (JexExpr) cm.getExpr(); // System.out.println("ast: "+oldExpr.getAST()); // System.out.println("Children of ast: // "+oldExpr.getAST().jjtGetNumChildren()); Vector<String> variables = new Vector<String>(); oldExpr.getAllVariables(variables); /* * System.out.println("Variables of ast: "+variables.size()); * for(int ii=0; ii<variables.size(); ii++) { * System.out.println("ast variable: * "+(String)variables.get(ii)); } */ findPrimaryAndReplace((SimpleNode) oldExpr.getAST(), from, to, null); // System.out.println("--------------------------"); } } } private void setAttributeVariable( final String from, final String to, final VarTuple vars, final Iterator<?> elems) { while (elems.hasNext()) { GraphObject obj = (GraphObject) elems.next(); ValueTuple fromObj = (ValueTuple) obj.getAttribute(); for (int i = 0; i < fromObj.getSize(); i++) { ValueMember fromVM = fromObj.getValueMemberAt(i); if (fromVM.isSet()) { if (fromVM.getExpr().isVariable()) { if (fromVM.getExprAsText().equals(from) && (vars.getVarMemberAt(to) != null)) { fromVM.setExprAsText(to); // System.out.println(">>>>> set Attribute expr (is // Variable) : "+from+" to "+to); } } else if (fromVM.getExpr().isComplex()) { // System.out.println("\n--------- set Attribute (is // Complex) : "+fromVM.getName()+" = // "+fromVM.getExprAsText()); // VarMember toVM = vars.getVarMemberAt(to); // System.out.println("(to) VarMember : // "+toVM.getName()+" "+toVM); JexExpr oldExpr = (JexExpr) fromVM.getExpr(); // System.out.println("ast: "+oldExpr.getAST()); // System.out.println("Children of ast: // "+oldExpr.getAST().jjtGetNumChildren()); Vector<String> variables = new Vector<String>(); oldExpr.getAllVariables(variables); /* * System.out.println("Variables of ast: * "+variables.size()); for(int ii=0; ii<variables.size(); * ii++) { System.out.println("ast variable: * "+(String)variables.get(ii)); } */ findPrimaryAndReplace((SimpleNode) oldExpr.getAST(), from, to, vars); // System.out.println("------------------------------"); } } } } } private void findPrimaryAndReplace(SimpleNode node, String from, String to, VarTuple vars) { // System.out.println("Convert.findPrimaryAndChange: in "+node); for (int j = 0; j < node.jjtGetNumChildren(); j++) { SimpleNode n = (SimpleNode) node.jjtGetChild(j); // System.out.println(j+" Child of ast: "+n+" is "+n.getString()); if (n instanceof ASTPrimaryExpression) { // System.out.println("Convert.findPrimaryAndChange: // ASTPrimaryExpression: "+n+" NumChildren: "+ // n.jjtGetNumChildren()); for (int j1 = 0; j1 < n.jjtGetNumChildren(); j1++) { SimpleNode n1 = (SimpleNode) n.jjtGetChild(j1); // System.out.println("n1: "+n1); if (n1 instanceof ASTExpression) { // System.out.println("n1: // "+((ASTExpression)n1).getString()+" // "+n1.jjtGetNumChildren()+" "+n1.jjtGetChild(0)); findPrimaryAndReplace(n1, from, to, vars); } } // String ident = ((ASTPrimaryExpression) n).getIdentifier(); // System.out.println("Identifier: "+ ident+" "+ // ((ASTPrimaryExpression) n).getString()); if (n.getString().equals(from)) { // System.out.println("from is found: getString()= // "+n.getString()+" toString()= "+n.toString()+" // hasStringType()= "+n.hasStringType()+" getSymbolTable()= // "+n.getSymbolTable()); SymbolTable symbs = SimpleNode.getSymbolTable(); // System.out.println("SymbolTable: "+from+" type= // "+symbs.getType(from)+" expr= "+ symbs.getExpr(from)); // System.out.println("SymbolTable: "+to+" type= // "+symbs.getType(to)+" expr= "+ symbs.getExpr(to)); boolean to_found = false; ContextView context = (ContextView) symbs; VarTuple vt = (VarTuple) context.getVariables(); for (int i = 0; i < vt.getSize(); i++) { VarMember vm = vt.getVarMemberAt(i); // System.out.println(vm.getName()+" "+vm); if (vm.getName().equals(to)) { to_found = true; // System.out.println(to+" exists in SymbolTable :: // "+vm.getName()+" "+vm); HandlerType t = vm.getDeclaration().getType(); try { HandlerExpr expression = vm.getHandler() .newHandlerExpr(t, to); // System.out.println(expression.getAST()); SimpleNode test = (SimpleNode) expression .getAST().jjtGetChild(0); // System.out.println(test); node.replaceChild(n, test); // System.out.println("child replaced: // getString()= // "+node.jjtGetChild(0).getString()+" // "+node.jjtGetChild(0).toString()); } catch (AttrHandlerException ex) { } } } if (!to_found && (vars != null)) { // System.out.println("Something wrong: "+to+" NOT FOUND // in SymbolTable! Try to replace if variable exists in // VarTuple."); for (int i = 0; i < vars.getSize(); i++) { VarMember vm = vars.getVarMemberAt(i); // System.out.println(vm.getName()+" "+vm); if (vm.getName().equals(to)) { to_found = true; // System.out.println(to+" exists in vars // "+vm.getName()+" "+vm); HandlerType t = vm.getDeclaration().getType(); try { HandlerExpr expression = vm.getHandler() .newHandlerExpr(t, to); // System.out.println(expression.getAST()); SimpleNode test = (SimpleNode) expression .getAST().jjtGetChild(0); // System.out.println(test); node.replaceChild(n, test); // System.out.println("child replaced: // getString()= // "+node.jjtGetChild(0).getString()+" // "+node.jjtGetChild(0).toString()); } catch (AttrHandlerException ex) { } } } if (!to_found) { System.out.println("Something wrong again: " + to + " NOT FOUND! CANNOT replace."); } } } } else { // System.out.println("Take Child of ast: "+n); findPrimaryAndReplace(n, from, to, vars); } } } }