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

it.unibo.tuprolog.parser.dynamic.DynamicParser Maven / Gradle / Ivy

package it.unibo.tuprolog.parser.dynamic;

import org.antlr.v4.runtime.Parser;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.TokenStream;

import java.util.*;
import java.util.function.IntBinaryOperator;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public abstract class DynamicParser extends Parser {

    private static final boolean DEBUG = false;

    private final Map> operators = new HashMap<>();
    private DynamicLexer lexer;

    public DynamicParser(TokenStream input) {
        super(input);
        if (input.getTokenSource() instanceof DynamicLexer) {
            this.lexer = (DynamicLexer) input.getTokenSource();
        } else {
            throw new IllegalStateException("No lexer was provided");
        }
    }

    public DynamicParser(TokenStream input, DynamicLexer lexer) {
        super(input);
        this.lexer = lexer;
    }

    public void setLexer(DynamicLexer lexer) {
        this.lexer = lexer;
    }

    public DynamicLexer getLexer() {
        return lexer;
    }

    public int getOperatorPriority(String operator, Associativity associativity) {
        return Optional.ofNullable(operators.get(operator))
                       .map(m -> m.get(associativity))
                       .orElse(Integer.MAX_VALUE);
    }

    public int getOperatorPriority(Token operator, Associativity associativity) {
        return getOperatorPriority(operator.getText(), associativity);
    }

    public boolean isOperator(Token token) {
        return lexer.isOperator(token);
    }

    public boolean isOperator(String functor) {
        return lexer.isOperator(functor);
    }

    public void addOperator(String functor, Associativity associativity, int priority) {
        lexer.addOperators(functor);
        final Map item = Collections.singletonMap(associativity, priority);

        operators.merge(functor, item, (m1, m2) -> {
            final Map m3 = new HashMap<>(m1);
            m3.putAll(m2);
            return m3;
        });
    }

    public void removeOperator(String functor) {
        lexer.removeOperators(functor);
        operators.remove(functor);
    }

    public boolean isOperatorAssociativity(Token token, Associativity associativity) {
        return isOperatorAssociativity(token.getText(), associativity);
    }

    public boolean isOperatorAssociativity(String functor, Associativity a) {
        return operators.containsKey(functor)
               && operators.get(functor).containsKey(a);
    }

    protected static void log(String format, Object... args) {
        if (DEBUG) {
            System.err.printf(format, args);
        }
    }

    protected OptionalInt lookahead(IntBinaryOperator f, Associativity associativity, int priority, String... except) {
        final Token lookahead = getTokenStream().LT(1);

        log("r=%d, c=%d, l='%s' a=%s e=[%s] p(%s)=%d",
            lookahead.getLine(),
            lookahead.getCharPositionInLine(),
            lookahead.getText(),
            associativity,
            except.length > 0 ? "'" + String.join("','", except) + "'" : "",
            lookahead.getText(),
            getOperatorPriority(lookahead, associativity)
        );

        if (Stream.of(except).filter(this::isOperator).anyMatch(o -> lookahead.getText().equals(o))) {
            return OptionalInt.empty();
        }
        if (!isOperator(lookahead)) {
            return OptionalInt.empty();
        }
        if (!isOperatorAssociativity(lookahead, associativity)) {
            return OptionalInt.empty();
        }

        return OptionalInt.of(f.applyAsInt(getOperatorPriority(lookahead, associativity), priority));
    }

    protected boolean lookaheadIs(EnumSet associativities, String... except) {
        final Token lookahead = getTokenStream().LT(1);

        log("r=%d, c=%d, l='%s' e=[%s]",
            lookahead.getLine(),
            lookahead.getCharPositionInLine(),
            lookahead.getText(),
            except.length > 0 ? "'" + String.join("','", except) + "'" : ""
        );

        boolean result = Stream.of(except).filter(this::isOperator).noneMatch(o -> lookahead.getText().equals(o))
                         && associativities.stream().anyMatch(a -> isOperatorAssociativity(lookahead, a));

        log(" %s %s\n", result ? "is" : "is not", associativities.size() == 1
                                                  ? associativities.iterator().next()
                                                  : associativities.stream().map(Objects::toString).collect(Collectors.joining(",", "oneOf(", ")")));

        return result;
    }

    protected boolean lookaheadGt(Associativity associativity, int priority, String... except) {
        boolean res = lookahead(Integer::compare, associativity, priority, except).orElse(-1) > 0;
        log(" > %d? %s\n", priority, res ? "yes" : "no");
        return res;
    }

    protected boolean lookaheadEq(Associativity associativity, int priority, String... except) {
        boolean res = lookahead(Integer::compare, associativity, priority, except).orElse(-1) == 0;
        log(" == %d? %s\n", priority, res ? "yes" : "no");
        return res;
    }

    protected boolean lookaheadNeq(Associativity associativity, int priority, String... except) {
        boolean res = lookahead(Integer::compare, associativity, priority, except).orElse(0) != 0;
        log(" != %d? %s\n", priority, res ? "yes" : "no");
        return res;
    }

    protected boolean lookaheadGeq(Associativity associativity, int priority, String... except) {
        boolean res = lookahead(Integer::compare, associativity, priority, except).orElse(-1) >= 0;
        log(" >= %d? %s\n", priority, res ? "yes" : "no");
        return res;
    }

    protected boolean lookaheadLeq(Associativity associativity, int priority, String... except) {
        boolean res = lookahead(Integer::compare, associativity, priority, except).orElse(1) <= 0;
        log(" =< %d? %s\n", priority, res ? "yes" : "no");
        return res;
    }

    protected boolean lookaheadLt(Associativity associativity, int priority, String... except) {
        boolean res = lookahead(Integer::compare, associativity, priority, except).orElse(1) < 0;
        log(" < %d? %s\n", priority, res ? "yes" : "no");
        return res;
    }

    protected boolean lookahead(Associativity associativity, int top, int bottom, String... except) {
        return lookahead(EnumSet.of(associativity), top, bottom, except);
    }

    protected boolean lookahead(EnumSet associativities, int top, int bottom, String... except) {
        final Token lookahead = getTokenStream().LT(1);

        log("r=%d, c=%d, l='%s' a=%s e=[%s] p(%s)=%s",
            lookahead.getLine(),
            lookahead.getCharPositionInLine(),
            lookahead.getText(),
            associativities.size() == 1
                ? associativities.iterator().next()
                : associativities.stream().map(Objects::toString).collect(Collectors.joining(",", "oneOf(", ")")),
            except.length > 0 ? "'" + String.join("','", except) + "'" : "",
            lookahead.getText(),
            associativities.size() == 1
                ? associativities.stream().map(a -> getOperatorPriority(lookahead,a)).map(String::valueOf).findAny().get()
                : associativities.stream().map(a -> getOperatorPriority(lookahead,a)).map(String::valueOf).collect(Collectors.joining(",", "oneOf(", ")"))
        );


        final boolean result = Stream.of(except).filter(this::isOperator).noneMatch(o -> lookahead.getText().equals(o))
                               && associativities.stream().anyMatch(associativity -> {
                                    if (!isOperatorAssociativity(lookahead, associativity)) {
                                        return false;
                                    }

                                    final int priority = getOperatorPriority(lookahead, associativity);

                                    return priority <= top && priority >= bottom;
                                });

        log(" in [%d, %d]? %s\n", top, bottom, result ? "yes" : "no");

        return result;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy