    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    }