src/pset-impl.lisp: Accept `yup' and `nope' as booleans.
[sod] / src / pset-impl.lisp
index e498deb..42049db 100644 (file)
@@ -7,7 +7,7 @@
 
 ;;;----- Licensing notice ---------------------------------------------------
 ;;;
-;;; This file is part of the Sensble Object Design, an object system for C.
+;;; This file is part of the Sensible Object Design, an object system for C.
 ;;;
 ;;; SOD is free software; you can redistribute it and/or modify
 ;;; it under the terms of the GNU General Public License as published by
 (cl:in-package #:sod)
 
 ;;;--------------------------------------------------------------------------
+;;; Conversion utilities.
+
+(defun string-to-symbol
+    (string &key (package *package*) (swap-case t) (swap-hyphen t))
+  "Convert STRING to a symbol in PACKAGE.
+
+   Parse off a `PACKAGE:' prefix from STRING if necessary, to identify the
+   package; PACKAGE is used if there isn't a prefix.  A doubled colon allows
+   access to internal symbols, and will intern if necessary.  Note that
+   escape characters are /not/ processed; don't put colons in package names
+   if you want to use them from SOD property sets.
+
+   The portions of the string are modified by `frob-identifier'; the
+   arguments SWAP-CASE and SWAP-HYPHEN are passed to `frob-identifier' to
+   control this process."
+
+  (let* ((length (length string))
+        (colon (position #\: string)))
+    (multiple-value-bind (start internalp)
+       (cond ((not colon) (values 0 t))
+             ((and (< (1+ colon) length)
+                   (char= (char string (1+ colon)) #\:))
+              (values (+ colon 2) t))
+             (t
+              (values (1+ colon) nil)))
+      (when colon
+       (let* ((package-name (if (zerop colon) "KEYWORD"
+                                (frob-identifier (subseq string 0 colon)
+                                                 :swap-case swap-case
+                                                 :swap-hyphen swap-hyphen)))
+              (found (find-package package-name)))
+         (unless found
+           (error "Unknown package `~A'" package-name))
+         (setf package found)))
+      (let ((name (frob-identifier (subseq string start)
+                                  :swap-case swap-case
+                                  :swap-hyphen swap-hyphen)))
+       (multiple-value-bind (symbol status)
+           (funcall (if internalp #'intern #'find-symbol) name package)
+         (cond ((or internalp (eq status :external))
+                symbol)
+               ((not status)
+                (error "Symbol `~A' not found in package `~A'"
+                       name (package-name package)))
+               (t
+                (error "Symbol `~A' not external in package `~A'"
+                       name (package-name package)))))))))
+
+(let ((truth-map (make-hash-table :test #'equalp)))
+  (dolist (string '("true" "t" "yes" "on" "yup" "verily"))
+    (setf (gethash string truth-map) t))
+  (dolist (string '("false" "nil" "no" "off" "nope" "nowise"))
+    (setf (gethash string truth-map) nil))
+  (defun truishp (string)
+    "Convert STRING to a boolean."
+    (multiple-value-bind (val foundp) (gethash string truth-map)
+      (if foundp val
+         (error "Unrecognized boolean value `~A'" string)))))
+
+;;;--------------------------------------------------------------------------
 ;;; Property representation.
 
 (defmethod file-location ((prop property))
   (file-location (p-location prop)))
 
+;;; Input conversions.
+
+(defmethod decode-property ((raw symbol)) (values :symbol raw))
+(defmethod decode-property ((raw integer)) (values :int raw))
+(defmethod decode-property ((raw string)) (values :string raw))
+(defmethod decode-property ((raw character)) (values :char raw))
+(defmethod decode-property ((raw function)) (values :func raw))
+(defmethod decode-property ((raw c-type)) (values :type raw))
+(defmethod decode-property ((raw c-fragment)) (values :c-fragment raw))
+
 ;;; Keywords.
 
 (defmethod coerce-property-value
     ((value symbol) (type (eql :symbol)) (wanted (eql :id)))
   (frob-identifier (symbol-name value)))
 
+;;; Boolean.
+
+(defmethod coerce-property-value
+    ((value symbol) (type (eql :symbol)) (wanted (eql :boolean)))
+  value)
+
+(defmethod coerce-property-value
+    ((value string) (type (eql :id)) (wanted (eql :boolean)))
+  (truishp value))
+
+(defmethod coerce-property-value
+    ((value integer) (type (eql :int)) (wanted (eql :boolean)))
+  (not (zerop value)))
+
+;;; Types.
+
+(defmethod coerce-property-value
+    ((value string) (type (eql :id)) (wanted (eql :type)))
+  (or (and (boundp '*module-type-map*)
+          (gethash value *module-type-map*))
+      (find-simple-c-type value)
+      (error "Unknown type `~A'" value)))
+
 ;;;--------------------------------------------------------------------------
 ;;; Property sets.