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 }