parser-combinators.scm 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. ;;; Guile Parser Combinators
  2. ;;; Copyright © 2015 David Thompson <davet@gnu.org>
  3. ;;;
  4. ;;; This module is free software; you can redistribute it and/or
  5. ;;; modify it under the terms of the GNU Lesser General Public License
  6. ;;; as published by the Free Software Foundation; either version 3 of
  7. ;;; the License, or (at your option) any later version.
  8. ;;;
  9. ;;; This module is distributed in the hope that it will be useful, but
  10. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. ;;; Lesser General Public License for more details.
  13. ;;;
  14. ;;; You should have received a copy of the GNU Lesser General Public
  15. ;;; License along with this module. If not, see
  16. ;;; <http://www.gnu.org/licenses/>.
  17. ;;; Commentary:
  18. ;;
  19. ;; Monadic parser combinators.
  20. ;;
  21. ;;; Code:
  22. (define-module (parser-combinators)
  23. #:use-module (ice-9 match)
  24. #:use-module (ice-9 q)
  25. #:use-module (srfi srfi-1)
  26. #:use-module (srfi srfi-9)
  27. #:use-module (srfi srfi-26)
  28. #:use-module (srfi srfi-41)
  29. #:export (parse-result
  30. parse-result?
  31. parse-result-value
  32. parse-result-index
  33. parse-failure?
  34. parse-success?
  35. %parse-failure
  36. parse-fail
  37. parse-bind
  38. parse-return
  39. parse-lift
  40. parse
  41. parse-map
  42. parse-match
  43. parse-any
  44. parse-each
  45. parse-end
  46. parse-zero-or-more
  47. parse-one-or-more
  48. parse-up-to
  49. parse-maybe
  50. parse-any-char
  51. parse-char
  52. parse-char-set
  53. parse-string))
  54. ;;;
  55. ;;; Core
  56. ;;;
  57. (define-record-type <parse-result>
  58. (parse-result value stream)
  59. parse-result?
  60. (value parse-result-value)
  61. (stream parse-result-stream))
  62. (define (parse-failure? result)
  63. "Return #t if RESULT represents a failed parse."
  64. (not (parse-result-stream result)))
  65. (define (parse-success? result)
  66. "Return #t if RESULT represents a successful parse."
  67. (stream? (parse-result-stream result)))
  68. (define (parse-done? result)
  69. "Return #t if the remainder of RESULT is the empty stream."
  70. (stream-null? (parse-result-stream result)))
  71. (define %parse-failure (parse-result #f #f))
  72. (define (parse-fail stream)
  73. "Always fail to parse STREAM."
  74. %parse-failure)
  75. (define (parse-bind proc parser)
  76. (lambda (stream)
  77. (match (parser stream)
  78. ((? parse-failure? _) %parse-failure)
  79. (($ <parse-result> value stream)
  80. ((proc value) stream)))))
  81. (define (parse-return x)
  82. "Return a parser that always yields X as the parse result."
  83. (lambda (stream)
  84. (parse-result x stream)))
  85. (define (parse-lift proc)
  86. "Return a procedure that wraps the result of PROC in a parser."
  87. (lambda args
  88. (parse-return (apply proc args))))
  89. (define (string->stream str)
  90. "Convert the string STR into a stream of characters."
  91. (stream-map (lambda (i)
  92. (string-ref str i))
  93. (stream-range 0 (string-length str))))
  94. (define* (parse parser obj #:optional (fail-value #f))
  95. "Parse the contents of OBJ with PARSER. OBJ may be either a string, port,
  96. or stream."
  97. (let ((stream (match obj
  98. ;; Handle strings and ports as a convenience.
  99. ((? string? str) (string->stream str))
  100. ((? port? port) (port->stream port))
  101. ((? stream? stream) stream))))
  102. (match (parser stream)
  103. ((or (? parse-failure?)
  104. (not (? parse-done?)))
  105. fail-value)
  106. (($ <parse-result> value _) value))))
  107. ;;;
  108. ;;; Extras
  109. ;;;
  110. (define (parse-map proc parser)
  111. "Return a new parser that applies PROC to result of PARSER."
  112. (parse-bind (parse-lift proc) parser))
  113. (define-syntax-rule (parse-match parser matchers ...)
  114. "Create a parser that applies pattern matching to transform the
  115. successful results of PARSER using MATCHERS. MATCHERS uses the (ice-9
  116. match) pattern matching syntax."
  117. (parse-map (match-lambda matchers ...) parser))
  118. (define (%parse-any . parsers)
  119. (lambda (stream)
  120. (let loop ((parsers parsers))
  121. (match parsers
  122. (() %parse-failure)
  123. ((parser . rest)
  124. (match ((force parser) stream)
  125. ((? parse-failure? _)
  126. (loop rest))
  127. (result result)))))))
  128. (define (%parse-each . parsers)
  129. (lambda (stream)
  130. (let loop ((stream stream)
  131. (parsers parsers)
  132. (result '()))
  133. (match parsers
  134. (() (parse-result (reverse result) stream))
  135. ((parser . rest)
  136. (match ((force parser) stream)
  137. ((? parse-failure?) %parse-failure)
  138. (($ <parse-result> value stream)
  139. (loop stream rest (cons value result)))))))))
  140. ;; parse-any and parse-seach are special forms to abstract the lazy
  141. ;; evaluation used to handle right recursive grammars.
  142. (define-syntax-rule (parse-any parser ...)
  143. "Create a disjunctive parser that succeeds if any of the input
  144. parsers succeed."
  145. (%parse-any (delay parser) ...))
  146. (define-syntax-rule (parse-each parser ...)
  147. "Create a sequential parser that returns a list of parse results if
  148. all of the input parsers succeed."
  149. (%parse-each (delay parser) ...))
  150. (define (parse-end stream)
  151. "Succeed with #t if STREAM is emtpy or fail otherwise."
  152. (if (stream-null? stream)
  153. (parse-result #t stream-null)
  154. %parse-failure))
  155. (define (parse-zero-or-more parser)
  156. "Create a parser that applies PARSER as many times as it can before
  157. failing and returns list of the successful parse results."
  158. (lambda (stream)
  159. (let loop ((stream stream)
  160. (result '()))
  161. (match (parser stream)
  162. ((? parse-failure?)
  163. (parse-result (reverse result) stream))
  164. (($ <parse-result> value stream)
  165. (loop stream (cons value result)))))))
  166. (define (parse-one-or-more parser)
  167. "Return a parser that succeeds when PARSER can be successfully
  168. applied at least once and returns a list of the successful parse
  169. results."
  170. (lambda (stream)
  171. (let loop ((stream stream)
  172. (result '()))
  173. (match (parser stream)
  174. ((? parse-failure?)
  175. (if (null? result)
  176. %parse-failure
  177. (parse-result (reverse result) stream)))
  178. (($ <parse-result> value stream)
  179. (loop stream (cons value result)))))))
  180. (define (parse-up-to n parser)
  181. "Create a parser that applies PARSER at most N times and returns a
  182. list of the successful parse results."
  183. (lambda (stream)
  184. (let loop ((stream stream)
  185. (n n))
  186. (if (zero? n)
  187. '()
  188. (match (parser stream)
  189. ((? parse-failure?) '())
  190. (($ <parse-result> value stream)
  191. (cons value (loop stream (1- n)))))))))
  192. (define* (parse-maybe parser #:optional (default #f))
  193. "Create a parser that returns the result of PARSER upon success, or
  194. DEFAULT upon failure."
  195. (lambda (stream)
  196. (match (parser stream)
  197. ((? parse-failure?)
  198. (parse-result default stream))
  199. (result result))))
  200. (define (parse-any-char stream)
  201. "Parse any single character or fail if STREAM is empty."
  202. (stream-match stream
  203. (() %parse-failure)
  204. ((head . tail)
  205. (parse-result head tail))))
  206. (define (parse-char c)
  207. "Create a parser that succeeds when the next character in the stream
  208. is C."
  209. (lambda (stream)
  210. (stream-match stream
  211. (() %parse-failure)
  212. ((head . tail)
  213. (if (equal? head c)
  214. (parse-result head tail)
  215. %parse-failure)))))
  216. (define (parse-char-set char-set)
  217. "Create a parser that succeeds when the next character in the stream
  218. is a member of CHAR-SET."
  219. (lambda (stream)
  220. (stream-match stream
  221. (() %parse-failure)
  222. ((char . tail)
  223. (if (char-set-contains? char-set char)
  224. (parse-result char tail)
  225. %parse-failure)))))
  226. (define stream->string (compose list->string stream->list))
  227. (define (parse-string str)
  228. "Create a parser that succeeds when the front of the stream contains
  229. the character sequence in STR."
  230. (lambda (stream)
  231. (let ((input (stream->string (stream-take (string-length str) stream))))
  232. (if (string=? str input)
  233. (parse-result str (stream-drop (string-length str) stream))
  234. %parse-failure))))