Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add parser using regular expressions using cl-ppcre.

  • Loading branch information...
commit fa7a216276ffee2c4dccc5912f585973852bcbf1 1 parent 23f84e9
@Ramarren authored
View
10 package.lisp
@@ -56,6 +56,7 @@
#:between*
#:atleast*
#:make-context
+ #:copy-context
#:delayed?
#:<-
#:make-parse-result
@@ -97,4 +98,11 @@
#:named-seq*
#:gather-if-not*)
(:export #:string?-using-context
- #:gather-if-not*-using-context))
+ #:gather-if-not*-using-context)
+ ;; some function for creating -using-context parsers from other packages
+ (:export #:storage-of
+ #:common-of
+ #:vector-context
+ #:end-context
+ #:define-oneshot-result
+ #:parser-possibility))
View
8 parser-combinators-cl-ppcre.asd
@@ -0,0 +1,8 @@
+(asdf:defsystem parser-combinators-cl-ppcre
+ :version "0"
+ :description "An implementation of parser combinators for Common Lisp"
+ :maintainer "Jakub Higersberger <ramarren@gmail.com>"
+ :author "Jakub Higersberger <ramarren@gmail.com>"
+ :licence "BSD-style"
+ :depends-on (:iterate :alexandria :cl-ppcre :parser-combinators)
+ :components ((:file "regex-parser")))
View
42 regex-parser.lisp
@@ -0,0 +1,42 @@
+(defpackage :parser-combinators-cl-ppcre
+ (:use :cl :parser-combinators :iterate)
+ (:export #:regex* #:regex*-using-context))
+
+(in-package :parser-combinators-cl-ppcre)
+
+(defgeneric regex*-using-context (inp regex limit return-builder)
+ (:method ((inp t) regex limit return-builder)
+ (error "Parser regex* not implemented for this context type"))
+ (:method ((inp vector-context) regex limit return-builder)
+ (check-type (storage-of inp) string)
+ (multiple-value-bind (match-start match-end regs-start regs-end)
+ (cl-ppcre:scan regex (storage-of inp)
+ :start (position-of inp)
+ :end (if (and limit (<= limit (length (storage-of inp))))
+ (+ limit (position-of inp))
+ (length (storage-of inp))))
+ (let ((result
+ (case return-builder
+ ((t) (subseq (storage-of inp) match-start match-end))
+ ((nil) nil)
+ (t (let ((regs (iter (for reg-start in-vector regs-start)
+ (for reg-end in-vector regs-end)
+ (collect (subseq (storage-of inp) reg-start reg-end)))))
+ (apply return-builder (subseq (storage-of inp) match-start match-end) regs))))))
+ (if (= match-end (length (storage-of inp)))
+ (values result (make-instance 'end-context
+ :common (common-of inp)
+ :position (length (storage-of inp))))
+ (values result (make-instance 'vector-context
+ :common (common-of inp)
+ :position match-end)))))))
+
+(defun regex* (regex &key (limit nil) (return-builder t))
+ "Non-backtracking parser: regular expression is applied to the input, and a result is constructed by return-builder (default will just return the match) from the result and submatches passed as strings. Passing regex-builder as nil will discard the result (use regex only to advance the input)."
+ (let ((compiled-regex (cl-ppcre:create-scanner regex)))
+ (define-oneshot-result inp is-unread
+ (multiple-value-bind (result new-input) (regex*-using-context inp compiled-regex limit return-builder)
+ (when new-input
+ (make-instance 'parser-possibility
+ :tree result
+ :suffix new-input))))))
Please sign in to comment.
Something went wrong with that request. Please try again.