Skip to content

Commit

Permalink
Added Optima pattern for pattern-matching on Erlang binaries.
Browse files Browse the repository at this point in the history
  • Loading branch information
flambard committed Feb 1, 2014
1 parent 8fc7e49 commit 940b20c
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 0 deletions.
2 changes: 2 additions & 0 deletions erlang-term-optima.asd
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
((:module :optima
:components
((:file "package")
(:file "binary"
:depends-on ("package"))
(:file "erlang-string"
:depends-on ("package"))
(:file "tuple"
Expand Down
65 changes: 65 additions & 0 deletions optima/binary.lisp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
(in-package :erlang-term-optima)

;;
;; Pattern matching for Erlang binaries.
;;
;; Syntax:
;;
;; binary-pattern-constructor ::= (binary SEGMENT*)
;;
;;
;; Example:
;;
;; (match (binary 1 2 88)
;; ((binary 1 b "X") b))
;; => 2
;;


;;;
;;; BINARY pattern
;;;

(defstruct (binary-pattern
(:include optima::constructor-pattern)
(:constructor make-binary-pattern (&rest optima::subpatterns)))
)


(defmethod optima::destructor-equal ((x binary-pattern) (y binary-pattern))
(= (optima::constructor-pattern-arity x)
(optima::constructor-pattern-arity y)))

(defmethod optima::destructor-predicate-form ((pattern binary-pattern) var)
`(and (typep ,var 'erlang-binary)
(= (size ,var) ,(optima::constructor-pattern-arity pattern))))

(defmethod optima::destructor-forms ((pattern binary-pattern) var)
(loop
for i from 0 below (optima::constructor-pattern-arity pattern)
collect `(aref (bytes ,var) ,i)))

(defmethod optima::parse-constructor-pattern ((name (eql 'binary)) &rest args)
(apply #'make-binary-pattern
(mapcar #'optima::parse-pattern
(flatten-string-patterns-to-bytes args))))

(defmethod optima::unparse-pattern ((pattern binary-pattern))
;; Currently strings in patterns will not be unparsed back to strings,
;; they will be unparsed to constant bytes.
`(binary ,@(mapcar #'optima::unparse-pattern
(binary-pattern-subpatterns pattern))))


;;;
;;; Helper functions
;;;

(defun flatten-string-patterns-to-bytes (patterns)
(reduce #'(lambda (pattern acc)
(if (stringp pattern)
(nconc (string-to-byte-list pattern) acc)
(cons pattern acc)))
patterns
:initial-value nil
:from-end t))
34 changes: 34 additions & 0 deletions test/optima-tests.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,40 @@

(in-suite optima-patterns)

(test binary-pattern

(is-true (match (binary)
((binary 0) nil)
((binary 1 2 3) nil)
((binary) t)))

(is-true (match (binary 255 255 255 0)
((binary) nil)
((binary 255 255 255) nil)
((binary 255 255 255 0 0) nil)
((binary a b c d)
(and (= 255 a b c) (= 0 d)))))

(is-true (match (string-to-binary "hej")
((binary) nil)
((binary 104 101 106 33) nil)
((binary 104 101) nil)
((binary 104 101 106) t)))

(is-true (match (binary (char-code #\X))
((binary 0 "X" 34) nil)
((binary "X" 0) t)
((binary "X") t)))

(is-true (match (binary 104 101 106)
((binary) nil)
((binary "hej!") nil)
((binary "he") nil)
((binary "hej") t)))

)


(test erlang-string-pattern
(is-true (match (list)
((erlang-string "hello") nil)
Expand Down

0 comments on commit 940b20c

Please sign in to comment.