2 ;████████╗██╗ ██╗██╗ ██╗███╗ ██╗
3 ;╚══██╔══╝██║ ██║██║ ██║████╗ ██║
4 ; ██║ ███████║██║ ██║██╔██╗ ██║
5 ; ██║ ██╔══██║██║ ██║██║╚██╗██║
6 ; ██║ ██║ ██║╚██████╔╝██║ ╚████║
7 ; ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝
9 ;Copyright © 2023 Simon Forman
11 ;This file is part of Thun
13 ;Thun is free software: you can redistribute it and/or modify
14 ;it under the terms of the GNU General Public License as published by
15 ;the Free Software Foundation, either version 3 of the License, or
16 ;(at your option) any later version.
18 ;Thun is distributed in the hope that it will be useful,
19 ;but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ;GNU General Public License for more details.
23 ;You should have received a copy of the GNU General Public License
24 ;along with Thun. If not see <http://www.gnu.org/licenses/>.
28 (import (chicken string))
34 ;(load "defs.scm") ; csc -prologue defs.scm joy.scm
36 (chicken-script (load "defs.scm"))
40 ;██╗███╗ ██╗████████╗███████╗██████╗ ██████╗ ██████╗ ███████╗████████╗███████╗██████╗
41 ;██║████╗ ██║╚══██╔══╝██╔════╝██╔══██╗██╔══██╗██╔══██╗██╔════╝╚══██╔══╝██╔════╝██╔══██╗
42 ;██║██╔██╗ ██║ ██║ █████╗ ██████╔╝██████╔╝██████╔╝█████╗ ██║ █████╗ ██████╔╝
43 ;██║██║╚██╗██║ ██║ ██╔══╝ ██╔══██╗██╔═══╝ ██╔══██╗██╔══╝ ██║ ██╔══╝ ██╔══██╗
44 ;██║██║ ╚████║ ██║ ███████╗██║ ██║██║ ██║ ██║███████╗ ██║ ███████╗██║ ██║
45 ;╚═╝╚═╝ ╚═══╝ ╚═╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝╚══════╝ ╚═╝ ╚══════╝╚═╝ ╚═╝
48 (define (joy stack expression dict)
49 ;(joy-trace stack expression)
50 (if (null? expression)
52 (if (symbol? (car expression))
54 (joy-eval (car expression) stack (cdr expression) dict)
56 (joy (cons (car expression) stack) (cdr expression) dict))))
58 (define (joy-eval symbol stack expression dict)
60 ((+ add) (values (joy-math-func + stack) expression dict))
61 ((- sub) (values (joy-math-func - stack) expression dict))
62 ((* mul) (values (joy-math-func * stack) expression dict))
63 ((/ div) (values (joy-math-func quotient stack) expression dict)) ; but for negative divisor, no!?
64 ((% mod) (values (joy-math-func modulo stack) expression dict))
66 ((< lt) (values (joy-math-func < stack) expression dict))
67 ((> gt) (values (joy-math-func > stack) expression dict))
68 ((<= le) (values (joy-math-func <= stack) expression dict))
69 ((>= ge) (values (joy-math-func >= stack) expression dict))
70 ((= eq) (values (joy-math-func = stack) expression dict))
71 ((<> != neq) (values (joy-math-func not-equal stack) expression dict))
73 ((bool) (joy-bool stack expression dict))
75 ((dup) (values (joy-dup stack) expression dict))
76 ((pop) (values (cdr stack) expression dict))
77 ((stack) (values (cons stack stack) expression dict))
78 ((swaack) (values (cons (cdr stack) (car stack)) expression dict))
79 ((swap) (values (cons (cadr stack) (cons (car stack) (cddr stack))) expression dict))
81 ((concat) (joy-func append stack expression dict))
82 ((cons) (joy-func cons stack expression dict))
83 ((first) (values (joy-first stack) expression dict))
84 ((rest) (values (joy-rest stack) expression dict))
86 ((i) (joy-i stack expression dict))
87 ((dip) (joy-dip stack expression dict))
88 ((branch) (joy-branch stack expression dict))
89 ((loop) (joy-loop stack expression dict))
91 (else (if (hash-table-exists? dict symbol)
92 (values stack (append (hash-table-ref dict symbol) expression) dict)
93 (error (conc "Unknown word: " symbol))))))
96 ;██╗ ██╗████████╗██╗██╗ ███████╗
97 ;██║ ██║╚══██╔══╝██║██║ ██╔════╝
98 ;██║ ██║ ██║ ██║██║ ███████╗
99 ;██║ ██║ ██║ ██║██║ ╚════██║
100 ;╚██████╔╝ ██║ ██║███████╗███████║
101 ; ╚═════╝ ╚═╝ ╚═╝╚══════╝╚══════╝
104 (define (not-equal a b) (not (= a b)))
106 (define (joy-func op stack expression dict)
107 (values (cons (op (cadr stack) (car stack)) (cddr stack)) expression dict))
109 (define (joy-math-func op stack0)
110 (receive (a stack1) (pop-int stack0)
111 (receive (b stack) (pop-int stack1)
112 (cons (op b a) stack))))
114 (define (pop-any stack)
115 (if (null-list? stack)
116 (abort "Not enough values on Stack")
119 (define (pop-kind stack predicate message)
120 (receive (term rest) (pop-any stack)
121 (if (predicate term) (values term rest) (abort message))))
123 (define (pop-list stack) (pop-kind stack list? "Not a list."))
124 (define (pop-int stack) (pop-kind stack number? "Not an integer."))
125 (define (pop-bool stack) (pop-kind stack boolean? "Not a Boolean value."))
128 ; ██████╗ ██████╗ ██████╗ ███████╗ ██╗ ██╗ ██████╗ ██████╗ ██████╗ ███████╗
129 ;██╔════╝██╔═══██╗██╔══██╗██╔════╝ ██║ ██║██╔═══██╗██╔══██╗██╔══██╗██╔════╝
130 ;██║ ██║ ██║██████╔╝█████╗ ██║ █╗ ██║██║ ██║██████╔╝██║ ██║███████╗
131 ;██║ ██║ ██║██╔══██╗██╔══╝ ██║███╗██║██║ ██║██╔══██╗██║ ██║╚════██║
132 ;╚██████╗╚██████╔╝██║ ██║███████╗ ╚███╔███╔╝╚██████╔╝██║ ██║██████╔╝███████║
133 ; ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚══╝╚══╝ ╚═════╝ ╚═╝ ╚═╝╚═════╝ ╚══════╝
136 (define (joy-bool stack expression dict)
137 (values (cons (joy-bool-term (car stack)) (cdr stack)) expression dict))
139 (define (joy-bool-term term)
140 (cond ((boolean? term) term)
141 ((number? term) (not-equal 0 term))
142 ((list? term) (not (null? term)))
145 (define (joy-dup stack)
146 (receive (term _) (pop-any stack) (cons term stack)))
149 (define (joy-rest stack0)
150 (receive (el stack) (pop-list stack0)
152 (abort "Cannot take rest of empty list.")
153 (cons (cdr el) stack))))
155 (define (joy-first stack0)
156 (receive (el stack) (pop-list stack0)
158 (abort "Cannot take first of empty list.")
159 (cons (car el) stack))))
162 ; ██████╗ ██████╗ ███╗ ███╗██████╗ ██╗███╗ ██╗ █████╗ ████████╗ ██████╗ ██████╗ ███████╗
163 ;██╔════╝██╔═══██╗████╗ ████║██╔══██╗██║████╗ ██║██╔══██╗╚══██╔══╝██╔═══██╗██╔══██╗██╔════╝
164 ;██║ ██║ ██║██╔████╔██║██████╔╝██║██╔██╗ ██║███████║ ██║ ██║ ██║██████╔╝███████╗
165 ;██║ ██║ ██║██║╚██╔╝██║██╔══██╗██║██║╚██╗██║██╔══██║ ██║ ██║ ██║██╔══██╗╚════██║
166 ;╚██████╗╚██████╔╝██║ ╚═╝ ██║██████╔╝██║██║ ╚████║██║ ██║ ██║ ╚██████╔╝██║ ██║███████║
167 ; ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═════╝ ╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝
170 (define (joy-i stack expression dict)
171 (values (cdr stack) (append (car stack) expression) dict))
173 (define (joy-dip stack expression dict)
175 (append (car stack) (cons (cadr stack) expression))
178 (define (joy-branch stack expression dict)
179 (let ((flag (caddr stack))
180 (false_body (cadr stack))
181 (true_body (car stack)))
182 (values (cdddr stack)
183 (append (if flag true_body false_body) expression)
186 (define (joy-loop stack expression dict)
187 (let ((flag (cadr stack))
190 (if flag (append body (cons body (cons "loop" expression))) expression)
194 ;██████╗ █████╗ ██████╗ ███████╗███████╗██████╗
195 ;██╔══██╗██╔══██╗██╔══██╗██╔════╝██╔════╝██╔══██╗
196 ;██████╔╝███████║██████╔╝███████╗█████╗ ██████╔╝
197 ;██╔═══╝ ██╔══██║██╔══██╗╚════██║██╔══╝ ██╔══██╗
198 ;██║ ██║ ██║██║ ██║███████║███████╗██║ ██║
199 ;╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚══════╝╚═╝ ╚═╝
202 (define (string-replace str from to)
203 (string-intersperse (string-split str from #t) to))
205 (define (tokenize str)
207 (string-replace (string-replace str "]" " ] ") "[" " [ ")))
209 (define (tokenator token)
210 (cond ((string->number token) (string->number token))
211 ((string=? token "true") #t)
212 ((string=? token "false") #f)
213 (else (string->symbol token))))
215 (define (expect-right-bracket tokens acc)
217 (error "Missing closing bracket.")
218 (expect-right-bracket-lookahead (car tokens) (cdr tokens) acc)))
220 (define (expect-right-bracket-lookahead token tokens acc)
222 ("]" (values acc tokens))
223 ("[" (receive (sub_list rest) (expect-right-bracket tokens '())
224 (receive (el rrest) (expect-right-bracket rest acc)
225 (values (cons sub_list el) rrest))))
226 (_ (receive (el rest) (expect-right-bracket tokens acc)
227 (values (cons (tokenator token) el) rest)))))
229 (define (one-token-lookahead token tokens)
231 ("]" (error "Extra closing bracket."))
232 ("[" (expect-right-bracket tokens '()))
233 (_ (values (tokenator token) tokens))))
235 (define (parse0 tokens acc)
238 (receive (term rest_of_tokens)
239 (one-token-lookahead (car tokens) (cdr tokens))
240 (cons term (parse0 rest_of_tokens acc)))))
242 (define (parse tokens) (parse0 tokens '()))
244 (define (text->expression text) (parse (tokenize text)))
247 ;██████╗ ██████╗ ██╗███╗ ██╗████████╗███████╗██████╗
248 ;██╔══██╗██╔══██╗██║████╗ ██║╚══██╔══╝██╔════╝██╔══██╗
249 ;██████╔╝██████╔╝██║██╔██╗ ██║ ██║ █████╗ ██████╔╝
250 ;██╔═══╝ ██╔══██╗██║██║╚██╗██║ ██║ ██╔══╝ ██╔══██╗
251 ;██║ ██║ ██║██║██║ ╚████║ ██║ ███████╗██║ ██║
252 ;╚═╝ ╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝ ╚═╝ ╚══════╝╚═╝ ╚═╝
255 (define (joy-term->string term)
256 (cond ((boolean? term) (if term "true" "false"))
257 ((number? term) (->string term))
258 ((list? term) (conc "[" (joy-expression->string term) "]"))
259 (else (symbol->string term))))
261 (define (joy-expression->string expr)
262 (string-intersperse (map joy-term->string expr) " "))
265 ;██████╗ ███████╗███████╗██╗███╗ ██╗██╗████████╗██╗ ██████╗ ███╗ ██╗███████╗
266 ;██╔══██╗██╔════╝██╔════╝██║████╗ ██║██║╚══██╔══╝██║██╔═══██╗████╗ ██║██╔════╝
267 ;██║ ██║█████╗ █████╗ ██║██╔██╗ ██║██║ ██║ ██║██║ ██║██╔██╗ ██║███████╗
268 ;██║ ██║██╔══╝ ██╔══╝ ██║██║╚██╗██║██║ ██║ ██║██║ ██║██║╚██╗██║╚════██║
269 ;██████╔╝███████╗██║ ██║██║ ╚████║██║ ██║ ██║╚██████╔╝██║ ╚████║███████║
270 ;╚═════╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝╚══════╝
274 (load-defs! (make-hash-table equal? symbol-hash)))
276 (define (load-defs! dict)
277 (for-each (lambda (def) (add-def! def dict)) (defs))
278 ; defs is defined in defs.scm
281 (define (add-def! def dict)
282 (let ((def_list (text->expression def)))
283 (hash-table-set! dict (car def_list) (cdr def_list))))
286 ;██████╗ ███████╗██████╗ ██╗
287 ;██╔══██╗██╔════╝██╔══██╗██║
288 ;██████╔╝█████╗ ██████╔╝██║
289 ;██╔══██╗██╔══╝ ██╔═══╝ ██║
290 ;██║ ██║███████╗██║ ███████╗
291 ;╚═╝ ╚═╝╚══════╝╚═╝ ╚══════╝
294 (define (prompt) (display "joy? ") (read-line))
296 (define (main-loop stack0 dict0)
297 (let ((text (prompt)))
298 (if (eof-object? text)
300 (receive (stack dict)
301 (handle-exceptions exn
302 (begin (display exn) (newline) (values stack0 dict0))
303 (joy stack0 (text->expression text) dict0))
304 (print (joy-expression->string (reverse stack)))
305 (main-loop stack dict)))))
307 (define (joy-trace stack expression)
308 (print (conc (joy-expression->string (reverse stack)) " . " (joy-expression->string expression))))
310 (main-loop '() (initialize))
313 ;(display (text->expression "5 [] cons [4] concat first"))
314 ;(display (doit "5 down_to_zero"))
315 ;(display (doit "1 2 true [4 5 false] loop <"))