Skip to content

Commit 9fbcaf6

Browse files
committed
metacircular interpreter WIP
1 parent 4c8cf54 commit 9fbcaf6

File tree

3 files changed

+83
-1
lines changed

3 files changed

+83
-1
lines changed

mylis/mylis_2/metacircular.rkt

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#lang racket/base
2+
3+
(define (MAKE-GLOBAL-ENV) (list
4+
(list (quote NOT) not)
5+
(list (quote EQ?) eq?)
6+
(list (quote EQUAL?) equal?)
7+
(list (quote ADD) +)
8+
(list (quote SUB) -)
9+
(list (quote MUL) *)
10+
(list (quote DIV) /)
11+
(list (quote MAP) map)
12+
(list (quote LIST) list)
13+
(list (quote APPEND) append)
14+
))
15+
16+
(define GLOBAL-ENV (MAKE-GLOBAL-ENV))
17+
18+
(define (LOOKUP name env)
19+
(cond
20+
((null? env) #f)
21+
((equal? name (car (car env))) (car (cdr (car env))))
22+
(else (LOOKUP name (cdr env)))))
23+
24+
(define (REST list) (cdr list))
25+
(define (FIRST list) (car list))
26+
(define (SECOND list) (car (cdr list)))
27+
(define (THIRD list) (car (cdr (cdr list))))
28+
(define (FOURTH list) (car (cdr (cdr (cdr list)))))
29+
30+
(define (EVLIS exps env)
31+
(if (null? exps)
32+
(quote ())
33+
(cons (EVAL (FIRST exps) env)
34+
(EVLIS (REST exps) env))
35+
)
36+
)
37+
38+
(define (EVAL exp env)
39+
(cond
40+
((number? exp) exp)
41+
((symbol? exp) (LOOKUP exp env))
42+
((equal? (FIRST exp) (quote QUOTE))
43+
(SECOND exp) )
44+
((equal? (FIRST exp) (quote IF))
45+
(if (EVAL (SECOND exp) env)
46+
(EVAL (THIRD exp) env)
47+
(EVAL (FOURTH exp) env)))
48+
((equal? (FIRST exp) (quote LAMBDA))
49+
(MAKE-PROCEDURE (SECOND exp) (THIRD exp) env))
50+
((equal? (FIRST exp) (quote DEFINE-GLOBAL))
51+
(set! GLOBAL-ENV (cons (list (SECOND exp) (EVAL (THIRD exp) env)) GLOBAL-ENV)))
52+
(else
53+
(apply (EVAL (FIRST exp) env) (EVLIS (REST exp) env)))))
54+
55+
(define (MAKE-PROCEDURE parms body definition-env)
56+
(lambda (args)
57+
(EVAL body
58+
(append
59+
(map list parms (list args))
60+
definition-env))
61+
)
62+
)
63+
64+
(require rackunit)
65+
66+
; LOOKUP
67+
(check-equal? (LOOKUP 'ADD GLOBAL-ENV) + "Existing name")
68+
(check-equal? (LOOKUP 'NO-SUCH-NAME GLOBAL-ENV) #f "Non-existing name")
69+
70+
; EVAL
71+
(check-equal? (EVAL '1 '()) 1 "Number literal")
72+
(check-equal? (EVAL 'ADD GLOBAL-ENV) + "Built-in procedure")
73+
(check-equal? (EVAL '(QUOTE (A (B C))) GLOBAL-ENV) '(A (B C)) "QUOTE form")
74+
(check-equal? (EVAL '(IF (EQUAL? 3 3) 1 0) GLOBAL-ENV) 1 "IF form, consequence branch")
75+
(check-equal? (EVAL '(IF (EQUAL? 3 4) 1 0) GLOBAL-ENV) 0 "IF form, alternative branch")
76+
(check-true (procedure? (EVAL '(LAMBDA (N) (MUL N 2)) GLOBAL-ENV)) "LAMBDA form, definition")
77+
(check-equal? (EVAL '((LAMBDA (N) (MUL N 2)) 4) GLOBAL-ENV) 8 "LAMBDA form, application")
78+
(check-equal? (begin (EVAL '(DEFINE-GLOBAL X 8) GLOBAL-ENV) (FIRST GLOBAL-ENV)) '(X 8)) ; how do I inspect the GLOBAL-ENV?
79+
; I don't yet know how to write DEFINE, because it would need to update the local environment
80+
(check-equal? (begin (EVAL '(DEFINE-GLOBAL X2 (LAMBDA (N) (MUL N 2))) GLOBAL-ENV) (EVAL '(X2 8) GLOBAL-ENV)) 16)
81+
82+
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import mylis
77
import lis
88

9-
META_SCM = Path('meta.scm').read_text()
9+
META_SCM = Path('metacircular.scm').read_text()
1010

1111

1212
def test_GLOBAL_ENV_data():

0 commit comments

Comments
 (0)