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

org.btrplace.safeplace.spec.MyCstrSpecVisitor Maven / Gradle / Ivy

/*
 * Copyright (c) 2017 University Nice Sophia Antipolis
 *
 * This file is part of btrplace.
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see .
 */

package org.btrplace.safeplace.spec;

import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.misc.NotNull;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.btrplace.safeplace.spec.antlr.CstrSpecBaseVisitor;
import org.btrplace.safeplace.spec.antlr.CstrSpecParser;
import org.btrplace.safeplace.spec.prop.*;
import org.btrplace.safeplace.spec.term.*;
import org.btrplace.safeplace.spec.term.func.Function;
import org.btrplace.safeplace.spec.term.func.FunctionCall;
import org.btrplace.safeplace.spec.term.func.ValueAt;
import org.btrplace.safeplace.spec.type.*;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;


/**
 * @author Fabien Hermenier
 */
public class MyCstrSpecVisitor extends CstrSpecBaseVisitor {

    private SymbolsTable symbols;

    private String filename;

    public MyCstrSpecVisitor() {
        symbols = new SymbolsTable();
    }

    public MyCstrSpecVisitor args(List> args) {
        args.forEach(symbols::put);
        return this;
    }

    public MyCstrSpecVisitor library(List> funcs) {
        funcs.forEach(symbols::put);
        return this;
    }

    public MyCstrSpecVisitor constraints(List cstrs) {
        cstrs.forEach(symbols::put);
        return this;
    }


    /**
     * @param name
     * @param t
     * @return
     * @throws SpecException
     */
    public Proposition getProposition(String name, ParseTree t) {
        symbols = symbols.enterSpec();
        filename = name;
        try {
            return (Proposition) visit(t);
        } finally {
            symbols = symbols.leaveScope();
        }
    }

    /**
     *
     * @param name
     * @param t
     * @throws SpecException
     * @return
     */
    public UserVar getUserVar(String name, ParseTree t) {
        symbols = symbols.enterSpec();
        filename = name;
        try {
            return ((List) visit(t)).get(0);
        } finally {
            symbols = symbols.leaveScope();
        }
    }

    @Override
    public Proposition visitAll(@NotNull CstrSpecParser.AllContext ctx) {
        List> vars = visitTypedef(ctx.typedef());
        Proposition p = (Proposition) visit(ctx.formula());
        return new ForAll(vars, p);
    }

    @Override
    public Exists visitExists(@NotNull CstrSpecParser.ExistsContext ctx) {
        List> vars = visitTypedef(ctx.typedef());
        Proposition p = (Proposition) visit(ctx.formula());
        return new Exists(vars, p);
    }

    private Function resolveFunction(Token t, List args) {
        Function f = symbols.getFunction(t.getText());
        if (f == null) {
            throw SpecException.unknownSymbol(filename, t);
        }

        Type[] expected = f.signature();
        if (expected.length != args.size()) {
            throw SpecException.badFunctionCall(filename, t, f, args);
        }
        for (int i = 0; i < expected.length; i++) {
            if (!expected[i].equals(args.get(i).type())) {
                throw SpecException.badFunctionCall(filename, t, f, args);
            }
        }

        return f;
    }

    @Override
    public FunctionCall visitCall(@NotNull CstrSpecParser.CallContext ctx) {

        List ps = ctx.term().stream().map(t -> (Term) visit(t)).collect(Collectors.toList());
        Function f = resolveFunction(ctx.ID().getSymbol(), ps);

        FunctionCall.Moment m = FunctionCall.Moment.ANY;
        if (ctx.BEGIN() != null) {
            m = FunctionCall.Moment.BEGIN;
        }
        return new FunctionCall(f, ps, m);
    }

    @Override
    public ConstraintCall visitCstrCall(@NotNull CstrSpecParser.CstrCallContext ctx) {
        List ps = ctx.call().term().stream().map(t -> (Term) visit(t)).collect(Collectors.toList());
        Function f = resolveFunction(ctx.call().ID().getSymbol(), ps);
        return new ConstraintCall(f, ps);
    }

