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