/* * Reference ETL Parser for Java * Copyright (c) 2000-2009 Constantine A Plotnikov * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package net.sf.etl.parsers.internal.term_parser.flattened; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.ListIterator; import java.util.Map; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import net.sf.etl.parsers.internal.term_parser.flattened.DirectedAcyclicGraph.DefinitionGatherer; import net.sf.etl.parsers.internal.term_parser.flattened.DirectedAcyclicGraph.ImportDefinitionGatherer; import net.sf.etl.parsers.internal.term_parser.flattened.DirectedAcyclicGraph.Node; import net.sf.etl.parsers.internal.term_parser.grammar.Associativity; import net.sf.etl.parsers.internal.term_parser.grammar.Context; import net.sf.etl.parsers.internal.term_parser.grammar.ContextImport; import net.sf.etl.parsers.internal.term_parser.grammar.ContextInclude; import net.sf.etl.parsers.internal.term_parser.grammar.ContextMember; import net.sf.etl.parsers.internal.term_parser.grammar.Element; import net.sf.etl.parsers.internal.term_parser.grammar.RefOp; import net.sf.etl.parsers.internal.term_parser.grammar.SyntaxDefinition; import net.sf.etl.parsers.internal.term_parser.grammar.Wrapper; /** * This is a view of context belonging to grammar * * @author const * */ public class ContextView { /** this is gather of imports by grammar include direction */ private static final IncludeGathererByGrammarInclude INCLUDE_GATHERER_BY_GRAMMAR_INCLUDE = new IncludeGathererByGrammarInclude(); /** this is gather of imports by grammar include direction */ private static final IncludeGathererByContextInclude INCLUDE_GATHERER_BY_CONTEXT_INCLUDE = new IncludeGathererByContextInclude(); /** this is gather of imports by grammar include direction */ private static final ImportGathererByGrammarInclude IMPORT_GATHERER_BY_GRAMMAR_INCLUDE = new ImportGathererByGrammarInclude(); /** this is gather of definitions by grammar include direction */ private static final DefinitionGrathererByGrammarInclude DEFINITION_GATHERER_BY_GRAMMAR_INCLUDE = new DefinitionGrathererByGrammarInclude(); /** this is gather of imports by grammar include direction */ private static final ImportGathererByContextInclude IMPORT_GATHERER_BY_CONTEXT_INCLUDE = new ImportGathererByContextInclude(); /** this is gather of definitions by grammar include direction */ private static final DefinitionGrathererByContextInclude DEFINITION_GATHERER_BY_CONTEXT_INCLUDE = new DefinitionGrathererByContextInclude(); /** * A tree map from precedence to level view object */ private final SortedMap<Integer, OpLevel> operatorLevels = new TreeMap<Integer, OpLevel>(); /** * Attributes specification for context */ private AttributesView attributes; /** * Documentation specification for context */ private DocumentationView documentation; /** * Statements defined in the context */ private final HashSet<StatementView> statements = new HashSet<StatementView>(); /** * Map from name to definition */ private final HashMap<String, DefView> defs = new HashMap<String, DefView>(); /** DAG node in context include hierarchy */ private final Node<ContextView> contextIncludesNode; /** Map from included context name to context include views */ private final Map<String, ContextIncludeView> contextIncludes = new HashMap<String, ContextIncludeView>(); /** DAG node in context include along with grammar include hierarchy */ private final Node<ContextView> grammarIncludesNode; /** a map that contains imports. key is local name of context */ private final Map<String, ContextImportView> imports = new HashMap<String, ContextImportView>(); /** a map that definitions. key is name of definition. */ private final Map<String, DefinitionView> definitions = new HashMap<String, DefinitionView>(); /** * A context name */ private final String name; /** * A grammar view for this context view */ private final GrammarView grammar; /** * A context object for this context view. It may be null for inherited * contexts. */ private final Context context; /** * A context object for this context view. On which errors are reported. If * there are no real context object, a fake on is created and positioned at * the end of the grammar. */ private final Element reportingContext; /** * A constructor for view * * @param context * a context that is wrapped by this view. It may be null in case * if grammar does not have a view defined. * @param grammar * a grammar view that contains this context view * @param name * a name of context * @param contextGrammarIncludes * a context grammar include graph * @param contextContextIncludes * a context content include graph */ public ContextView(GrammarView grammar, String name, Context context, DirectedAcyclicGraph<ContextView> contextGrammarIncludes, DirectedAcyclicGraph<ContextView> contextContextIncludes) { super(); this.context = context; this.grammar = grammar; this.name = name; this.grammarIncludesNode = contextGrammarIncludes.getNode(this); this.contextIncludesNode = contextContextIncludes.getNode(this); if (context != null) { reportingContext = context; } else { reportingContext = grammar.getGrammar(); } } /** * gather content from context */ private void loadContent() { assert context != null; for (final ContextMember m : context.content) { if (m instanceof ContextInclude) { final ContextInclude ci = (ContextInclude) m; final ContextView referencedContext = grammar .context(ci.contextName); if (referencedContext == null) { error(ci, "grammar.Context.ContextInclude.missingContext", ci.contextName); continue; } // check if duplicate include if (contextIncludes.containsKey(referencedContext.name())) { error(ci, "grammar.Context.ContextInclude.duplicateInclude", ci.contextName); continue; } // create wrapper link WrapperLink wrapperLink = null; for (final ListIterator<Wrapper> j = ci.wrappers .listIterator(ci.wrappers.size()); j.hasPrevious();) { final Wrapper w = j.previous(); final String name = w.object.name; final String prefix = w.object.prefix; final String property = w.property; if (name != null && prefix != null && property != null) { final String namespace = grammar.namespace(prefix); if (namespace == null) { error(w, "grammar.Wrapper.undefinedWrapperPrefix", prefix); continue; } else { wrapperLink = new WrapperLink(wrapperLink, namespace, name, property); } } else { // there were syntax error continue; } } contextIncludes.put(referencedContext.name(), new ContextIncludeView(ci, this, referencedContext, wrapperLink)); } else if (m instanceof ContextImport) { final ContextImport ci = (ContextImport) m; final GrammarView referencedGrammar; if (ci.grammarName == null) { referencedGrammar = grammar; } else { referencedGrammar = grammar .getImportedGrammar(ci.grammarName); if (referencedGrammar == null) { error( ci, "grammar.Context.ContextImport.missingGrammarImport", ci.grammarName); continue; } } final ContextView referencedContext = referencedGrammar .context(ci.contextName); if (referencedContext == null) { if (referencedGrammar == grammar) { error(ci, "grammar.Context.ContextImport.missingContext", ci.contextName); } else { error( ci, "grammar.Context.ContextImport.missingContextInGrammar", ci.contextName, referencedGrammar.getSystemId()); } continue; } if (imports.containsKey(ci.localName)) { error(ci, "grammar.Context.ContextImport.duplicateImport", ci.contextName); continue; } final ContextImportView view = new ContextImportView(ci, this, referencedContext); imports.put(view.localName(), view); } else if (m instanceof SyntaxDefinition) { final SyntaxDefinition def = (SyntaxDefinition) m; if (definitions.containsKey(def.name)) { error(def, "grammar.Context.Definition.duplicateDefinition", def.name); continue; } definitions.put(def.name, DefinitionView.get(this, def)); } else { assert false : "Unknown type of context content" + m.getClass().getCanonicalName(); } } } /** * @return name of context */ public String name() { return name; } /** * Associate this context with context from parent grammar * * @param pgc * a context from parent grammar */ public void processGrammarInclude(ContextView pgc) { // add parent along with grammar include path final boolean rc = grammarIncludesNode .addParentNode(pgc.grammarIncludesNode); assert rc : "It is assumed that adding parent will never fail " + "because graph following grammar include hierarchy " + "that already does not have cycles"; } /** * Report non fatal grammar error * * @param errorId * error identifier * @param arg1 * error argument * @param arg2 * error argument */ public void error(String errorId, Object arg1, Object arg2) { error(reportingContext, errorId, arg1, arg2); } /** * Report non fatal grammar error * * @param errorId * error identifier * @param arg1 * error argument * @param arg2 * error argument * @param arg3 * error argument */ public void error(String errorId, Object arg1, Object arg2, Object arg3) { error(reportingContext, errorId, arg1, arg2, arg3); } /** * Report non fatal grammar error * * @param errorId * error identifier * @param args * error arguments */ public void error(String errorId, Object args[]) { error(reportingContext, errorId, args); } /** * Report non fatal grammar error * * @param errorId * error identifier * @param arg1 * error argument */ public void error(String errorId, Object arg1) { error(reportingContext, errorId, arg1); } /** * Report non fatal grammar error * * @param errorId * error identifier */ public void error(String errorId) { error(reportingContext, errorId); } /** * Report non fatal grammar error * * @param e * element in error * @param errorId * error identifier * @param arg1 * error argument * @param arg2 * error argument */ public void error(Element e, String errorId, Object arg1, Object arg2) { grammar.error(e, errorId, arg1, arg2); } /** * Report non fatal grammar error * * @param e * element in error * @param errorId * error identifier * @param arg1 * error argument * @param arg2 * error argument * @param arg3 * error argument */ public void error(Element e, String errorId, Object arg1, Object arg2, Object arg3) { grammar.error(e, errorId, arg1, arg2, arg3); } /** * Report non fatal grammar error * * @param e * element in error * @param errorId * error identifier * @param arg1 * error argument */ public void error(Element e, String errorId, Object arg1) { grammar.error(e, errorId, arg1); } /** * Report non fatal grammar error * * @param e * element in error * @param errorId * error identifier * @param args * error arguments */ public void error(Element e, String errorId, Object args[]) { grammar.error(e, errorId, args); } /** * Report non fatal grammar error * * @param e * element in error * @param errorId * error identifier */ public void error(Element e, String errorId) { grammar.error(e, errorId); } /** * Gather content according to grammar include hierarchy */ public void implementGrammarInclude() { if (context != null) { // load content of this context loadContent(); } INCLUDE_GATHERER_BY_GRAMMAR_INCLUDE.gatherDefinitions(this); // finalize includes for (final Iterator<ContextIncludeView> i = contextIncludes.values() .iterator(); i.hasNext();) { final ContextIncludeView civ = i.next(); if (!contextIncludesNode .addParentNode(civ.referencedContext().contextIncludesNode)) { Element e; if (civ.originalDefinition().definingContext() == this) { // if definied in this context e = civ.contextIncludeElement(); } else { e = reportingContext; } error(e, "grammar.Context.ContextInclude.cyclicContextInclude", civ.referencedContext().name()); continue; } } IMPORT_GATHERER_BY_GRAMMAR_INCLUDE.gatherDefinitions(this); DEFINITION_GATHERER_BY_GRAMMAR_INCLUDE.gatherDefinitions(this); } /** * implement context include */ public void implementContextInclude() { INCLUDE_GATHERER_BY_CONTEXT_INCLUDE.gatherDefinitions(this); IMPORT_GATHERER_BY_CONTEXT_INCLUDE.gatherDefinitions(this); DEFINITION_GATHERER_BY_CONTEXT_INCLUDE.gatherDefinitions(this); } /** * @return grammar that holds this context */ public GrammarView grammar() { return grammar; } /** * @return true if wrapped context is abstract */ public boolean isDefault() { return context != null && context.defaultModifier != null; } /** * This method sorts definitions by categories */ public void sortDefinitionsByCategories() { assert !isAbstract() : "This method should not be called for abstract contexts"; for (final ContextImportView v : imports.values()) { if (v.referencedContext().isAbstract()) { if (v.definingContext() == this) { error( v.definition(), "grammar.Context.ContextImport.nonAbstractContextImportsAbstractContext", v.localName(), v.referencedContext().grammar() .getSystemId(), v.referencedContext() .name()); } else { error( "grammar.Context.ContextImport.includedImportsAbstractContext", new Object[] { name(), v.definingContext().grammar().getSystemId(), v.definingContext().name(), v.localName(), v.referencedContext().grammar() .getSystemId(), v.referencedContext().name() }); } } } members: for (final Iterator<DefinitionView> i = definitions.values() .iterator(); i.hasNext();) { final DefinitionView m = i.next(); if (m instanceof OpDefinitionView) { final OpDefinitionView op = (OpDefinitionView) m; final Associativity associativity = op.associativity(); if (associativity == null) { // the definition is invalid. there likely were a parse // error. So nothing is reported here. continue members; } final Integer precedence = op.precedence(); OpLevel level = operatorLevels.get(precedence); if (level == null) { level = new OpLevel(); level.precedence = precedence.intValue(); operatorLevels.put(precedence, level); } if (Associativity.F != associativity && 0 == precedence.intValue()) { error( op.definition(), "grammar.Context.OperatorDefinition.wrongPrecedenceAssociativity", precedence, associativity); continue members; } switch (associativity) { case F: level.f.add(op); break; case FX: level.fx.add(op); break; case FY: level.fy.add(op); break; case YF: level.yf.add(op); break; case YFX: level.yfx.add(op); break; case XF: level.xf.add(op); break; case XFX: level.xfx.add(op); break; case XFY: level.xfy.add(op); break; case YFY: level.yfy.add(op); break; default: throw new RuntimeException( "[BUG] Unsupported precedence level: " + associativity); } } else if (m instanceof AttributesView) { final AttributesView view = (AttributesView) m; if (attributes == null) { attributes = view; } else { error("grammar.Context.multipleAttributesSpecifications", attributes.definition().name, view.definition().name); continue members; } } else if (m instanceof DocumentationView) { final DocumentationView view = (DocumentationView) m; if (documentation == null) { documentation = view; } else { error( "grammar.Context.multipleDocumentationSpecifications", documentation.definition().name, view.definition().name); continue members; } } else if (m instanceof StatementView) { final StatementView view = (StatementView) m; statements.add(view); } else if (m instanceof DefView) { final DefView view = (DefView) m; defs.put(view.definition().name, view); } else { throw new RuntimeException( "[BUG] Unsupported definition kind: " + m.getClass().getName()); } } if (operatorLevels.get(new Integer(0)) != null) { // Establish links between operator levels OpLevel previous = null; for (final Iterator<OpLevel> j = operatorLevels.values().iterator(); j .hasNext();) { final OpLevel current = j.next(); current.previousLevel = previous; if (previous != null) { previous.nextLevel = current; } previous = current; } } else { if (!operatorLevels.isEmpty()) { error("grammar.Context.noPrimaryLevelInExpressions", name()); operatorLevels.clear(); } } } /** * @return documentation specification for this context or null if no * documentation is specified */ public DocumentationView documetation() { return documentation; } /** * @return attributes specification for this context or null if no * attributes specification is specified */ public AttributesView attributes() { return attributes; } /** * Get definition for name * * @param name * a name of definition * @return a definition or null if definition is not found */ public DefView def(String name) { final DefView defView = defs.get(name); return defView; } /** * @return a set of statements */ public Set<StatementView> statements() { return statements; } /** * @return operator level for all expressions or null if expressions are not * allowed in this context */ public OpLevel allExpressionsLevel() { if (operatorLevels.isEmpty()) { return null; } return operatorLevels.get(operatorLevels.lastKey()); } /** * Resolve reference in the context. * * @param d * an actual definition that holds this reference * @param s * a reference to resolve * @return a DefView or null if reference cannot be resolved. */ public DefView def(DefinitionView d, RefOp s) { final DefView rc = defs.get(s.name); if (rc == null) { d.definingContext().error(s, "grammar.Ref.danglingRef", s.name); } return rc; } /** * Get a chain of wrapper links for including context * * @param ci * a included context * @return a chain of wrappers */ public WrapperLink includeWrappers(ContextView ci) { if (ci == this) { return null; } final ContextIncludeView view = contextInclude(ci); return view.wrappers(); } /** * @param ci * a context view * @return context include */ public ContextIncludeView contextInclude(ContextView ci) { return contextIncludes.get(ci.name()); } /** * Get context import view by name * * @param ci * a context import name * @return a context import view */ public ContextImportView contextImport(String ci) { return imports.get(ci); } /** * Get definition by name. Used for testing * * @param name * a name of definition * @return a definition for specified name or null. */ public DefinitionView definition(String name) { return definitions.get(name); } /** * Abstract class for context import gatherers */ private abstract static class ContextImportGatherer extends ImportDefinitionGatherer<ContextView, String, ContextImportView, ContextView> { /** * {@inheritDoc} */ @Override protected void reportDuplicateImportError(ContextView sourceHolder, String key) { final ContextView sourceNode = sourceHolder; sourceNode.error(duplcateErrorId(), key); } /** * @return errorId of duplicate import */ protected abstract String duplcateErrorId(); /** * {@inheritDoc} */ @Override protected ContextView importedObject(ContextImportView importDefinition) { return importDefinition.referencedContext(); } /** * {@inheritDoc} */ @Override protected String definitionKey(ContextImportView definition) { final ContextImportView def = definition; return def.localName(); } } /** * This is gatherer of definitions by director of grammar include. */ private static abstract class ContextDefinitionGratherer extends DefinitionGatherer<ContextView, String, DefinitionView> { /** * Error id */ final String errorId; /** * @param id * id of duplicate definitions error */ public ContextDefinitionGratherer(String id) { this.errorId = id; } /** * {@inheritDoc} */ @Override protected void reportDuplicates(ContextView sourceHolder, String key, HashSet<DefinitionView> duplicateNodes) { final ContextView holder = sourceHolder; holder.error(errorId, key); } /** * {@inheritDoc} */ @Override protected String definitionKey(DefinitionView definition) { final DefinitionView def = definition; return def.name(); } /** * {@inheritDoc} */ @Override protected Map<String, DefinitionView> definitionMap(ContextView holder) { final ContextView context = holder; return context.definitions; } } /** * This is gatherer of definitions by director of grammar include. */ private static class DefinitionGrathererByGrammarInclude extends ContextDefinitionGratherer { /** * A constructor */ public DefinitionGrathererByGrammarInclude() { super( "grammar.Context.Definition.duplicateDefinitionByGrammarInclude"); } /** * {@inheritDoc} */ @Override protected Node<ContextView> getHolderNode(ContextView definitionHolder) { return definitionHolder.grammarIncludesNode; } /** * {@inheritDoc} */ @Override protected Node<ContextView> definitionNode(DefinitionView definition) { return definition.originalDefinition().definingContext().grammarIncludesNode; } /** * {@inheritDoc} */ @Override protected DefinitionView originalDefinition(DefinitionView def) { return def.originalDefinition(); } /** * {@inheritDoc} */ @Override protected DefinitionView includingDefinition(ContextView sourceHolder, DefinitionView object) { return DefinitionView.get(sourceHolder, object); } } /** * This is gatherer of definitions by director of grammar include. */ private static class DefinitionGrathererByContextInclude extends ContextDefinitionGratherer { /** * A constructor */ public DefinitionGrathererByContextInclude() { super( "grammar.Context.Definition.duplicateDefinitionByContextInclude"); } /** * {@inheritDoc} */ @Override protected Node<ContextView> getHolderNode(ContextView definitionHolder) { final ContextView holder = definitionHolder; return holder.contextIncludesNode; } /** * {@inheritDoc} */ @Override protected Node<ContextView> definitionNode(DefinitionView definition) { final DefinitionView def = definition; return def.includingContext().contextIncludesNode; } } /** * This class gathers imports by grammar include hierarchy */ private static class ImportGathererByGrammarInclude extends ContextImportGatherer { /** * {@inheritDoc} */ @Override protected ContextImportView originalDefinition(ContextImportView def) { return (def).originalDefinition(); } /** * {@inheritDoc} */ @Override protected ContextImportView includingDefinition( ContextView sourceHolder, ContextImportView object) { final ContextImportView def = object; final ContextView holder = sourceHolder; return new ContextImportView(holder, def); } /** * {@inheritDoc} */ @Override protected Node<ContextView> getHolderNode(ContextView definitionHolder) { final ContextView holder = definitionHolder; return holder.grammarIncludesNode; } /** * {@inheritDoc} */ @Override protected Node<ContextView> definitionNode(ContextImportView definition) { final ContextImportView def = definition; return def.originalDefinition().definingContext().grammarIncludesNode; } /** * {@inheritDoc} */ @Override protected Map<String, ContextImportView> definitionMap( ContextView sourceHolder) { final ContextView holder = sourceHolder; return holder.imports; } /** * {@inheritDoc} */ @Override protected String duplcateErrorId() { return "grammar.Context.ContextImport.duplciateImportByGrammarInclude"; } } /** * This class gathers imports by grammar include hierarchy */ private static class ImportGathererByContextInclude extends ContextImportGatherer { /** * {@inheritDoc} */ @Override protected Node<ContextView> getHolderNode(ContextView definitionHolder) { final ContextView holder = definitionHolder; return holder.contextIncludesNode; } /** * {@inheritDoc} */ @Override protected Node<ContextView> definitionNode(ContextImportView definition) { final ContextImportView def = definition; return def.includingContext().contextIncludesNode; } /** * {@inheritDoc} */ @Override protected Map<String, ContextImportView> definitionMap( ContextView sourceHolder) { final ContextView holder = sourceHolder; return holder.imports; } /** * {@inheritDoc} */ @Override protected String duplcateErrorId() { return "grammar.Context.ContextImport.duplciateImportByGrammarInclude"; } } /** * @return true if wrapped context is abstract */ public boolean isAbstract() { if (context != null) { return context.abstractModifier != null; } else { // If context is included from parent grammar and at least one of // immediate parents is abstract, treat this context as abstract // too. for (final Iterator<ContextView> i = grammarIncludesNode .immediateParentsIterator(); i.hasNext();) { final ContextView v = i.next(); if (v.isAbstract()) { return true; } } return false; } } /** * A gatherer of include definitions by grammar include * * @author const */ private static abstract class ContextIncludeGatherer extends DefinitionGatherer<ContextView, String, ContextIncludeView> { /** * {@inheritDoc} */ @Override protected String definitionKey(ContextIncludeView definition) { final ContextIncludeView include = definition; return include.referencedContext().name(); } /** * {@inheritDoc} */ @Override protected Map<String, ContextIncludeView> definitionMap( ContextView holder) { final ContextView context = holder; return context.contextIncludes; } /** * {@inheritDoc} */ @Override protected void reportDuplicates(ContextView holder, String key, HashSet<ContextIncludeView> duplicateNodes) { final ContextView context = holder; final HashSet<WrapperLink> wrappers = new HashSet<WrapperLink>(); boolean isFirst = true; WrapperLink firstWrapper = null; for (final ContextIncludeView include : duplicateNodes) { if (isFirst) { firstWrapper = include.wrappers(); isFirst = false; wrappers.add(firstWrapper); } else { if (!wrappers.contains(include.wrappers())) { context.error(errorId(), key, String .valueOf(firstWrapper), String.valueOf(include .wrappers())); wrappers.add(include.wrappers()); } } } } /** * @return errorId for error reporting */ protected abstract String errorId(); } /** * A gatherer of include definitions by grammar include * * @author const */ private static class IncludeGathererByGrammarInclude extends ContextIncludeGatherer { /** * {@inheritDoc} */ @Override protected ContextIncludeView includingDefinition(ContextView holder, ContextIncludeView definition) { final ContextIncludeView include = definition; final ContextView context = holder; return new ContextIncludeView(context, include); } /** * {@inheritDoc} */ @Override protected ContextIncludeView originalDefinition( ContextIncludeView definition) { final ContextIncludeView include = definition; return include.originalDefinition(); } /** * @return errorId for error reporting */ @Override protected String errorId() { return "grammar.Context.ContextImport.duplciateWrappersByGrammarInclude"; } /** * {@inheritDoc} */ @Override protected Node<ContextView> getHolderNode(ContextView holder) { final ContextView context = holder; return context.grammarIncludesNode; } /** * {@inheritDoc} */ @Override protected Node<ContextView> definitionNode(ContextIncludeView definition) { final ContextIncludeView include = definition; return include.originalDefinition().definingContext().grammarIncludesNode; } } /** * A gatherer of include definitions by grammar include * * @author const */ private static class IncludeGathererByContextInclude extends ContextIncludeGatherer { /** * {@inheritDoc} */ @Override protected ContextIncludeView includingDefinition(ContextView holder, ContextIncludeView definition) { final ContextIncludeView include = definition; final ContextView context = holder; final ContextIncludeView wrappingInclude = context.contextIncludes .get(include.includingContext().name()); assert wrappingInclude != null : "that is immediatly included context"; return new ContextIncludeView(wrappingInclude, include); } /** * {@inheritDoc} */ @Override protected ContextIncludeView originalDefinition( ContextIncludeView definition) { final ContextIncludeView include = definition; return include.wrappedDefinition(); } /** * @return errorId for error reporting */ @Override protected String errorId() { return "grammar.Context.ContextImport.duplciateWrappersByContextInclude"; } /** * {@inheritDoc} */ @Override protected Node<ContextView> getHolderNode(ContextView holder) { final ContextView context = holder; return context.contextIncludesNode; } /** * {@inheritDoc} */ @Override protected Node<ContextView> definitionNode(ContextIncludeView definition) { final ContextIncludeView include = definition; return include.wrappedDefinition().includingContext().contextIncludesNode; } } }