using-parsers.scm 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. ;;;; using-parsers.scm --- utilities to make using parsers easier
  2. ;;;;
  3. ;;;; Copyright (C) 2010, 2011 Free Software Foundation, Inc.
  4. ;;;;
  5. ;;;; This library is free software; you can redistribute it and/or
  6. ;;;; modify it under the terms of the GNU Lesser General Public
  7. ;;;; License as published by the Free Software Foundation; either
  8. ;;;; version 3 of the License, or (at your option) any later version.
  9. ;;;;
  10. ;;;; This library is distributed in the hope that it will be useful,
  11. ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. ;;;; Lesser General Public License for more details.
  14. ;;;;
  15. ;;;; You should have received a copy of the GNU Lesser General Public
  16. ;;;; License along with this library; if not, write to the Free Software
  17. ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  18. ;;;;
  19. (define-module (ice-9 peg using-parsers)
  20. #:use-module (ice-9 peg simplify-tree)
  21. #:use-module (ice-9 peg codegen)
  22. #:use-module (ice-9 peg cache)
  23. #:export (match-pattern define-peg-pattern search-for-pattern
  24. prec make-prec peg:start peg:end peg:string
  25. peg:tree peg:substring peg-record?))
  26. ;;;
  27. ;;; Helper Macros
  28. ;;;
  29. (define-syntax until
  30. (syntax-rules ()
  31. "Evaluate TEST. If it is true, return its value. Otherwise,
  32. execute the STMTs and try again."
  33. ((_ test stmt stmt* ...)
  34. (let lp ()
  35. (or test
  36. (begin stmt stmt* ... (lp)))))))
  37. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  38. ;;;;; FOR DEFINING AND USING NONTERMINALS
  39. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  40. ;; Parses STRING using NONTERM
  41. (define (match-pattern nonterm string)
  42. ;; We copy the string before using it because it might have been modified
  43. ;; in-place since the last time it was parsed, which would invalidate the
  44. ;; cache. Guile uses copy-on-write for strings, so this is fast.
  45. (let ((res (nonterm (string-copy string) (string-length string) 0)))
  46. (if (not res)
  47. #f
  48. (make-prec 0 (car res) string (string-collapse (cadr res))))))
  49. ;; Defines a new nonterminal symbol accumulating with ACCUM.
  50. (define-syntax define-peg-pattern
  51. (lambda (x)
  52. (syntax-case x ()
  53. ((_ sym accum pat)
  54. (let ((matchf (compile-peg-pattern #'pat (syntax->datum #'accum)))
  55. (accumsym (syntax->datum #'accum)))
  56. ;; CODE is the code to parse the string if the result isn't cached.
  57. (let ((syn (wrap-parser-for-users x matchf accumsym #'sym)))
  58. #`(define sym #,(cg-cached-parser syn))))))))
  59. (define (peg-like->peg pat)
  60. (syntax-case pat ()
  61. (str (string? (syntax->datum #'str)) #'(peg str))
  62. (else pat)))
  63. ;; Searches through STRING for something that parses to PEG-MATCHER. Think
  64. ;; regexp search.
  65. (define-syntax search-for-pattern
  66. (lambda (x)
  67. (syntax-case x ()
  68. ((_ pattern string-uncopied)
  69. (let ((pmsym (syntax->datum #'pattern)))
  70. (let ((matcher (compile-peg-pattern (peg-like->peg #'pattern) 'body)))
  71. ;; We copy the string before using it because it might have been
  72. ;; modified in-place since the last time it was parsed, which would
  73. ;; invalidate the cache. Guile uses copy-on-write for strings, so
  74. ;; this is fast.
  75. #`(let ((string (string-copy string-uncopied))
  76. (strlen (string-length string-uncopied))
  77. (at 0))
  78. (let ((ret (until (or (>= at strlen)
  79. (#,matcher string strlen at))
  80. (set! at (+ at 1)))))
  81. (if (eq? ret #t) ;; (>= at strlen) succeeded
  82. #f
  83. (let ((end (car ret))
  84. (match (cadr ret)))
  85. (make-prec
  86. at end string
  87. (string-collapse match))))))))))))
  88. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  89. ;;;;; PMATCH STRUCTURE MUNGING
  90. ;; Pretty self-explanatory.
  91. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  92. (define prec
  93. (make-record-type "peg" '(start end string tree)))
  94. (define make-prec
  95. (record-constructor prec '(start end string tree)))
  96. (define (peg:start pm)
  97. (if pm ((record-accessor prec 'start) pm) #f))
  98. (define (peg:end pm)
  99. (if pm ((record-accessor prec 'end) pm) #f))
  100. (define (peg:string pm)
  101. (if pm ((record-accessor prec 'string) pm) #f))
  102. (define (peg:tree pm)
  103. (if pm ((record-accessor prec 'tree) pm) #f))
  104. (define (peg:substring pm)
  105. (if pm (substring (peg:string pm) (peg:start pm) (peg:end pm)) #f))
  106. (define peg-record? (record-predicate prec))