001    package com.hammurapi.bnf2emf;
002    
003    import java.io.File;
004    import java.io.FileReader;
005    import java.io.Reader;
006    import java.util.ArrayList;
007    import java.util.Collection;
008    import java.util.HashMap;
009    import java.util.HashSet;
010    import java.util.Map;
011    import java.util.Set;
012    
013    import org.eclipse.emf.common.util.EList;
014    import org.eclipse.emf.common.util.URI;
015    import org.eclipse.emf.ecore.EAttribute;
016    import org.eclipse.emf.ecore.EClass;
017    import org.eclipse.emf.ecore.EClassifier;
018    import org.eclipse.emf.ecore.EDataType;
019    import org.eclipse.emf.ecore.EObject;
020    import org.eclipse.emf.ecore.EPackage;
021    import org.eclipse.emf.ecore.EReference;
022    import org.eclipse.emf.ecore.EcoreFactory;
023    import org.eclipse.emf.ecore.resource.Resource;
024    import org.eclipse.emf.ecore.resource.ResourceSet;
025    import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
026    import org.eclipse.emf.ecore.util.EcoreUtil;
027    import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl;
028    
029    import antlr.ASTFactory;
030    import antlr.RecognitionException;
031    import antlr.TokenStreamException;
032    import antlr.collections.AST;
033    
034    import com.hammurapi.bnf2emf.Attribute.AttributeType;
035    
036    public class Bnf2Emf {
037            
038            private Collection<RuleDefinition> ruleDefinitions=new ArrayList<RuleDefinition>();
039            /**
040             * Keeps mapping subclass (String) -> superclass (RuleDefinition)
041             */
042            Map<String, RuleDefinition> superClasses=new HashMap<String, RuleDefinition>();
043            Map<String, Collection<RuleDefinition>> interfaces=new HashMap<String, Collection<RuleDefinition>>();
044            Map<String, RuleDefinition> rulesMap=new HashMap<String, RuleDefinition>(); // name -> rule
045            
046            void addInterface(String implementor, RuleDefinition theInterface) {
047                    Collection<RuleDefinition> interfaceCollection=interfaces.get(implementor);
048                    if (interfaceCollection==null) {
049                            interfaceCollection=new ArrayList<RuleDefinition>();
050                            interfaces.put(implementor, interfaceCollection);
051                    }
052                    interfaceCollection.add(theInterface);
053                    
054                    // Validation that no interface extends class.
055                    for (RuleDefinition rule: ruleDefinitions) {
056                            if (rule.isInterface() && !(rule.getSuperRule()==null || rule.getSuperRule().isInterface())) {
057                                    System.err.println("Interface rule "+rule.getName()+" extends class rule "+rule.getSuperClassName());
058                            }
059                    }               
060            }
061            
062            public Bnf2Emf(Reader r, String rootLanguageElementClassName) throws Bnf2EmfException {
063                    try {
064                            BnfLexer lexer=new BnfLexer(r);
065                            BnfRecognizer parser=new BnfRecognizer(lexer);
066                            ASTFactory astFactory = new ASTFactory();
067                            parser.setASTFactory(astFactory);
068                            parser.grammar();
069                            AST ast=parser.getAST();
070                            
071                            Set<String> names=new HashSet<String>();
072                            for (AST node=ast; node!=null; node=node.getNextSibling()) {
073                                    if (names.add(node.getText())) {
074                                            RuleDefinition ruleDefinition = new RuleDefinition(this, node, rootLanguageElementClassName);
075                                            ruleDefinitions.add(ruleDefinition);
076                                            rulesMap.put(ruleDefinition.getName(), ruleDefinition);
077                                    } else {
078                                            System.err.println("Rule already defined: "+node.getText());
079                                    }
080                            }                       
081                    } catch (TokenStreamException e) {
082                            throw new Bnf2EmfException(e);
083                    } catch (RecognitionException e) {
084                            throw new Bnf2EmfException(e);
085                    }
086                    
087            }
088    
089            public Collection<RuleDefinition> getRuleDefinitions() {
090                    return ruleDefinitions;
091            }
092            
093            public RuleDefinition getRuleDefinition(String name) {
094                    return rulesMap.get(name);
095            }               
096    
097            /**
098             * @param args
099             */
100            public static void main(final String[] args) throws Exception {
101                    System.out.println("Arguments: <bnf file> <root language element class name> <seed model> <output file>");
102                    if (args.length!=4) {
103                            System.err.println("Invalid number of arguments");
104                            return;
105                    }
106                    
107                    ResourceSet resourceSet = new ResourceSetImpl();
108                    
109                    resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put(
110                                    Resource.Factory.Registry.DEFAULT_EXTENSION, 
111                                    new XMIResourceFactoryImpl());
112                    
113    //              resourceSet.getPackageRegistry().put(NotationPackage.eNS_URI, NotationPackage.eINSTANCE);               
114    
115                    File file = new File(args[2]);
116                    URI uri = URI.createFileURI(file.getAbsolutePath());
117                                    
118                    Resource seed = resourceSet.getResource(uri, true);
119                    
120                    EPackage ePackage = (EPackage) EcoreUtil.copy(seed.getContents().get(0));
121                    Map<String, EClass> classMap = new HashMap<String, EClass>();
122                    Map<String, EDataType> dataTypeMap = new HashMap<String, EDataType>();
123                    
124                    for (EClassifier classifier: ePackage.getEClassifiers()) {
125                            if (classifier instanceof EClass) {
126                                    classMap.put(classifier.getName(), (EClass) classifier);
127                            } else if (classifier instanceof EDataType) {
128                                    dataTypeMap.put(classifier.getName(), (EDataType) classifier);                          
129                            }
130                    }
131                            
132                    if (classMap.get(args[1])==null) {
133                            EClass rootClass = EcoreFactory.eINSTANCE.createEClass();
134                            rootClass.setName(args[2]);
135                            ePackage.getEClassifiers().add(rootClass);
136                            classMap.put(rootClass.getName(), rootClass);
137                    }
138                    
139                    Bnf2Emf model = new Bnf2Emf(new FileReader(args[0]), args[1]);
140    
141                    // First iteration - create classes.
142                    for (RuleDefinition rd: model.getRuleDefinitions()) {
143                            if (classMap.get(rd.getName())==null) {
144                                    EClass eClass = EcoreFactory.eINSTANCE.createEClass();
145                                    eClass.setName(rd.getName());
146                                    ePackage.getEClassifiers().add(eClass);
147                                    classMap.put(eClass.getName(), eClass);
148                                    if (rd.isInterface()) {
149                                            eClass.setInterface(true);
150                                            eClass.setAbstract(true);
151                                    }
152                            }
153                    }
154                    
155                    // Second iteration - establish references, create attributes.
156                    // TODO - Handle factories.
157                    for (RuleDefinition rd: model.getRuleDefinitions()) {
158                            EClass eClass = classMap.get(rd.getName());
159                            if (!rd.isInterface()) {
160                                    String superClassName = rd.getSuperClassName();
161                                    if (superClassName!=null && superClassName.trim().length()!=0) {
162                                            EClass superClass = classMap.get(superClassName);
163                                            if (superClass==null) {
164                                                    throw new NullPointerException("Superclass "+superClassName+" for class "+rd.getName()+" not found in the model.");
165                                            }
166                                            if (!eClass.getESuperTypes().contains(superClass)) {
167                                                    eClass.getESuperTypes().add(superClass);
168                                            }
169                                    }
170                                    for (String ii: rd.getImplements()) {
171                                            EClass iClass = classMap.get(ii);
172                                            if (!eClass.getESuperTypes().contains(iClass)) {
173                                                    eClass.getESuperTypes().add(iClass);
174                                            }
175                                    }
176                            }
177                            
178                            for (Attribute attr: rd.getAttributes()) {
179                                    if (eClass.getEStructuralFeature(attr.getName())==null) {
180                                            switch (attr.getAttributeType()) {
181                                            case ATTRIBUTE:
182                                                    // If type name resolves to data type - create attribute, otherwise create reference.
183                                                    EDataType dataType = dataTypeMap.get(attr.getType());
184                                                    if (dataType!=null) {
185                                                            EAttribute eAttr = EcoreFactory.eINSTANCE.createEAttribute();
186                                                            eClass.getEStructuralFeatures().add(eAttr);
187                                                            eAttr.setName(decapitalize(attr.getName()));
188                                                            eAttr.setEType(dataType);
189                                                            if (attr.isList()) {
190                                                                    eAttr.setUpperBound(-1);
191                                                            }
192                                                            break;
193                                                    }
194                                            case REFERENCE:
195                                                    EReference ref = EcoreFactory.eINSTANCE.createEReference();
196                                                    ref.setName(decapitalize(attr.getName()));
197                                                    String typeName = "_root".equals(attr.getType()) ? args[2] : attr.getType();
198                                                    EClass otherEnd = classMap.get(typeName);
199                                                    if (otherEnd==null) {
200                                                            throw new Bnf2EmfException("Class not found in the model: "+typeName);
201                                                    }
202                                                    ref.setEType(otherEnd);
203                                                    eClass.getEStructuralFeatures().add(ref);
204                                                    
205                                                    if (attr.isList()) {
206                                                            ref.setUpperBound(-1);
207                                                    }
208                                                    
209                                                    ref.setContainment(attr.getAttributeType()==AttributeType.ATTRIBUTE);
210                                                    
211                                                    if (attr.getOpposite()!=null) {                                 
212                                                            EReference opposite = EcoreFactory.eINSTANCE.createEReference();
213                                                            opposite.setContainment(attr.getOpposite().getAttributeType()==AttributeType.ATTRIBUTE);                                                        
214                                                            opposite.setName(decapitalize(attr.getOpposite().getName()));
215                                                            opposite.setEType(eClass);
216                                                            otherEnd.getEStructuralFeatures().add(opposite);
217                                                            if (attr.getOpposite().isList()) {
218                                                                    opposite.setUpperBound(-1);
219                                                            }                                                       
220                                                            
221                                                            ref.setEOpposite(opposite);
222                                                            opposite.setEOpposite(ref);
223                                                    }
224                                            }
225                                    }
226                            }
227                    }
228                    
229                    URI outUri = URI.createFileURI(new File(args[3]).getAbsolutePath());
230                    Resource outResource = resourceSet.createResource(outUri);
231                    EList<EObject> contents = outResource.getContents();
232                    contents.add(ePackage);
233                    outResource.save(null);
234                    
235            }
236    
237            private static String decapitalize(String str) {
238                    return str.substring(0,1).toLowerCase()+str.substring(1);
239            }
240    
241    }