/******************************************************************************* * Copyright (c) 2009 University of Edinburgh. * All rights reserved. This program and the accompanying materials are made * available under the terms of the BSD Licence, which accompanies this feature * and can be downloaded from http://groups.inf.ed.ac.uk/pepa/update/licence.txt ******************************************************************************/ package uk.ac.ed.inf.biopepa.core.compiler; import java.util.*; import java.util.Map.Entry; import uk.ac.ed.inf.biopepa.core.BioPEPAException; import uk.ac.ed.inf.biopepa.core.analysis.StaticAnalysis; import uk.ac.ed.inf.biopepa.core.dom.*; /** * Compiles a BioPEPA model * * @author mtribast * */ public class ModelCompiler implements DynamicExpressionModelContext { // listens to problems as collected by internal visitors IProblemRequestor problemRequestor; // The AST being compiled private Model model; // used to prevent cycles private String currentlyVisitedVariableName = null; // Model variables, as found by the compiler private Map<String, VariableData> variables = new HashMap<String, VariableData>(); private Set<String> dynamicComponents = new HashSet<String>(); // Model compartments private Map<String, CompartmentData> compartments = new HashMap<String, CompartmentData>(); // Model species private Map<String, SpeciesData> species = new HashMap<String, SpeciesData>(); // Definitions of functional rates private Map<String, FunctionalRateData> functionalRates = new HashMap<String, FunctionalRateData>(); // Definitions of components private Map<String, ComponentData> components = new HashMap<String, ComponentData>(); // Compositional definitions private Map<String, SystemEquationData> compositions = new HashMap<String, SystemEquationData>(); private SystemEquationNode systemEquation = null; private List<ProblemInfo> problems = new ArrayList<ProblemInfo>(); public ModelCompiler(Model model) { if (model == null) throw new IllegalArgumentException(); this.model = model; this.problemRequestor = new IProblemRequestor() { IProblemPolicy policy = new DefaultProblemPolicy(); public boolean accept(ProblemKind problem, ASTNode affectedNode) { return accept(problem, "", affectedNode); } public boolean accept(ProblemInfo.Severity severity, String message, ASTNode node) { ProblemInfo info = new ProblemInfo(); info.severity = severity; info.message = message; info.sourceRange = node.getSourceRange(); problems.add(info); return true; } public boolean accept(ProblemKind problem, String additionalComment, ASTNode affectedNode) { StringBuffer message = new StringBuffer(problem.toString()); message.append(additionalComment).append("."); ProblemInfo info = new ProblemInfo(); info.severity = (policy.isWarning(problem) ? ProblemInfo.Severity.WARNING : ProblemInfo.Severity.ERROR); info.message = message.toString(); info.sourceRange = affectedNode.getSourceRange(); problems.add(info); return true; } public IProblemPolicy getProblemPolicy() { return policy; } public void setProblemPolicy(IProblemPolicy policy) { throw new IllegalArgumentException(); } }; } public ProblemInfo[] compile() { try { discoverDynamicComponents(); compileVariableDeclarations(); compileCompartmentDeclarations(); compileSpeciesDeclarations(); compileFunctionalRates(); compileComponents(); compileSystemEquation(); compileOutWildCards(); generateWarnings(); problems.addAll(StaticAnalysis.analysis(model, this)); } catch (BioPEPAException e) { } return problems.toArray(new ProblemInfo[problems.size()]); } public boolean containsVariable(String name) { return variables.containsKey(name); } public boolean containsComponent(String name) { return components.containsKey(name); } public boolean containsCompartment(String name) { return compartments.containsKey(name); } public boolean containsSpecies(String name) { return species.containsKey(name); } public boolean containsFunctionalRate(String name) { return functionalRates.containsKey(name); } public boolean containsCompositionalDefinition(String name) { return compositions.containsKey(name); } public boolean containsAnyDeclaration(String name) { return containsCompartment(name) || containsVariable(name) || containsSpecies(name) || containsFunctionalRate(name) || containsCompositionalDefinition(name) || containsComponent(name); } int getNumberOfDefinedCompartments() { return compartments.size(); } String getCurrentlyVisitedVariable() { return currentlyVisitedVariableName; } public boolean isDynamic(String name) { return dynamicComponents.contains(name); } VariableData checkAndGetVariableData(String name) { VariableData data = variables.get(name); if (data == null) return null; data.registerNewUsage(); return data; } CompartmentData checkAndGetCompartmentData(String name) { CompartmentData data = compartments.get(name); if (data == null) return null; data.registerNewUsage(); return data; } SpeciesData checkAndGetSpeciesData(String identifier) { SpeciesData data = species.get(identifier); if (data == null) return null; data.registerNewUsage(); return data; } FunctionalRateData checkAndGetFunctionalRate(String identifier) { FunctionalRateData data = functionalRates.get(identifier); if (data == null) return null; data.registerNewUsage(); return data; } SystemEquationData checkAndGetComposition(String name) { SystemEquationData data = compositions.get(name); if (data == null) return null; data.registerNewUsage(); return data; } ComponentData checkAndGetComponentData(String name) { ComponentData data = components.get(name); if (data == null) return null; data.registerNewUsage(); return data; } /** * TODO doesn't verify which are in use and which aren't; merely compiles a * list of stated dynamic components. * * @throws BioPEPAException */ private void discoverDynamicComponents() throws BioPEPAException { VariableDeclaration dec; Expression rhs; DynamicComponentGathererVisitor dcgv = new DynamicComponentGathererVisitor(this); Name name; for (Statement statement : model.statements()) { if (statement instanceof VariableDeclaration) { dec = (VariableDeclaration) statement; if (dec.getKind() == VariableDeclaration.Kind.CONTAINER) { name = dec.getName(); if (name instanceof LocatedName) dynamicComponents.add(((LocatedName) name).getName()); else dynamicComponents.add(dec.getName().getIdentifier()); } else if (dec.getKind() == VariableDeclaration.Kind.COMPONENT) { rhs = dec.getRightHandSide(); if (rhs instanceof Cooperation || rhs instanceof Component) { rhs.accept(dcgv); } } } else if (statement instanceof ExpressionStatement) { ((ExpressionStatement) statement).getExpression().accept(dcgv); } } dynamicComponents.addAll(dcgv.components); } private void compileVariableDeclarations() throws BioPEPAException { // look for variable declarations and evaluate expressions for (Statement statement : model.statements()) { if (statement instanceof VariableDeclaration) { VariableDeclaration dec = (VariableDeclaration) statement; if (dec.getKind() == VariableDeclaration.Kind.VARIABLE) { VariableCompiler visitor = new VariableCompiler(this, dec); currentlyVisitedVariableName = dec.getName().getIdentifier(); VariableData data = (VariableData) visitor.getData(); assert data != null; variables.put(data.getName(), data); } } } currentlyVisitedVariableName = null; } private void compileCompartmentDeclarations() throws BioPEPAException { for (Statement statement : model.statements()) { if (statement instanceof VariableDeclaration) { VariableDeclaration dec = (VariableDeclaration) statement; if (dec.getKind() == VariableDeclaration.Kind.CONTAINER) { CompartmentCompiler visitor = new CompartmentCompiler(this, dec); CompartmentData data = (CompartmentData) visitor.getData(); assert data != null; compartments.put(data.getName(), data); } } } } private void compileSpeciesDeclarations() throws BioPEPAException { List<SpeciesData> speciesList; for (Statement statement : model.statements()) { if (statement instanceof VariableDeclaration) { VariableDeclaration dec = (VariableDeclaration) statement; if (dec.getKind() == VariableDeclaration.Kind.SPECIES) { SpeciesDefinitionCompiler visitor = new SpeciesDefinitionCompiler(this, dec); speciesList = visitor.doGetDataList(); for (SpeciesData sd : speciesList) { assert sd != null; species.put(sd.getName(), sd); } } } } } private void compileFunctionalRates() throws BioPEPAException { for (Statement statement : model.statements()) { if (statement instanceof VariableDeclaration) { VariableDeclaration dec = (VariableDeclaration) statement; if (dec.getKind() == VariableDeclaration.Kind.FUNCTION) { FunctionalRateCompiler visitor = new FunctionalRateCompiler(this, VariableDeclaration.Kind.FUNCTION, dec); FunctionalRateData data = (FunctionalRateData) visitor.getData(); assert data != null; functionalRates.put(data.getName(), data); } } } } private void compileComponents() throws BioPEPAException { VariableDeclaration dec; Expression rhs; ComponentCompiler cc; ComponentData cd; for (Statement statement : model.statements()) if (statement instanceof VariableDeclaration) { dec = (VariableDeclaration) statement; if (dec.getKind() == VariableDeclaration.Kind.COMPONENT) { rhs = dec.getRightHandSide(); // looking for compositional definitions if (!(rhs instanceof Cooperation || rhs instanceof Component)) { cc = new ComponentCompiler(this, dec); cd = (ComponentData) cc.getData(); assert cd != null; components.put(cd.getName(), cd); } } } // Handle compositional declarations last to allow for checking that a // component definition exists for (Statement statement : model.statements()) if (statement instanceof VariableDeclaration) { dec = (VariableDeclaration) statement; if (dec.getKind() == VariableDeclaration.Kind.COMPONENT) { rhs = dec.getRightHandSide(); if (rhs instanceof Cooperation || rhs instanceof Component) { if (containsAnyDeclaration(dec.getName().getIdentifier())) { problemRequestor.accept(ProblemKind.DUPLICATE_USAGE, dec); throw new CompilerException(); } CompositionalVisitor visitor = new CompositionalVisitor(this); rhs.accept(visitor); String identifier = dec.getName().getIdentifier(); SystemEquationData data = new SystemEquationData(identifier, dec); data.setSystemEquationNode(visitor.getData()); compositions.put(identifier, data); } } } } private void compileSystemEquation() throws BioPEPAException { boolean foundSystemEquation = false; List<Statement> statements = model.statements(); for (Statement s : statements) { if (s instanceof ExpressionStatement) { if (!foundSystemEquation) { Expression systemEquation = ((ExpressionStatement) s).getExpression(); CompositionalVisitor v = new CompositionalVisitor(this); systemEquation.accept(v); this.systemEquation = v.result; foundSystemEquation = true; } else { problemRequestor.accept(ProblemKind.MULTIPLE_SYSTEM_EQUATIONS, s); throw new CompilerException(); } } } if (!foundSystemEquation){ problemRequestor.accept(ProblemKind.NO_SYSTEM_EQUATION, statements.get(statements.size() - 1)); } } private void compileOutWildCards() { ActionSetCompiler asc = new ActionSetCompiler(this); asc.computeWildCardSets(); } private void generateWarnings() { findUnused(variables); findUnused(compartments); // removed because species data is optional // findUnused(species); findUnused(components); findUnused(functionalRates); findUnused(compositions); } public VariableData getVariableData(String name) { return variables.get(name); } public CompiledExpression getDynamicExpression(String name) { VariableData vData = this.getVariableData(name); if (vData != null){ return vData.getValue(); } else { return null; } } public CompartmentData getCompartmentData(String name) { return compartments.get(name); } public ComponentData getComponentData(String name) { return components.get(name); } public SpeciesData getSpeciesData(String identifier) { return species.get(identifier); } public FunctionalRateData getFunctionalRate(String identifier) { return functionalRates.get(identifier); } public SystemEquationData getComposition(String name) { return compositions.get(name); } public SystemEquationNode getSystemEquation() { return systemEquation; } private void findUnused(Map<String, ?> map) { for (Map.Entry<String, ?> entry : map.entrySet()) { Data datum = (Data) entry.getValue(); if (datum.usages == 0) { this.problemRequestor.accept(ProblemInfo.Severity.INFO, ProblemKind.DEFINITION_DECLARED_BUT_NOT_USED .toString(), datum.declaration); } } } public Collection<ComponentData> getComponents(){ return components.values(); } public Map<String, FunctionalRateData> getFunctionalRateMap(){ return functionalRates; } public Collection<VariableData> getAllVariables() { return variables.values(); } public VariableData[] getDynamicVariables() { List<VariableData> list = new ArrayList<VariableData>(); for (VariableData vd : variables.values()) if (vd.isDynamic()) list.add(vd); return list.toArray(new VariableData[] {}); } public VariableData[] getStaticVariables() { List<VariableData> list = new ArrayList<VariableData>(); for (VariableData vd : variables.values()) if (!vd.isDynamic()) list.add(vd); return list.toArray(new VariableData[] {}); } void debug() { System.out.println("Variables:\n****"); for (VariableData d : variables.values()) { System.out.println(d.name + "=" + d.getValue() + " (" + d.getUsage() + ")"); } System.out.println("Compartments:\n****"); for (CompartmentData d : compartments.values()) { System.out.println(d); } System.out.println("Species:\n****"); for (SpeciesData d : species.values()) { System.out.println(d); } System.out.println("Functional Rates:\n****"); for (FunctionalRateData d : functionalRates.values()) { System.out.println(d + "(" + d.getUsage() + ")"); } System.out.println("Components:\n****"); for (ComponentData d : components.values()) { System.out.println(d); } System.out.println("System Equation:\n***"); System.out.println(systemEquation); } }