UNPKG

14.3 kBtext/coffeescriptView Raw
1# Evaluate an expression, for example...
2#
3# push(p1)
4# Eval()
5# p2 = pop()
6
7
8
9Eval = ->
10 check_esc_flag()
11 save()
12 p1 = pop()
13 if !p1?
14 debugger
15
16 if !evaluatingAsFloats and isfloating(p1)
17 willEvaluateAsFloats = true
18 evaluatingAsFloats++
19
20 switch (p1.k)
21 when CONS
22 Eval_cons()
23 when NUM
24 if evaluatingAsFloats
25 push_double(convert_rational_to_double(p1))
26 else
27 push(p1)
28 when DOUBLE, STR
29 push(p1)
30 when TENSOR
31 Eval_tensor()
32 when SYM
33 Eval_sym()
34 else
35 stop("atom?")
36
37 if willEvaluateAsFloats
38 evaluatingAsFloats--
39
40 restore()
41
42Eval_sym = ->
43
44 # note that function calls are not processed here
45 # because, since they have an argument (at least an empty one)
46 # they are actually CONs, which is a branch of the
47 # switch before the one that calls this function
48
49 # bare keyword?
50 # If it's a keyword, then we don't look
51 # at the binding array, because keywords
52 # are not redefinable.
53 if (iskeyword(p1))
54 push(p1)
55 push(symbol(LAST))
56 list(2)
57 Eval()
58 return
59 else if (p1 == symbol(PI) and evaluatingAsFloats)
60 push_double(Math.PI)
61 return
62
63 # Evaluate symbol's binding
64 p2 = get_binding(p1)
65 if DEBUG then console.log "looked up: " + p1 + " which contains: " + p2
66
67 push(p2)
68
69
70 # differently from standard Lisp,
71 # here the evaluation is not
72 # one-step only, rather it keeps evaluating
73 # "all the way" until a symbol is
74 # defined as itself.
75 # Uncomment these two lines to get Lisp
76 # behaviour (and break most tests)
77 if (p1 != p2)
78
79 # detect recursive lookup of symbols, which would otherwise
80 # cause a stack overflow.
81 # Note that recursive functions will still work because
82 # as mentioned at the top, this method doesn't look
83 # up and evaluate function calls.
84 positionIfSymbolAlreadyBeingEvaluated = chainOfUserSymbolsNotFunctionsBeingEvaluated.indexOf(p1)
85 if positionIfSymbolAlreadyBeingEvaluated != -1
86 cycleString = ""
87 for i in [positionIfSymbolAlreadyBeingEvaluated...chainOfUserSymbolsNotFunctionsBeingEvaluated.length]
88 cycleString += chainOfUserSymbolsNotFunctionsBeingEvaluated[i].printname + " -> "
89 cycleString += p1.printname
90
91 stop("recursive evaluation of symbols: " + cycleString)
92 return
93
94 chainOfUserSymbolsNotFunctionsBeingEvaluated.push(p1)
95
96
97 Eval()
98
99 chainOfUserSymbolsNotFunctionsBeingEvaluated.pop()
100
101Eval_cons = ->
102
103 cons_head = car(p1)
104
105 # normally the cons_head is a symbol,
106 # but sometimes in the case of
107 # functions we don't have a symbol,
108 # we have to evaluate something to get to the
109 # symbol. For example if a function is inside
110 # a tensor, then we need to evaluate an index
111 # access first to get to the function.
112 # In those cases, we find an EVAL here,
113 # so we proceed to EVAL
114 if car(cons_head) == symbol(EVAL)
115 Eval_user_function()
116 return
117
118 # If we didn't fall in the EVAL case above
119 # then at this point we must have a symbol.
120 if (!issymbol(cons_head))
121 stop("cons?")
122
123 switch (symnum(cons_head))
124 when ABS then Eval_abs()
125 when ADD then Eval_add()
126 when ADJ then Eval_adj()
127 when AND then Eval_and()
128 when ARCCOS then Eval_arccos()
129 when ARCCOSH then Eval_arccosh()
130 when ARCSIN then Eval_arcsin()
131 when ARCSINH then Eval_arcsinh()
132 when ARCTAN then Eval_arctan()
133 when ARCTANH then Eval_arctanh()
134 when ARG then Eval_arg()
135 when ATOMIZE then Eval_atomize()
136 when BESSELJ then Eval_besselj()
137 when BESSELY then Eval_bessely()
138 when BINDING then Eval_binding()
139 when BINOMIAL then Eval_binomial()
140 when CEILING then Eval_ceiling()
141 when CHECK then Eval_check()
142 when CHOOSE then Eval_choose()
143 when CIRCEXP then Eval_circexp()
144 when CLEAR then Eval_clear()
145 when CLEARALL then Eval_clearall()
146 when CLEARPATTERNS then Eval_clearpatterns()
147 when CLOCK then Eval_clock()
148 when COEFF then Eval_coeff()
149 when COFACTOR then Eval_cofactor()
150 when CONDENSE then Eval_condense()
151 when CONJ then Eval_conj()
152 when CONTRACT then Eval_contract()
153 when COS then Eval_cos()
154 when COSH then Eval_cosh()
155 when DECOMP then Eval_decomp()
156 when DEGREE then Eval_degree()
157 when DEFINT then Eval_defint()
158 when DENOMINATOR then Eval_denominator()
159 when DERIVATIVE then Eval_derivative()
160 when DET then Eval_det()
161 when DIM then Eval_dim()
162 when DIRAC then Eval_dirac()
163 when DIVISORS then Eval_divisors()
164 when DO then Eval_do()
165 when DOT then Eval_inner()
166 when DRAW then Eval_draw()
167 when DSOLVE then Eval_dsolve()
168 when EIGEN then Eval_eigen()
169 when EIGENVAL then Eval_eigenval()
170 when EIGENVEC then Eval_eigenvec()
171 when ERF then Eval_erf()
172 when ERFC then Eval_erfc()
173 when EVAL then Eval_Eval()
174 when EXP then Eval_exp()
175 when EXPAND then Eval_expand()
176 when EXPCOS then Eval_expcos()
177 when EXPSIN then Eval_expsin()
178 when FACTOR then Eval_factor()
179 when FACTORIAL then Eval_factorial()
180 when FACTORPOLY then Eval_factorpoly()
181 when FILTER then Eval_filter()
182 when FLOATF then Eval_float()
183 when APPROXRATIO then Eval_approxratio()
184 when FLOOR then Eval_floor()
185 when FOR then Eval_for()
186 # this is invoked only when we
187 # evaluate a function that is NOT being called
188 # e.g. when f is a function as we do
189 # g = f
190 when FUNCTION then Eval_function_reference()
191 when GAMMA then Eval_gamma()
192 when GCD then Eval_gcd()
193 when HERMITE then Eval_hermite()
194 when HILBERT then Eval_hilbert()
195 when IMAG then Eval_imag()
196 when INDEX then Eval_index()
197 when INNER then Eval_inner()
198 when INTEGRAL then Eval_integral()
199 when INV then Eval_inv()
200 when INVG then Eval_invg()
201 when ISINTEGER then Eval_isinteger()
202 when ISPRIME then Eval_isprime()
203 when LAGUERRE then Eval_laguerre()
204 # when LAPLACE then Eval_laplace()
205 when LCM then Eval_lcm()
206 when LEADING then Eval_leading()
207 when LEGENDRE then Eval_legendre()
208 when LOG then Eval_log()
209 when LOOKUP then Eval_lookup()
210 when MOD then Eval_mod()
211 when MULTIPLY then Eval_multiply()
212 when NOT then Eval_not()
213 when NROOTS then Eval_nroots()
214 when NUMBER then Eval_number()
215 when NUMERATOR then Eval_numerator()
216 when OPERATOR then Eval_operator()
217 when OR then Eval_or()
218 when OUTER then Eval_outer()
219 when PATTERN then Eval_pattern()
220 when PATTERNSINFO then Eval_patternsinfo()
221 when POLAR then Eval_polar()
222 when POWER then Eval_power()
223 when PRIME then Eval_prime()
224 when PRINT then Eval_print()
225 when PRINT2DASCII then Eval_print2dascii()
226 when PRINTFULL then Eval_printfull()
227 when PRINTLATEX then Eval_printlatex()
228 when PRINTLIST then Eval_printlist()
229 when PRINTPLAIN then Eval_printplain()
230 when PRODUCT then Eval_product()
231 when QUOTE then Eval_quote()
232 when QUOTIENT then Eval_quotient()
233 when RANK then Eval_rank()
234 when RATIONALIZE then Eval_rationalize()
235 when REAL then Eval_real()
236 when ROUND then Eval_round()
237 when YYRECT then Eval_rect()
238 when ROOTS then Eval_roots()
239 when SETQ then Eval_setq()
240 when SGN then Eval_sgn()
241 when SILENTPATTERN then Eval_silentpattern()
242 when SIMPLIFY then Eval_simplify()
243 when SIN then Eval_sin()
244 when SINH then Eval_sinh()
245 when SHAPE then Eval_shape()
246 when SQRT then Eval_sqrt()
247 when STOP then Eval_stop()
248 when SUBST then Eval_subst()
249 when SUM then Eval_sum()
250 when SYMBOLSINFO then Eval_symbolsinfo()
251 when TAN then Eval_tan()
252 when TANH then Eval_tanh()
253 when TAYLOR then Eval_taylor()
254 when TEST then Eval_test()
255 when TESTEQ then Eval_testeq()
256 when TESTGE then Eval_testge()
257 when TESTGT then Eval_testgt()
258 when TESTLE then Eval_testle()
259 when TESTLT then Eval_testlt()
260 when TRANSPOSE then Eval_transpose()
261 when UNIT then Eval_unit()
262 when ZERO then Eval_zero()
263 else
264 Eval_user_function()
265
266Eval_binding = ->
267 push(get_binding(cadr(p1)))
268
269### check =====================================================================
270
271Tags
272----
273scripting, JS, internal, treenode, general concept
274
275Parameters
276----------
277p
278
279General description
280-------------------
281Checks the predicate p, e.g. check(a = b)
282Note how "check" can turn what normally would be an assignment into a test,
283so in the case above "a" is not assigned anything.
284
285###
286
287# check definition
288Eval_check = ->
289 push(cadr(p1))
290 Eval_predicate()
291 p1 = pop()
292 push(p1)
293
294Eval_det = ->
295 push(cadr(p1))
296 Eval()
297 det()
298
299
300### dim =====================================================================
301
302Tags
303----
304scripting, JS, internal, treenode, general concept
305
306Parameters
307----------
308m,n
309
310General description
311-------------------
312Returns the cardinality of the nth index of tensor "m".
313
314###
315
316Eval_dim = ->
317 #int n
318 push(cadr(p1))
319 Eval()
320 p2 = pop()
321 if (iscons(cddr(p1)))
322 push(caddr(p1))
323 Eval()
324 n = pop_integer()
325 else
326 n = 1
327 if (!istensor(p2))
328 push_integer(1) # dim of scalar is 1
329 else if (n < 1 || n > p2.tensor.ndim)
330 push(p1)
331 else
332 push_integer(p2.tensor.dim[n - 1])
333
334Eval_divisors = ->
335 push(cadr(p1))
336 Eval()
337 divisors()
338
339### do =====================================================================
340
341Tags
342----
343scripting, JS, internal, treenode, general concept
344
345Parameters
346----------
347a,b,...
348
349General description
350-------------------
351Evaluates each argument from left to right. Returns the result of the last argument.
352
353###
354
355Eval_do = ->
356 push(car(p1))
357 p1 = cdr(p1)
358 while (iscons(p1))
359 pop()
360 push(car(p1))
361 Eval()
362 p1 = cdr(p1)
363
364Eval_dsolve = ->
365 push(cadr(p1))
366 Eval()
367 push(caddr(p1))
368 Eval()
369 push(cadddr(p1))
370 Eval()
371 dsolve()
372
373# for example, Eval(f,x,2)
374
375Eval_Eval = ->
376 push(cadr(p1))
377 Eval()
378 p1 = cddr(p1)
379 while (iscons(p1))
380 push(car(p1))
381 Eval()
382 push(cadr(p1))
383 Eval()
384 subst()
385 p1 = cddr(p1)
386 Eval()
387
388# exp evaluation: it replaces itself with
389# a POWER(E,something) node and evals that one
390Eval_exp = ->
391 push(cadr(p1))
392 Eval()
393 exponential()
394
395Eval_factorial = ->
396 push(cadr(p1))
397 Eval()
398 factorial()
399
400Eval_factorpoly = ->
401 p1 = cdr(p1)
402 push(car(p1))
403 Eval()
404 p1 = cdr(p1)
405 push(car(p1))
406 Eval()
407 factorpoly()
408 p1 = cdr(p1)
409 while (iscons(p1))
410 push(car(p1))
411 Eval()
412 factorpoly()
413 p1 = cdr(p1)
414
415Eval_hermite = ->
416 push(cadr(p1))
417 Eval()
418 push(caddr(p1))
419 Eval()
420 hermite()
421
422Eval_hilbert = ->
423 push(cadr(p1))
424 Eval()
425 hilbert()
426
427Eval_index = ->
428 h = tos
429 orig = p1
430
431 # look into the head of the list,
432 # when evaluated it should be a tensor
433 p1 = cdr(p1)
434 push car(p1)
435 Eval()
436 theTensor = stack[tos-1]
437
438 if isnum(theTensor)
439 stop("trying to access a scalar as a tensor")
440
441 if !istensor(theTensor)
442 # the tensor is not allocated yet, so
443 # leaving the expression unevalled
444 moveTos h
445 push orig
446 return
447
448 # we examined the head of the list which
449 # was the tensor, now look into
450 # the indexes
451 p1 = cdr(p1)
452 while (iscons(p1))
453 push(car(p1))
454 Eval()
455 if !isintegerorintegerfloat(stack[tos-1])
456 # index with something other than
457 # an integer
458 moveTos h
459 push orig
460 return
461 p1 = cdr(p1)
462 index_function(tos - h)
463
464Eval_inv = ->
465 push(cadr(p1))
466 Eval()
467 inv()
468
469Eval_invg = ->
470 push(cadr(p1))
471 Eval()
472 invg()
473
474Eval_isinteger = ->
475 push(cadr(p1))
476 Eval()
477 p1 = pop()
478 if (isrational(p1))
479 if (isinteger(p1))
480 push(one)
481 else
482 push(zero)
483 return
484 if (isdouble(p1))
485 n = Math.floor(p1.d)
486 if (n == p1.d)
487 push(one)
488 else
489 push(zero)
490 return
491 push_symbol(ISINTEGER)
492 push(p1)
493 list(2)
494
495Eval_number = ->
496 push(cadr(p1))
497 Eval()
498 p1 = pop()
499 if (p1.k == NUM || p1.k == DOUBLE)
500 push_integer(1)
501 else
502 push_integer(0)
503
504Eval_operator = ->
505 h = tos
506 push_symbol(OPERATOR)
507 p1 = cdr(p1)
508 while (iscons(p1))
509 push(car(p1))
510 Eval()
511 p1 = cdr(p1)
512 list(tos - h)
513
514# quote definition
515Eval_quote = ->
516 push(cadr(p1))
517
518# rank definition
519Eval_rank = ->
520 push(cadr(p1))
521 Eval()
522 p1 = pop()
523 if (istensor(p1))
524 push_integer(p1.tensor.ndim)
525 else
526 push(zero)
527
528# Evaluates the right side and assigns the
529# result of the evaluation to the left side.
530# It's called setq because it stands for "set quoted" from Lisp,
531# see:
532# http://stackoverflow.com/questions/869529/difference-between-set-setq-and-setf-in-common-lisp
533
534# Example:
535# f = x
536# // f evaluates to x, so x is assigned to g really
537# // rather than actually f being assigned to g
538# g = f
539# f = y
540# g
541# > x
542
543Eval_setq = ->
544 # case of array
545 if (caadr(p1) == symbol(INDEX))
546 setq_indexed()
547 return
548
549 # case of function definition
550 if (iscons(cadr(p1)))
551 define_user_function()
552 return
553
554 if (!issymbol(cadr(p1)))
555 stop("symbol assignment: error in symbol")
556
557 push(caddr(p1))
558 Eval()
559 p2 = pop()
560 set_binding(cadr(p1), p2)
561
562 push(symbol(NIL))
563
564# Here "setq" is a misnomer because
565# setq wouldn't work in Lisp to set array elements
566# since setq stands for "set quoted" and you wouldn't
567# quote an array element access.
568# You'd rather use setf, which is a macro that can
569# assign a value to anything.
570# (setf (aref YourArray 2) "blue")
571# see
572# http://stackoverflow.com/questions/18062016/common-lisp-how-to-set-an-element-in-a-2d-array
573#-----------------------------------------------------------------------------
574#
575# Example: a[1] = b
576#
577# p1 *-------*-----------------------*
578# | | |
579# setq *-------*-------* b
580# | | |
581# index a 1
582#
583# cadadr(p1) -> a
584#
585#-----------------------------------------------------------------------------
586
587setq_indexed = ->
588 p4 = cadadr(p1)
589 if (!issymbol(p4))
590 stop("indexed assignment: error in symbol")
591 h = tos
592 push(caddr(p1))
593 Eval()
594 p2 = cdadr(p1)
595 while (iscons(p2))
596 push(car(p2))
597 Eval()
598 p2 = cdr(p2)
599 set_component(tos - h)
600 p3 = pop()
601 set_binding(p4, p3)
602 push(symbol(NIL))
603
604
605Eval_sqrt = ->
606 push(cadr(p1))
607 Eval()
608 push_rational(1, 2)
609 power()
610
611Eval_stop = ->
612 stop("user stop")
613
614Eval_subst = ->
615 push(cadddr(p1))
616 Eval()
617 push(caddr(p1))
618 Eval()
619 push(cadr(p1))
620 Eval()
621 subst()
622 Eval() # normalize
623
624# always returns a matrix with rank 2
625# i.e. two dimensions,
626# the passed parameter is the size
627Eval_unit = ->
628 i = 0
629 n = 0
630 push(cadr(p1))
631 Eval()
632 n = pop_integer()
633
634 if isNaN(n)
635 push(p1)
636 return
637
638 if (n < 1)
639 push(p1)
640 return
641
642 p1 = alloc_tensor(n * n)
643 p1.tensor.ndim = 2
644 p1.tensor.dim[0] = n
645 p1.tensor.dim[1] = n
646 for i in [0...n]
647 p1.tensor.elem[n * i + i] = one
648 check_tensor_dimensions p1
649 push(p1)
650
651Eval_noexpand = ->
652 prev_expanding = expanding
653 expanding = 0
654 Eval()
655 expanding = prev_expanding
656
657# like Eval() except "=" (assignment) is treated
658# as "==" (equality test)
659
660Eval_predicate = ->
661 save()
662 p1 = top()
663 if (car(p1) == symbol(SETQ))
664 # replace the assignment in the
665 # head with an equality test
666 pop()
667 push_symbol(TESTEQ)
668 push cadr(p1)
669 push caddr(p1)
670 list 3
671
672 Eval()
673 restore()