package abstrasy;
import abstrasy.consoleui.OutputTextArea;
import abstrasy.externals.AExtTools;
import abstrasy.interpreter.AbortException;
import abstrasy.interpreter.FreezeTimeOut;
import abstrasy.interpreter.InterpreterException;
import abstrasy.interpreter.ListPackageContents;
import abstrasy.interpreter.RestartException;
import abstrasy.interpreter.RetryException;
import abstrasy.interpreter.SilentException;
import abstrasy.interpreter.StdErrors;
import java.awt.event.ActionEvent;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Properties;
import java.util.Vector;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.Timer;
/**
* 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 Interpreter extends Thread {
/**
* Variables de version et de révisions:
* -------------------------------------
*
* Veuillez ne pas modifier les numéros de version et de révision.
* Ceux-ci sont réservés pour déterminer le niveau de révision et
* la version principale du langage que l'interpréteur est capable
* d'exécuter.
*
*/
public static final String version = "1.0";
public static final int revisionInt = 6342;
/**
* Numéro de sous-révision à votre disposition pour répertorier vos
* propres modifications.
*/
public static final int subrevisionInt = 0;
/**
* Conformément aux lois qui protègent le droit d'auteur, veuillez laisser
* inchangée toutes les mentions de copyright de l'auteur.
*/
public static final String revision = Interpreter.revisionInt + "." + subrevisionInt;
public static final String copyright = "Copyright (c) 2006-2012, Luc Bruninx.";
public static final String TITLE_APP = "Abstrasy Interpreter " + version + " rev:" + revision + " - " + copyright;
/**
* Taille de la pile (de frames) et de la pile du Thread exécutant l'interpréteur.
*/
public static int DEFAULT_STATICHEAP_SIZE = 2048;
// Sur un systeme 64 bits, nous doublons arbitrairement la taille de la pile.
// Celle-ci est augmentée par rapport aux valeurs habituels pour des arch 32 bits
// (512Ko au lieu de 320Ko) de manière supporter l'imbrication des méthodes
// exec_q() et eval_q() de Node.
public static int DEFAULT_INTERPRETER_STACK_SIZE = (512 * 1024) * (System.getProperty("sun.arch.data.model", "32").equals("64") ? 2: 1);
private boolean timeOutRaising = false;
private boolean breakingFromSEMAPHORE = false;
private boolean endingFromSEMAPHORE = false;
//
public static final int BREAKCODE_NONE = 0;
public static final int BREAKCODE_LOOP = 1;
public static final int BREAKCODE_TAIL = 2;
public static final int BREAKCODE_RETURN = 3;
public static final int BREAKCODE_REINFER = 4;
private int breakCode = BREAKCODE_NONE;
private boolean inLoop = false;
private boolean canLoop = false;
private boolean tailNode = false;
private boolean terminalNode=false;
private long callerSignature = 0;
private Node wrapperFunction = null;
private Node thisFunction = null;
private Node self=null;
private Node root=null;
private Node iface=null;
private static InterpreterSemaphore semaphore = new InterpreterSemaphore();
private OutputTextArea outputTextArea = null;
private OutputTextArea logTextArea = null;
private long executionTimeOut = 15000;
private long deadlockTime = 0;
private boolean timeOutCheck = false;
/**
* exitCode : code de retour en cas d'arrêt brusque (forcé)...
*/
static private int exitCode = 0;
static private boolean _hasExitCode = false;
static public void setExitCode(int _exitCode) {
exitCode = _exitCode;
_hasExitCode = true;
}
static public int getExitCode() {
return exitCode;
}
static public boolean hasExitCode() {
return _hasExitCode;
}
private Interpreter() {
super(null, null, "", DEFAULT_INTERPRETER_STACK_SIZE);
}
public static final Interpreter SHARED_INTERPRETER = new Interpreter();
private Action timeOutAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
if (timeOutCheck) {
timeOutRaising = (System.currentTimeMillis() > deadlockTime);
if (__thisInterpreter != null) {
if (!__thisInterpreter.isAlive()) {
Interpreter.Log("Interpreter breaking -> TimeOutThread Ending...");
timeOutTimer.stop();
}
}
}
}
};
private Timer timeOutTimer = new Timer(100, timeOutAction);
private String source = null;
private Node node = null;
public void setNode(Node node) {
this.node = node;
}
public Node getNode() {
return node;
}
private Node returnedNode = null;
public Node getReturnedNode() {
return returnedNode;
}
private Exception lastException = null;
public Exception getLastException() {
return lastException;
}
/**
* Il ne peut y avoir qu'une seul restart Exception par thread...
*/
private RestartException restartException = new RestartException();
public RestartException getRestartException(Node from, Node perform, Node args) {
restartException.setFrom(from);
restartException.setPerform(perform);
restartException.setArgs(args);
return restartException;
}
/**
* Section de controle du debugage et des logs...
*/
private static boolean debugMode = false;
/**
* Permet d'activer le mode de débogage de l'interpréteur
*
* @param mode
*/
public final static void setDebugMode(boolean mode) {
debugMode = mode;
}
public final static boolean isDebugMode() {
return debugMode;
}
public final static void LogTitle(String str) {
if (debugMode) {
System.out.println("### " + str);
Interpreter interpreter = Interpreter.mySelf();
if (interpreter != null) {
OutputTextArea logArea = interpreter.getLogTextArea();
if (logArea != null) {
try{
logArea.write("### " + str + "\n");
}
catch(Exception e){e.printStackTrace();}
}
}
}
}
public final static void Log(String str) {
if (debugMode) {
System.out.println(" # " + str);
Interpreter interpreter = Interpreter.mySelf();
if (interpreter != null) {
OutputTextArea logArea = interpreter.getLogTextArea();
if (logArea != null) {
try{
logArea.write(" # " + str + "\n");
}
catch(Exception e){e.printStackTrace();}
}
}
}
}
public final static void LogAlways(String str) {
System.out.println(" > " + str);
Interpreter interpreter = Interpreter.mySelf();
if (interpreter != null) {
OutputTextArea logArea = interpreter.getLogTextArea();
if (logArea != null) {
try{
logArea.write(" # " + str + "\n");
}
catch(Exception e){e.printStackTrace();}
}
}
}
public static long StartChrono() {
return System.currentTimeMillis();
}
public static void LogChrono(long start, String txt) {
if (debugMode) {
long res = System.currentTimeMillis() - start;
Interpreter.LogAlways(txt + " : " + res + "ms.");
}
return;
}
private Interpreter motherThread = null;
public Interpreter getMotherThread() {
return motherThread;
}
private boolean interThread = false;
public boolean isInterThread() {
return interThread;
}
public void setInterThread(boolean ithread) {
this.interThread = ithread;
}
public static InterpreterSemaphore getSemaphore() {
return semaphore;
}
public void setTimeOutCheck(boolean timeOutCheck) {
this.timeOutCheck = timeOutCheck;
}
public boolean isTimeOutCheck() {
return timeOutCheck;
}
public void setExecutionTimeOut(long executionTimeOut) {
this.executionTimeOut = executionTimeOut;
}
public long getExecutionTimeOut() {
return executionTimeOut;
}
public void setDeadlockTime(long deadlockTime) {
this.deadlockTime = deadlockTime;
}
public long getDeadlockTime() {
return deadlockTime;
}
public void setTimeOutRaising(boolean timeOutRaising) {
this.timeOutRaising = timeOutRaising;
}
public boolean isTimeOutRaising() {
// cas fail-over...
if (failOver) {
return false;
}
// traitement habituel...
return timeOutRaising;
}
public void setTimeOutTimer(Timer timeOutTimer) {
this.timeOutTimer = timeOutTimer;
}
public Timer getTimeOutTimer() {
return timeOutTimer;
}
public void setBreakingFromSEMAPHORE(boolean breakingFromSEMAPHORE) {
this.breakingFromSEMAPHORE = breakingFromSEMAPHORE;
}
public boolean isBreakingFromSEMAPHORE() {
// cas fail-over...
if (failOver) {
return false;
}
// traitement habituel...
return breakingFromSEMAPHORE;
}
public void setEndingFromSEMAPHORE(boolean endingFromSEMAPHORE) {
this.endingFromSEMAPHORE = endingFromSEMAPHORE;
}
public boolean isEndingFromSEMAPHORE() {
// cas fail-over...
if (failOver) {
return false;
}
// traitement habituel...
return endingFromSEMAPHORE;
}
private StaticHeap GLOBAL = null;
public void setGLOBAL(StaticHeap GLOBAL) {
this.GLOBAL = GLOBAL;
}
public StaticHeap getGLOBAL() {
return GLOBAL;
}
private String pluggedLibrariesPath = "";
public static String getPluggedLibrariesPath() {
return Interpreter.mySelf().pluggedLibrariesPath;
}
public static void setPluggedLibrariesPath(String path) {
Interpreter.mySelf().pluggedLibrariesPath = path;
}
private static Node _Registry_ = null;
public static Node getRegistry_() {
if (_Registry_ == null) {
_Registry_ = Node.createNamespace(new Heap()).letFinal(true);
}
return _Registry_;
}
public static Heap Application_Heaps = new_Application_Heap();
public static Heap Reserved = new Heap();
public static Heap Modules = new Heap();
public static Heap BuiltIn_Reserved = new Heap();
private static Node _Modules_ = null;
public static Node getModules_() {
if (_Modules_ == null) {
_Modules_ = Node.createNamespace(Modules).letFinal(true);
}
return _Modules_;
}
private final static Heap new_Application_Heap() {
_Registry_ = null;
_Modules_ = null;
Heap ah = new Heap();
ah.put(PCoder.REGISTRY, getModules_());
return ah;
}
static {
BuiltIn_Reserved.put(PCoder.TRUE, new Node(Node.TRUE).letFinal(true));
BuiltIn_Reserved.put(PCoder.FALSE, new Node(Node.FALSE).letFinal(true));
BuiltIn_Reserved.put(PCoder.PI, new Node(Math.PI).letFinal(true));
BuiltIn_Reserved.put(PCoder.NAPIER, new Node(Math.E).letFinal(true));
BuiltIn_Reserved.put(PCoder.EULER, new Node(0.5772156649015329).letFinal(true));
BuiltIn_Reserved.put(PCoder.MAIN, new Node(Node.TRUE).letFinal(true));
BuiltIn_Reserved.put(PCoder.INTERPRETER_REVISION, new Node(Interpreter.revisionInt).letFinal(true));
}
private static Vector<PackageEntry> packagesAdded = null;
public void setBreakCode(int breakCode) {
this.breakCode = breakCode;
}
public int getBreakCode() {
return breakCode;
}
public boolean hasNoBreakCode() {
return breakCode == BREAKCODE_NONE;
}
public void consumeBreakCode_onLoop() {
if (getBreakCode() == BREAKCODE_LOOP) {
setBreakCode(BREAKCODE_NONE);
}
}
public void consumeBreakCode_onTail() {
if (getBreakCode() == BREAKCODE_TAIL) {
setBreakCode(BREAKCODE_NONE);
}
}
public void consumeBreakCode_onReturn() {
if (getBreakCode() == BREAKCODE_RETURN) {
setBreakCode(BREAKCODE_NONE);
}
}
public void setCallerSignature(long callerSignature) {
this.callerSignature = callerSignature;
//System.out.println("Set Caller Signature : "+callerSignature);
}
public long getCallerSignature() {
return callerSignature;
}
public void setTailNode(boolean tailNode) {
this.tailNode = tailNode;
}
public boolean isTailNode() {
return tailNode;
}
public void setTerminalNode(boolean terminalNode) {
this.terminalNode = terminalNode;
}
public boolean isTerminalNode() {
return terminalNode;
}
public void setThisFunction(Node thisNode) {
this.thisFunction = thisNode;
}
public Node getThisFunction() {
return thisFunction;
}
public void setWrapperFunction(Node wrapper) {
this.wrapperFunction = wrapper;
}
public Node getWrapperFunction() {
return wrapperFunction;
}
public void setSelf(Node self) {
this.self = self;
}
public Node getSelf() {
return self;
}
public void setRoot(Node root) {
this.root = root;
}
public Node getRoot() {
return root;
}
public void setIface(Node iface) {
this.iface = iface;
}
public Node getIface() {
return iface;
}
private static class PackageEntry {
private String packageName;
private String moduleName;
PackageEntry(String packageName, String moduleName) {
this.packageName = packageName;
this.moduleName = moduleName;
}
void setPackageName(String packageName) {
this.packageName = packageName;
}
String getPackageName() {
return packageName;
}
void setModuleName(String moduleName) {
this.moduleName = moduleName;
}
String getModuleName() {
return moduleName;
}
}
/**
* Permet d'ajouter les classes External_* du paquetage dont le nom est indiqué au pcfx stimulé.
*
* Il suffira alors d'importer le pcfx dans un script pour accéder au classes abstraites définies
* External_*:
*
* (import 'Nom-Module)
*
*
* @param package_name
* @param module_name
*/
public static void addPackageName(String package_name, String module_name) {
if (packagesAdded == null) {
packagesAdded = new Vector<PackageEntry>();
}
boolean addIt = true;
for (int i = 0; i < packagesAdded.size(); i++) {
PackageEntry pe = packagesAdded.elementAt(i);
if (pe.getPackageName().compareTo(package_name) != 0) {
addIt = false;
i = packagesAdded.size();
}
}
if (addIt) {
packagesAdded.addElement(new PackageEntry(package_name, module_name));
}
//
//
}
public static void removePackageName(String name) {
if (packagesAdded != null) {
Vector<PackageEntry> vtmp = new Vector<PackageEntry>();
for (int i = 0; i < packagesAdded.size(); i++) {
PackageEntry pe = packagesAdded.elementAt(i);
if (pe.getPackageName().compareTo(name) != 0) {
vtmp.addElement(pe);
}
}
packagesAdded = vtmp;
}
}
public static void clearPackagesNames() {
packagesAdded = null;
}
public static void addResourcesPath(String path) throws Exception {
Node iPaths = Reserved.get(PCoder.RESOURCES_PATH);
if (iPaths == null) {
iPaths = Node.createCList();
}
if (path != null) {
boolean commite = true;
for (int i = 0; i < iPaths.size(); i++) {
Node entree = iPaths.getSubNode(i,Node.TYPE_STRING);
if (entree.getString().equals(path)) {
commite = false;
i = iPaths.size();
}
}
if (commite) {
Interpreter.Log("Add " + PCoder.RESOURCES_PATH + " : " + path);
iPaths.addElement(new Node(path));
}
}
Reserved.put(PCoder.RESOURCES_PATH, iPaths);
}
public static void addLibrariesPath(String path) throws Exception {
Node iPaths = Reserved.get(PCoder.LIBRARIES_PATH);
if (iPaths == null) {
iPaths = Node.createCList();
}
if (path != null) {
boolean commite = true;
for (int i = 0; i < iPaths.size(); i++) {
Node entree = iPaths.getSubNode(i,Node.TYPE_STRING);
if (entree.getString().equals(path)) {
commite = false;
i = iPaths.size();
}
}
if (commite) {
Interpreter.Log("Add " + PCoder.LIBRARIES_PATH + " : " + path);
iPaths.addElement(new Node(path));
}
}
Reserved.put(PCoder.LIBRARIES_PATH, iPaths);
}
public static void addImportsPath(String path) throws Exception {
Node iPaths = Reserved.get(PCoder.IMPORTS_PATH);
if (iPaths == null) {
iPaths = Node.createCList();
}
if (path != null) {
boolean commite = true;
for (int i = 0; i < iPaths.size(); i++) {
Node entree = iPaths.getSubNode(i,Node.TYPE_STRING);
if (entree.getString().equals(path)) {
commite = false;
i = iPaths.size();
}
}
if (commite) {
Interpreter.Log("Add " + PCoder.IMPORTS_PATH + " : " + path);
iPaths.addElement(new Node(path));
}
}
Reserved.put(PCoder.IMPORTS_PATH, iPaths);
}
public static final void registerSourceAbsolutePath(String sourceFilePath) throws Exception {
addImportsPath(Tools.directoryOfFile(sourceFilePath));
addImportsPath(Tools.directoryOfFile(sourceFilePath) + PCoder.IMPORTS_RELPATH + File.separator);
addLibrariesPath(Tools.directoryOfFile(sourceFilePath));
addLibrariesPath(Tools.directoryOfFile(sourceFilePath) + PCoder.LIBRARIES_RELPATH + File.separator);
addResourcesPath(Tools.directoryOfFile(sourceFilePath));
addResourcesPath(Tools.directoryOfFile(sourceFilePath) + PCoder.RESOURCES_RELPATH + File.separator);
}
private static final boolean isStrInList_(String str, Node nodes) throws Exception {
boolean res = false;
for (int i = 0; i < nodes.size(); i++) {
res = nodes.getSubNode(i,Node.TYPE_STRING).getString().equals(str);
if (res) {
i = nodes.size();
}
}
return res;
}
public static void addImportsBaseURL(String baseurl) throws Exception {
Node iPaths = Reserved.get(PCoder.IMPORTS_BASE_URL);
if (iPaths == null) {
iPaths = Node.createCList();
}
if (baseurl != null && !isStrInList_(baseurl, iPaths)) {
Interpreter.Log("Add " + PCoder.IMPORTS_BASE_URL + " : " + baseurl);
iPaths.addElement(new Node(baseurl));
}
Reserved.put(PCoder.IMPORTS_BASE_URL, iPaths);
}
public static void addLibrariesBaseURL(String baseurl) throws Exception {
Node iPaths = Reserved.get(PCoder.LIBRARIES_BASE_URL);
if (iPaths == null) {
iPaths = Node.createCList();
}
if (baseurl != null && !isStrInList_(baseurl, iPaths)) {
Interpreter.Log("Add " + PCoder.LIBRARIES_BASE_URL + " : " + baseurl);
iPaths.addElement(new Node(baseurl));
}
Reserved.put(PCoder.LIBRARIES_BASE_URL, iPaths);
}
public static void addResourcesBaseURL(String baseurl) throws Exception {
Node iPaths = Reserved.get(PCoder.RESOURCES_BASE_URL);
if (iPaths == null) {
iPaths = Node.createCList();
}
if (baseurl != null && !isStrInList_(baseurl, iPaths)) {
Interpreter.Log("Add " + PCoder.RESOURCES_BASE_URL + " : " + baseurl);
iPaths.addElement(new Node(baseurl));
}
Reserved.put(PCoder.RESOURCES_BASE_URL, iPaths);
}
public static void addReserved(String packName) throws Exception {
Interpreter.Log("Add built-in package : " + packName);
String ressourceName = (packName).replace('/', '.'); // Attention ici à la représentation initiale du packName (dossier avec '/').
Vector<String> externals = makeReserved(ressourceName);
String packFilter = packName + ".External_";
for (int i = 0; i < externals.size(); i++) {
String cname = (String) externals.elementAt(i);
//System.out.println("CNAME:"+cname);
String sname = cname.substring(packFilter.length(), cname.length());
//System.out.println("SNAME:"+sname);
//
//if (!((sname.charAt(0) == '_') || (sname.charAt(sname.length() - 1) == '_'))) {
sname = sname.replace('_', '-');
//}
/*if (sname.startsWith("is-")) {
sname = sname.substring(3, sname.length()) + "?";
}*/
//
if (Reserved.get(sname) != null) {
Interpreter.Log(".Replace built-in class : " + sname + " as " + cname);
Reserved.put(sname, Node.createPattern(cname));
}
else {
Interpreter.Log(".Add built-in class : " + sname + " as " + cname);
Reserved.put(sname, Node.createPattern(cname));
}
}
}
public static Node loadLibrary(String packName) throws Exception {
String ressourceName = (packName).replace('/', '.'); // Attention ici à la représentation initiale du packName (dossier avec '/').
Vector<String> externals = makeReserved(ressourceName);
ClassLoader loader = Thread.currentThread().getContextClassLoader();
InputStream istream = loader.getResourceAsStream(packName + "/" + PCoder.LIBRARY_PROPERTIES);
Properties props = new Properties();
props.load(istream);
String namespace = props.getProperty("name", null);
if (namespace == null) {
throw new InterpreterException(StdErrors.extend(StdErrors.External_error, "undefined space-name in " + packName + "/" + PCoder.LIBRARY_PROPERTIES));
}
Node library = Node.createNamespace(null);
Heap libHeap = (Heap)library.getExternal();
if (ressourceName.startsWith("abstrasy.")) {
Interpreter.Log("Add built-in external package : " + packName + " as " + namespace + ":*");
}
else {
Interpreter.Log("Add external package : " + packName + " as " + namespace + ":*");
}
String packFilter = packName + ".External_";
for (int i = 0; i < externals.size(); i++) {
String cname = (String) externals.elementAt(i); // doit cloner l'intitulé de la chaîne...
//System.out.println("CNAME:"+cname);
String sname = cname.substring(packFilter.length(), cname.length());
//System.out.println("SNAME:"+sname);
//
if (!((sname.charAt(0) == '_') || (sname.charAt(sname.length() - 1) == '_'))) {
sname = sname.replace('_', '-');
}
if (libHeap.get(sname) != null) {
Interpreter.Log(".Replace external class : " + namespace + ":" + sname + " as " + cname);
libHeap.put(sname, Node.createPattern(cname));
}
else {
Interpreter.Log(".Add external class : " + namespace + ":" + sname + " as " + cname);
libHeap.put(sname, Node.createPattern(cname));
}
}
return library;
}
public static void addLibraryReserved(String packName) throws Exception {
Heap namedH = new Heap();
String ressourceName = (packName).replace('/', '.'); // Attention ici à la représentation initiale du packName (dossier avec '/').
Vector<String> externals = makeReserved(ressourceName);
ClassLoader loader = Thread.currentThread().getContextClassLoader();
InputStream istream = loader.getResourceAsStream(packName + "/" + PCoder.LIBRARY_PROPERTIES);
Properties props = new Properties();
props.load(istream);
String namespace = props.getProperty("name", null);
if (namespace == null) {
throw new InterpreterException(StdErrors.extend(StdErrors.External_error, "undefined space-name in " + packName + "/" + PCoder.LIBRARY_PROPERTIES));
}
if (ressourceName.startsWith("abstrasy.")) {
Interpreter.Log("Add built-in external package : " + packName + " as " + namespace + ":*");
}
else {
Interpreter.Log("Add external package : " + packName + " as " + namespace + ":*");
}
String packFilter = packName + ".External_";
for (int i = 0; i < externals.size(); i++) {
String cname = (String) externals.elementAt(i); // doit cloner l'intitulé de la chaîne...
//System.out.println("CNAME:"+cname);
String sname = cname.substring(packFilter.length(), cname.length());
//System.out.println("SNAME:"+sname);
//
if (!((sname.charAt(0) == '_') || (sname.charAt(sname.length() - 1) == '_'))) {
sname = sname.replace('_', '-');
}
if (namedH.get(sname) != null) {
Interpreter.Log(".Replace external class : " + namespace + ":" + sname + " as " + cname);
namedH.put(sname, Node.createPattern(cname));
}
else {
Interpreter.Log(".Add external class : " + namespace + ":" + sname + " as " + cname);
namedH.put(sname, Node.createPattern(cname));
}
}
synchronized (Interpreter.Modules) {
if (Interpreter.Modules == null) {
Interpreter.Log("WARNING : Libraries null !!!...");
throw new InterpreterException(StdErrors.Internal_error);
}
if (Interpreter.Modules.get(namespace) != null) {
Interpreter.Log(".Mixin library : " + namespace + ":* ...");
//throw new InterpreterException(InterpreterException.EC_EXTERNAL,
// "Espace de nommage déjà défini : " + namespace + ":* pour " + packName);
/**
* fusionner...
*
*/
Node modNode = Interpreter.Modules.get(namespace);
Heap modHeap = (Heap)modNode.getExternal();
modHeap.fusion(namedH);
}
else {
Interpreter.Log(".Add library : " + namespace + "...");
Interpreter.Modules.put(namespace, Node.createNamespace(namedH));
}
}
}
public static Node plugLibrary_jar(File jarFile) throws Exception {
String class_path = System.getProperty("java.class.path");
String path_separator = System.getProperty("path.separator");
if (class_path.indexOf(path_separator + jarFile.getAbsolutePath()) < 0) {
// le plugin n'est pas déjà inséré...
try {
Interpreter.Log("Loading external library : " + jarFile.getAbsolutePath() + " ...");
// trouver les noms de packages principaux...
Vector<String> packages = new Vector<String>();
InputStream is = new BufferedInputStream(new FileInputStream(jarFile));
JarInputStream jis = new JarInputStream(is);
JarEntry entry;
while ((entry = jis.getNextJarEntry()) != null) {
try {
//parse the class name
String cName = entry.getName();
if ((cName.indexOf('/') >= 0)) {
String package_name = cName.split("/")[0];
if (!cName.equals("META-INF")) {
boolean found = false;
for (int i = 0; i < packages.size(); i++) {
found = (packages.elementAt(i)).equals(package_name);
if (found) {
i = packages.size();
}
}
if (!found) {
packages.addElement(package_name);
Interpreter.Log(".Finding external package : " + package_name + " ...");
}
}
}
}
catch (Exception e) {
if (Interpreter.isDebugMode()) {
e.printStackTrace();
}
//don't do anything - we want to keep looping
}
}
// insérer le plugin:
String jURL = "jar:" + jarFile.toURI().toURL().toString() + "!/";
URL[] urls = { new URL(jURL) };
class_path += path_separator + jarFile.getAbsolutePath();
System.setProperty("java.class.path", class_path);
ClassLoader aCL = Thread.currentThread().getContextClassLoader();
URLClassLoader aUrlCL = new URLClassLoader(urls, aCL);
Thread.currentThread().setContextClassLoader(aUrlCL);
if (packages.size() > 1) {
throw new InterpreterException(StdErrors.extend(StdErrors.Library_error, "More than one package"));
}
return loadLibrary((String) packages.elementAt(0));
}
catch (Exception ex) {
Interpreter.Log(ex.getMessage());
if (Interpreter.isDebugMode()) {
ex.printStackTrace();
}
throw new InterpreterException(StdErrors.Library_error);
}
}
return null;
}
public static void linkResources_jar(File jarFile) throws Exception {
String class_path = System.getProperty("java.class.path");
String path_separator = System.getProperty("path.separator");
if (class_path.indexOf(path_separator + jarFile.getAbsolutePath()) < 0) {
// le plugin n'est pas déjà inséré...
try {
Interpreter.Log("Link external resources : " + jarFile.getAbsolutePath() + " ...");
// Etablir la liaison avec la paquetage de resources...
String jURL = "jar:" + jarFile.toURI().toURL().toString() + "!/";
URL[] urls = { new URL(jURL) };
class_path += path_separator + jarFile.getAbsolutePath();
System.setProperty("java.class.path", class_path);
ClassLoader aCL = Thread.currentThread().getContextClassLoader();
URLClassLoader aUrlCL = new URLClassLoader(urls, aCL);
Thread.currentThread().setContextClassLoader(aUrlCL);
// on lie simplement la resource dans le classpath...
}
catch (Exception ex) {
Interpreter.Log(ex.getMessage());
if (Interpreter.isDebugMode()) {
ex.printStackTrace();
}
throw new InterpreterException(StdErrors.Resource_error);
}
}
}
public static void classpath_addFile(String s) throws IOException {
File f = new File(s);
classpath_addFile(f);
} //end method
public static void classpath_addFile(File f) throws IOException {
classpath_addURL(f.toURI().toURL());
} //end method
private static final Class<?>[] __parameters = new Class<?>[] { URL.class };
public static void classpath_addURL(URL u) throws IOException {
URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Class<?> sysclass = URLClassLoader.class;
try {
Method method = sysclass.getDeclaredMethod("addURL", __parameters);
method.setAccessible(true);
method.invoke(sysloader, new Object[] { u });
}
catch (Throwable t) {
if (Interpreter.isDebugMode()) {
t.printStackTrace();
}
throw new IOException("Error, could not add URL to system classloader");
} //end try catch
} //end method
private static final String getFileNameFromURL(URL url) {
String ufstr = url.toString().replace(File.separatorChar, '/'); // attention à Windows ??? \dir -> /dir !!!
String path_separator = "/";
int lasti = ufstr.lastIndexOf(path_separator, ufstr.length());
return ufstr.substring((lasti < 0 ? 0: lasti), ufstr.length());
}
private static final String getDirectoryNameFromURL(URL url) {
String ufstr = url.toString().replace(File.separatorChar, '/'); // attention à Windows ??? \dir -> /dir !!!
String path_separator = "/";
int lasti = ufstr.lastIndexOf(path_separator, (ufstr.charAt(ufstr.length() - 1) == '/' ? ufstr.length() - 1: ufstr.length()));
return ufstr.substring((lasti < 0 ? 0: lasti), (ufstr.charAt(ufstr.length() - 1) == '/' ? ufstr.length() - 1: ufstr.length()));
}
private static String getNewEAIC() {
String temp_path = System.getProperty("java.io.tmpdir");
String res = null;
File fres = null;
while (res == null) {
// création d'un Extension Abstrasy Interpretor Contex ...
res = temp_path + File.separator + "EAIC-" + java.util.UUID.randomUUID().toString();
fres = new File(res);
if (fres.exists()) {
res = null;
}
}
fres.mkdirs();
Interpreter.Log("Extended Abstrasy Cache " + res + " created...");
return res;
}
private static synchronized void removeEAIC() {
if (EAIC_TEMP_DIR != null) {
File eaicd = new File(EAIC_TEMP_DIR);
if (eaicd.exists()) {
File[] eaicf = eaicd.listFiles();
for (int i = 0; i < eaicf.length; i++) {
try {
eaicf[i].delete();
}
finally {
}
}
try {
eaicd.delete();
}
finally {
}
EAIC_TEMP_DIR = null;
Interpreter.Log("Extended Abstrasy Cache " + eaicd.getAbsolutePath() + " removed...");
}
}
}
public static synchronized void resetEAIC() {
if (EAIC_TEMP_DIR != null) {
Interpreter.Log("Extended Abstrasy Cache resetting...");
removeEAIC();
//EAIC_TEMP_DIR = getNewEAIC();
}
}
private static String EAIC_TEMP_DIR = null;
public static synchronized String getCurrentEAIC() {
if (EAIC_TEMP_DIR == null) {
EAIC_TEMP_DIR = getNewEAIC();
}
return EAIC_TEMP_DIR;
}
static {
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
Interpreter.removeEAIC();
}
});
}
public static void linkResources_jar(URL jarFile) throws Exception {
/**
* Le principe ne marche pas avec un accès direct à l'URL...
* Il est donc nécessaire de rapatrier le fichier avant de poursuivre...
*/
String class_path = System.getProperty("java.class.path");
//System.out.println("CLASSPATH: "+class_path);
String path_separator = System.getProperty("path.separator");
String tmpJFN = getCurrentEAIC() + File.separator + getFileNameFromURL(jarFile);
if (class_path.indexOf(path_separator + new File(tmpJFN).getAbsolutePath()) < 0) {
// le plugin n'est pas déjà inséré...
try {
Interpreter.Log("Get external resources : " + getFileNameFromURL(jarFile) + " from URL \"" + jarFile.toString() + "\" ...");
InputStream is = new BufferedInputStream(jarFile.openStream());
String tempFileN = tmpJFN;
File tempFile = new File(tempFileN);
if (tempFile.exists()) {
tempFile.delete();
}
FileOutputStream fos = new FileOutputStream(tempFile);
byte[] sb = new byte[65536];
while (true) {
int stb = is.read(sb);
if (stb == -1) {
break;
}
fos.write(sb, 0, stb);
}
is.close();
fos.close();
linkResources_jar(tempFile); // et puis on fait le lien...
}
catch (Exception ex) {
if (Interpreter.isDebugMode()) {
ex.printStackTrace();
}
throw new Exception(ex.getMessage());
}
}
}
public static Node plugLibrary_jar(URL jarFile) throws Exception {
/**
* Le principe ne marche pas avec un accès direct à l'URL...
* Il est donc nécessaire de rapatrier le fichier avant de poursuivre...
*/
String class_path = System.getProperty("java.class.path");
//System.out.println("CLASSPATH: "+class_path);
String path_separator = System.getProperty("path.separator");
String tmpJFN = getCurrentEAIC() + File.separator + getFileNameFromURL(jarFile);
if (class_path.indexOf(path_separator + new File(tmpJFN).getAbsolutePath()) < 0) {
// le plugin n'est pas déjà inséré...
try {
Interpreter.Log("Get external library : " + getFileNameFromURL(jarFile) + " from URL \"" + jarFile.toString() + "\" ...");
InputStream is = new BufferedInputStream(jarFile.openStream());
String tempFileN = tmpJFN;
File tempFile = new File(tempFileN);
if (tempFile.exists()) {
tempFile.delete();
}
FileOutputStream fos = new FileOutputStream(tempFile);
byte[] sb = new byte[65536];
while (true) {
int stb = is.read(sb);
if (stb == -1) {
break;
}
fos.write(sb, 0, stb);
}
is.close();
fos.close();
return plugLibrary_jar(tempFile);
}
catch (Exception ex) {
if (Interpreter.isDebugMode()) {
ex.printStackTrace();
}
throw new Exception(ex.getMessage());
}
}
return null;
}
/**
* Charge tous les composants par défaut nécessaire au fonctionnement de l'interpréteur.
*
* @throws Exception
*/
public static void makeDefaultReserved() throws Exception {
addLibrariesPath(null); // réinitialiser la liste
addImportsPath(null); // réinitialiser la liste
addResourcesPath(null); //réinitialiser la liste
addLibrariesPath(getCurrentDirectory());
addLibrariesPath(getCurrentDirectory() + PCoder.LIBRARIES_RELPATH + File.separator);
addImportsPath(getCurrentDirectory());
addImportsPath(getCurrentDirectory() + PCoder.IMPORTS_RELPATH + File.separator);
addResourcesPath(getCurrentDirectory());
addResourcesPath(getCurrentDirectory() + PCoder.RESOURCES_RELPATH + File.separator);
addImportsBaseURL(null); // réinitialiser la liste
addLibrariesBaseURL(null); // réinitialiser la liste
addResourcesBaseURL(null); // réinitialiser la liste
addImportsBaseURL(getInterpreterImportsBaseURL());
addLibrariesBaseURL(getInterpreterLibrariesBaseURL());
addResourcesBaseURL(getInterpreterResourcesBaseURL());
String packName = AExtTools.class.getPackage().getName();
addReserved(packName);
if (packagesAdded != null) {
for (int i = 0; i < packagesAdded.size(); i++) {
PackageEntry pe = packagesAdded.elementAt(i);
addLibraryReserved(pe.getPackageName());
}
}
}
public static Vector<String> makeReserved(String packName) {
Vector<String> r1 = new Vector<String>();
String packFilter = packName + ".External_";
//System.out.println("makeReserved: "+ packName);
ListPackageContents lpc = new ListPackageContents(packName, false);
Iterator<String> iter = lpc.getPackageContents().iterator();
while (iter.hasNext()) {
String item = iter.next();
//System.out.println("makeReserved : "+item);
if (item.startsWith(packFilter) && (item.indexOf('$') < 0)) {
r1.addElement(item);
}
}
return r1;
}
public static String getInterpreterImportsBaseURL() {
String underFile = "_.properties";
URL url = Interpreter.class.getResource(PCoder.IMPORTS_RELPATH + "/" + underFile);
String ts2 = url.toString();
String res = ts2.substring(0, ts2.length() - underFile.length());
return res;
}
public static String getInterpreterLibrariesBaseURL() {
String underFile = "_.properties";
URL url = Interpreter.class.getResource(PCoder.LIBRARIES_RELPATH + "/" + underFile);
String ts2 = url.toString();
String res = ts2.substring(0, ts2.length() - underFile.length());
return res;
}
public static String getInterpreterResourcesBaseURL() {
String underFile = "_.properties";
URL url = Interpreter.class.getResource(PCoder.RESOURCES_RELPATH + "/" + underFile);
String ts2 = url.toString();
String res = ts2.substring(0, ts2.length() - underFile.length());
return res;
}
public static String getCurrentDirectory() {
String cd = new File(".").getAbsolutePath();
if (cd.endsWith(".")) {
cd = cd.substring(0, cd.length() - 1);
}
return cd;
}
private final void _check_GLOBAL(){
if (GLOBAL == null) {
this.GLOBAL = new StaticHeap(DEFAULT_STATICHEAP_SIZE);
this.GLOBAL.push(BuiltIn_Reserved);
this.GLOBAL.push(Reserved);
//this.GLOBAL.push(Libraries);
this.GLOBAL.push(Application_Heaps);
this.GLOBAL.push();
}
}
public void softReset() {
this.executionTimeOut = 15000;
this.deadlockTime = 0;
this.timeOutCheck = false;
this.breakingFromSEMAPHORE = false;
this.endingFromSEMAPHORE = false;
this.inLoop = false;
this.canLoop = false;
this.failOver = false;
this.returnedNode = null;
this.lastException = null;
this.node = null;
this.returnedNode = null;
this.lastException = null;
this.source = null;
this.GLOBAL = null;
Application_Heaps = Interpreter.new_Application_Heap();
_check_GLOBAL();
this.threadlock_A.clear();
this.threadlock_R.clear();
this.pendingMsg = null;
}
public void hardReset() throws Exception {
Reserved = new Heap();
Modules = new Heap();
resetEAIC();
softReset();
makeDefaultReserved();
}
public static final String SUPERINTERPRETER_THREAD_NAME = "__Supervisor__";
private static Interpreter _superInterpreter = null;
private static final void interpr_resetSuperInterpreter() throws Exception {
_superInterpreter.hardReset();
_superInterpreter.setName(SUPERINTERPRETER_THREAD_NAME);
}
/**
* Retourne l'instance du super-interpreteur (le thread superviseur).
* Dans le même temps, cette méthode permet de réinitialiser la VM.
* Pour cela, il suffit de placer forceReset sur true.
* @param forceReset
* @return instance du super-interpreter
*/
public static final int GETSUPERINTERPRETER_LESSMODE = 0;
public static final int GETSUPERINTERPRETER_HARDMODE = 1;
public static final int GETSUPERINTERPRETER_SOFTMODE = 2;
public static final Interpreter interpr_getSuperInterpreter(int gsi_mode) throws Exception {
if (_superInterpreter == null || (gsi_mode != GETSUPERINTERPRETER_LESSMODE)) {
_superInterpreter = new Interpreter();
}
if (gsi_mode == GETSUPERINTERPRETER_HARDMODE) {
interpr_resetSuperInterpreter();
}
else if (gsi_mode == GETSUPERINTERPRETER_SOFTMODE) {
_superInterpreter.softReset();
}
return _superInterpreter;
}
/**
* Retourne une nouvel interpreter fils sans paramètres spécifiques.
* @return
*/
public static final Interpreter interpr_getNewChildInterpreter() {
Interpreter interp = new Interpreter();
interp.setName(Interpreter.mySelf().getName() + "-child");
return interp;
}
public static final Interpreter interpr_getNewThreadInterpreter(String threadName) {
Interpreter interpreter = Interpreter.mySelf();
Interpreter interp = new Interpreter();
interp.motherThread = interpreter;
interp.source = interpreter.source;
interp.node = interpreter.node;
interp.outputTextArea = interpreter.outputTextArea;
interp.executionTimeOut = interpreter.executionTimeOut;
interp.deadlockTime = interpreter.deadlockTime;
interp.timeOutCheck = interpreter.timeOutCheck;
interp.breakingFromSEMAPHORE = interpreter.breakingFromSEMAPHORE;
synchronized (interpreter.GLOBAL) {
interp.GLOBAL = new StaticHeap(interpreter.GLOBAL);
/* Correctif du bug launchpad#1017442, l.bruninx (2012-06-25) */
interp.GLOBAL.push();
interp.GLOBAL.current().put(PCoder.ARGV, Node.createCList());
interp.GLOBAL.push();
/* Correctif du bug launchpad#1017442, l.bruninx (2012-06-25) */
}
interp.setInterThread(true);
//this.setPriority(interpreter.getPriority()+1);
interp.parse_strCnt = interpreter.parse_strCnt;
interp.parse_parCnt = interpreter.parse_parCnt;
interp.parse_dicCnt = interpreter.parse_dicCnt;
interp.parse_accCnt = interpreter.parse_accCnt;
interp.parse_croCnt = interpreter.parse_croCnt;
interp.parse_linCnt = interpreter.parse_linCnt;
interp.parse_strLineOffset = interpreter.parse_strLineOffset;
synchronized (semaphore) {
if (threadName != null && threadName.trim().length() != 0) {
String nThreadName = threadName;
int index = 0;
while (semaphore.isThreadsExists(threadName)) {
nThreadName = threadName + "-" + Integer.toString(++index);
}
interp.setName(nThreadName);
}
else {
String nThreadName = semaphore.getUniqueThreadName();
interp.setName(nThreadName);
}
Interpreter.Log("Register thread " + interp);
Interpreter.semaphore.registerThread(interp);
}
return interp;
}
public static final Interpreter interpr_cloneInterpreter(Interpreter interpreter) {
Interpreter interp = new Interpreter();
interp.motherThread = interpreter;
interp.source = interpreter.source;
interp.node = interpreter.node;
interp.outputTextArea = interpreter.outputTextArea;
interp.executionTimeOut = interpreter.executionTimeOut;
interp.deadlockTime = interpreter.deadlockTime;
interp.timeOutCheck = interpreter.timeOutCheck;
interp.breakingFromSEMAPHORE = interpreter.breakingFromSEMAPHORE;
synchronized (interpreter.GLOBAL) {
interp.GLOBAL = new StaticHeap(interpreter.GLOBAL);
}
interp.setInterThread(interpreter.isInterThread());
//this.setPriority(interpreter.getPriority()+1);
// interp.setExitCode(interpreter.getExitCode()); !!! ATTENTION : NE PAS UTILISER -> force l'arret de l'interpreteur...
interp.parse_strCnt = interpreter.parse_strCnt;
interp.parse_parCnt = interpreter.parse_parCnt;
interp.parse_dicCnt = interpreter.parse_dicCnt;
interp.parse_accCnt = interpreter.parse_accCnt;
interp.parse_croCnt = interpreter.parse_croCnt;
interp.parse_linCnt = interpreter.parse_linCnt;
interp.parse_strLineOffset = interpreter.parse_strLineOffset;
synchronized (semaphore) {
String threadName = interpreter.getName();
if (threadName != null && threadName.trim().length() != 0) {
String nThreadName = threadName;
int index = 0;
while (semaphore.isThreadsExists(threadName)) {
nThreadName = threadName + "-" + Integer.toString(++index);
}
interp.setName(nThreadName);
}
else {
String nThreadName = semaphore.getUniqueThreadName();
interp.setName(nThreadName);
}
Interpreter.Log("Register thread " + interp);
Interpreter.semaphore.registerThread(interp);
}
return interp;
}
private Exception interThreadException = null;
public void setInterThreadException(Exception ex, Interpreter interThrd) {
if (Interpreter.isDebugMode()) {
ex.printStackTrace();
}
interThreadException = new InterpreterException(StdErrors.createTrace(interThrd, ex));
}
/**
* Détection automatique des deadlocks et livelocks...
*/
// liste non bloquante des verrous acquis...
private ConcurrentLinkedQueue<Node> threadlock_A = new ConcurrentLinkedQueue<Node>();
// liste non bloquante des verrous demandé (donc en attente)...
private ConcurrentLinkedQueue<Node> threadlock_R = new ConcurrentLinkedQueue<Node>();
public void threadlock_A_add(Node node) {
threadlock_A.add(node);
}
public void threadlock_A_remove(Node node) {
threadlock_A.remove(node);
}
public boolean threadlock_A_has(Node node) {
return threadlock_A.contains(node);
}
public void threadlock_R_add(Node node) {
threadlock_R.add(node);
}
public void threadlock_R_remove(Node node) {
threadlock_R.remove(node);
}
public boolean threadlock_R_has(Node node) {
return threadlock_R.contains(node);
}
public void thowsDeadlock(Interpreter inter) throws InterpreterException {
/*
* Est-ce que je demande un verrous ?...
*/
if (inter != null && inter != this && !threadlock_R.isEmpty()) {
/*
* Détecter une circularité...
* ========================
*
* Pour commencer, est-ce qu'un de mes verrous acquis est demandé par l'autre processus ?...
*/
boolean hasA = false;
Iterator<Node> myA = threadlock_A.iterator();
while (myA.hasNext() && !hasA) {
hasA = hasA || inter.threadlock_R_has(myA.next()); // or pour passer à true s'il y en a un...
}
if (hasA) {
/*
* Si un de mes verrous est demandé par l'autre processus...
* Est-ce qu'un des verrous que je demande est déjà aquis par lui ?...
*/
boolean hasR = false;
Iterator<Node> myR = threadlock_R.iterator();
while (myR.hasNext() && !hasR) {
hasR = hasR || inter.threadlock_A_has(myR.next()); // or pour passer à true s'il y en a un...
}
/*
* Si c'est le cas aussi, alors nous sommes inter-bloqués...
*/
if (hasA && hasR) {
throw new InterpreterException(StdErrors.Deadlock_error);
}
}
}
/*
* sinon, pas de problème....
*/
return;
}
/**
* Gestion des piles du processus courant
*/
/*
* Piles pour l'opérateur/méthode equ?:
* -----------------------------------
* Permet d'éliminer l'exploration inutile des éléments circulaires.
*/
private NodeTags equStack_A = new NodeTags();
public NodeTags getEquStack_A(){
return equStack_A;
}
private NodeTags equStack_B = new NodeTags();
public NodeTags getEquStack_B(){
return equStack_B;
}
/*
* Piles pour l'opérateur/méthode compare:
* --------------------------------------
* Permet d'éliminer l'exploration inutile des éléments circulaires.
*/
private NodeTags compareStack_A = new NodeTags();
public NodeTags getCompareStack_A(){
return compareStack_A;
}
private NodeTags compareStack_B = new NodeTags();
public NodeTags getCompareStack_B(){
return compareStack_B;
}
/**
* Gestion générale des threads: Hooks, messages et signaux...
*/
private boolean threadStop = false;
private boolean threadSuspend = false;
private int threadLock = 0; // compteur de verroux (à partir de rev6251)
private int threadInLockSection = 0; // compteur de section (lock v{...})...
static private Vector<WeakReference<Runnable>> supervisorHooks = new Vector<WeakReference<Runnable>>();
private ConcurrentLinkedQueue<Node> threadMessages = new ConcurrentLinkedQueue<Node>();
private ConcurrentLinkedQueue<Object> threadSignals = new ConcurrentLinkedQueue<Object>();
final private static Object DEFAULT_SIGNAL = new Object();
private Object threadSuspendLock = new Object();
public Object thread_getSuspendLock() {
return threadSuspendLock;
}
public boolean isThreadSuspended() {
return threadSuspend;
}
public boolean isThreadStopped() {
// cas fail-over...
if (failOver) {
return false;
}
// traitement habituel...
return threadStop;
}
public void setThreadStopped(boolean stopstatus) {
threadStop = stopstatus;
}
public boolean isThreadRaising() throws Exception {
// cas fail-over...
if (failOver) {
return false;
}
// traitement habituel...
throwInterThreadException();
return threadStop || timeOutRaising || breakingFromSEMAPHORE;
}
/** **********************************************
*
* Implementation du Modèle d'acteurs:
*
* **********************************************
*
* Tous les processus légers sont des acteurs.
* Il y a un acteur principal, il s'agit du superviseur.
* Les acteurs peuvent requérir un traitement atomique de certaines actions.
* Un acteur peut s'endormir (pendant un certain délai) lui-même uniquement.
* Un acteur peut se suspendre lui-même uniquement.
* Un acteur peut en réveiller un autre mais jamais lui-même.
* Un acteur peut tuer un autre acteur mais jamais lui-même.
* Le acteurs communiquent entre eux par l'envoie et la réception de messages.
*
* Le superviseur peut recevoir un hook qui est une tâche à effectuer lors de l'arrêt du processus superviseur.
*
*/
/**
* Gestion de l'acteur principal : le superviseur.
*
*/
/**
* obtenir l'objet Interpreter du superviseur
* @return
*/
static public Interpreter supervisor_getInterpreter() {
return _superInterpreter;
}
/**
* ajouter un hook au superviseur.
* @param hook
*/
static public Object supervisor_PUTHOOK(Runnable hook) {
WeakReference<Runnable> weakRef = new WeakReference<Runnable>(hook);
synchronized (supervisorHooks) {
supervisorHooks.addElement(weakRef);
}
return weakRef;
}
/**
* Supprimer le hook sans l'exécuter
*
* @param weakRef
*/
static public void supervisor_REMOVEHOOK(Object weakRef) {
synchronized (supervisorHooks) {
if (weakRef != null) {
supervisorHooks.remove(weakRef);
WeakReference<?> wref = (WeakReference<?>) weakRef;
wref.clear();
}
}
}
static private Runnable supervisor_GETHOOK() {
Runnable res = null;
synchronized (supervisorHooks) {
int queue = supervisorHooks.size() - 1;
if (queue >= 0) {
WeakReference<Runnable> weakRef = supervisorHooks.elementAt(queue);
supervisorHooks.remove(queue);
res = weakRef.get();
}
}
return res;
}
static public boolean supervisor_HASHOOK() {
boolean res = false;
synchronized (supervisorHooks) {
res = (supervisorHooks.size() > 0);
}
return res;
}
static private void supervisor_CONSUMEHOOK() {
synchronized (supervisorHooks) {
while (supervisorHooks.size() > 0) {
Interpreter.Log(" --> CONSUMEHOOK #" + supervisorHooks.size() + "...");
Runnable hook = supervisor_GETHOOK();
if (hook != null) {
try {
hook.run();
}
finally {
}
}
}
}
return;
}
public void actor_PUTMSG(Node node) {
//synchronized (threadMessages) {
threadMessages.add(node);
//}
}
public Node actor_GETMSG() {
//Node res = null;
//synchronized (threadMessages) {
// if (threadMessages.size() > 0) {
// res = (Node) threadMessages.elementAt(0);
// threadMessages.remove(0);
// }
//}
return (Node) threadMessages.poll();
//return res;
}
public boolean actor_HASMSG() {
//boolean res = false;
//synchronized (threadMessages) {
return (threadMessages.size() > 0);
//}
//return res;
//
// La méthode size() est déjà synchronisée...
}
public void actor_EMPTYMSGS() {
//synchronized (threadMessages) {
if (threadMessages.size() > 0) {
Interpreter.Log(" --> REMOVING " + threadMessages.size() + " THREAD-MSG...");
}
threadMessages.clear();
//threadMessages.removeAllElements();
//}
return;
}
public void actor_SIGNAL() {
//synchronized (threadSignals) {
threadSignals.add(DEFAULT_SIGNAL);
//}
}
public boolean actor_CONSUMESIGNAL() {
//boolean res = false;
//synchronized (threadSignals) {
// if (threadSignals.size() > 0) {
// res = true;
// threadSignals.remove(0);
// }
//}
return threadSignals.poll() != null;
}
public boolean actor_HASSIGNALS() {
boolean res = false;
//synchronized (threadSignals) {
res = (threadSignals.size() > 0);
//}
return res;
}
public void actor_EMPTYSIGNALS() {
//synchronized (threadSignals) {
if (threadSignals.size() > 0) {
Interpreter.Log(" --> REMOVING " + threadSignals.size() + " THREAD-SIGNALS...");
}
//threadSignals.removeAllElements();
threadSignals.clear();
//}
return;
}
/*
* actor_LOCKMUTEX et actor_UNLOCKMUTEX ne devraient être accédé qu'à partir de l'acteur lui-même.
* Ces méthodes n'ont donc pas besoin d'être synchronisées.
*/
public void actor_LOCKMUTEX() {
threadLock++;
}
public void actor_UNLOCKMUTEX() {
threadLock--;
}
public boolean actor_ISMUTEX() {
return threadLock != 0;
}
/*
* actor_LOCKSECTION, actor_UNLOCKSECTION, et actor_ISLOCKEDSECTION ne devraient être accédée qu'à partir de
* l'acteur lui-même pour marquer les sections atomiques.
* Il n'y adonc pas besoin de synchronisation.
*/
public void actor_LOCKSECTION() {
threadInLockSection++;
}
public void actor_UNLOCKSECTION() {
threadInLockSection--;
}
public boolean actor_ISLOCKEDSECTION() {
return threadInLockSection != 0;
}
/*
* Il ne devrait pas y avoir de compétition pour accéder à actor_STOP.
* Il est donc inutile de synchronizer la méthode.
*/
public void actor_STOP() {
threadStop = true;
}
/*
* Situation de compétition possible, mais devrait être extraimement rare.
* Utiliser donc une stratégie optimiste du type test-and-set
*/
public void actor_SUSPEND() {
while (!threadSuspend) {
threadSuspend = true;
}
}
public void actor_RESUME() {
while (threadSuspend) {
threadSuspend = false;
}
}
/**
*
* Gestion des listes des messages postposés (c-à-d mis en attente).
*
**/
private LinkedList<Node> pendingMsg = null;
/*
* Permet l'implémentation de (pending{ ... (postpone msg)...})
* Les message postposés sont ajoutés à la fin de la queue (pendingMsg).
* Lorsqu'on sort de la section controlée par pending, tous les messages postposés sont replacés dans la boite
* de réception.
*
*
*/
/**
* Ouvre une nouvelle queue de messages en attente.
*
* @return la référence de la liste précédente
*/
public LinkedList<Node> pendingMsg_OPEN() {
LinkedList<Node> old = pendingMsg;
pendingMsg = new LinkedList<Node>();
return old;
}
/**
* Ferme la queue de message en attente courrante et restaure la précédente.
*
* En fermant la queue courante, les éventuels messages qu'elle contient sont
* automatiquement ajouté à la boite à message de l'acteur.
*
* @param old : ancienne queue retournée par pendingMsg_OPEN().
*/
public void pendingMsg_CLOSE(LinkedList<Node> old) throws Exception {
if (!pendingMsg.isEmpty()) {
if (!threadMessages.addAll(pendingMsg)) {
/*
* Si le ou les messages ne peuvent être ajoutés, une exception doit être produite...
*/
throw new InterpreterException(StdErrors.Internal_error);
}
}
pendingMsg = old;
}
/**
* Teste si une queue de messages en attente a été ouverte...
*
* @return true si une queue est disponible.
*/
public boolean pendingMsg_HASQUEUE() {
return pendingMsg != null;
}
/**
* Ajoute le message postposé à la fin de la queue pendingMsg.
* @param message
*/
public void pendingMsg_POSTPONE(Node message) throws Exception {
if (!pendingMsg.add(message)) {
/*
* Si le message ne peut être ajouté, une exception doit être produite...
*/
throw new InterpreterException(StdErrors.Internal_error);
}
}
/**
* Teste s'il y a des messages mis en d'attente.
*
* Attention, s'il n'y a pas de liste d'attente, il n'y a pas de message en attente non plus...
*
* @return true, s'il y a des messages en attente.
*/
public boolean pendingMsg_HASPOSTPONED() {
return pendingMsg != null && !pendingMsg.isEmpty();
}
/*
* Gestion fail-over pour hiniber l'arrêt brutal de l'interpréteur...
*/
private boolean failOver = false;
public final void setFailOver(boolean failOver) {
this.failOver = failOver;
}
public final boolean isFailOver() {
return failOver;
}
/*
* Lancement d'exception en fonction de l'état de l'interpréteur...
*/
public final void throwInterThreadException() throws Exception {
if (failOver)
return;
if (interThreadException != null) {
// fin Exception dans un thread fils...
if (timeOutTimer.isRunning()) {
timeOutTimer.stop();
}
Exception ex = interThreadException;
interThreadException = null;
throw ex;
}
if (breakingFromSEMAPHORE) {
// fin Breaking...
if (timeOutTimer.isRunning()) {
timeOutTimer.stop();
}
throw new InterpreterException(StdErrors.Breaking_exception);
}
if (timeOutRaising) {
// fin TimeOut Raising...
if (timeOutTimer.isRunning()) {
timeOutTimer.stop();
}
timeOutCheck = false;
timeOutRaising = false;
throw new InterpreterException(StdErrors.Timed_expired_exception);
}
if (endingFromSEMAPHORE || threadStop) {
// fin silencieuse
if (timeOutTimer.isRunning()) {
timeOutTimer.stop();
}
throw new SilentException();
}
}
/*
* Optimisation Java 6 : suppression du NodePool au bénéfice du GC de la JVM.
* -------------------------------------------------------------------------
*
* 27 janvier 2011.
*
*/
public final static Interpreter mySelf() {
Thread rThread = Thread.currentThread();
if (rThread instanceof Interpreter) {
Interpreter ms = (Interpreter) rThread;
if (ms.isInterThread()) {
ms.breakingFromSEMAPHORE = Interpreter.semaphore.isSignalBreak();
ms.endingFromSEMAPHORE = Interpreter.semaphore.isSignalEnd();
}
return ms;
}
return null;
}
/*
* Le paramètre canLoop est automatiquement restauré lors de la sortie d'une
* boucle itérative.
*
* Cette restauration est également réalisée en cas d'exception.
*/
public final void setCanLoop(boolean canLoop) {
this.canLoop = canLoop;
}
public final boolean isCanLoop() {
return canLoop;
}
public final void setInLoop(boolean inLoop) {
this.inLoop = inLoop;
}
public final boolean isInLoop() {
return inLoop;
}
/*
* Remplace le couple de tests: isCanLoop() && hasNoBreakCode() de manière à permettre un test supplémentaire:
* -Si isCanLoop()->true et hasNoBreakCode()->false (avec BREAKCODE_LOOP), il s'agit d'un skip-loop
*/
public final boolean isCanIterate() {
if (canLoop) {
switch(breakCode){
case BREAKCODE_NONE:
return true;
case BREAKCODE_LOOP:
// canLook est affirmatif, aussi on absorbe ce break-loop...
// il s'agit d'un skip-loop...
breakCode = BREAKCODE_NONE;
return true;
default:
return false;
}
}
else {
// autres ??!... Alors on arrête...
return false;
}
}
private Interpreter __thisInterpreter = null;
private Node interpreterArgs = null;
public void setInterpreterArgs(Node interpreterArgs) {
this.interpreterArgs = interpreterArgs;
}
public Node getInterpreterArgs() {
return interpreterArgs==null ? Node.createCList() : interpreterArgs;
}
public void run() {
if (isDebugMode()) {
Interpreter.LogTitle("NEW INTERPRETER INSTANCE STARTING...");
}
if (!this.isInterThread()) {
if (isDebugMode()) {
Interpreter.Log("");
Interpreter.Log("SUPERVISOR-THREAD -> register " + this);
}
Interpreter.semaphore.registerThread(this);
// interpréteur principal
long startlog = Interpreter.StartChrono();
try {
if (isDebugMode()) {
Interpreter.Log("");
Interpreter.Log("PARSING:");
Interpreter.Log(" . Parsing source code : " + this.source.length() + " characters...");
}
this.compile();
Interpreter.LogChrono(startlog, " . Parsing time");
if (isDebugMode()) {
Interpreter.Log(" . Generate AST of "+this.node.size_deep()+" nodes:" +
Tools.replaceCSeq("\n"+this.node.toString(),"\n","\n . "));
}
synchronized (semaphore) {
semaphore.reset();
}
String res = "";
returnedNode = null;
Interpreter.Log("");
Interpreter.Log("RUNNING AST:");
startlog = Interpreter.StartChrono();
__thisInterpreter = mySelf();
returnedNode = this.execute();
if (returnedNode != null) {
res = returnedNode.toString();
Interpreter.Log(" . Result Value : " + res);
}
else {
res = "";
}
synchronized (semaphore) {
semaphore.endAllCoroutines(); // déblocage de toutes coroutines...
}
Interpreter.LogChrono(startlog, " . Running time");
if (outputTextArea != null || Main.arg_prompt) {
if(outputTextArea != null){
if(res.length()>0)
outputTextArea.write(res + "\n");
outputTextArea.resetStyles();
outputTextArea.write("Ready...\n");
}
else{
if(res.length()>0)
System.out.println(res);
if(!System.getProperty("os.name").toLowerCase().startsWith("windows")){
byte[] esc=new byte[]{27,91,48,77 /* <esc>[0m */};
System.out.write(esc);
}
System.out.println("Ready...");
}
}
}
catch (Exception ex) {
if (ex instanceof SilentException) {
Interpreter.Log("SUPERVISON-THREAD -> SILENT-EXCEPTION");
}
else {
this.lastException = ex;
Interpreter.Log("ERROR: " + ex);
if (Interpreter.isDebugMode()) {
ex.printStackTrace();
}
if (outputTextArea != null) {
try{
outputTextArea.resetStyles();
outputTextArea.write("ERROR...\n" + ex.getMessage() + "\n");
}
catch(Exception e){e.printStackTrace();}
}
else{
System.err.print("ERROR...\n" + ex.getMessage() + "\n");
}
}
}
try {
// par sécurité...
synchronized (semaphore) {
semaphore.endAllCoroutines(); // déblocage de toutes coroutines...
}
}
catch (Exception ex) {
if (Interpreter.isDebugMode()) {
ex.printStackTrace();
}
}
Interpreter.Log("");
Interpreter.Log("Resource Counters :");
Interpreter.Log("------------------------:--------------------------");
Interpreter.Log("Heaps : maximum use of : " + GLOBAL.getMaxUse_cnt());
Interpreter.Log(" : created : " + GLOBAL.getCreation_cnt());
Interpreter.Log(" : reused : " + GLOBAL.getReuse_cnt());
Interpreter.Log(" : cleared : " + GLOBAL.getClearing_cnt());
Interpreter.Log("------------------------:--------------------------");
Interpreter.Log("Nodes : created : " + Node.getSerialCnt());
Interpreter.Log(" : cloned : " + Node.getExecCloneCnt());
Interpreter.Log("");
// Interpreter.Log("Node Tracker : " + Node.op_tracker); // pour debug...
Interpreter.Log("");
Interpreter.Log("SUPERVISOR-THREAD -> consume shutdown hooks.");
Interpreter.supervisor_CONSUMEHOOK();
Interpreter.Log("SUPERVISOR-THREAD -> emptying list of messages.");
Interpreter.mySelf().actor_EMPTYMSGS();
Interpreter.Log("SUPERVISOR-THREAD -> emptying list of signals.");
Interpreter.mySelf().actor_EMPTYSIGNALS();
Interpreter.Log("SUPERVISOR-THREAD -> unregister " + mySelf());
Interpreter.semaphore.unregisterThread(mySelf());
Interpreter.Log("SUPERVISOR-THREAD -> END." + (hasExitCode() ? " (Exit Code = " + getExitCode() + ").": ""));
}
else {
// il s'agit d'une coroutine...
try {
try {
synchronized (Interpreter.semaphore) {
Interpreter.semaphore.wait(10);
}
}
catch (Exception ex) {
if (Interpreter.isDebugMode()) {
ex.printStackTrace();
}
}
Interpreter.Log(mySelf() + " -> execute:");
String res = "";
returnedNode = null;
__thisInterpreter = mySelf();
returnedNode = this.execute();
if (returnedNode != null) {
res = returnedNode.toString();
Interpreter.Log(mySelf() + " -> result: " + res);
}
else {
res = "";
}
}
catch (SilentException silex) {
Interpreter.Log(mySelf() + " -> SILENT-EXCEPTION");
}
catch (Exception ex) {
Interpreter mother = mySelf().getMotherThread();
if (mother != null) {
// on a un interpréteur "maman"...
//final InterpreterException nex = new InterpreterException();
mother.setInterThreadException(ex, mySelf());
// S'ASSURER DE LA FIN DU TIMER
if (timeOutTimer.isRunning()) {
timeOutTimer.stop();
}
}
else {
// traitement par défaut...
// S'ASSURER DE LA FIN DU TIMER
if (timeOutTimer.isRunning()) {
timeOutTimer.stop();
}
this.lastException = ex;
Interpreter.Log("ERROR: " + ex);
if (Interpreter.isDebugMode()) {
ex.printStackTrace();
}
if (outputTextArea != null) {
try{
outputTextArea.resetStyles();
outputTextArea.write(mySelf() + " -> ERROR " + ex.getMessage() + "\n");
}
catch(Exception e){e.printStackTrace();}
}
else{
System.err.print(mySelf() + " -> ERROR " + ex.getMessage() + "\n");
}
}
}
// ne prend pas en compte les autres exceptions dans un thread...
Interpreter.Log(mySelf() + " -> emptying the list of messages.");
Interpreter.mySelf().actor_EMPTYMSGS();
Interpreter.Log(mySelf() + " -> emptying the list of signals.");
Interpreter.mySelf().actor_EMPTYSIGNALS();
Interpreter.Log(mySelf() + " -> END.");
Interpreter.semaphore.unregisterThread(mySelf());
Interpreter.Log(mySelf() + " -> unregister " + mySelf());
}
}
public void setLogTextArea(OutputTextArea logTextArea) {
this.logTextArea = logTextArea;
}
public OutputTextArea getLogTextArea() {
return logTextArea;
}
public void setOutputTextArea(OutputTextArea outputTextArea) {
this.outputTextArea = outputTextArea;
}
public OutputTextArea getOutputTextArea() {
return outputTextArea;
}
public void setSource(String source) {
this.source = source;
}
public String getSource() {
return source;
}
public void compile() throws Exception {
node = Node.compile(source);
if (node.isLazy()) {
node.setType(Node.TYPE_EXPR);
}
}
public Node execute() throws Exception {
String oClass_path = System.getProperty("java.class.path");
Node res = null;
try {
deadlockTime = StartChrono() + executionTimeOut;
_check_GLOBAL();
/* Corrige le bug launchpad#1009077 (l.bruninx, 2012-06-07) */
if(Heap.exists(ASymbol.SYMBOL_ARGV))
// argv est déjà dans la pile
Heap.swapv(ASymbol.SYMBOL_ARGV, this.getInterpreterArgs());
else{
// argv n'est pas encore dans la pile
Heap.defv(ASymbol.SYMBOL_ARGV, this.getInterpreterArgs());
// Il faut protéger l'espace de nom de argv. Il peut être redéfini.
Heap.push();
}
/* Corrige le bug launchpad#1009077, l.bruninx (2012-06-07) */
res = node.exec(false);
if (timeOutTimer.isRunning()) {
timeOutTimer.stop();
}
}
catch (RestartException talex) {
throw new InterpreterException(StdErrors.createTrace(talex.getFrom(), new InterpreterException(StdErrors.Restart_error)));
}
catch (RetryException retryex) {
throw new InterpreterException(StdErrors.createTrace(retryex.getFrom(), new InterpreterException(StdErrors.Retry_error)));
}
catch (AbortException abortex) {
throw new InterpreterException(StdErrors.createTrace(abortex.getFrom(), new InterpreterException(StdErrors.Retry_error)));
}
catch (Exception e) {
System.setProperty("java.class.path", oClass_path);
throw e;
}
System.setProperty("java.class.path", oClass_path);
return res;
}
public static FreezeTimeOut freezeTimeOut() {
Interpreter interpreter = Interpreter.mySelf();
interpreter.timeOutTimer.stop();
FreezeTimeOut ft = new FreezeTimeOut(0, interpreter.timeOutCheck);
if (interpreter.timeOutCheck) {
interpreter.timeOutCheck = false;
long now_to = System.currentTimeMillis();
long end_to = interpreter.deadlockTime;
long reste = end_to - now_to;
if (reste < 0) {
reste = 0;
}
ft.reste_to = reste;
}
return ft;
}
public static void unfreezeTimeOut(FreezeTimeOut popFreeze) {
if (popFreeze.to_state) {
Interpreter interpreter = Interpreter.mySelf();
interpreter.deadlockTime = System.currentTimeMillis() + popFreeze.reste_to;
interpreter.timeOutCheck = true;
interpreter.timeOutTimer.start();
}
}
/**
* propriétés générales de la vérification de la syntaxe lors
* de la compilation.
*/
int parse_strCnt = 0;
int parse_parCnt = 0;
int parse_dicCnt = 0;
int parse_accCnt = 0;
int parse_croCnt = 0;
int parse_linCnt = 0;
int parse_strLineOffset = 0;
}