All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fitnesse.wikitext.parser.ParseSpecification Maven / Gradle / Ivy

The newest version!
package fitnesse.wikitext.parser;

import java.util.ArrayList;
import java.util.Arrays;

public class ParseSpecification {
    public static final int nestingPriority = 2;
    public static final int tablePriority = 1;
    public static final int normalPriority = 0;

    private SymbolProvider provider = SymbolProvider.wikiParsingProvider;
    private ArrayList terminators = new ArrayList<>();
    private ArrayList ignoresFirst = new ArrayList<>();
    private ArrayList ends = new ArrayList<>();
    private int priority = 0;

    public ParseSpecification provider(SymbolProvider provider) {
        this.provider = provider;
        return this;
    }

    public ParseSpecification provider(ParseSpecification specification) {
        this.provider = specification.provider;
        return this;
    }

    public ParseSpecification priority(int priority) {
        this.priority = priority;
        return this;
    }

    public ParseSpecification terminator(SymbolType terminator) {
        terminators.add(terminator);
        return this;
    }

    public ParseSpecification ignoreFirst(SymbolType ignoreFirst) {
        ignoresFirst.add(ignoreFirst);
        return this;
    }

    public void clearIgnoresFirst() {
        ignoresFirst.clear();
    }

    public ParseSpecification end(SymbolType end) {
        ends.add(end);
        return this;
    }

    public ParseSpecification makeSpecification(SymbolProvider providerModel, SymbolType[] providerTypes) {
        SymbolProvider newProvider = new SymbolProvider(providerModel);
        newProvider.addTypes(ends);
        newProvider.addTypes(terminators);
        newProvider.addTypes(Arrays.asList(providerTypes));
        return new ParseSpecification().provider(newProvider);
    }

    public boolean endsOn(SymbolType symbolType) {
        return contains(ends, symbolType);
    }

    public SymbolMatch findMatch(final ScanString input, final int startPosition, final SymbolStream symbols) {
        return provider.findMatch(input.charAt(0), new SymbolMatcher() {
            @Override
            public SymbolMatch makeMatch(Matchable candidate) {
                if (input.getOffset() != startPosition || !ignores(candidate)) {
                    SymbolMatch match = candidate.makeMatch(input, symbols);
                    if (match.isMatch()) return match;
                }
                return SymbolMatch.noMatch;
            }
        });
    }

    public boolean matchesFor(SymbolType symbolType) {
        return provider.matchesFor(symbolType);
    }

    public boolean owns(SymbolType current, ParseSpecification other) {
        return terminatesOn(current) && priority > other.priority;
    }

    public Symbol parse(Parser parser, Scanner scanner) {
        Symbol result = new Symbol(SymbolType.SymbolList);
        result.setStartOffset(scanner.getOffset());
        while (true) {
            Maybe parsedSymbol = parseSymbol(parser, scanner);
            if (parsedSymbol.isNothing()) {
                break;
            } else {
                result.add(parsedSymbol.getValue());
            }
        }
        result.setEndOffset(scanner.getOffset());
        return result;
    }

    /**
     *
     * @param parser parser
     * @param scanner scanner
     * @return a possible value if parser should stop.
     */
    public Maybe parseSymbol(Parser parser, Scanner scanner) {
        while (true) {
            Scanner backup = new Scanner(scanner);
            scanner.moveNextIgnoreFirst(this);
            if (scanner.isEnd()) return Maybe.nothingBecause("scanner is at end of buffer");
            Symbol currentToken = scanner.getCurrent();
            int startOffset = currentToken.getStartOffset();
            if (endsOn(currentToken.getType()) || parser.parentOwns(currentToken.getType(), this)) {
                scanner.copy(backup);
                return Maybe.nothingBecause("At termination symbol or parent owns symbol");
            }
            if (terminatesOn(currentToken.getType())) return Maybe.nothingBecause("At termination symbol");
            Rule currentRule = currentToken.getType().getWikiRule();
            Maybe parsedSymbol = currentRule.parse(currentToken, parser);
            if (parsedSymbol.isNothing()) {
                ignoreFirst(currentToken.getType());
                scanner.copy(backup);
            } else {
                parsedSymbol.getValue().setStartOffset(startOffset).setEndOffset(scanner.getOffset());
                clearIgnoresFirst();
                return parsedSymbol;
            }
        }
    }

    private boolean terminatesOn(SymbolType symbolType) {
        return contains(terminators, symbolType);
    }

    private boolean contains(Iterable terminators, Matchable currentType) {
        for (SymbolType terminator: terminators)
            if (currentType.matchesFor(terminator)) return true;
        return false;
    }

    private boolean ignores(Matchable symbolType) {
        return contains(ignoresFirst, symbolType);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy