package fitnesse.wikitext.parser;
import java.util.ArrayList;
import java.util.List;
public class Parser {
private static final ArrayList<Symbol> emptySymbols = new ArrayList<>();
public static Parser make(ParsingPage currentPage, CharSequence input) {
return make(currentPage, input, SymbolProvider.wikiParsingProvider);
}
public static Parser make(ParsingPage currentPage, CharSequence input, SymbolProvider provider) {
ParseSpecification specification = new ParseSpecification().provider(provider);
return new Parser(null, currentPage, new Scanner(new TextMaker(currentPage, currentPage.getNamedPage()), input), specification);
}
private ParsingPage currentPage;
private Scanner scanner;
private Parser parent;
private ParseSpecification specification;
public Parser(Parser parent, ParsingPage currentPage, Scanner scanner, ParseSpecification specification) {
this.parent = parent;
this.currentPage = currentPage;
this.scanner = scanner;
this.specification = specification;
}
public ParsingPage getPage() { return currentPage; }
public VariableSource getVariableSource() { return currentPage; }
public Symbol getCurrent() { return scanner.getCurrent(); }
public int getOffset() { return scanner.getOffset(); }
public boolean atEnd() { return scanner.isEnd(); }
public boolean isMoveNext(SymbolType type) { return moveNext(1).isType(type); }
public boolean endsOn(SymbolType type) { return specification.endsOn(type); }
public Symbol moveNext(int count) {
for (int i = 0; i < count; i++) scanner.moveNextIgnoreFirst(specification);
return scanner.getCurrent();
}
public List<Symbol> moveNext(SymbolType[] symbolTypes) {
ArrayList<Symbol> tokens = new ArrayList<>();
for (SymbolType type: symbolTypes) {
Symbol current = moveNext(1);
if (!current.isType(type)) return new ArrayList<>();
tokens.add(current);
}
return tokens;
}
public Symbol peek() {
return peek(1).get(0);
}
public List<Symbol> peek(int size) {
return scanner.peek(size, new ParseSpecification().provider(specification));
}
public List<Symbol> peek(SymbolType[] types) {
List<Symbol> lookAhead = scanner.peek(types.length, new ParseSpecification().provider(specification));
if (lookAhead.size() != types.length) return emptySymbols;
for (int i = 0; i < lookAhead.size(); i++) {
if (!lookAhead.get(i).isType(types[i])) return emptySymbols;
}
return lookAhead;
}
public Maybe<String> parseToAsString(SymbolType terminator) {
int start = scanner.getOffset();
scanner.markStart();
parseTo(terminator);
if (!atEnd() && !getCurrent().isType(terminator)) return Maybe.noString;
return scanner.stringFromStart(start);
}
public String parseLiteral(SymbolType terminator) {
return scanner.makeLiteral(terminator).getContent();
}
public Symbol parse(String input) {
return parseWithParent(input, this);
}
public Symbol parseWithParent(String input, Parser parent) {
return new Parser(parent, currentPage, new Scanner(new TextMaker(currentPage, currentPage.getNamedPage()), input), new ParseSpecification().provider(specification)).parse();
}
public Symbol parseToIgnoreFirst(SymbolType type) {
return parseToIgnoreFirst(new SymbolType[] {type});
}
public Symbol parseToIgnoreFirst(SymbolType[] types) {
ParseSpecification newSpecification = new ParseSpecification().provider(specification);
for (SymbolType symbolType: types) {
newSpecification.terminator(symbolType);
newSpecification.ignoreFirst(symbolType);
}
return parse(newSpecification);
}
public Symbol parseToIgnoreFirstWithSymbols(SymbolType ignore, SymbolProvider provider) {
return parse(new ParseSpecification().ignoreFirst(ignore).terminator(ignore).provider(provider));
}
public Symbol parseTo(SymbolType terminator) {
return parseTo(terminator, ParseSpecification.normalPriority);
}
public Symbol parseTo(SymbolType terminator, int priority) {
return parse(new ParseSpecification() /*.provider(specification)*/ .terminator(terminator).priority(priority));
}
public Symbol parseToWithSymbols(SymbolType terminator, SymbolProvider provider, int priority) {
SymbolType[] terminators = new SymbolType[] {terminator};
return parseToWithSymbols(terminators, provider, priority);
}
public Symbol parseToWithSymbols(SymbolType[] terminators, SymbolProvider provider, int priority) {
ParseSpecification newSpecification = new ParseSpecification().provider(provider).priority(priority);
for (SymbolType terminator: terminators) newSpecification.terminator(terminator);
return parse(newSpecification);
}
public Symbol parseToEnd(SymbolType end) {
return parse(new ParseSpecification().provider(specification).end(end));
}
public Symbol parseToEnds(int priority, SymbolProvider provider, SymbolType[] moreEnds) {
ParseSpecification newSpecification = specification.makeSpecification(provider, moreEnds).priority(priority);
for (SymbolType end: moreEnds) newSpecification.end(end);
return parse(newSpecification);
}
private Symbol parse(ParseSpecification newSpecification) {
return new Parser(this, currentPage, scanner, newSpecification).parse();
}
public Symbol parse() {
return specification.parse(this, scanner);
}
public boolean parentOwns(SymbolType current, ParseSpecification specification) {
if (parent == null) return false;
if (parent.specification.owns(current, specification)) return true;
return parent.parentOwns(current, specification);
}
}