#lang scheme
(require "parse.ss")
(require "combinator.ss")
(require test-engine/scheme-tests)
(define calc
(parse expr
(expr ((a := mulexp '+ b := mulexp)
(+ a b))
((a := mulexp) a))
(mulexp ((a := simple '* b := simple)
(* a b))
((a := simple '* b := simple)
(* a b))
((a := simple) a))
(simple ((a := 'num) a)
(('oparen a := expr 'cparen) a))))
(define g (packrat-list-results '((num . 1) (+) (num . 2) (*) (num . 3))))
(check-expect (parse-result-semantic-value (calc g)) 7)
(define (number . cs)
(string->number (apply string cs)))
(define (identifier . cs)
(string->symbol (apply string cs)))
(define lexer
(parse <lexeme>
(<lexeme>
[(a := <number>) (cons 'N a)]
[(a := <identifier>) (cons 'I a)]
[(a := <boolean>) (cons 'B a)]
[(a := <character>) (cons 'C a)]
[(a := <string>) (cons 'S a)]
[('#\() '(LP)]
[('#\)) '(RP)]
[('#\.) '(DOT)]
[('#\# '#\() '(VP)]
[('#\') '(Q)]
[('#\`) '(QQ)]
[('#\, '#\@) '(US)]
[('#\,) '(UQ)]
[(<atmosphere> a := <lexeme>) a])
(<atmosphere>*
((<atmosphere> <atmosphere>*) #f)
(() #f))
(<atmosphere>
((<whitespace>) #f)
((<comment>) #f))
(<comment>
(('#\; <not-line-ending>*) #f))
(<not-line-ending>*
((? (λ (x) (not (eqv? #\newline x))) <not-line-ending>*) #f)
(() #f))
(<whitespace>
((? char-whitespace?) #f))
(<identifier>
((a := <initial> b := <subsequent>*) (apply identifier a b))
((a := <peculiar-identifier>) a))
(<peculiar-identifier>
(('#\+) '+)
(('#\-) '-))
(<initial>
((a := <letter>) a)
((a := <special-initial>) a))
(<subsequent>*
((s := <subsequent> s* := <subsequent>*) (cons s s*))
(() empty))
(<subsequent>
((a := <initial>) a)
((a := <digit>) a)
((a := <special-subsequent>) a))
(<special-subsequent>
(('#\+) #\+)
(('#\-) #\-)
(('#\.) #\.)
(('#\@) #\@))
(<special-initial>
(('#\!) #\!)
(('#\$) #\$)
(('#\%) #\%)
(('#\&) #\&)
(('#\*) #\*)
(('#\/) #\/)
(('#\:) #\:)
(('#\<) #\<)
(('#\=) #\=)
(('#\>) #\>)
(('#\?) #\?)
(('#\^) #\^)
(('#\_) #\_)
(('#\~) #\~))
(<letter>
((a := (? char-alphabetic?)) a))
(<boolean>
(('#\# '#\t) #t)
(('#\# '#\f) #f))
(<number>
((f := <sign> ds := <digit>+) (apply number f ds)))
(<character> (('#\# '#\\ c := <c>) c))
(<c>
(('#\n '#\e '#\w '#\l '#\i '#\n '#\e) #\newline)
(('#\s '#\p '#\a '#\c '#\e) #\space)
((c := (? char?)) c))
(<string>
(('#\" s := <string-elems>* '#\") (apply string s)))
(<string-elems>*
((s := <string-element> cs := <string-elems>*) (cons s cs))
(() empty))
(<string-element>
((c := (? (λ (x) (not (or (char=? x '#\\)
(char=? x '#\"))))))
c)
(('#\\ '#\\) '#\\)
(('#\\ '#\") '#\"))
(<sign>
(('#\-) #\-)
(('#\+) #\+)
(() #\+))
(<digit>+
((d := <digit> ds := <digit>+) (cons d ds))
((d := <digit> (! <digit>)) (list d)))
(<digit>
(('#\0) #\0)
(('#\1) #\1)
(('#\2) #\2)
(('#\3) #\3)
(('#\4) #\4)
(('#\5) #\5)
(('#\6) #\6)
(('#\7) #\7)
(('#\8) #\8)
(('#\9) #\9))))
(define parser
(parse <datum>
(<datum>
[(a := <lexeme-datum>) a]
[(a := <compound-datum>) a])
(<lexeme-datum>
[(a := 'N) a]
[(a := 'I) a]
[(a := 'B) a]
[(a := 'C) a]
[(a := 'S) a])
(<compound-datum>
[(a := <list>) a]
[(a := <vector>) a])
(<list>
(('LP ds := <datum>* 'RP) ds)
(('LP ds := <datum>+ 'DOT d := <datum> 'RP)
(append ds d))
((a := <abbreviation>) a))
(<abbreviation>
((p := <abbreviation-prefix> d := <datum>) (cons p (list d))))
(<abbreviation-prefix>
(('Q) 'quote)
(('QQ) 'quasiquote)
(('UQ) 'unquote)
(('US) 'unquote-splicing))
(<vector>
(('VP ds := <datum>* 'RP) ds))
(<datum>+
((d := <datum> ds := <datum>*) (cons d ds)))
(<datum>*
((d := <datum> ds := <datum>*) (cons d ds))
(() empty))))
(define (lex s)
(let loop ((rs (packrat-string-results "fn" s)))
(let ((r (lexer rs)))
(if (parse-result-successful? r)
(cons (parse-result-semantic-value r)
(loop (parse-result-next r)))
empty))))
(define (par l)
(let ((r (parser (packrat-list-results l))))
(if (parse-result-successful? r)
(parse-result-semantic-value r)
(parse-result-error r))))
(define (read-string s)
(par (lex s)))
(check-expect (lex "x") '((I . x)))
(check-expect (lex "-16") '((N . -16)))
(check-expect (lex "(") '((LP)))
(check-expect (lex "#\\(") '((C . #\()))
(check-expect (lex "#t") '((B . #t)))
(check-expect (lex "#f") '((B . #f)))
(check-expect (lex "+") '((I . +)))
(check-expect (lex "-") '((I . -)))
(check-expect (lex "'") '((Q)))
(check-expect (lex ",") '((UQ)))
(check-expect (lex ",@") '((US)))
(check-expect (lex "string-append0") '((I . string-append0)))
(check-expect (parse-error? (read-string "")) #t)
(check-expect (read-string "x") 'x)
(check-expect (read-string "5") 5)
(check-expect (read-string "-16") -16)
(check-expect (read-string "#t") #t)
(check-expect (read-string "#f") #f)
(check-expect (read-string "#\\a") #\a)
(check-expect (read-string "\"\"") "")
(check-expect (read-string "\"hi\"") "hi")
(check-expect (read-string "<hi>") '<hi>)
(check-expect (read-string "string->number") 'string->number)
(check-expect (read-string "()") '())
(check-expect (read-string "(1 . 2)") '(1 . 2))
(check-expect (read-string "(1 . 2 )") '(1 . 2))
(check-expect (read-string "( 1 . 2)") '(1 . 2))
(check-expect (read-string "(1 2)") '(1 2))
(check-expect (read-string "(1 2 )") '(1 2))
(check-expect (read-string "( 1 2)") '(1 2))
(check-expect (read-string "'(1 2)") ''(1 2))
(check-expect (read-string ",(1 2)") ',(1 2))
(check-expect (read-string ",@(1 2)") ',@(1 2))
(check-expect (read-string #<<***
(define (f x) (string-append "(f x)" x))
***
)
'(define (f x) (string-append "(f x)" x)))
(test)