#lang scheme/base
(require "depend.ss"
mzlib/defmacro
(for-syntax scheme/base
"depend.ss"
scheme/match
)
"primitive.ss"
"input.ss"
)
(define (bind parser v->parser)
(lambda (in)
(let-values (((v in)
(parser in)))
((v->parser v) in))))
(define (result parser transform)
(bind parser
(lambda (v)
(if (succeeded? v)
(return (transform v))
fail))))
(define (result* parser transform)
(bind parser
(lambda (v)
(if (and (succeeded? v) (list? v))
(return (apply transform v))
fail))))
(define-macro (seq . exps)
(define *in (gensym 'in)) (define *v (gensym 'v)) (define literal 'literal)
(define (body exps)
(match exps
((list exp)
`((,literal ,exp) ,*in))
((list-rest var '<- exp rest)
`(let-values (((,var ,*in)
((,literal ,exp) ,*in)))
(if (succeeded? ,var)
,(body rest)
(fail in))))
((list-rest exp rest)
(body `(,*v <- ,exp . ,rest)))
))
`(lambda (in)
(let ((,*in in))
,(body exps))))
(define (sequence parsers)
(lambda (IN)
(define (helper parsers in acc)
(if (null? parsers)
((return (reverse acc)) in)
(let-values (((v in)
((car parsers) in)))
(if (succeeded? v)
(helper (cdr parsers) in (cons v acc))
(fail IN)))))
(helper (map literal parsers) IN '())))
(define (sequence* . parsers)
(sequence parsers))
(define-macro (choice . exps)
(define *in (gensym 'in)) (define *v (gensym 'v)) (define (body exps)
(match exps
((list)
`(fail ,*in))
((list-rest exp rest)
`(let-values (((,*v ,*in)
((literal ,exp) ,*in)))
(if (succeeded? ,*v)
((return ,*v) ,*in)
,(body rest))))
))
`(lambda (,*in)
,(body exps)))
(define (one-of parsers)
(lambda (in)
(define (helper parsers)
(if (null? parsers)
(fail in)
(let-values (((v in)
((car parsers) in)))
(if (succeeded? v)
((return v) in)
(helper (cdr parsers))))))
(helper (map literal parsers))))
(define (one-of* . parsers)
(one-of parsers))
(define (all-of parsers)
(lambda (in)
(define (helper parsers v)
(if (null? parsers)
((return v) in)
(let-values (((v IN)
((car parsers) in)))
(if (succeeded? v)
(helper (cdr parsers) v)
(fail in)))))
(helper (map literal parsers) (make-failed 0))))
(define (all-of* . parsers)
(all-of parsers))
(define (repeat parser (min 1) (max +inf.0))
(define (make parser)
(lambda (IN)
(define (helper prev-in acc count)
(let-values (((v in)
(parser prev-in)))
(if (succeeded? v)
(if (< count max)
(helper in (cons v acc) (add1 count))
((return (reverse acc)) prev-in))
(if (< count min)
(fail IN)
((return (reverse acc)) in)))))
(helper IN '() 0)))
(make (literal parser)))
(define (zero-many parser)
(repeat parser 0))
(define (one-many parser)
(repeat parser))
(define (zero-one parser default)
(lambda (in)
(let-values (((v in)
((literal parser) in)))
((return (if (succeeded? v) v default)) in))))
(provide bind
result
result*
seq
sequence
sequence*
choice
one-of
one-of*
all-of
all-of*
repeat
zero-many
one-many
zero-one
)