diff --git a/AlgebraicDataflowArchitectureModel/.settings/org.eclipse.jdt.core.prefs b/AlgebraicDataflowArchitectureModel/.settings/org.eclipse.jdt.core.prefs index 838bd9d..3fd6c25 100644 --- a/AlgebraicDataflowArchitectureModel/.settings/org.eclipse.jdt.core.prefs +++ b/AlgebraicDataflowArchitectureModel/.settings/org.eclipse.jdt.core.prefs @@ -1,11 +1,12 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.compliance=1.8 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.7 +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/AlgebraicDataflowArchitectureModel/models/Kinetics.model b/AlgebraicDataflowArchitectureModel/models/Kinetics.model new file mode 100644 index 0000000..4b446cb --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/Kinetics.model @@ -0,0 +1,20 @@ +channel CIO { + out force(f, push(x)) == x + out time(t, push(x)) == t + 0.01 +} + +channel C1 { + in force(f, update1(y, m)) == y + in mass(m, update1(y, m)) == m + out acceleration(a, update1(y, m)) == y / m +} + +channel C2 { + in acceleration(a, update2(z)) == z + out velocity(v, update2(z)) == v + 0.01 * z +} + +channel C3 { + in velocity(v, update3(v)) == u + out position(p, update3(v)) == p + 0.01 * v +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/models/POS.model b/AlgebraicDataflowArchitectureModel/models/POS.model new file mode 100644 index 0000000..9b13485 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/POS.model @@ -0,0 +1,18 @@ +channel CIO { + out payment(p, purchase(x)) == x +} + +channel C1 { + in payment(p, update1(y)) == y + out loyalty(l, update1(y)) == floor(y * 0.05) +} + +channel C2 { + in payment(p, update2(z)) == z + out history(h, update2(z)) == cons(z, h) +} + +channel C3 { + in history(h, update3(u)) == u + out total(t, update3(u)) == sum(u) +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/models/POS2.model b/AlgebraicDataflowArchitectureModel/models/POS2.model new file mode 100644 index 0000000..2756c96 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/POS2.model @@ -0,0 +1,18 @@ +channel CIO { + out payment(p, purchase(x)) == x +} + +channel C1 { + in payment(p1, update1(y)) == y + out loyalty(l, update1(y)) == floor(y * 0.05) +} + +channel C2 { + in payment(p1, update2(z)) == z + out history(h, update2(z)) == cons(z, h) +} + +channel C3 { + in history(h, update3(u)) == cons(u, h) + out total(t, update3(u)) == u + t +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Constant.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Constant.java new file mode 100644 index 0000000..690b9ec --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Constant.java @@ -0,0 +1,34 @@ +package models.algebra; + +import java.util.ArrayList; + +public class Constant extends Term { + + public Constant(String value) { + super(new Symbol(value, 0), new ArrayList()); + } + + public Constant(String value, Type type) { + super(new Symbol(value, 0), new ArrayList()); + symbol.setSignature(new Type[] {type}); + } + + public Constant(Symbol symbol) { + super(symbol); + } + + @Override + public boolean equals(Object another) { + if (!(another instanceof Constant)) return false; + return symbol.equals(((Constant) another).symbol); + } + + @Override + public Object clone() { + return new Constant(symbol); + } + + public String toString() { + return symbol.getName(); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Expression.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Expression.java new file mode 100644 index 0000000..9ba946c --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Expression.java @@ -0,0 +1,16 @@ +package models.algebra; + +import java.util.HashMap; + +public abstract class Expression implements Cloneable { + public abstract Expression getSubTerm(Position pos); + public abstract Expression unify(Expression another); + public abstract Expression getInverseMap(Expression outputValue, Position targetPos); + public abstract boolean contains(Expression exp); + public abstract Object clone(); + public abstract HashMap getSubTerms(Class clazz); + + public HashMap getVariables() { + return getSubTerms(Variable.class); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Field.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Field.java new file mode 100644 index 0000000..a95a1c4 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Field.java @@ -0,0 +1,41 @@ +package models.algebra; + +import java.util.ArrayList; + +/** + * A field in the implementation (regarded as a constant in the algebraic system) + * @author Nitta + * + */ +public class Field extends Constant { + + public Field(String name) { + super(name); + } + + public Field(String name, Type type) { + super(name, type); + } + + public Field(Symbol symbol) { + super(symbol); + } + + public Type getType() { + if (symbol.getSignature().length >= 1) { + return symbol.getSignature()[0]; + } + return null; + } + + @Override + public boolean equals(Object another) { + if (!(another instanceof Field)) return false; + return symbol.equals(((Field) another).symbol); + } + + @Override + public Object clone() { + return new Field(symbol); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/FutureWorkException.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/FutureWorkException.java new file mode 100644 index 0000000..ce01dc7 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/FutureWorkException.java @@ -0,0 +1,5 @@ +package models.algebra; + +public class FutureWorkException extends Exception { + +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/InvalidMessage.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/InvalidMessage.java new file mode 100644 index 0000000..c250f2f --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/InvalidMessage.java @@ -0,0 +1,5 @@ +package models.algebra; + +public class InvalidMessage extends Exception { + +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Parameter.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Parameter.java new file mode 100644 index 0000000..739ab80 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Parameter.java @@ -0,0 +1,39 @@ +package models.algebra; + +/** + * A parameter in the implementation (regarded as a constant in the algebraic system) + * @author Nitta + * + */ +public class Parameter extends Constant { + + public Parameter(String name) { + super(name); + } + + public Parameter(String name, Type type) { + super(name, type); + } + + public Parameter(Symbol symbol) { + super(symbol); + } + + public Type getType() { + if (symbol.getSignature().length >= 1) { + return symbol.getSignature()[0]; + } + return null; + } + + @Override + public boolean equals(Object another) { + if (!(another instanceof Parameter)) return false; + return symbol.equals(((Parameter) another).symbol); + } + + @Override + public Object clone() { + return new Parameter(symbol); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/ParameterizedIdentifierIsFutureWork.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/ParameterizedIdentifierIsFutureWork.java new file mode 100644 index 0000000..f37087b --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/ParameterizedIdentifierIsFutureWork.java @@ -0,0 +1,5 @@ +package models.algebra; + +public class ParameterizedIdentifierIsFutureWork extends FutureWorkException { + +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Position.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Position.java new file mode 100644 index 0000000..1708506 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Position.java @@ -0,0 +1,35 @@ +package models.algebra; + +import java.util.ArrayList; +import java.util.List; + +public class Position implements Cloneable { + private ArrayList orders = new ArrayList(); + + public Position() { + } + + public Position(ArrayList orders) { + this.orders = orders; + } + + public void addHeadOrder(int order) { + orders.add(0, order); + } + + public int removeHeadOrder() { + return orders.remove(0); + } + + public List getOrders() { + return orders; + } + + public boolean isEmpty() { + return (orders == null || orders.size() == 0); + } + + public Object clone() { + return new Position((ArrayList) orders.clone()); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Symbol.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Symbol.java new file mode 100644 index 0000000..0c9c9b8 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Symbol.java @@ -0,0 +1,81 @@ +package models.algebra; + +public class Symbol { + private String name; + private int arity = 0; + private Type operatorType = Type.PREFIX; + private Symbol[] inverses = null; + private models.algebra.Type[] signature = null; + + public Symbol(String name) { + this.name = name; + this.arity = 0; + } + + public Symbol(String name, int arity) { + this.name = name; + this.arity = arity; + } + + public Symbol(String name, int arity, Type operatorType) { + this.name = name; + this.arity = arity; + this.operatorType = operatorType; + } + + public void setArity(int arity) { + this.arity = arity; + } + + public int getArity() { + return arity; + } + + public String getName() { + return name; + } + + public boolean isInfix() { + return (operatorType == Type.INFIX); + } + + public boolean isMethod() { + return (operatorType == Type.METHOD); + } + + public Symbol[] getInverses() { + return inverses; + } + + public void setInverses(Symbol[] inverses) { + this.inverses = inverses; + } + + public models.algebra.Type[] getSignature() { + return signature; + } + + public void setSignature(models.algebra.Type[] signature) { + this.signature = signature; + } + + public boolean equals(Object another) { + if (!(another instanceof Symbol)) return false; + return name.equals(((Symbol) another).name) && arity == ((Symbol) another).arity; + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + public String toString() { + return name; + } + + public enum Type { + PREFIX, + INFIX, + METHOD + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java new file mode 100644 index 0000000..6a02785 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java @@ -0,0 +1,189 @@ +package models.algebra; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map.Entry; + +public class Term extends Expression { + protected Symbol symbol = null; + protected ArrayList children = new ArrayList<>(); + + public Term(Symbol symbol) { + super(); + this.symbol = symbol; + } + + public Term(Symbol symbol, ArrayList children) { + super(); + this.symbol = symbol; + this.children = children; + } + + public Symbol getSymbol() { + return symbol; + } + + public int getArity() { + return symbol.getArity(); + } + + public boolean addChild(Expression child) { + if (children.size() >= getArity()) return false; + children.add(child); + return true; + } + + public void addChild(Expression child, boolean bForced) { + if (!bForced && children.size() >= getArity()) return; + children.add(child); + } + + public Expression getChild(int n) { + return children.get(n); + } + + public HashMap getSubTerms(Class clazz) { + HashMap subTerms = new HashMap<>(); + if (clazz == this.getClass()) { + subTerms.put(new Position(), (T) this); + } + for (int i = 0; i < children.size(); i++) { + HashMap terms = children.get(i).getSubTerms(clazz); + for (Entry term: terms.entrySet()) { + Position pos = term.getKey(); + pos.addHeadOrder(i); + subTerms.put(pos, term.getValue()); + } + } + return subTerms; + } + + public Expression getSubTerm(Position pos) { + if (pos.isEmpty()) return this; + pos = (Position) pos.clone(); + int i = pos.removeHeadOrder(); + if (i >= children.size()) return null; + return children.get(i).getSubTerm(pos); + } + + public Term substitute(Variable variable, Expression value) { + Term newTerm = (Term) this.clone(); + HashMap variables = getVariables(); + for (Entry varEnt: variables.entrySet()) { + if (varEnt.getValue().equals(variable)) { + newTerm.replaceSubTerm(varEnt.getKey(), value); + } + } + return newTerm; + } + + public void replaceSubTerm(Position pos, Expression newSubTerm) { + if (pos.isEmpty()) return; + pos = (Position) pos.clone(); + int i = pos.removeHeadOrder(); + if (pos.isEmpty()) { + children.set(i, newSubTerm); + } else { + if (!(children.get(i) instanceof Term)) return; + ((Term) children.get(i)).replaceSubTerm(pos, newSubTerm); + } + } + + @Override + public Expression unify(Expression another) { + if (another instanceof Variable) return (Expression) this.clone(); + if (another instanceof Term) { + Term anotherTerm = (Term) another; + if (!symbol.equals(anotherTerm.symbol)) return null; + if (children.size() != anotherTerm.children.size()) return null; + Term unifiedTerm = new Term(symbol); + for (int i = 0; i < children.size(); i++) { + unifiedTerm.addChild(children.get(i).unify(anotherTerm.children.get(i))); + } + return unifiedTerm; + } else { + return null; + } + } + + @Override + public Expression getInverseMap(Expression outputValue, Position targetPos) { + if (targetPos.isEmpty()) return outputValue; + targetPos = (Position) targetPos.clone(); + int i = targetPos.removeHeadOrder(); + Symbol[] inverseSymbols = symbol.getInverses(); + if (inverseSymbols == null || i >= inverseSymbols.length || inverseSymbols[i] == null) return null; + Term inverseMap = new Term(inverseSymbols[i]); + inverseMap.addChild(outputValue); + for (int n = 0; n < inverseSymbols[i].getArity(); n++) { + if (n != i) { + inverseMap.addChild(children.get(n)); + } + } + return children.get(i).getInverseMap(inverseMap, targetPos); + } + + @Override + public boolean contains(Expression exp) { + if (equals(exp)) return true; + for (Expression e: children) { + if (e.contains(exp)) return true; + } + return false; + } + + @Override + public boolean equals(Object another) { + if (!(another instanceof Term)) return false; + if (this == another) return true; + Term anotherTerm = (Term) another; + if (!symbol.equals(anotherTerm.symbol)) return false; + if (children.size() != anotherTerm.children.size()) return false; + for (int i = 0; i < children.size(); i++) { + Expression e = children.get(i); + Expression e2 = anotherTerm.children.get(i); + if (!e.equals(e2)) return false; + } + return true; + } + + @Override + public int hashCode() { + return symbol.hashCode(); + } + + + @Override + public Object clone() { + Term newTerm = new Term(symbol); + for (Expression e: children) { + newTerm.addChild((Expression) e.clone()); + } + return newTerm; + } + + public String toString() { + if (getArity() == 2 && symbol.isInfix()) { + return "(" + children.get(0) + symbol.toString() + children.get(1) + ")"; + } + if (getArity() >= 1 && symbol.isMethod()) { + String exp = children.get(0).toString() + "." + symbol.toString() + "("; + String delimiter = ""; + for (int i = 1; i < children.size(); i++) { + Expression e = children.get(i); + exp += (delimiter + e.toString()); + delimiter = ","; + } + return exp + ")"; + } else { + String exp = symbol.toString() + "("; + String delimiter = ""; + for (Expression e: children) { + exp += (delimiter + e.toString()); + delimiter = ","; + } + return exp + ")"; + } + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Type.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Type.java new file mode 100644 index 0000000..53e4b2a --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Type.java @@ -0,0 +1,27 @@ +package models.algebra; + +public class Type { + private String typeName; + private String implementastionTypeName; + + public Type(String typeName, String implementastionTypeName) { + this.typeName = typeName; + this.implementastionTypeName = implementastionTypeName; + } + + public String getTypeName() { + return typeName; + } + + public void setTypeName(String typeName) { + this.typeName = typeName; + } + + public String getImplementastionTypeName() { + return implementastionTypeName; + } + + public void setImplementastionTypeName(String implementastionTypeName) { + this.implementastionTypeName = implementastionTypeName; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/UnificationFailed.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/UnificationFailed.java new file mode 100644 index 0000000..b0de344 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/UnificationFailed.java @@ -0,0 +1,5 @@ +package models.algebra; + +public class UnificationFailed extends Exception { + +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/ValueUndefined.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/ValueUndefined.java new file mode 100644 index 0000000..4c6de4c --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/ValueUndefined.java @@ -0,0 +1,5 @@ +package models.algebra; + +public class ValueUndefined extends Exception { + +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Variable.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Variable.java new file mode 100644 index 0000000..99ae839 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Variable.java @@ -0,0 +1,82 @@ +package models.algebra; + +import java.util.HashMap; + +public class Variable extends Expression { + private String name; + private Type type = null; + + public Variable(String name) { + super(); + this.name = name; + } + + public Variable(String name, Type type) { + super(); + this.name = name; + this.type = type; + } + + public String getName() { + return name; + } + + public Type getType() { + return type; + } + + public void setType(Type type) { + this.type = type; + } + + @Override + public HashMap getSubTerms(Class clazz) { + HashMap subTerms = new HashMap<>(); + if (clazz == this.getClass()) { + subTerms.put(new Position(), (T) this); + } + return subTerms; + } + + @Override + public Expression getSubTerm(Position pos) { + if (pos.isEmpty()) return this; + return null; + } + + @Override + public Expression unify(Expression another) { + return (Expression) another.clone(); + } + + @Override + public Expression getInverseMap(Expression outputValue, Position targetPos) { + if (targetPos.isEmpty()) return outputValue; + return null; + } + + @Override + public boolean contains(Expression exp) { + return equals(exp); + } + + @Override + public boolean equals(Object another) { + if (!(another instanceof Variable)) return false; + return name.equals(((Variable) another).name); + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public Object clone() { + return new Variable(name, type); + } + + public String toString() { + return name; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ChannelGenerator.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ChannelGenerator.java index ba04f70..8105369 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ChannelGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ChannelGenerator.java @@ -4,14 +4,20 @@ import java.util.Set; public class ChannelGenerator { + protected String channelName; protected Set groupSelectors = null; protected Set channelSelectors = null; protected Set channelMembers = null; - public ChannelGenerator() { + public ChannelGenerator(String channelName) { + this.channelName = channelName; groupSelectors = new HashSet<>(); channelSelectors = new HashSet<>(); channelMembers = new HashSet<>(); + } + + public String getChannelName() { + return channelName; } public Set getGroupSelectors() { diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ChannelMember.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ChannelMember.java index 91c573d..d862851 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ChannelMember.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ChannelMember.java @@ -42,4 +42,12 @@ public void setStateTransition(StateTransition stateTransition) { this.stateTransition = stateTransition; } + + @Override + public String toString() { + return identifierTemplate.getResourceName() + "(" + + stateTransition.getCurStateExpression() + "," + + stateTransition.getMessageExpression() + ")" + + " == " + stateTransition.getNextStateExpression(); + } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java index 24b264b..411eb5e 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java @@ -1,57 +1,133 @@ package models.dataConstraintModel; +import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.Set; +import models.algebra.Symbol; +import models.algebra.Type; +import parser.Parser; + public class DataConstraintModel { - protected Set identifierTemplates = null; - protected Set channelGenerators = null; - protected Set ioChannelGenerators = null; + protected HashMap identifierTemplates = null; + protected HashMap channelGenerators = null; + protected HashMap ioChannelGenerators = null; + protected HashMap symbols = null; + public static final Symbol add = new Symbol(Parser.ADD, 2, Symbol.Type.INFIX); + public static final Symbol mul = new Symbol(Parser.MUL, 2, Symbol.Type.INFIX);; + public static final Symbol sub = new Symbol(Parser.SUB, 2, Symbol.Type.INFIX); + public static final Symbol div = new Symbol(Parser.DIV, 2, Symbol.Type.INFIX); + public static final Symbol minus = new Symbol(Parser.MINUS, 1); + public static final Symbol cons = new Symbol("cons", 2); + public static final Symbol head = new Symbol("head", 1); + public static final Symbol body = new Symbol("body", 1); + public static final Type typeInt = new Type("Int", "int"); + public static final Type typeFloat = new Type("Float", "float"); + public static final Type typeDouble = new Type("Double", "double"); + public static final Type typeList = new Type("List", "List"); + + static { + add.setInverses(new Symbol[] {sub, sub}); + mul.setInverses(new Symbol[] {div, div}); + sub.setInverses(new Symbol[] {add}); + div.setInverses(new Symbol[] {mul}); + minus.setInverses(new Symbol[] {minus}); + cons.setInverses(new Symbol[] {head, body}); + } public DataConstraintModel() { - identifierTemplates = new HashSet<>(); - channelGenerators = new HashSet<>(); - ioChannelGenerators = new HashSet<>(); + identifierTemplates = new HashMap<>(); + channelGenerators = new HashMap<>(); + ioChannelGenerators = new HashMap<>(); + symbols = new HashMap<>(); + addSymbol(add); + addSymbol(mul); + addSymbol(sub); + addSymbol(div); + addSymbol(minus); + addSymbol(cons); + addSymbol(head); + addSymbol(body); } - public Set getIdentifierTemplates() { - return identifierTemplates; + public Collection getIdentifierTemplates() { + return identifierTemplates.values(); } - public void setIdentifierTemplates(Set identifierTemplates) { + public IdentifierTemplate getIdentifierTemplate(String resourceName) { + return identifierTemplates.get(resourceName); + } + + public void addIdentifierTemplates(IdentifierTemplate identifierTemplate) { + identifierTemplates.put(identifierTemplate.getResourceName(), identifierTemplate); + } + + public void setIdentifierTemplates(HashMap identifierTemplates) { this.identifierTemplates = identifierTemplates; } - public Set getChannelGenerators() { - return channelGenerators; + public Collection getChannelGenerators() { + return channelGenerators.values(); + } + + public ChannelGenerator getChannelGenerator(String channelName) { + return channelGenerators.get(channelName); } - public void setChannelGenerators(Set channelGenerators) { + public void setChannelGenerators(HashMap channelGenerators) { this.channelGenerators = channelGenerators; - for (ChannelGenerator g: channelGenerators) { - identifierTemplates.addAll(g.getIdentifierTemplates()); - + for (ChannelGenerator g: channelGenerators.values()) { + for (IdentifierTemplate id: g.getIdentifierTemplates()) { + identifierTemplates.put(id.getResourceName(), id); + } } } public void addChannelGenerator(ChannelGenerator channelGenerator) { - channelGenerators.add(channelGenerator); - identifierTemplates.addAll(channelGenerator.getIdentifierTemplates()); + channelGenerators.put(channelGenerator.getChannelName(), channelGenerator); + for (IdentifierTemplate id: channelGenerator.getIdentifierTemplates()) { + identifierTemplates.put(id.getResourceName(), id); + } } - public Set getIOChannelGenerators() { - return ioChannelGenerators; + public Collection getIOChannelGenerators() { + return ioChannelGenerators.values(); } - public void setIOChannelGenerators(Set ioChannelGenerators) { + public void setIOChannelGenerators(HashMap ioChannelGenerators) { this.ioChannelGenerators = ioChannelGenerators; - for (ChannelGenerator g: ioChannelGenerators) { - identifierTemplates.addAll(g.getIdentifierTemplates()); + for (ChannelGenerator g: ioChannelGenerators.values()) { + for (IdentifierTemplate id: g.getIdentifierTemplates()) { + identifierTemplates.put(id.getResourceName(), id); + } } } public void addIOChannelGenerator(ChannelGenerator ioChannelGenerator) { - ioChannelGenerators.add(ioChannelGenerator); - identifierTemplates.addAll(ioChannelGenerator.getIdentifierTemplates()); + ioChannelGenerators.put(ioChannelGenerator.getChannelName(), ioChannelGenerator); + for (IdentifierTemplate id: ioChannelGenerator.getIdentifierTemplates()) { + identifierTemplates.put(id.getResourceName(), id); + } + } + + public void addSymbol(Symbol symbol) { + symbols.put(symbol.getName(), symbol); + } + + public Symbol getSymbol(String name) { + return symbols.get(name); + } + + @Override + public String toString() { + String out = ""; + for (ChannelGenerator channelGenerator: ioChannelGenerators.values()) { + out += channelGenerator.toString(); + } + for (ChannelGenerator channelGenerator: channelGenerators.values()) { + out += channelGenerator.toString(); + } + return out; } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/Expression.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/Expression.java deleted file mode 100644 index fdbf8ed..0000000 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/Expression.java +++ /dev/null @@ -1,7 +0,0 @@ -package models.dataConstraintModel; - -public class Expression { - public boolean contains(Expression exp) { - return false; - } -} diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/IdentifierTemplate.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/IdentifierTemplate.java index 9658a11..0ea7b6a 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/IdentifierTemplate.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/IdentifierTemplate.java @@ -1,13 +1,36 @@ package models.dataConstraintModel; +import models.algebra.Type; + public class IdentifierTemplate { - int numParameters = 0; + private String resourceName = null; + private Type resourceStateType = null; + private int numParameters = 0; - public IdentifierTemplate(int numParameters) { + public IdentifierTemplate(String resourceName, int numParameters) { + this.resourceName = resourceName; this.numParameters =numParameters; } + + public IdentifierTemplate(String resourceName, Type resourceStateType, int numParameters) { + this.resourceName = resourceName; + this.resourceStateType = resourceStateType; + this.numParameters = numParameters; + } + + public String getResourceName() { + return resourceName; + } public int getNumberOfParameters() { return numParameters; } + + public Type getResourceStateType() { + return resourceStateType; + } + + public void setResourceStateType(Type resourceStateType) { + this.resourceStateType = resourceStateType; + } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/StateTransition.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/StateTransition.java index 6fa8529..2bfb09b 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/StateTransition.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/StateTransition.java @@ -1,8 +1,21 @@ package models.dataConstraintModel; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map.Entry; + +import models.algebra.Expression; +import models.algebra.InvalidMessage; +import models.algebra.Position; +import models.algebra.Term; +import models.algebra.ValueUndefined; +import models.algebra.Variable; +import models.dataFlowModel.ResolvingMultipleDefinitionIsFutureWork; + public class StateTransition { private Expression curStateExpression = null; private Expression nextStateExpression = null; + private Expression messageExpression = null; public Expression getCurStateExpression() { return curStateExpression; @@ -19,4 +32,112 @@ public void setNextStateExpression(Expression nextStateExpression) { this.nextStateExpression = nextStateExpression; } + + public Expression getMessageExpression() { + return messageExpression; + } + + public void setMessageExpression(Expression messageExpression) { + this.messageExpression = messageExpression; + } + + public Expression deriveMessageConstraintFor(Expression curStateValue, Expression nextStateValue) throws InvalidMessage, ResolvingMultipleDefinitionIsFutureWork { + HashMap> bindings = new HashMap<>(); + + Expression curStateTerm = getCurStateExpression(); + HashMap curStateVars = curStateTerm.getVariables(); + for (Entry curStateVarEnt: curStateVars.entrySet()) { + Variable var = curStateVarEnt.getValue(); + Position varPos = curStateVarEnt.getKey(); + Expression valueCalc = curStateTerm.getInverseMap(curStateValue, varPos); + if (valueCalc != null) { + ArrayList values = bindings.get(var); + if (values == null) { + values = new ArrayList(); + bindings.put(var, values); + } + values.add(valueCalc); + } + } + + Expression nextStateTerm = (Expression) getNextStateExpression().clone(); + for (Variable var: bindings.keySet()) { + HashMap vars2 = nextStateTerm.getVariables(); + for (Variable var2: vars2.values()) { + if (var.equals(var2) && bindings.get(var).size() == 1) { + if (nextStateTerm instanceof Term) { + nextStateTerm = ((Term) nextStateTerm).substitute(var, bindings.get(var).get(0)); + } else if (nextStateTerm instanceof Variable && nextStateTerm.equals(var)) { + nextStateTerm = bindings.get(var).get(0); + } + } + } + } + + HashMap nextStateVars = nextStateTerm.getVariables(); + for (Entry nextStateVarEnt: nextStateVars.entrySet()) { + Variable var = nextStateVarEnt.getValue(); + Position varPos = nextStateVarEnt.getKey(); + Expression valueCalc = nextStateTerm.getInverseMap(nextStateValue, varPos); + if (valueCalc != null) { + ArrayList values = bindings.get(var); + if (values == null) { + values = new ArrayList(); + bindings.put(var, values); + } + values.add(valueCalc); + } + } + + Expression messageTerm = getMessageExpression(); + if (!(messageTerm instanceof Term)) throw new InvalidMessage(); + HashMap messageVars = messageTerm.getVariables(); + for (Variable var: messageVars.values()) { + if (bindings.get(var) != null) { + if (bindings.get(var).size() > 1) throw new ResolvingMultipleDefinitionIsFutureWork(); + messageTerm = ((Term) messageTerm).substitute(var, bindings.get(var).iterator().next()); + } + } + return messageTerm; + } + + public Expression deriveNextStateExpressionFor(Expression curStateValue, Term concreteMessage) + throws ResolvingMultipleDefinitionIsFutureWork, ValueUndefined { + HashMap bindings = new HashMap<>(); + + Expression curStateTerm = getCurStateExpression(); + HashMap curStateVars = curStateTerm.getVariables(); + for (Entry curStateVarEnt: curStateVars.entrySet()) { + Variable var = curStateVarEnt.getValue(); + Position varPos = curStateVarEnt.getKey(); + Expression valueCalc = curStateTerm.getInverseMap(curStateValue, varPos); + if (valueCalc != null) { + if (bindings.get(var) != null) throw new ResolvingMultipleDefinitionIsFutureWork(); + bindings.put(var, valueCalc); + } + } + + Expression messageTerm = getMessageExpression(); + HashMap messageVars = messageTerm.getVariables(); + for (Entry messageVarEnt: messageVars.entrySet()) { + Variable var = messageVarEnt.getValue(); + Position varPos = messageVarEnt.getKey(); + Expression valueCalc = concreteMessage.getSubTerm(varPos); + if (valueCalc != null) { + if (bindings.get(var) != null) throw new ResolvingMultipleDefinitionIsFutureWork(); + bindings.put(var, valueCalc); + } + } + + Expression nextStateTerm = getNextStateExpression(); + if (nextStateTerm instanceof Variable) { + nextStateTerm = bindings.get((Variable) nextStateTerm); + if (nextStateTerm == null) throw new ValueUndefined(); + } else { + for (Variable var: bindings.keySet()) { + nextStateTerm = ((Term) nextStateTerm).substitute(var, bindings.get(var)); + } + } + return nextStateTerm; + } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataFlowModel.java b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataFlowModel.java index 1d56e40..75f00d8 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataFlowModel.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataFlowModel.java @@ -9,7 +9,7 @@ public class DataFlowModel extends DataConstraintModel { public ResourceDependencyGraph getResourceDependencyGraph() { ResourceDependencyGraph resourceDependencyGraph = new ResourceDependencyGraph(); - for (ChannelGenerator channelGen: channelGenerators) { + for (ChannelGenerator channelGen: getChannelGenerators()) { DataflowChannelGenerator dfChannelGen = (DataflowChannelGenerator)channelGen; Set inputResources = dfChannelGen.getInputIdentifierTemplates(); Set outputResources = dfChannelGen.getOutputIdentifierTemplates(); diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataflowChannelGenerator.java b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataflowChannelGenerator.java index 5058708..42fc9ac 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataflowChannelGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataflowChannelGenerator.java @@ -1,15 +1,24 @@ package models.dataFlowModel; +import java.util.HashMap; import java.util.HashSet; import java.util.Set; +import models.algebra.Expression; +import models.algebra.InvalidMessage; +import models.algebra.Parameter; +import models.algebra.ParameterizedIdentifierIsFutureWork; +import models.algebra.Term; +import models.algebra.UnificationFailed; +import models.algebra.ValueUndefined; import models.dataConstraintModel.*; public class DataflowChannelGenerator extends ChannelGenerator { protected Set inputChannelMembers = null; protected Set outputChannelMembers = null; - public DataflowChannelGenerator() { + public DataflowChannelGenerator(String channelName) { + super(channelName); inputChannelMembers = new HashSet<>(); outputChannelMembers = new HashSet<>(); } @@ -63,4 +72,91 @@ } return outputIdentifierTemplates; } + + public Expression deriveUpdateExpressionOf(ChannelMember targetMember) throws ParameterizedIdentifierIsFutureWork, ResolvingMultipleDefinitionIsFutureWork, InvalidMessage, UnificationFailed, ValueUndefined { + IResourceStateAccessor defaultStateAccessor = new IResourceStateAccessor() { + HashMap curStateParams = new HashMap<>(); + HashMap nextStateParams = new HashMap<>(); + + @Override + public Expression getCurrentStateAccessorFor(IdentifierTemplate target, IdentifierTemplate from) { + String resource = target.getResourceName(); + Parameter curStateParam = curStateParams.get(resource); + if (curStateParam == null) { + curStateParam = new Parameter("cur" + resource); + curStateParams.put(resource, curStateParam); + } + return curStateParam; + } + + @Override + public Expression getNextStateAccessorFor(IdentifierTemplate target, IdentifierTemplate from) { + String resource = target.getResourceName(); + Parameter nextStateParam = nextStateParams.get(resource); + if (nextStateParam == null) { + nextStateParam = new Parameter("next" + resource); + nextStateParams.put(resource, nextStateParam); + } + return nextStateParam; + } + }; + return deriveUpdateExpressionOf(targetMember, defaultStateAccessor); + } + + public Expression deriveUpdateExpressionOf(ChannelMember targetMember, IResourceStateAccessor stateAccessor) + throws ParameterizedIdentifierIsFutureWork, ResolvingMultipleDefinitionIsFutureWork, InvalidMessage, UnificationFailed, ValueUndefined { + if (!getOutputChannelMembers().contains(targetMember)) return null; + HashSet messageConstraints = new HashSet<>(); + + // Calculate message constraints from input state transitions + for (ChannelMember inputMember: getInputChannelMembers()) { + IdentifierTemplate inputIdentifier = inputMember.getIdentifierTemplate(); + if (inputIdentifier.getNumberOfParameters() > 0) { + throw new ParameterizedIdentifierIsFutureWork(); + } + Expression curInputStateAccessor = stateAccessor.getCurrentStateAccessorFor(inputIdentifier, targetMember.getIdentifierTemplate()); + Expression nextInputStateAccessor = stateAccessor.getNextStateAccessorFor(inputIdentifier, targetMember.getIdentifierTemplate()); + Expression messageConstraintByInput = inputMember.getStateTransition().deriveMessageConstraintFor(curInputStateAccessor, nextInputStateAccessor); + messageConstraints.add((Term) messageConstraintByInput); + } + + // Unify message constaints + Term unifiedMessage = null; + for (Term messageContraint: messageConstraints) { + if (unifiedMessage == null) { + unifiedMessage = messageContraint; + } else { + unifiedMessage = (Term) unifiedMessage.unify(messageContraint); + if (unifiedMessage == null) { + throw new UnificationFailed(); + } + } + } + + // Calculate the next state of target resource from the unified message and the current resource state + IdentifierTemplate targetIdentifier = targetMember.getIdentifierTemplate(); + if (targetIdentifier.getNumberOfParameters() > 0) { + throw new ParameterizedIdentifierIsFutureWork(); + } + Expression curOutputStateAccessor = stateAccessor.getCurrentStateAccessorFor(targetIdentifier, targetIdentifier); + return targetMember.getStateTransition().deriveNextStateExpressionFor(curOutputStateAccessor, unifiedMessage); + } + + @Override + public String toString() { + String channelSource = "channel " + getChannelName() + " {\n"; + for (ChannelMember inputMember: inputChannelMembers) { + channelSource += "\t in " + inputMember + "\n"; + } + for (ChannelMember outputMember: outputChannelMembers) { + channelSource += "\t out " + outputMember + "\n"; + } + channelSource += "}\n"; + return channelSource; + } + + public interface IResourceStateAccessor { + Expression getCurrentStateAccessorFor(IdentifierTemplate target, IdentifierTemplate from); + Expression getNextStateAccessorFor(IdentifierTemplate target, IdentifierTemplate from); + } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ResolvingMultipleDefinitionIsFutureWork.java b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ResolvingMultipleDefinitionIsFutureWork.java new file mode 100644 index 0000000..9444ee3 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ResolvingMultipleDefinitionIsFutureWork.java @@ -0,0 +1,7 @@ +package models.dataFlowModel; + +import models.algebra.FutureWorkException; + +public class ResolvingMultipleDefinitionIsFutureWork extends FutureWorkException { + +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ResourceDependency.java b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ResourceDependency.java index 63adf94..8a3bed5 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ResourceDependency.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ResourceDependency.java @@ -13,4 +13,8 @@ public DataflowChannelGenerator getChannelGenerator() { return channelGenerator; } + + public String toString() { + return channelGenerator.getChannelName(); + } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ResourceNode.java b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ResourceNode.java index 4097971..698eac3 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ResourceNode.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ResourceNode.java @@ -19,4 +19,12 @@ if (!(another instanceof ResourceNode)) return false; return identifierTemplate.equals(((ResourceNode)another).identifierTemplate); } + + public int hashCode() { + return identifierTemplate.hashCode(); + } + + public String toString() { + return identifierTemplate.getResourceName(); + } } diff --git a/AlgebraicDataflowArchitectureModel/src/parser/ExpectedChannel.java b/AlgebraicDataflowArchitectureModel/src/parser/ExpectedChannel.java new file mode 100644 index 0000000..e80a4b8 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/parser/ExpectedChannel.java @@ -0,0 +1,9 @@ +package parser; + +public class ExpectedChannel extends ParseException { + + public ExpectedChannel(int line) { + super(line); + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/parser/ExpectedChannelName.java b/AlgebraicDataflowArchitectureModel/src/parser/ExpectedChannelName.java new file mode 100644 index 0000000..e802150 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/parser/ExpectedChannelName.java @@ -0,0 +1,9 @@ +package parser; + +public class ExpectedChannelName extends ParseException { + + public ExpectedChannelName(int line) { + super(line); + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/parser/ExpectedEquals.java b/AlgebraicDataflowArchitectureModel/src/parser/ExpectedEquals.java new file mode 100644 index 0000000..89640fd --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/parser/ExpectedEquals.java @@ -0,0 +1,9 @@ +package parser; + +public class ExpectedEquals extends ParseException { + + public ExpectedEquals(int line) { + super(line); + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/parser/ExpectedInOrOutKeyword.java b/AlgebraicDataflowArchitectureModel/src/parser/ExpectedInOrOutKeyword.java new file mode 100644 index 0000000..7bd81de --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/parser/ExpectedInOrOutKeyword.java @@ -0,0 +1,9 @@ +package parser; + +public class ExpectedInOrOutKeyword extends ParseException { + + public ExpectedInOrOutKeyword(int line) { + super(line); + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/parser/ExpectedLeftCurlyBracket.java b/AlgebraicDataflowArchitectureModel/src/parser/ExpectedLeftCurlyBracket.java new file mode 100644 index 0000000..7f14ae0 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/parser/ExpectedLeftCurlyBracket.java @@ -0,0 +1,9 @@ +package parser; + +public class ExpectedLeftCurlyBracket extends ParseException { + + public ExpectedLeftCurlyBracket(int line) { + super(line); + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/parser/ExpectedRHSExpression.java b/AlgebraicDataflowArchitectureModel/src/parser/ExpectedRHSExpression.java new file mode 100644 index 0000000..2f315a5 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/parser/ExpectedRHSExpression.java @@ -0,0 +1,9 @@ +package parser; + +public class ExpectedRHSExpression extends ParseException { + + public ExpectedRHSExpression(int line) { + super(line); + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/parser/ExpectedRightBracket.java b/AlgebraicDataflowArchitectureModel/src/parser/ExpectedRightBracket.java new file mode 100644 index 0000000..34ac65b --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/parser/ExpectedRightBracket.java @@ -0,0 +1,9 @@ +package parser; + +public class ExpectedRightBracket extends ParseException { + + public ExpectedRightBracket(int line) { + super(line); + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/parser/ExpectedStateTransition.java b/AlgebraicDataflowArchitectureModel/src/parser/ExpectedStateTransition.java new file mode 100644 index 0000000..0a50c12 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/parser/ExpectedStateTransition.java @@ -0,0 +1,9 @@ +package parser; + +public class ExpectedStateTransition extends ParseException { + + public ExpectedStateTransition(int line) { + super(line); + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/parser/ParseException.java b/AlgebraicDataflowArchitectureModel/src/parser/ParseException.java new file mode 100644 index 0000000..c9dcf30 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/parser/ParseException.java @@ -0,0 +1,10 @@ +package parser; + +public class ParseException extends Exception { + protected int line; + + public ParseException(int line) { + super("at line " + (line + 1)); + this.line = line; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/parser/Parser.java b/AlgebraicDataflowArchitectureModel/src/parser/Parser.java new file mode 100644 index 0000000..8df86b4 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/parser/Parser.java @@ -0,0 +1,354 @@ +package parser; + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.Symbol; +import models.algebra.Term; +import models.algebra.Variable; +import models.dataConstraintModel.ChannelMember; +import models.dataConstraintModel.IdentifierTemplate; +import models.dataConstraintModel.StateTransition; +import models.dataFlowModel.DataFlowModel; +import models.dataFlowModel.DataflowChannelGenerator; + +public class Parser { + private BufferedReader reader; + public static final String CHANNEL = "channel"; + public static final String LEFT_CURLY_BRACKET = "{"; + public static final String RIGHT_CURLY_BRACKET = "}"; + public static final String LEFT_CURLY_BRACKET_REGX = "\\{"; + public static final String RIGHT_CURLY_BRACKET_REGX = "\\}"; + public static final String LEFT_BRACKET = "("; + public static final String RIGHT_BRACKET = ")"; + public static final String LEFT_BRACKET_REGX = "\\("; + public static final String RIGHT_BRACKET_REGX = "\\)"; + public static final String ADD = "+"; + public static final String MUL = "*"; + public static final String SUB = "-"; + public static final String DIV = "/"; + public static final String MINUS = "-"; + public static final String ADD_REGX = "\\+"; + public static final String MUL_REGX = "\\*"; + public static final String SUB_REGX = "\\-"; + public static final String DIV_REGX = "/"; + public static final String IN = "in"; + public static final String OUT = "out"; + public static final String EQUALS = "=="; + public static final String COMMA = ","; + + public Parser(BufferedReader reader) { + this.reader = reader; + } + + public DataFlowModel doParse() + throws ExpectedRightBracket, ExpectedChannel, ExpectedChannelName, ExpectedLeftCurlyBracket, ExpectedInOrOutKeyword, ExpectedStateTransition, ExpectedEquals, ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression { + TokenStream stream = new TokenStream(); + try { + String line; + while ((line = reader.readLine()) != null) { + stream.addLine(line); + } + reader.close(); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + + return parseDataFlowModel(stream); + } + + public static DataFlowModel parseDataFlowModel(TokenStream stream) + throws ExpectedRightBracket, ExpectedChannel, ExpectedChannelName, ExpectedLeftCurlyBracket, ExpectedInOrOutKeyword, ExpectedStateTransition, ExpectedEquals, ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression { + DataFlowModel model = new DataFlowModel(); + DataflowChannelGenerator channel; + while ((channel = parseChannel(stream, model)) != null) { + if (channel.getInputChannelMembers().size() == 0) { + model.addIOChannelGenerator(channel); + } else { + model.addChannelGenerator(channel); + } + } + return model; + } + + public static DataflowChannelGenerator parseChannel(TokenStream stream, DataFlowModel model) + throws ExpectedRightBracket, ExpectedChannel, ExpectedChannelName, ExpectedLeftCurlyBracket, ExpectedInOrOutKeyword, ExpectedStateTransition, ExpectedEquals, ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression { + if (!stream.hasNext()) return null; + String channelKeyword = stream.next(); + if (!channelKeyword.equals(CHANNEL)) throw new ExpectedChannel(stream.getLine()); + if (!stream.hasNext()) throw new ExpectedChannelName(stream.getLine()); + String channelName = stream.next(); + if (channelName.equals(LEFT_CURLY_BRACKET)) throw new ExpectedChannelName(stream.getLine()); + + DataflowChannelGenerator channel = new DataflowChannelGenerator(channelName); + String leftBracket = stream.next(); + if (!leftBracket.equals(LEFT_CURLY_BRACKET)) throw new ExpectedLeftCurlyBracket(stream.getLine()); + String inOrOut = null; + while (stream.hasNext() && !(inOrOut = stream.next()).equals(RIGHT_CURLY_BRACKET)) { + ChannelMember channelMember = null; + if (inOrOut.equals(IN)) { + channelMember = parseChannelMember(stream, model); + if (channelMember != null) { + channel.addChannelMemberAsInput(channelMember); + } + } else if (inOrOut.equals(OUT)) { + channelMember = parseChannelMember(stream, model); + if (channelMember != null) { + channel.addChannelMemberAsOutput(channelMember); + } + } else { + throw new ExpectedInOrOutKeyword(stream.getLine()); + } + } + return channel; + } + + public static ChannelMember parseChannelMember(TokenStream stream, DataFlowModel model) + throws ExpectedRightBracket, ExpectedStateTransition, ExpectedEquals, ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression { + if (!stream.hasNext()) throw new ExpectedStateTransition(stream.getLine()); + Expression leftTerm = parseTerm(stream, model); + if (leftTerm == null || !(leftTerm instanceof Term)) throw new WrongLHSExpression(stream.getLine()); + + if (!stream.hasNext()) throw new ExpectedEquals(stream.getLine()); + String equals = stream.next(); + if (!equals.equals(EQUALS)) throw new ExpectedEquals(stream.getLine()); + + if (!stream.hasNext()) throw new ExpectedRHSExpression(stream.getLine()); + Expression rightTerm = parseTerm(stream, model); + if (rightTerm == null) throw new WrongRHSExpression(stream.getLine()); + + String resourceName = ((Term) leftTerm).getSymbol().getName(); + IdentifierTemplate identifier = model.getIdentifierTemplate(resourceName); + if (identifier == null) { + identifier = new IdentifierTemplate(resourceName, 0); + model.addIdentifierTemplates(identifier); + } + ChannelMember channelMember = new ChannelMember(identifier); + StateTransition stateTransition = new StateTransition(); + stateTransition.setCurStateExpression(((Term) leftTerm).getChild(0)); + stateTransition.setMessageExpression(((Term) leftTerm).getChild(1)); + stateTransition.setNextStateExpression(rightTerm); + channelMember.setStateTransition(stateTransition); + return channelMember; + } + + public static Expression parseTerm(TokenStream stream, DataFlowModel model) throws ExpectedRightBracket { + ArrayList expressions = new ArrayList<>(); + ArrayList operators = new ArrayList<>(); + String operator = null; + for (;;) { + String leftBracketOrMinus = stream.next(); + if (leftBracketOrMinus.equals(LEFT_BRACKET)) { + Expression exp = parseTerm(stream, model); + String rightBracket = stream.next(); + if (!rightBracket.equals(RIGHT_BRACKET)) throw new ExpectedRightBracket(stream.getLine()); + expressions.add(exp); + } else { + Symbol minus = null; + String symbolName = null; + if (leftBracketOrMinus.equals(MINUS)) { + minus = DataFlowModel.minus; // not sub + symbolName = stream.next(); + } else { + symbolName = leftBracketOrMinus; + } + Expression exp = null; + if (stream.checkNext() != null && stream.checkNext().equals(LEFT_BRACKET)) { + Symbol symbol = model.getSymbol(symbolName); + if (symbol == null) { + symbol = new Symbol(symbolName); + model.addSymbol(symbol); + } + Term term = new Term(symbol); + int arity = 0; + do { + stream.next(); // LEFT_BRACKET or COMMA + arity++; + Expression subTerm = parseTerm(stream, model); + term.addChild(subTerm, true); + if (!stream.hasNext()) throw new ExpectedRightBracket(stream.getLine()); + } while (stream.checkNext().equals(COMMA)); + String rightBracket = stream.next(); + if (!rightBracket.equals(RIGHT_BRACKET)) throw new ExpectedRightBracket(stream.getLine()); + symbol.setArity(arity); + exp = term; + } else { + try { + Double d = Double.parseDouble(symbolName); + exp = new Constant(symbolName); + } catch (NumberFormatException e) { + exp = new Variable(symbolName); + } + } + if (minus != null) { + Term minusTerm = new Term(minus); + minusTerm.addChild(exp); + expressions.add(minusTerm); + } else { + expressions.add(exp); + } + } + operator = stream.checkNext(); + if (operator == null) { + break; + } else if (operator.equals(ADD)) { + operators.add(DataFlowModel.add); + } else if (operator.equals(MUL)) { + operators.add(DataFlowModel.mul); + } else if (operator.equals(SUB)) { + operators.add(DataFlowModel.sub); // not minus + } else if (operator.equals(DIV)) { + operators.add(DataFlowModel.div); + } else { + break; + } + stream.next(); // an arithmetic operator + } + if (expressions.size() == 1) { + // no arithmetic operators + return expressions.get(0); + } + ArrayList monomials = new ArrayList<>(); + ArrayList addSubs = new ArrayList<>(); + Expression first = expressions.get(0); + int i = 1; + for (Symbol op: operators) { + Expression second = expressions.get(i); + if (op.getName().equals(MUL) || op.getName().equals(DIV)) { + Term term = new Term(op); + term.addChild(first); + term.addChild(second); + first = term; + } else { + // add or sub ==> new monomial + monomials.add(first); + addSubs.add(op); + first = second; + } + i++; + } + if (first != null) monomials.add(first); + Expression firstMonomial = monomials.get(0); + i = 1; + for (Symbol op: addSubs) { + Expression secondMonomial = monomials.get(i); + Term term = new Term(op); + term.addChild(firstMonomial); + term.addChild(secondMonomial); + firstMonomial = term; + i++; + } + return firstMonomial; + } + + public static class TokenStream { + private ArrayList> tokens = new ArrayList<>(); + private int line = 0; + private int n = 0; + + public TokenStream() { + line = 0; + n = 0; + } + + public void addLine(String line) { + line = line.trim(); + tokens.add( + splitBy( + splitBy( + splitBy( + splitBy( + splitBy( + splitBy( + splitBy( + splitBy( + splitBy( + splitBy( + Arrays.asList(line.split("[ \t]")), + ADD, + ADD_REGX), + MUL, + MUL_REGX), + SUB, + SUB_REGX), + DIV, + DIV_REGX), + COMMA, + COMMA), + LEFT_BRACKET, + LEFT_BRACKET_REGX), + RIGHT_BRACKET, + RIGHT_BRACKET_REGX), + EQUALS, + EQUALS), + LEFT_CURLY_BRACKET, + LEFT_CURLY_BRACKET_REGX), + RIGHT_CURLY_BRACKET, + RIGHT_CURLY_BRACKET_REGX)); + } + + private ArrayList splitBy(List tokens, String delimiter, String delimiterRegx) { + ArrayList newTokens = new ArrayList<>(); + for (String token: tokens) { + String[] splitTokens = token.split(delimiterRegx); + boolean fFirstToken = true; + for (String t: splitTokens) { + if (!fFirstToken) { + newTokens.add(delimiter); + } + if (t.length() > 0) { + newTokens.add(t); + } + fFirstToken = false; + } + while (token.endsWith(delimiter)) { + newTokens.add(delimiter); + token = token.substring(0, token.length() - 1); + } + } + return newTokens; + } + + public String next() { + if (line >= tokens.size()) return null; + while (n >= tokens.get(line).size()) { + line++; + n = 0; + if (line >= tokens.size()) return null; + } + String token = tokens.get(line).get(n); + n++; + return token; + } + + public String checkNext() { + if (line >= tokens.size()) return null; + while (n >= tokens.get(line).size()) { + line++; + n = 0; + if (line >= tokens.size()) return null; + } + return tokens.get(line).get(n); + } + + public boolean hasNext() { + if (line >= tokens.size()) return false; + while (n >= tokens.get(line).size()) { + line++; + n = 0; + if (line >= tokens.size()) return false; + } + return true; + } + + public int getLine() { + return line; + } + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/parser/WrongLHSExpression.java b/AlgebraicDataflowArchitectureModel/src/parser/WrongLHSExpression.java new file mode 100644 index 0000000..0d99ec1 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/parser/WrongLHSExpression.java @@ -0,0 +1,9 @@ +package parser; + +public class WrongLHSExpression extends ParseException { + + public WrongLHSExpression(int line) { + super(line); + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/parser/WrongRHSExpression.java b/AlgebraicDataflowArchitectureModel/src/parser/WrongRHSExpression.java new file mode 100644 index 0000000..9c52885 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/parser/WrongRHSExpression.java @@ -0,0 +1,9 @@ +package parser; + +public class WrongRHSExpression extends ParseException { + + public WrongRHSExpression(int line) { + super(line); + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/tests/DataConstraintModelTest.java b/AlgebraicDataflowArchitectureModel/src/tests/DataConstraintModelTest.java index 264ccdf..5719cac 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/DataConstraintModelTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/DataConstraintModelTest.java @@ -12,25 +12,25 @@ public void test() { // Construct a data constraint architecture model. DataConstraintModel model = new DataConstraintModel(); - IdentifierTemplate customer_off = new IdentifierTemplate(1); - IdentifierTemplate customer_add = new IdentifierTemplate(1); - IdentifierTemplate company_add = new IdentifierTemplate(1); + IdentifierTemplate customer_off = new IdentifierTemplate("customers.{customer_id}.off", 1); + IdentifierTemplate customer_add = new IdentifierTemplate("customers.{customer_id}.add", 1); + IdentifierTemplate company_add = new IdentifierTemplate("companies.{company_id}.add", 1); - ChannelGenerator gin_1 = new ChannelGenerator(); // set customer's office + ChannelGenerator gin_1 = new ChannelGenerator("gin_1"); // set customer's office GroupSelector x1 = new GroupSelector(); ChannelMember customer_off_1 = new ChannelMember(customer_off); customer_off_1.addSelector(x1); gin_1.addChannelMember(customer_off_1); assertEquals(customer_off.getNumberOfParameters(), customer_off_1.getSelectors().size()); - ChannelGenerator gin_2 = new ChannelGenerator(); // set companie's address + ChannelGenerator gin_2 = new ChannelGenerator("gin_2"); // set companie's address GroupSelector x2 = new GroupSelector(); ChannelMember company_add_1 = new ChannelMember(company_add); company_add_1.addSelector(x2); gin_2.addChannelMember(company_add_1); assertEquals(company_add.getNumberOfParameters(), company_add_1.getSelectors().size()); - ChannelGenerator g = new ChannelGenerator(); // update customer's address + ChannelGenerator g = new ChannelGenerator("g"); // update customer's address GroupSelector x3 = new GroupSelector(); ChannelSelector y = new ChannelSelector(); ChannelMember customer_off_2 = new ChannelMember(customer_off); diff --git a/AlgebraicDataflowArchitectureModel/src/tests/DataFlowModelTest.java b/AlgebraicDataflowArchitectureModel/src/tests/DataFlowModelTest.java index 080a992..b83e99a 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/DataFlowModelTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/DataFlowModelTest.java @@ -14,16 +14,16 @@ public void test() { // Construct a data-flow architecture model. DataFlowModel model = new DataFlowModel(); - IdentifierTemplate customer_off = new IdentifierTemplate(1); // an identifier template to specify a customer's office resource - IdentifierTemplate company_add = new IdentifierTemplate(1); // an identifier template to specify a companie's address resource - IdentifierTemplate customer_add = new IdentifierTemplate(1); // an identifier template to specify a customer's address resource + IdentifierTemplate customer_off = new IdentifierTemplate("customers.{x1}.off", 1); // an identifier template to specify a customer's office resource + IdentifierTemplate company_add = new IdentifierTemplate("companies.{x2}.add", 1); // an identifier template to specify a companie's address resource + IdentifierTemplate customer_add = new IdentifierTemplate("customers.{x1}.add", 1); // an identifier template to specify a customer's address resource // === gin_1 === // - // {x1}.customer_off(c, set(x)) = x - // {x1}.customer_off(c, e) = c + // customers.{x1}.off(c, set(x)) == x + // customers.{x1}.off(c, e) == c // - DataflowChannelGenerator gin_1 = new DataflowChannelGenerator(); // set customer's office (an input channel) + DataflowChannelGenerator gin_1 = new DataflowChannelGenerator("gin_1"); // set customer's office (an input channel) GroupSelector x1 = new GroupSelector(); ChannelMember customer_off_1 = new ChannelMember(customer_off); customer_off_1.addSelector(x1); // x1 is determined by the path parameter in customer's office template, and serves as a group selector in this channel @@ -32,10 +32,10 @@ // === gin_2 === // - // {x2}.company_add(a, set(y)) = y - // {x2}.company_add(a, e) = a + // companies.{x2}.add(a, set(y)) == y + // companies.{x2}.add(a, e) == a // - DataflowChannelGenerator gin_2 = new DataflowChannelGenerator(); // set companie's address (an input channel) + DataflowChannelGenerator gin_2 = new DataflowChannelGenerator("gin_2"); // set companie's address (an input channel) GroupSelector x2 = new GroupSelector(); ChannelMember company_add_1 = new ChannelMember(company_add); company_add_1.addSelector(x2); // x2 is determined by the path parameter in companie's address template, and serves as a group selector in this channel @@ -44,11 +44,11 @@ // === g === // - // {x3}.customer_off( c, update(y, z)) = y - // {y}.company_add( a1, update(y, z)) = z - // {x3}.customer_add(a2, update(y, z)) = z + // customers.{x3}.off( c, update(y, z)) == y + // companies.{y}.add( a1, update(y, z)) == z + // customers.{x3}.add(a2, update(y, z)) == z // - DataflowChannelGenerator g = new DataflowChannelGenerator(); // update customer's address + DataflowChannelGenerator g = new DataflowChannelGenerator("g"); // update customer's address GroupSelector x3 = new GroupSelector(); ChannelSelector y = new ChannelSelector(); ChannelMember customer_off_2 = new ChannelMember(customer_off); @@ -81,7 +81,7 @@ assertEquals(3, resourceDependencyGraph.getNodes().size()); assertEquals(2, resourceDependencyGraph.getEdges().size()); for (Edge e: resourceDependencyGraph.getEdges()) { - System.out.println(e.getSource() + "->" + e.getDestination()); + System.out.println(e.getSource() + "-(" + e + ")->" + e.getDestination()); } } diff --git a/AlgebraicDataflowArchitectureModel/src/tests/InverseTest.java b/AlgebraicDataflowArchitectureModel/src/tests/InverseTest.java new file mode 100644 index 0000000..5196688 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/tests/InverseTest.java @@ -0,0 +1,46 @@ +package tests; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.HashMap; + +import org.junit.Test; + +import models.algebra.Expression; +import models.algebra.Position; +import models.algebra.Variable; +import models.dataFlowModel.DataFlowModel; +import parser.ExpectedRightBracket; +import parser.Parser; +import parser.Parser.TokenStream; + +public class InverseTest { + @Test + public void test() { + String lhs = "y"; + DataFlowModel model = new DataFlowModel(); + try { + String rhs = "(a * x + b) * c"; + TokenStream stream = new TokenStream(); + stream.addLine(rhs); + Expression rhsExp = Parser.parseTerm(stream, model); + System.out.println(lhs + " = " + rhsExp); + HashMap rhsVars = rhsExp.getVariables(); + assertEquals(4, rhsVars.size()); + + // Solve {y = (a * x + b) + c} for a, b, c, x + Variable y = new Variable(lhs); + for (Position vPos: rhsVars.keySet()) { + Variable v = rhsVars.get(vPos); + Expression inv = rhsExp.getInverseMap(y, vPos); // inverse map to get v back from the output value y + assertTrue(inv.contains(y)); + assertFalse(inv.contains(v)); + System.out.println(rhsVars.get(vPos) + " = " + inv); + } + } catch (ExpectedRightBracket e) { + e.printStackTrace(); + } + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/tests/ParseTest.java b/AlgebraicDataflowArchitectureModel/src/tests/ParseTest.java new file mode 100644 index 0000000..598c922 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/tests/ParseTest.java @@ -0,0 +1,69 @@ +package tests; + +import static org.junit.Assert.assertEquals; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; + +import models.Edge; +import models.algebra.InvalidMessage; +import models.algebra.ParameterizedIdentifierIsFutureWork; +import models.algebra.UnificationFailed; +import models.algebra.ValueUndefined; +import models.dataConstraintModel.ChannelGenerator; +import models.dataConstraintModel.ChannelMember; +import models.dataFlowModel.DataFlowModel; +import models.dataFlowModel.DataflowChannelGenerator; +import models.dataFlowModel.ResolvingMultipleDefinitionIsFutureWork; +import models.dataFlowModel.ResourceDependencyGraph; +import models.dataFlowModel.ResourceNode; +import parser.ExpectedChannel; +import parser.ExpectedChannelName; +import parser.ExpectedEquals; +import parser.ExpectedInOrOutKeyword; +import parser.ExpectedLeftCurlyBracket; +import parser.ExpectedRHSExpression; +import parser.ExpectedRightBracket; +import parser.ExpectedStateTransition; +import parser.Parser; +import parser.WrongLHSExpression; +import parser.WrongRHSExpression; + +public class ParseTest { + + public static void main(String[] args) { + File file = new File("models/POS2.model"); + try { + Parser parser = new Parser(new BufferedReader(new FileReader(file))); + DataFlowModel model; + try { + model = parser.doParse(); + System.out.println(model); + + for (ChannelGenerator c: model.getChannelGenerators()) { + for (ChannelMember out: ((DataflowChannelGenerator) c).getOutputChannelMembers()) { + System.out.println("next" + out.getIdentifierTemplate().getResourceName() + " = " + ((DataflowChannelGenerator) c).deriveUpdateExpressionOf(out)); + } + } + + System.out.println(); + + ResourceDependencyGraph resourceDependencyGraph = model.getResourceDependencyGraph(); + for (Edge e: resourceDependencyGraph.getEdges()) { + System.out.println(e.getSource() + "-(" + e + ")->" + e.getDestination()); + } + } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutKeyword + | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression + | WrongRHSExpression | ExpectedRightBracket | ParameterizedIdentifierIsFutureWork + | ResolvingMultipleDefinitionIsFutureWork | InvalidMessage + | UnificationFailed | ValueUndefined e) { + e.printStackTrace(); + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/tests/SimplifiedDataFlowModelTest.java b/AlgebraicDataflowArchitectureModel/src/tests/SimplifiedDataFlowModelTest.java index 4cc256d..e16163b 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/SimplifiedDataFlowModelTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/SimplifiedDataFlowModelTest.java @@ -14,26 +14,26 @@ public void test() { // Construct a data-flow architecture model. DataFlowModel model = new DataFlowModel(); - IdentifierTemplate payment = new IdentifierTemplate(0); // an identifier template to specify the payment resource - IdentifierTemplate loyalty = new IdentifierTemplate(0); // an identifier template to specify the loyalty resource - IdentifierTemplate history = new IdentifierTemplate(0); // an identifier template to specify the payment history resource - IdentifierTemplate total = new IdentifierTemplate(0); // an identifier template to specify the total payment resource + IdentifierTemplate payment = new IdentifierTemplate("payment", 0); // an identifier template to specify the payment resource + IdentifierTemplate loyalty = new IdentifierTemplate("loyalty", 0); // an identifier template to specify the loyalty resource + IdentifierTemplate history = new IdentifierTemplate("history", 0); // an identifier template to specify the payment history resource + IdentifierTemplate total = new IdentifierTemplate("total", 0); // an identifier template to specify the total payment resource // === cin === // - // payment(p1, purchase(x)) = x + // payment(p1, purchase(x)) == x // - DataflowChannelGenerator cin = new DataflowChannelGenerator(); + DataflowChannelGenerator cin = new DataflowChannelGenerator("cin"); ChannelMember cin_payment = new ChannelMember(payment); cin.addChannelMember(cin_payment); assertEquals(cin.getChannelMembers().size(), 1); // === c1 === // - // payment(p1, update1(y)) = y - // loyalty(l, update1(y)) = floor(y * 0.05) + // payment(p1, update1(y)) == y + // loyalty(l, update1(y)) == floor(y * 0.05) // - DataflowChannelGenerator c1 = new DataflowChannelGenerator(); + DataflowChannelGenerator c1 = new DataflowChannelGenerator("c1"); ChannelMember c1_payment = new ChannelMember(payment); ChannelMember c1_loyalty = new ChannelMember(loyalty); c1.addChannelMemberAsInput(c1_payment); @@ -44,10 +44,10 @@ // === c2 === // - // payment(p1, update2(z)) = z - // history(h, update2(z)) = cons(z, h) + // payment(p1, update2(z)) == z + // history(h, update2(z)) == cons(z, h) // - DataflowChannelGenerator c2 = new DataflowChannelGenerator(); + DataflowChannelGenerator c2 = new DataflowChannelGenerator("c2"); ChannelMember c2_payment = new ChannelMember(payment); ChannelMember c2_history = new ChannelMember(history); c2.addChannelMemberAsInput(c2_payment); @@ -58,10 +58,10 @@ // === c3 === // - // history(h, update3(u)) = u - // total(t, update3(u)) = sum(u) + // history(h, update3(u)) == u + // total(t, update3(u)) == sum(u) // - DataflowChannelGenerator c3 = new DataflowChannelGenerator(); + DataflowChannelGenerator c3 = new DataflowChannelGenerator("c3"); ChannelMember c3_history = new ChannelMember(history); ChannelMember c3_total = new ChannelMember(total); c3.addChannelMemberAsInput(c3_history); @@ -88,7 +88,7 @@ assertEquals(4, resourceDependencyGraph.getNodes().size()); assertEquals(3, resourceDependencyGraph.getEdges().size()); for (Edge e: resourceDependencyGraph.getEdges()) { - System.out.println(e.getSource() + "->" + e.getDestination()); + System.out.println(e.getSource() + "-(" + e + ")->" + e.getDestination()); } } diff --git a/AlgebraicDataflowArchitectureModel/src/tests/TermTest.java b/AlgebraicDataflowArchitectureModel/src/tests/TermTest.java new file mode 100644 index 0000000..9ae2ec0 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/tests/TermTest.java @@ -0,0 +1,52 @@ +package tests; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; +import org.junit.Test; + +import models.algebra.Constant; +import models.algebra.Symbol; +import models.algebra.Term; +import models.algebra.Variable; + +public class TermTest { + + @Test + public void test() { + Symbol add = new Symbol("add", 2); + Symbol mul = new Symbol("mul", 2); + Constant one = new Constant("1"); + Constant two = new Constant("2"); + Variable x = new Variable("x"); + Variable y = new Variable("y"); + Variable z = new Variable("z"); + Term t1 = new Term(add); // add(1, x) + t1.addChild(one); + t1.addChild(x); + Term t2 = new Term(mul); // mul(add(1, x), y) + t2.addChild(t1); + t2.addChild(y); + Term t3 = new Term(add); // add(1, x) + t3.addChild(one); + t3.addChild(x); + + assertTrue(t1.contains(x)); + assertFalse(t1.contains(y)); + assertTrue(t2.contains(x)); + assertTrue(t2.contains(y)); + assertTrue(t2.contains(t1)); + assertTrue(t2.contains(t3)); + assertFalse(t2.contains(z)); + assertFalse(t2.contains(two)); + assertTrue(one.equals(one)); + assertTrue(two.equals(two)); + assertTrue(x.equals(x)); + assertTrue(y.equals(y)); + assertFalse(x.equals(y)); + assertFalse(x.equals(one)); + assertFalse(t1.equals(x)); + System.out.println(t1); + System.out.println(t2); + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/tests/UpdateCodeGenerationTest.java b/AlgebraicDataflowArchitectureModel/src/tests/UpdateCodeGenerationTest.java new file mode 100644 index 0000000..0955539 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/tests/UpdateCodeGenerationTest.java @@ -0,0 +1,303 @@ +package tests; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.Field; +import models.algebra.InvalidMessage; +import models.algebra.Parameter; +import models.algebra.ParameterizedIdentifierIsFutureWork; +import models.algebra.Symbol; +import models.algebra.Term; +import models.algebra.UnificationFailed; +import models.algebra.ValueUndefined; +import models.algebra.Variable; +import models.dataConstraintModel.ChannelMember; +import models.dataConstraintModel.ChannelSelector; +import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.GroupSelector; +import models.dataConstraintModel.IdentifierTemplate; +import models.dataConstraintModel.StateTransition; +import models.dataFlowModel.DataFlowModel; +import models.dataFlowModel.DataflowChannelGenerator; +import models.dataFlowModel.DataflowChannelGenerator.IResourceStateAccessor; +import models.dataFlowModel.ResolvingMultipleDefinitionIsFutureWork; + +public class UpdateCodeGenerationTest { + + public static void main(String[] args) { + // Pre-defined symbols + Symbol floor = new Symbol("floor", 1); + + IdentifierTemplate payment = new IdentifierTemplate("payment", DataConstraintModel.typeInt, 0); // an identifier template to specify the payment resource + IdentifierTemplate loyalty = new IdentifierTemplate("loyalty", DataConstraintModel.typeInt, 0); // an identifier template to specify the loyalty resource + IdentifierTemplate history = new IdentifierTemplate("history", DataConstraintModel.typeList, 0);// an identifier template to specify the payment history resource + IdentifierTemplate total = new IdentifierTemplate("total", DataConstraintModel.typeInt, 0); // an identifier template to specify the total payment resource + + // fields + final Field fPayment = new Field("payment", DataConstraintModel.typeInt); + final Field fLoyalty = new Field("loyalty", DataConstraintModel.typeInt); + final Field fHistory = new Field("history", DataConstraintModel.typeList); + final Field fTotal = new Field("total", DataConstraintModel.typeInt); + // parameters + final Parameter pPayment = new Parameter("payment", DataConstraintModel.typeInt); + final Parameter pLoyalty = new Parameter("loyalty", DataConstraintModel.typeInt); + final Parameter pHistory = new Parameter("history", DataConstraintModel.typeList); + final Parameter pTotal = new Parameter("total", DataConstraintModel.typeInt); + IResourceStateAccessor pushAccessor = new IResourceStateAccessor() { + @Override + public Expression getCurrentStateAccessorFor(IdentifierTemplate target, IdentifierTemplate from) { + if (target.equals(from)) { + if (target.equals(payment)) return fPayment; + if (target.equals(loyalty)) return fLoyalty; + if (target.equals(history)) return fHistory; + if (target.equals(total)) return fTotal; + } + return null; + } + @Override + public Expression getNextStateAccessorFor(IdentifierTemplate target, IdentifierTemplate from) { + if (target.equals(payment)) return pPayment; + if (target.equals(loyalty)) return pLoyalty; + if (target.equals(history)) return pHistory; + if (target.equals(total)) return pTotal; + return null; + } + }; + + final Symbol paymentGetter = new Symbol("getPayment", 1, Symbol.Type.METHOD); + final Symbol loyltyGetter = new Symbol("getLoyalty", 1, Symbol.Type.METHOD); + final Symbol historyGetter = new Symbol("getHistory", 1, Symbol.Type.METHOD); + final Symbol totalGetter = new Symbol("getTotal", 1, Symbol.Type.METHOD); + IResourceStateAccessor pullAccessor = new IResourceStateAccessor() { + @Override + public Expression getCurrentStateAccessorFor(IdentifierTemplate target, IdentifierTemplate from) { + if (target.equals(from)) { + if (target.equals(payment)) return fPayment; + if (target.equals(loyalty)) return fLoyalty; + if (target.equals(history)) return fHistory; + if (target.equals(total)) return fTotal; + } + return null; + } + @Override + public Expression getNextStateAccessorFor(IdentifierTemplate target, IdentifierTemplate from) { + if (target.equals(payment)) { + Term getter = new Term(paymentGetter); + getter.addChild(fPayment); + return getter; + } + if (target.equals(loyalty)) { + Term getter = new Term(loyltyGetter); + getter.addChild(fLoyalty); + return getter; + } + if (target.equals(history)) { + Term getter = new Term(historyGetter); + getter.addChild(fHistory); + return getter; + } + if (target.equals(total)) { + Term getter = new Term(totalGetter); + getter.addChild(fTotal); + return getter; + } + return null; + } + }; + + // === c1 === + // + // payment(p1, update1(y)) == y + // loyalty(l, update1(y)) == floor(y * 0.05) + // + DataflowChannelGenerator c1 = new DataflowChannelGenerator("c1"); + ChannelMember c1_payment = new ChannelMember(payment); + ChannelMember c1_loyalty = new ChannelMember(loyalty); + c1.addChannelMemberAsInput(c1_payment); + c1.addChannelMemberAsOutput(c1_loyalty); + + Variable p1 = new Variable("p1"); + Variable y = new Variable("y"); + Variable l = new Variable("l"); + Constant c_0_05 = new Constant("0.05"); + Symbol update1 = new Symbol("update1", 1); + Term c1_message = new Term(update1); // update1(y) + c1_message.addChild(y); + Term rawLoyality = new Term(DataConstraintModel.mul); // y*0.05 + rawLoyality.addChild(y); + rawLoyality.addChild(c_0_05); + Term nextLoyality = new Term(floor); // floor(y*0.05) + nextLoyality.addChild(rawLoyality); + + StateTransition c1_payment_transition = new StateTransition(); + c1_payment_transition.setCurStateExpression(p1); + c1_payment_transition.setMessageExpression(c1_message); + c1_payment_transition.setNextStateExpression(y); + c1_payment.setStateTransition(c1_payment_transition); + + StateTransition c1_loyalty_transition = new StateTransition(); + c1_loyalty_transition.setCurStateExpression(l); + c1_loyalty_transition.setMessageExpression(c1_message); + c1_loyalty_transition.setNextStateExpression(nextLoyality); + c1_loyalty.setStateTransition(c1_loyalty_transition); + + System.out.println(c1); + + try { + System.out.println("-----"); + System.out.println(c1.deriveUpdateExpressionOf(c1_loyalty)); + + System.out.println("-- PUSH --"); + Expression loyaltyPushUpdate = c1.deriveUpdateExpressionOf(c1_loyalty, pushAccessor); + Parameter param = null; + for (Parameter p: loyaltyPushUpdate.getSubTerms(Parameter.class).values()) { + if (p.equals(pPayment) || p.equals(pLoyalty) || p.equals(pHistory) || p.equals(pTotal)) { + param = p; + break; + } + } + System.out.println("void update(" + param.getType().getImplementastionTypeName() + " " + param + ") {"); + System.out.println("\t" + fLoyalty + " = " + loyaltyPushUpdate + ";"); + System.out.println("}"); + + System.out.println("-- PULL --"); + System.out.println(loyalty.getResourceStateType().getImplementastionTypeName() + " " + loyltyGetter + "() {"); + System.out.println("\t return " + c1.deriveUpdateExpressionOf(c1_loyalty, pullAccessor) + ";"); + System.out.println("}"); + } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork | InvalidMessage + | UnificationFailed | ValueUndefined e) { + e.printStackTrace(); + } + + System.out.println("=========="); + + // === c2 === + // + // payment(p1, update2(z)) == z + // history(h, update2(z)) == cons(z, h) + // + DataflowChannelGenerator c2 = new DataflowChannelGenerator("c2"); + ChannelMember c2_payment = new ChannelMember(payment); + ChannelMember c2_history = new ChannelMember(history); + c2.addChannelMemberAsInput(c2_payment); + c2.addChannelMemberAsOutput(c2_history); + + Variable z = new Variable("z"); + Variable h = new Variable("h"); + Symbol update2 = new Symbol("update2", 1); + Term c2_message = new Term(update2); // update2(z) + c2_message.addChild(z); + Term nextHistory = new Term(DataFlowModel.cons); // cons(z, h) + nextHistory.addChild(z); + nextHistory.addChild(h); + + StateTransition c2_payment_transition = new StateTransition(); + c2_payment_transition.setCurStateExpression(p1); + c2_payment_transition.setMessageExpression(c2_message); + c2_payment_transition.setNextStateExpression(z); + c2_payment.setStateTransition(c2_payment_transition); + + StateTransition c2_history_transition = new StateTransition(); + c2_history_transition.setCurStateExpression(h); + c2_history_transition.setMessageExpression(c2_message); + c2_history_transition.setNextStateExpression(nextHistory); + c2_history.setStateTransition(c2_history_transition); + + System.out.println(c2); + + try { + System.out.println("-----"); + System.out.println(c2.deriveUpdateExpressionOf(c2_history)); + + System.out.println("-- PUSH --"); + Expression historyPushUpdate = c2.deriveUpdateExpressionOf(c2_history, pushAccessor); + Parameter param = null; + for (Parameter p: historyPushUpdate.getSubTerms(Parameter.class).values()) { + if (p.equals(pPayment) || p.equals(pLoyalty) || p.equals(pHistory) || p.equals(pTotal)) { + param = p; + break; + } + } + System.out.println("void update(" + param.getType().getImplementastionTypeName() + " " + param + ") {"); + System.out.println("\t" + fHistory + " = " + historyPushUpdate + ";"); + System.out.println("}"); + + System.out.println("-- PULL --"); + System.out.println(history.getResourceStateType().getImplementastionTypeName() + " " + historyGetter + "() {"); + System.out.println("\t return " + c2.deriveUpdateExpressionOf(c2_history, pullAccessor) + ";"); + System.out.println("}"); + } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork | InvalidMessage + | UnificationFailed | ValueUndefined e) { + e.printStackTrace(); + } + + System.out.println("=========="); + + // === c3 === + // + // history(h, update3(u)) = u + // total(t, update3(u)) = sum(u) + // + DataflowChannelGenerator c3 = new DataflowChannelGenerator("c3"); + ChannelMember c3_history = new ChannelMember(history); + ChannelMember c3_total = new ChannelMember(total); + c3.addChannelMemberAsInput(c3_history); + c3.addChannelMemberAsOutput(c3_total); + + Variable u = new Variable("u"); + Variable t = new Variable("t"); + Symbol update3 = new Symbol("update3", 1); + Term c3_message = new Term(update3); // update3(u) + c3_message.addChild(u); + Expression nextHistory2 = u; + Term nextTotal = new Term(new Symbol("sum", 1)); + nextTotal.addChild(u); + + StateTransition c3_history_transition = new StateTransition(); + c3_history_transition.setCurStateExpression(h); + c3_history_transition.setMessageExpression(c3_message); + c3_history_transition.setNextStateExpression(nextHistory2); + c3_history.setStateTransition(c3_history_transition); + + StateTransition c3_total_transition = new StateTransition(); + c3_total_transition.setCurStateExpression(t); + c3_total_transition.setMessageExpression(c3_message); + c3_total_transition.setNextStateExpression(nextTotal); + c3_total.setStateTransition(c3_total_transition); + + System.out.println(c3); + + try { + System.out.println("-----"); + System.out.println(c3.deriveUpdateExpressionOf(c3_total)); + + System.out.println("-- PUSH --"); + Expression totalPushUpdate = c3.deriveUpdateExpressionOf(c3_total, pushAccessor); + Parameter param = null; + for (Parameter p: totalPushUpdate.getSubTerms(Parameter.class).values()) { + if (p.equals(pPayment) || p.equals(pLoyalty) || p.equals(pHistory) || p.equals(pTotal)) { + param = p; + break; + } + } + System.out.println("void update(" + param.getType().getImplementastionTypeName() + " " + param + ") {"); + System.out.println("\t" + fTotal + " = " + totalPushUpdate + ";"); + System.out.println("}"); + + System.out.println("-- PULL --"); + System.out.println(total.getResourceStateType().getImplementastionTypeName() + " " + totalGetter + "() {"); + System.out.println("\t return " + c3.deriveUpdateExpressionOf(c3_total, pullAccessor) + ";"); + System.out.println("}"); + } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork | InvalidMessage + | UnificationFailed | ValueUndefined e) { + e.printStackTrace(); + } + + System.out.println("=========="); + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/tests/UpdateConflictCheckTest.java b/AlgebraicDataflowArchitectureModel/src/tests/UpdateConflictCheckTest.java index 5354b5b..b945cd5 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/UpdateConflictCheckTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/UpdateConflictCheckTest.java @@ -19,11 +19,11 @@ public void test() { // Construct a data-flow architecture model. DataFlowModel model = new DataFlowModel(); - IdentifierTemplate customer_off = new IdentifierTemplate(1); // an identifier template to specify a customer's + IdentifierTemplate customer_off = new IdentifierTemplate("customers.{customer_id}.off", 1); // an identifier template to specify a customer's // office resource - IdentifierTemplate company_add = new IdentifierTemplate(1); // an identifier template to specify a companie's - // address resource - IdentifierTemplate customer_add = new IdentifierTemplate(1); // an identifier template to specify a customer's + IdentifierTemplate company_add = new IdentifierTemplate("companies.{company_id}.add", 1); // an identifier template to specify a companie's + // address resource + IdentifierTemplate customer_add = new IdentifierTemplate("customers.{customer_id}.add", 1); // an identifier template to specify a customer's // address resource // === gin_1 === @@ -31,7 +31,7 @@ // {x1}.customer_off(c, set(x)) = x // {x1}.customer_off(c, e) = c // - DataflowChannelGenerator gin_1 = new DataflowChannelGenerator(); // set customer's office (an input channel) + DataflowChannelGenerator gin_1 = new DataflowChannelGenerator("gin_1"); // set customer's office (an input channel) GroupSelector x1 = new GroupSelector(); ChannelMember customer_off_1 = new ChannelMember(customer_off); customer_off_1.addSelector(x1); // x1 is determined by the path parameter in customer's office template, and @@ -44,7 +44,7 @@ // {x2}.company_add(a, set(y)) = y // {x2}.company_add(a, e) = a // - DataflowChannelGenerator gin_2 = new DataflowChannelGenerator(); // set companie's address (an input channel) + DataflowChannelGenerator gin_2 = new DataflowChannelGenerator("gin_2"); // set companie's address (an input channel) GroupSelector x2 = new GroupSelector(); ChannelMember company_add_1 = new ChannelMember(company_add); company_add_1.addSelector(x2); // x2 is determined by the path parameter in companie's address template, and @@ -58,7 +58,7 @@ // {y}.company_add( a1, update(y, z)) = z // {x3}.customer_add(a2, update(y, z)) = z // - DataflowChannelGenerator g = new DataflowChannelGenerator(); // update customer's address + DataflowChannelGenerator g = new DataflowChannelGenerator("g"); // update customer's address GroupSelector x3 = new GroupSelector(); ChannelSelector y = new ChannelSelector(); ChannelMember customer_off_2 = new ChannelMember(customer_off);