package fitnesse.wikitext.parser; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; public class Symbol { private static final List<Symbol> NO_CHILDREN = Collections.emptyList(); public static final Maybe<Symbol> nothing = new Maybe<>(); public static final Symbol emptySymbol = new Symbol(SymbolType.Empty); private SymbolType type; private String content; private List<Symbol> children; private Map<String,String> variables; private Map<String,String> properties; private int startOffset = -1; private int endOffset = -1; public Symbol(SymbolType type) { this(type, ""); } public Symbol(SymbolType type, String content) { this.type = type; this.content = content; this.children = NO_CHILDREN; } public Symbol(SymbolType type, String content, int startOffset) { this(type, content); this.startOffset = startOffset; this.endOffset = startOffset + content.length(); } public Symbol(SymbolType type, String content, int startOffset, int endOffset) { this(type, content); this.startOffset = startOffset; this.endOffset = endOffset; } public SymbolType getType() { return type; } public boolean isType(SymbolType type) { return this.type.matchesFor(type); } public boolean isStartCell() { return isType(Table.symbolType) || isType(SymbolType.EndCell); } public boolean isStartLine() { return isType(HorizontalRule.symbolType) || isType(Nesting.symbolType); } public boolean isLineType() { return isType(HeaderLine.symbolType) || isType(SymbolType.CenterLine) || isType(SymbolType.Meta) || isType(SymbolType.NoteLine); } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public Symbol childAt(int index) { return getChildren().get(index); } public Symbol lastChild() { return childAt(getChildren().size() - 1); } public List<Symbol> getChildren() { return children; } private List<Symbol> children() { if (children == NO_CHILDREN) { children = new LinkedList<>(); } return children; } public Symbol addToFront(Symbol child) { children().add(0, child); return this; } public Symbol add(Symbol child) { children().add(child); return this; } public Symbol add(String text) { children().add(new Symbol(SymbolType.Text, text)); return this; } public Symbol childrenAfter(int after) { Symbol result = new Symbol(SymbolType.SymbolList); for (int i = after + 1; i < children.size(); i++) result.add(children.get(i)); return result; } public boolean walkPostOrder(SymbolTreeWalker walker) { if (walker.visitChildren(this)) { for (Symbol child: children) { if (!child.walkPostOrder(walker)) return false; } } return walker.visit(this); } public boolean walkPreOrder(SymbolTreeWalker walker) { if (!walker.visit(this)) return false; if (walker.visitChildren(this)) { for (Symbol child: children) { if (!child.walkPreOrder(walker)) return false; } } return true; } public void evaluateVariables(String[] names, VariableSource source) { if (variables == null) variables = new HashMap<>(names.length); for (String name: names) { Maybe<String> value = source.findVariable(name); if (!value.isNothing()) variables.put(name, value.getValue()); } } public String getVariable(String name, String defaultValue) { return variables != null && variables.containsKey(name) ? variables.get(name) : defaultValue; } public Symbol putProperty(String key, String value) { if (properties == null) properties = new HashMap<>(1); properties.put(key, value); return this; } public boolean hasProperty(String key) { return properties != null && properties.containsKey(key); } public String getProperty(String key, String defaultValue) { return properties != null && properties.containsKey(key) ? properties.get(key) : defaultValue; } public String getProperty(String key) { return getProperty(key, ""); } public boolean hasOffset() { return startOffset != -1 && endOffset != -1; } Symbol setStartOffset(int startOffset) { this.startOffset = startOffset; return this; } public int getStartOffset() { return startOffset; } Symbol setEndOffset(int endOffset) { this.endOffset = endOffset; return this; } public int getEndOffset() { return endOffset; } public void setType(SymbolType type) { this.type = type; } }