-
-
Notifications
You must be signed in to change notification settings - Fork 86
/
ducktype.lisp
121 lines (97 loc) · 2.93 KB
/
ducktype.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#|
This file is a part of Clack package.
URL: http://github.com/fukamachi/clack
Copyright (c) 2011 Eitarow Fukamachi <e.arrows@gmail.com>
Clack is freely distributable under the LLGPL License.
|#
(in-package :cl-user)
(defpackage clack.util.ducktype
(:use :cl))
(in-package :clack.util.ducktype)
(cl-syntax:use-syntax :annot)
(defvar *previous-readtables* nil
"Stack of readtables for duck-typing reader.")
@export
(defun duck-function (fn obj)
"Detect correct function for `obj'.
The function should be interned a package which exports a class of `obj'."
(symbol-function
(intern (symbol-name fn)
(symbol-package (type-of obj)))))
@export
(defmacro duckcall (fn obj &body body)
"Call `duck-function' of the `obj'.
I supposed `enable-duck-reader' may help you."
`(funcall (duck-function ,fn ,obj) ,obj ,@body))
@export
(defmacro duckapply (fn obj &body body)
"Apply `duck-function' of the `obj'.
I supposed `enable-duck-reader' may help you."
`(apply (duck-function ,fn ,obj) ,obj ,@body))
(defun duck-reader (stream arg)
@ignore arg
(let ((args (gensym "ARGS"))
(fn (read-preserving-whitespace stream))
(obj (read-preserving-whitespace stream)))
`(lambda (&rest ,args) (duckapply ',fn ,obj ,args))))
(defun %enable-duck-reader ()
(push *readtable* *previous-readtables*)
(setq *readtable* (copy-readtable))
(set-macro-character #\& #'duck-reader)
(values))
(defun %disable-duck-reader ()
(setq *readtable*
(if *previous-readtables*
(pop *previous-readtables*)
(copy-readtable nil))))
@export
(defmacro enable-duck-reader ()
"Enable duck-typing-reader.
Example:
(&call app env)
"
`(eval-when (:compile-toplevel :load-toplevel :execute)
(%enable-duck-reader)))
@export
(defmacro disable-duck-reader ()
"Disable duck-typing-reader if it is enabled."
`(eval-when (:compile-toplevel :load-toplevel :execute)
(%disable-duck-reader)))
(doc:start)
@doc:NAME "
Clack.Util.Ducktype - Duck-typing with Common Lisp.
"
@doc:SYNOPSIS "
;; hoge
(defpackage hoge
(:use :cl)
(:export :<hoge>))
(in-package :hoge)
(defclass <hoge> () ())
(defmethod call ((this <hoge>)))
;; fuga
(defpackage fuga
(:use :cl)
(:export :<fuga>))
(in-package :fuga)
(defclass <fuga> () ())
(defmethod call ((this <fuga>)))
;; main
(defpackage main
(:use :cl
:hoge
:fuga
:clack.util.ducktype))
(in-package :main)
(enable-duck-reader)
(&call (make-instance '<hoge>))
(&call (make-instance '<fuga>))
(disable-duck-reader)
"
@doc:DESCRIPTION "
Clack.Util.Ducktype provides a way to call different objects which have a same name method, like duck-typing. These objects are no need to inherit each other.
This reader macro seems useful for Clack development, but, isn't used in Core now.
"
@doc:AUTHOR "
* Eitarow Fukamachi (e.arrows@gmail.com)
"