Re: syntax-case in the repl and in the module system

Johannes Bruegmann <[email protected]> Mon, 19 May 2008 22:19:56 +0200
Newsgroups gmane.comp.java.sisc.user
Message-ID <[email protected]>
Hello,

"Scott G. Miller" <[email protected]> writes:

> On Mon, May 19, 2008 at 11:29 AM, Johannes Bruegmann
> <[email protected]> wrote:
>>
> Psyntax is a bit picky about the way modules reference defined
> bindings in their own definitions.  It behaves like letrec, where
> right hand sides can't reference any other letrec binding at
> definition time.  In awk.scm, this happens when it expands the syntax
> definitions in the awk macro.  The easiest workaround is to make the
> dependent functions of the awk macro internal definitions, eg:
>
> (define-syntax awk
>   (lambda (stx)
>     (define (syntax->list ...
>
> etc
>
> Hope that works,

It worked, yes! And now i know where to read on regarding psyntax!


Thanks a lot,
Johannes

The working awk.scm now looks like this (in case anybody else ever
will be interested in):

;;; awk.scm - provide awk-like macro

;;; the awk macro and its dependencies in this file are from mzscheme/mzlib=
/awk.ss
;;; syntax->list is from ChezScheme

;;;@chapter Module @code{awk}
;;;@section Imports/Exports in SISC
;;;@lisp
;;; (module awk
;;;     (make-infix-field-splitter newline? read-line regexp regexp-match r=
egexp-exec (awk))
;;; =

;;;   (import srfi-1)
;;;   (import srfi-14)
;;;   (import srfi-23)
;;;   (import srfi-28)
;;;   (import scsh-regexp/scsh-regexp)
;;; =

;;;   (include "awk.scm")
;;; =

;;; )
;;;@end lisp
;;;@section Description
;;;provide awk-like macro (as introduced by Olin Shivers in Scsh-Manual, Ch=
apter 8) for SISC

;;;@args : char -> bool
;;;predicate for newline
(define (newline? char)
  (and (char-set-contains? char-set:whitespace char)
       (not (char-set-contains? char-set:blank char))))

;;;@args : port -> string
;;;reads @var{port} until newline
(define (read-line port . maybe-drop-newline?)
  (let ((drop-newline? (if (null? maybe-drop-newline?) #f (car maybe-drop-n=
ewline?))))
    (let loop ((chars '()))
      (let ((c (peek-char port)))
	(if (and (null? chars) (eof-object? c))
	    c
	    (let ((next-chars (if (eof-object? c) =

				  chars =

				  (if (and (newline? (read-char port)) drop-newline?)
				      chars =

				      (cons c chars)))))
	      (if (or (eof-object? c) (newline? c))
		  (list->string (reverse next-chars))
		  (loop next-chars))))))))

;;;@args : delim -> string -> list of fields
;;;create an infix field splitter
(define (make-infix-field-splitter delim)
  (let ((rx (posix-string->regexp (format "[^~a]+" delim))))
    (lambda (string)
      (regexp-fold-right rx =

			 (lambda (m nm res)
			     (cons (match:substring m 0) res))
			 '() string))))

(define regexp posix-string->regexp)

(define (regexp-exec re s)
  (let ((rx (if (string? re) (posix-string->regexp re) re)))
    (let ((m (regexp-search rx s)))
      m)))

(define (regexp-match re s)
  (let ((rx (if (string? re) (posix-string->regexp re) re)))
    (let ((m (regexp-search rx s)))
      m)))

;;;@ (AWK <.next-record.> <.record&field-vars.> [<.counter.>] <.state-var-d=
ecls.> <.clause[1].> ...)
;;;provide loop macro with awk facility, see SCSH-Manual, Chapter 8
(define-syntax awk
  (lambda (stx)
    ;; from Chez Scheme, K. Dybvig, syntax-case
    (define syntax->list
      (lambda (ls)
	(syntax-case ls ()
	  (() '())
	  ((x . r) (cons (syntax x) (syntax->list (syntax r)))))))

    ;; a syntax null?
    (define (stx-null? p)
      (or (null? p)
	  (null? (syntax-object->datum p))))

    (define (raise-syntax-error=A0name message-string=A0expr sub-expr)
      (error (string-append name ": " message-string ": " expr ": " sub-exp=
r)))

    (syntax-case stx ()
      ((_ next-record (record field ...) counter ((state-variable init-expr=
) ...) continue clause ...)
       (and (identifier? (syntax counter)) (identifier? (syntax continue)))
       (let ((clauses (syntax->list (syntax (clause ...))))
             (initvars '()))
         (with-syntax (((local-state ...) (generate-temporaries (syntax->li=
st (syntax (state-variable ...))))))
           (letrec ((get-after-clauses (lambda ()
					 (let loop ((l clauses) (afters '()))
					   (cond
					    ((null? l) (if (stx-null? afters)
							   (syntax ((values state-variable ...)))
							   afters))
					    ((syntax-case (car l) (after) ((after . rest) (syntax rest)) (_els=
e #f))
					     =3D> (lambda (rest)
						  (with-syntax (((after ...) afters))
						    (loop (cdr l) (syntax (after ... .  rest))))))
					    (else (loop (cdr l) afters))))))
		    (wrap-state (lambda (e)
				  (syntax-case e (=3D>) =

				    ((=3D> f) (with-syntax ((body (wrap-state (syntax ((f arg))))))
					      (syntax (=3D> (lambda (arg) . body)))))
				    (body (syntax ((call-with-values (lambda () . body)
						     (lambda (local-state ... . extras)
						       (set! else-ready? #f)
						       (set! state-variable local-state)
						       ...))))))))
		    (make-range (lambda (include-on? include-off? body rest)
				  (syntax-case body ()
				    ((t1 t2 . body)
				     (with-syntax ((on? (car (generate-temporaries '(1))))
						   (t1 (make-test (syntax-object->datum (syntax t1)) (syntax t1)))
						   (t2 (make-test (syntax-object->datum (syntax t2)) (syntax t2)))
						   (body (wrap-state (syntax body))))
				       (with-syntax ((check (if include-on?
								(if include-off?
								    (syntax post-on-on?)
								    (syntax on?))
								(if include-off?
								    (syntax orig-on?)
								    (syntax (and orig-on? on?))))))
					 (set! initvars (cons (syntax (on? #f)) initvars))
					 (syntax ((let ((orig-on? on?))
						    (unless on? (set! on? t1))
						    (let ((post-on-on? on?))
						      (when on? (set! on? (not t2))))
						    (when check . body)) . rest)))))
				    (_else (raise-syntax-error #f "bad range" stx body)))))
		    (make-test (lambda (test expr)
				 (cond
				  ((string? test)
				   (with-syntax ((g (car (generate-temporaries '(1))))
						 (expr expr))
				     (set! initvars (cons (syntax (g (regexp expr))) initvars))
				     (syntax (regexp-exec expr record))))
				  ((number? test)
				   (with-syntax ((expr expr))
				     (syntax (=3D expr counter))))
				  (else expr))))
		    (get-testing-clauses =

		     (lambda ()
		       (let loop ((l clauses))
			 (if (null? l)
			     '()
			     (syntax-case (car l) ()
			       ((test-expr body ...)
				(with-syntax ((rest (loop (cdr l))))
				  (let ((test (syntax-object->datum (syntax test-expr)))
					(body (syntax (body ...))))
				    (cond
				     ((or (string? test) (number? test))
				      (with-syntax ((t (make-test test (syntax test-expr)))
						    (body (wrap-state body)))
					(syntax ((cond (t . body) (else (void))) . rest))))
				     ((eq? test 'else)
				      (with-syntax ((body (wrap-state body)))
					(syntax ((when else-ready? . body) (set! else-ready? #t) . rest))))
				     ((eq? test 'range) =

				      (make-range #f #f body (syntax rest)))
				     ((eq? test ':range)
				      (make-range #t #f body (syntax rest)))
				     ((eq? test 'range:)
				      (make-range #f #t body (syntax rest)))
				     ((eq? test ':range:)
				      (make-range #t #t body (syntax rest)))
				     ((eq? test 'after) =

				      (syntax rest))
				     ((eq? test '/)
				      (with-syntax ((g (car (generate-temporaries '(1)))))
					; PLT used syntax-case* at this place (syntax-case* takes a comparison=
-procedure after the literals
                                        ; to compare literals with their po=
tential matches in clauses
					(syntax-case body (/) =

						      ((re / (var ...) . body)
						       (and ;((lambda (a b) (eq? (syntax-object->datum a) (syntax-obj=
ect->datum b))) (syntax /) (syntax slash))
							    (string? (syntax-object->datum (syntax re)))
							    (andmap (lambda (x) (or (identifier? x) (not (syntax-object->dat=
um x))))
								    (syntax->list (syntax (var ...)))))
						       (with-syntax (((var ...) (map (lambda (x)
										       (if (identifier? x)
											   x
											   (car (generate-temporaries '(1)))))
										     (syntax->list (syntax (var ...)))))
								     (body (wrap-state (syntax body))))
							 (set! initvars (cons (syntax (g (regexp re))) initvars))
							 (syntax ((cond
								   ((regexp-match re record) =3D> (lambda (arg)
												  (apply (lambda (var ...) . body) arg)))
								   (else (void)))
								  . rest))))
						      (_else (raise-syntax-error #f "bad / ... / clause" stx (car l))=
))))
				     (else (with-syntax ((body (wrap-state body)))
					     (syntax ((cond =

						       (test-expr . body)
						       (else (void))) . rest))))))))
			       (_else (raise-syntax-error #f "bad clause" stx (car l)))))))))
             (with-syntax ((testing-clauses (get-testing-clauses))
			   (after-clauses (get-after-clauses))
			   (initvars initvars))
	       (syntax (let ((state-variable init-expr) ... . initvars)
			 (let loop ((counter 1)) =

			   (call-with-values (lambda () next-record)
			     (lambda (record field ...)
			       (if (eof-object? record)
				   (begin . after-clauses)
				   (let ((else-ready? #t))
				     (call-with-current-continuation =

				      (lambda (escape)
					(let ((continue (lambda (local-state ... . extras)
							  (set! state-variable local-state)
							  ...
							  (escape))))
					  . testing-clauses)))
				     (loop (add1 counter))))))))))))))
      ;; Left out continue...
      ((_ next-record (record field-variable ...) counter-variable ((state-=
variable init-expr) ...) clause ...)
       (identifier? (syntax counter-variable))
       (syntax (awk next-record (record field-variable ...) counter-variabl=
e ((state-variable init-expr) ...) continue clause ...)))
      ;; Left out counter...
      ((_ next-record (record field-variable ...) ((state-variable init-exp=
r) ...) continue-variable clause ...)
       (identifier? (syntax continue-variable))
       (syntax (awk next-record (record field-variable ...) counter ((state=
-variable init-expr) ...) continue-variable clause ...)))
      ;; Left out both...
      ((_ next-record (record field-variable ...) ((state-variable init-exp=
r) ...) clause ...)
       (syntax (awk next-record (record field-variable ...) counter ((state=
-variable init-expr) ...) continue clause ...))))))

-- =

       Wo  sind  denn  deine  G=F6tter, die du dir gemacht hast? Sie sollen=
 sich
       aufmachen, wenn sie dich retten k=F6nnen zur Zeit deines Ungl=FCcks!

                                                    Jeremia 2, 28

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft =

Defy all challenges. Microsoft(R) Visual Studio 2008. =

http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/