Add 'not-followed-by' PEG
authorNoah Lavine <nlavine@haverford.edu>
Mon, 19 Sep 2011 14:33:09 +0000 (10:33 -0400)
committerAndy Wingo <wingo@pobox.com>
Wed, 16 Jan 2013 09:11:46 +0000 (10:11 +0100)
The PEG s-expression syntax now uses '(not-followed-by ...)' instead of
'(body ! ... 1)'.

doc/ref/api-peg.texi
module/ice-9/peg/codegen.scm
module/ice-9/peg/string-peg.scm

index 4976b59..111f150 100644 (file)
@@ -99,13 +99,13 @@ it.  Succeeds if @var{a} would succeed.
 @code{(followed-by a)}
 @end deftp
 
-@deftp {PEG Pattern} {not predicate} a
+@deftp {PEG Pattern} {not followed by} a
 Makes sure it is impossible to parse @var{a}, but does not actually
 parse it.  Succeeds if @var{a} would fail.
 
 @code{"!a"}
 
-@code{(body ! a 1)}
+@code{(not-followed-by a)}
 @end deftp
 
 @deftp {PEG Pattern} {string literal} ``abc''
index 22fb195..3cdf4cc 100644 (file)
@@ -316,6 +316,26 @@ return EXP."
                      #,#`(and success
                               #,(cggr (baf accum) 'cg-body #''() #'at)))))))))))
 
+(define (cg-not-followed-by args accum)
+  (syntax-case args ()
+    ((pat)
+     #`(lambda (str strlen at)
+         (let ((body '()))
+           (let lp ((end at) (count 0))
+             (let* ((match (#,(peg-sexp-compile #'pat (baf accum))
+                            str strlen end))
+                    (new-end (if match (car match) end))
+                    (count (if (> new-end end) (1+ count) count)))
+               (if (> new-end end)
+                   (push-not-null! body (single-filter (cadr match))))
+               (if (and (> new-end end)
+                        #,#'(< count 1))
+                   (lp new-end count)
+                   (let ((success #,#'(= count 1)))
+                     #,#`(if success
+                                #f
+                                #,(cggr (baf accum) 'cg-body #''() #'at)))))))))))
+
 ;; Association list of functions to handle different expressions as PEGs
 (define peg-compiler-alist '())
 
@@ -333,6 +353,7 @@ return EXP."
 (add-peg-compiler! '+ cg-+)
 (add-peg-compiler! '? cg-?)
 (add-peg-compiler! 'followed-by cg-followed-by)
+(add-peg-compiler! 'not-followed-by cg-not-followed-by)
 
 ;; Takes an arbitrary expressions and accumulation variable, then parses it.
 ;; E.g.: (peg-sexp-compile syntax '(and "abc" (or "-" (range #\a #\z))) 'all)
index ccd4056..c776d1d 100644 (file)
@@ -78,12 +78,12 @@ RB < ']'
       (and "." peg-sp)
       peg-literal
       peg-charclass
-      (and peg-nonterminal (body ! "<" 1))))
+      (and peg-nonterminal (not-followed-by "<"))))
 (define-sexp-parser peg-literal all
-  (and "'" (* (and (body ! "'" 1) peg-any)) "'" peg-sp))
+  (and "'" (* (and (not-followed-by "'") peg-any)) "'" peg-sp))
 (define-sexp-parser peg-charclass all
   (and (ignore "[")
-       (* (and (body ! "]" 1)
+       (* (and (not-followed-by "]")
                (or charclass-range charclass-single)))
        (ignore "]")
        peg-sp))