package org.kefirsf.bb.proc; import org.kefirsf.bb.util.IntSet; import java.util.HashMap; import java.util.Map; /** * The bb-processing context * * @author Kefir */ public class Context { /** * Parent context */ private final Context parent; /** * source text */ private Source source; /** * Target builder */ private Appendable target = null; /** * Text terminator,this mark stop text processing */ private ProcPatternElement terminator = null; /** * Code scope */ private ProcScope scope; /** * Context attributes */ private final Map<String, CharSequence> attributes = new HashMap<String, CharSequence>(); /** * тэги с ошибками. т.е. позиции в которых тэги с ошибками */ private final Map<ProcScope, IntSet> falseMemo; private IntSet scopeFalseMemo; /** * Nesting limit for this context. */ private int nestingLimit; /** * Default constructor */ public Context() { parent = null; falseMemo = new HashMap<ProcScope, IntSet>(); } /** * Constructor of child-context * * @param parent parent context */ public Context(Context parent) { this.parent = parent; this.source = parent.source; this.target = parent.target; this.falseMemo = parent.falseMemo; this.terminator = parent.terminator; this.nestingLimit = parent.nestingLimit-1; this.setScope(parent.scope); } /** * Add the bag tag position * * @param offset offset of bad tag in source */ public void addBadTag(int offset) { scopeFalseMemo.add(offset); } /** * Check the bag tag * * @param offset offset of tag * @return true if at this ofsset tag is bad */ public boolean checkBadTag(int offset) { return scopeFalseMemo.contains(offset); } /** * Check has chars in source before terminator or not * * @return true if chars exists * false if chars canceled */ public boolean hasNextAdjustedForTerminator() { return terminator == null || !terminator.isNextIn(this); } /** * Put all local attributes to parent context */ public void mergeWithParent() { parent.attributes.putAll(this.attributes); } /** * Add or set context attribute * * @param name attribute name * @param value attribute value */ public void setAttribute(String name, CharSequence value) { attributes.put(name, value); } /** * Get the context attribute. If attribute not exists in current context, * then context search the sttribute in parent context * * @param name attribute name * @return attribute value */ public Object getAttribute(String name) { Object value = getLocalAttribute(name); if (value == null && parent != null) { value = parent.getAttribute(name); } return value; } /** * Return attribute from this context, not parent * * @param name attribute name * @return attribute value */ public Object getLocalAttribute(String name) { return attributes.get(name); } /** * Set list of codes in current context * * @param scope code scope */ public void setScope(ProcScope scope) { this.scope = scope; // Scope false memo scopeFalseMemo = falseMemo.get(scope); if (scopeFalseMemo == null) { scopeFalseMemo = new IntSet(); falseMemo.put(scope, scopeFalseMemo); } } public Source getSource() { return source; } public void setSource(Source source) { this.source = source; } public Appendable getTarget() { return target; } public void setTarget(Appendable target) { this.target = target; } /** * get Text terminator,this mark stop text processing * * @return terminator */ public ProcPatternElement getTerminator() { return terminator; } /** * @param terminator Text terminator,this mark stop text processing */ public void setTerminator(ProcPatternElement terminator) { this.terminator = terminator; } public ProcScope getScope() { return scope; } /** * Set nesting limit for this context. * * @param nestingLimit nesting limit */ public void setNestingLimit(int nestingLimit) { this.nestingLimit = nestingLimit; } /** Check nesting. * * @throws NestingException if nesting limit less than 0. */ public void checkNesting() throws NestingException { if(nestingLimit<0){ throw new NestingException(); } } public Map<String, CharSequence> getAttributes() { return attributes; } }