altos/scheme: Support scheme subsetting via feature settings
[fw/altos] / src / scheme / ao_scheme_const.scheme
1 ;
2 ; Copyright © 2016 Keith Packard <keithp@keithp.com>
3 ;
4 ; This program is free software; you can redistribute it and/or modify
5 ; it under the terms of the GNU General Public License as published by
6 ; the Free Software Foundation, either version 2 of the License, or
7 ; (at your option) any later version.
8 ;
9 ; This program is distributed in the hope that it will be useful, but
10 ; WITHOUT ANY WARRANTY; without even the implied warranty of
11 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 ; General Public License for more details.
13 ;
14 ; Lisp code placed in ROM
15
16                                         ; return a list containing all of the arguments
17 (def (quote list) (lambda l l))
18
19 (def (quote def!)
20      (macro (name value)
21             (list
22              def
23              (list quote name)
24              value)
25             )
26      )
27
28 (begin
29  (def! append
30    (lambda args
31           (def! append-list
32             (lambda (a b)
33               (cond ((null? a) b)
34                     (else (cons (car a) (append-list (cdr a) b)))
35                     )
36               )
37             )
38             
39           (def! append-lists
40             (lambda (lists)
41               (cond ((null? lists) lists)
42                     ((null? (cdr lists)) (car lists))
43                     (else (append-list (car lists) (append-lists (cdr lists))))
44                     )
45               )
46             )
47           (append-lists args)
48           )
49    )
50  'append)
51
52 (append '(a b c) '(d e f) '(g h i))
53
54                                         ; boolean operators
55
56 (begin
57  (def! or
58    (macro l
59           (def! _or
60             (lambda (l)
61               (cond ((null? l) #f)
62                     ((null? (cdr l))
63                      (car l))
64                     (else
65                      (list
66                       cond
67                       (list
68                        (car l))
69                       (list
70                        'else
71                        (_or (cdr l))
72                        )
73                       )
74                      )
75                     )
76               )
77             )
78           (_or l)))
79  'or)
80
81                                         ; execute to resolve macros
82
83 (or #f #t)
84
85 (begin
86  (def! and
87    (macro l
88           (def! _and
89             (lambda (l)
90               (cond ((null? l) #t)
91                     ((null? (cdr l))
92                      (car l))
93                     (else
94                      (list
95                       cond
96                       (list
97                        (car l)
98                        (_and (cdr l))
99                        )
100                       )
101                      )
102                     )
103               )
104             )
105           (_and l)
106           )
107    )
108  'and)
109
110                                         ; execute to resolve macros
111
112 (and #t #f)
113
114 (begin
115  (def! quasiquote
116    (macro (x)
117           (def! constant?
118                                         ; A constant value is either a pair starting with quote,
119                                         ; or anything which is neither a pair nor a symbol
120
121             (lambda (exp)
122               (cond ((pair? exp)
123                      (eq? (car exp) 'quote)
124                      )
125                     (else
126                      (not (symbol? exp))
127                      )
128                     )
129               )
130             )
131           (def! combine-skeletons
132             (lambda (left right exp)
133               (cond
134                ((and (constant? left) (constant? right)) 
135                 (cond ((and (eqv? (eval left) (car exp))
136                             (eqv? (eval right) (cdr exp)))
137                        (list 'quote exp)
138                        )
139                       (else
140                        (list 'quote (cons (eval left) (eval right)))
141                        )
142                       )
143                 )
144                ((null? right)
145                 (list 'list left)
146                 )
147                ((and (pair? right) (eq? (car right) 'list))
148                 (cons 'list (cons left (cdr right)))
149                 )
150                (else
151                 (list 'cons left right)
152                 )
153                )
154               )
155             )
156
157           (def! expand-quasiquote
158             (lambda (exp nesting)
159               (cond
160
161                                         ; non cons -- constants
162                                         ; themselves, others are
163                                         ; quoted
164
165                ((not (pair? exp)) 
166                 (cond ((constant? exp)
167                        exp
168                        )
169                       (else
170                        (list 'quote exp)
171                        )
172                       )
173                 )
174
175                                         ; check for an unquote exp and
176                                         ; add the param unquoted
177
178                ((and (eq? (car exp) 'unquote) (= (length exp) 2))
179                 (cond ((= nesting 0)
180                        (car (cdr exp))
181                        )
182                       (else
183                        (combine-skeletons ''unquote 
184                                           (expand-quasiquote (cdr exp) (- nesting 1))
185                                           exp))
186                       )
187                 )
188
189                                         ; nested quasi-quote --
190                                         ; construct the right
191                                         ; expression
192
193                ((and (eq? (car exp) 'quasiquote) (= (length exp) 2))
194                 (combine-skeletons ''quasiquote 
195                                    (expand-quasiquote (cdr exp) (+ nesting 1))
196                                    exp))
197
198                                         ; check for an
199                                         ; unquote-splicing member,
200                                         ; compute the expansion of the
201                                         ; value and append the rest of
202                                         ; the quasiquote result to it
203
204                ((and (pair? (car exp))
205                      (eq? (car (car exp)) 'unquote-splicing)
206                      (= (length (car exp)) 2))
207                 (cond ((= nesting 0)
208                        (list 'append (car (cdr (car exp)))
209                              (expand-quasiquote (cdr exp) nesting))
210                        )
211                       (else
212                        (combine-skeletons (expand-quasiquote (car exp) (- nesting 1))
213                                           (expand-quasiquote (cdr exp) nesting)
214                                           exp))
215                       )
216                 )
217
218                                         ; for other lists, just glue
219                                         ; the expansion of the first
220                                         ; element to the expansion of
221                                         ; the rest of the list
222
223                (else (combine-skeletons (expand-quasiquote (car exp) nesting)
224                                         (expand-quasiquote (cdr exp) nesting)
225                                         exp)
226                      )
227                )
228               )
229             )
230           (def! result (expand-quasiquote x 0))
231           result
232           )
233    )
234  'quasiquote)
235
236                                         ;
237                                         ; Define a variable without returning the value
238                                         ; Useful when defining functions to avoid
239                                         ; having lots of output generated.
240                                         ;
241                                         ; Also accepts the alternate
242                                         ; form for defining lambdas of
243                                         ; (define (name x y z) sexprs ...) 
244                                         ;
245
246 (begin
247  (def! define
248    (macro (first . rest)
249                                         ; check for alternate lambda definition form
250
251           (cond ((list? first)
252                  (set! rest
253                        (append
254                         (list
255                          'lambda
256                          (cdr first))
257                         rest))
258                  (set! first (car first))
259                  )
260                 (else
261                  (set! rest (car rest))
262                  )
263                 )
264           (def! result `(,begin
265                          (,def (,quote ,first) ,rest)
266                          (,quote ,first))
267             )
268           result
269           )
270    )
271  'define
272  )
273
274                                         ; basic list accessors
275
276 (define (caar l) (car (car l)))
277
278 (define (cadr l) (car (cdr l)))
279
280 (define (cdar l) (cdr (car l)))
281
282 (define (caddr l) (car (cdr (cdr l))))
283
284                                         ; (if <condition> <if-true>)
285                                         ; (if <condition> <if-true> <if-false)
286
287 (define if
288   (macro (test . args)
289          (cond ((null? (cdr args))
290                 `(cond (,test ,(car args)))
291                 )
292                (else
293                 `(cond (,test ,(car args))
294                        (else ,(cadr args)))
295                 )
296                )
297          )
298   )
299
300 (if (> 3 2) 'yes)
301 (if (> 3 2) 'yes 'no)
302 (if (> 2 3) 'no 'yes)
303 (if (> 2 3) 'no)
304
305                                         ; simple math operators
306
307 (define zero? (macro (value) `(eq? ,value 0)))
308
309 (zero? 1)
310 (zero? 0)
311 (zero? "hello")
312
313 (define positive? (macro (value) `(> ,value 0)))
314
315 (positive? 12)
316 (positive? -12)
317
318 (define negative? (macro (value) `(< ,value 0)))
319
320 (negative? 12)
321 (negative? -12)
322
323 (define (abs x) (if (>= x 0) x (- x)))
324
325 (abs 12)
326 (abs -12)
327
328 (define max (lambda (first . rest)
329                    (while (not (null? rest))
330                      (cond ((< first (car rest))
331                             (set! first (car rest)))
332                            )
333                      (set! rest (cdr rest))
334                      )
335                    first)
336   )
337
338 (max 1 2 3)
339 (max 3 2 1)
340
341 (define min (lambda (first . rest)
342                    (while (not (null? rest))
343                      (cond ((> first (car rest))
344                             (set! first (car rest)))
345                            )
346                      (set! rest (cdr rest))
347                      )
348                    first)
349   )
350
351 (min 1 2 3)
352 (min 3 2 1)
353
354 (define (even? x) (zero? (% x 2)))
355
356 (even? 2)
357 (even? -2)
358 (even? 3)
359 (even? -1)
360
361 (define (odd? x) (not (even? x)))
362
363 (odd? 2)
364 (odd? -2)
365 (odd? 3)
366 (odd? -1)
367
368
369 (define (list-tail x k)
370   (if (zero? k)
371       x
372     (list-tail (cdr x (- k 1)))
373     )
374   )
375
376 (define (list-ref x k)
377   (car (list-tail x k))
378   )
379
380                                         ; define a set of local
381                                         ; variables all at once and
382                                         ; then evaluate a list of
383                                         ; sexprs
384                                         ;
385                                         ; (let (var-defines) sexprs)
386                                         ;
387                                         ; where var-defines are either
388                                         ;
389                                         ; (name value)
390                                         ;
391                                         ; or
392                                         ;
393                                         ; (name)
394                                         ;
395                                         ; e.g.
396                                         ;
397                                         ; (let ((x 1) (y)) (set! y (+ x 1)) y)
398
399 (define let
400   (macro (vars . exprs)
401          (define (make-names vars)
402            (cond ((not (null? vars))
403                   (cons (car (car vars))
404                         (make-names (cdr vars))))
405                  (else ())
406                  )
407            )
408
409                                         ; the parameters to the lambda is a list
410                                         ; of nils of the right length
411
412          (define (make-vals vars)
413            (cond ((not (null? vars))
414                   (cons (cond ((null? (cdr (car vars))) ())
415                               (else
416                                (car (cdr (car vars))))
417                               )
418                         (make-vals (cdr vars))))
419                  (else ())
420                  )
421            )
422                                         ; prepend the set operations
423                                         ; to the expressions
424
425                                         ; build the lambda.
426
427          `((lambda ,(make-names vars) ,@exprs) ,@(make-vals vars))
428          )
429      )
430                    
431
432 (let ((x 1) (y)) (set! y 2) (+ x y))
433
434                                         ; define a set of local
435                                         ; variables one at a time and
436                                         ; then evaluate a list of
437                                         ; sexprs
438                                         ;
439                                         ; (let* (var-defines) sexprs)
440                                         ;
441                                         ; where var-defines are either
442                                         ;
443                                         ; (name value)
444                                         ;
445                                         ; or
446                                         ;
447                                         ; (name)
448                                         ;
449                                         ; e.g.
450                                         ;
451                                         ; (let* ((x 1) (y)) (set! y (+ x 1)) y)
452
453 (define let*
454   (macro (vars . exprs)
455
456                                         ;
457                                         ; make the list of names in the let
458                                         ;
459
460          (define (make-names vars)
461            (cond ((not (null? vars))
462                   (cons (car (car vars))
463                         (make-names (cdr vars))))
464                  (else ())
465                  )
466            )
467
468                                         ; the set of expressions is
469                                         ; the list of set expressions
470                                         ; pre-pended to the
471                                         ; expressions to evaluate
472
473          (define (make-exprs vars exprs)
474            (cond ((null? vars) exprs)
475                  (else
476                   (cons
477                    (list set
478                          (list quote
479                                (car (car vars))
480                                )
481                          (cond ((null? (cdr (car vars))) ())
482                                (else (cadr (car vars))))
483                          )
484                    (make-exprs (cdr vars) exprs)
485                    )
486                   )
487                  )
488            )
489
490                                         ; the parameters to the lambda is a list
491                                         ; of nils of the right length
492
493          (define (make-nils vars)
494            (cond ((null? vars) ())
495                  (else (cons () (make-nils (cdr vars))))
496                  )
497            )
498                                         ; build the lambda.
499
500          `((lambda ,(make-names vars) ,@(make-exprs vars exprs)) ,@(make-nils vars))
501          )
502      )
503
504 (let* ((x 1) (y x)) (+ x y))
505
506 (define when (macro (test . l) `(cond (,test ,@l))))
507
508 (when #t (write 'when))
509
510 (define unless (macro (test . l) `(cond ((not ,test) ,@l))))
511
512 (unless #f (write 'unless))
513
514 (define (reverse list)
515   (let ((result ()))
516     (while (not (null? list))
517       (set! result (cons (car list) result))
518       (set! list (cdr list))
519       )
520     result)
521   )
522
523 (reverse '(1 2 3))
524
525 (define (list-tail x k)
526   (if (zero? k)
527       x
528     (list-tail (cdr x) (- k 1))))
529
530 (list-tail '(1 2 3) 2)
531
532 (define (list-ref x k) (car (list-tail x k)))
533
534 (list-ref '(1 2 3) 2)
535     
536                                         ; recursive equality
537
538 (define (equal? a b)
539   (cond ((eq? a b) #t)
540         ((and (pair? a) (pair? b))
541          (and (equal? (car a) (car b))
542               (equal? (cdr a) (cdr b)))
543          )
544         (else #f)
545         )
546   )
547
548 (equal? '(a b c) '(a b c))
549 (equal? '(a b c) '(a b b))
550
551 (define member (lambda (obj list . test?)
552                       (cond ((null? list)
553                              #f
554                              )
555                             (else
556                              (if (null? test?) (set! test? equal?) (set! test? (car test?)))
557                              (if (test? obj (car list))
558                                  list
559                                (member obj (cdr list) test?))
560                              )
561                             )
562                       )
563   )
564
565 (member '(2) '((1) (2) (3)))
566
567 (member '(4) '((1) (2) (3)))
568
569 (define (memq obj list) (member obj list eq?))
570
571 (memq 2 '(1 2 3))
572
573 (memq 4 '(1 2 3))
574
575 (memq '(2) '((1) (2) (3)))
576
577 (define (memv obj list) (member obj list eqv?))
578
579 (memv 2 '(1 2 3))
580
581 (memv 4 '(1 2 3))
582
583 (memv '(2) '((1) (2) (3)))
584
585 (define (_assoc obj list test?)
586   (if (null? list)
587       #f
588     (if (test? obj (caar list))
589         (car list)
590       (_assoc obj (cdr list) test?)
591       )
592     )
593   )
594
595 (define (assq obj list) (_assoc obj list eq?))
596 (define (assv obj list) (_assoc obj list eqv?))
597 (define (assoc obj list) (_assoc obj list equal?))
598
599 (assq 'a '((a 1) (b 2) (c 3)))
600 (assv 'b '((a 1) (b 2) (c 3)))
601 (assoc '(c) '((a 1) (b 2) ((c) 3)))
602
603 (define char? integer?)
604
605 (char? #\q)
606 (char? "h")
607
608 (define (char-upper-case? c) (<= #\A c #\Z))
609
610 (char-upper-case? #\a)
611 (char-upper-case? #\B)
612 (char-upper-case? #\0)
613 (char-upper-case? #\space)
614
615 (define (char-lower-case? c) (<= #\a c #\a))
616
617 (char-lower-case? #\a)
618 (char-lower-case? #\B)
619 (char-lower-case? #\0)
620 (char-lower-case? #\space)
621
622 (define (char-alphabetic? c) (or (char-upper-case? c) (char-lower-case? c)))
623
624 (char-alphabetic? #\a)
625 (char-alphabetic? #\B)
626 (char-alphabetic? #\0)
627 (char-alphabetic? #\space)
628
629 (define (char-numeric? c) (<= #\0 c #\9))
630
631 (char-numeric? #\a)
632 (char-numeric? #\B)
633 (char-numeric? #\0)
634 (char-numeric? #\space)
635
636 (define (char-whitespace? c) (or (<= #\tab c #\return) (= #\space c)))
637
638 (char-whitespace? #\a)
639 (char-whitespace? #\B)
640 (char-whitespace? #\0)
641 (char-whitespace? #\space)
642
643 (define (char->integer c) c)
644 (define integer->char char->integer)
645
646 (define (char-upcase c) (if (char-lower-case? c) (+ c (- #\A #\a)) c))
647
648 (char-upcase #\a)
649 (char-upcase #\B)
650 (char-upcase #\0)
651 (char-upcase #\space)
652
653 (define (char-downcase c) (if (char-upper-case? c) (+ c (- #\a #\A)) c))
654
655 (char-downcase #\a)
656 (char-downcase #\B)
657 (char-downcase #\0)
658 (char-downcase #\space)
659
660 (define string (lambda chars (list->string chars)))
661
662 (display "apply\n")
663 (apply cons '(a b))
664
665 (define map
666   (lambda (proc . lists)
667          (define (args lists)
668            (cond ((null? lists) ())
669                  (else
670                   (cons (caar lists) (args (cdr lists)))
671                   )
672                  )
673            )
674          (define (next lists)
675            (cond ((null? lists) ())
676                  (else
677                   (cons (cdr (car lists)) (next (cdr lists)))
678                   )
679                  )
680            )
681          (define (domap lists)
682            (cond ((null? (car lists)) ())
683                  (else
684                   (cons (apply proc (args lists)) (domap (next lists)))
685                   )
686                  )
687            )
688          (domap lists)
689          )
690   )
691
692 (map cadr '((a b) (d e) (g h)))
693
694 (define for-each (lambda (proc . lists)
695                         (apply map proc lists)
696                         #t))
697
698 (for-each display '("hello" " " "world" "\n"))
699
700 (define (_string-ml strings)
701   (if (null? strings) ()
702     (cons (string->list (car strings)) (_string-ml (cdr strings)))
703     )
704   )
705
706 (define string-map (lambda (proc . strings)
707                           (list->string (apply map proc (_string-ml strings))))))
708
709 (string-map (lambda (x) (+ 1 x)) "HAL")
710
711 (define string-for-each (lambda (proc . strings)
712                                (apply for-each proc (_string-ml strings))))
713
714 (string-for-each write-char "IBM\n")
715
716 (define (newline) (write-char #\newline))
717
718 (newline)
719
720 (call-with-current-continuation
721  (lambda (exit)
722    (for-each (lambda (x)
723                (write "test" x)
724                (if (negative? x)
725                    (exit x)))
726              '(54 0 37 -3 245 19))
727    #t))
728
729
730                                         ; `q -> (quote q)
731                                         ; `(q) -> (append (quote (q)))
732                                         ; `(a ,(+ 1 2)) -> (append (quote (a)) (list (+ 1 2)))
733                                         ; `(a ,@(list 1 2 3) -> (append (quote (a)) (list 1 2 3))
734
735
736
737 `(hello ,(+ 1 2) ,@(list 1 2 3) `foo)
738
739
740 (define repeat
741   (macro (count . rest)
742          (define counter '__count__)
743          (cond ((pair? count)
744                 (set! counter (car count))
745                 (set! count (cadr count))
746                 )
747                )
748          `(let ((,counter 0)
749                 (__max__ ,count)
750                 )
751             (while (< ,counter __max__)
752               ,@rest
753               (set! ,counter (+ ,counter 1))
754               )
755             )
756          )
757   )
758
759 (repeat 2 (write 'hello))
760 (repeat (x 3) (write 'goodbye x))
761
762 (define case
763   (macro (test . l)
764                                         ; construct the body of the
765                                         ; case, dealing with the
766                                         ; lambda version ( => lambda)
767
768          (define (_unarrow l)
769            (cond ((null? l) l)
770                  ((eq? (car l) '=>) `(( ,(cadr l) __key__)))
771                  (else l))
772            )
773
774                                         ; Build the case elements, which is
775                                         ; simply a list of cond clauses
776
777          (define (_case l)
778
779            (cond ((null? l) ())
780
781                                         ; else case
782
783                  ((eq? (caar l) 'else)
784                   `((else ,@(_unarrow (cdr (car l))))))
785
786                                         ; regular case
787                  
788                  (else
789                   (cons
790                    `((eqv? ,(caar l) __key__)
791                      ,@(_unarrow (cdr (car l))))
792                    (_case (cdr l)))
793                   )
794                  )
795            )
796
797                                         ; now construct the overall
798                                         ; expression, using a lambda
799                                         ; to hold the computed value
800                                         ; of the test expression
801
802          `((lambda (__key__)
803              (cond ,@(_case l))) ,test)
804          )
805   )
806
807 (case 12 (1 "one") (2 "two") (3 => (lambda (x) (write "the value is" x))) (12 "twelve") (else "else"))