1 
2 #include "yacas/arggetter.h"
3 #include "yacas/arrayclass.h"
4 #include "yacas/associationclass.h"
5 #include "yacas/errors.h"
6 #include "yacas/infixparser.h"
7 #include "yacas/lispatom.h"
8 #include "yacas/lispenvironment.h"
9 #include "yacas/lisperror.h"
10 #include "yacas/lispeval.h"
11 #include "yacas/lispparser.h"
12 #include "yacas/lispuserfunc.h"
13 #include "yacas/mathuserfunc.h"
14 #include "yacas/numbers.h"
15 #include "yacas/patternclass.h"
16 #include "yacas/platfileio.h"
17 #include "yacas/platmath.h"
18 #include "yacas/standard.h"
19 #include "yacas/string_utils.h"
20 #include "yacas/stringio.h"
21 #include "yacas/substitute.h"
22 
23 #include <cstring>
24 #include <limits.h>
25 #include <sstream>
26 #include <stdlib.h>
27 #include <string>
28 
29 #ifdef _WIN32
30 #    include <windows.h>
31 #else
32 #    include <unistd.h>
33 #endif
34 
35 #define InternalEval aEnvironment.iEvaluator->Eval
36 #define RESULT aEnvironment.iStack[aStackTop]
37 #define ARGUMENT(i) aEnvironment.iStack[aStackTop + i]
38 
39 void LispLexCompare2(LispEnvironment& aEnvironment,
40                      int aStackTop,
41                      bool (*lexfunc)(const char* f1,
42                                      const char* f2,
43                                      LispHashTable& aHashTable,
44                                      int aPrecision),
45                      bool (*numfunc)(BigNumber& n1, BigNumber& n2));
46 
LispQuote(LispEnvironment & aEnvironment,int aStackTop)47 void LispQuote(LispEnvironment& aEnvironment, int aStackTop)
48 {
49     RESULT = (ARGUMENT(1)->Copy());
50 }
51 
LispEval(LispEnvironment & aEnvironment,int aStackTop)52 void LispEval(LispEnvironment& aEnvironment, int aStackTop)
53 {
54     InternalEval(aEnvironment, RESULT, ARGUMENT(1));
55 }
56 
57 /// Execute the Yacas commands \c Set and \c MacroSet.
58 /// The argument \a aMacroMode determines whether the first argument
59 /// should be evaluated. The real work is done by
60 /// LispEnvironment::SetVariable() .
61 /// \sa LispSetVar(), LispMacroSetVar()
InternalSetVar(LispEnvironment & aEnvironment,int aStackTop,bool aMacroMode,bool aGlobalLazyVariable)62 static void InternalSetVar(LispEnvironment& aEnvironment,
63                            int aStackTop,
64                            bool aMacroMode,
65                            bool aGlobalLazyVariable)
66 {
67     const LispString* varstring = nullptr;
68     if (aMacroMode) {
69         LispPtr result;
70         InternalEval(aEnvironment, result, ARGUMENT(1));
71         varstring = result->String();
72     } else {
73         varstring = ARGUMENT(1)->String();
74     }
75     CheckArg(varstring, 1, aEnvironment, aStackTop);
76     CheckArg(!IsNumber(*varstring, true), 1, aEnvironment, aStackTop);
77 
78     LispPtr result;
79     InternalEval(aEnvironment, result, ARGUMENT(2));
80     aEnvironment.SetVariable(varstring, result, aGlobalLazyVariable);
81     InternalTrue(aEnvironment, RESULT);
82 }
83 
84 /// Corresponds to the Yacas function \c Set.
85 /// This function simply calls InternalSetVar() .
LispSetVar(LispEnvironment & aEnvironment,int aStackTop)86 void LispSetVar(LispEnvironment& aEnvironment, int aStackTop)
87 {
88     InternalSetVar(aEnvironment, aStackTop, false, false);
89 }
90 
91 /// Corresponds to the Yacas function \c MacroSet.
92 /// This function simply calls InternalSetVar() .
LispMacroSetVar(LispEnvironment & aEnvironment,int aStackTop)93 void LispMacroSetVar(LispEnvironment& aEnvironment, int aStackTop)
94 {
95     InternalSetVar(aEnvironment, aStackTop, true, false);
96 }
97 
LispSetGlobalLazyVariable(LispEnvironment & aEnvironment,int aStackTop)98 void LispSetGlobalLazyVariable(LispEnvironment& aEnvironment, int aStackTop)
99 {
100     InternalSetVar(aEnvironment, aStackTop, false, true);
101 }
102 
LispClearVar(LispEnvironment & aEnvironment,int aStackTop)103 void LispClearVar(LispEnvironment& aEnvironment, int aStackTop)
104 {
105     LispPtr* subList = ARGUMENT(1)->SubList();
106     if (subList) {
107         LispIterator iter(*subList);
108         for (int nr = 1; (++iter).getObj(); nr++) {
109             const LispString* str = iter.getObj()->String();
110             CheckArg(str, nr, aEnvironment, aStackTop);
111             aEnvironment.UnsetVariable(str);
112         }
113     }
114     InternalTrue(aEnvironment, RESULT);
115 }
116 
LispVars(LispEnvironment & aEnvironment,int aStackTop)117 void LispVars(LispEnvironment& aEnvironment, int aStackTop)
118 {
119     LispPtr vars;
120     aEnvironment.GlobalVariables(vars);
121     RESULT = vars;
122 }
123 
124 /* StrCompare returns f1-f2: if f1 < f2 it returns -1, if f1=f2 it
125  returns 0, and it returns 1 if f1>f2
126  */
127 // the aPrecision argument is ignored here
LexLessThan(const char * f1,const char * f2,LispHashTable & aHashTable,int aPrecision)128 static bool LexLessThan(const char* f1,
129                         const char* f2,
130                         LispHashTable& aHashTable,
131                         int aPrecision)
132 {
133     return (std::strcmp(f1, f2) < 0);
134 }
135 
136 // the aPrecision argument is ignored here
LexGreaterThan(const char * f1,const char * f2,LispHashTable & aHashTable,int aPrecision)137 static bool LexGreaterThan(const char* f1,
138                            const char* f2,
139                            LispHashTable& aHashTable,
140                            int aPrecision)
141 {
142     return (std::strcmp(f1, f2) > 0);
143 }
144 
BigLessThan(BigNumber & n1,BigNumber & n2)145 static bool BigLessThan(BigNumber& n1, BigNumber& n2)
146 {
147     return n1.LessThan(n2) && !n1.Equals(n2);
148 }
BigGreaterThan(BigNumber & n1,BigNumber & n2)149 static bool BigGreaterThan(BigNumber& n1, BigNumber& n2)
150 {
151     return !(n1.LessThan(n2) || n1.Equals(n2));
152 }
153 
LispStrictTotalOrder(LispEnvironment & aEnvironment,int aStackTop)154 void LispStrictTotalOrder(LispEnvironment& aEnvironment, int aStackTop)
155 {
156     LispPtr e1(ARGUMENT(1));
157     LispPtr e2(ARGUMENT(2));
158 
159     InternalBoolean(
160         aEnvironment, RESULT, InternalStrictTotalOrder(aEnvironment, e1, e2));
161 }
162 
LispLessThan(LispEnvironment & aEnvironment,int aStackTop)163 void LispLessThan(LispEnvironment& aEnvironment, int aStackTop)
164 {
165     LispLexCompare2(aEnvironment, aStackTop, LexLessThan, BigLessThan);
166 }
167 
LispGreaterThan(LispEnvironment & aEnvironment,int aStackTop)168 void LispGreaterThan(LispEnvironment& aEnvironment, int aStackTop)
169 {
170     LispLexCompare2(aEnvironment, aStackTop, LexGreaterThan, BigGreaterThan);
171 }
172 
LispLexCompare2(LispEnvironment & aEnvironment,int aStackTop,bool (* lexfunc)(const char * f1,const char * f2,LispHashTable & aHashTable,int aPrecision),bool (* numfunc)(BigNumber & n1,BigNumber & n2))173 void LispLexCompare2(LispEnvironment& aEnvironment,
174                      int aStackTop,
175                      bool (*lexfunc)(const char* f1,
176                                      const char* f2,
177                                      LispHashTable& aHashTable,
178                                      int aPrecision),
179                      bool (*numfunc)(BigNumber& n1, BigNumber& n2))
180 {
181     LispPtr result1(ARGUMENT(1));
182     LispPtr result2(ARGUMENT(2));
183     bool cmp;
184     BigNumber* n1 = result1->Number(aEnvironment.Precision());
185     BigNumber* n2 = result2->Number(aEnvironment.Precision());
186     if (n1 && n2) {
187         cmp = numfunc(*n1, *n2);
188     } else {
189         const LispString* str1 = result1->String();
190         const LispString* str2 = result2->String();
191         CheckArg(str1, 1, aEnvironment, aStackTop);
192         CheckArg(str2, 2, aEnvironment, aStackTop);
193         // the precision argument is ignored in "lex" functions
194         cmp = lexfunc(str1->c_str(),
195                       str2->c_str(),
196                       aEnvironment.HashTable(),
197                       aEnvironment.Precision());
198     }
199 
200     InternalBoolean(aEnvironment, RESULT, cmp);
201 }
202 
LispFullForm(LispEnvironment & aEnvironment,int aStackTop)203 void LispFullForm(LispEnvironment& aEnvironment, int aStackTop)
204 {
205     RESULT = (ARGUMENT(1));
206     LispPrinter printer;
207     printer.Print(RESULT, aEnvironment.CurrentOutput(), aEnvironment);
208     aEnvironment.CurrentOutput().put('\n');
209 }
210 
LispHead(LispEnvironment & aEnvironment,int aStackTop)211 void LispHead(LispEnvironment& aEnvironment, int aStackTop)
212 {
213     InternalNth(RESULT, ARGUMENT(1), 1);
214 }
215 
LispNth(LispEnvironment & aEnvironment,int aStackTop)216 void LispNth(LispEnvironment& aEnvironment, int aStackTop)
217 {
218     const LispString* str = ARGUMENT(2)->String();
219     CheckArg(str, 2, aEnvironment, aStackTop);
220     CheckArg(IsNumber(str->c_str(), false), 2, aEnvironment, aStackTop);
221     int index = InternalAsciiToInt(*str);
222     InternalNth(RESULT, ARGUMENT(1), index);
223 }
224 
LispTail(LispEnvironment & aEnvironment,int aStackTop)225 void LispTail(LispEnvironment& aEnvironment, int aStackTop)
226 {
227     LispPtr first;
228     InternalTail(first, ARGUMENT(1));
229     InternalTail(RESULT, first);
230     LispPtr head(aEnvironment.iList->Copy());
231     head->Nixed() = ((*RESULT->SubList()));
232     (*RESULT->SubList()) = (head);
233 }
234 
LispUnList(LispEnvironment & aEnvironment,int aStackTop)235 void LispUnList(LispEnvironment& aEnvironment, int aStackTop)
236 {
237     CheckArg(ARGUMENT(1), 1, aEnvironment, aStackTop);
238     CheckArg(ARGUMENT(1)->SubList(), 1, aEnvironment, aStackTop);
239     LispObject* subList = (*ARGUMENT(1)->SubList());
240     CheckArg(subList, 1, aEnvironment, aStackTop);
241     CheckArg(subList->String() == aEnvironment.iList->String(),
242              1,
243              aEnvironment,
244              aStackTop);
245     InternalTail(RESULT, ARGUMENT(1));
246 }
247 
LispListify(LispEnvironment & aEnvironment,int aStackTop)248 void LispListify(LispEnvironment& aEnvironment, int aStackTop)
249 {
250     CheckArg(ARGUMENT(1)->SubList(), 1, aEnvironment, aStackTop);
251     LispPtr head(aEnvironment.iList->Copy());
252     head->Nixed() = ((*ARGUMENT(1)->SubList()));
253     RESULT = (LispSubList::New(head));
254 }
255 
LispDestructiveReverse(LispEnvironment & aEnvironment,int aStackTop)256 void LispDestructiveReverse(LispEnvironment& aEnvironment, int aStackTop)
257 {
258     CheckArgIsList(1, aEnvironment, aStackTop);
259 
260     LispPtr reversed(aEnvironment.iList->Copy());
261     InternalReverseList(reversed->Nixed(), (*ARGUMENT(1)->SubList())->Nixed());
262     RESULT = (LispSubList::New(reversed));
263 }
264 
LispLength(LispEnvironment & aEnvironment,int aStackTop)265 void LispLength(LispEnvironment& aEnvironment, int aStackTop)
266 {
267     std::size_t size = 0;
268 
269     if (LispPtr* subList = ARGUMENT(1)->SubList()) {
270         size = InternalListLength((*subList)->Nixed());
271     } else if (InternalIsString(ARGUMENT(1)->String())) {
272         size = ARGUMENT(1)->String()->size() - 2;
273     } else if (ArrayClass* arr =
274                    dynamic_cast<ArrayClass*>(ARGUMENT(1)->Generic())) {
275         size = arr->Size();
276     } else if (AssociationClass* assoc =
277                    dynamic_cast<AssociationClass*>(ARGUMENT(1)->Generic())) {
278         size = assoc->Size();
279     } else
280         CheckArg(false, 1, aEnvironment, aStackTop);
281 
282     RESULT = LispAtom::New(aEnvironment, std::to_string(size));
283 }
284 
LispList(LispEnvironment & aEnvironment,int aStackTop)285 void LispList(LispEnvironment& aEnvironment, int aStackTop)
286 {
287     LispPtr all(aEnvironment.iList->Copy());
288     LispIterator tail(all);
289     ++tail;
290     LispIterator iter(*ARGUMENT(1)->SubList());
291     while ((++iter).getObj()) {
292         LispPtr evaluated;
293         InternalEval(aEnvironment, evaluated, *iter);
294         // Ideally this would work, but it does not yet: (*tail++) = (evaluated)
295         (*tail) = (evaluated);
296         ++tail;
297     }
298     RESULT = (LispSubList::New(all));
299 }
300 
LispConcatenate(LispEnvironment & aEnvironment,int aStackTop)301 void LispConcatenate(LispEnvironment& aEnvironment, int aStackTop)
302 {
303     LispPtr all(aEnvironment.iList->Copy());
304     LispIterator tail(all);
305     ++tail;
306     LispIterator iter(*ARGUMENT(1)->SubList());
307     for (int arg = 1; (++iter).getObj(); arg++) {
308         CheckArgIsList(*iter, arg, aEnvironment, aStackTop);
309         InternalFlatCopy(
310             *tail,
311             (*(*iter)->SubList())->Nixed()); // TODO: woof -- prefer below
312         // InternalFlatCopy(*tail,iter.getObj()->Nixed());
313         while (tail.getObj())
314             ++tail;
315     }
316     RESULT = (LispSubList::New(all));
317 }
318 
LispConcatenateStrings(LispEnvironment & aEnvironment,int aStackTop)319 void LispConcatenateStrings(LispEnvironment& aEnvironment, int aStackTop)
320 {
321     std::string s;
322     s.push_back('\"');
323 
324     int arg = 1;
325     for (LispIterator iter(*ARGUMENT(1)->SubList()); (++iter).getObj();) {
326         CheckArgIsString(*iter, arg++, aEnvironment, aStackTop);
327         const std::string& p = *iter.getObj()->String();
328         s.append(p.substr(1, p.size() - 2));
329     }
330     s.push_back('\"');
331 
332     RESULT = LispAtom::New(aEnvironment, s);
333 }
334 
335 static void
InternalDelete(LispEnvironment & aEnvironment,int aStackTop,int aDestructive)336 InternalDelete(LispEnvironment& aEnvironment, int aStackTop, int aDestructive)
337 {
338     LispPtr evaluated(ARGUMENT(1));
339     CheckArgIsList(1, aEnvironment, aStackTop);
340 
341     LispPtr copied;
342     if (aDestructive) {
343         copied = ((*evaluated->SubList()));
344     } else {
345         InternalFlatCopy(copied, *evaluated->SubList());
346     }
347 
348     LispPtr index(ARGUMENT(2));
349     CheckArg(index, 2, aEnvironment, aStackTop);
350     CheckArg(index->String(), 2, aEnvironment, aStackTop);
351     int ind = InternalAsciiToInt(*index->String());
352     CheckArg(ind > 0, 2, aEnvironment, aStackTop);
353 
354     LispIterator iter(copied);
355     while (--ind >= 0)
356         ++iter;
357     if (!iter.getObj()) {
358         ShowStack(aEnvironment);
359         throw LispErrListNotLongEnough();
360     }
361     LispIterator temp = iter++;
362     (*temp) = (*iter);
363     RESULT = (LispSubList::New(copied));
364 }
365 
LispDelete(LispEnvironment & aEnvironment,int aStackTop)366 void LispDelete(LispEnvironment& aEnvironment, int aStackTop)
367 {
368     InternalDelete(aEnvironment, aStackTop, false);
369 }
370 
LispDestructiveDelete(LispEnvironment & aEnvironment,int aStackTop)371 void LispDestructiveDelete(LispEnvironment& aEnvironment, int aStackTop)
372 {
373     InternalDelete(aEnvironment, aStackTop, true);
374 }
375 
LispFlatCopy(LispEnvironment & aEnvironment,int aStackTop)376 void LispFlatCopy(LispEnvironment& aEnvironment, int aStackTop)
377 {
378     LispPtr copied;
379 
380     if (ARGUMENT(1)->SubList() == nullptr)
381         CheckArgIsList(1, aEnvironment, aStackTop);
382 
383     InternalFlatCopy(copied, *ARGUMENT(1)->SubList());
384     RESULT = (LispSubList::New(copied));
385 }
386 
387 static void
InternalInsert(LispEnvironment & aEnvironment,int aStackTop,int aDestructive)388 InternalInsert(LispEnvironment& aEnvironment, int aStackTop, int aDestructive)
389 {
390     CheckArgIsList(1, aEnvironment, aStackTop);
391 
392     LispPtr evaluated(ARGUMENT(1));
393 
394     LispPtr copied;
395     if (aDestructive) {
396         copied = ((*evaluated->SubList()));
397     } else {
398         InternalFlatCopy(copied, *evaluated->SubList());
399     }
400 
401     LispPtr index(ARGUMENT(2));
402     CheckArg(index, 2, aEnvironment, aStackTop);
403     CheckArg(index->String(), 2, aEnvironment, aStackTop);
404     int ind = InternalAsciiToInt(*index->String());
405     CheckArg(ind > 0, 2, aEnvironment, aStackTop);
406 
407     LispIterator iter(copied);
408     while (--ind >= 0)
409         ++iter;
410     LispPtr toInsert(ARGUMENT(3));
411     toInsert->Nixed() = (iter.getObj());
412     (*iter) = (toInsert);
413     RESULT = (LispSubList::New(copied));
414 }
415 
LispInsert(LispEnvironment & aEnvironment,int aStackTop)416 void LispInsert(LispEnvironment& aEnvironment, int aStackTop)
417 {
418     InternalInsert(aEnvironment, aStackTop, false);
419 }
420 
LispDestructiveInsert(LispEnvironment & aEnvironment,int aStackTop)421 void LispDestructiveInsert(LispEnvironment& aEnvironment, int aStackTop)
422 {
423     InternalInsert(aEnvironment, aStackTop, true);
424 }
425 
426 static void
InternalReplace(LispEnvironment & aEnvironment,int aStackTop,int aDestructive)427 InternalReplace(LispEnvironment& aEnvironment, int aStackTop, int aDestructive)
428 {
429     LispPtr evaluated(ARGUMENT(1));
430     //    CHK_ISLIST_CORE(evaluated,1);
431     // Ok, so lets not check if it is a list, but it needs to be at least a
432     // 'function'
433     CheckArg(evaluated->SubList(), 1, aEnvironment, aStackTop);
434 
435     LispPtr index(ARGUMENT(2));
436     CheckArg(index, 2, aEnvironment, aStackTop);
437     CheckArg(index->String(), 2, aEnvironment, aStackTop);
438     int ind = InternalAsciiToInt(*index->String());
439 
440     LispPtr copied;
441     if (aDestructive) {
442         copied = ((*evaluated->SubList()));
443     } else {
444         InternalFlatCopy(copied, *evaluated->SubList());
445     }
446     CheckArg(ind > 0, 2, aEnvironment, aStackTop);
447 
448     LispIterator iter(copied);
449     while (--ind >= 0)
450         ++iter;
451     LispPtr toInsert(ARGUMENT(3));
452     CheckArg(iter.getObj(), 2, aEnvironment, aStackTop);
453 
454     LispIterator temp = iter++;
455     toInsert->Nixed() = (*iter);
456     (*temp) = (toInsert);
457     RESULT = (LispSubList::New(copied));
458 }
459 
LispReplace(LispEnvironment & aEnvironment,int aStackTop)460 void LispReplace(LispEnvironment& aEnvironment, int aStackTop)
461 {
462     InternalReplace(aEnvironment, aStackTop, false);
463 }
464 
LispDestructiveReplace(LispEnvironment & aEnvironment,int aStackTop)465 void LispDestructiveReplace(LispEnvironment& aEnvironment, int aStackTop)
466 {
467     InternalReplace(aEnvironment, aStackTop, true);
468 }
469 
LispNot(LispEnvironment & aEnvironment,int aStackTop)470 void LispNot(LispEnvironment& aEnvironment, int aStackTop)
471 {
472     LispPtr evaluated(ARGUMENT(1));
473     if (IsTrue(aEnvironment, evaluated) || IsFalse(aEnvironment, evaluated)) {
474         InternalNot(RESULT, aEnvironment, evaluated);
475     } else {
476         LispPtr ptr(ARGUMENT(0)->Copy());
477         ptr->Nixed() = (evaluated);
478         RESULT = (LispSubList::New(ptr));
479     }
480 }
481 
LispLazyAnd(LispEnvironment & aEnvironment,int aStackTop)482 void LispLazyAnd(LispEnvironment& aEnvironment, int aStackTop)
483 {
484     LispPtr nogos;
485     int nrnogos = 0;
486     LispPtr evaluated;
487 
488     LispIterator iter(*ARGUMENT(1)->SubList());
489     while ((++iter).getObj()) {
490         InternalEval(aEnvironment, evaluated, *iter);
491         if (IsFalse(aEnvironment, evaluated)) {
492             InternalFalse(aEnvironment, RESULT);
493             return;
494         } else if (!IsTrue(aEnvironment, evaluated)) {
495             nrnogos++;
496             LispPtr ptr(evaluated->Copy());
497             ptr->Nixed() = (nogos);
498             nogos = (ptr);
499         }
500     }
501 
502     if (!!nogos) {
503         if (nrnogos == 1) {
504             RESULT = (nogos);
505         } else {
506             LispPtr ptr;
507             InternalReverseList(ptr, nogos);
508             nogos = (ptr);
509 
510             ptr = (ARGUMENT(0)->Copy());
511             ptr->Nixed() = (nogos);
512             nogos = (ptr);
513             RESULT = (LispSubList::New(nogos));
514             // aEnvironment.CurrentPrinter().Print(RESULT,
515             // *aEnvironment.CurrentOutput());
516         }
517     } else {
518         InternalTrue(aEnvironment, RESULT);
519     }
520 }
521 
LispLazyOr(LispEnvironment & aEnvironment,int aStackTop)522 void LispLazyOr(LispEnvironment& aEnvironment, int aStackTop)
523 {
524     LispPtr nogos;
525     int nrnogos = 0;
526 
527     LispPtr evaluated;
528 
529     LispIterator iter(*ARGUMENT(1)->SubList());
530     while ((++iter).getObj()) {
531         InternalEval(aEnvironment, evaluated, *iter);
532         if (IsTrue(aEnvironment, evaluated)) {
533             InternalTrue(aEnvironment, RESULT);
534             return;
535         } else if (!IsFalse(aEnvironment, evaluated)) {
536             nrnogos++;
537             LispPtr ptr(evaluated->Copy());
538             ptr->Nixed() = (nogos);
539             nogos = (ptr);
540         }
541     }
542 
543     if (!!nogos) {
544         if (nrnogos == 1) {
545             RESULT = (nogos);
546         } else {
547             LispPtr ptr;
548             InternalReverseList(ptr, nogos);
549             nogos = (ptr);
550 
551             ptr = (ARGUMENT(0)->Copy());
552             ptr->Nixed() = (nogos);
553             nogos = (ptr);
554             RESULT = (LispSubList::New(nogos));
555         }
556         // aEnvironment.CurrentPrinter().Print(RESULT,
557         // *aEnvironment.CurrentOutput());
558     } else {
559         InternalFalse(aEnvironment, RESULT);
560     }
561 }
562 
LispEquals(LispEnvironment & aEnvironment,int aStackTop)563 void LispEquals(LispEnvironment& aEnvironment, int aStackTop)
564 {
565     LispPtr evaluated1(ARGUMENT(1));
566     LispPtr evaluated2(ARGUMENT(2));
567 
568     InternalBoolean(aEnvironment,
569                     RESULT,
570                     InternalEquals(aEnvironment, evaluated1, evaluated2));
571 }
572 
LispWrite(LispEnvironment & aEnvironment,int aStackTop)573 void LispWrite(LispEnvironment& aEnvironment, int aStackTop)
574 {
575     LispPtr* subList = ARGUMENT(1)->SubList();
576     if (subList) {
577         LispIterator iter(*subList);
578         while ((++iter).getObj()) {
579             aEnvironment.CurrentPrinter().Print(
580                 *iter, aEnvironment.CurrentOutput(), aEnvironment);
581         }
582     }
583     InternalTrue(aEnvironment, RESULT);
584 }
585 
LispWriteString(LispEnvironment & aEnvironment,int aStackTop)586 void LispWriteString(LispEnvironment& aEnvironment, int aStackTop)
587 {
588     CheckArg(ARGUMENT(1), 1, aEnvironment, aStackTop);
589     const LispString* str = ARGUMENT(1)->String();
590     CheckArg(str, 1, aEnvironment, aStackTop);
591     CheckArg((*str)[0] == '\"', 1, aEnvironment, aStackTop);
592     CheckArg((*str)[str->size() - 1] == '\"', 1, aEnvironment, aStackTop);
593 
594     const std::size_t nr = str->size() - 1;
595     //((*str)[i] != '\"')
596     for (std::size_t i = 1; i < nr; ++i)
597         aEnvironment.CurrentOutput().put((*str)[i]);
598 
599     // pass last printed character to the current printer
600     aEnvironment.CurrentPrinter().RememberLastChar(
601         (*str)[nr - 1]); // hacky hacky
602     InternalTrue(aEnvironment, RESULT);
603 }
604 
LispProgBody(LispEnvironment & aEnvironment,int aStackTop)605 void LispProgBody(LispEnvironment& aEnvironment, int aStackTop)
606 {
607     // Allow accessing previous locals.
608     LispLocalFrame frame(aEnvironment, false);
609 
610     InternalTrue(aEnvironment, RESULT);
611 
612     // Evaluate args one by one.
613 
614     LispIterator iter(*ARGUMENT(1)->SubList());
615     while ((++iter).getObj()) {
616         InternalEval(aEnvironment, RESULT, *iter);
617     }
618 }
619 
LispNewLocal(LispEnvironment & aEnvironment,int aStackTop)620 void LispNewLocal(LispEnvironment& aEnvironment, int aStackTop)
621 {
622     LispPtr* subList = ARGUMENT(1)->SubList();
623     if (subList) {
624         LispIterator iter(*subList);
625         for (int nr = 1; (++iter).getObj(); nr++) {
626             const LispString* variable = iter.getObj()->String();
627             CheckArg(variable, nr, aEnvironment, aStackTop);
628             // printf("Variable %s\n",variable->String());
629             aEnvironment.NewLocal(variable, nullptr);
630         }
631     }
632     InternalTrue(aEnvironment, RESULT);
633 }
634 
LispWhile(LispEnvironment & aEnvironment,int aStackTop)635 void LispWhile(LispEnvironment& aEnvironment, int aStackTop)
636 {
637     LispPtr& arg1 = ARGUMENT(1);
638     LispPtr& arg2 = ARGUMENT(2);
639 
640     LispPtr predicate;
641     InternalEval(aEnvironment, predicate, arg1);
642 
643     while (IsTrue(aEnvironment, predicate)) {
644         LispPtr evaluated;
645         InternalEval(aEnvironment, evaluated, arg2);
646         InternalEval(aEnvironment, predicate, arg1);
647     }
648     CheckArg(IsFalse(aEnvironment, predicate), 1, aEnvironment, aStackTop);
649     InternalTrue(aEnvironment, RESULT);
650 }
651 
652 static void
MultiFix(LispEnvironment & aEnvironment,int aStackTop,LispOperators & aOps)653 MultiFix(LispEnvironment& aEnvironment, int aStackTop, LispOperators& aOps)
654 {
655 
656     // Get operator
657     CheckArg(ARGUMENT(1), 1, aEnvironment, aStackTop);
658     const LispString* orig = ARGUMENT(1)->String();
659     CheckArg(orig, 1, aEnvironment, aStackTop);
660 
661     LispPtr precedence;
662     InternalEval(aEnvironment, precedence, ARGUMENT(2));
663     CheckArg(precedence->String(), 2, aEnvironment, aStackTop);
664     int prec = InternalAsciiToInt(*precedence->String());
665     CheckArg(prec <= KMaxPrecedence, 2, aEnvironment, aStackTop);
666     aOps[SymbolName(aEnvironment, *orig)] = LispInFixOperator(prec);
667     InternalTrue(aEnvironment, RESULT);
668 }
669 
LispInFix(LispEnvironment & aEnvironment,int aStackTop)670 void LispInFix(LispEnvironment& aEnvironment, int aStackTop)
671 {
672     MultiFix(aEnvironment, aStackTop, aEnvironment.InFix());
673 }
674 
SingleFix(int aPrecedence,LispEnvironment & aEnvironment,int aStackTop,LispOperators & aOps)675 static void SingleFix(int aPrecedence,
676                       LispEnvironment& aEnvironment,
677                       int aStackTop,
678                       LispOperators& aOps)
679 {
680     // Get operator
681     CheckArg(ARGUMENT(1), 1, aEnvironment, aStackTop);
682     const LispString* orig = ARGUMENT(1)->String();
683     CheckArg(orig, 1, aEnvironment, aStackTop);
684     aOps[SymbolName(aEnvironment, *orig)] = LispInFixOperator(aPrecedence);
685     InternalTrue(aEnvironment, RESULT);
686 }
687 
LispPreFix(LispEnvironment & aEnvironment,int aStackTop)688 void LispPreFix(LispEnvironment& aEnvironment, int aStackTop)
689 {
690     /*
691         int nrArguments = InternalListLength(ARGUMENT(0));
692         if (nrArguments == 2)
693         {
694             SingleFix(0, aEnvironment, aStackTop, aEnvironment.PreFix());
695         }
696         else
697     */
698     {
699         MultiFix(aEnvironment, aStackTop, aEnvironment.PreFix());
700     }
701 }
702 
LispPostFix(LispEnvironment & aEnvironment,int aStackTop)703 void LispPostFix(LispEnvironment& aEnvironment, int aStackTop)
704 {
705     const std::size_t nrArguments = InternalListLength(ARGUMENT(0));
706     if (nrArguments == 2)
707         SingleFix(0, aEnvironment, aStackTop, aEnvironment.PostFix());
708     else
709         MultiFix(aEnvironment, aStackTop, aEnvironment.PostFix());
710 }
711 
LispBodied(LispEnvironment & aEnvironment,int aStackTop)712 void LispBodied(LispEnvironment& aEnvironment, int aStackTop)
713 {
714     MultiFix(aEnvironment, aStackTop, aEnvironment.Bodied());
715 }
716 
LispAtomize(LispEnvironment & aEnvironment,int aStackTop)717 void LispAtomize(LispEnvironment& aEnvironment, int aStackTop)
718 {
719     LispPtr evaluated(ARGUMENT(1));
720 
721     // Get operator
722     CheckArg(evaluated, 1, aEnvironment, aStackTop);
723     const LispString* orig = evaluated->String();
724     CheckArg(orig, 1, aEnvironment, aStackTop);
725     RESULT = LispAtom::New(aEnvironment, orig->substr(1, orig->length() - 2));
726 }
727 
LispStringify(LispEnvironment & aEnvironment,int aStackTop)728 void LispStringify(LispEnvironment& aEnvironment, int aStackTop)
729 {
730     LispPtr evaluated(ARGUMENT(1));
731 
732     // Get operator
733     CheckArg(evaluated, 1, aEnvironment, aStackTop);
734     const LispString* orig = evaluated->String();
735     CheckArg(orig, 1, aEnvironment, aStackTop);
736 
737     RESULT = LispAtom::New(aEnvironment, stringify(*orig));
738 }
739 
LispLoad(LispEnvironment & aEnvironment,int aStackTop)740 void LispLoad(LispEnvironment& aEnvironment, int aStackTop)
741 {
742     CheckSecure(aEnvironment, aStackTop);
743 
744     LispPtr evaluated(ARGUMENT(1));
745 
746     // Get file name
747     CheckArg(evaluated, 1, aEnvironment, aStackTop);
748     const LispString* orig = evaluated->String();
749     CheckArg(orig, 1, aEnvironment, aStackTop);
750 
751     InternalLoad(aEnvironment, *orig);
752     InternalTrue(aEnvironment, RESULT);
753 }
754 
LispTmpFile(LispEnvironment & aEnvironment,int aStackTop)755 void LispTmpFile(LispEnvironment& aEnvironment, int aStackTop)
756 {
757     CheckSecure(aEnvironment, aStackTop);
758 
759 #ifndef _WIN32
760     char fn[] = "/tmp/yacas-XXXXXX";
761 
762     int fd = mkstemp(fn);
763 
764     // FIXME: not very clear
765     if (fd < 0) {
766         ShowStack(aEnvironment);
767         throw LispErrFileNotFound();
768     }
769 
770     close(fd);
771     RESULT = LispAtom::New(aEnvironment, stringify(fn));
772 
773 #else
774     char tmp_path[MAX_PATH];
775     char tmp_fn[MAX_PATH];
776 
777     GetTempPath(MAX_PATH, tmp_path);
778     GetTempFileName(tmp_path, "yacas", 0, tmp_fn);
779 
780     RESULT = LispAtom::New(aEnvironment, stringify(tmp_fn));
781 #endif
782 }
783 
LispProtect(LispEnvironment & env,int top)784 void LispProtect(LispEnvironment& env, int top)
785 {
786     LispPtr p(env.iStack[top + 1]);
787 
788     CheckArg(p, 1, env, top);
789     const LispString* s = p->String();
790     CheckArg(s, 1, env, top);
791 
792     env.Protect(s);
793 
794     InternalTrue(env, env.iStack[top]);
795 }
796 
LispUnProtect(LispEnvironment & env,int top)797 void LispUnProtect(LispEnvironment& env, int top)
798 {
799     LispPtr p(env.iStack[top + 1]);
800 
801     CheckArg(p, 1, env, top);
802     const LispString* s = p->String();
803     CheckArg(s, 1, env, top);
804 
805     env.UnProtect(s);
806 
807     InternalTrue(env, env.iStack[top]);
808 }
809 
LispIsProtected(LispEnvironment & env,int top)810 void LispIsProtected(LispEnvironment& env, int top)
811 {
812     LispPtr p(env.iStack[top + 1]);
813 
814     CheckArg(p, 1, env, top);
815     const LispString* s = p->String();
816     CheckArg(s, 1, env, top);
817 
818     env.iStack[top] = env.Protected(s) ? env.iTrue->Copy() : env.iFalse->Copy();
819 }
820 
821 /// Implements the Yacas functions \c RuleBase and \c MacroRuleBase .
822 /// The real work is done by LispEnvironment::DeclareRuleBase().
823 static void
InternalRuleBase(LispEnvironment & aEnvironment,int aStackTop,int aListed)824 InternalRuleBase(LispEnvironment& aEnvironment, int aStackTop, int aListed)
825 {
826     // Get operator
827 
828     CheckArg(ARGUMENT(1), 1, aEnvironment, aStackTop);
829     const LispString* orig = ARGUMENT(1)->String();
830     CheckArg(orig, 1, aEnvironment, aStackTop);
831     LispPtr args(ARGUMENT(2));
832 
833     // The arguments
834     CheckArgIsList(2, aEnvironment, aStackTop);
835 
836     // Finally define the rule base
837     aEnvironment.DeclareRuleBase(
838         SymbolName(aEnvironment, *orig), (*args->SubList())->Nixed(), aListed);
839 
840     // Return true
841     InternalTrue(aEnvironment, RESULT);
842 }
843 
844 /// Corresponds to the Yacas function \c RuleBase .
845 /// This function simply calls InternalRuleBase().
LispRuleBase(LispEnvironment & aEnvironment,int aStackTop)846 void LispRuleBase(LispEnvironment& aEnvironment, int aStackTop)
847 {
848     InternalRuleBase(aEnvironment, aStackTop, false);
849 }
850 
LispMacroRuleBase(LispEnvironment & aEnvironment,int aStackTop)851 void LispMacroRuleBase(LispEnvironment& aEnvironment, int aStackTop)
852 {
853     InternalRuleBase(aEnvironment, aStackTop, false);
854 }
855 
InternalDefMacroRuleBase(LispEnvironment & aEnvironment,int aStackTop,int aListed)856 void InternalDefMacroRuleBase(LispEnvironment& aEnvironment,
857                               int aStackTop,
858                               int aListed)
859 {
860     // Get operator
861     // LispPtr body;
862 
863     CheckArg(ARGUMENT(1), 1, aEnvironment, aStackTop);
864     const LispString* orig = ARGUMENT(1)->String();
865     CheckArg(orig, 1, aEnvironment, aStackTop);
866 
867     // The arguments
868     LispPtr args(ARGUMENT(2));
869     CheckArgIsList(2, aEnvironment, aStackTop);
870 
871     // Finally define the rule base
872     aEnvironment.DeclareMacroRuleBase(
873         SymbolName(aEnvironment, *orig), (*args->SubList())->Nixed(), aListed);
874 
875     // Return true
876     InternalTrue(aEnvironment, RESULT);
877 }
878 
LispDefMacroRuleBaseListed(LispEnvironment & aEnvironment,int aStackTop)879 void LispDefMacroRuleBaseListed(LispEnvironment& aEnvironment, int aStackTop)
880 {
881     InternalDefMacroRuleBase(aEnvironment, aStackTop, true);
882 }
883 
LispDefMacroRuleBase(LispEnvironment & aEnvironment,int aStackTop)884 void LispDefMacroRuleBase(LispEnvironment& aEnvironment, int aStackTop)
885 {
886     InternalDefMacroRuleBase(aEnvironment, aStackTop, false);
887 }
888 
LispRuleBaseListed(LispEnvironment & aEnvironment,int aStackTop)889 void LispRuleBaseListed(LispEnvironment& aEnvironment, int aStackTop)
890 {
891     InternalRuleBase(aEnvironment, aStackTop, true);
892 }
893 
LispMacroRuleBaseListed(LispEnvironment & aEnvironment,int aStackTop)894 void LispMacroRuleBaseListed(LispEnvironment& aEnvironment, int aStackTop)
895 {
896     InternalRuleBase(aEnvironment, aStackTop, true);
897 }
898 
LispHoldArg(LispEnvironment & aEnvironment,int aStackTop)899 void LispHoldArg(LispEnvironment& aEnvironment, int aStackTop)
900 {
901     // Get operator
902     CheckArg(ARGUMENT(1), 1, aEnvironment, aStackTop);
903     const LispString* orig = ARGUMENT(1)->String();
904     CheckArg(orig, 1, aEnvironment, aStackTop);
905 
906     // The arguments
907     const LispString* tohold = ARGUMENT(2)->String();
908     CheckArg(tohold, 2, aEnvironment, aStackTop);
909     aEnvironment.HoldArgument(SymbolName(aEnvironment, *orig), tohold);
910     // Return true
911     InternalTrue(aEnvironment, RESULT);
912 }
913 
InternalNewRule(LispEnvironment & aEnvironment,int aStackTop)914 static void InternalNewRule(LispEnvironment& aEnvironment, int aStackTop)
915 {
916     int arity;
917     int precedence;
918 
919     LispPtr ar;
920     LispPtr pr;
921     LispPtr predicate;
922     LispPtr body;
923 
924     // Get operator
925     CheckArg(ARGUMENT(1), 1, aEnvironment, aStackTop);
926     const LispString* orig = ARGUMENT(1)->String();
927     CheckArg(orig, 1, aEnvironment, aStackTop);
928     ar = (ARGUMENT(2));
929     pr = (ARGUMENT(3));
930     predicate = (ARGUMENT(4));
931     body = (ARGUMENT(5));
932 
933     // The arity
934     CheckArg(ar, 2, aEnvironment, aStackTop);
935     CheckArg(ar->String(), 2, aEnvironment, aStackTop);
936     arity = InternalAsciiToInt(*ar->String());
937 
938     // The precedence
939     CheckArg(pr, 3, aEnvironment, aStackTop);
940     CheckArg(pr->String(), 3, aEnvironment, aStackTop);
941     precedence = InternalAsciiToInt(*pr->String());
942 
943     // Finally define the rule base
944     aEnvironment.DefineRule(
945         SymbolName(aEnvironment, *orig), arity, precedence, predicate, body);
946 
947     // Return true
948     InternalTrue(aEnvironment, RESULT);
949 }
950 
LispNewRule(LispEnvironment & aEnvironment,int aStackTop)951 void LispNewRule(LispEnvironment& aEnvironment, int aStackTop)
952 {
953     InternalNewRule(aEnvironment, aStackTop);
954 }
955 
LispMacroNewRule(LispEnvironment & aEnvironment,int aStackTop)956 void LispMacroNewRule(LispEnvironment& aEnvironment, int aStackTop)
957 {
958     InternalNewRule(aEnvironment, aStackTop);
959 }
960 
LispUnFence(LispEnvironment & aEnvironment,int aStackTop)961 void LispUnFence(LispEnvironment& aEnvironment, int aStackTop)
962 {
963     // Get operator
964     CheckArg(ARGUMENT(1), 1, aEnvironment, aStackTop);
965     const LispString* orig = ARGUMENT(1)->String();
966     CheckArg(orig, 1, aEnvironment, aStackTop);
967 
968     // The arity
969     CheckArg(ARGUMENT(2), 2, aEnvironment, aStackTop);
970     CheckArg(ARGUMENT(2)->String(), 2, aEnvironment, aStackTop);
971     int arity = InternalAsciiToInt(*ARGUMENT(2)->String());
972 
973     aEnvironment.UnFenceRule(SymbolName(aEnvironment, *orig), arity);
974 
975     // Return true
976     InternalTrue(aEnvironment, RESULT);
977 }
978 
LispIsFunction(LispEnvironment & aEnvironment,int aStackTop)979 void LispIsFunction(LispEnvironment& aEnvironment, int aStackTop)
980 {
981     LispPtr result(ARGUMENT(1));
982     InternalBoolean(aEnvironment, RESULT, result->SubList() != nullptr);
983 }
984 
LispIsAtom(LispEnvironment & aEnvironment,int aStackTop)985 void LispIsAtom(LispEnvironment& aEnvironment, int aStackTop)
986 {
987     LispPtr result(ARGUMENT(1));
988     InternalBoolean(aEnvironment, RESULT, result->String() != nullptr);
989 }
990 
LispIsNumber(LispEnvironment & aEnvironment,int aStackTop)991 void LispIsNumber(LispEnvironment& aEnvironment, int aStackTop)
992 {
993     LispPtr result(ARGUMENT(1));
994     InternalBoolean(aEnvironment,
995                     RESULT,
996                     result->Number(aEnvironment.Precision()) != nullptr);
997 }
998 
LispIsInteger(LispEnvironment & aEnvironment,int aStackTop)999 void LispIsInteger(LispEnvironment& aEnvironment, int aStackTop)
1000 {
1001     LispPtr result(ARGUMENT(1));
1002 
1003     BigNumber* num(result->Number(aEnvironment.Precision()));
1004     InternalBoolean(aEnvironment, RESULT, num && num->IsInt());
1005 }
1006 
LispIsList(LispEnvironment & aEnvironment,int aStackTop)1007 void LispIsList(LispEnvironment& aEnvironment, int aStackTop)
1008 {
1009     LispPtr result(ARGUMENT(1));
1010     InternalBoolean(aEnvironment, RESULT, InternalIsList(aEnvironment, result));
1011 }
1012 
LispIsString(LispEnvironment & aEnvironment,int aStackTop)1013 void LispIsString(LispEnvironment& aEnvironment, int aStackTop)
1014 {
1015     LispPtr result(ARGUMENT(1));
1016     InternalBoolean(aEnvironment, RESULT, InternalIsString(result->String()));
1017 }
1018 
LispIsBound(LispEnvironment & aEnvironment,int aStackTop)1019 void LispIsBound(LispEnvironment& aEnvironment, int aStackTop)
1020 {
1021     const LispString* str = ARGUMENT(1)->String();
1022     if (str) {
1023         LispPtr val;
1024         aEnvironment.GetVariable(str, val);
1025         if (!!val) {
1026             InternalTrue(aEnvironment, RESULT);
1027             return;
1028         }
1029     }
1030     InternalFalse(aEnvironment, RESULT);
1031 }
1032 
LispIf(LispEnvironment & aEnvironment,int aStackTop)1033 void LispIf(LispEnvironment& aEnvironment, int aStackTop)
1034 {
1035     int nrArguments = InternalListLength(ARGUMENT(0));
1036     if (nrArguments != 3 && nrArguments != 4) {
1037         ShowStack(aEnvironment);
1038         throw LispErrWrongNumberOfArgs();
1039     }
1040 
1041     LispPtr predicate;
1042     InternalEval(aEnvironment, predicate, ARGUMENT(1));
1043 
1044     if (IsTrue(aEnvironment, predicate)) {
1045         InternalEval(aEnvironment, RESULT, Argument(ARGUMENT(0), 2));
1046     } else {
1047         CheckArg(IsFalse(aEnvironment, predicate), 1, aEnvironment, aStackTop);
1048         if (nrArguments == 4)
1049             InternalEval(aEnvironment, RESULT, Argument(ARGUMENT(0), 3));
1050         else
1051             InternalFalse(aEnvironment, RESULT);
1052     }
1053 }
1054 
LispRetract(LispEnvironment & aEnvironment,int aStackTop)1055 void LispRetract(LispEnvironment& aEnvironment, int aStackTop)
1056 {
1057     // Get operator
1058     LispPtr evaluated(ARGUMENT(1));
1059 
1060     CheckArg(evaluated, 1, aEnvironment, aStackTop);
1061     const LispString* orig = evaluated->String();
1062     CheckArg(orig, 1, aEnvironment, aStackTop);
1063     const LispString* oper = SymbolName(aEnvironment, *orig);
1064 
1065     LispPtr arity(ARGUMENT(2));
1066     CheckArg(arity->String(), 2, aEnvironment, aStackTop);
1067     int ar = InternalAsciiToInt(*arity->String());
1068     aEnvironment.Retract(oper, ar);
1069     InternalTrue(aEnvironment, RESULT);
1070 }
1071 
YacasBuiltinPrecisionSet(LispEnvironment & aEnvironment,int aStackTop)1072 void YacasBuiltinPrecisionSet(LispEnvironment& aEnvironment, int aStackTop)
1073 {
1074     LispPtr index(ARGUMENT(1));
1075     CheckArg(index, 1, aEnvironment, aStackTop);
1076     CheckArg(index->String(), 1, aEnvironment, aStackTop);
1077 
1078     int ind = InternalAsciiToInt(*index->String());
1079     CheckArg(ind > 0, 1, aEnvironment, aStackTop);
1080     aEnvironment.SetPrecision(ind);
1081     InternalTrue(aEnvironment, RESULT);
1082 }
1083 
LispDefaultDirectory(LispEnvironment & aEnvironment,int aStackTop)1084 void LispDefaultDirectory(LispEnvironment& aEnvironment, int aStackTop)
1085 {
1086     // Get file name
1087     CheckArg(ARGUMENT(1), 1, aEnvironment, aStackTop);
1088     const LispString* orig = ARGUMENT(1)->String();
1089     CheckArg(orig, 1, aEnvironment, aStackTop);
1090     aEnvironment.iInputDirectories.push_back(InternalUnstringify(*orig));
1091     InternalTrue(aEnvironment, RESULT);
1092 }
1093 
LispFromFile(LispEnvironment & aEnvironment,int aStackTop)1094 void LispFromFile(LispEnvironment& aEnvironment, int aStackTop)
1095 {
1096     CheckSecure(aEnvironment, aStackTop);
1097 
1098     LispPtr evaluated;
1099     InternalEval(aEnvironment, evaluated, ARGUMENT(1));
1100 
1101     // Get file name
1102     CheckArg(evaluated, 1, aEnvironment, aStackTop);
1103     const LispString* orig = evaluated->String();
1104     CheckArg(orig, 1, aEnvironment, aStackTop);
1105 
1106     const std::string fname = orig->substr(1, orig->length() - 2);
1107 
1108     InputStatus oldstatus = aEnvironment.iInputStatus;
1109     aEnvironment.iInputStatus.SetTo(fname);
1110 
1111     // Open file
1112     LispLocalFile localFP(
1113         aEnvironment, fname, true, aEnvironment.iInputDirectories);
1114     if (!localFP.stream.is_open()) {
1115         ShowStack(aEnvironment);
1116         throw LispErrFileNotFound();
1117     }
1118     StdFileInput newInput(localFP, aEnvironment.iInputStatus);
1119     LispLocalInput localInput(aEnvironment, &newInput);
1120 
1121     // Evaluate the body
1122     InternalEval(aEnvironment, RESULT, ARGUMENT(2));
1123 
1124     aEnvironment.iInputStatus.RestoreFrom(oldstatus);
1125     // Return the result
1126 }
1127 
LispFromString(LispEnvironment & aEnvironment,int aStackTop)1128 void LispFromString(LispEnvironment& aEnvironment, int aStackTop)
1129 {
1130     LispPtr evaluated;
1131     InternalEval(aEnvironment, evaluated, ARGUMENT(1));
1132 
1133     // Get file name
1134     CheckArg(evaluated, 1, aEnvironment, aStackTop);
1135     const LispString* orig = evaluated->String();
1136     CheckArg(orig, 1, aEnvironment, aStackTop);
1137     const std::string oper = InternalUnstringify(*orig);
1138 
1139     InputStatus oldstatus = aEnvironment.iInputStatus;
1140     aEnvironment.iInputStatus.SetTo("String");
1141     StringInput newInput(oper, aEnvironment.iInputStatus);
1142     LispLocalInput localInput(aEnvironment, &newInput);
1143 
1144     // Evaluate the body
1145     InternalEval(aEnvironment, RESULT, ARGUMENT(2));
1146     aEnvironment.iInputStatus.RestoreFrom(oldstatus);
1147 
1148     // Return the result
1149 }
1150 
LispRead(LispEnvironment & aEnvironment,int aStackTop)1151 void LispRead(LispEnvironment& aEnvironment, int aStackTop)
1152 {
1153     LispTokenizer& tok = *aEnvironment.iCurrentTokenizer;
1154     InfixParser parser(tok,
1155                        *aEnvironment.CurrentInput(),
1156                        aEnvironment,
1157                        aEnvironment.PreFix(),
1158                        aEnvironment.InFix(),
1159                        aEnvironment.PostFix(),
1160                        aEnvironment.Bodied());
1161     // Read expression
1162     parser.Parse(RESULT);
1163 }
1164 
LispReadToken(LispEnvironment & aEnvironment,int aStackTop)1165 void LispReadToken(LispEnvironment& aEnvironment, int aStackTop)
1166 {
1167     LispTokenizer& tok = *aEnvironment.iCurrentTokenizer;
1168     const LispString* result = aEnvironment.HashTable().LookUp(
1169         tok.NextToken(*aEnvironment.CurrentInput()));
1170 
1171     if (result->empty()) {
1172         RESULT = aEnvironment.iEndOfFile->Copy();
1173         return;
1174     }
1175     RESULT = LispAtom::New(aEnvironment, *result);
1176 }
1177 
LispToFile(LispEnvironment & aEnvironment,int aStackTop)1178 void LispToFile(LispEnvironment& aEnvironment, int aStackTop)
1179 {
1180     CheckSecure(aEnvironment, aStackTop);
1181 
1182     LispPtr evaluated;
1183     InternalEval(aEnvironment, evaluated, ARGUMENT(1));
1184 
1185     // Get file name
1186     CheckArg(evaluated, 1, aEnvironment, aStackTop);
1187     const LispString* orig = evaluated->String();
1188     CheckArg(orig, 1, aEnvironment, aStackTop);
1189     const std::string oper = InternalUnstringify(*orig);
1190 
1191     // Open file for writing
1192     LispLocalFile localFP(
1193         aEnvironment, oper, false, aEnvironment.iInputDirectories);
1194     if (!localFP.stream.is_open()) {
1195         ShowStack(aEnvironment);
1196         throw LispErrFileNotFound();
1197     }
1198     LispLocalOutput localOutput(aEnvironment, localFP.stream);
1199 
1200     // Evaluate the body
1201     InternalEval(aEnvironment, RESULT, ARGUMENT(2));
1202 
1203     // Return the result
1204 }
1205 
LispCheck(LispEnvironment & aEnvironment,int aStackTop)1206 void LispCheck(LispEnvironment& aEnvironment, int aStackTop)
1207 {
1208     LispPtr pred;
1209     InternalEval(aEnvironment, pred, ARGUMENT(1));
1210     if (!IsTrue(aEnvironment, pred)) {
1211         LispPtr evaluated;
1212         InternalEval(aEnvironment, evaluated, ARGUMENT(2));
1213         CheckArgIsString(evaluated, 2, aEnvironment, aStackTop);
1214         ShowStack(aEnvironment);
1215         throw LispErrUser(*evaluated->String());
1216     }
1217     RESULT = pred;
1218 }
1219 
LispTrapError(LispEnvironment & aEnvironment,int aStackTop)1220 void LispTrapError(LispEnvironment& aEnvironment, int aStackTop)
1221 {
1222     try {
1223         InternalEval(aEnvironment, RESULT, ARGUMENT(1));
1224     } catch (const LispError& error) {
1225         HandleError(error, aEnvironment, aEnvironment.iErrorOutput);
1226     }
1227 
1228     if (!aEnvironment.iErrorOutput.str().empty()) {
1229         InternalEval(aEnvironment, RESULT, ARGUMENT(2));
1230         aEnvironment.iErrorOutput.clear();
1231         aEnvironment.iErrorOutput.str("");
1232     }
1233 }
1234 
LispGetCoreError(LispEnvironment & aEnvironment,int aStackTop)1235 void LispGetCoreError(LispEnvironment& aEnvironment, int aStackTop)
1236 {
1237     RESULT =
1238         LispAtom::New(aEnvironment, stringify(aEnvironment.iErrorOutput.str()));
1239 }
1240 
LispSystemCall(LispEnvironment & aEnvironment,int aStackTop)1241 void LispSystemCall(LispEnvironment& aEnvironment, int aStackTop)
1242 {
1243     CheckSecure(aEnvironment, aStackTop);
1244 
1245     LispPtr result(ARGUMENT(1));
1246     CheckArgIsString(1, aEnvironment, aStackTop);
1247 
1248     const std::string command = InternalUnstringify(*result->String());
1249 
1250     // we would like to pass the exit code back to Yacas. Right now, let's pass
1251     // True/False according to whether the exit code is 0 or not.
1252     InternalBoolean(aEnvironment, RESULT, system(command.c_str()) == 0);
1253 }
1254 
LispSystemName(LispEnvironment & aEnvironment,int aStackTop)1255 void LispSystemName(LispEnvironment& aEnvironment, int aStackTop)
1256 {
1257     const char* s = "Unknown";
1258 
1259 #if defined(_WIN32)
1260     s = "Windows";
1261 #elif defined(__APPLE__)
1262     s = "MacOSX";
1263 #elif defined(__linux__)
1264     s = "Linux";
1265 #endif
1266 
1267     RESULT = LispAtom::New(aEnvironment, stringify(s));
1268 }
1269 
LispMaxEvalDepth(LispEnvironment & aEnvironment,int aStackTop)1270 void LispMaxEvalDepth(LispEnvironment& aEnvironment, int aStackTop)
1271 {
1272     LispPtr index(ARGUMENT(1));
1273     CheckArg(index, 1, aEnvironment, aStackTop);
1274     CheckArg(index->String(), 1, aEnvironment, aStackTop);
1275 
1276     int ind = InternalAsciiToInt(*index->String());
1277     aEnvironment.iMaxEvalDepth = ind;
1278     InternalTrue(aEnvironment, RESULT);
1279 }
1280 
LispDefLoad(LispEnvironment & aEnvironment,int aStackTop)1281 void LispDefLoad(LispEnvironment& aEnvironment, int aStackTop)
1282 {
1283     CheckSecure(aEnvironment, aStackTop);
1284 
1285     LispPtr evaluated(ARGUMENT(1));
1286 
1287     // Get file name
1288     CheckArg(evaluated, 1, aEnvironment, aStackTop);
1289     const LispString* orig = evaluated->String();
1290     CheckArg(orig, 1, aEnvironment, aStackTop);
1291 
1292     LoadDefFile(aEnvironment, *orig);
1293     InternalTrue(aEnvironment, RESULT);
1294 }
1295 
LispUse(LispEnvironment & aEnvironment,int aStackTop)1296 void LispUse(LispEnvironment& aEnvironment, int aStackTop)
1297 {
1298     LispPtr evaluated(ARGUMENT(1));
1299 
1300     // Get file name
1301     CheckArg(evaluated, 1, aEnvironment, aStackTop);
1302     const LispString* orig = evaluated->String();
1303     CheckArg(orig, 1, aEnvironment, aStackTop);
1304 
1305     InternalUse(aEnvironment, *orig);
1306     InternalTrue(aEnvironment, RESULT);
1307 }
1308 
LispRightAssociative(LispEnvironment & aEnvironment,int aStackTop)1309 void LispRightAssociative(LispEnvironment& aEnvironment, int aStackTop)
1310 {
1311     // Get operator
1312     CheckArg(ARGUMENT(1), 1, aEnvironment, aStackTop);
1313     const LispString* orig = ARGUMENT(1)->String();
1314     CheckArg(orig, 1, aEnvironment, aStackTop);
1315 
1316     LispOperators::iterator opi =
1317         aEnvironment.InFix().find(SymbolName(aEnvironment, *orig));
1318     if (opi == aEnvironment.InFix().end())
1319         throw LispErrNotAnInFixOperator();
1320     opi->second.SetRightAssociative();
1321 
1322     InternalTrue(aEnvironment, RESULT);
1323 }
1324 
LispLeftPrecedence(LispEnvironment & aEnvironment,int aStackTop)1325 void LispLeftPrecedence(LispEnvironment& aEnvironment, int aStackTop)
1326 {
1327     // Get operator
1328     CheckArg(ARGUMENT(1), 1, aEnvironment, aStackTop);
1329     const LispString* orig = ARGUMENT(1)->String();
1330     CheckArg(orig, 1, aEnvironment, aStackTop);
1331 
1332     LispPtr index;
1333     InternalEval(aEnvironment, index, ARGUMENT(2));
1334     CheckArg(index, 2, aEnvironment, aStackTop);
1335     CheckArg(index->String(), 2, aEnvironment, aStackTop);
1336     int ind = InternalAsciiToInt(*index->String());
1337 
1338     LispOperators::iterator opi =
1339         aEnvironment.InFix().find(SymbolName(aEnvironment, *orig));
1340     if (opi == aEnvironment.InFix().end())
1341         throw LispErrNotAnInFixOperator();
1342     opi->second.SetLeftPrecedence(ind);
1343 
1344     InternalTrue(aEnvironment, RESULT);
1345 }
1346 
LispRightPrecedence(LispEnvironment & aEnvironment,int aStackTop)1347 void LispRightPrecedence(LispEnvironment& aEnvironment, int aStackTop)
1348 {
1349     // Get operator
1350     CheckArg(ARGUMENT(1), 1, aEnvironment, aStackTop);
1351     const LispString* orig = ARGUMENT(1)->String();
1352     CheckArg(orig, 1, aEnvironment, aStackTop);
1353 
1354     LispPtr index;
1355     InternalEval(aEnvironment, index, ARGUMENT(2));
1356     CheckArg(index, 2, aEnvironment, aStackTop);
1357     CheckArg(index->String(), 2, aEnvironment, aStackTop);
1358     int ind = InternalAsciiToInt(*index->String());
1359 
1360     LispOperators::iterator opi =
1361         aEnvironment.InFix().find(SymbolName(aEnvironment, *orig));
1362     if (opi == aEnvironment.InFix().end())
1363         throw LispErrNotAnInFixOperator();
1364     opi->second.SetRightPrecedence(ind);
1365 
1366     InternalTrue(aEnvironment, RESULT);
1367 }
1368 
OperatorInfo(LispEnvironment & aEnvironment,int aStackTop,LispOperators & aOperators)1369 static LispInFixOperator* OperatorInfo(LispEnvironment& aEnvironment,
1370                                        int aStackTop,
1371                                        LispOperators& aOperators)
1372 {
1373     // Get operator
1374     CheckArg(ARGUMENT(1), 1, aEnvironment, aStackTop);
1375 
1376     LispPtr evaluated(ARGUMENT(1));
1377 
1378     const LispString* orig = evaluated->String();
1379     CheckArg(orig, 1, aEnvironment, aStackTop);
1380 
1381     const LispOperators::iterator opi =
1382         aOperators.find(SymbolName(aEnvironment, *orig));
1383     if (opi != aOperators.end())
1384         return &opi->second;
1385     return nullptr;
1386 }
1387 
LispIsInFix(LispEnvironment & aEnvironment,int aStackTop)1388 void LispIsInFix(LispEnvironment& aEnvironment, int aStackTop)
1389 {
1390     LispInFixOperator* op =
1391         OperatorInfo(aEnvironment, aStackTop, aEnvironment.InFix());
1392     InternalBoolean(aEnvironment, RESULT, op != nullptr);
1393 }
1394 
LispIsBodied(LispEnvironment & aEnvironment,int aStackTop)1395 void LispIsBodied(LispEnvironment& aEnvironment, int aStackTop)
1396 {
1397     LispInFixOperator* op =
1398         OperatorInfo(aEnvironment, aStackTop, aEnvironment.Bodied());
1399     InternalBoolean(aEnvironment, RESULT, op != nullptr);
1400 }
1401 
LispGetPrecedence(LispEnvironment & aEnvironment,int aStackTop)1402 void LispGetPrecedence(LispEnvironment& aEnvironment, int aStackTop)
1403 {
1404     LispInFixOperator* op =
1405         OperatorInfo(aEnvironment, aStackTop, aEnvironment.InFix());
1406     if (!op) { // also need to check for a postfix or prefix operator
1407         op = OperatorInfo(aEnvironment, aStackTop, aEnvironment.PreFix());
1408         if (!op) {
1409             op = OperatorInfo(aEnvironment, aStackTop, aEnvironment.PostFix());
1410             if (!op) { // or maybe it's a bodied function
1411                 op = OperatorInfo(
1412                     aEnvironment, aStackTop, aEnvironment.Bodied());
1413                 if (!op) {
1414                     ShowStack(aEnvironment);
1415                     throw LispErrIsNotInFix();
1416                 }
1417             }
1418         }
1419     }
1420     RESULT = LispAtom::New(aEnvironment, std::to_string(op->iPrecedence));
1421 }
1422 
LispGetLeftPrecedence(LispEnvironment & aEnvironment,int aStackTop)1423 void LispGetLeftPrecedence(LispEnvironment& aEnvironment, int aStackTop)
1424 {
1425     LispInFixOperator* op =
1426         OperatorInfo(aEnvironment, aStackTop, aEnvironment.InFix());
1427     if (!op) { // infix and postfix operators have left precedence
1428         op = OperatorInfo(aEnvironment, aStackTop, aEnvironment.PostFix());
1429         if (!op) {
1430             ShowStack(aEnvironment);
1431             throw LispErrIsNotInFix();
1432         }
1433     }
1434 
1435     RESULT = LispAtom::New(aEnvironment, std::to_string(op->iLeftPrecedence));
1436 }
1437 
LispGetRightPrecedence(LispEnvironment & aEnvironment,int aStackTop)1438 void LispGetRightPrecedence(LispEnvironment& aEnvironment, int aStackTop)
1439 {
1440     LispInFixOperator* op =
1441         OperatorInfo(aEnvironment, aStackTop, aEnvironment.InFix());
1442     if (!op) { // bodied, infix and prefix operators have right precedence
1443         op = OperatorInfo(aEnvironment, aStackTop, aEnvironment.PreFix());
1444         if (!op) { // or maybe it's a bodied function
1445             op = OperatorInfo(aEnvironment, aStackTop, aEnvironment.Bodied());
1446             if (!op) {
1447                 ShowStack(aEnvironment);
1448                 throw LispErrIsNotInFix();
1449             }
1450         }
1451     }
1452 
1453     RESULT = LispAtom::New(aEnvironment, std::to_string(op->iRightPrecedence));
1454 }
1455 
LispIsPreFix(LispEnvironment & aEnvironment,int aStackTop)1456 void LispIsPreFix(LispEnvironment& aEnvironment, int aStackTop)
1457 {
1458     LispInFixOperator* op =
1459         OperatorInfo(aEnvironment, aStackTop, aEnvironment.PreFix());
1460     InternalBoolean(aEnvironment, RESULT, op != nullptr);
1461 }
1462 
LispIsPostFix(LispEnvironment & aEnvironment,int aStackTop)1463 void LispIsPostFix(LispEnvironment& aEnvironment, int aStackTop)
1464 {
1465     LispInFixOperator* op =
1466         OperatorInfo(aEnvironment, aStackTop, aEnvironment.PostFix());
1467 
1468     InternalBoolean(aEnvironment, RESULT, op != nullptr);
1469 }
1470 
YacasBuiltinPrecisionGet(LispEnvironment & aEnvironment,int aStackTop)1471 void YacasBuiltinPrecisionGet(LispEnvironment& aEnvironment, int aStackTop)
1472 {
1473     RESULT =
1474         LispAtom::New(aEnvironment, std::to_string(aEnvironment.Precision()));
1475 }
1476 
LispToString(LispEnvironment & aEnvironment,int aStackTop)1477 void LispToString(LispEnvironment& aEnvironment, int aStackTop)
1478 {
1479     std::ostringstream os;
1480 
1481     LispLocalOutput localOutput(aEnvironment, os);
1482 
1483     // Evaluate the body
1484     InternalEval(aEnvironment, RESULT, ARGUMENT(1));
1485 
1486     // Return the result
1487     RESULT = LispAtom::New(aEnvironment, stringify(os.str()));
1488 }
1489 
LispToStdout(LispEnvironment & aEnvironment,int aStackTop)1490 void LispToStdout(LispEnvironment& aEnvironment, int aStackTop)
1491 {
1492     LispLocalOutput localOutput(aEnvironment, *aEnvironment.iInitialOutput);
1493     // Evaluate the body
1494     InternalEval(aEnvironment, RESULT, ARGUMENT(1));
1495 }
1496 
LispSecure(LispEnvironment & aEnvironment,int aStackTop)1497 void LispSecure(LispEnvironment& aEnvironment, int aStackTop)
1498 {
1499     LispSecureFrame security(aEnvironment);
1500     InternalEval(aEnvironment, RESULT, ARGUMENT(1));
1501 }
1502 
LispFindFile(LispEnvironment & aEnvironment,int aStackTop)1503 void LispFindFile(LispEnvironment& aEnvironment, int aStackTop)
1504 {
1505     CheckSecure(aEnvironment, aStackTop);
1506 
1507     LispPtr evaluated(ARGUMENT(1));
1508 
1509     // Get file name
1510     CheckArg(evaluated, 1, aEnvironment, aStackTop);
1511     const LispString* orig = evaluated->String();
1512     CheckArg(orig, 1, aEnvironment, aStackTop);
1513     const std::string oper = InternalUnstringify(*orig);
1514 
1515     const std::string path =
1516         InternalFindFile(oper, aEnvironment.iInputDirectories);
1517 
1518     RESULT = LispAtom::New(aEnvironment, stringify(path));
1519 }
1520 
LispIsGeneric(LispEnvironment & aEnvironment,int aStackTop)1521 void LispIsGeneric(LispEnvironment& aEnvironment, int aStackTop)
1522 {
1523     LispPtr evaluated(ARGUMENT(1));
1524 
1525     InternalBoolean(aEnvironment, RESULT, evaluated->Generic() != nullptr);
1526 }
1527 
LispGenericTypeName(LispEnvironment & aEnvironment,int aStackTop)1528 void LispGenericTypeName(LispEnvironment& aEnvironment, int aStackTop)
1529 {
1530     LispPtr evaluated(ARGUMENT(1));
1531     CheckArg(evaluated, 1, aEnvironment, aStackTop);
1532 
1533     const char* name = evaluated->Generic()->TypeName();
1534     RESULT = (LispAtom::New(aEnvironment, name));
1535 }
1536 
GenArrayCreate(LispEnvironment & aEnvironment,int aStackTop)1537 void GenArrayCreate(LispEnvironment& aEnvironment, int aStackTop)
1538 {
1539     LispPtr sizearg(ARGUMENT(1));
1540 
1541     CheckArg(sizearg, 1, aEnvironment, aStackTop);
1542     CheckArg(sizearg->String(), 1, aEnvironment, aStackTop);
1543 
1544     int size = InternalAsciiToInt(*sizearg->String());
1545 
1546     LispPtr initarg(ARGUMENT(2));
1547 
1548     ArrayClass* array = new ArrayClass(size, initarg);
1549     RESULT = (LispGenericClass::New(array));
1550 }
1551 
GenArraySize(LispEnvironment & aEnvironment,int aStackTop)1552 void GenArraySize(LispEnvironment& aEnvironment, int aStackTop)
1553 {
1554     LispPtr evaluated(ARGUMENT(1));
1555 
1556     GenericClass* gen = evaluated->Generic();
1557     ArrayClass* arr = dynamic_cast<ArrayClass*>(gen);
1558     CheckArg(arr, 1, aEnvironment, aStackTop);
1559     RESULT = LispAtom::New(aEnvironment, std::to_string(arr->Size()));
1560 }
1561 
GenArrayGet(LispEnvironment & aEnvironment,int aStackTop)1562 void GenArrayGet(LispEnvironment& aEnvironment, int aStackTop)
1563 {
1564     LispPtr evaluated(ARGUMENT(1));
1565 
1566     GenericClass* gen = evaluated->Generic();
1567     ArrayClass* arr = dynamic_cast<ArrayClass*>(gen);
1568     CheckArg(arr, 1, aEnvironment, aStackTop);
1569 
1570     LispPtr sizearg(ARGUMENT(2));
1571     CheckArg(sizearg, 2, aEnvironment, aStackTop);
1572     CheckArg(sizearg->String(), 2, aEnvironment, aStackTop);
1573 
1574     int size = InternalAsciiToInt(*sizearg->String());
1575 
1576     CheckArg(size > 0 && static_cast<std::size_t>(size) <= arr->Size(),
1577              2,
1578              aEnvironment,
1579              aStackTop);
1580     LispObject* object = arr->GetElement(size);
1581     RESULT = (object->Copy());
1582 }
1583 
GenArraySet(LispEnvironment & aEnvironment,int aStackTop)1584 void GenArraySet(LispEnvironment& aEnvironment, int aStackTop)
1585 {
1586     LispPtr evaluated(ARGUMENT(1));
1587 
1588     GenericClass* gen = evaluated->Generic();
1589     ArrayClass* arr = dynamic_cast<ArrayClass*>(gen);
1590     CheckArg(arr, 1, aEnvironment, aStackTop);
1591 
1592     LispPtr sizearg(ARGUMENT(2));
1593     CheckArg(sizearg, 2, aEnvironment, aStackTop);
1594     CheckArg(sizearg->String(), 2, aEnvironment, aStackTop);
1595 
1596     int size = InternalAsciiToInt(*sizearg->String());
1597 
1598     CheckArg(size > 0 && static_cast<std::size_t>(size) <= arr->Size(),
1599              2,
1600              aEnvironment,
1601              aStackTop);
1602     LispPtr obj(ARGUMENT(3));
1603     arr->SetElement(size, obj);
1604 
1605     InternalTrue(aEnvironment, RESULT);
1606 }
1607 
GenAssociationCreate(LispEnvironment & aEnvironment,int aStackTop)1608 void GenAssociationCreate(LispEnvironment& aEnvironment, int aStackTop)
1609 {
1610     AssociationClass* a = new AssociationClass(aEnvironment);
1611     RESULT = LispGenericClass::New(a);
1612 }
1613 
GenAssociationSize(LispEnvironment & aEnvironment,int aStackTop)1614 void GenAssociationSize(LispEnvironment& aEnvironment, int aStackTop)
1615 {
1616     LispPtr evaluated(ARGUMENT(1));
1617 
1618     GenericClass* gen = evaluated->Generic();
1619     AssociationClass* a = dynamic_cast<AssociationClass*>(gen);
1620     CheckArg(a, 1, aEnvironment, aStackTop);
1621     RESULT = LispAtom::New(aEnvironment, std::to_string(a->Size()));
1622 }
1623 
GenAssociationContains(LispEnvironment & aEnvironment,int aStackTop)1624 void GenAssociationContains(LispEnvironment& aEnvironment, int aStackTop)
1625 {
1626     LispPtr p(ARGUMENT(1));
1627     GenericClass* gen = p->Generic();
1628     AssociationClass* a = dynamic_cast<AssociationClass*>(gen);
1629     CheckArg(a, 1, aEnvironment, aStackTop);
1630 
1631     LispPtr k(ARGUMENT(2));
1632 
1633     if (a->GetElement(k))
1634         InternalTrue(aEnvironment, RESULT);
1635     else
1636         InternalFalse(aEnvironment, RESULT);
1637 }
1638 
GenAssociationGet(LispEnvironment & aEnvironment,int aStackTop)1639 void GenAssociationGet(LispEnvironment& aEnvironment, int aStackTop)
1640 {
1641     LispPtr p(ARGUMENT(1));
1642     GenericClass* gen = p->Generic();
1643     AssociationClass* a = dynamic_cast<AssociationClass*>(gen);
1644     CheckArg(a, 1, aEnvironment, aStackTop);
1645 
1646     LispPtr k(ARGUMENT(2));
1647     LispObject* v = a->GetElement(k);
1648 
1649     if (v)
1650         RESULT = v->Copy();
1651     else
1652         RESULT = LispAtom::New(aEnvironment, "Undefined");
1653 }
1654 
GenAssociationSet(LispEnvironment & aEnvironment,int aStackTop)1655 void GenAssociationSet(LispEnvironment& aEnvironment, int aStackTop)
1656 {
1657     LispPtr p(ARGUMENT(1));
1658     GenericClass* gen = p->Generic();
1659     AssociationClass* a = dynamic_cast<AssociationClass*>(gen);
1660     CheckArg(a, 1, aEnvironment, aStackTop);
1661 
1662     LispPtr k(ARGUMENT(2));
1663     LispPtr v(ARGUMENT(3));
1664 
1665     a->SetElement(k, v);
1666 
1667     InternalTrue(aEnvironment, RESULT);
1668 }
1669 
GenAssociationDrop(LispEnvironment & aEnvironment,int aStackTop)1670 void GenAssociationDrop(LispEnvironment& aEnvironment, int aStackTop)
1671 {
1672     LispPtr p(ARGUMENT(1));
1673     GenericClass* gen = p->Generic();
1674     AssociationClass* a = dynamic_cast<AssociationClass*>(gen);
1675     CheckArg(a, 1, aEnvironment, aStackTop);
1676 
1677     LispPtr k(ARGUMENT(2));
1678     if (a->DropElement(k))
1679         InternalTrue(aEnvironment, RESULT);
1680     else
1681         InternalFalse(aEnvironment, RESULT);
1682 }
1683 
GenAssociationKeys(LispEnvironment & aEnvironment,int aStackTop)1684 void GenAssociationKeys(LispEnvironment& aEnvironment, int aStackTop)
1685 {
1686     LispPtr p(ARGUMENT(1));
1687     GenericClass* gen = p->Generic();
1688     AssociationClass* a = dynamic_cast<AssociationClass*>(gen);
1689     CheckArg(a, 1, aEnvironment, aStackTop);
1690 
1691     RESULT = a->Keys();
1692 }
1693 
GenAssociationToList(LispEnvironment & aEnvironment,int aStackTop)1694 void GenAssociationToList(LispEnvironment& aEnvironment, int aStackTop)
1695 {
1696     LispPtr p(ARGUMENT(1));
1697     GenericClass* gen = p->Generic();
1698     AssociationClass* a = dynamic_cast<AssociationClass*>(gen);
1699     CheckArg(a, 1, aEnvironment, aStackTop);
1700 
1701     RESULT = a->ToList();
1702 }
1703 
GenAssociationHead(LispEnvironment & aEnvironment,int aStackTop)1704 void GenAssociationHead(LispEnvironment& aEnvironment, int aStackTop)
1705 {
1706     LispPtr p(ARGUMENT(1));
1707     GenericClass* gen = p->Generic();
1708     AssociationClass* a = dynamic_cast<AssociationClass*>(gen);
1709     CheckArg(a, 1, aEnvironment, aStackTop);
1710     CheckArg(a->Size(), 1, aEnvironment, aStackTop);
1711 
1712     RESULT = a->Head();
1713 }
1714 
LispCustomEval(LispEnvironment & aEnvironment,int aStackTop)1715 void LispCustomEval(LispEnvironment& aEnvironment, int aStackTop)
1716 {
1717     if (aEnvironment.iDebugger)
1718         delete aEnvironment.iDebugger;
1719     aEnvironment.iDebugger =
1720         new DefaultDebugger(ARGUMENT(1), ARGUMENT(2), ARGUMENT(3));
1721     LispLocalEvaluator local(aEnvironment, new TracedEvaluator);
1722     aEnvironment.iDebugger->Start();
1723     InternalEval(aEnvironment, RESULT, ARGUMENT(4));
1724     aEnvironment.iDebugger->Finish();
1725     delete aEnvironment.iDebugger;
1726     aEnvironment.iDebugger = nullptr;
1727 }
1728 
LispCustomEvalExpression(LispEnvironment & aEnvironment,int aStackTop)1729 void LispCustomEvalExpression(LispEnvironment& aEnvironment, int aStackTop)
1730 {
1731     if (!aEnvironment.iDebugger)
1732         throw LispErrGeneric(
1733             "Trying to get CustomEval results while not in custom evaluation");
1734 
1735     RESULT = (aEnvironment.iDebugger->iTopExpr);
1736 }
1737 
LispCustomEvalResult(LispEnvironment & aEnvironment,int aStackTop)1738 void LispCustomEvalResult(LispEnvironment& aEnvironment, int aStackTop)
1739 {
1740     if (!aEnvironment.iDebugger)
1741         throw LispErrGeneric(
1742             "Trying to get CustomEval results while not in custom evaluation");
1743 
1744     RESULT = (aEnvironment.iDebugger->iTopResult);
1745 }
1746 
LispCustomEvalLocals(LispEnvironment & aEnvironment,int aStackTop)1747 void LispCustomEvalLocals(LispEnvironment& aEnvironment, int aStackTop)
1748 {
1749     aEnvironment.CurrentLocals(RESULT);
1750 }
1751 
LispCustomEvalStop(LispEnvironment & aEnvironment,int aStackTop)1752 void LispCustomEvalStop(LispEnvironment& aEnvironment, int aStackTop)
1753 {
1754     if (!aEnvironment.iDebugger)
1755         throw LispErrGeneric(
1756             "Trying to get CustomEval results while not in custom evaluation");
1757 
1758     aEnvironment.iDebugger->iStopped = true;
1759 
1760     InternalTrue(aEnvironment, RESULT);
1761 }
1762 
LispTraceStack(LispEnvironment & aEnvironment,int aStackTop)1763 void LispTraceStack(LispEnvironment& aEnvironment, int aStackTop)
1764 {
1765     LispLocalEvaluator local(aEnvironment, new TracedStackEvaluator);
1766     InternalEval(aEnvironment, RESULT, ARGUMENT(1));
1767 }
1768 
LispReadLisp(LispEnvironment & aEnvironment,int aStackTop)1769 void LispReadLisp(LispEnvironment& aEnvironment, int aStackTop)
1770 {
1771     LispTokenizer& tok = *aEnvironment.iCurrentTokenizer;
1772     LispParser parser(tok, *aEnvironment.CurrentInput(), aEnvironment);
1773     // Read expression
1774     parser.Parse(RESULT);
1775 }
1776 
LispReadLispListed(LispEnvironment & aEnvironment,int aStackTop)1777 void LispReadLispListed(LispEnvironment& aEnvironment, int aStackTop)
1778 {
1779     LispTokenizer& tok = *aEnvironment.iCurrentTokenizer;
1780     LispParser parser(tok, *aEnvironment.CurrentInput(), aEnvironment);
1781     parser.iListed = true;
1782     // Read expression
1783     parser.Parse(RESULT);
1784 }
1785 
LispTraceRule(LispEnvironment & aEnvironment,int aStackTop)1786 void LispTraceRule(LispEnvironment& aEnvironment, int aStackTop)
1787 {
1788     LispPtr* ptr = ARGUMENT(0)->Nixed()->SubList();
1789     LispUserFunction* userfunc = nullptr;
1790     if (ptr)
1791         userfunc = GetUserFunction(aEnvironment, ptr);
1792     LispLocalTrace trace(userfunc);
1793     InternalEval(aEnvironment, RESULT, ARGUMENT(2));
1794 }
1795 
LispType(LispEnvironment & aEnvironment,int aStackTop)1796 void LispType(LispEnvironment& aEnvironment, int aStackTop)
1797 {
1798     LispPtr evaluated(ARGUMENT(1));
1799     LispPtr* subList = evaluated->SubList();
1800     LispObject* head = nullptr;
1801     if (!subList) {
1802         goto EMPTY;
1803     }
1804     head = (*subList);
1805     if (!head->String())
1806         goto EMPTY;
1807     RESULT = LispAtom::New(
1808         aEnvironment,
1809         *aEnvironment.HashTable().LookUp(stringify(*head->String())));
1810     return;
1811 
1812 EMPTY:
1813     RESULT = LispAtom::New(aEnvironment, "\"\"");
1814     return;
1815 }
1816 
YacasStringMidGet(LispEnvironment & aEnvironment,int aStackTop)1817 void YacasStringMidGet(LispEnvironment& aEnvironment, int aStackTop)
1818 {
1819     CheckArgIsString(3, aEnvironment, aStackTop);
1820     LispPtr evaluated(ARGUMENT(3));
1821 
1822     const LispString* orig = evaluated->String();
1823 
1824     LispPtr index(ARGUMENT(1));
1825     CheckArg(index, 1, aEnvironment, aStackTop);
1826     CheckArg(index->String(), 1, aEnvironment, aStackTop);
1827     const int sfrom = InternalAsciiToInt(*index->String());
1828     CheckArg(sfrom > 0, 1, aEnvironment, aStackTop);
1829     const std::size_t from = sfrom;
1830 
1831     index = (ARGUMENT(2));
1832     CheckArg(index, 2, aEnvironment, aStackTop);
1833     CheckArg(index->String(), 2, aEnvironment, aStackTop);
1834     const int scount = InternalAsciiToInt(*index->String());
1835     const std::size_t count = scount;
1836 
1837     std::string str = "\"";
1838     // FIXME: it's actually the set of args which is wrong, not the specific one
1839     CheckArg(from + count < orig->size(), 1, aEnvironment, aStackTop);
1840     for (std::size_t i = from; i < from + count; ++i)
1841         str.push_back((*orig)[i]);
1842     str.push_back('\"');
1843     RESULT = LispAtom::New(aEnvironment, str);
1844 }
1845 
YacasStringMidSet(LispEnvironment & aEnvironment,int aStackTop)1846 void YacasStringMidSet(LispEnvironment& aEnvironment, int aStackTop)
1847 {
1848     CheckArgIsString(3, aEnvironment, aStackTop);
1849     LispPtr evaluated(ARGUMENT(3));
1850     const LispString* orig = evaluated->String();
1851     LispPtr index(ARGUMENT(1));
1852     CheckArg(index, 1, aEnvironment, aStackTop);
1853     CheckArg(index->String(), 1, aEnvironment, aStackTop);
1854     const int sfrom = InternalAsciiToInt(*index->String());
1855     CheckArg(sfrom > 0, 1, aEnvironment, aStackTop);
1856     const std::size_t from = sfrom;
1857 
1858     LispPtr ev2(ARGUMENT(2));
1859     CheckArgIsString(2, aEnvironment, aStackTop);
1860     const LispString* replace = ev2->String();
1861 
1862     std::string str(*orig);
1863     const std::size_t count = replace->size();
1864     // FIXME: it's actually the set of args which is wrong, not the specific one
1865     CheckArg(from + count < orig->size() + 2, 1, aEnvironment, aStackTop);
1866 
1867     for (std::size_t i = 0; i < count - 2; ++i)
1868         str[i + from] = (*replace)[i + 1];
1869     RESULT = LispAtom::New(aEnvironment, str);
1870 }
1871 
LispFindFunction(LispEnvironment & aEnvironment,int aStackTop)1872 void LispFindFunction(LispEnvironment& aEnvironment, int aStackTop)
1873 {
1874     CheckSecure(aEnvironment, aStackTop);
1875 
1876     LispPtr evaluated(ARGUMENT(1));
1877 
1878     // Get file name
1879     CheckArg(evaluated, 1, aEnvironment, aStackTop);
1880     const LispString* orig = evaluated->String();
1881     CheckArg(orig, 1, aEnvironment, aStackTop);
1882     const std::string oper = InternalUnstringify(*orig);
1883 
1884     LispMultiUserFunction* multiUserFunc =
1885         aEnvironment.MultiUserFunction(aEnvironment.HashTable().LookUp(oper));
1886     if (multiUserFunc) {
1887         LispDefFile* def = multiUserFunc->iFileToOpen;
1888         if (def) {
1889             RESULT = LispAtom::New(aEnvironment, def->FileName());
1890             return;
1891         }
1892     }
1893 
1894     RESULT = LispAtom::New(aEnvironment, "\"\"");
1895 }
1896 
1897 /// Corresponds to the Yacas function \c PatternCreate .
1898 /// This function constructs a new PatternClass, and puts it in a new
1899 /// LispGenericObject. The result is set to this LispGenericObject.
GenPatternCreate(LispEnvironment & aEnvironment,int aStackTop)1900 void GenPatternCreate(LispEnvironment& aEnvironment, int aStackTop)
1901 {
1902     LispPtr pattern(ARGUMENT(1));
1903     LispPtr postpredicate(ARGUMENT(2));
1904 
1905     LispIterator iter(pattern);
1906     LispObject* pObj = iter.getObj();
1907     CheckArg(pObj, 1, aEnvironment, aStackTop);
1908     LispPtr* pPtr = pObj->SubList();
1909     CheckArg(pPtr, 1, aEnvironment, aStackTop);
1910     iter = *pPtr;
1911     CheckArg(iter.getObj(), 1, aEnvironment, aStackTop);
1912     ++iter;
1913 
1914     YacasPatternPredicateBase* matcher =
1915         new YacasPatternPredicateBase(aEnvironment, *iter, postpredicate);
1916     PatternClass* p = new PatternClass(matcher);
1917     RESULT = (LispGenericClass::New(p));
1918 }
1919 
GenPatternMatches(LispEnvironment & aEnvironment,int aStackTop)1920 void GenPatternMatches(LispEnvironment& aEnvironment, int aStackTop)
1921 {
1922     LispPtr pattern(ARGUMENT(1));
1923     GenericClass* gen = pattern->Generic();
1924     PatternClass* pat = dynamic_cast<PatternClass*>(gen);
1925     CheckArg(pat, 1, aEnvironment, aStackTop);
1926 
1927     LispPtr list(ARGUMENT(2));
1928 
1929     LispIterator iter(list);
1930     LispObject* pObj = iter.getObj();
1931     CheckArg(pObj, 2, aEnvironment, aStackTop);
1932     LispPtr* pPtr = pObj->SubList();
1933     CheckArg(pPtr, 2, aEnvironment, aStackTop);
1934     iter = *pPtr;
1935     CheckArg(iter.getObj(), 2, aEnvironment, aStackTop);
1936     ++iter;
1937 
1938     CheckArg(iter.getObj(), 2, aEnvironment, aStackTop);
1939     bool matches = pat->Matches(aEnvironment, *iter);
1940     InternalBoolean(aEnvironment, RESULT, matches);
1941 }
1942 
LispRuleBaseDefined(LispEnvironment & aEnvironment,int aStackTop)1943 void LispRuleBaseDefined(LispEnvironment& aEnvironment, int aStackTop)
1944 {
1945     LispPtr name(ARGUMENT(1));
1946     const LispString* orig = name->String();
1947     CheckArg(orig, 1, aEnvironment, aStackTop);
1948     const std::string oper = InternalUnstringify(*orig);
1949 
1950     LispPtr sizearg(ARGUMENT(2));
1951     CheckArg(sizearg, 2, aEnvironment, aStackTop);
1952     CheckArg(sizearg->String(), 2, aEnvironment, aStackTop);
1953 
1954     int arity = InternalAsciiToInt(*sizearg->String());
1955 
1956     LispUserFunction* userFunc =
1957         aEnvironment.UserFunction(aEnvironment.HashTable().LookUp(oper), arity);
1958     InternalBoolean(aEnvironment, RESULT, !!userFunc);
1959 }
1960 
LispDefLoadFunction(LispEnvironment & aEnvironment,int aStackTop)1961 void LispDefLoadFunction(LispEnvironment& aEnvironment, int aStackTop)
1962 {
1963     LispPtr name(ARGUMENT(1));
1964     const LispString* orig = name->String();
1965     CheckArg(orig, 1, aEnvironment, aStackTop);
1966     const std::string oper = InternalUnstringify(*orig);
1967 
1968     LispMultiUserFunction* multiUserFunc =
1969         aEnvironment.MultiUserFunction(aEnvironment.HashTable().LookUp(oper));
1970     if (multiUserFunc) {
1971         if (multiUserFunc->iFileToOpen != nullptr) {
1972             LispDefFile* def = multiUserFunc->iFileToOpen;
1973             if (!def->IsLoaded()) {
1974                 multiUserFunc->iFileToOpen = nullptr;
1975                 // InternalUse(aEnvironment, def->FileName());
1976             }
1977         }
1978     }
1979     InternalTrue(aEnvironment, RESULT);
1980 }
1981 
LispRuleBaseArgList(LispEnvironment & aEnvironment,int aStackTop)1982 void LispRuleBaseArgList(LispEnvironment& aEnvironment, int aStackTop)
1983 {
1984     LispPtr name(ARGUMENT(1));
1985     const LispString* orig = name->String();
1986     CheckArg(orig, 1, aEnvironment, aStackTop);
1987     const std::string oper = InternalUnstringify(*orig);
1988 
1989     LispPtr sizearg(ARGUMENT(2));
1990     CheckArg(sizearg, 2, aEnvironment, aStackTop);
1991     CheckArg(sizearg->String(), 2, aEnvironment, aStackTop);
1992 
1993     int arity = InternalAsciiToInt(*sizearg->String());
1994 
1995     LispUserFunction* userFunc =
1996         aEnvironment.UserFunction(aEnvironment.HashTable().LookUp(oper), arity);
1997     CheckArg(userFunc, 1, aEnvironment, aStackTop);
1998 
1999     const LispPtr& list = userFunc->ArgList();
2000     LispPtr head(aEnvironment.iList->Copy());
2001     head->Nixed() = (list);
2002     RESULT = (LispSubList::New(head));
2003 }
2004 
InternalNewRulePattern(LispEnvironment & aEnvironment,int aStackTop,bool aMacroMode)2005 static void InternalNewRulePattern(LispEnvironment& aEnvironment,
2006                                    int aStackTop,
2007                                    bool aMacroMode)
2008 {
2009     int arity;
2010     int precedence;
2011 
2012     LispPtr ar;
2013     LispPtr pr;
2014     LispPtr predicate;
2015     LispPtr body;
2016 
2017     // Get operator
2018     CheckArg(ARGUMENT(1), 1, aEnvironment, aStackTop);
2019     const LispString* orig = ARGUMENT(1)->String();
2020     CheckArg(orig, 1, aEnvironment, aStackTop);
2021     ar = (ARGUMENT(2));
2022     pr = (ARGUMENT(3));
2023     predicate = (ARGUMENT(4));
2024     body = (ARGUMENT(5));
2025 
2026     // The arity
2027     CheckArg(ar, 2, aEnvironment, aStackTop);
2028     CheckArg(ar->String(), 2, aEnvironment, aStackTop);
2029     arity = InternalAsciiToInt(*ar->String());
2030 
2031     // The precedence
2032     CheckArg(ar, 3, aEnvironment, aStackTop);
2033     CheckArg(ar->String(), 3, aEnvironment, aStackTop);
2034     precedence = InternalAsciiToInt(*pr->String());
2035 
2036     // Finally define the rule base
2037     aEnvironment.DefineRulePattern(
2038         SymbolName(aEnvironment, *orig), arity, precedence, predicate, body);
2039 
2040     // Return true
2041     InternalTrue(aEnvironment, RESULT);
2042 }
2043 
LispNewRulePattern(LispEnvironment & aEnvironment,int aStackTop)2044 void LispNewRulePattern(LispEnvironment& aEnvironment, int aStackTop)
2045 {
2046     InternalNewRulePattern(aEnvironment, aStackTop, false);
2047 }
2048 
LispMacroNewRulePattern(LispEnvironment & aEnvironment,int aStackTop)2049 void LispMacroNewRulePattern(LispEnvironment& aEnvironment, int aStackTop)
2050 {
2051     InternalNewRulePattern(aEnvironment, aStackTop, true);
2052 }
2053