1 /** \file lispenvironment.h
2 * General environment access.
3 *
4 */
5
6 #ifndef YACAS_LISPENVIRONMENT_H
7 #define YACAS_LISPENVIRONMENT_H
8
9 #include "lispobject.h"
10 #include "lisphash.h"
11 #include "lispevalhash.h"
12 #include "lispuserfunc.h"
13 #include "deffile.h"
14 #include "lisperror.h"
15 #include "lispio.h"
16 #include "stringio.h"
17 #include "lispglobals.h"
18 #include "lispoperator.h"
19 #include "xmltokenizer.h"
20 #include "errors.h"
21 #include "noncopyable.h"
22
23 #include <atomic>
24 #include <string>
25 #include <sstream>
26 #include <vector>
27 #include <deque>
28
29 #include <unordered_set>
30
31 typedef std::unordered_set<LispStringSmartPtr, std::hash<const LispString*> > LispIdentifiers;
32
33
34 class LispDefFiles;
35
36 class LispInput;
37 class LispOutput;
38 class LispPrinter;
39 class LispUserFunction;
40 class LispMultiUserFunction;
41 class LispEvaluatorBase;
42 class BasicEvaluator;
43 class DefaultDebugger;
44 class LispEnvironment;
45
46
47 /// The Lisp environment.
48 /// This huge class is the central class of the Yacas program. It
49 /// implements a dialect of Lisp.
50
51 class LispEnvironment: NonCopyable {
52 public:
53 /// \name Constructor and destructor
54 //@{
55 LispEnvironment(YacasCoreCommands &aCoreCommands,
56 LispUserFunctions& aUserFunctions,
57 LispGlobal& aGlobals,
58 LispHashTable& aHashTable,
59 std::ostream& aOutput,
60 LispPrinter& aPrinter,
61 LispOperators &aPreFixOperators,
62 LispOperators &aInFixOperators,
63 LispOperators &aPostFixOperators,
64 LispOperators &aBodiedOperators,
65 LispIdentifiers& protected_symbols,
66 LispInput* aCurrentInput);
67 ~LispEnvironment();
68 //@}
69
70 public:
71 /// \name Lisp variables
72 //@{
73
74 /// Assign a value to a Lisp variable.
75 /// \param aString name of the variable
76 /// \param aValue value to be assigned to \a aString
77 ///
78 /// If there is a local variable with the name \a aString, the
79 /// object \a aValue is assigned to it. Otherwise, a
80 /// LispGlobalVariable is constructed, and it is associated with
81 /// \a aValue in #iGlobals.
82 /// \sa FindLocal
83 void SetVariable(const LispString* aString, LispPtr& aValue, bool aGlobalLazyVariable);
84
85 /// Get the value assigned to a variable.
86 /// \param aVariable name of the variable
87 /// \param aResult (on exit) value of \a aVariable
88 ///
89 /// - If there is a local variable with the name \a aString,
90 /// \a aResult is set to point to the value assigned to this local
91 /// variable.
92 /// - If there is a global variable \a aString and its
93 /// #iEvalBeforeReturn is false, its value is returned via
94 /// \a aResult.
95 /// - If there is a global variable \a aString and its
96 /// #iEvalBeforeReturn is true, its value is evaluated. The
97 /// result is assigned back to the variable, its
98 /// #iEvalBeforeReturn is set to false, and a copy of the result
99 /// is returned in \a aResult.
100 /// - Otherwise, \a aResult is set to #nullptr.
101 void GetVariable(const LispString* aVariable, LispPtr& aResult);
102
103 void UnsetVariable(const LispString * aString);
104 void PushLocalFrame(bool aFenced);
105 void PopLocalFrame();
106 void NewLocal(const LispString* aVariable, LispObject* aValue);
107 void CurrentLocals(LispPtr& aResult);
108 void GlobalVariables(LispPtr& aResult);
109 //@}
110
111 public:
112 /// \name Lisp functions
113 //@{
114
115 /// Return the #iCoreCommands attribute.
116 const YacasCoreCommands& CoreCommands() const;
117 const LispUserFunctions& UserFunctions() const;
118
119 /// Add a command to the list of core commands.
120 /// \param aEvaluatorFunc C function evaluating the core command
121 /// \param aString name of the command
122 /// \param aNrArgs number of arguments
123 /// \param aFlags flags, see YacasEvaluator::FunctionFlags
124 void SetCommand(YacasEvalCaller aEvaluatorFunc, const char* aString,int aNrArgs,int aFlags);
125
126 void RemoveCoreCommand(char* aString);
127
128 inline LispHashTable& HashTable();
129 LispUserFunction* UserFunction(LispPtr& aArguments);
130 LispUserFunction* UserFunction(const LispString* aName,int aArity);
131
132 /// Return LispMultiUserFunction with given name.
133 /// \param aArguments name of the multi user function
134 ///
135 /// The table of user functions, #iUserFunctions, is consulted. If
136 /// a user function with the given name exists, it is returned.
137 /// Otherwise, a new LispMultiUserFunction is constructed, added
138 /// to #iUserFunctions, and returned.
139 LispMultiUserFunction* MultiUserFunction(const LispString* aArguments);
140
141 LispDefFiles& DefFiles();
142 void DeclareRuleBase(const LispString* aOperator, LispPtr& aParameters,
143 int aListed);
144 void DeclareMacroRuleBase(const LispString* aOperator, LispPtr& aParameters,
145 int aListed);
146 void DefineRule(const LispString* aOperator,int aArity,
147 int aPrecedence, LispPtr& aPredicate,
148 LispPtr& aBody);
149 void DefineRulePattern(const LispString* aOperator,int aArity,
150 int aPrecedence, LispPtr& aPredicate,
151 LispPtr& aBody);
152
153
154 void UnFenceRule(const LispString* aOperator,int aArity);
155 void Retract(const LispString* aOperator,int aArity);
156 void HoldArgument(const LispString* aOperator, const LispString* aVariable);
157
158 void Protect(const LispString*);
159 void UnProtect(const LispString*);
160 bool Protected(const LispString*) const;
161 //@}
162
163 public:
164 /// \name Precision
165 //@{
166
167 /// set precision to a given number of decimal digits
168 void SetPrecision(int aPrecision);
169 int Precision(void) const;
170 int BinaryPrecision(void) const;
171 //@}
172
173 public:
174 void SetPrettyPrinter(const LispString* aPrettyPrinter);
175 const LispString* PrettyPrinter();
176
177 void SetPrettyReader(const LispString* aPrettyReader);
178 const LispString* PrettyReader();
179
180 public:
181 int GetUniqueId();
182 public:
183 LispPrinter& CurrentPrinter();
184
185 public:
186 /// \name Operators
187 //@{
188 LispOperators& PreFix();
189 LispOperators& InFix();
190 LispOperators& PostFix();
191 LispOperators& Bodied();
192 //@}
193
194 public:
195 /// \name Input and output
196 //@{
197 LispInput* CurrentInput();
198 void SetCurrentInput(LispInput* aInput);
199 public:
200 std::ostream& CurrentOutput();
201 void SetCurrentOutput(std::ostream&);
202 //@}
203
204 protected:
205 /// current precision for user interaction, in decimal and in binary
206 int iPrecision;
207 int iBinaryPrecision;
208 public:
209 std::vector<std::string> iInputDirectories;
210 //DeletingLispCleanup iCleanup;
211 int iEvalDepth;
212 int iMaxEvalDepth;
213 #ifdef YACAS_NO_ATOMIC_TYPES
214 volatile bool
215 #else
216 std::atomic_bool
217 #endif // YACAS_NO_ATOMIC_TYPES
218 stop_evaluation;
219 LispEvaluatorBase* iEvaluator;
220
221 public: // Error information when some error occurs.
222 InputStatus iInputStatus;
223 bool secure;
224 public: // pre-found
225 RefPtr<LispObject> iTrue;
226 RefPtr<LispObject> iFalse;
227
228 RefPtr<LispObject> iEndOfFile;
229 RefPtr<LispObject> iEndStatement;
230 RefPtr<LispObject> iProgOpen;
231 RefPtr<LispObject> iProgClose;
232 RefPtr<LispObject> iNth;
233 RefPtr<LispObject> iBracketOpen;
234 RefPtr<LispObject> iBracketClose;
235 RefPtr<LispObject> iListOpen;
236 RefPtr<LispObject> iListClose;
237 RefPtr<LispObject> iComma;
238 RefPtr<LispObject> iList;
239 RefPtr<LispObject> iProg;
240
241 int iLastUniqueId;
242
243 public: // Error reporting
244 std::ostringstream iErrorOutput;
245 DefaultDebugger* iDebugger;
246
247 private:
248 LispPtr *FindLocal(const LispString * aVariable);
249
250 struct LispLocalVariable {
LispLocalVariableLispLocalVariable251 LispLocalVariable(const LispString* var, LispObject* val):
252 var(var), val(val)
253 {
254 }
255
256
257 LispStringSmartPtr var;
258 LispPtr val;
259 };
260
261 struct LocalVariableFrame {
LocalVariableFrameLocalVariableFrame262 LocalVariableFrame(std::size_t first, bool fenced):
263 first(first), fenced(fenced)
264 {
265 }
266
267 std::size_t first;
268 bool fenced;
269 };
270
271 std::vector<LispLocalVariable> _local_vars;
272 std::vector<LocalVariableFrame> _local_frames;
273
274 public:
275 std::ostream* iInitialOutput;
276
277 private:
278 /// Hash of core commands with associated YacasEvaluator
279 YacasCoreCommands& iCoreCommands;
280
281 LispUserFunctions& iUserFunctions;
282 LispHashTable& iHashTable;
283 LispDefFiles iDefFiles;
284 LispPrinter& iPrinter;
285 std::ostream* iCurrentOutput;
286
287 /// Hash of global variables with their values
288 LispGlobal& iGlobals;
289
290 LispOperators& iPreFixOperators;
291 LispOperators& iInFixOperators;
292 LispOperators& iPostFixOperators;
293 LispOperators& iBodiedOperators;
294
295 LispIdentifiers& protected_symbols;
296
297 LispInput* iCurrentInput;
298
299 const LispString* iPrettyReader;
300 const LispString* iPrettyPrinter;
301 public:
302 LispTokenizer iDefaultTokenizer;
303 XmlTokenizer iXmlTokenizer;
304 LispTokenizer* iCurrentTokenizer;
305
306 std::deque<LispPtr> iStack;
307 };
308
Precision(void)309 inline int LispEnvironment::Precision(void) const
310 {
311 return iPrecision;
312 }
313
BinaryPrecision(void)314 inline int LispEnvironment::BinaryPrecision(void) const
315 {
316 return iBinaryPrecision;
317 }
318
319
320
CoreCommands()321 inline const YacasCoreCommands& LispEnvironment::CoreCommands() const
322 {
323 return iCoreCommands;
324 }
325
UserFunctions()326 inline const LispUserFunctions& LispEnvironment::UserFunctions() const
327 {
328 return iUserFunctions;
329 }
330
HashTable()331 inline LispHashTable& LispEnvironment::HashTable()
332 {
333 return iHashTable;
334 }
335
336
337
338 // Local lisp stack, unwindable by the exception handler
339 class LispLocalFrame
340 {
341 public:
LispLocalFrame(LispEnvironment & aEnvironment,bool aFenced)342 LispLocalFrame(LispEnvironment& aEnvironment, bool aFenced)
343 : iEnvironment(aEnvironment)
344 {
345 iEnvironment.PushLocalFrame(aFenced);
346 };
347
~LispLocalFrame()348 virtual ~LispLocalFrame()
349 {
350 iEnvironment.PopLocalFrame();
351 };
352
353 private:
354 LispEnvironment& iEnvironment;
355 };
356
357
358
359 class LispSecureFrame
360 {
361 public:
LispSecureFrame(LispEnvironment & aEnvironment)362 LispSecureFrame(LispEnvironment& aEnvironment):
363 iEnvironment(aEnvironment), previous_secure(aEnvironment.secure)
364 {
365 iEnvironment.secure = true;
366 };
~LispSecureFrame()367 virtual ~LispSecureFrame()
368 {
369 iEnvironment.secure = previous_secure;
370 };
371 private:
372 LispEnvironment& iEnvironment;
373 bool previous_secure;
374 };
375
376
377 // LispLocalInput takes ownership over the LispInput class
378 class LispLocalInput: NonCopyable
379 {
380 public:
LispLocalInput(LispEnvironment & aEnvironment,LispInput * aInput)381 LispLocalInput(LispEnvironment& aEnvironment, LispInput* aInput)
382 : iEnvironment(aEnvironment),iPreviousInput(iEnvironment.CurrentInput())
383 {
384 iEnvironment.SetCurrentInput(aInput);
385 };
~LispLocalInput()386 virtual ~LispLocalInput()
387 {
388 iEnvironment.SetCurrentInput(iPreviousInput);
389 };
390
391 private:
392 LispEnvironment& iEnvironment;
393 LispInput* iPreviousInput;
394 };
395
396
397 // LispLocalInput takes ownership over the LispInput class
398 class LispLocalOutput: NonCopyable
399 {
400 public:
LispLocalOutput(LispEnvironment & aEnvironment,std::ostream & aOutput)401 LispLocalOutput(LispEnvironment& aEnvironment, std::ostream& aOutput)
402 : iEnvironment(aEnvironment), iPreviousOutput(&iEnvironment.CurrentOutput())
403 {
404 iEnvironment.SetCurrentOutput(aOutput);
405 };
~LispLocalOutput()406 virtual ~LispLocalOutput()
407 {
408 iEnvironment.SetCurrentOutput(*iPreviousOutput);
409 };
410
411 private:
412 LispEnvironment& iEnvironment;
413 std::ostream* iPreviousOutput;
414 };
415
416 class LispLocalEvaluator: NonCopyable
417 {
418 public:
419 LispLocalEvaluator(LispEnvironment& aEnvironment,LispEvaluatorBase* aNewEvaluator);
420 ~LispLocalEvaluator();
421
422 private:
423 LispEvaluatorBase* iPreviousEvaluator;
424 LispEnvironment& iEnvironment;
425 };
426
427 class LispLocalTrace: NonCopyable
428 {
429 public:
430 LispLocalTrace(LispUserFunction* aUserFunc);
431 ~LispLocalTrace();
432 private:
433 LispUserFunction* iUserFunc;
434 };
435
SetPrettyReader(const LispString * aPrettyReader)436 inline void LispEnvironment::SetPrettyReader(const LispString* aPrettyReader)
437 {
438 iPrettyReader = aPrettyReader;
439 }
PrettyReader()440 inline const LispString* LispEnvironment::PrettyReader()
441 {
442 return iPrettyReader;
443 }
444
SetPrettyPrinter(const LispString * aPrettyPrinter)445 inline void LispEnvironment::SetPrettyPrinter(const LispString * aPrettyPrinter)
446 {
447 iPrettyPrinter = aPrettyPrinter;
448 }
PrettyPrinter()449 inline const LispString* LispEnvironment::PrettyPrinter()
450 {
451 return iPrettyPrinter;
452 }
453
454
455 #endif
456