PEBL 2.2
Psychology Experiment Building Language - Cross-platform psychological experiment development system
Loader.cpp
Go to the documentation of this file.
1//* -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- */
3// Name: src/base/Loader.cpp
4// Purpose: Defines an class that loads a parsed PNode tree into PEBL Environment
5// Author: Shane T. Mueller, Ph.D.
6// Copyright: (c) 2003-2026 Shane T. Mueller <smueller@obereed.net>
7// License: GPL 2
8//
9//
10//
11//
12// This file is part of the PEBL project.
13//
14// PEBL is free software; you can redistribute it and/or modify
15// it under the terms of the GNU General Public License as published by
16// the Free Software Foundation; either version 2 of the License, or
17// (at your option) any later version.
18//
19// PEBL is distributed in the hope that it will be useful,
20// but WITHOUT ANY WARRANTY; without even the implied warranty of
21// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22// GNU General Public License for more details.
23//
24// You should have received a copy of the GNU General Public License
25// along with PEBL; if not, write to the Free Software
26// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28
29#include "Loader.h"
30
31#include "PNode.h"
32#include "grammar.tab.hpp"
33#include "Variant.h"
34#include "FunctionMap.h"
35
36#ifdef PEBL_EMSCRIPTEN
37#include "Evaluator-es.h"
38#include <emscripten.h>
39#else
40#include "Evaluator.h"
41#endif
42
43#include "../utility/PEBLUtility.h"
44#include "../utility/PError.h"
45
46//Include the function libraries
47#include "../libs/Functions.h"
48#include "../libs/PEBLEnvironment.h"
49#include "../libs/PEBLMath.h"
50#include "../libs/PEBLObjects.h"
51#include "../libs/PEBLStream.h"
52#include "../libs/PEBLString.h"
53
54
55#include <iostream>
56#include <list>
57#include <string>
58
59#undef PEBL_DEBUG_PRINT
60
61
62using std::cerr;
63using std::cout;
64using std::endl;
65using std::flush;
66using std::list;
67using std::string;
68
70{
71
72}
73
75{
76
77 //cout << "Deleting loader\n";
78 //DumpFunctionSet();
79}
80
81
82
83
84
88void Loader::FindFunctions(const PNode * node)
89{
90
91
92 //First, determine if this is a data node; if it is,
93 //see if it is a function name.
94 if(node->GetType() == PEBL_DATA_NODE)
95 {
96 //cout << "A Data node." << endl;
97 if(((DataNode*)node)->GetDataType() == P_DATA_FUNCTION)
98 {
99 //cout << "\tA Function Node: " << *node << endl;
100 //If the node is a function name, insert the name into the
101 //functionname set
102
103 //This cast should be done in a smarter way:
104 Variant v = ((DataNode*)(node))->GetValue();
105
106
107 //Now, convert the function name in v to upper case
108 //It is really just a string.
109 std::string ucasename = PEBLUtility::ToUpper(v);
110
111 Variant v2 = Variant(ucasename.c_str(), P_DATA_FUNCTION);
112
113 //cout << "\tValue: " << v2 << "|" << v2.GetDataTypeName() << endl;
114 //std::pair<std::set<Variant>::iterator, bool> myPair;
115 //myPair = mFunctionSet.insert(v2);
116 mFunctionSet.insert(v2);
117
118 // cout << "Result: " << *(myPair.first) << " " << (myPair.second) << endl;
119 //DumpFunctionSet();
120 }
121 }
122 else
123 {
124
125 //Otherwise, it is an OpNode. Recurse on the left and right nodes.
126
127 PNode * node1 = ((OpNode*)node)->GetLeft();
128
129
130 if(node1)
131 {
132 FindFunctions(node1);
133 }
134
135 node1 = ((OpNode*)node)->GetRight();
136 if(node1)
137 {
138 FindFunctions(node1);
139 }
140 }
141}
142
143
148{
149
150 //This will only parse down to PEBL_FUNCTION
151 //OpNodes, and so should only include two types:
152 //PEBL_FUNCTION and PEBL_FUNCTIONS.
153
154 OpNode *node1;
155
156 //If this is a PEBL_FUNCTIONS node, the left is either a PEBL_FUNCTIONS or
157 // a PEBL_FUNCTION and the right is either a PEBL_FUNCTIONS
158 //or a NULL. If null, we are done.
159
160
161 //Add the PEBL_FUNCTION
162 node1 = (OpNode*)(node->GetLeft());
163 if(node1->GetOp() == PEBL_FUNCTION)
164 {
165
166 Evaluator::mFunctionMap.AddFunction( ((DataNode*)(((OpNode*)node1)->GetLeft()))->GetValue(),
167 (OpNode*)node1->GetRight());
168 }
169 else if (node1->GetOp() == PEBL_FUNCTIONS)
170 {
171 LoadUserFunctions(node1);
172 }
173 else
174 {
175 cerr << "PEBL_FUNCTION is " << PEBL_FUNCTION << endl;
176 cerr << "PEBL_FUNCTIONS is " << PEBL_FUNCTIONS << endl;
177 cerr << "Unknown Node type in Loader::LoadUserFunctions: " << node1->GetOp() << endl;
178 PError::SignalFatalError("Unknown Node Type");
179 }
180 //Get the PEBL_FUNCTIONS node and recurse
181 node1 = (OpNode*)(node->GetRight());
182 if(node1)
183 {
184 LoadUserFunctions(node1);
185 }
186
187}
188
189
190
196{
197 //Get an iterator to the first item
198 std::set<Variant>::iterator p;
199 p=mFunctionSet.begin();
200
201 PEBL_Function_Type * functionTable = NULL;
202
203 while(p != mFunctionSet.end())
204 {
205 //Check inside mFunctionMap, to make sure it hasn't been found yet;
206 //If it is found, it may be a user-defined function (as in Start), or
207 //one that has already been loaded previously.
208
209 string name = (*p).GetFunctionName();
210 //cout << "Checking [" << name <<"]"<< endl;
211 if(!(Evaluator::mFunctionMap.IsFunction(name)) )
212 {
213 //cout <<"isfuncion"<< endl;
214 bool functionNotFound = true;
215
216 //Go through each library, searching for the function.
217 for(int library = 0; library < 6; library++)
218 {
219 switch(library)
220 {
221 case 0:
222 //********************Check the Math Library******************
223 functionTable = PEBLMath::FunctionTable;
224 break;
225
226 case 1:
227 //********************Check the Stream Library******************
228 functionTable = PEBLStream::FunctionTable;
229 break;
230
231 case 2:
232 //********************Check the Objects Library******************
233 functionTable = PEBLObjects::FunctionTable;
234 break;
235
236 case 3:
237 //********************Check the Environment Library******************
238 functionTable = PEBLEnvironment::FunctionTable;
239 break;
240
241 case 4:
242 //********************Check the List Library******************
243 functionTable = PEBLList::FunctionTable;
244 break;
245 case 5:
246 functionTable = PEBLString::FunctionTable;
247 break;
248 default:
249 PError::SignalFatalError("Library Not Found.");
250 }
251
252
253 int i = 0;
254
255 while (functionTable[i].name && functionNotFound)
256 {
257 //cout << "checking name:[" <<name<< "]"<<endl;
258 bool globalnamespace = true;
259 string name2 = name;
260 if(name[0]== ':')
261 {
262 name2=name.substr(1,name.length());
263 }
264 //cout << "checking name:[" <<name2<< "]"<<endl;
265 if(functionTable[i].name == name2)
266 {
267 //Its a match. Construct a top-level function node with pieces below it
268 //that can be processed appropriately by the Evaluator.
269
270 //The filename and linenumber are irrelevant; this is not tied directly
271 //to the source code.
272 string filename = "<PEBL STANDARD LIBRARY FILE>";
273 int linenum = -1;
274
275 //Make a DataNode with numargs to signal the number of arguments required by the function; connect
276 //them with an AND node.
277 PNode * node0a = new DataNode(Variant(functionTable[i].minNumArgs),filename, linenum);
278 PNode * node0b = new DataNode(Variant(functionTable[i].maxNumArgs),filename, linenum);
279 PNode * node0 = new OpNode(PEBL_AND, node0a, node0b,filename, linenum);
280
281 //Make a DataNode with a functionpointer variant in it.
282 PNode * node1 = new DataNode(functionTable[i].funcname,filename, linenum);
283
284
285 if(globalnamespace)
286 {
287 //if we call a :Function(), thise aren't
288 //declared specifically, but implicitly created on-demand at this point.
289
290 OpNode * node2 = new OpNode(PEBL_LIBRARYFUNCTION, node0, node1,filename, linenum);
291 Variant newname = name;
292 node2->SetFunctionName(newname);
294 // cout << "2\n";
295
296 }else{
297 //this is a normal function
298 // Make a new OpNode with the *NumArgs on the left and the function pointer on the right.
299 OpNode * node2 = new OpNode(PEBL_LIBRARYFUNCTION, node0, node1,filename, linenum);
300 node2->SetFunctionName(*p);
302 }
303
304
305 //Add a :Function version that will always be callable, because it can't be overwritteen
306 //with define(). This lets you override Draw() but call :Draw() inside it.
307
308 /*
309 node2 = new OpNode(PEBL_LIBRARYFUNCTION, node0, node1,filename, linenum);
310 Variant newname = Variant(":")+(*p);
311 node2->SetFunctionName(newname);
312 Evaluator::mFunctionMap.AddFunction(newname,node2);
313 cout << "2\n";
314 */
315
316 //break out of the while--we are done.
317 functionNotFound = false;
318 }
319
320 i++;
321 }
322 }
323
324
325 //At this point, if functionNotFound is still true, we are in trouble.
326
327
328 //If this happens, we should parse all .pbl files in pebl-lib,
329 //run FindFunctions on it, and try again.
330 if(functionNotFound == true)
331 {
332 string message = "Function [" ;
333 message += name;
334 message += "] not found in libraries or user-defined functions.";
336 std::cerr << "********>>>>>ERROR: " << message << std::endl;
337 std::cerr.flush();
338#ifdef PEBL_EMSCRIPTEN
339 EM_ASM({
340 console.error("MISSING FUNCTION: " + UTF8ToString($0));
341 }, message.c_str());
342#endif
344 }
345
346 }
347 else
348 {
349
350
351
352 //In this case, the named function WAS found in the functionmap.
353 }
354
355 //Move on to the next function to load.
356 p++;
357 }
358
359}
360
366{
367
368 return true;
369}
370
371
373{
374 // Get the main PEBL Function, returning it
375 // or 0 if it doesn't exist.
376 PNode * node = Evaluator::mFunctionMap.GetFunction("START");
377 if (node)
378 return node;
379 else
380 return 0;
381}
382
383
384
386{
387 //Get an iterator to the first item
388 std::set<Variant>::iterator p;
389 p=mFunctionSet.begin();
390
391 cerr << "\t-----------------------------------------------------------\n";
392 cerr << "\tPrinting all functions in mFunctionSet\n";
393 while(p != mFunctionSet.end())
394 {
395 cerr << "\t\tFunction: ["<< *p << "]\n";
396 p++;
397 }
398 cerr << "\t-----------------------------------------------------------\n";
399
400
401}
#define NULL
Definition BinReloc.cpp:317
@ PEBL_DATA_NODE
Definition PNode.h:36
@ P_DATA_FUNCTION
Definition Variant.h:43
static FunctionMap mFunctionMap
Initiate some static member data.
void DumpValues()
void AddFunction(std::string funcname, OpNode *node)
PNode * GetFunction(const std::string &funcname)
~Loader()
Definition Loader.cpp:74
void DumpFunctionSet()
Definition Loader.cpp:385
void LoadUserFunctions(OpNode *node)
Definition Loader.cpp:147
void LoadLibraryFunctions()
Definition Loader.cpp:195
void FindFunctions(const PNode *Node)
Definition Loader.cpp:88
Loader()
Definition Loader.cpp:69
bool Verify()
Definition Loader.cpp:365
PNode * GetMainPEBLFunction()
Definition Loader.cpp:372
PNode * GetRight() const
Definition PNode.h:115
int GetOp() const
Definition PNode.h:111
PNode * GetLeft() const
Definition PNode.h:114
Definition PNode.h:45
void SetFunctionName(const std::string &funcname)
Definition PNode.cpp:107
PNODE_TYPE GetType() const
Access mType data.
Definition PNode.h:61
PEBL_Function_Type FunctionTable[]
Definition Functions.h:297
PEBL_Function_Type FunctionTable[]
Definition Functions.h:420
PEBL_Function_Type FunctionTable[]
Definition Functions.h:51
PEBL_Function_Type FunctionTable[]
Definition Functions.h:207
PEBL_Function_Type FunctionTable[]
Definition Functions.h:123
PEBL_Function_Type FunctionTable[]
Definition Functions.h:461
std::string ToUpper(const std::string &text)
void SignalFatalError(const std::string &message)