    @Override
    public List> visitTypedef(@NotNull CstrSpecParser.TypedefContext ctx) {

        Term parent = (Term) visit(ctx.term());
        if (parent.type() instanceof Atomic) {
            throw new SpecException(filename, ctx.op.getCharPositionInLine(), "The right-hand side must be a collection");
        }
        List> vars = new ArrayList<>();
        for (TerminalNode n : ctx.ID()) {
            String lbl = n.getText();
            UserVar v = new UserVar(lbl, ctx.op.getText(), parent);
            symbols.put(v);
            vars.add(v);
        }
        return vars;
    }

    @Override
    public Proposition visitFormulaOp(@NotNull CstrSpecParser.FormulaOpContext ctx) {
        Proposition p1 = (Proposition) visit(ctx.f1);
        Proposition p2 = (Proposition) visit(ctx.f2);
        switch (ctx.op.getType()) {
            case CstrSpecParser.AND:
                return new And(p1, p2);
            case CstrSpecParser.OR:
                return new Or(p1, p2);
            case CstrSpecParser.IMPLIES:
                return new Implies(p1, p2);
            case CstrSpecParser.IFF:
                return new Iff(p1, p2);
            default:
                throw SpecException.unsupportedOperation(filename, BoolType.getInstance(), ctx.op, BoolType.getInstance());
        }
    }

    @Override
    public ExplodedSet visitSetInExtension(@NotNull CstrSpecParser.SetInExtensionContext ctx) {
        List s = new ArrayList<>();
        Type ty = null;
        for (CstrSpecParser.TermContext t : ctx.term()) {
            Term tr = (Term) visit(t);
            if (ty == null) {
                ty = tr.type();
            }
            assertEqualsTypes(t.getStart(), ty, tr.type());
            s.add(tr);
        }
        return new ExplodedSet(s, ty);
    }

    @Override
    public Term visitProtectedTerm(@NotNull CstrSpecParser.ProtectedTermContext ctx) {
        Term t = (Term) visit(ctx.term());
        return new ProtectedTerm(t);
    }

    @Override
    public SetBuilder visitSetInComprehension(@NotNull CstrSpecParser.SetInComprehensionContext ctx) {
        //Get the binder
        List> v = visitTypedef(ctx.typedef());

        Proposition p = Proposition.True;
        if (ctx.COMMA() != null) {
            p = (Proposition) visit(ctx.formula());
        }
        Term t = (Term) visit(ctx.term());
        return new SetBuilder<>(t, v.get(0), p);
    }

    @Override
    public ListBuilder visitListInComprehension(@NotNull CstrSpecParser.ListInComprehensionContext ctx) {
        //Get the binder
        List> v = visitTypedef(ctx.typedef());

        Proposition p = Proposition.True;
        if (ctx.COMMA() != null) {
            p = (Proposition) visit(ctx.formula());
        }
        Term t = (Term) visit(ctx.term());
        return new ListBuilder<>(t, v.get(0), p);
    }

    @Override
    public Proposition visitProtectedFormula(@NotNull CstrSpecParser.ProtectedFormulaContext ctx) {
        Proposition p = (Proposition) visit(ctx.formula());
        return new ProtectedProposition(p);
    }

    @Override
    public Term visitArrayTerm(@NotNull CstrSpecParser.ArrayTermContext ctx) {
        String lbl = ctx.ID().getText();
        Var v = symbols.getVar(lbl);
        if (v == null) {
            throw SpecException.unknownSymbol(filename, ctx.ID().getSymbol());
        }
        //Type check
        if (!(v.type() instanceof ListType)) {
            throw new SpecException(filename, ctx.ID().getSymbol().getCharPositionInLine(), "List expected. Got '" + v.type() + "')");
        }

        Term idx = (Term) visit(ctx.term());
        assertEqualsTypes(ctx.term().getStart(), IntType.getInstance(), idx.type());
        return new ValueAt(v, idx);
    }

    @Override
    public Term visitIdTerm(@NotNull CstrSpecParser.IdTermContext ctx) {
        String ref = ctx.ID().getText();
        Term v = symbols.getVar(ref);
        if (v != null) {
            return v;
        }
        Term c = VMStateType.getInstance().parse(ref);
        if (c == null) {
            c = NodeStateType.getInstance().parse(ref);
        }
        if (c == null) {
            throw SpecException.unknownSymbol(filename, ctx.ID().getSymbol());
        }
        return c;
    }

    @Override
    public Constant visitIntTerm(@NotNull CstrSpecParser.IntTermContext ctx) {
        return IntType.getInstance().parse(ctx.INT().getText());
    }

