- rewrote expect with a functional interface expect*
This commit is contained in:
parent
87fd5ead30
commit
7606bdca71
|
@ -24,10 +24,6 @@
|
|||
;;; - expect-package
|
||||
;;; This package must be opened by expect's clients.
|
||||
|
||||
(define error (structure-ref signals error))
|
||||
|
||||
(define-syntax expect expand-expect)
|
||||
|
||||
;;; A task is a guy with whom we can interact.
|
||||
|
||||
(define-record-type task
|
||||
|
@ -285,3 +281,211 @@
|
|||
(let ((s (task:buf task)))
|
||||
(if (zero? (string-length s)) (otherwise)
|
||||
(tm s s otherwise))))
|
||||
|
||||
|
||||
;;; expect functional interface
|
||||
|
||||
(define *default-timeout* 10)
|
||||
(define *default-echo* #f)
|
||||
(define *default-max-size* #f)
|
||||
|
||||
(define-record-type :eof-pattern
|
||||
(make-eof-pattern)
|
||||
eof-pattern?)
|
||||
|
||||
(define eof-pattern (make-eof-pattern))
|
||||
|
||||
(define (in-select! rvec timeout)
|
||||
(receive (in out ex)
|
||||
(select! rvec '#() '#() timeout)
|
||||
(not (zero? in))))
|
||||
|
||||
;; pattern: (match (lambda () regexp) (lambda (match) ...))
|
||||
;; or (eof (lambda () ...))
|
||||
;; or (test (lambda () #t/#f) (lambda (v) ...))
|
||||
;; or (else (lambda () ...)) ; else
|
||||
|
||||
(define (expect* options . tasks-patterns-alist)
|
||||
(let ((monitor (cond
|
||||
((assq 'monitor options) => cdr)
|
||||
(else null-monitor)))
|
||||
(on-timeout (cond
|
||||
((assq 'on-timeout options) => cdr)
|
||||
(else (lambda () #f))))
|
||||
(timeout (cond
|
||||
((assq 'timeout options) => cdr)
|
||||
(else *default-timeout*)))
|
||||
(echo (cond
|
||||
((assq 'echo options) => cdr)
|
||||
(else *default-echo*)))
|
||||
(max-size (cond
|
||||
((assq 'max-size options) => cdr)
|
||||
(else *default-max-size*))))
|
||||
(expect-1* on-timeout monitor timeout echo max-size tasks-patterns-alist)))
|
||||
|
||||
(define (expect-1* on-timeout monitor timeout echo max-size
|
||||
tasks-patterns-alist)
|
||||
(let ((handle-input
|
||||
(lambda (task patterns input do-next)
|
||||
(let ((s (task:buf task)))
|
||||
(let loop ((patterns patterns))
|
||||
(if (null? patterns)
|
||||
(do-next)
|
||||
(let ((pattern (car patterns)))
|
||||
(case (car pattern)
|
||||
((match)
|
||||
(let ((m (string-match ((cadr pattern)) s)))
|
||||
(if m
|
||||
(begin
|
||||
(do-match-hacking task m s input monitor)
|
||||
(monitor task m) ;; ??
|
||||
((caddr pattern) m))
|
||||
(loop (cdr patterns)))))
|
||||
((eof) (loop (cdr patterns)))
|
||||
((test)
|
||||
(let ((v ((cadr pattern))))
|
||||
(if v
|
||||
((caddr pattern) v)
|
||||
(loop (cdr patterns)))))
|
||||
((else)
|
||||
((cadr pattern)))
|
||||
(else (error "undefined pattern type" (car pattern)))
|
||||
)))))))
|
||||
(handle-eof
|
||||
(lambda (task patterns do-next)
|
||||
(set-task:pre-match! task (task:buf task))
|
||||
(set-task:buf! task "")
|
||||
(monitor task #f)
|
||||
(let loop ((patterns patterns))
|
||||
(if (null? patterns)
|
||||
(do-next)
|
||||
(let ((pattern (car patterns)))
|
||||
(case (car pattern)
|
||||
((eof) ((cadr pattern)))
|
||||
((match test else) (loop (cdr patterns)))
|
||||
(else (error "undefined pattern type" (car pattern)))
|
||||
))))))
|
||||
(handle-timeout
|
||||
(lambda ()
|
||||
(monitor #f 'timeout)
|
||||
(on-timeout))))
|
||||
|
||||
;; first check existing data in the buffers
|
||||
(let loop ((f-tasks-patterns-alist tasks-patterns-alist))
|
||||
(if (not (null? f-tasks-patterns-alist))
|
||||
(let* ((task-patterns (car f-tasks-patterns-alist))
|
||||
(task (car task-patterns))
|
||||
(s (task:buf task)))
|
||||
(if (not (zero? (string-length s)))
|
||||
(handle-input task (cdr task-patterns) s
|
||||
(lambda () (loop (cdr f-tasks-patterns-alist))))
|
||||
(loop (cdr f-tasks-patterns-alist))))
|
||||
|
||||
;; start looking for input, handle it and throw away those
|
||||
;; that got eof
|
||||
(let loop ((tasks-patterns-alist tasks-patterns-alist))
|
||||
(if (null? tasks-patterns-alist)
|
||||
#f ;; all eof
|
||||
(let ((ivec (list->vector (map (lambda (task-patterns)
|
||||
(task:in (car task-patterns)))
|
||||
tasks-patterns-alist))))
|
||||
;; what is this (time) thing in the original?
|
||||
(if (not (in-select! ivec timeout))
|
||||
(handle-timeout)
|
||||
(let iloop ((inports (vector->list ivec))
|
||||
(tasks-patterns-alist tasks-patterns-alist)
|
||||
(remaining '()))
|
||||
(if (null? tasks-patterns-alist)
|
||||
(loop (reverse remaining))
|
||||
(if (car inports)
|
||||
(let* ((task-patterns (car tasks-patterns-alist))
|
||||
(task (car task-patterns))
|
||||
(s (do-input task)))
|
||||
(if s
|
||||
(handle-input
|
||||
task (cdr task-patterns) s
|
||||
(lambda ()
|
||||
(iloop (cdr inports)
|
||||
(cdr tasks-patterns-alist)
|
||||
(cons task-patterns
|
||||
remaining))))
|
||||
(handle-eof
|
||||
task (cdr task-patterns)
|
||||
(lambda ()
|
||||
(iloop (cdr inports)
|
||||
(cdr tasks-patterns-alist)
|
||||
remaining)))))
|
||||
(iloop (cdr inports)
|
||||
(cdr tasks-patterns-alist)
|
||||
(cons (car tasks-patterns-alist)
|
||||
remaining)))))))))))))
|
||||
|
||||
;; Syntax based on procedural interface
|
||||
|
||||
(define-syntax expect-options-clauses
|
||||
(syntax-rules (on-timeout timeout echo max-size monitor)
|
||||
((expect-options-clauses)
|
||||
'())
|
||||
((expect-options-clauses (on-timeout body ...) clause ...)
|
||||
(cons (cons 'on-timeout (lambda () body ...))
|
||||
(expect-options-clauses clause ...)))
|
||||
((expect-options-clauses (timeout v) clause ...)
|
||||
(cons (cons 'timeout v)
|
||||
(expect-options-clauses clause ...)))
|
||||
((expect-options-clauses (echo v) clause ...)
|
||||
(cons (cons 'echo v)
|
||||
(expect-options-clauses clause ...)))
|
||||
((expect-options-clauses (max-size v) clause ...)
|
||||
(cons (cons 'max-size v)
|
||||
(expect-options-clauses clause ...)))
|
||||
((expect-options-clauses (monitor proc) clause ...)
|
||||
(cons (cons 'monitor proc)
|
||||
(expect-options-clauses clause ...)))
|
||||
((expect-options-clauses x clause ...)
|
||||
(expect-options-clauses clause ...))))
|
||||
|
||||
(define-syntax expect-action-clauses
|
||||
(syntax-rules (on-eof test => else)
|
||||
((expect-action-clauses loop)
|
||||
'())
|
||||
((expect-action-clauses loop (on-eof body ...) clause ...)
|
||||
(cons (list 'eof
|
||||
(lambda () body ...))
|
||||
(expect-action-clauses loop clause ...)))
|
||||
((expect-action-clauses loop (test exp body ...) clause ...)
|
||||
(cons (list 'test
|
||||
(lambda () exp)
|
||||
(lambda (_) body ...))
|
||||
(expect-action-clauses loop clause ...)))
|
||||
((expect-action-clauses loop (test exp => proc) clause ...)
|
||||
(cons (list 'test
|
||||
(lambda () exp)
|
||||
(lambda (v) (proc v)))
|
||||
(expect-action-clauses loop clause ...)))
|
||||
((expect-action-clauses loop (pattern (mvars ...) body ...) clause ...)
|
||||
(cons (list 'match (lambda () pattern)
|
||||
(lambda (m)
|
||||
(let-match m (mvars ...) body ...)))
|
||||
(expect-action-clauses loop clause ...)))
|
||||
((expect-action-clauses loop (else body ...) clause ...)
|
||||
(cons (list else (lambda () body ...))
|
||||
(expect-action-clauses loop clause ...)))))
|
||||
|
||||
(define-syntax expect-task-clauses
|
||||
(syntax-rules ()
|
||||
((expect-task-clauses loop)
|
||||
'())
|
||||
((expect-task-clauses loop (task aclause ...) clause ...)
|
||||
(append (cons task (expect-action-clauses loop aclause ...))
|
||||
(expect-task-clauses loop clause ...)))))
|
||||
|
||||
(define-syntax expect
|
||||
(syntax-rules ()
|
||||
((expect name (var-inits ...) eclause ...)
|
||||
(let name (var-inits ...)
|
||||
(expect* (expect-options-clauses eclause ...)
|
||||
(expect-task-clauses name eclause ...))))
|
||||
((expect (x ...) eclause ...)
|
||||
(let loop ()
|
||||
(expect* (expect-options-clauses loop (x ...) eclause ...)
|
||||
(expect-task-clauses loop (x ...) eclause ...))))))
|
||||
|
|
|
@ -25,14 +25,14 @@
|
|||
spawn* (spawn :syntax)
|
||||
tsend tsend/cr
|
||||
(expect :syntax)
|
||||
expect*
|
||||
|
||||
interact* interact/char*
|
||||
(interact :syntax))
|
||||
(for-syntax (open expect-syntax-support scheme))
|
||||
(for-syntax (open scheme-with-scsh))
|
||||
|
||||
(open scheme-with-scsh formats structure-refs let-opt
|
||||
receiving srfi-9 srfi-13 srfi-1)
|
||||
(access signals) ; for ERROR
|
||||
|
||||
(files expect interact))
|
||||
|
||||
|
|
Loading…
Reference in New Issue