001package org.clafer.ast.analysis; 002 003import java.util.HashMap; 004import java.util.Map; 005import java.util.Set; 006import org.clafer.ast.AstAbstractClafer; 007import org.clafer.ast.AstClafer; 008import org.clafer.ast.AstConcreteClafer; 009import org.clafer.ast.AstException; 010import org.clafer.ast.Card; 011 012/** 013 * 014 * @author jimmy 015 */ 016public class GlobalCardAnalyzer implements Analyzer { 017 018 @Override 019 public Analysis analyze(Analysis analysis) { 020 Map<AstClafer, Card> globalCardMap = new HashMap<>(); 021 globalCardMap.put(analysis.getModel(), new Card(1, 1)); 022 023 for (Set<AstClafer> component : analysis.getClafersInParentAndSubOrder()) { 024 for (AstClafer clafer : component) { 025 if (clafer instanceof AstConcreteClafer) { 026 analyze((AstConcreteClafer) clafer, analysis, globalCardMap); 027 } else { 028 analyze((AstAbstractClafer) clafer, analysis, globalCardMap); 029 } 030 } 031 } 032 return analysis.setGlobalCardMap(globalCardMap); 033 } 034 035 private static void analyze(AstAbstractClafer clafer, Analysis analysis, Map<AstClafer, Card> globalCardMap) { 036 Card globalCard = new Card(0, 0); 037 for (AstClafer sub : clafer.getSubs()) { 038 Card subGlobalCard = globalCardMap.get(sub); 039 if (subGlobalCard == null) { 040 // This is possible if a child of an abstract extends the abstract. 041 // Assume the worst possible case. 042 subGlobalCard = new Card(0, analysis.getScope(sub)); 043 } 044 globalCard = globalCard.add(subGlobalCard); 045 } 046 globalCardMap.put(clafer, globalCard); 047 } 048 049 private static void analyze(AstConcreteClafer clafer, Analysis analysis, Map<AstClafer, Card> globalCardMap) { 050 Card parentGlobalCard; 051 if (!clafer.hasParent()) { 052 parentGlobalCard = new Card(1, 1); 053 } else { 054 parentGlobalCard = globalCardMap.get(clafer.getParent()); 055 if (parentGlobalCard == null) { 056 // Not analyzed yet due to cycle. 057 parentGlobalCard = new Card(0, analysis.getScope(clafer.getParent())); 058 } 059 } 060 // Cap by scope 061 Card globalCard = parentGlobalCard.mult(analysis.getCard(clafer)); 062 int scope = analysis.getScope(clafer); 063 if (scope < globalCard.getLow()) { 064 throw new AstException("Scope of " + clafer.getName() + " is " + scope + " which is too low, needs to be at least " + globalCard.getLow()); 065 } 066 globalCard = new Card( 067 globalCard.getLow(), 068 Math.min(globalCard.getHigh(), analysis.getScope(clafer))); 069 globalCardMap.put(clafer, globalCard); 070 } 071}