1 |
#include <Python.h> |
2 |
|
3 |
#include <iostream> |
4 |
#include <stdexcept> |
5 |
#include <sstream> |
6 |
using namespace std; |
7 |
|
8 |
#undef NDEBUG |
9 |
|
10 |
#include "config.h" |
11 |
|
12 |
extern "C"{ |
13 |
#include <utilities/ascConfig.h> |
14 |
#include <compiler/compiler.h> |
15 |
#include <general/list.h> |
16 |
#include <compiler/slist.h> |
17 |
#include <compiler/ascCompiler.h> |
18 |
#include <compiler/fractions.h> |
19 |
#include <compiler/compiler.h> |
20 |
/* #include <compiler/redirectFile.h> */ |
21 |
#include <compiler/module.h> |
22 |
#include <compiler/prototype.h> |
23 |
#include <compiler/dump.h> |
24 |
#include <compiler/dimen.h> |
25 |
#include <compiler/child.h> |
26 |
#include <compiler/childio.h> |
27 |
#include <compiler/type_desc.h> |
28 |
#include <compiler/typedef.h> |
29 |
#include <compiler/library.h> |
30 |
#include <compiler/childinfo.h> |
31 |
#include <solver/slv_types.h> |
32 |
#include <solver/system.h> |
33 |
#include <utilities/ascEnvVar.h> |
34 |
#include <compiler/symtab.h> |
35 |
#include <general/table.h> |
36 |
#include <compiler/instance_enum.h> |
37 |
#include <compiler/notate.h> |
38 |
#include <compiler/simlist.h> |
39 |
#include <compiler/parser.h> |
40 |
#include <utilities/error.h> |
41 |
#include <general/env.h> |
42 |
#include <compiler/importhandler.h> |
43 |
} |
44 |
|
45 |
#include "library.h" |
46 |
#include "simulation.h" |
47 |
#include "solver.h" |
48 |
|
49 |
Library::Library(const char *defaultpath){ |
50 |
static int have_init; |
51 |
if(!have_init){ |
52 |
cerr << "Initialising ASCEND library..." << endl; |
53 |
|
54 |
#ifdef REIMPLEMENT_STREAMS |
55 |
Asc_RedirectCompilerDefault(); // Ensure that error message reach stderr |
56 |
#endif |
57 |
|
58 |
Asc_CompilerInit(1); |
59 |
env_import(PATHENVIRONMENTVAR,getenv,Asc_PutEnv); |
60 |
char *x = Asc_GetEnv(PATHENVIRONMENTVAR); |
61 |
if(x==NULL || strcmp(x,"")==0){ |
62 |
if(defaultpath==NULL){ |
63 |
ERROR_REPORTER_NOLINE(ASC_PROG_WARNING,"Using default " |
64 |
PATHENVIRONMENTVAR " = '" DEFAULT_ASCENDLIBRARY "'" |
65 |
); |
66 |
defaultpath = DEFAULT_ASCENDLIBRARY; |
67 |
} |
68 |
|
69 |
string s = string(PATHENVIRONMENTVAR "=") + defaultpath; |
70 |
//ERROR_REPORTER_HERE(ASC_PROG_NOTE,"Setting %s",s.c_str());; |
71 |
Asc_PutEnv(s.c_str()); |
72 |
} |
73 |
Asc_ImportPathList(PATHENVIRONMENTVAR); |
74 |
//cerr << PATHENVIRONMENTVAR << " = " << x << endl; |
75 |
//cerr << "Created LIBRARY" << endl; |
76 |
//cerr << "Registering solvers..." << endl; |
77 |
registerStandardSolvers(); |
78 |
}/*else{ |
79 |
CONSOLE_DEBUG("Reusing LIBRARY"); |
80 |
}*/ |
81 |
have_init=1; |
82 |
} |
83 |
|
84 |
Library::~Library(){ |
85 |
//ERROR_REPORTER_NOLINE(ASC_PROG_WARNING,"DESTROYED LIBRARY!"); |
86 |
//DestroyLibrary(); |
87 |
// ... need to use some kind of reference counting before you can do that... |
88 |
} |
89 |
|
90 |
/** |
91 |
Load an ASCEND model file into the Library. It will be parsed such that |
92 |
its types will be visible to Library::findType. |
93 |
|
94 |
@param filename Filename, will be searched for relative to ASCENDLIBRARY environment |
95 |
variable, if necessary. |
96 |
*/ |
97 |
void |
98 |
Library::load(const char *filename){ |
99 |
|
100 |
//std::cerr << "Loading '" << filename << "'" << std::endl; |
101 |
|
102 |
int status; |
103 |
struct module_t *m=Asc_RequireModule(filename,&status); |
104 |
if(m!=NULL){ |
105 |
//std::cerr << "Loaded module '" << Asc_ModuleName(m) << "'" << std::endl; |
106 |
}else{ |
107 |
std::cerr << "Error: unable to load module '" << filename << "'." << std::endl; |
108 |
} |
109 |
|
110 |
char *msg; |
111 |
switch(status){ |
112 |
case 5: |
113 |
msg = "The module '%s' already exists. "; break; |
114 |
case 4: |
115 |
msg = "Caught an attempt to do a recursive require under '%s'."; break; |
116 |
case 3: |
117 |
msg = "A new module was created from '%s', overwriting a module's alias."; break; |
118 |
case 2: |
119 |
msg = "An existing module is being returned for '%s'." ; break; |
120 |
case 1: |
121 |
msg = "An new version of an existing module was created for '%s'."; break; |
122 |
case 0: |
123 |
msg = "Module for '%s' created OK."; break; |
124 |
case -1: |
125 |
msg = "Error: File not found for '%s'. (-1)"; break; |
126 |
case -2: |
127 |
msg = "Error: Unable to open '%s' for reading. (-2)";break; |
128 |
case -3: |
129 |
msg = "Error: Insuffient memory to create module for '%s'. (-3)"; break; |
130 |
case -4: |
131 |
msg = "Error: bad input, null or zero length filename in '%s'. (-4)"; break; |
132 |
default: |
133 |
throw std::runtime_error("Invalid status code in library.cpp"); |
134 |
} |
135 |
|
136 |
char msg1[100]; |
137 |
sprintf(msg1,msg,filename); |
138 |
|
139 |
if(status<0 || status>0){ |
140 |
throw std::runtime_error(msg1); |
141 |
}else{ |
142 |
std::cerr << "Note: Module " << Asc_ModuleName(m) << ": " << msg1 << std::endl; |
143 |
} |
144 |
|
145 |
CONSOLE_DEBUG("Beginning parse of %s",Asc_ModuleName(m)); |
146 |
error_reporter_tree_start(); |
147 |
status = zz_parse(); |
148 |
switch(status){ |
149 |
case 0: break; |
150 |
case 1: ERROR_REPORTER_NOLINE(ASC_USER_ERROR,"Parsing of %s was aborted",Asc_ModuleName(m)); break; |
151 |
case 2: ERROR_REPORTER_NOLINE(ASC_PROG_FATAL,"Out of memory when parsing %s",Asc_ModuleName(m)); break; |
152 |
default: ERROR_REPORTER_NOLINE(ASC_PROG_ERROR,"Invalid return from zz_parse"); break; |
153 |
} |
154 |
status = error_reporter_tree_has_error(); |
155 |
error_reporter_tree_end(); |
156 |
if(!status){ |
157 |
CONSOLE_DEBUG("CLEARING TREE..."); |
158 |
error_reporter_tree_clear(); |
159 |
CONSOLE_DEBUG("DONE CLEARING TREE..."); |
160 |
}else{ |
161 |
ERROR_REPORTER_NOLINE(ASC_USER_ERROR,"Error(s) when loading '%s'",filename); |
162 |
stringstream ss; |
163 |
ss << "Errors found in '" << filename << "'"; |
164 |
throw runtime_error(ss.str()); |
165 |
} |
166 |
|
167 |
|
168 |
struct gl_list_t *l = Asc_TypeByModule(m); |
169 |
CONSOLE_DEBUG("%lu library entries loaded from %s",gl_length(l), filename); |
170 |
} |
171 |
|
172 |
/** |
173 |
Return a vector of all the Modules which have been loaded into |
174 |
the current library. |
175 |
*/ |
176 |
vector<Module> |
177 |
Library::getModules(const int module_type){ |
178 |
if(module_type < 0 || module_type > 2){ |
179 |
throw std::runtime_error("Library::getModules: invalid module_type parameter"); |
180 |
} |
181 |
|
182 |
vector<Module> v; |
183 |
struct gl_list_t *l = Asc_ModuleList(module_type); |
184 |
if(l==NULL){ |
185 |
CONSOLE_DEBUG("list is empty"); |
186 |
return v; |
187 |
} |
188 |
for(int i=0, end=gl_length(l); i<end; ++i){ |
189 |
symchar *name = (symchar *)gl_fetch(l,i+1); |
190 |
if(AscFindSymbol(name)==NULL){ |
191 |
throw runtime_error("Library::getModules: invalid symchar *"); |
192 |
} |
193 |
//cerr << "GOT " << SCP( name ) << endl; |
194 |
const module_t *m = Asc_GetModuleByName((const char *)name); |
195 |
v.push_back(Module(m)); |
196 |
} |
197 |
/*cerr << "LENGTH OF V IS " << v.size() << endl; |
198 |
if(v.size()){ |
199 |
cerr << "MODULE 0's NAME IS " << v[0].getName() << endl; |
200 |
}*/ |
201 |
return v; |
202 |
} |
203 |
|
204 |
/** |
205 |
Output to stderr the names of the modules loaded into the current Library. |
206 |
*/ |
207 |
void |
208 |
Library::listModules(const int module_type){ |
209 |
if(module_type < 0 || module_type > 2){ |
210 |
throw std::runtime_error("Library::listModules: invalid module_type parameter"); |
211 |
} |
212 |
|
213 |
char *type = NULL; |
214 |
switch(module_type){ |
215 |
case 0: type = "defined types"; break; |
216 |
case 1: type = "string definitions"; break; |
217 |
case 2: type = "statements"; break; |
218 |
} |
219 |
|
220 |
vector<Module> v = getModules(module_type); |
221 |
if(v.size()){ |
222 |
std::cerr << "Listing " << v.size() << " modules with " << type << std::endl; |
223 |
for(vector<Module>::const_iterator i=v.begin(); i < v.end(); ++i){ |
224 |
cerr << " - " << i->getName() << endl; |
225 |
vector<Type> tt = getModuleTypes(*i); |
226 |
for(vector<Type>::const_iterator j = tt.begin(); j < tt.end(); ++j){ |
227 |
cerr << " * " << j->getName() << endl; |
228 |
} |
229 |
} |
230 |
}else{ |
231 |
std::cerr << "Notice: No " << type << " found in module list." << std::endl; |
232 |
} |
233 |
} |
234 |
|
235 |
Type & |
236 |
Library::findType(const SymChar &sym){ |
237 |
TypeDescription *t = FindType(sym.getInternalType()); |
238 |
if(t==NULL){ |
239 |
stringstream ss; |
240 |
ss << "Library::findType: type '" << sym << "' not found in library"; |
241 |
throw runtime_error(ss.str()); |
242 |
}/*else{ |
243 |
cerr << "Found something for type " << sym << endl; |
244 |
}*/ |
245 |
Type *t2=new Type(t); |
246 |
return *t2; |
247 |
} |
248 |
|
249 |
/** |
250 |
This could be quite a bit more efficient if we could get a gl_list_t of TypeDescription rather than names |
251 |
*/ |
252 |
vector<Type> |
253 |
Library::getModuleTypes(const Module &m){ |
254 |
//cerr << "GET MODULE TYPES\n" << endl; |
255 |
vector<Type> v; |
256 |
struct gl_list_t *l = Asc_TypeByModule(m.getInternalType()); |
257 |
for(int i=0,end=gl_length(l); i<end; ++i){ |
258 |
char *name = (char *)gl_fetch(l,i+1); |
259 |
//CONSOLE_DEBUG("Found type %s",name); |
260 |
TypeDescription *t = FindType((const symchar *)name); |
261 |
v.push_back(Type(t)); |
262 |
} |
263 |
return v; |
264 |
} |
265 |
|
266 |
/** |
267 |
This function is kinda fighting against the Table implementation of the external function library. What we really need is some kind of iterator on the Table struct, but it doesn't seem to be implemented. Instead there is a C-style equivalent of the STL 'bind1st' function which we can use, but it's not exported from the current extfunc.h so we need to add it. |
268 |
*/ |
269 |
vector<ExtMethod> |
270 |
Library::getExtMethods(){ |
271 |
// Clear the vector |
272 |
extmethod_vector = vector<ExtMethod>(); |
273 |
|
274 |
// Traverse the vector |
275 |
TraverseExtFuncLibrary(Library::extMethodTraverse, (void *)this); |
276 |
|
277 |
return extmethod_vector; |
278 |
} |
279 |
|
280 |
/** |
281 |
This method exists only to allow the TraverseExtFuncLibrary function |
282 |
to make callbacks to the Library class from C. |
283 |
|
284 |
@NOTE there might be issues with C/C++ linking here? |
285 |
*/ |
286 |
void |
287 |
Library::extMethodTraverse(void *a1, void *a2){ |
288 |
Library *self = (Library *)a2; |
289 |
self->appendToExtMethodVector(a1); |
290 |
} |
291 |
|
292 |
void |
293 |
Library::appendToExtMethodVector(void *a1){ |
294 |
struct ExternalFunc *e = (struct ExternalFunc *)a1; |
295 |
extmethod_vector.push_back(ExtMethod(e)); |
296 |
} |
297 |
|
298 |
/** |
299 |
Clear the library: 'DESTROY TYPES' |
300 |
|
301 |
@TODO do this more efficiently, don't destroy the whole ASCEND compiler. |
302 |
*/ |
303 |
void |
304 |
Library::clear(){ |
305 |
/* Asc_CompilerDestroy(); |
306 |
cerr << "COMPLETED ASC_COMPILERDESTROY" << endl; |
307 |
Asc_CompilerInit(1); |
308 |
cerr << "... ASC_COMPILERINIT OK" << endl; |
309 |
Asc_ImportPathList(PATHENVIRONMENTVAR); |
310 |
registerStandardSolvers(); |
311 |
cerr << "... REGISTER_STANDARD_SOLVERS" << endl; |
312 |
DefineFundamentalTypes(); |
313 |
cerr << "... DEFINED FUND TYPES" << endl; |
314 |
\*SetUniversalProcedureList(NULL); |
315 |
*/ |
316 |
|
317 |
//CONSOLE_DEBUG("Displaying library modules and types..."); |
318 |
//listModules(); |
319 |
|
320 |
CONSOLE_DEBUG("Destroying simulations..."); |
321 |
Asc_DestroySimulations(); |
322 |
|
323 |
CONSOLE_DEBUG("Clearing library..."); |
324 |
DestroyNotesDatabase(LibraryNote()); |
325 |
SetUniversalProcedureList(NULL); |
326 |
DestroyLibrary(); |
327 |
DestroyPrototype(); |
328 |
EmptyTrash(); |
329 |
Asc_DestroyModules((DestroyFunc)DestroyStatementList); |
330 |
importhandler_destroylibrary(); |
331 |
WriteChildMissing(NULL,NULL,NULL); |
332 |
//Asc_CompilerInit(1) |
333 |
DefineFundamentalTypes(); |
334 |
InitNotesDatabase(LibraryNote()); |
335 |
ERROR_REPORTER_NOLINE(ASC_PROG_WARNING,"LIBRARY CLEARED!"); |
336 |
} |
337 |
|
338 |
AnnotationDatabase |
339 |
Library::getAnnotationDatabase(){ |
340 |
return AnnotationDatabase(SCP(LibraryNote())); |
341 |
} |