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

io.github.tdf4j.parser.AbstractParser Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2019 tdf4j
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.github.tdf4j.parser;

import io.github.tdf4j.core.model.Token;
import io.github.tdf4j.core.model.ast.AST;
import io.github.tdf4j.core.model.ast.ASTNode;
import io.github.tdf4j.core.model.ebnf.NonTerminal;
import io.github.tdf4j.core.model.ebnf.Terminal;
import io.github.tdf4j.core.utils.*;

import java.util.Arrays;
import java.util.function.Consumer;

import static io.github.tdf4j.core.model.ast.ASTCursor.Movement.*;
import static io.github.tdf4j.core.model.ebnf.EBNFBuilder.nonTerminal;

@SuppressWarnings("all")
public abstract class AbstractParser implements Parser {

    protected final Predictor predictor;

    protected BufferedStream stream;
    protected AST ast;

    public AbstractParser(final Predictor predictor) {
        this.predictor = predictor;
    }

    protected CallableNonTerminal callableNonTerminal(final String nonTerminal, final Callback callback) {
        return new CallableNonTerminal(nonTerminal(nonTerminal), callback);
    }

    protected boolean canReach(final Terminal terminal) {
        return canReach(terminal.getValue());
    }

    protected boolean canReach(final NonTerminal nonTerminal) {
        return canReach(nonTerminal.getValue());
    }

    protected boolean canReach(final String element) {
        return predictor.predict(stream.peek()).contains(element);
    }

    protected boolean canReachAny(final String... elements) {
        for(final String element : elements) {
            if(canReach(element)) {
                return true;
            }
        }
        return false;
    }

    protected void match(final Terminal terminal) {
        match(terminal, null);
    }

    protected void match(final Terminal terminal, final Consumer action) {
        if(stream.peek() != null && stream.peek().getTag().equals(terminal)) {
            ast.addLeaf(stream.next());
            if(action != null) {
                action.accept(ast.moveCursor(TO_LAST_LEAF_CHILD).onCursor().asLeaf().getToken());
                ast.moveCursor(TO_PARENT);
            }
        } else {
            throw new UnexpectedTokenException(stream.peek(), terminal.getValue());
        }
    }

    protected int predict(final Alt... alternatives) throws UnexpectedTokenException {
        final java.util.Optional choice = Arrays.stream(alternatives)
                .filter(alt -> canReachAny(alt.elements))
                .findFirst();
        if(!choice.isPresent()) {
            throw new UnexpectedTokenException(stream.peek(), expected(alternatives));
        }
        return choice.get().index;
    }

    protected String[] expected(final Alt... alternatives) {
        return Arrays.stream(alternatives)
                .flatMap(alt -> Arrays.stream(alt.elements))
                .toArray(String[]::new);
    }

    protected void call(final CallableNonTerminal nonTerminal) {
        call(nonTerminal, null);
    }

    protected void call(final CallableNonTerminal nonTerminal, final Consumer action) {
        ast.addNode(nonTerminal.getValue()).moveCursor(TO_LAST_NODE_CHILD);
        nonTerminal.call();
        if (action != null) {
            action.accept(ast.onCursor().asNode());
        }
        ast.moveCursor(TO_PARENT);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy