Package abstrasy.pcfx

Source Code of abstrasy.pcfx.PCFx_function

package abstrasy.pcfx;


import abstrasy.Function;
import abstrasy.Heap;
import abstrasy.Node;
import abstrasy.PCoder;
import abstrasy.ASymbol;

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

/**
* 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_function extends PCFx {

    public PCFx_function() {
    }

    /*
     * Memoization native dépréciée momentanément (l.bruninx, 2012-07-20)
     * ------------------------------------------------------------------
     *  La mémoization implémentée jusqu'ici utilise un type interne non accessible par le programmeur.
     *  Cette implémentation entre en conflit avec l'utilisation de Node.external pour y mettre le heap
     *  d'un node de type OBJECT ou NAMESPACE.
     *
     *  Cette dernière implémentation est prioritaire sur la première d'autant plus qu'elle permet de
     *  résoudre également un souci de partage des données dans un contexte parallèlisé. Le objHeap d'un
     *  Node FUNCTION peut être réécrit par des procéssus différents. Alors que dans le cas d'un object,
     *  le node contenant reste le même.
     *

    private static final void memoize(Node fx, Node args, Node rnode) throws Exception {
        boolean memoizable = Node.isMemoizable(args);
        Node memoizeN=fx.elementAt(2);
        if (memoizeN.getExternal() == null) {
            fx.setElementAt(Node.createExternal(new Hashtable<MemoizeKey, Node>()),2);
        }
        if (memoizable) {
            Hashtable<MemoizeKey,Node> memoiz = (Hashtable<MemoizeKey,Node>) fx.elementAt(2).getExternal();
            memoiz.put(new MemoizeKey(args), rnode);
        }
        else {
            throw new InterpreterException(StdErrors.Memoizable_argument_required);
        }
    }

    private static final void memoize_dump(Node fx, Node lanode) throws Exception {
        for (int i = 0; i < lanode.size(); i++) {
            // traiter cas par cas...
            Node segnode = lanode.getSubNode(i, Node.TYPE_LIST | Node.TYPE_QEXPR);
            segnode.requirePCode(1, PCoder.PC_RETURN);
            Node anode = segnode.getSubNode(0, Node.TYPE_LIST);
            Node rnode = segnode.getSubNode(2, Node.VTYPE_VALUABLE);
            segnode.isGoodArgsCnt(3);
            memoize(fx, anode, rnode);
        }
    }
    */

    /**
     * eval
     *
     * @param startAt Node
     * @return Node
     * @throws Exception
     * @todo Implémenter cette méthode abstrasy.PCFx
     */
    public Node eval(Node startAt) throws Exception {
        /**
     * formes:
         *
         *  Forme générale:
         *      (function [final] [inline|override] ['symbole] [{...}] [[with [{...}|scope]|[yield [{...}|scope]] )
         *
         *
         *
         *
         *  Fonction inline: (cas particulier)
         *  ---------------
         *      (function inline 'symbol {...})
         *      (function inline {...}) -> fx
         *
         *
         *
         *  Fonction classique:
         *  ------------------
         *      (function {...}) -> fx
         *      (function 'symbol {...})
         *
         *
         *
         *
         *  Fonction avec fermeture "privée":
         *  --------------------------------
         *      (function {...} with lazy/scope) -> fx
         *      (function 'symbol {...} with lazy/scope)
         *     
         *              La fonction utilise un scope pour stocker des variables privées. Le scope liée à la fonction
         *              à l'aide de with n'est pas "exporté" lors d'un override. Il s'agit donc d'une fermeture "privée".
         *
         *  Fonction avec fermeture "rapportée":
         *  -----------------------------------
         *      (function {...} yield lazy/scope) -> fx
         *      (function 'symbol {...} yield lazy/scope)
         *
         *              La fonction utilise un scope pour stocker des variables. Toutefois le scope est "rapporté" en
         *              cas d'un override. Les variables du scope yield sont donc disponibles pour le corps de la
         *              fonction override.
         *             
         *  Fonction avec fermetures "privée" et "rapportée":
         *  ------------------------------------------------
         *      (function {...} with lazy/scope yield lazy/scope) -> fx
         *      (function 'symbol {...} with lazy/scope yield lazy/scope)
         *     
         *              On peut associer les deux modes de exportation des fermetures.
         *
         *
         *  Fonction wrapper:
         *  ----------------
         *      (function wrapper with ... yield ...) -> fx
         *      (function wrapper 'symbole with ... yield ...)
         *
         *
         *  Fonction override (simple copie, mais pas la même identité):
         *  -----------------------------------------------------------
         *      (function override 'super)
         *      (function override super) -> fx
         *     
         *  Fonction override avec remplacement du corps de la fonction:
         *  -----------------------------------------------------------
         *      (function override 'super {...})
         *      (function override super {...}) -> fx
         *
         *  Fonction override avec fermetures (toutes les variantes possibles):
         *  ------------------------------------------------------------------
         *      (function override 'symbol {...} with ... yield ...)
         *      (function override 'symbol with ... yield ...)
         *      (function override symbol {...} with ...  yield ...) -> fx
         *      (function override symbol with ... yield ...) -> fx
         *
     */


        // o_rel : position relative du dernier argument lu...
        int o_rel = 1;
       
        // o_arg dernier argument lu...
        Node o_arg=startAt.elementAt(o_rel).getSymbolicValue();
       
        //
        // option final
        //
        boolean e_final = (!o_arg.isQuoted()) && o_arg.isPCode(PCoder.PC_FINAL);
        if(e_final)
            o_arg=startAt.elementAt(++o_rel).getSymbolicValue();


        //
        // option inline | override | wrapper
        //
        boolean e_inline = (!o_arg.isQuoted()) && o_arg.isPCode(PCoder.PC_INLINE);
        boolean e_override = (!o_arg.isQuoted()) && o_arg.isPCode(PCoder.PC_OVERRIDE);
        boolean e_wrapper = (!o_arg.isQuoted()) && o_arg.isPCode(PCoder.PC_WRAPPER);
        if(e_inline||e_override||e_wrapper)
            o_arg=startAt.elementAt(++o_rel).getSymbolicValue();
   
       
        //
        //
        // On peut déjà faire un dispatching en fonction de l'option inline ou override
        //
        // (function [final] [inline|override] *...)
        //
       
        if (e_inline) {
            /**
             * inline:
             * ------
             */
            o_arg.requireNodeType(Node.TYPE_QSYMBOL|Node.TYPE_LAZY);
            if(o_arg.isQSymbol()){
                //
                // forme : ... 'symbole {...})
                //
                ASymbol e_symbole = o_arg.getSymbol();
                Node e_body = startAt.getSubNode(++o_rel, Node.TYPE_LAZY);
                startAt.isGoodArgsCnt(o_rel+1); // Vérifie la forme
                Node e_function = Node.createInlineFunction(e_body);
                if (e_final && !e_symbole.isImmutable())
                    throw new InterpreterException(StdErrors.Immutable_symbol_required);
                Heap.defv(e_symbole, e_function.letFinal(e_symbole.isImmutable()));
                return null;  
            }
            else{
                //
                // forme : ... {...})
                //
                startAt.isGoodArgsCnt(o_rel+1);
                Node e_body = o_arg;
                Node e_function = Node.createInlineFunction(e_body).letFinal(e_final);
                return e_function;
            }
        }
        else if(e_override){
            /**
             * override
             */
            //
            // forme : ... 'symbole ...
            //    et : ... function ...
            //
            o_arg.requireNodeType(Node.TYPE_QSYMBOL|Node.TYPE_FUNCTION);
            ASymbol e_symbole=null;
            Node e_body=null;
            Node e_super=null;
            if(o_arg.isQSymbol()){
                e_symbole = o_arg.getSymbol();
                e_super = Heap.getv(e_symbole);
                e_super.requireAccessType(Node.ACCESSVTYPE_MUTABLE_WRITELOCK);
                e_super.requireNodeType(Node.TYPE_FUNCTION);
            }
            else{
               e_super = o_arg;
               e_super.requireAccessType(Node.ACCESSVTYPE_MUTABLE_WRITELOCK);
            }
            //
            // forme : ... [{...}] ...
            //
            if(startAt.testSubNode(++o_rel, Node.TYPE_LAZY)){
                e_body=startAt.getSubNode(o_rel, Node.TYPE_LAZY);
            }
            else{
                o_rel--; // Attention!!! il faut revenir en arrière...
                e_body=((Function) e_super.getExternal()).getBodyFx();
            }
            //
            // Rechercher la forme [with lazy/scope] et/ou [from lazy/scope]
            //
            Node e_with=null;
            Node e_yield=null;
            while(startAt.size()>o_rel+1){
                o_arg=startAt.getSubNode(++o_rel, Node.TYPE_PCODE);
                if(o_arg.isPCode(PCoder.PC_WITH))
                    if(e_with!=null)
                        throw new InterpreterException(StdErrors.extend(StdErrors.Duplicate_parameters,o_arg.toString()));
                    else{
                        e_with=startAt.getSubNode(++o_rel, Node.TYPE_LAZY|Node.TYPE_SCOPE);
                        if(e_with.isLazy())
                            e_with=Node.createScope(e_with);
                    }
                else if(o_arg.isPCode(PCoder.PC_YIELD))
                    if(e_yield!=null)
                        throw new InterpreterException(StdErrors.extend(StdErrors.Duplicate_parameters,o_arg.toString()));
                    else{
                        e_yield=startAt.getSubNode(++o_rel, Node.TYPE_LAZY|Node.TYPE_SCOPE);
                        if(e_yield.isLazy())
                            e_yield=Node.createScope(e_yield);
                    }
            }
            //
            // On a tout ce qu'il faut...
            //
            startAt.isGoodArgsCnt(o_rel+1); // Vérifie la forme
            Node e_function = Node.createOverridedFunction(e_body,e_yield,e_with,e_super);
            if (e_symbole == null)
                return e_function.letFinal(e_final);
            else {
                e_function.derefTo(e_super);
                return null;
            }
           
           
        }
        else if(e_wrapper){
            /**
             * wrapper
             */
            //
            // forme : ... ['symbole] ...
            //
            o_arg.requireNodeType(Node.TYPE_QSYMBOL|Node.TYPE_PCODE);
            ASymbol e_symbole=null;
            if(o_arg.isQSymbol()){
                e_symbole = o_arg.getSymbol();
                o_arg=startAt.getSubNode(++o_rel, Node.TYPE_PCODE);
            }
   
            //
            // Rechercher la forme [with lazy/scope] et/ou [from lazy/scope]
            //
            // Attention, dans ce cas, o_arg contient déjà le premier PCode with ou yield.
            // --------------------------------------------------------------------------
            // La boucle est donc différente ici que dans les autres cas...
            //
            // De plus, il est obligatoire de stipuler au moins un des deux scopes.
            //                                         -----------
            //
            Node e_with=null;
            Node e_yield=null;
            do{
                // on ne cherche o_arg que s'il est null
                if(o_arg==null)
                    o_arg=startAt.getSubNode(++o_rel, Node.TYPE_PCODE);
                if(o_arg.isPCode(PCoder.PC_WITH))
                    if(e_with!=null)
                        throw new InterpreterException(StdErrors.extend(StdErrors.Duplicate_parameters,o_arg.toString()));
                    else{
                        e_with=startAt.getSubNode(++o_rel, Node.TYPE_LAZY|Node.TYPE_SCOPE);
                        if(e_with.isLazy())
                            e_with=Node.createScope(e_with);
                    }
                else if(o_arg.isPCode(PCoder.PC_YIELD))
                    if(e_yield!=null)
                        throw new InterpreterException(StdErrors.extend(StdErrors.Duplicate_parameters,o_arg.toString()));
                    else{
                        e_yield=startAt.getSubNode(++o_rel, Node.TYPE_LAZY|Node.TYPE_SCOPE);
                        if(e_yield.isLazy())
                            e_yield=Node.createScope(e_yield);
                    }
                // on met o_arg=null pour la suite...
                o_arg=null;
            }while(startAt.size()>o_rel+1);
            //
            // On a tout ce qu'il faut...
            //
            startAt.isGoodArgsCnt(o_rel+1); // Vérifie la forme
            Node e_function = Node.createFunction(null,e_yield,e_with); // on crée une fonction wrapper (sans corps)
            if(e_symbole!=null){
                if (e_final && !e_symbole.isImmutable())
                    throw new InterpreterException(StdErrors.Immutable_symbol_required);
                Heap.defv(e_symbole, e_function.letFinal(e_symbole.isImmutable()));
                return null;
            }
            else
                return e_function.letFinal(e_final);
           
        }
        else{
            /**
             * classique
             */
            //
            // forme : ... 'symbole {...} ...
            //    et : ... {...} ...
            //
            o_arg.requireNodeType(Node.TYPE_QSYMBOL|Node.TYPE_LAZY);
            ASymbol e_symbole=null;
            if(o_arg.isQSymbol()){
                e_symbole = o_arg.getSymbol();
                o_arg=startAt.getSubNode(++o_rel, Node.TYPE_LAZY);
            }
            Node e_body = o_arg;
            //
            // Rechercher la forme [with lazy/scope] et/ou [from lazy/scope]
            //
            Node e_with=null;
            Node e_yield=null;
            while(startAt.size()>o_rel+1){
                o_arg=startAt.getSubNode(++o_rel, Node.TYPE_PCODE);
                if(o_arg.isPCode(PCoder.PC_WITH))
                    if(e_with!=null)
                        throw new InterpreterException(StdErrors.extend(StdErrors.Duplicate_parameters,o_arg.toString()));
                    else{
                        e_with=startAt.getSubNode(++o_rel, Node.TYPE_LAZY|Node.TYPE_SCOPE);
                        if(e_with.isLazy())
                            e_with=Node.createScope(e_with);
                    }
                else if(o_arg.isPCode(PCoder.PC_YIELD))
                    if(e_yield!=null)
                        throw new InterpreterException(StdErrors.extend(StdErrors.Duplicate_parameters,o_arg.toString()));
                    else{
                        e_yield=startAt.getSubNode(++o_rel, Node.TYPE_LAZY|Node.TYPE_SCOPE);
                        if(e_yield.isLazy())
                            e_yield=Node.createScope(e_yield);
                    }
            }
            //
            // On a tout ce qu'il faut...
            //
            startAt.isGoodArgsCnt(o_rel+1); // Vérifie la forme
            Node e_function = Node.createFunction(e_body,e_yield,e_with);
            if(e_symbole!=null){
                if (e_final && !e_symbole.isImmutable())
                    throw new InterpreterException(StdErrors.Immutable_symbol_required);
                Heap.defv(e_symbole, e_function.letFinal(e_symbole.isImmutable()));
                return null;
            }
            else
                return e_function.letFinal(e_final);
           
        }
       
    }


}

TOP

Related Classes of abstrasy.pcfx.PCFx_function

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.