- removed obsolete expect-syntax.scm
- incorporated chat into the expect package
This commit is contained in:
		
							parent
							
								
									f327192879
								
							
						
					
					
						commit
						adbb0856af
					
				| 
						 | 
				
			
			@ -1,272 +0,0 @@
 | 
			
		|||
;;; The EXPECT macro expander
 | 
			
		||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | 
			
		||||
(define syntax-error (structure-ref signals error))
 | 
			
		||||
 | 
			
		||||
;;; LET*, except that you can use multiple-value expressions in the binding
 | 
			
		||||
;;; forms. MLET = "M ultiple-value LET." I use this to keep the very long
 | 
			
		||||
;;; expect-expander code from drifting off the right side of the screen.
 | 
			
		||||
 | 
			
		||||
(define-syntax mlet
 | 
			
		||||
  (syntax-rules ()
 | 
			
		||||
    ((mlet () body ...) (begin body ...))
 | 
			
		||||
 | 
			
		||||
    ;; Hack -- If a clause binds 0 vals, we *ignore* its return vals.
 | 
			
		||||
    ;; We don't require it to return exactly 0 vals.
 | 
			
		||||
    ((mlet ((() exp) init ...) body ...)
 | 
			
		||||
     (begin exp (mlet (init ...) body ...)))
 | 
			
		||||
 | 
			
		||||
    ((mlet (((v ...) exp) init ...) body ...)
 | 
			
		||||
     (receive (v ...) exp
 | 
			
		||||
       (mlet (init ...) body ...)))
 | 
			
		||||
 | 
			
		||||
    ((mlet ((v exp) init ...) body ...)
 | 
			
		||||
     (let ((v exp)) (mlet (init ...) body ...)))))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
;;; This is a hairy mother.  If you ever try to read it or change it, you are
 | 
			
		||||
;;; advised to first try expanding a couple of toy examples and looking at the
 | 
			
		||||
;;; output to get a feel for the basic compilation strategy.
 | 
			
		||||
 | 
			
		||||
