/*
* 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;
}
}
}