/** * Copyright 2004-2016 Riccardo Solmi. All rights reserved. * This file is part of the Whole Platform. * * The Whole Platform is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * The Whole Platform is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with the Whole Platform. If not, see <http://www.gnu.org/licenses/>. */ package org.whole.lang.grammars.visitors; import java.util.HashMap; import java.util.Map; import org.whole.lang.commons.factories.CommonsEntityAdapterFactory; import org.whole.lang.factories.IEntityBuilder; import org.whole.lang.grammars.model.As; import org.whole.lang.grammars.model.DataType; import org.whole.lang.grammars.model.Grammar; import org.whole.lang.grammars.model.LanguageDescriptor; import org.whole.lang.grammars.model.Name; import org.whole.lang.grammars.model.NonTerminal; import org.whole.lang.grammars.model.Production; import org.whole.lang.grammars.model.Productions; import org.whole.lang.grammars.model.Repeat; import org.whole.lang.grammars.model.Rule; import org.whole.lang.grammars.model.Template; import org.whole.lang.grammars.model.When; import org.whole.lang.grammars.reflect.GrammarsEntityDescriptorEnum; import org.whole.lang.grammars.util.GrammarsUtils; import org.whole.lang.iterators.AbstractPatternFilterIterator; import org.whole.lang.iterators.IEntityIterator; import org.whole.lang.iterators.IteratorFactory; import org.whole.lang.iterators.ScannerIterator; import org.whole.lang.matchers.Matcher; import org.whole.lang.model.IEntity; import org.whole.lang.models.factories.ModelsEntityFactory; import org.whole.lang.models.model.ComponentModifierEnum; import org.whole.lang.models.model.CompositeEntity; import org.whole.lang.models.model.DataEntity; import org.whole.lang.models.model.EntityModifierEnum; import org.whole.lang.models.model.EnumEntity; import org.whole.lang.models.model.EnumValues; import org.whole.lang.models.model.Feature; import org.whole.lang.models.model.FeatureModifierEnum; import org.whole.lang.models.model.Features; import org.whole.lang.models.model.Model; import org.whole.lang.models.model.ModelDeclaration; import org.whole.lang.models.model.ModelDeclarations; import org.whole.lang.models.model.SimpleEntity; import org.whole.lang.models.model.SimpleName; import org.whole.lang.models.model.Types; import org.whole.lang.models.reflect.ModelsEntityDescriptorEnum; import org.whole.lang.models.reflect.ModelsFeatureDescriptorEnum; import org.whole.lang.operations.NormalizerOperation; import org.whole.lang.reflect.EntityDescriptor; import org.whole.lang.util.EntityUtils; /** * @author Riccardo Solmi, Enrico Persiani */ public class Grammars2ModelsVisitor extends GrammarsTraverseAllVisitor { private ModelDeclarations modelDeclarations; private Map<String, ModelDeclaration> declarationMap = new HashMap<String, ModelDeclaration>(); // entityName -> ModelDeclaration private Map<String, Production> productionMap = new HashMap<String, Production>(); // ntName -> Production private Map<String, Production> lexiconMap = new HashMap<String, Production>(); // ntName -> Production private String name; protected boolean normalizeGrammar; public Grammars2ModelsVisitor(boolean normalizeGrammar) { this.normalizeGrammar = normalizeGrammar; } protected boolean isLexicalNonTerminal(NonTerminal nt) { return lexiconMap.keySet().contains(nt.getValue()); } protected Grammar normalize(Grammar grammar) { if (normalizeGrammar) { grammar = EntityUtils.clone(grammar); NormalizerOperation.normalize(grammar); } return grammar; } @Override public void visit(Grammar entity) { entity = normalize(entity); IEntityIterator<Production> lexiconIiterator = IteratorFactory.<Production>childIterator(); lexiconIiterator.reset(entity.getLexicalStructure()); for (Production p : lexiconIiterator) lexiconMap.put(p.getName().getValue(), p); LanguageDescriptor ld = (LanguageDescriptor) entity.getTargetLanguage(); ModelsEntityFactory mf = ModelsEntityFactory.instance; Model model = mf.createModel( mf.createSimpleName(ld.getName().getValue()), mf.createTypeRelations(), modelDeclarations = mf.createModelDeclarations(), mf.createNamespace(ld.getNamespace().getValue()), EntityUtils.isResolver(ld.getVersion()) ? CommonsEntityAdapterFactory.createResolver(ModelsEntityDescriptorEnum.Version) : mf.createVersion(ld.getVersion().getValue()), mf.createURI(ld.getUri().getValue())); entity.getPhraseStructure().accept(this); setResult(model); } @Override public void visit(Productions entity) { ModelsEntityFactory mf = ModelsEntityFactory.instance; ScannerIterator<Production> i = IteratorFactory.<Production>childScannerIterator(); i.reset(entity); for (Production p : i) { String eName = getMappedEntityName(p); ModelDeclaration mDecl = CommonsEntityAdapterFactory.createResolver(ModelsEntityDescriptorEnum.ModelDeclaration); productionMap.put(p.getName().getValue(), p); declarationMap.put(eName, mDecl); modelDeclarations.wAdd(mDecl); mDecl.setModifiers(mf.createEntityModifiers()); mDecl.setName(mf.createSimpleName(eName)); mDecl.setTypes(mf.createTypes()); } super.visit(entity); } @Override public void visit(Production entity) { ModelsEntityFactory mf = ModelsEntityFactory.instance; String eName = getMappedEntityName(entity); Rule rule = entity.getRule(); AbstractPatternFilterIterator<Rule> ruleIterator = IteratorFactory.<Rule>descendantOrSelfMatcherIterator().withPattern(GrammarsEntityDescriptorEnum.Rule); ruleIterator.reset(rule); while (ruleIterator.hasNext()) { rule = ruleIterator.next(); switch (rule.wGetEntityOrd()) { // map productions with a single lexical non-terminal as data entities case GrammarsEntityDescriptorEnum.NonTerminal_ord: if (!isLexicalNonTerminal((NonTerminal) rule) || !EntityUtils.hasParent(rule) || !Matcher.match(GrammarsEntityDescriptorEnum.Production, rule.wGetParent()) || !Matcher.match(GrammarsEntityDescriptorEnum.DataTerminal, lexiconMap.get(((NonTerminal) rule).getValue()).getRule())) break; case GrammarsEntityDescriptorEnum.DataTerminal_ord: DataEntity de = getModelDeclaration(eName, ModelsEntityDescriptorEnum.DataEntity); Template template = entity.getTemplate(); if (Matcher.matchImpl(GrammarsEntityDescriptorEnum.DataType, template)) de.getDataType().wSetValue(GrammarsUtils.getDataType((DataType) template)); else if (Matcher.matchImpl(GrammarsEntityDescriptorEnum.CustomDataType, template)) de.getDataType().wSetValue(template.wStringValue()); return; case GrammarsEntityDescriptorEnum.Choose_ord: boolean isPolymorphic = false; AbstractPatternFilterIterator<NonTerminal> ruleIterator2 = IteratorFactory.<NonTerminal>descendantOrSelfMatcherIterator() .withPattern(GrammarsEntityDescriptorEnum.NonTerminal); ruleIterator2.reset(rule); for (NonTerminal nt2 : ruleIterator2) if (!isLexicalNonTerminal(nt2)) { ensureType(getModelDeclaration(getMappedEntityName(nt2)).getTypes(), eName); isPolymorphic = true; } if (isPolymorphic) { SimpleEntity se = getModelDeclaration(eName, ModelsEntityDescriptorEnum.SimpleEntity); se.getModifiers().wAdd(mf.createEntityModifier(EntityModifierEnum._abstract)); return; } else if (!rule.wIsEmpty() && Matcher.match(GrammarsEntityDescriptorEnum.As, rule.wGet(0))) { EnumEntity ee = getModelDeclaration(eName, ModelsEntityDescriptorEnum.EnumEntity); EnumValues enumValues = ModelsEntityFactory.instance.createEnumValues(0); AbstractPatternFilterIterator<As> ruleIterator3 = IteratorFactory.<As>descendantOrSelfMatcherIterator() .withPattern(GrammarsEntityDescriptorEnum.As); ruleIterator3.reset(rule); for (As as : ruleIterator3) enumValues.wAdd(ModelsEntityFactory.instance.createEnumValue(as.getName().getValue())); ee.setValues(enumValues); return; } // while (ruleIterator.skipTo(GrammarsEntityDescriptorEnum.NonTerminal)) { // NonTerminal nt = ruleIterator.next(GrammarsEntityDescriptorEnum.NonTerminal); // ensureType(getModelDeclaration(getMappedEntityName(nt)).getTypes(), eName); // } break; case GrammarsEntityDescriptorEnum.Repeat_ord: if (ruleIterator.skipTo(GrammarsEntityDescriptorEnum.NonTerminal)) { //FIXME wrongly assumes that the separator, if present, is a lexical token if (!EntityUtils.isResolver(((Repeat) rule).getSeparator())) {//if (Matcher.matchImpl(GrammarsEntityDescriptorEnum.NonTerminal, ((Repeat) rule).getSeparator())) { ruleIterator.next(); ruleIterator.skipTo(GrammarsEntityDescriptorEnum.NonTerminal); } NonTerminal nt = null; AbstractPatternFilterIterator<NonTerminal> ruleIterator4 = IteratorFactory.<NonTerminal>descendantOrSelfMatcherIterator() .withPattern(GrammarsEntityDescriptorEnum.NonTerminal); ruleIterator4.reset(rule); for (NonTerminal nt2 : ruleIterator4) if (!isLexicalNonTerminal(nt2)) { nt = nt2; break; } //FIXME after normalization, component type can be polymorphic // by now we assume that the separator, if present, is a lexical token if (nt == null) break; // the above statements replace this code, allowing lexical Repeat rule // NonTerminal nt = ruleIterator.next(GrammarsEntityDescriptorEnum.NonTerminal); // while (isLexicalNonTerminal(nt)) { // nt = ruleIterator.next(GrammarsEntityDescriptorEnum.NonTerminal); // } CompositeEntity ce = getModelDeclaration(eName, ModelsEntityDescriptorEnum.CompositeEntity); ce.setComponentType(mf.createSimpleName(getMappedEntityName(nt))); ce.getComponentModifiers().wAdd(mf.createComponentModifier(ComponentModifierEnum.ordered)); } return; case GrammarsEntityDescriptorEnum.As_ord: As asRule = (As) rule; // normalization invariants assure that this branch is unreachable // if (Matcher.match(GrammarsEntityDescriptorEnum.LiteralTerminal, asRule.getRule())) { // EnumEntity ee = getModelDeclaration(eName, ModelsEntityDescriptorEnum.EnumEntity); // // ee.getValues().wAdd(mf.createEnumValue(getMappedName(asRule))); // // while (ruleIterator.skipTo(GrammarsEntityDescriptorEnum.As)) { // rule = ruleIterator.next(GrammarsEntityDescriptorEnum.As); // asRule = (As) rule; // // ee.getValues().wAdd(mf.createEnumValue(getMappedName(asRule))); // } // } else { SimpleEntity se = getModelDeclaration(eName, ModelsEntityDescriptorEnum.SimpleEntity); Features features = se.getFeatures(); ensureFeature(features, ruleIterator, asRule); while (ruleIterator.hasNext()) { rule = ruleIterator.next(); switch (rule.wGetEntityOrd()) { case GrammarsEntityDescriptorEnum.As_ord: asRule = (As) rule; ensureFeature(features, ruleIterator, asRule); break; // normalization invariants assure that this branch is unreachable (choose rules nested into as rules always become fresh productions) // case GrammarsEntityDescriptorEnum.Choose_ord: // ruleIterator.prune(); // // se.getModifiers().wAdd(mf.createEntityModifier(EntityModifierEnum._abstract)); // // for (NonTerminal nt2 : IteratorFactory.<NonTerminal>topDownMatcherIterator(rule).usePattern(GrammarsEntityDescriptorEnum.NonTerminal)) // ensureType(getModelDeclaration(getMappedEntityName(nt2)).getTypes(), eName); } } // } return; case GrammarsEntityDescriptorEnum.Concatenate_ord: break; } } getModelDeclaration(eName, ModelsEntityDescriptorEnum.SimpleEntity); } @Override public void visit(Name entity) { name = entity.getValue(); } @Override public void visit(NonTerminal entity) { name = entity.getValue(); } protected void ensureType(Types types, String typeName) { AbstractPatternFilterIterator<SimpleName> i = IteratorFactory.<SimpleName>childMatcherIterator() .withPattern(ModelsEntityDescriptorEnum.SimpleName); i.reset(types); for (SimpleName type : i) if (typeName.equals(type.getValue())) return; types.wAdd(ModelsEntityFactory.instance.createSimpleName(typeName)); } protected void ensureFeature(Features features, IEntityIterator<Rule> ruleIterator, As asRule) { String featureName = getMappedName(asRule); AbstractPatternFilterIterator<Feature> i = IteratorFactory.<Feature>childMatcherIterator() .withPattern(ModelsEntityDescriptorEnum.Feature); i.reset(features); for (Feature feature : i) if (featureName.equals(feature.getName().getValue())) return; features.wAdd(createFeature(ruleIterator, featureName)); } protected Feature createFeature(IEntityIterator<Rule> ruleIterator, String featureName) { ModelsEntityFactory mf = ModelsEntityFactory.instance; IEntityBuilder<Feature> fb = mf.buildFeature(); fb.set(ModelsFeatureDescriptorEnum.name, featureName); while (ruleIterator.hasNext()) { Rule rule = ruleIterator.next(); switch (rule.wGetEntityOrd()) { // case GrammarsEntityDescriptorEnum.Optional_ord: // fb.set(ModelsFeatureDescriptorEnum.modifiers, // mf.createFeatureModifiers( // mf.createFeatureModifier(FeatureModifierEnum.optional))); // break; case GrammarsEntityDescriptorEnum.When_ord: When when = (When) rule; ((AbstractPatternFilterIterator<Rule>) ruleIterator).skipTo(when.getRule()); break; case GrammarsEntityDescriptorEnum.NonTerminal_ord: if (isLexicalNonTerminal((NonTerminal) rule) && EntityUtils.hasParent(rule) && Matcher.match(GrammarsEntityDescriptorEnum.Concatenate, rule.wGetParent())) break; fb.set(ModelsFeatureDescriptorEnum.type, mf.createSimpleName(getMappedEntityName((NonTerminal) rule))); IEntity ancestor = null; IEntityIterator<IEntity> iterator = IteratorFactory.ancestorIterator(); iterator.reset(Matcher.findAncestor(GrammarsEntityDescriptorEnum.As, rule)); while (iterator.hasNext() && !Matcher.match(GrammarsEntityDescriptorEnum.Production, ancestor = iterator.next())) if (Matcher.match(GrammarsEntityDescriptorEnum.Optional, ancestor)) fb.set(ModelsFeatureDescriptorEnum.modifiers, mf.createFeatureModifiers( mf.createFeatureModifier(FeatureModifierEnum.optional))); return fb.getResult(); } } throw new IllegalArgumentException("Missing NonTerminal"); } protected String getMappedName(As as) { as.getName().accept(this); return name; } protected String getMappedEntityName(NonTerminal nt) { return getMappedEntityName(productionMap.get(nt.getValue())); } protected String getMappedEntityName(Production production) { return production.getName().getValue();//FIXME use template } protected ModelDeclaration getModelDeclaration(String name) { return declarationMap.get(name); } protected <T extends ModelDeclaration> T getModelDeclaration(String name, EntityDescriptor<T> ed) { ModelDeclaration e = declarationMap.get(name); T result = e.wResolveWith(ed); if (result != e) declarationMap.put(name, result); return result; } }