/** * Copyright (c) 2009-2011, The HATS Consortium. All rights reserved. * This file is licensed under the terms of the Modified BSD License. */ package abs.frontend.delta; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.TreeMap; import abs.frontend.analyser.ErrorMessage; import abs.frontend.analyser.SemanticConditionList; import abs.frontend.analyser.SPLTypeError; import abs.frontend.ast.*; public class ProgramTypeAbstraction { private final Map<String, Map<String, Set<String>>> classes; private final SemanticConditionList errors; // Keep track of sequence of deltas already applied to this TA, for better error reporting private final java.util.List<DeltaDecl> deltas; // Keep track of the product we are currently trying to build, for better error reporting private Product product; // Constructor public ProgramTypeAbstraction(SemanticConditionList errors) { this.errors = errors; deltas = new ArrayList<DeltaDecl>(); classes = new HashMap<String, Map<String, Set<String>>>(); } // Copy constructor public ProgramTypeAbstraction(ProgramTypeAbstraction sourceTA) { this.errors = sourceTA.errors; this.deltas = new ArrayList<DeltaDecl>(sourceTA.deltas); classes = new HashMap<String, Map<String, Set<String>>>(); for (String className : sourceTA.classes.keySet()) { addClass(className); for (String name : sourceTA.classes.get(className).get("fields")) classes.get(className).get("fields").add(name); for (String name : sourceTA.classes.get(className).get("methods")) classes.get(className).get("methods").add(name); } } public void applyDelta(DeltaDecl delta, Product product) { deltas.add(delta); this.product = product; for (ModuleModifier mod : delta.getModuleModifiers()) { mod.applyToTypeAbstraction(this); } } public void addClass(AddClassModifier node) { String className = node.qualifiedName(); if (classes.containsKey(className)) errors.add(new SPLTypeError(node, ErrorMessage.DUPLICATE_CLASS_NAME, deltas, product, className, // TODO add " at file:line" with location of original definition "")); else addClass(className); } public void addClass(String className) { classes.put(className, new HashMap<String, Set<String>>()); classes.get(className).put("fields", new HashSet<String>()); classes.get(className).put("methods", new HashSet<String>()); } public void removeClass(RemoveClassModifier node) { String className = node.qualifiedName(); if (classes.containsKey(className)) classes.remove(className); else errors.add(new SPLTypeError(node, ErrorMessage.NO_CLASS_DECL, deltas, product, className)); } public void addField(String className, AddFieldModifier node) { String name = node.getFieldDecl().getName(); if (! classes.get(className).get("fields").contains(name)) addField(className, name); else errors.add(new SPLTypeError(node, ErrorMessage.DUPLICATE_FIELD_NAME, deltas, product, name)); } public void addField(String className, String fieldName) { classes.get(className).get("fields").add(fieldName); } public void removeField(String className, RemoveFieldModifier node) { String name = node.getFieldDecl().getName(); if (classes.get(className).get("fields").contains(name)) classes.get(className).get("fields").remove(name); else errors.add(new SPLTypeError(node, ErrorMessage.NO_FIELD_DECL, deltas, product, name)); } public void addMethod(String className, String methodName) { classes.get(className).get("methods").add(methodName); } // helper method public boolean existsClass(ModifyClassModifier node) { String className = node.qualifiedName(); if (classes.containsKey(className)) { return true; } else { errors.add(new SPLTypeError(node, ErrorMessage.NO_CLASS_DECL, deltas, product, className)); return false; } } @Override public String toString() { StringBuilder s = new StringBuilder(); final Map<String,Object> sortedClasses = new TreeMap<String, Object>(classes); for (String cls : sortedClasses.keySet()) { s.append(" Class: " + cls + "\n" + " Fields:\n"); for (String field : classes.get(cls).get("fields")) s.append(" " + field + "\n"); s.append(" Methods:\n"); for (String method : classes.get(cls).get("methods")) s.append(" " + method + "\n"); } return s.toString(); } }