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;
}
}