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:
parent
86849e2c19
commit
00923497d2
1 changed files with 73 additions and 56 deletions
|
@ -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))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue