Package abstrasy.pcfx

Source Code of abstrasy.pcfx.PCFx_infer$Rule

package abstrasy.pcfx;


import abstrasy.Heap;
import abstrasy.Interpreter;
import abstrasy.Node;
import abstrasy.PCoder;

import abstrasy.interpreter.BaseContextSnapshot;
import abstrasy.interpreter.InterpreterException;
import abstrasy.interpreter.StdErrors;

import java.util.ArrayList;


/**
* Abstrasy Interpreter
*
* Copyright : Copyright (c) 2006-2012, Luc Bruninx.
*
* Concédée sous licence EUPL, version 1.1 uniquement (la «Licence»).
*
* Vous ne pouvez utiliser la présente oeuvre que conformément à la Licence.
* Vous pouvez obtenir une copie de la Licence à l’adresse suivante:
*
*   http://www.osor.eu/eupl
*
* Sauf obligation légale ou contractuelle écrite, le logiciel distribué sous
* la Licence est distribué "en l’état", SANS GARANTIES OU CONDITIONS QUELLES
* QU’ELLES SOIENT, expresses ou implicites.
*
* Consultez la Licence pour les autorisations et les restrictions
* linguistiques spécifiques relevant de la Licence.
*
*
* @author Luc Bruninx
* @version 1.0
*/

public class PCFx_infer extends PCFx {

    public PCFx_infer() {
    }


    private static final class Rule {

        int ruleType;
        Node condition;
        Node consequenceThen;
        Node consequenceElse;

        Rule(int ruleType, Node condition, Node consequenceThen, Node consequenceElse) {
            this.ruleType = ruleType;
            this.condition = condition;
            this.consequenceThen = consequenceThen;
            this.consequenceElse = consequenceElse;
        }

        Node getCondition() {
            return condition;
        }

        Node getConsequenceThen() {
            return consequenceThen;
        }

        Node getConsequenceElse() {
            return consequenceElse;
        }

        public int getRuleType() {
            return ruleType;
        }

    }

    private final static Node evalSection(Heap local, Node thenode) throws Exception {
        if(thenode!=null && thenode.isLazy()) {
            if (local.isLoaded()) {
                local.clear();
            }
            return thenode.exec(true);
        }
        return thenode;
    }

    private static final void addRules(ArrayList<Rule> rules, Node startAt) throws Exception {

        /*
             * vérification élémentaire de la syntaxe
             *
             * Minumum (each-time|once {...} then ...
             */
        startAt.isGoodArgsCnt(4, 6);
        Node rt_node = startAt.getSubNode(0, Node.TYPE_PCODE);
        int ruleType = rt_node.getPCFx_Code();
        if (ruleType != PCoder.PC_ONCE && ruleType != PCoder.PC_EACH_TIME) {
            throw new InterpreterException(StdErrors.extend(StdErrors.Syntax_error,
                        "\'" + PCoder.getReserved(PCoder.PC_ONCE) + "\' or \'" + PCoder.getReserved(PCoder.PC_EACH_TIME) + "\'expected."));
        }
        Node cd_node = startAt.getSubNode(1, Node.TYPE_LAZY);
        startAt.requirePCode(2, PCoder.PC_THEN);
        Node th_node = startAt.elementAt(3);
        /*
             * clause else ... ?
             */
        if (ruleType == PCoder.PC_ONCE) {
            /*
                 * Si régle est once{...} then{...}, il n'y a pas de else...
                 *
                 * On enregistre donc la règle et on continue si la fin n'est pas atteinte...
                 */
            startAt.isGoodArgsCnt(4);
            rules.add(new Rule(ruleType, cd_node, th_node, null));
        }
        else {
            /*
                 * Si la règle est each-time{...} then{...}, il est possible qu'il y ait un else...
                 *
                 * On va donc analyser la suite en conséquence...
                 */
            if (startAt.size() > 4) {
                startAt.requirePCode(4, PCoder.PC_ELSE);
                Node el_node = startAt.elementAt(5);
                rules.add(new Rule(ruleType, cd_node, th_node, el_node));
            }
            else {
                rules.add(new Rule(ruleType, cd_node, th_node, null));
                //puis on continue... each-time|once doit normalement se trouver à la position pos...
            }

        }

    }

    /**
     * eval
     *
     * @param startAt Node
     * @return Node
     * @throws Exception
     * @todo Implémenter cette méthode abstrasy.PCFx
     */


    public Node eval(Node startAt) throws Exception {
        /*
         * forme (infer règles)
         * ----------------------------------------------------------------------------------------------------------------------
         *
         * où rôles est une liste de la forme:
         *
         *    once{condition} then ...               : défini une règle qui ne peut être vérifiée qu'une seule fois.
         *
         *    each-time{condition} then ...          : défini une règle qui peut être vérifiée un nombre indéfini de fois.
         *    each-time{condition} then ... else ...
         *
         * La boucle d'inférence s'arrête lorsque plus aucune condition n'est vérifiée ou lorsqu'un résultat est déterminé.
         *
         * Exemple:
         * =======
         *
         *    (define 'x 32)
         *    (define 'i (floor(sqrt x)))
         *    (infer [
         *      '(each-time{zero? (mod x i)} then{ (incr! x) (setn! i (floor (sqrt x))) } else{decr! i})
         *      '(once{<=? i 1} then {,x})
         *    ])
         *
         *    Retourne le nombre premier qui suit 32, soit dans ce cas 37.
         *
         * Remarques:
         * =========
         *
         *    Attention, once ne permet pas de définir de conséquence alternative (else). Ceci pour éviter des éventuelles
         *    confusions au niveau sémantique entre once et each-time.
         *
         *    En effet, once="une fois que" et each-time="chaque fois que", ainsi on pourrait conclure que la proposition
         *    else qui serait assiciée à once voudrait dire "chaque fois que la condition 'une fois que' n'est pas remplie alors...".
         *
         *    Cette interprétation peut porter à confusion. Aussi, once n'accepte pas de proposition alternative. Le programmeur
         *    est encourrager à formuler ses règles en tenant compte de ce point.
         *
         *    Par ailleurs, comme infer prend comme argument une liste de règles, Il est donc possible, de modifier cette liste
         *    en fonction des besoins. On notera toutefois que si la liste à la source des règles est modifiée, il est nécessaire
         *    de l'inférer à nouveau.
         *
         */

        /*
         * vérification élémentaire de la syntaxe.
         */
        startAt.isGoodArgsCnt(2,4);

        /*
         * liste des règles
         */
       
        // longueur de l'expression...
        int size = startAt.size();

        // fermeture...
        Heap fermeture = null;

        // liste des règles
        ArrayList<Rule> rules = new ArrayList<Rule>();

        // résultat...
        Node res = null;

        //
        Interpreter interpreter = Interpreter.mySelf();

        /*
         * récupération de la liste des règles
         */
        Node liste_r = startAt.getSubNode(1, Node.TYPE_CLIST);

        /*
         * rechercher la description de la fermeture s'il y en a une...
         */
        Node with_cache = null;
        if (size == 4) {
            startAt.requirePCode(2,PCoder.PC_WITH);
            /*
             * il y a une fermeture...
             */
            with_cache = startAt.getSubNode(3, Node.TYPE_LAZY);
            fermeture = new Heap();
        }
    
           
        /**
         * protection du système...
         */
        BaseContextSnapshot contextSnapShot = new BaseContextSnapshot(interpreter);


        /**
         * boucle principale...
         */

        interpreter.setCanLoop(true);
        interpreter.setInLoop(true);

        Exception allExcep = null;
        try {

            /**
             * Lecture des règles...
             *
             */
            for (int i = 0; i < liste_r.size(); i++) {
                Node elem_r = liste_r.getSubNode(i, Node.TYPE_QEXPR);
                addRules(rules, elem_r);
            }

            /**
             * On va commencé la boucle d'inférence...
             */
            // placer la fermeture s'il y en a une...
            if(fermeture!=null){
                Heap.push(fermeture);
                with_cache.exec(true);
            }
            // préparer le heap local pour le traitement...
            Heap.push();
            Heap local = Heap.current();

            // préparer la boucle d'inférence...
            int verif;
            do {
                verif = 0;
                int i = 0;
                while (i < rules.size() && interpreter.hasNoBreakCode()) {
                    /*
                     * Conserver rules.size() la taille pouvant être modifiée en cours d'évaluation.
                     * De plus, en cas de code break quelconque, on s'arrête (skip-loop) et (break-loop).
                     * Par contre dans le cas de (complete-loop) on termine l'analyse de l'ensemble des règles
                     * avant d'arrêter.
                     */
                    Rule rule = (Rule) rules.get(i);
                    if (Node.isTrueEquivalent(evalSection(local, rule.condition))) {
                        /*
                         * condition vérifiée... On traite la partie then...
                         */
                        verif++;
                        res = evalSection(local, rule.getConsequenceThen().getSymbolicValue()); // évaluation pareseuse des symboles...
                        if (res != null) {
                            break;
                        }
                        if (rule.getRuleType() == PCoder.PC_ONCE) {
                            // once : supprimer la règle (l'index actuel pointe donc sur la règle suivante)
                            rules.remove(i);
                        }
                        else {
                            // each-time : on ne supprime pas la règle et on passe à la suivante
                            i++;
                        }
                    }
                    else if (rule.getConsequenceElse() != null) {
                        // étant donné le parsing précédent, pas besoin de valider: il ne peut s'agir que de each-time...
                        /*
                         * si pas vérifié et qu'il y a une clause else... On traite la partie else...
                         */
                        verif++;
                        res = evalSection(local, rule.getConsequenceElse().getSymbolicValue()); // évaluation paresseuse des symboles...
                        if (res != null) {
                            break;
                        }
                        // on ne peut avoir ici que each-time -> on ne supprime pas la règle et on passe à la suivante
                        i++;
                    }
                    else {
                        /*
                         * si pas vérifié et pas de else... On passe alors au suivant...
                         */
                        i++;
                    }
                }
            }
            while (verif > 0 && res == null && interpreter.isCanIterate());
            /*
             * Si (skip-loop), on repart...
             * Si (complete-loop), on s'arrête...
             * Si (break-loop), on s'arrête aussi...
             */

            // Supprime le heap local...
            Heap.pull();
            // Supprime la fermeture s'il y en a une...
            if(fermeture!=null){
                Heap.pull();
            }

        }
      
        catch (Exception ex) {
            allExcep = ex;
        }
       
       
        /*
         * restauration du système...
         */
        contextSnapShot.restore(); // remplace restore_ignoreBreakCode() qui ne restaure pas les état BREAK (ce qui était une erreur de logique).
       
        /*
         * propagation de l'exception éventuelle...
         */
        if (allExcep != null) {
            throw allExcep;
        }

        /*
         * si tout va bien, on retourne le résultat...
         */
        return res;

    }


}
TOP

Related Classes of abstrasy.pcfx.PCFx_infer$Rule

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.