    @Override
    public Constant visitStringTerm(@NotNull CstrSpecParser.StringTermContext ctx) {
        String txt = ctx.STRING().getText();
        return StringType.getInstance().parse(txt.substring(1, txt.length()));
    }

    private void assertEqualsTypes(Token to, Type expected, Type... got) {
        for (Type t : got) {
            if (!expected.equals(t)) {
                throw SpecException.typeMismatch(filename, to.getCharPositionInLine(), expected, t);
            }
        }
    }

    private void assertIn(Token to, Term t1, Term t2) {
        Type t = t2.type();
        if (!(t instanceof SetType)) {
            throw new SpecException(filename, to.getCharPositionInLine(), "The right-hand side must be a collection. Got '" + t2.type() + "'");
        }
        SetType st = (SetType) t;
        if (!st.enclosingType().equals(t1.type())) {
            throw new SpecException(filename, to.getCharPositionInLine(),
                    "Type mismatch. Expected '" + st.enclosingType() + "' for left-hand side. Got '" + t1.type() + "'");

        }
    }

    @Override
    public Proposition visitTermComparison(@NotNull CstrSpecParser.TermComparisonContext c) {
        CstrSpecParser.ComparisonContext ctx = c.comparison();
        Term t1 = (Term) visit(ctx.t1);
        Term t2 = (Term) visit(ctx.t2);

        switch (ctx.op.getType()) {

            case CstrSpecParser.INCL:
                assertEqualsTypes(ctx.op, t1.type(), t2.type());
                return new Inc(t1, t2);
            case CstrSpecParser.NOT_INCL:
                assertEqualsTypes(ctx.op, t1.type(), t2.type());
                return new NInc(t1, t2);
            case CstrSpecParser.EQ:
                assertEqualsTypes(ctx.op, t1.type(), t2.type());
                return new Eq(t1, t2);
            case CstrSpecParser.NOT_EQ:
                assertEqualsTypes(ctx.op, t1.type(), t2.type());
                return new NEq(t1, t2);
            case CstrSpecParser.LT:
                assertEqualsTypes(ctx.op, IntType.getInstance(), t1.type(), t2.type());
                return new Lt(t1, t2);
            case CstrSpecParser.LEQ:
                assertEqualsTypes(ctx.op, IntType.getInstance(), t1.type(), t2.type());
                return new Leq(t1, t2);
            case CstrSpecParser.GT:
                assertEqualsTypes(ctx.op, IntType.getInstance(), t1.type(), t2.type());
                return new Lt(t2, t1);
            case CstrSpecParser.GEQ:
                assertEqualsTypes(ctx.op, IntType.getInstance(), t1.type(), t2.type());
                return new Leq(t2, t1);

            case CstrSpecParser.IN:
                assertIn(ctx.op, t1, t2);
                return new In(t1, t2);
            case CstrSpecParser.NOT_IN:
                assertIn(ctx.op, t1, t2);
                return new NIn(t1, t2);
            case CstrSpecParser.PART:
                assertIn(ctx.op, t2, t1);
                return new Packings(t1, t2);
            case CstrSpecParser.NOT_PART:
                assertIn(ctx.op, t2, t1);
                return new NoPackings(t1, t2);
            default:
                throw SpecException.unsupportedOperation(filename, t1.type(), ctx.op, t2.type());
        }
    }

    @Override
    public Term visitTermOp(@NotNull CstrSpecParser.TermOpContext ctx) {
        Term t1 = (Term) visit(ctx.t1);
        Term t2 = (Term) visit(ctx.t2);

        assertEqualsTypes(ctx.op, t1.type(), t2.type());
        switch (ctx.op.getType()) {
            case CstrSpecParser.PLUS:
                if (t1.type() == IntType.getInstance()) {
                    return new IntPlus(t1, t2);
                } else if (t1.type() instanceof SetType) {
                    return new SetPlus(t1, t2);
                }
                break;
            case CstrSpecParser.MINUS:
                if (t1.type() == IntType.getInstance()) {
                    return new IntMinus(t1, t2);
                } else if (t1.type() instanceof SetType) {
                    return new SetMinus(t1, t2);
                }
                break;
            case CstrSpecParser.MULT:
                return new Mult(t1, t2);
            default:
        }
        throw SpecException.unsupportedOperation(filename, t1.type(), ctx.op, t2.type());
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy