Package abstrasy

Source Code of abstrasy.Heap

package abstrasy;


import abstrasy.interpreter.ExternalTK;
import abstrasy.interpreter.InterpreterException;
import abstrasy.interpreter.PRECOMP;
import abstrasy.interpreter.StdErrors;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Vector;

/**
* 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 final class Heap extends QHash {
    /*
     * ----------------------------------------------------------------------------------------------------
     * Notes:
     * ----------------------------------------------------------------------------------------------------
     * Il est difficile d'estimer s'il est plus performant de surcharger une HashMap ou de l'implémenter
     * par délagation. Cette dernière possibilité évite la création d'une hashmap en même temps que le
     * Heap. Cependant, chaque tentative de get et de put nécessite le test de l'existance de la table
     * de hashage. Ce qui nécessite un traitement continu, alors que le création de la hashtable n'a lieu
     * qu'une seule fois.
     *
     * On notera que Node utilise une délagation pour les childs. Cependant, dans ce cas, la plupart des
     * Node n'ont pas de childs. Or, la grande majorité des Heaps emportent des données (au moins une). La
     * stratégie doit donc être différente.
     *
     * Aussi, est-il plus efficace de créer un type particulier pour recevoir les symboles ?...
     *
     * Il est évident que l'on peut certainement gagner du temps en supprimant la nécessiter de "splitter"
     * systématiquement chaque symboles composés lors de chaque interrogation. Toutefois, il faut retenir
     * qu'Abstrasy est un langage hautement dynamique. Ainsi, le code même du programme en cours peut même
     * changer au cours de sa propre évaluation. Il faut donc éviter tout "prélink" qui pourrait finalement
     * indiquer une mauvaise position dans la mémoire.
     *
     * Idéalement, une solution aurait pu être facilement implémentée s'il était possible de créer une
     * spécification de String. Mais en Java, String est final. En outre, créer une nouvelle classe dans
     * laquelle toutes les méthodes ou presque seraient des délagations de String serait contre-productif.
     *
     * ----------------------------------------------------------------------------------------------------
     */

    static private final Object REG_COUNTER_SYNCHRONIZER = new Object();
    static private int REG_COUNTER = 0;

    static private final int get_REG_COUNTER() {
        synchronized (REG_COUNTER_SYNCHRONIZER) {
            if (REG_COUNTER == Integer.MAX_VALUE)
                REG_COUNTER = 0;
            return ++REG_COUNTER;
        }
    }

    static public String createSymbolReg() {
        String code = Integer.toString(get_REG_COUNTER(), 32);
        String micro = Integer.toHexString((int) System.currentTimeMillis() & 0xF);
        return code + micro;
    }

    final private static String SEP_str = PCoder.SEP_str;
    final private static int REG = PCoder.REG;

    final public static String ROOT_str = "";
   

    private boolean keep = false;

    void setKeep(boolean keep) {
        this.keep = keep;
    }

    boolean isKeep() {
        return keep;
    }

    private static int _UIDCnt = 0;

    private int uid = 0;

    private final int getUID() {
        if (uid == 0) {
            uid = ++_UIDCnt;
            if (_UIDCnt == 0)
                return getUID(); // 0 pas autorisé...
        }
        return uid;
    }

    public boolean isItMe(Heap heap) {
        return getUID() == heap.getUID();
    }


    /**
     * Continuer sur le Namespace suivant...
     */
    private Node extended = null;

    public boolean isExtended() {
        return extended != null;
    }

    public Node getExtended() {
        return extended;
    }

    public void setExtended(Node binded) throws InterpreterException {
        binded.requireNodeType(Node.VTYPE_DELEGABLE);
        Node bloop = binded;
        while (bloop != null && (bloop.isNamespace() || bloop.isScope())) {
            Heap bloop_h = ((Heap) bloop.getExternal());
            if (isItMe(bloop_h))
                throw new InterpreterException(StdErrors.Circulare_reference);
            bloop = bloop_h.extended;
        }
        this.extended = binded;
    }

    public void clear() {
        uid = 0;
        keep = false;
        extended = null;
        super.clear();
    }

    public boolean isLoaded() {
        return super.isLoaded() || extended != null;
    }


    public void remove_s(String key) {
        //System.out.println("Remove "+key);
        if (this.containsKey(key))
            this.remove(key);
    }

    public Heap() {
        super();
    }

    /**
     * Copie de la structure du Heap. Le contenu est simplement reporté sans
     * aucun clonage ni déréférencement.
     *
     * @param heap
     */
    public Heap(Heap heap) {
        keep = heap.keep;
        extended = heap.extended; // c'est un Node (pas un Heap)
       
        Iterator<String> cles = heap.keysIterator();
        while (cles.hasNext()) {
            String symbol = cles.next();
            this.put(symbol, heap.get(symbol));
            /*
             * Ne pas cloner les valeurs, simplement duppliquer la structure du Heap...
             */
        }

    }

    /*
     * Clonage de Heap...
     */

    static Heap createClone(Heap heap, Bivalence bival) throws Exception {
        if (heap == null)
            return null;
        // op_clone++; // pour debug...
        //System.out.println("Clone heap!!! : " + heap.toString()); // pour debug...
        Heap t = new Heap();
        t.keep = heap.keep;

        /**
         * Le node object est mis dans bival avant le clonage, si on le retrouve,
         * on utilise le même référence.
         **/
        t.extended = heap.extended != null ? Node.createClone(heap.extended, bival): null;

        //t.ancestor=null; // inutile, déjà appliqué par défaut...
        /**
         * La transversalité s'applique t'elle à un clone ?
         * ================================================
         *
         * Cela peut donner lieu à un débat. Toutefois, il faut faire un choix.
         *
         * La proposition qui parait la plus judicieuse consiste à ne pas appliquer de transversalité à un clone.
         *
         * En effet, imaginons le cas où nous clonons un Heap dans un acteur fils. L'accès à une variable à lecture
         * destructive dans le clone, ne consiste pas à un accès transversal, mais bien à un accès à l'instance
         * clonée (qui est une nouvelle instance).
         *
         * De fait, l'héritage transversal ne s'applique pas aux clones (on peut considérer que les clones n'ont pas de parents).
         *
         *
         **/
        Iterator<String> cles = heap.keysIterator();
        while (cles.hasNext()) {
            String symbol = cles.next();
            Node ynode = heap.get(symbol);
            if (ynode != null)
                t.put(symbol, Node.createClone(ynode, bival));
            //System.out.println("CLONE-HEAP: "+symbol+" = "+heap.get(symbol)); // pour debug
        }
        return t;
    }


    final private static boolean isMatching_(String s) {
        return s.charAt(0) == '?';
    }

    final private static boolean isImmutable_(String s) {
        char c = s.charAt(0);
        return (c <= 'Z' && c >= 'A');
    }

    final private static boolean isImmuable_(String s) {
        int i = s.length();
        if (i <= 1)
            return false;
        while (i > 0) {
            char c = s.charAt(--i);
            if ((c > 'Z' || c < 'A') && c != '_')
                return false;
        }
        return true;
    }


    final public static void push() {
        Interpreter.mySelf().getGLOBAL().push();
    }

    final public static void push(Heap objHeap) {
        Interpreter.mySelf().getGLOBAL().push(objHeap);
    }

    final public static void pull() {
        Interpreter.mySelf().getGLOBAL().pull();
    }

    final public static Heap current() {
        return Interpreter.mySelf().getGLOBAL().current();
    }


    /**
     *
     * retrouver les données...
     *
     */


    final static private void require_delegable_(Node node) throws InterpreterException {
        if (node == null)
            throw new InterpreterException(StdErrors.Symbol_not_defined);
        else if (!node.isDelegable()) //System.out.println("*** "+ node);
            throw new InterpreterException(StdErrors.extend(StdErrors.Delegable_object_required, node.typeOfNode()));
    }

    /**
     * Effectue les vérifications d'usages. Node doit être un vObject disposant d'un heap.
     *
     * @param node
     * @throws Exception
     */
    final static private void require_namespace_(Node node) throws InterpreterException {
        if (node == null)
            throw new InterpreterException(StdErrors.Symbol_not_defined);
        else if (!node.isNamespace())
            throw new InterpreterException(StdErrors.extend(StdErrors.Object_required, node.typeOfNode()));
        //else if (node.getExternal() == null)
        //    throw new InterpreterException(StdErrors.Internal_error);
    }

    /**
     * Recherche la référence du symbole (non composé) dans la pile globale.
     * Si le symbole n'est pas trouvé, déclenche une exception.
     * S'il est trouvé, la méthode retourne le Heap dans lequel le symbole est
     * défini.
     *
     * Attention, il s'agit de la version non destructrice.
     *
     * @param global : pile.
     * @param id     : symbole
     * @return Heap
     * @throws Exception
     */
    final private static Heap geth_nd_(StaticHeap global, String id) throws InterpreterException {
        Node res = null;
        int hi = global.size() - 1;
        while (hi >= 0) {
            Heap heap = global.get(hi--);
            if (heap.isLoaded()) {
                res = heap.get(id);
                if (res != null)
                    return heap;
            }
        }
        throw new InterpreterException(StdErrors.Symbol_not_defined);
    }

    /**
     * Recherche la référence du symbole (non composé) dans la pile globale.
     * Si le symbole n'est pas trouvé, déclenche une exception.
     *
     * Attention, il s'agit de la version non destructrice.
     *
     * @param global : pile.
     * @param id     : symbole
     * @return Node  : Node trouvé.
     * @throws Exception
     */
    final private static Node get_nd_(StaticHeap global, String id) throws InterpreterException {
        /**
         * optimisation sur des variables et constantes système
         */
        if (id == ROOT_str)
            return abstrasy.SELF.get();
       
        /**
         * non optimisé...
         */
        Node res = null;
        int hi = global.size() - 1;
        while (hi >= 0) {
            Heap heap = global.get(hi--);
            //if (heap.isLoaded()) {
            res = heap.get(id);
            if (res != null) {
                res.setSelfFx(null);
                /**
                 * JUSTEMENT, IL ne faut pas transporter le heap local ici !!!
                 *
                 * On n'est pas dans un objet!!!
                 */
                return res;
            }
            //}
        }
        throw new InterpreterException(StdErrors.Symbol_not_defined);
    }

    /**
     * Recherche la référence du symbole (non composé) dans la pile globale.
     * Si le symbole n'est pas trouvé, déclenche une exception.
     *
     * Version destructrice.
     *
     * @param global : pile.
     * @param id     : symbole
     * @return Node  : Node trouvé.
     * @throws Exception
     */
    final private static Node get_uo_(StaticHeap global, String id) throws InterpreterException {
        /**
         * optimisation sur des variables et constantes système
         */

        if (id == ROOT_str)
            return abstrasy.SELF.get();

        /**
         * non optimisé...
         */
        Node res;
        int hi = global.size() - 1;
        while (hi >= 0) {
            Heap heap = global.get(hi--);
            //if (heap.isLoaded()) {
            res = heap.get(id);
            if (res != null) {
                res.setSelfFx(null);
                //
                // JUSTEMENT, IL ne faut pas transporter le heap local ici !!!
                //
                // On n'est pas dans un objet!!!
                //
                return res;
            }
            //}
        }
        //System.out.println("get_uo_("+id+"):"+res);
        throw new InterpreterException(StdErrors.extend(StdErrors.Symbol_not_defined, id));
    }

    /**
     * Effectue le post-traitement d'une référence par rapport à l'immutabilité.
     * Si id est un symbole immutable, la référence est duppliquée et marquée comme
     * finale.
     *
     * @param node
     * @param id
     * @return
     */
    final private static Node post_check_(Node node, String id) throws InterpreterException {
        if (node != null && isImmutable_(id) && !node.isFinalNode()) {
            //System.out.println("Symbole postcheck: "+id);
            Node res = node.deref();
            res.setFinalNode(true);
            return res;
        }
        return node;
    }

    /**
     * Récupère une référence sur la pile et affecte la référence en fonction de l'immutabilité
     * du symbole.
     *
     * Attention, il s'agit de la version non destructive.
     *
     * @param global
     * @param id
     * @return
     * @throws Exception
     */
    final private static Node get_single_nd_(StaticHeap global, String id) throws InterpreterException {
        return post_check_(get_nd_(global, id), id);
    }

    /**
     * Récupère une référence sur la pile et affecte la référence en fonction de l'immutabilité
     * du symbole.
     *
     * version destructive.
     *
     * @param global
     * @param id
     * @return
     * @throws Exception
     */
    final private static Node get_single_uo_(StaticHeap global, String id) throws InterpreterException {
        return post_check_(get_uo_(global, id), id);
    }

    /**
     * Permet de rechercher une référence dans la hiérarchie d'un objet.
     * Tient compte de la possibilité que le symbole soit Hidden.
     *
     * S'il est trouvé, la fonction retourne le heap.
     *
     * Attention, version non destructive...
     *
     * @param vobj
     * @param id
     * @return
     * @throws Exception
     */
    final private static Heap geth_nd_(Node vobj, String id) throws InterpreterException {
        require_namespace_(vobj);
        Heap heap = (Heap) vobj.getExternal();
        Node res = heap.get(id);
        if (res != null)
            return heap;
        //
        //
        // Cas d'espace de noms liés.
        //
        if (heap.extended != null)
            return geth_nd_(heap.extended, id);
        else
            throw new InterpreterException(StdErrors.Symbol_not_defined);
    }

    /**
     * Permet de rechercher une référence dans la hiérarchie d'un objet.
     * Tient compte de la possibilité que le symbole soit Hidden.
     *
     * Attention, version non destructive...
     *
     * @param vobj
     * @param id
     * @return
     * @throws Exception
     */
    final private static Node get_nd_(Node vobj, String id) throws InterpreterException {
        //System.out.println("Get_nd_ OBJ="+vobj);
        require_delegable_(vobj);

        if (id == ROOT_str)
            return vobj;

        switch (vobj.getType()) {

            case Node.TYPE_NAMESPACE:
                Heap heap = (Heap) vobj.getExternal();
                Node res = heap.get(id);
                //
                if (res != null) {
                    res.setSelfFx(vobj);
                    return res;
                }
                //
                //
                // Cas d'espace de noms liés.
                //
                if (heap.extended != null) {
                    res = get_nd_(heap.extended, id);
                    if (res!=null)
                        res.setSelfFx(vobj);
                    // si res nécessite le transport du heap local (type autre que Node.namespace)
                    // System.out.println("Get_nd_ RES="+res);
                    return res;
                }
                else
                    throw new InterpreterException(StdErrors.extend(StdErrors.Symbol_not_defined, id));


            case Node.TYPE_EXTERNAL:
                if (ExternalTK.hasSlot(vobj, id))
                    return Node.createInlineFunction(Node.createLazy().append(PRECOMP.PC_EXTCALL_).append(vobj).append(Node.createQSymbol(id)));
                throw new InterpreterException(StdErrors.extend(StdErrors.Symbol_not_defined, id));

            case Node.TYPE_FUNCTION:
                //if (Node.VDelegable.hasSlot(vobj, id))
                    return Node.createInlineFunction(Node.createLazy().append(vobj).append(Node.createQSymbol(id)));
                //throw new InterpreterException(StdErrors.extend(StdErrors.Symbol_not_defined, id));

            default:
                throw new InterpreterException(StdErrors.Internal_error);
        }
    }


    /**
     * Permet de rechercher une référence dans la hiérarchie d'un objet.
     * Tient compte de la possibilité que le symbole soit Hidden.
     *
     * version destructive...
     *
     * @param vobj
     * @param id
     * @return
     * @throws Exception
     */
    final private static Node get_uo_(Node vobj, String id) throws InterpreterException {
        require_delegable_(vobj);

        if (id == ROOT_str)
            return vobj;

        switch (vobj.getType()) {

            case Node.TYPE_NAMESPACE:
                Heap heap = (Heap) vobj.getExternal();
                Node res = heap.get(id);
                if (res != null) {
                    res.setSelfFx(vobj);
                    /*
                     * nécessite le transport du heap local (type autre que Node.namespace)
                     */
                    return res;
                }

                //
                //
                // Cas d'espace de noms liés.
                //
                if (heap.extended != null) {
                    res = get_uo_(heap.extended, id);
                    if (res != null) {
                        res.setSelfFx(vobj);
                        /*
                         * nécessite le transport du heap local (type autre que Node.namespace)
                         */
                        return res;
                    }
                }
                else
                    throw new InterpreterException(StdErrors.Symbol_not_defined);


            case Node.TYPE_EXTERNAL:
                if (ExternalTK.hasSlot(vobj, id))
                    return Node.createInlineFunction(Node.createLazy().append(PRECOMP.PC_EXTCALL_).append(vobj).append(Node.createQSymbol(id)));
                throw new InterpreterException(StdErrors.extend(StdErrors.Symbol_not_defined, id));

            case Node.TYPE_FUNCTION:
                //if (Node.VDelegable.hasSlot(vobj, id))
                    return Node.createInlineFunction(Node.createLazy().append(vobj).append(Node.createQSymbol(id)));
                //throw new InterpreterException(StdErrors.extend(StdErrors.Symbol_not_defined, id));

            default:
                throw new InterpreterException(StdErrors.Internal_error);
        }
    }

    /**
     * Permet de rechercher le heap d'un symbole composé.
     * La recherche tient compte du fait que le symbole soit privé ou hidden.
     * Notez que le symbole doit absolument être présent.
     *
     * Lorsque le symbole est trouvé, la méthode retourne le Heap de l'élément.
     *
     * Il s'agit de la version non destructive.
     *
     * @param global
     * @param ids
     * @return
     * @throws Exception
     */
    final private static Heap gethAlways_nd_(StaticHeap global, String[] ids) throws InterpreterException {
        Node res = get_nd_(global, ids[0]);
        int maxprof = ids.length - 1; // s'il y a des éléments intermédiaires...
        for (int i = 1; i < maxprof; i++)
            res = get_nd_(res, ids[i]);
        return geth_nd_(res, ids[ids.length - 1]);
    }


    /**
     * Permet de rechercher le heap d'un symbole composé. Cette alternative à la méthode
     * précédente ne nécessite pas que la référence finale soit effectivement définie. Elle
     * retourne le Heap dans lequel la référence peut être définie. Cette méthode est donc
     * utile pour setv(...) lorsqu'un symbole composé doit être défini.
     * Par ailleurs, la recherche tient compte du fait que le symbole soit privé ou hidden.
     *
     * La méthode retourne le Heap dans lequel l'élément peut être défini.
     *
     * Il s'agit de la version non destructive.
     *
     * @param global
     * @param ids
     * @return
     * @throws Exception
     */
    final private static Heap getPhAlways_nd_(StaticHeap global, String[] ids) throws Exception {
        Node res = get_nd_(global, ids[0]);
        int maxprof = ids.length - 1; // s'il y a des éléments intermédiaires...
        for (int i = 1; i < maxprof; i++)
            res = get_nd_(res, ids[i]);
        require_namespace_(res);
        return (Heap) res.getExternal();
    }



    /**
     * Permet de rechercher un symbole composé. La référence est affectée selon qu'elle
     * soit immutable ou non. Par ailleurs, la recherche tient compte du fait que le symbole
     * soit privé ou hidden.
     *
     * version destructive.
     *
     * @param global
     * @param ids
     * @return
     * @throws Exception
     */
    final private static Node getAlways_uo_(StaticHeap global, String[] ids) throws InterpreterException {
        Node res = get_uo_(global, ids[0]);

        for (int i = 1; i < ids.length; i++)
            res = get_uo_(res, ids[i]);

        return post_check_(res, ids[ids.length - 1]);
    }

    /**
     * Permet de rechercher un symbole composé. La référence est affectée selon qu'elle
     * soit immutable ou non. Par ailleurs, la recherche tient compte du fait que le symbole
     * soit privé ou hidden.
     *
     * version destructive.
     *
     * @param namespace (espace de noms)
     * @param ids
     * @return
     * @throws Exception
     */
    final private static Node getAlways_uo_(Node namespace, String[] ids) throws InterpreterException {
        Node res = get_uo_(namespace, ids[0]);

        for (int i = 1; i < ids.length; i++)
            res = get_uo_(res, ids[i]);


        return post_check_(res, ids[ids.length - 1]);
    }

    /**
     * Place une nouvelle référence dans le Heap indiqué. Si toutefois le symbole est immutable et qu'il
     * est déjà défini, une exception est levée.
     *
     * Il en sera de même si le symbole est du type UseOnce. En vue d'éviter les effets de bords éventuels, une valeur
     * use once ne peut être redéfinie (sauf si elle a été lue et détruite avant).
     *
     * @param heap
     * @param id
     * @param node
     * @throws Exception
     */
    final private static void setv_in_(Heap heap, String id, Node node) throws Exception {
        if (isMatching_(id))
            throw new InterpreterException(StdErrors.Illegal_access_to_matching_symbol);
        if (isImmutable_(id) && heap.containsKey(id))
                throw new InterpreterException(StdErrors.Immutable_symbol_already_defined);
        heap.put(id, node);
    }


    final private static void setv_local_(StaticHeap global, ASymbol id, Node node) throws Exception {
        /**
          * test d'immuabilité...
          */
        if (isImmuable_(id.getStr()) && exists(id))
            throw new InterpreterException(StdErrors.Symbol_already_exists);
        setv_in_(global.current(), id.getStr(), node);
    }

    /**
     * Permet de placer une nouvelle variable dans le contexte en cours.
     * Si le symbole est immutable, il ne peut pas être re-assigné.
     *
     * Il s'agit de la version privée statique.
     *
     * @param id     : symbole (local)
     * @param node   : valeur
     * @throws Exception
     * @Deprecated
     */
    final public static void setv(ASymbol id, Node node) throws Exception {
        /**
     * auto réparation de la pile
     */
        StaticHeap global = Interpreter.mySelf().getGLOBAL();
        int href = global.size();
        int slock = global.getOffset();
        try {
            if (id.getIdsCnt() > 1) {
                String ids[] = id.getIds();
                /**
                 * test d'immuabilité NON intégré...
                 */
                if (isImmuable_(ids[ids.length - 1]) && exists(id))
                    throw new InterpreterException(StdErrors.Symbol_already_exists);
                /**
                 * on continue si ok!...
                 */
                Heap heap = getPhAlways_nd_(global, ids);
                setv_in_(heap, ids[ids.length - 1], node);
            }
            else {
                /**
                 * test d'immutabilité intégré...
                 */
                setv_local_(global, id, node);
            }
        }
        /**
     * auto réparation de la pile
     */
        catch (Exception ex) {
            // restaurer la pile si nécessaire...
            if (global.size() != href) {
                global.setOffset(slock);
                global.setSize(href);
            }
            // relancer l'exception
            throw ex;
        }
    }

    /**
     * Permet de définir une nouvelle variable dans le contexte en cours.
     * Si le symbole existe déjà, une exception est déclenchée.
     *
     * Il s'agit de la version privée statique.
     *
     * @param id     : symbole (local)
     * @param node   : valeur
     * @throws Exception
     */
    final private static void defv_local_(StaticHeap global, String id, Node node) throws Exception {
        /**
          * Si le symbole est déjà défini...
          */
        Heap localHeap = global.current();
        if (localHeap.containsKey(id))
            throw new InterpreterException(StdErrors.extend(StdErrors.Symbol_already_exists, id));
        setv_in_(localHeap, id, node);
    }

    final public static void defv(ASymbol id, Node node) throws Exception {
        /**
     * auto réparation de la pile
     */
        StaticHeap global = Interpreter.mySelf().getGLOBAL();
        int href = global.size();
        int slock = global.getOffset();
        try {
            if (id.getIdsCnt() > 1) {
                /**
                 * On trouve le heap du symbole
                 */
                String[]ids=id.getIds();
                Heap heap = getPhAlways_nd_(global, ids);
                /**
                 * test d'existance NON intégré...
                 */
                if (heap.containsKey(ids[ids.length - 1])) // Correctif du bug launchpad#1017500, l.bruninx (2012-06-25).
                    throw new InterpreterException(StdErrors.Symbol_already_exists);
                /**
                 * on continue si ok!...
                 */
                setv_in_(heap, ids[ids.length - 1], node);
            }
            else {
                /**
                 * test d'existance intégré...
                 */
                defv_local_(global, id.getStr(), node);
            }
        }
        /**
     * auto réparation de la pile
     */
        catch (Exception ex) {
            // restaurer la pile si nécessaire...
            if (global.size() != href) {
                global.setOffset(slock);
                global.setSize(href);
            }
            // relancer l'exception
            throw ex;
        }
    }

    /**
     * Echange le contenant de la variable dont le chemin est id par le
     * nouveau node. La méthode retourne l'ancien contenant de cette
     * variable.
     *
     * @param id
     * @param node
     * @return old_node
     * @throws Exception
     */
    final public static Node swapv(ASymbol id, Node node) throws Exception {
        Heap h = geth(id);
        String localId = id.getLocalName();
        Node old = h.get(localId);
        setv_in_(h, localId, node);
        return old;
    }


    public final static class DynamicConstants {

        /**
         * Permet de modifier l'état de MAIN de TRUE à FALSE...
         */
        final public static void setMAIN_FALSE() {
            StaticHeap global = Interpreter.mySelf().getGLOBAL();
            global.current().put(PCoder.MAIN, new Node(Node.FALSE).letFinal(true));
        }

    }





    final public static void newRETURN() {
        StaticHeap global = Interpreter.mySelf().getGLOBAL();
        global.current().put(PCoder.REG_RETURN, PRECOMP.VOIDNODE);
    }

    private static final Node _unVOID_(Node fromNode) {
        if (fromNode == null)
            return null;
        else if (fromNode.getType() == Node.TYPE_NONE)
            return null;
        else
            return fromNode;
    }

    final public static Node getRETURN() throws Exception {
        return _unVOID_(getv(ASymbol.SYMBOL_REG_RETURN));
    }

    final public static void setRETURN(Node value) throws Exception {
        geth(ASymbol.SYMBOL_REG_RETURN).put(PCoder.REG_RETURN, value);
    }


    private static final Node _getv_(ASymbol id) throws InterpreterException {
        /**
         * intégre la version destrctuve
         */
        /**
     * auto réparation de la pile
     */
        StaticHeap global = Interpreter.mySelf().getGLOBAL();
        int href = global.size();
        int slock = global.getOffset();
        try {

            if (id.getIdsCnt() > 1 ) {
                String ids[] = id.getIds();
                return getAlways_uo_(global, ids);
            }
            else
                return get_single_uo_(global, id.getStr());

        }
        /**
     * auto réparation de la pile
     */
        catch (InterpreterException ex) {
            // restaurer la pile si nécessaire...
            if (global.size() != href) {
                global.setOffset(slock);
                global.setSize(href);
            }
            // relancer l'exception
            throw ex;
        }

    }

    /**
     * Permet de récupérer la référence associée au symbole id.
     * Cette méthode accompli un traitement complet en validant l'accessibilité
     * de la variable ainsi que sa destructivité.
     *
     * En cas de problème, la méthode renvoie une exception.
     *
     * @param id
     * @return
     * @throws Exception
     */
    final public static Node getv(ASymbol id) throws InterpreterException {
        return _getv_(id).requireReadLockAccess();
    }


    /**
     * Comme getv(String) mais sans contrôle d'accès concurrents.
     *
     * @param id
     * @return
     * @throws Exception
     */
    final public static Node getv_unsafe(ASymbol id) throws Exception {
        return _getv_(id);
    }


    private static final Node _getv_(Node namespace, ASymbol id) throws InterpreterException {
        /**
         * version destructive
         */
        if (id.getIdsCnt() > 1) {
            //String ids[] = split(id, SEP);
            //int index = 0;
            return getAlways_uo_(namespace, id.getIds());
        }
        else {
            return get_uo_(namespace, id.getStr());
            //System.out.println("Gets_ RES="+x);
            //return x;
        }
    }

   

    /**
     * Version orienté espace de noms de getv(...).
     *
     * Si la variable n'est pas accessible, une exception est retournée.
     *
     * @param id
     * @return
     * @throws Exception
     */
    final public static Node getv(Node namspace, ASymbol id) throws InterpreterException {
        return _getv_(namspace, id).requireReadLockAccess();
    }



    /**
     * Comme gets(Object,String) mais sans contrôle d'accès concurrents ni exception.
     * S'il y a un souci, la méthode retourne tout simplement null.
     *
     * @param namespace
     * @param id
     * @return
     */
    final public static Node getv_unsafe_or_null(Node namespace, ASymbol id) {
        try {
            return _getv_(namespace, id);
        }
        catch (InterpreterException ie) {
            return null;
        }
    }

    /**
     * Comme getv(Object,String) mais sans contrôle d'accès concurrents.
     *
     * @param namespace
     * @param id
     * @return
     * @throws Exception
     */
    final public static Node getv_unsafe(Node namespace, ASymbol id) throws InterpreterException {
        return _getv_(namespace, id);
    }

    /**
     * permet de vérifier si un symbole est défini ou non sans créer d'exception.
     *
     * @param id
     * @return
     */
    final public static boolean exists(ASymbol id) {
        try {
            return _getv_(id) != null;
        }
        catch (Exception e) {
            return false;
        }
    }

    /**
     * permet de vérifier si un symbole est défini ou non sans créer d'exception.
     *
     * Idem que précédente, mais pour un espace de noms..
     *
     * @param namespace
     * @param id
     * @return
     */
    final public static boolean exists(Node namespace, ASymbol id) {
        try {
            //Node x = gets(object, id);
            //System.out.println("exists_ RES="+x);
            return _getv_(namespace, id) != null;
        }
        catch (InterpreterException e) {
            return false;
        }
    }

    /**
     * permet de vérifier si un symbole est défini et du type indiqué sans créer d'exception.
     *
     * @param id
     * @return
     */
    public static boolean exists(ASymbol id, int nodeQType) {
        try {
            Node x = _getv_(id);
            return x != null && (x.getQType() & nodeQType) != 0;
        }
        catch (InterpreterException e) {
            return false;
        }
    }

    /**
     * permet de vérifier si un symbole est défini et du type indiqué sans créer d'exception.
     *
     * Idem que précédente, mais pour un espace de noms..
     *
     * @param namespace
     * @param id
     * @param nodeQType
     * @return
     */
    final public static boolean exists(Node namespace, ASymbol id, long nodeQType) {
        try {
            Node x = _getv_(namespace, id);
            return x != null && (x.getQType() & nodeQType) != 0;
        }
        catch (InterpreterException e) {
            return false;
        }
    }

    /**
     * Permet de récupérer le Heap dans lequel le symbole est défini.
     *
     * En cas de problème, une exception est déclenchée.
     *
     * @param id
     * @return
     * @throws Exception
     */
    private static Heap geth(ASymbol id) throws InterpreterException {
        /**
     * auto réparation de la pile
     */
        StaticHeap global = Interpreter.mySelf().getGLOBAL();
        int href = global.size();
        int slock = global.getOffset();
        try {
            if (id.getIdsCnt() > 1) {
                //String ids[] = split(id, SEP);
                return gethAlways_nd_(global, id.getIds());
            }
            else {
                return geth_nd_(global, id.getStr());
            }
        }
        /**
     * auto réparation de la pile
     */
        catch (InterpreterException ex) {
            // restaurer la pile si nécessaire...
            if (global.size() != href) {
                global.setOffset(slock);
                global.setSize(href);
            }
            // relancer l'exception
            throw ex;
        }
    }


    /**
     * Cette méthode est une alternative à Heap.defv(). Cette version n'autorise que les symboles locaux.
     *
     * @param id     : symbole (local)
     * @param node   : valeur
     * @throws Exception
     */
    public static void defv_local(ASymbol id, Node node) throws Exception {
        if (id.getIdsCnt() > 1)
            throw new InterpreterException(StdErrors.Invalid_symbol);
        defv(id, node);
    }


    private static final String QUOTED_ = "\'";


    String dump(Node contenant, String exclude) throws Exception {
        boolean is_delegable = contenant.isDelegable();
        String res = "";

        if (extended != null)
            res += "  (" + PCoder.getReserved(PCoder.PC_EXTEND) + " " + extended.nodeToString(1) + ")\n";

        Iterator<String> enumx = this.keysIterator();
        Vector<String> elements = new Vector<String>();
        while (enumx.hasNext())
            elements.addElement(enumx.next());
        //Collections.sort(elements, new AlphaComparator());
        for (int i = 0; i < elements.size(); i++) {
            String element = elements.elementAt(i);
            if (!element.equals(exclude) && !element.startsWith(PCoder.REG_str)) {
                Node contenu = this.get(element);
                if (contenu == null) {
                    res = res + "  /* Symbol " + element + " = nil */\n";
                }
                else if (contenu.isNamespace()) {

                    if (contenu.getExternal() == this)
                        // cas de l'auto-référence...
                        res =
res + "  (" + PCoder.getReserved(PCoder.PC_DEFINE) + " " + QUOTED_ + "$" + (is_delegable ? SEP_str: "") + element + " (" + PCoder.getReserved(PCoder.PC_SELF) + "))\n";

                    else
                        res +=
"  (" + PCoder.getReserved(PCoder.PC_DEFINE) + " " + QUOTED_ + "$" + (is_delegable ? SEP_str: "") + element + " " + Tools.replaceCSeq(contenu.toString(), "\n", "\n  ").trim() + ")\n";


                }
                else if (contenu.isExternal()) {
                    res += "  (" + PCoder.getReserved(PCoder.PC_DEFINE) + " " + QUOTED_ + "$" + (is_delegable ? SEP_str: "") + element + " " + contenu.nodeToString() + ")";
                }
                else {
                    Node tnode = Node.createExpr();
                    tnode.addElement(Node.createPCode(PCoder.PC_DEFINE));
                    tnode.addElement(Node.createQSymbol((is_delegable ? SEP_str: "") + element));
                    tnode.addElement(contenu);
                    res = res + "  " + tnode.nodeToString(1) + "\n";
                }
            }
        }
        return res;
    }

    /*
    private final static class AlphaComparator implements Comparator<String> {

        private static int getIndex(String s) {
            for (int i = 0; i < PCoder.ORDER_FROM_ALL.length; i++) {
                if (s.equals(PCoder.ORDER_FROM_ALL[i]))
                    return i;
            }
            return Integer.MAX_VALUE;
        }

        public int compare(String a, String b) {
            int ia = getIndex(a);
            int ib = getIndex(b);
            if (ia == Integer.MAX_VALUE && ib == Integer.MAX_VALUE) {
                return a.compareTo(b);
            }
            else if (ia < ib) {
                return -1;
            }
            else if (ia > ib) {
                return 1;
            }
            else {
                return 0;
            }
        }

        @Override
        public boolean equals(Object obj) {
            return false;
        }

    }
*/

    @Deprecated
    public String toString() {
        return super.toString();
    }

    private String _nesting_to_space_(int nesting){
        String s="  ";
        StringBuilder r=new StringBuilder();
        for(int i=0;i<nesting;i++){
            r.append(s);  
        }
        return r.toString();
    }
   
    public String toString(Node contenant,int nesting) {
        boolean is_delegable = contenant.isDelegable();
        String res = "";
       
        String spc=_nesting_to_space_(nesting);
       
        try {

            if (extended != null)
                res += spc+"(" + PCoder.getReserved(PCoder.PC_EXTEND) + " " + extended.nodeToString(nesting+1) + ")\n";

            Iterator<String> enumx = this.keysIterator();
            Vector<String> elements = new Vector<String>();
            while (enumx.hasNext())
                elements.addElement(enumx.next());
            //Collections.sort(elements, new AlphaComparator());
            for (int i = 0; i < elements.size(); i++) {
                String element = elements.elementAt(i);
                if (element.charAt(0) != REG) {
                    Node contenu = this.get(element);
                    if (contenu.isNamespace()) {
                        if (contenu.getExternal() == this) {
                            res = res + spc + "(" +
                                           PCoder.getReserved(PCoder.PC_DEFINE) + " " + QUOTED_ + "$" + (is_delegable ? SEP_str: "") + element +
                                  " (" + PCoder.getReserved(PCoder.PC_SELF) + "))\n";
                        }
                        else {
                            res = res + spc +"(" +
                                  PCoder.getReserved(PCoder.PC_DEFINE) + " " + QUOTED_ + "$" + (is_delegable ? SEP_str: "") + element +
                                  " /* abstracted : " + contenu.typeOfNode() + " */)\n";

                        }
                    }
                    else if (contenu.isExternal()) {
                        res = res + spc+"(" + PCoder.getReserved(PCoder.PC_DEFINE) + " " + QUOTED_ + "$" + (is_delegable ? SEP_str: "") + element +
                              " (" + PCoder.getReserved(PCoder.PC_EXTERNAL) + " \"" + contenu.getExternal().getClass().getName() + "\"))\n";
                    }
                    else {
                        Node tnode = Node.createExpr();
                        tnode.addElement(Node.createPCode(PCoder.PC_DEFINE));
                        tnode.addElement(Node.createQSymbol((is_delegable ? SEP_str: "") + element));
                        tnode.addElement(contenu);
                        //res = res + "  ";

                        res += spc+tnode.nodeToString(nesting);

                        res += "\n";
                    }
                }
            }
            if(res.length()>=1 && res.charAt(res.length()-1)=='\n')
                res=res.substring(0,res.length()-1);
        }
        catch (Exception e) {
            if (Interpreter.isDebugMode())
                e.printStackTrace();
            Interpreter.LogAlways(e.toString());
            res += "ERROR";
        }
        return res;
    }

    private static final void _addSlotsTo_(Node delegable, ArrayList<String> slotsList) throws Exception {
        ArrayList<String> locals = Node.VDelegable.slotsOf(delegable);
        for (int j = 0; j < locals.size(); j++) {
            String local_s = locals.get(j);

            boolean fnd = false;
            int i = 0;
            while (i < slotsList.size() && !fnd) {
                fnd = local_s.equals(slotsList.get(i++));
            }

            if (!fnd)
                slotsList.add(local_s);

        }
    }

    /**
     * Méthode pour obtenir la liste des slots d'un namespace.
     *
     * Un namespace peut etendre n'importe quel objet "délégable",
     * de ce fait, la recherche doit être réalisée à l'aide des
     * méthodes VDelagable.
     *
     * @return
     * @throws Exception
     */
    public ArrayList<String> getSlots() throws Exception {
        ArrayList<String> slotsList = new ArrayList<String>();
        Iterator<String> enumx = this.keysIterator();
        while (enumx.hasNext())
            slotsList.add(enumx.next());
        if (extended != null)
            _addSlotsTo_(extended, slotsList);

        return slotsList;
    }


    /**
     * Fusion de Heaps destinée à l'utilisation de modules.
     * la méthode tient donc comptes des exclusions possibles.
     *
     * Cette méthode fusionne le contenu du heap addinHeap en ajoutant
     * son contenu dans le heap courant.
     *
     * Pour un minimum de protection (cadre parallèle), les données sont
     * déréférencées.
     *
     * @param addinHeap
     * @throws InterpreterException
     */
    public synchronized void fusion(Heap addinHeap) throws InterpreterException {
        Iterator<String> addinEnum = addinHeap.keysIterator();
        while (addinEnum.hasNext()) {
            String k = addinEnum.next();
            this.put(k, addinHeap.get(k).deref());
        }
    }


    /**
     * utilisé pour la construction de modules
     * @param emuSymbol
     * @return
     */
    public Node get_emul(String emuSymbol) {
        /**
         * non destructifs
         */
        if (emuSymbol.indexOf(PCoder.SEP) >= 0) {
            String seg[] = emuSymbol.split(PCoder.SEP_str);
            Node sentinel = this.get(seg[0]);
            if (sentinel == null || !sentinel.isNamespace())
                return null;
            String reconst = emuSymbol.substring(seg[0].length() + 1, emuSymbol.length());
            return ((Heap) sentinel.getExternal()).get_emul(reconst);
        }
        else {
            return this.get(emuSymbol);
        }
    }

    /**
     * utilisé pour la construction de modules
     * @param emuSymbol
     * @param node
     * @return
     */
    public boolean put_emul(String emuSymbol, Node node) {
        /**
         * non destructifs
         */
        if (emuSymbol.indexOf(PCoder.SEP) >= 0) {
            String seg[] = emuSymbol.split(PCoder.SEP_str);
            Node sentinel = this.get(seg[0]);
            if (sentinel == null || !sentinel.isNamespace())
                return false;
            String reconst = emuSymbol.substring(seg[0].length() + 1, emuSymbol.length());
            return ((Heap) sentinel.getExternal()).put_emul(reconst, node);
        }
        else {
            this.put(emuSymbol, node);
            return true;
        }
    }

    /**
     * Récupère la liste des éléments pouvant être utilisés comme mixin.
     *
     * Pour cela, retourne un tableau composé de 2 Vectors. Le premier correspondant à la liste des symboles
     * (non 'selfié') et le deuxième aux valeurs correspondantes.
     *
     * @return Vector[2]
     * @throws Exception
     */
    public static ArrayList[] getMixins(Heap spaceName) throws Exception {
        String symbol;
        ArrayList<Node> values = new ArrayList<Node>();
        ArrayList<String> symbols = new ArrayList<String>();
        ArrayList<String> tmp_symb = spaceName.getSlots();
        for (int i = 0; i < tmp_symb.size(); i++)
            symbols.add(tmp_symb.get(i));
        for (int i = 0; i < symbols.size(); i++)
            values.add(spaceName.get(symbols.get(i)));
        ArrayList<?>[] result = new ArrayList<?>[2];
        result[0] = symbols;
        result[1] = values;
        return result;
    }


}
TOP

Related Classes of abstrasy.Heap

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.