chiark / gitweb /
src/optparse.lisp: Muffle warnings about `&optional ... &key ...'.
[sod] / src / pset-impl.lisp
1 ;;; -*-lisp-*-
2 ;;;
3 ;;; Implementation for property sets
4 ;;;
5 ;;; (c) 2009 Straylight/Edgeware
6 ;;;
7
8 ;;;----- Licensing notice ---------------------------------------------------
9 ;;;
10 ;;; This file is part of the Sensible Object Design, an object system for C.
11 ;;;
12 ;;; SOD is free software; you can redistribute it and/or modify
13 ;;; it under the terms of the GNU General Public License as published by
14 ;;; the Free Software Foundation; either version 2 of the License, or
15 ;;; (at your option) any later version.
16 ;;;
17 ;;; SOD is distributed in the hope that it will be useful,
18 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 ;;; GNU General Public License for more details.
21 ;;;
22 ;;; You should have received a copy of the GNU General Public License
23 ;;; along with SOD; if not, write to the Free Software Foundation,
24 ;;; Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
26 (cl:in-package #:sod)
27
28 ;;;--------------------------------------------------------------------------
29 ;;; Conversion utilities.
30
31 (defun string-to-symbol
32     (string &key (package *package*) (swap-case t) (swap-hyphen t))
33   "Convert STRING to a symbol in PACKAGE.
34
35    Parse off a `PACKAGE:' prefix from STRING if necessary, to identify the
36    package; PACKAGE is used if there isn't a prefix.  A doubled colon allows
37    access to internal symbols, and will intern if necessary.  Note that
38    escape characters are /not/ processed; don't put colons in package names
39    if you want to use them from SOD property sets.
40
41    The portions of the string are modified by `frob-identifier'; the
42    arguments SWAP-CASE and SWAP-HYPHEN are passed to `frob-identifier' to
43    control this process."
44
45   (let* ((length (length string))
46          (colon (position #\: string)))
47     (multiple-value-bind (start internalp)
48         (cond ((not colon) (values 0 t))
49               ((and (< (1+ colon) length)
50                     (char= (char string (1+ colon)) #\:))
51                (values (+ colon 2) t))
52               (t
53                (values (1+ colon) nil)))
54       (when colon
55         (let* ((package-name (if (zerop colon) "KEYWORD"
56                                  (frob-identifier (subseq string 0 colon)
57                                                   :swap-case swap-case
58                                                   :swap-hyphen swap-hyphen)))
59                (found (find-package package-name)))
60           (unless found
61             (error "Unknown package `~A'" package-name))
62           (setf package found)))
63       (let ((name (frob-identifier (subseq string start)
64                                    :swap-case swap-case
65                                    :swap-hyphen swap-hyphen)))
66         (multiple-value-bind (symbol status)
67             (funcall (if internalp #'intern #'find-symbol) name package)
68           (cond ((or internalp (eq status :external))
69                  symbol)
70                 ((not status)
71                  (error "Symbol `~A' not found in package `~A'"
72                         name (package-name package)))
73                 (t
74                  (error "Symbol `~A' not external in package `~A'"
75                         name (package-name package)))))))))
76
77 (let ((truish '("true" "t" "yes" "on" "verily"))
78       (falsish '("false" "nil" "no" "off" "nowise")))
79   (defun truishp (string)
80     "Convert STRING to a boolean."
81     (cond ((member string truish :test #'string-equal) t)
82           ((member string falsish :test #'string-equal) nil)
83           (t (error "Unrecognized boolean value `~A'" string)))))
84
85 ;;;--------------------------------------------------------------------------
86 ;;; Property representation.
87
88 (defmethod file-location ((prop property))
89   (file-location (p-location prop)))
90
91 ;;; Input conversions.
92
93 (defmethod decode-property ((raw symbol)) (values :symbol raw))
94 (defmethod decode-property ((raw integer)) (values :int raw))
95 (defmethod decode-property ((raw string)) (values :string raw))
96 (defmethod decode-property ((raw character)) (values :char raw))
97 (defmethod decode-property ((raw function)) (values :func raw))
98 (defmethod decode-property ((raw c-type)) (values :type raw))
99 (defmethod decode-property ((raw c-fragment)) (values :c-fragment raw))
100
101 ;;; Keywords.
102
103 (defmethod coerce-property-value
104     ((value symbol) (type (eql :symbol)) (wanted (eql :keyword)))
105   value)
106
107 (defmethod coerce-property-value
108     ((value string) (type (eql :id)) (wanted (eql :keyword)))
109   (string-to-symbol value :package :keyword))
110
111 (defmethod coerce-property-value
112     ((value string) (type (eql :string)) (wanted (eql :keyword)))
113   (string-to-symbol value :package :keyword :swap-hyphen nil))
114
115 ;;; Symbols.
116
117 (defmethod coerce-property-value
118     ((value string) (type (eql :id)) (wanted (eql :symbol)))
119   (string-to-symbol value))
120
121 (defmethod coerce-property-value
122     ((value string) (type (eql :string)) (wanted (eql :symbol)))
123   (string-to-symbol value :swap-hyphen nil))
124
125 ;;; Identifiers.
126
127 (defmethod coerce-property-value
128     ((value string) (type (eql :string)) (wanted (eql :id)))
129   value)
130
131 (defmethod coerce-property-value
132     ((value symbol) (type (eql :symbol)) (wanted (eql :id)))
133   (frob-identifier (symbol-name value)))
134
135 ;;; Boolean.
136
137 (defmethod coerce-property-value
138     ((value symbol) (type (eql :symbol)) (wanted (eql :boolean)))
139   value)
140
141 (defmethod coerce-property-value
142     ((value string) (type (eql :id)) (wanted (eql :boolean)))
143   (truishp value))
144
145 (defmethod coerce-property-value
146     ((value integer) (type (eql :int)) (wanted (eql :boolean)))
147   (not (zerop value)))
148
149 ;;; Types.
150
151 (defmethod coerce-property-value
152     ((value string) (type (eql :id)) (wanted (eql :type)))
153   (or (and (boundp '*module-type-map*)
154            (gethash value *module-type-map*))
155       (find-simple-c-type value)
156       (error "Unknown type `~A'" value)))
157
158 ;;;--------------------------------------------------------------------------
159 ;;; Property sets.
160
161 (defmethod print-object ((pset pset) stream)
162   (print-unreadable-object (pset stream :type t)
163     (pprint-logical-block (stream nil)
164       (let ((firstp t))
165         (pset-map (lambda (prop)
166                     (cond (firstp (setf firstp nil))
167                           (t (write-char #\space stream)
168                              (pprint-newline :linear stream)))
169                     (format stream "~:@<~S ~@_~S ~@_~S~:>"
170                             (p-name prop) (p-type prop) (p-value prop)))
171                   pset)))))
172
173 ;;;----- That's all, folks --------------------------------------------------