(define (expand-expect exp r c)
 | 
			
		||||
  (mlet (((exp-name loop-var-inits clauses)	; Parse out the loop name
 | 
			
		||||
	  (if (and (<= 3 (length exp))		; and var inits, if any.
 | 
			
		||||
		   (not (pair? (cadr exp))))
 | 
			
		||||
	      (values (cadr exp) (caddr exp) (cdddr exp))	; Yep.
 | 
			
		||||
	      (values #f '() (cdr exp))))			; Nope.
 | 
			
		||||
 | 
			
		||||
	 ;; Parse the clauses into task clauses, a list of options, 
 | 
			
		||||
	 ;; and 0 or 1 on-timeout clauses.
 | 
			
		||||
	 ((task-clauses options timeout-clauses)
 | 
			
		||||
	  (let recur ((clauses clauses))
 | 
			
		||||
	    (if (pair? clauses)
 | 
			
		||||
		(let ((clause (car clauses)))
 | 
			
		||||
		  (receive (t o to) (recur (cdr clauses))
 | 
			
		||||
		    (cond ((not (pair? clause))
 | 
			
		||||
			   (syntax-error "Bad EXPECT clause" clause))
 | 
			
		||||
 | 
			
		||||
			  ((c (car clause) (r 'option))
 | 
			
		||||
			   (values t (append (cdr clause) o) to))
 | 
			
		||||
 | 
			
		||||
			  ((c (car clause) (r 'on-timeout))
 | 
			
		||||
			   (if (null? to)
 | 
			
		||||
			       (values t o (cons (cdr clause) to))
 | 
			
		||||
			       (syntax-error "Too many ON-TIMEOUT clauses in EXPECT" exp)))
 | 
			
		||||
 | 
			
		||||
			  ;; It's a task clause.
 | 
			
		||||
			  (else (values (cons clause t) o to)))))
 | 
			
		||||
 | 
			
		||||
		(values '() '() '()))))
 | 
			
		||||
      
 | 
			
		||||
	 ;; Parse each task clause into three parts: the task expression, the 
 | 
			
		||||
	 ;; pattern/action aclauses, and 0 or 1 ON-EOF aclauses.
 | 
			
		||||
	 ((tasks pa-clauses-list eof-clauses)
 | 
			
		||||
	  (let recur ((clauses task-clauses))
 | 
			
		||||
	    (if (pair? clauses)
 | 
			
		||||
		(let* ((clause (car clauses))
 | 
			
		||||
		       (task (car clause))
 | 
			
		||||
		       (aclauses (cdr clause)))
 | 
			
		||||
		  (receive (tasks pas eofs) (recur (cdr clauses))
 | 
			
		||||
		    (receive (this-tasks-eofs this-tasks-pas)
 | 
			
		||||
			(partition (lambda (ac)
 | 
			
		||||
				     (if (pair? ac)
 | 
			
		||||
					 (c (car ac) (r 'on-eof))
 | 
			
		||||
					 (syntax-error "Bad action clause in EXPECT"
 | 
			
		||||
						clause ac)))
 | 
			
		||||
				   aclauses)
 | 
			
		||||
		      (if (> (length this-tasks-eofs) 1)
 | 
			
		||||
			  (syntax-error "Too many ON-EOF action clauses in EXPECT"
 | 
			
		||||
				 clause)
 | 
			
		||||
			  (values (cons task tasks)
 | 
			
		||||
				  (cons this-tasks-pas pas)
 | 
			
		||||
				  (cons this-tasks-eofs eofs))))))
 | 
			
		||||
		(values '() '() '()))))
 | 
			
		||||
		      
 | 
			
		||||
	 (%vector (r 'vector))		; Bind a mess of syntax
 | 
			
		||||
	 (%lambda (r 'lambda))
 | 
			
		||||
	 (%let (r 'let))
 | 
			
		||||
	 (%let* (r 'let*))
 | 
			
		||||
	 (%letrec (r 'letrec))
 | 
			
		||||
	 (%begin (r 'begin))
 | 
			
		||||
	 (%and (r 'and))
 | 
			
		||||
	 (%string-match (r 'string-match))
 | 
			
		||||
	 (%vector (r 'vector))
 | 
			
		||||
	 (%let-match (r 'let-match))
 | 
			
		||||
	 (%s (r 's))
 | 
			
		||||
	 (%i (r 'i))
 | 
			
		||||
	 (%m (r 'm))
 | 
			
		||||
	 (%monitor (r 'mon))
 | 
			
		||||
	 (%do-next (r 'do-next))
 | 
			
		||||
	 (%do-match-hacking (r 'do-match-hacking))
 | 
			
		||||
	 (%do-select (r 'do-select))
 | 
			
		||||
	 (%=> (r '=>))
 | 
			
		||||
	 (%test (r 'test))
 | 
			
		||||
	 (%else (r 'else))
 | 
			
		||||
	 (%cond (r 'cond))
 | 
			
		||||
	 (%try-task (r 'try-task))
 | 
			
		||||
	 (%task:buf (r 'task:buf))
 | 
			
		||||
	 (%task:in (r 'task:in))
 | 
			
		||||
	 (%set-prematch (r 'set-prematch))
 | 
			
		||||
	 (%first-try (r 'first-try))
 | 
			
		||||
	 (%time (r 'time))
 | 
			
		||||
	 (%receive (r 'receive))
 | 
			
		||||
	 (%select! (r 'select!))
 | 
			
		||||
	 (%if (r 'if))
 | 
			
		||||
	 (%- (r '-))
 | 
			
		||||
	 (%+ (r '+))
 | 
			
		||||
	 (%> (r '>))
 | 
			
		||||
 | 
			
		||||
	 ;; Now we need a bunch of label names. Task clause #3 needs
 | 
			
		||||
	 ;; try-task3, task3, try-match3, and maybe do-eof3 (if it has 
 | 
			
		||||
	 ;; an ON-EOF action clause)
 | 
			
		||||
	 (task-indices (let recur ((tclauses task-clauses) (i 0))
 | 
			
		||||
			 (if (pair? tclauses)
 | 
			
		||||
			     (cons i (recur (cdr tclauses) (+ i 1)))
 | 
			
		||||
			     '())))
 | 
			
		||||
	 (vari (lambda (s i)
 | 
			
		||||
		 (r (string->symbol (string-append s (number->string i))))))
 | 
			
		||||
	 (try-task-vars (map (lambda (i) (vari "try-task" i)) task-indices))
 | 
			
		||||
	 (task-vars (map (lambda (i) (vari "task" i)) task-indices))
 | 
			
		||||
	 (try-match-vars (map (lambda (i) (vari "try-match" i)) task-indices))
 | 
			
		||||
	 (do-eof-vars (map (lambda (i maybe-eof-clause)
 | 
			
		||||
			     ;; #F if the tclause doesn't have an ON-EOF aclause.
 | 
			
		||||
			     (and (pair? maybe-eof-clause)
 | 
			
		||||
				  (vari "do-eof" i)))
 | 
			
		||||
			   task-indices eof-clauses))
 | 
			
		||||
 | 
			
		||||
	 ;; do-next[i] is the proc task I should call to 
 | 
			
		||||
	 ;; do the next thing.
 | 
			
		||||
	 (do-nexts (append (cdr try-task-vars)
 | 
			
		||||
			   (list %do-select)))
 | 
			
		||||
 | 
			
		||||
	 ;; Build a bunch of LET bindings.
 | 
			
		||||
	 ;; First, evaluate and bind all the tasks.
 | 
			
		||||
	 (task-bindings (map list task-vars tasks))
 | 
			
		||||
	 
 | 
			
		||||
	 ;; Bind IVEC to the task vector.
 | 
			
		||||
	 (ivec (r 'ivec))
 | 
			
		||||
	 (ivec-binding `(,ivec (,%vector ,@(map (lambda (tv) `(,%task:in ,tv))
 | 
			
		||||
						task-vars))))
 | 
			
		||||
	 
 | 
			
		||||
	 ;; Build a bunch of LETREC bindings.
 | 
			
		||||
	 ;; First, the do-eof bindings.
 | 
			
		||||
	 (do-eofs1 (map (lambda (label bodies) ; (length BODIES) < 2.
 | 
			
		||||
			  (and (pair? bodies)
 | 
			
		||||
			       `(,label (,%lambda () . ,(cdar bodies)))))
 | 
			
		||||
			do-eof-vars eof-clauses))
 | 
			
		||||
	 (do-eofs (filter (lambda (x) x) do-eofs1))
 | 
			
		||||
	 
 | 
			
		||||
	 ;; Second, the try-matchI bindings.
 | 
			
		||||
	 (pa->cond-clause (lambda (pa-clause task)
 | 
			
		||||
			    (if (c (car pa-clause) %test)
 | 
			
		||||
				(cdr pa-clause)
 | 
			
		||||
				`((,%string-match ,(car pa-clause) ,%s) ,%=>
 | 
			
		||||
			          (,%lambda (,%m)
 | 
			
		||||
				    (,%do-match-hacking ,task ,%m ,%s ,%i ,%monitor)
 | 
			
		||||
				    (,%let-match ,%m . ,(cdr pa-clause)))))))
 | 
			
		||||
 | 
			
		||||
	 (try-matcher (lambda (pa-clauses task)
 | 
			
		||||
			`(,%lambda (,%s ,%i ,%do-next)
 | 
			
		||||
			   (,%cond ,@(map (lambda (pa)
 | 
			
		||||
					    (pa->cond-clause pa task))
 | 
			
		||||
					  pa-clauses)
 | 
			
		||||
				   (,%else (,%monitor ,task ,%i)
 | 
			
		||||
					   (,%do-next))))))
 | 
			
		||||
 | 
			
		||||
	 (try-matches (map (lambda (label task pa-clauses)
 | 
			
		||||
			     `(,label ,(try-matcher pa-clauses task)))
 | 
			
		||||
			   try-match-vars
 | 
			
		||||
			   task-vars
 | 
			
		||||
			   pa-clauses-list))
 | 
			
		||||
 | 
			
		||||
	 ;; Third, the try-taskI bindings
 | 
			
		||||
	 (try-tasks (map (lambda (label task i match-tryer
 | 
			
		||||
					do-next do-eof)
 | 
			
		||||
			   `(,label (,%lambda ()
 | 
			
		||||
				      (,%try-task ,ivec ,i ,task ,match-tryer
 | 
			
		||||
						  ,do-next
 | 
			
		||||
						  ,(or do-eof do-next)
 | 
			
		||||
						  ,%monitor))))
 | 
			
		||||
			       
 | 
			
		||||
			 try-task-vars task-vars task-indices
 | 
			
		||||
			 try-match-vars do-nexts do-eof-vars))
 | 
			
		||||
	       
 | 
			
		||||
	 
 | 
			
		||||
	 ;; When EXPECT starts, there may be leftover data sitting in
 | 
			
		||||
	 ;; the task buffers from a previous EXPECT execution (too bad
 | 
			
		||||
	 ;; we don't have infinite push-back ports). So we have to run
 | 
			
		||||
	 ;; all the pattern/action match code before doing the select
 | 
			
		||||
	 ;; call, or trying to do input. This expression is the code
 | 
			
		||||
	 ;; that does this. If there *isn't* any saved-up input in a
 | 
			
		||||
	 ;; task's push-back buffer, we don't call the task's try-match
 | 
			
		||||
	 ;; proc.
 | 
			
		||||
	 (initial-trymatch
 | 
			
		||||
	     (let recur ((try-matchers try-match-vars)
 | 
			
		||||
			 (tasks task-vars))
 | 
			
		||||
	       (if (pair? try-matchers)
 | 
			
		||||
		   (let ((try-match (car try-matchers))
 | 
			
		||||
			 (try-matchers (cdr try-matchers))
 | 
			
		||||
			 (task (car tasks))
 | 
			
		||||
			 (tasks (cdr tasks)))
 | 
			
		||||
		     `(,%first-try ,task ,try-match 
 | 
			
		||||
				  (,%lambda () ,(recur try-matchers tasks))))
 | 
			
		||||
		   `(,%do-select))))
 | 
			
		||||
 | 
			
		||||
	 ;; Parse the options
 | 
			
		||||
	 ((timeout-secs mon-exp)
 | 
			
		||||
	  (let lp ((timeout-secs 10) (mon-exp (r 'null-monitor))
 | 
			
		||||
				     (opts options))
 | 
			
		||||
	    (if (pair? opts)
 | 
			
		||||
		(let ((opt (car opts))
 | 
			
		||||
		      (opts (cdr opts)))
 | 
			
		||||
		  (if (or (not (pair? opt))
 | 
			
		||||
			  (not (= (length opt) 2)))
 | 
			
		||||
		      (syntax-error "Illegal EXPECT option" opt))
 | 
			
		||||
		  (let ((kw (car opt)))
 | 
			
		||||
		    (cond ((c kw (r 'timeout))
 | 
			
		||||
			   (lp (cadr opt) mon-exp opts))
 | 
			
		||||
			  ((c kw (r 'monitor))
 | 
			
		||||
			   (lp timeout-secs (cadr opt) opts))
 | 
			
		||||
			  (else (syntax-error "Illegal EXPECT option" opt)))))
 | 
			
		||||
		(values timeout-secs mon-exp))))
 | 
			
		||||
 | 
			
		||||
	 ;; Build the select code.
 | 
			
		||||
	 ;; The TIME-DONE var is bound to "what time we time out",
 | 
			
		||||
	 ;; not "how many seconds until we time out."
 | 
			
		||||
	 (timeout-var (and timeout-secs (r 'time-done)))
 | 
			
		||||
	 (loop-top `(,%lambda ()
 | 
			
		||||
		      (,%receive (in out ex)
 | 
			
		||||
		          (,%select! ,ivec '#() '#()
 | 
			
		||||
				     ,@(if timeout-var
 | 
			
		||||
					   `((,%and ,timeout-var
 | 
			
		||||
						    (,%- ,timeout-var (,%time))))
 | 
			
		||||
					   '()))
 | 
			
		||||
			(,%if (,%> in 0)
 | 
			
		||||
			      (,(car try-task-vars))
 | 
			
		||||
			      ,(if (pair? timeout-clauses)
 | 
			
		||||
				   `(,%begin ,@(car timeout-clauses))
 | 
			
		||||
				   ''timeout)))))
 | 
			
		||||
 | 
			
		||||
	 ;; This is the core letrec -- the wait-for-input &
 | 
			
		||||
	 ;; try-to-match loop.
 | 
			
		||||
	 (inner-loop `(,%letrec (,@do-eofs
 | 
			
		||||
				 ,@try-matches
 | 
			
		||||
				 ,@try-tasks
 | 
			
		||||
				 (,%do-select ,loop-top))
 | 
			
		||||
		        ,initial-trymatch))
 | 
			
		||||
 | 
			
		||||
	 ;; This is the outer, named loop (if any).
 | 
			
		||||
	 (named-loop (if exp-name
 | 
			
		||||
			 `(,%let ,exp-name ,loop-var-inits
 | 
			
		||||
			    ,inner-loop)
 | 
			
		||||
			 inner-loop)))
 | 
			
		||||
 | 
			
		||||
    ;; Build the final expression.
 | 
			
		||||
    `(,%let* (,@task-bindings
 | 
			
		||||
	      ,ivec-binding
 | 
			
		||||
	      (,%monitor ,mon-exp)
 | 
			
		||||
	      ,@(if timeout-var
 | 
			
		||||
		    `((,timeout-var ,timeout-secs)
 | 
			
		||||
		      (,timeout-var (,%and ,timeout-var
 | 
			
		||||
					   (,%+ (,%time) ,timeout-var))))
 | 
			
		||||
		    '()))		; No timeout-var binding needed.
 | 
			
		||||
       ,named-loop)))
 | 
			
		||||
| 
						 | 
				
			
			@ -3,13 +3,6 @@
 | 
			
		|||
  (open scheme-with-scsh let-opt)
 | 
			
		||||
  (files tty-utils))
 | 
			
		||||
 | 
			
		||||
(define-structure expect-syntax-support
 | 
			
		||||
  (export expand-expect)
 | 
			
		||||
  (open scheme structure-refs srfi-1
 | 
			
		||||
	receiving) ; for making alien containers.
 | 
			
		||||
  (access signals) ; for ERROR
 | 
			
		||||
  (files expect-syntax))
 | 
			
		||||
 | 
			
		||||
(define-structure expect
 | 
			
		||||
  (export task? make-task
 | 
			
		||||
	  task:process
 | 
			
		||||
| 
						 | 
				
			
			@ -27,25 +20,21 @@
 | 
			
		|||
	  (expect :syntax)
 | 
			
		||||
	  expect*
 | 
			
		||||
 | 
			
		||||
	  interact* interact/char*
 | 
			
		||||
	  (interact :syntax))
 | 
			
		||||
  (for-syntax (open scheme-with-scsh))
 | 
			
		||||
	  interact*
 | 
			
		||||
	  (interact :syntax)
 | 
			
		||||
 | 
			
		||||
  (open scheme-with-scsh formats structure-refs let-opt
 | 
			
		||||
	receiving srfi-9 srfi-13 srfi-1)
 | 
			
		||||
 | 
			
		||||
  (files expect interact))
 | 
			
		||||
 | 
			
		||||
(define-structure chat
 | 
			
		||||
  (export chat-abort chat-timeout chat-monitor
 | 
			
		||||
	  chat-abort chat-timeout chat-monitor
 | 
			
		||||
	  port->chat-logger file->chat-logger
 | 
			
		||||
	  (look-for 	      :syntax)
 | 
			
		||||
	  (chat 	      :syntax)
 | 
			
		||||
	  send send/cr)
 | 
			
		||||
  (for-syntax (open scheme-with-scsh))
 | 
			
		||||
 | 
			
		||||
  (open scheme-with-scsh expect fluids)
 | 
			
		||||
  (open scheme-with-scsh formats structure-refs let-opt
 | 
			
		||||
	receiving srfi-9 srfi-13 srfi-1 srfi-11
 | 
			
		||||
	tty-utils fluids)
 | 
			
		||||
 | 
			
		||||
  (files chat))
 | 
			
		||||
  (files expect interact chat))
 | 
			
		||||
 | 
			
		||||
(define-structure printf-package
 | 
			
		||||
  (export printf sprintf display/cr display/nl)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue