package abstrasy.pcfx;
import abstrasy.ASymbol;
import abstrasy.Heap;
import abstrasy.Interpreter;
import abstrasy.Node;
import abstrasy.PCoder;
import abstrasy.SourceFile;
import abstrasy.interpreter.InterpreterException;
import abstrasy.interpreter.StdErrors;
import java.io.File;
import java.net.URL;
/**
* 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_import extends PCFx {
public PCFx_import() {
}
private static final void _check_symbol_(ASymbol symbole) throws InterpreterException {
/**
* le symbole ne peut pas être composé...
*/
if (symbole.getIdsCnt() > 1)
throw new InterpreterException(StdErrors.Invalid_symbol);
/**
* il doit au minimum être immutable
*/
if (!symbole.isImmutable()) {
throw new InterpreterException(StdErrors.Immutable_symbol_required);
}
}
private static final void _provide_(Node n_provide, String moduleID) throws Exception {
// traiter la liste provide si elle existe...
for (int i = 0; i < n_provide.size(); i++) {
ASymbol p_symbole = n_provide.elementAt(i).getSymbol();
// vérification du symbole : local et immutable
_check_symbol_(p_symbole);
// lien 'Symbole <-(synonyme)- 'Module:Symbole
Heap.defv(p_symbole, Heap.getv(new ASymbol(moduleID + PCoder.SEP + p_symbole.getStr())));
}
}
/**
* eval
*
* @param startAt Node
* @return Node
* @throws Exception
* @todo Implémenter cette méthode abstrasy.PCFx
*/
public Node eval(Node startAt) throws Exception {
/*
* formes :
*
* (import 'Module)
* (import 'Module provide 'Symbole0 'Symbole1 ....)
*
* (import 'Module from "chemin_fichier")
* (import 'Module from "chemin_fichier" provide 'Symbole0 'Symbole1 ....)
*
*/
/**
* Analyser la syntaxe de la forme...
*/
Node n_module = null;
Node n_from = null;
Node n_provide = Node.createCList();
// longueur minimum à ce stade: (import 'Module) = 2
int mxarg = 2;
startAt.isGoodArgsLength(false, mxarg);
int iarg = 1; // index de l'arg courant...
// récupérer le symbole du module...
n_module = startAt.getSubNode(iarg++, Node.TYPE_QSYMBOL);
// s'il y a plus d'argument...
while (startAt.size() > mxarg) {
// alors il y en a au moins 2 en plus...
mxarg += 2;
startAt.isGoodArgsLength(false, mxarg);
// récupération de l'opérateur de clause
Node c_op = startAt.getSubNode(iarg++, Node.TYPE_PCODE);
//
if (c_op.isPCode(PCoder.PC_FROM)) {
// forme ... from "chemin" ...
n_from = startAt.getSubNode(iarg++, Node.TYPE_STRING);
}
else if (c_op.isPCode(PCoder.PC_PROVIDE)) {
// forme ... provide 'S1 'S2 .... 'Sn )
while (iarg < startAt.size()) {
n_provide.addElement(startAt.getSubNode(iarg++, Node.TYPE_QSYMBOL));
}
mxarg = startAt.size();
}
else {
// erreur...
throw new InterpreterException(StdErrors.Syntax_error);
}
}
Node rnode = null;
/*
* préparation du symbole du module...
*/
ASymbol symbole = n_module.getSymbol();
// vérification du symbole : local et immutable
_check_symbol_(symbole);
//
/**
* ne pas aller plus loin si le module est déjà chargé...
*/
ASymbol moduleID = new ASymbol(PCoder.REGISTRY + PCoder.SEP + symbole.getStr());
if (Heap.exists(moduleID)) {
Heap.defv(symbole, Heap.getv(moduleID));
// traiter la liste provide si elle existe...
_provide_(n_provide,moduleID.getStr());
return null;
}
/**
* Le module n'est pas encore chargé.
* =================================
*
* On va le charger...
*
*/
// déterminer le nom du fichier à chercher...
Node npath = n_from == null ? new Node(symbole.getRootNamespace()): n_from;
// chercher le fichier...
File src = SourceFile.findSourceFileName(npath.getString());
// c'est parti!...
String msrc = "";
SourceFile in = null;
if (src != null) {
in = new SourceFile(src.getAbsolutePath());
}
else {
Node iPaths = Heap.getv(ASymbol.SYMBOL_IMPORTS_PATH);
if (iPaths != null) {
if (iPaths.getQType()==Node.TYPE_CLIST) {
for (int ip = (iPaths.size() - 1); ip >= 0; ip--) {
Node pval = iPaths.elementAt(ip);
if (pval.isString()) {
src = SourceFile.findSourceFileName(pval.getString() + npath.getString());
if (src != null) {
in = new SourceFile(src.getAbsolutePath());
ip = -1;
}
}
}
}
}
}
if (in == null) {
Node iPaths = Heap.getv(ASymbol.SYMBOL_IMPORTS_BASE_URL);
if (iPaths != null) {
if (iPaths.getQType()==Node.TYPE_CLIST) {
for (int ip = (iPaths.size() - 1); ip >= 0; ip--) {
Node pval = iPaths.elementAt(ip);
if (pval.isString()) {
URL surl = SourceFile.findSourceURLName(pval.getString() + npath.getString());
if (surl != null) {
in = new SourceFile(surl);
ip = -1;
}
}
}
}
}
}
if (in != null) {
try {
in.load();
msrc = in.getSource();
Interpreter interpreter = Interpreter.interpr_getNewChildInterpreter();
//Register continue dans le même thread...
Heap.push(); // mais en créant une closure
interpreter.setSource(msrc);
interpreter.compile();
Heap.DynamicConstants.setMAIN_FALSE();
if ((rnode = interpreter.getNode().exec(false)) != null) {
Interpreter.Log("Retour Import ??? " + rnode);
}
Heap.pull();
// enregistrer le module
Heap.defv(new ASymbol(symbole.getLocalName()), Heap.getv(moduleID));
// traiter la liste provide si elle existe...
_provide_(n_provide,moduleID.getStr());
return null;
}
catch (Exception ex) {
if (Interpreter.isDebugMode()) {
ex.printStackTrace();
}
throw new InterpreterException(StdErrors.createTrace(startAt, ex));
}
}
else {
throw new InterpreterException(StdErrors.Cannot_import_module);
}
}
}