Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Reimplementation pattern-matching algorithm.
- Loading branch information
Tomohiro Matsuyama
committed
Feb 17, 2011
1 parent
ed5fa57
commit 480c666
Showing
13 changed files
with
273 additions
and
197 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
(in-package :cl-user) | ||
|
||
(defpackage cl-pattern-test-asd | ||
(:use :cl :asdf)) | ||
|
||
(in-package :cl-pattern-test-asd) | ||
|
||
(defsystem cl-pattern-test | ||
:depends-on (:cl-test-more :cl-pattern) | ||
:components | ||
((:module "t" | ||
:serial t | ||
:components | ||
((:file "match"))))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
(in-package :cl-pattern) | ||
|
||
(annot:enable-annot-syntax) | ||
|
||
@eval-always | ||
(defun compile-case-clause (var clause else) | ||
(destructuring-bind (pattern then) | ||
clause | ||
(ecase (pattern-type pattern) | ||
(:const | ||
`(if (%equal ,pattern ,var) ,then ,else)) | ||
(:var | ||
`(let ((,pattern ,var)) ,then)) | ||
(:cons | ||
`(if (consp ,var) | ||
(let ((,(car pattern) (car ,var)) | ||
(,(cdr pattern) (cdr ,var))) | ||
(declare (ignorable ,(car pattern) ,(cdr pattern))) | ||
,then) | ||
,else))))) | ||
|
||
@eval-always | ||
(defun compile-case (var clauses else) | ||
(reduce (lambda (clause else) (compile-case-clause var clause else)) | ||
clauses | ||
:initial-value else | ||
:from-end t)) | ||
|
||
(defmacro %case (arg clauses else) | ||
(if (atom arg) | ||
(compile-case arg clauses else) | ||
(with-gensyms (var) | ||
`(let ((,var ,arg)) | ||
,(compile-case var clauses else))))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
(in-package :cl-pattern) | ||
|
||
(annot:enable-annot-syntax) | ||
|
||
(defun partition-match-clauses (clauses) | ||
(loop with groups | ||
with group-type | ||
with group-clauses | ||
for clause in clauses | ||
for head-pattern = (caar clause) | ||
for head-pattern-type = (pattern-type head-pattern) | ||
do | ||
(or group-type (setf group-type head-pattern-type)) | ||
(if (eq head-pattern-type group-type) | ||
(push clause group-clauses) | ||
(progn | ||
(push (cons group-type (nreverse group-clauses)) groups) | ||
(setf group-type head-pattern-type | ||
group-clauses (list clause)))) | ||
finally | ||
(if group-type | ||
(push (cons group-type (nreverse group-clauses)) groups)) | ||
(return (nreverse groups)))) | ||
|
||
(defun compile-match-variable (vars clauses else) | ||
`(%match ,(cdr vars) | ||
,(loop for ((var . rest) . then) in clauses | ||
if (string-equal var "_") | ||
collect `(,rest ,@then) | ||
else | ||
collect `(,rest (let ((,var ,(car vars))) | ||
(declare (ignorable ,var)) | ||
,@then))) | ||
,else)) | ||
|
||
(defun compile-match-constant (vars clauses else) | ||
(loop with alist | ||
for ((constant . rest) . then) in clauses | ||
for sub-clause = (cons rest then) | ||
for assoc = (assoc constant alist :test #'equal) | ||
if assoc | ||
do (setf (cdr assoc) (cons sub-clause (cdr assoc))) | ||
else | ||
do (push `(,constant ,sub-clause) alist) | ||
finally | ||
(return | ||
`(%case ,(car vars) | ||
,(loop for pair in (nreverse alist) | ||
for constant = (car pair) | ||
for sub-clauses = (nreverse (cdr pair)) | ||
collect | ||
`(,constant | ||
(%match ,(cdr vars) ,sub-clauses (%match-error)))) | ||
,else)))) | ||
|
||
(defun compile-match-constructor (vars clauses else) | ||
(let ((var (car vars))) | ||
(with-gensyms (car cdr) | ||
`(if (consp ,var) | ||
(let ((,car (car ,var)) | ||
(,cdr (cdr ,var))) | ||
(declare (ignorable ,car ,cdr)) | ||
(%match ,`(,car ,cdr ,@(cdr vars)) | ||
,(loop for (((par . pdr) . rest) . then) in clauses | ||
collect | ||
`(,`(,par ,pdr ,@rest) ,@then)) | ||
,else)) | ||
,else)))) | ||
|
||
(defun compile-match-empty (clauses else) | ||
(loop for (pattern . then) in clauses | ||
if (null pattern) | ||
do (return | ||
(if (> (length then) 1) | ||
`(progn ,@then) | ||
(car then))) | ||
finally (return else))) | ||
|
||
(defun compile-match-group (vars group else) | ||
(if vars | ||
(ecase (car group) | ||
(:var (compile-match-variable vars (cdr group) else)) | ||
(:const (compile-match-constant vars (cdr group) else)) | ||
(:cons (compile-match-constructor vars (cdr group) else))) | ||
(compile-match-empty (cdr group) else))) | ||
|
||
(defun compile-match-groups (vars groups else) | ||
(reduce (lambda (group else) | ||
(compile-match-group vars group else)) | ||
groups | ||
:initial-value else | ||
:from-end t)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
(in-package :cl-pattern) | ||
|
||
(annot:enable-annot-syntax) | ||
|
||
@export | ||
(define-condition match-error (error) ()) | ||
|
||
(defun %match-error () | ||
(error (make-condition 'match-error))) |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,24 +1,29 @@ | ||
(in-package :cl-pattern) | ||
|
||
(eval-when (:compile-toplevel :load-toplevel :execute) | ||
(defun compile-match-clauses (value clauses) | ||
(declare (type symbol value)) | ||
(if clauses | ||
(let+ ((((pattern . body) . rest) clauses) | ||
(body `(lambda () ,@body))) | ||
(cond | ||
((otherwise-variable-p pattern) body) | ||
((variable-p pattern) | ||
`(let+ ((,pattern ,value)) ,body)) | ||
((consp pattern) | ||
`(handler-case | ||
(let+ ((,pattern ,value)) ,body) | ||
(error () ,(compile-match-clauses value rest)))) | ||
(t `(if (%equal ,value ,pattern) | ||
,body | ||
,(compile-match-clauses value rest))))) | ||
'(error "match error")))) | ||
(annot:enable-annot-syntax) | ||
|
||
(defmacro match (value &body clauses) | ||
(once-only (value) | ||
`(funcall ,(compile-match-clauses value clauses)))) | ||
(defmacro %match (vars clauses else) | ||
(let ((groups (partition-match-clauses clauses))) | ||
(compile-match-groups vars groups else))) | ||
|
||
@export | ||
(defmacro match* (args &body clauses) | ||
(loop for arg in args | ||
for var = (gensym "VAR") | ||
if (atom arg) | ||
collect arg into vars | ||
else | ||
collect var into vars | ||
and collect `(,var ,arg) into bindings | ||
finally | ||
(return | ||
(let ((body `(%match ,vars ,clauses (%match-error)))) | ||
(if bindings | ||
`(let ,bindings ,body) | ||
body))))) | ||
|
||
@export | ||
(defmacro match (arg &body clauses) | ||
`(match* (,arg) | ||
,@(loop for (pattern . then) in clauses | ||
collect `((,pattern) ,@then)))) |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.