Newer
Older
AlgebraicDataflowArchitectureModel / AlgebraicDataflowArchitectureModel / src / models / dataConstraintModel / JsonAccessor.java
Shohei Yamagiwa 19 days ago 8 KB Format files
package models.dataConstraintModel;

import models.algebra.*;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class JsonAccessor extends Term {
	public JsonAccessor(Symbol symbol) {
		super(symbol);
	}
	
	@Override
	public Expression reduce() {
		Expression reducedTerm = super.reduce();
		if (reducedTerm instanceof Term) {
			if (symbol == DataConstraintModel.dot && getChildren().size() >= 2) {
				// this term is `json.key`.
				Expression expJson = getChild(0);
				Expression expKey = getChild(1);
				if (expKey instanceof Constant && expJson instanceof Term) {
					reducedTerm = getValue((Term) expJson, (Constant) expKey);
				}
			} else if (symbol == DataConstraintModel.dotParam && getChildren().size() >= 2) {
				// this term is `json.{param}`.
				Expression expJson = getChild(0);
				Expression expKey = getChild(1);
				if (expKey instanceof Variable && expJson instanceof Term) {
					reducedTerm = getValue((Term) expJson, (Variable) expKey);
				}
			}
		}
		return reducedTerm;
	}
	
	private Expression getValue(Term json, Expression key) {
		if (json instanceof JsonTerm) {
			if (key instanceof Constant) {
				return ((JsonTerm) json).get((Constant) key);
			} else if (key instanceof Variable) {
				return ((JsonTerm) json).get((Variable) key);
			}
		}
		if (key instanceof Constant || key instanceof Variable) {
			if (json.getSymbol().equals(DataConstraintModel.addMember) || json.getSymbol().equals(DataConstraintModel.set)) {
				if (json.getChild(1).equals(key)) {
					Expression value = json.getChild(2);
					if (value == null) {
						return new Constant(DataConstraintModel.null_);
					}
					return value;
				}
				if (json.getChild(0) == null || (json.getChild(0) instanceof Term && (((Term) json.getChild(0)).getSymbol().equals(DataConstraintModel.null_)) || ((Term) json.getChild(0)).getSymbol().equals(DataConstraintModel.nil)))
					return null;
				return getValue((Term) json.getChild(0), key);
			}
		}
		return new Constant(DataConstraintModel.null_);
	}
	
	private Expression getValue(Term json, Variable key) {
		if (json instanceof JsonTerm) {
			return ((JsonTerm) json).get(key);
		}
		if (json.getSymbol().equals(DataConstraintModel.addMember) || json.getSymbol().equals(DataConstraintModel.set)) {
			if (json.getChild(1).equals(key)) {
				Expression value = json.getChild(2);
				if (value == null) {
					return new Constant(DataConstraintModel.null_);
				}
				return value;
			}
			if (json.getChild(0) == null || (json.getChild(0) instanceof Term && (((Term) json.getChild(0)).getSymbol().equals(DataConstraintModel.null_)) || ((Term) json.getChild(0)).getSymbol().equals(DataConstraintModel.nil)))
				return null;
			return getValue((Term) json.getChild(0), key);
		}
		if (json.getSymbol().equals(DataConstraintModel.insert)) {
			if (json.getChild(1).equals(key)) {
				Expression value = json.getChild(2);
				if (value == null) {
					return new Constant(DataConstraintModel.null_);
				}
				return value;
			}
			if (json.getChild(0) == null || (json.getChild(0) instanceof Term && (((Term) json.getChild(0)).getSymbol().equals(DataConstraintModel.null_)) || ((Term) json.getChild(0)).getSymbol().equals(DataConstraintModel.nil)))
				return null;
			return getValue((Term) json.getChild(0), key);
		}
		return new Constant(DataConstraintModel.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 (i == 0) {
			if (symbol == DataConstraintModel.dot && getChildren().size() >= 2) {
				// this term is `json.key`.
				Expression expJson = getChild(0);
				Expression expKey = getChild(1);
				Type jsonType = null;
				if (expJson instanceof Variable) {
					jsonType = ((Variable) expJson).getType();
				} else if (expJson instanceof Term) {
					jsonType = ((Term) expJson).getType();
				}
				String keyName = null;
				if (expKey instanceof Constant) {
					keyName = (String) ((Constant) expKey).getValue();
					Term jsonTerm = new Constant(DataConstraintModel.nil);
					jsonTerm.setType(DataConstraintModel.typeJson);
					int v = 1;
					Map<String, Variable> vars = new HashMap<>();
					Set<String> keySet = new HashSet<>();
					if (jsonType == null || jsonType == DataConstraintModel.typeJson) {
						keySet.add(keyName);
					} else if (jsonType instanceof JsonType) {
						keySet.addAll(((JsonType) jsonType).getKeys());
						if (keySet.size() == 0) {
							keySet.add(keyName);
						}
					}
					for (String key : keySet) {
						Term addMemberTerm = new Term(DataConstraintModel.addMember);    // addMember(jsonTerm, key, v)
						addMemberTerm.addChild(jsonTerm);
						addMemberTerm.addChild(new Constant(key, DataConstraintModel.typeString));
						Variable var = new Variable("v" + v);
						addMemberTerm.addChild(var);
						vars.put(key, var);
						jsonTerm = addMemberTerm;
						v++;
					}
					Variable var = vars.get(keyName);
					LambdaAbstraction lambdaAbstraction = new LambdaAbstraction(var, jsonTerm);    // v -> addMember(jsonTerm, key, v)
					inverseSymbols = new Symbol[]{lambdaAbstraction};
				}
			} else if (symbol == DataConstraintModel.dotParam && getChildren().size() >= 2) {
				// this term is `json.{param}`.
				Expression expListOrMap = getChild(0);
				Expression expKey = getChild(1);
				JsonType jsonType = null;
				if (expListOrMap instanceof Variable) {
					jsonType = (JsonType) ((Variable) expListOrMap).getType();
				} else if (expListOrMap instanceof Term) {
					jsonType = (JsonType) ((Term) expListOrMap).getType();
				}
				Type keyType = null;
				if (expKey instanceof Variable) {
					keyType = ((Variable) expKey).getType();
				} else if (expKey instanceof Term) {
					keyType = ((Term) expKey).getType();
				}
				if (jsonType != null && keyType != null) {
					if (DataConstraintModel.typeList.isAncestorOf(jsonType) || keyType.equals(DataConstraintModel.typeInt)) {
						Term setElementTerm = new Term(DataConstraintModel.set);            // set(list, idx, v)
						setElementTerm.addChild(new Constant(DataConstraintModel.nil));
						setElementTerm.addChild(expKey);
						Variable var = new Variable("v");
						setElementTerm.addChild(var);
						LambdaAbstraction lambdaAbstraction = new LambdaAbstraction(var, setElementTerm);    // v -> set(list, idx, v)
						inverseSymbols = new Symbol[]{lambdaAbstraction};
					} else if (DataConstraintModel.typeMap.isAncestorOf(jsonType) || keyType.equals(DataConstraintModel.typeString)) {
						Term insertEntryTerm = new Term(DataConstraintModel.insert);            // insert(map, key, v)
						insertEntryTerm.addChild(new Constant(DataConstraintModel.nil));
						insertEntryTerm.addChild(expKey);
						Variable var = new Variable("v");
						insertEntryTerm.addChild(var);
						LambdaAbstraction lambdaAbstraction = new LambdaAbstraction(var, insertEntryTerm);    // v -> insert(map, key, v)
						inverseSymbols = new Symbol[]{lambdaAbstraction};
					}
				}
			}
		}
		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);
	}
	
	public String toString() {
		if (symbol.equals(DataConstraintModel.dotParam)) {
			if (children.get(1) instanceof Constant) {
				return children.get(0).toString() + symbol.toString() + (String) ((Constant) children.get(1)).getValue();
			}
			return children.get(0).toString() + symbol.toString() + children.get(1).toString();
		}
		return super.toString();
	}
	
	public String toImplementation(String[] sideEffects) {
		if (symbol.equals(DataConstraintModel.dotParam)) {
			return children.get(0).toImplementation(sideEffects) + "." + symbol.toImplementation() + "(" + children.get(1).toImplementation(sideEffects) + ")";
		}
		return super.toImplementation(sideEffects);
	}
	
	@Override
	public Object clone() {
		JsonAccessor newTerm = new JsonAccessor(symbol);
		for (Expression e : children) {
			newTerm.addChild((Expression) e.clone());
		}
		newTerm.type = type;
		return newTerm;
	}
}