/** * 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.Collection; import java.util.HashMap; import java.util.Map; import java.util.regex.Pattern; import org.whole.lang.grammars.codebase.GrammarsRegistry; import org.whole.lang.grammars.model.CompiledPattern; import org.whole.lang.grammars.model.DataTerminal; import org.whole.lang.grammars.model.Grammar; import org.whole.lang.grammars.model.NonTerminal; import org.whole.lang.grammars.model.Production; import org.whole.lang.grammars.model.Rule; import org.whole.lang.grammars.reflect.GrammarsEntityDescriptorEnum; import org.whole.lang.grammars.util.GrammarsUtils; import org.whole.lang.iterators.IEntityIterator; import org.whole.lang.iterators.IteratorFactory; import org.whole.lang.matchers.Matcher; import org.whole.lang.model.IEntity; import org.whole.lang.operations.IDecorationManager; import org.whole.lang.operations.ValidatorOperation; import org.whole.lang.reflect.EntityDescriptor; import org.whole.lang.reflect.EntityDescriptorEnum; import org.whole.lang.reflect.EntityKinds; import org.whole.lang.reflect.ILanguageKit; import org.whole.lang.reflect.ReflectionFactory; import org.whole.lang.util.DataTypeUtils; import org.whole.lang.util.EntityUtils; import org.whole.lang.visitors.GenericIdentityVisitor; /** * @author Enrico Persiani */ public class GenericGrammarBasedValidatorVisitor extends GenericIdentityVisitor { public GenericGrammarBasedValidatorVisitor() { } private IDecorationManager decorationManager; public IDecorationManager getDecorationManager() { if (decorationManager == null) decorationManager = ((ValidatorOperation) getOperation()).getDecorationManager(); return decorationManager; } protected DataTerminal getDataTerminal(EntityDescriptor<?> ed) { return dataTerminals.get(ed); } protected void validateDataTerminal(IEntity entity) { EntityDescriptor<?> ed = entity.wGetEntityDescriptor(); if (ed.getDataKind().isEnumValue()) return; String value = DataTypeUtils.getAsPersistenceString(entity); DataTerminal dataTerminal = getDataTerminal(ed); if (dataTerminal != null) { Pattern pattern = ((CompiledPattern) dataTerminal.getPattern()).getValue(); if (!pattern.matcher(value).matches()) getDecorationManager().addError(entity, "the data entity doesn't match the pattern: "+pattern.toString(), EntityUtils.getLocation(entity)); } else getDecorationManager().addError(entity, "the data entity is unknonwn", EntityUtils.getLocation(entity)); } private Map<EntityDescriptor<?>, DataTerminal> dataTerminals; private void calculateDataTerminals(Grammar grammar) { this.dataTerminals = new HashMap<EntityDescriptor<?>, DataTerminal>(); //TODO ensure grammar normalized Map<String, Rule> productions = new HashMap<String, Rule>(); IEntityIterator<Production> pi = IteratorFactory.<Production>childIterator(); pi.reset(grammar.getPhraseStructure()); for (Production p : pi) productions.put(p.getName().getValue(), p.getRule()); Map<String, Rule> lexicon = new HashMap<String, Rule>(); IEntityIterator<Production> li = IteratorFactory.<Production>childIterator(); li.reset(grammar.getLexicalStructure()); for (Production p : li) lexicon.put(p.getName().getValue(), p.getRule()); ILanguageKit languageKit = ReflectionFactory.getLanguageKit(GrammarsUtils.getLanguageURI(grammar), false, null); EntityDescriptorEnum edEnum = languageKit.getEntityDescriptorEnum(); for (EntityDescriptor<?> ed : edEnum) if (EntityUtils.isData(ed)) { Rule production = productions.get(ed.getName()); if(!ed.getDataKind().isEnumValue()) { DataTerminal dataTerminal = Matcher.find(GrammarsEntityDescriptorEnum.DataTerminal, production, false); if (dataTerminal == null) { NonTerminal nonTerminal = Matcher.find(GrammarsEntityDescriptorEnum.NonTerminal, production, false); dataTerminal = Matcher.find(GrammarsEntityDescriptorEnum.DataTerminal, lexicon.get(nonTerminal.getValue()), false); } dataTerminals.put(ed, EntityUtils.clone(dataTerminal)); } } } @Override public void visit(IEntity entity) { Collection<Grammar> grammars = GrammarsRegistry.instance().getGrammarsFor(entity); if (grammars.isEmpty()) throw new IllegalArgumentException("cannot find a suitable grammar to unparse the entity"); Grammar grammar = grammars.iterator().next(); calculateDataTerminals(grammar); IEntityIterator<IEntity> iterator = IteratorFactory.descendantOrSelfMatcherIterator().withPattern(EntityKinds.DATA); iterator.reset(entity); while (iterator.hasNext()) validateDataTerminal(iterator.next()); } }