package abstrasy.pcfx;
import abstrasy.ASymbol;
import abstrasy.Heap;
import abstrasy.Interpreter;
import abstrasy.Node;
import abstrasy.PCoder;
import abstrasy.StaticHeap;
import abstrasy.interpreter.BaseContextSnapshot;
import abstrasy.interpreter.InterpreterException;
import abstrasy.interpreter.RestartException;
import abstrasy.interpreter.SilentException;
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_perform extends PCFx {
public PCFx_perform() {
}
private final static void _clear_closure_(Heap closure){ if (closure.isLoaded()) closure.clear(); }
/**
* eval
*
* @param startAt Node
* @return Node
* @throws Exception
* @todo Implémenter cette méthode abstrasy.PCFx
*/
public Node eval(Node startAt) throws Exception {
/**
* forme: (perform {...}) -> n'affecte pas argv
* (perform [args] {...})
* (perform 'Symbole {...}) -> n'affecte pas argv
* (perform 'Symbole [args] {...})
*
*/
Node snode = null; // symbole
Node xnode = null; // lazy
Node anode = null; // args (list)
/**
* Analyse des arguments...
* Basée sur le nombre d'arguments...
*/
switch (startAt.size()) {
case 2:
/**
* (perform {...})
*/
xnode = startAt.getSubNode(1, Node.TYPE_LAZY);
break;
case 4:
/**
* (perfom 'Symbole [args] {...})
*/
snode = startAt.getSubNode(1, Node.TYPE_QSYMBOL);
anode = startAt.getSubNode(2, Node.TYPE_CLIST);
xnode = startAt.getSubNode(3, Node.TYPE_LAZY);
break;
case 3:
/**
* (perform [args] {...})
* (perform 'Symbole {...})
*/
snode = startAt.getSubNode(1, Node.TYPE_QSYMBOL | Node.TYPE_CLIST);
if (!snode.isQSymbol()) {
// si n'est pas un QSymbol, c'est forcément une liste...
anode = snode;
snode = null;
}
xnode = startAt.getSubNode(2, Node.TYPE_LAZY);
break;
default:
/**
* problème...
*/
throw new InterpreterException(StdErrors.Argument_count_mismatch);
}
/**
* si le symbole est défini...
* vérifier qu'il soit bien immutable...
*/
if (snode != null) {
ASymbol symbole=snode.getSymbol();
if (symbole.getStr().indexOf(PCoder.SEP) >= 0)
throw new InterpreterException(StdErrors.Local_symbol_required);
if (!symbole.isImmutable())
throw new InterpreterException(StdErrors.Immutable_symbol_required);
}
/**
* préparer la gestion de la pile de manière terminale...
*/
Interpreter interpreter = Interpreter.mySelf();
StaticHeap global = interpreter.getGLOBAL();
global.push();
// retenir le heap de control
Heap controlh=global.current();
/**
* si la forme compte un symbole...
*/
if (snode != null)
Heap.defv(snode.getSymbol(), xnode);
/**
* la section a besoin d'un contexte.
*/
global.push();
// on retient la référence du contexte courant...
Heap local=global.current();
/**
* A toutes fins utiles, on sauve l'état de la pile...
*/
BaseContextSnapshot contextSnapshot = new BaseContextSnapshot(interpreter);
/**
* Début de la boucle...
*/
boolean retry = true;
Node res = null;
boolean oldInLoop=interpreter.isInLoop();
while (retry) {
if (anode!=null)
controlh.put(PCoder.ARGV, anode);
else
controlh.put(PCoder.ARGV, Node.createCList());
try {
_clear_closure_(local);
interpreter.setInLoop(true);
res = xnode.exec(true);
retry = false;
}
catch (RestartException retrex) {
contextSnapshot.restore();
Node experform = retrex.getPerform();
if (experform == null)
retry = true;
else if (xnode.equalsIdentity(experform))
retry = true;
else {
retry = false;
throw retrex;
}
anode = retrex.getArgs();
}
catch (SilentException silex) {
contextSnapshot.restore();
retry = false;
throw silex;
}
catch (Exception excep) {
contextSnapshot.restore();
retry = false;
throw excep; // fait suivre l'exception...
}
}
interpreter.setInLoop(oldInLoop);
// heap local
global.pull();
// headp controlh
global.pull();
return res;
}
}