Skip to content

Commit d3ee7fe

Browse files
committed
Merge pull request #18 from AlexKnauth/afl
add anonymous function literals
2 parents 0df6f74 + 3f1686c commit d3ee7fe

File tree

3 files changed

+124
-0
lines changed

3 files changed

+124
-0
lines changed

clojure/reader.rkt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
(require racket/port
66
racket/set
77
syntax/readerr
8+
"reader/parse-afl.rkt"
89
)
910

1011
(define (make-clojure-readtable [rt (current-readtable)])
@@ -17,6 +18,7 @@
1718
#\{ 'dispatch-macro set-proc
1819
#\\ 'non-terminating-macro char-proc
1920
#\: 'non-terminating-macro kw-proc
21+
#\( 'dispatch-macro afl-proc
2022
))
2123

2224
(define (s-exp-comment-proc ch in src ln col pos)
@@ -65,3 +67,8 @@
6567
(read-syntax/recursive src in ch (make-readtable (current-readtable) ch #\: #f)))
6668
(syntax-property id-stx 'clojure-keyword #t))
6769

70+
(define (afl-proc ch in src ln col pos)
71+
(define lst-stx
72+
(read-syntax/recursive src in ch))
73+
(parse-afl lst-stx))
74+

clojure/reader/parse-afl.rkt

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
#lang racket/base
2+
3+
(provide parse-afl)
4+
5+
(require racket/match
6+
racket/list
7+
syntax/srcloc
8+
syntax/parse/define
9+
(for-syntax racket/base
10+
racket/list
11+
))
12+
(module+ test
13+
(require rackunit))
14+
15+
(define-simple-macro (require-a-lot req-spec ...)
16+
#:with (phase ...) (range -10 11)
17+
(require (for-meta phase req-spec ...) ...))
18+
19+
(require-a-lot (only-in racket/base lambda define-syntax #%app make-rename-transformer syntax))
20+
21+
(define (parse-afl stx)
22+
(define intro (make-syntax-introducer))
23+
(define stx* (intro stx))
24+
(with-syntax ([args (parse-args stx*)]
25+
[% (datum->syntax stx* '%)]
26+
[%1 (datum->syntax stx* '%1)]
27+
[body stx*])
28+
(intro
29+
(syntax/loc stx
30+
(lambda args
31+
(define-syntax % (make-rename-transformer #'%1))
32+
body)))))
33+
34+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
35+
36+
(module+ test
37+
(define chk (compose1 syntax->datum parse-afl))
38+
(check-equal? (chk #'(+))
39+
'(lambda ()
40+
(define-syntax % (make-rename-transformer #'%1))
41+
(+)))
42+
(check-equal? (chk #'(+ 2 %1 %1))
43+
'(lambda (%1)
44+
(define-syntax % (make-rename-transformer #'%1))
45+
(+ 2 %1 %1)))
46+
(check-equal? (chk #'(+ 2 %3 %2 %1))
47+
'(lambda (%1 %2 %3)
48+
(define-syntax % (make-rename-transformer #'%1))
49+
(+ 2 %3 %2 %1)))
50+
(check-equal? (chk #'(apply list* % %&))
51+
'(lambda (%1 . %&)
52+
(define-syntax % (make-rename-transformer #'%1))
53+
(apply list* % %&)))
54+
)
55+
56+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
57+
58+
;; parse-args : Stx -> Formals-Stx
59+
(define (parse-args stx)
60+
;; Filter the stxs to those that start with %,
61+
;; find the maximum, find whether there is a
62+
;; rest argument, and produce lambda formals
63+
;; based on that.
64+
(define-values (max-num rest?)
65+
(find-arg-info stx))
66+
(define datum-formals
67+
(append (for/list ([n (in-range 1 (add1 max-num))])
68+
(string->symbol (format "%~v" n)))
69+
(cond [rest? '%&]
70+
[else '()])))
71+
(datum->syntax stx datum-formals stx))
72+
73+
;; find-arg-info : Any -> (Values Natural Boolean)
74+
(define (find-arg-info v)
75+
(match (maybe-syntax-e v)
76+
[(? symbol? sym) (find-arg-info/sym sym)]
77+
[(? pair? pair) (find-arg-info/pair pair)]
78+
[_ (return)]))
79+
80+
;; find-arg-info/sym : Symbol -> (Values Natural Boolean)
81+
(define (find-arg-info/sym sym)
82+
(define str (symbol->string sym))
83+
(match str
84+
["%" (return #:max-num 1)]
85+
["%&" (return #:rest? #t)]
86+
[(regexp #px"^%\\d$")
87+
(return #:max-num (string->number (substring str 1)))]
88+
[_ (return)]))
89+
90+
;; find-arg-info/pair :
91+
;; (Cons Symbol Symbol) -> (Values Natural Boolean)
92+
(define (find-arg-info/pair pair)
93+
(define-values (car.max-num car.rest?)
94+
(find-arg-info (car pair)))
95+
(define-values (cdr.max-num cdr.rest?)
96+
(find-arg-info (cdr pair)))
97+
(return #:max-num (max car.max-num cdr.max-num)
98+
#:rest? (or car.rest? cdr.rest?)))
99+
100+
(define (return #:max-num [max-num 0] #:rest? [rest? #f])
101+
(values max-num rest?))
102+
103+
(define (maybe-syntax-e stx)
104+
(cond [(syntax? stx) (syntax-e stx)]
105+
[else stx]))

clojure/tests/test.rkt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#lang clojure
22

33
(require rackunit
4+
racket/list
5+
racket/stream
46
(only-in racket/match (== =:)))
57

68
(prn [1 2 3])
@@ -194,3 +196,13 @@ foo
194196
(check-equal? (pr-str '(a b foo :bar)) "(a b foo :bar)")
195197
(check-equal? (pr-str 1 2) "1 2")
196198

199+
(check-equal? (stream->list (map #(* 2 %) (range 0 10)))
200+
'(0 2 4 6 8 10 12 14 16 18))
201+
(check-equal? (#(+ %1 %2 %3) 1 2 3)
202+
6)
203+
(check-equal? (#(apply list* % %&) 1 '(2 3))
204+
'(1 2 3))
205+
(check-equal? (let [lambda "not lambda" define-syntax "not define-syntax"]
206+
(#(do %) 3))
207+
3)
208+

0 commit comments

Comments
 (0)