1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-06-09 13:30:26 +02:00

Make Macros Hygienic

* modules/ice-9/peg.scm: convert the unhygienic macros that generate code
    for string PEGs to use hygiene.
This commit is contained in:
Noah Lavine 2011-03-05 22:37:11 -05:00 committed by Andy Wingo
parent 86849e2c19
commit 00923497d2

View file

@ -294,7 +294,7 @@ RB < ']'
;; Pakes a string representing a PEG grammar and defines all the nonterminals in ;; Pakes a string representing a PEG grammar and defines all the nonterminals in
;; it as the associated PEGs. ;; it as the associated PEGs.
(define (peg-parser str) (define (peg-parser str for-syntax)
(let ((parsed (peg-parse peg-grammar str))) (let ((parsed (peg-parse peg-grammar str)))
(if (not parsed) (if (not parsed)
(begin (begin
@ -305,9 +305,10 @@ RB < ']'
((or (not (list? lst)) (null? lst)) ((or (not (list? lst)) (null? lst))
lst) lst)
((eq? (car lst) 'peg-grammar) ((eq? (car lst) 'peg-grammar)
(cons 'begin (map (lambda (x) (peg-nonterm->defn x)) #`(begin
(context-flatten (lambda (lst) (<= (depth lst) 2)) #,@(map (lambda (x) (peg-nonterm->defn x for-syntax))
(cdr lst)))))))))) (context-flatten (lambda (lst) (<= (depth lst) 2))
(cdr lst))))))))))
;; Macro wrapper for PEG-PARSER. Parses PEG grammars expressed as strings and ;; Macro wrapper for PEG-PARSER. Parses PEG grammars expressed as strings and
;; defines all the appropriate nonterminals. ;; defines all the appropriate nonterminals.
@ -315,88 +316,101 @@ RB < ']'
(lambda (x) (lambda (x)
(syntax-case x () (syntax-case x ()
((_ str) ((_ str)
(datum->syntax x (peg-parser (syntax->datum #'str))))))) (peg-parser (syntax->datum #'str) x)))))
(define define-grammar-f peg-parser) (define define-grammar-f peg-parser)
;; Parse a nonterminal and pattern listed in LST. ;; Parse a nonterminal and pattern listed in LST.
(define (peg-nonterm->defn lst) (define (peg-nonterm->defn lst for-syntax)
(let ((nonterm (car lst)) (let* ((nonterm (car lst))
(grabber (cadr lst)) (grabber (cadr lst))
(pattern (caddr lst))) (pattern (caddr lst))
`(define-nonterm ,(string->symbol (cadr nonterm)) (nonterm-name (datum->syntax for-syntax
,(cond (string->symbol (cadr nonterm)))))
((string=? grabber "<--") 'all) #`(define-nonterm #,nonterm-name
((string=? grabber "<-") 'body) #,(cond
(else 'none)) ((string=? grabber "<--") (datum->syntax for-syntax 'all))
,(compressor (peg-pattern->defn pattern))))) ((string=? grabber "<-") (datum->syntax for-syntax 'body))
(else (datum->syntax for-syntax 'none)))
#,(compressor (peg-pattern->defn pattern for-syntax) for-syntax))))
;; Parse a pattern. ;; Parse a pattern.
(define (peg-pattern->defn lst) (define (peg-pattern->defn lst for-syntax)
(cons 'or (map peg-alternative->defn #`(or #,@(map (lambda (x) (peg-alternative->defn x for-syntax))
(context-flatten (lambda (x) (eq? (car x) 'peg-alternative)) (context-flatten (lambda (x) (eq? (car x) 'peg-alternative))
(cdr lst))))) (cdr lst)))))
;; Parse an alternative. ;; Parse an alternative.
(define (peg-alternative->defn lst) (define (peg-alternative->defn lst for-syntax)
(cons 'and (map peg-body->defn #`(and #,@(map (lambda (x) (peg-body->defn x for-syntax))
(context-flatten (lambda (x) (or (string? (car x)) (context-flatten (lambda (x) (or (string? (car x))
(eq? (car x) 'peg-suffix))) (eq? (car x) 'peg-suffix)))
(cdr lst))))) (cdr lst)))))
;; Parse a body. ;; Parse a body.
(define (peg-body->defn lst) (define (peg-body->defn lst for-syntax)
(let ((suffix '()) (let ((suffix '())
(front 'lit)) (front (datum->syntax for-syntax 'lit)))
(cond (cond
((eq? (car lst) 'peg-suffix) ((eq? (car lst) 'peg-suffix)
(set! suffix lst)) (set! suffix lst))
((string? (car lst)) ((string? (car lst))
(begin (set! front (string->symbol (car lst))) (begin (set! front (datum->syntax for-syntax
(string->symbol (car lst))))
(set! suffix (cadr lst)))) (set! suffix (cadr lst))))
(else `(peg-parse-body-fail ,lst))) (else `(peg-parse-body-fail ,lst)))
`(body ,front ,@(peg-suffix->defn suffix)))) #`(body #,front #,@(peg-suffix->defn
suffix
for-syntax))))
;; Parse a suffix. ;; Parse a suffix.
(define (peg-suffix->defn lst) (define (peg-suffix->defn lst for-syntax)
(list (peg-primary->defn (cadr lst)) #`(#,(peg-primary->defn (cadr lst) for-syntax)
(if (null? (cddr lst)) #,(if (null? (cddr lst))
1 1
(string->symbol (caddr lst))))) (datum->syntax for-syntax (string->symbol (caddr lst))))))
;; Parse a primary. ;; Parse a primary.
(define (peg-primary->defn lst) (define (peg-primary->defn lst for-syntax)
(let ((el (cadr lst))) (let ((el (cadr lst)))
(cond (cond
((list? el) ((list? el)
(cond (cond
((eq? (car el) 'peg-literal) ((eq? (car el) 'peg-literal)
(peg-literal->defn el)) (peg-literal->defn el for-syntax))
((eq? (car el) 'peg-charclass) ((eq? (car el) 'peg-charclass)
(peg-charclass->defn el)) (peg-charclass->defn el for-syntax))
((eq? (car el) 'peg-nonterminal) ((eq? (car el) 'peg-nonterminal)
(string->symbol (cadr el))))) (datum->syntax for-syntax (string->symbol (cadr el))))))
((string? el) ((string? el)
(cond (cond
((equal? el "(") ((equal? el "(")
(peg-pattern->defn (caddr lst))) (peg-pattern->defn (caddr lst) for-syntax))
((equal? el ".") ((equal? el ".")
'peg-any) (datum->syntax for-syntax 'peg-any))
(else `(peg-parse-any unknown-string ,lst)))) (else (datum->syntax for-syntax
(else `(peg-parse-any unknown-el ,lst))))) `(peg-parse-any unknown-string ,lst)))))
(else (datum->syntax for-syntax
`(peg-parse-any unknown-el ,lst))))))
;; Parses a literal. ;; Parses a literal.
(define (peg-literal->defn lst) (trim-1chars (cadr lst))) (define (peg-literal->defn lst for-syntax)
(datum->syntax for-syntax (trim-1chars (cadr lst))))
;; Parses a charclass. ;; Parses a charclass.
(define (peg-charclass->defn lst) (define (peg-charclass->defn lst for-syntax)
(cons 'or #`(or
(map #,@(map
(lambda (cc) (lambda (cc)
(cond (cond
((eq? (car cc) 'charclass-range) ((eq? (car cc) 'charclass-range)
`(range ,(string-ref (cadr cc) 0) ,(string-ref (cadr cc) 2))) #`(range #,(datum->syntax
for-syntax
(string-ref (cadr cc) 0))
#,(datum->syntax
for-syntax
(string-ref (cadr cc) 2))))
((eq? (car cc) 'charclass-single) ((eq? (car cc) 'charclass-single)
(cadr cc)))) (datum->syntax for-syntax (cadr cc)))))
(context-flatten (context-flatten
(lambda (x) (or (eq? (car x) 'charclass-range) (lambda (x) (or (eq? (car x) 'charclass-range)
(eq? (car x) 'charclass-single))) (eq? (car x) 'charclass-single)))
@ -404,27 +418,30 @@ RB < ']'
;; Compresses a list to save the optimizer work. ;; Compresses a list to save the optimizer work.
;; e.g. (or (and a)) -> a ;; e.g. (or (and a)) -> a
(define (compressor lst) (define (compressor-core lst)
(if (or (not (list? lst)) (null? lst)) (if (or (not (list? lst)) (null? lst))
lst lst
(cond (cond
((and (or (eq? (car lst) 'or) (eq? (car lst) 'and)) ((and (or (eq? (car lst) 'or) (eq? (car lst) 'and))
(null? (cddr lst))) (null? (cddr lst)))
(compressor (cadr lst))) (compressor-core (cadr lst)))
((and (eq? (car lst) 'body) ((and (eq? (car lst) 'body)
(eq? (cadr lst) 'lit) (eq? (cadr lst) 'lit)
(eq? (cadddr lst) 1)) (eq? (cadddr lst) 1))
(compressor (caddr lst))) (compressor-core (caddr lst)))
(else (map compressor lst))))) (else (map compressor-core lst)))))
(define (compressor syn for-syntax)
(datum->syntax for-syntax
(compressor-core (syntax->datum syn))))
;; Builds a lambda-expressions for the pattern STR using accum. ;; Builds a lambda-expressions for the pattern STR using accum.
(define (peg-string-compile str-stx accum) (define (peg-string-compile str-stx accum)
(peg-sexp-compile (peg-sexp-compile
(datum->syntax (compressor
str-stx (peg-pattern->defn
(compressor (peg:tree (peg-parse peg-pattern (syntax->datum str-stx))) str-stx)
(peg-pattern->defn str-stx)
(peg:tree (peg-parse peg-pattern (syntax->datum str-stx))))))
accum)) accum))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;