chiark / gitweb /
src/pset-{proto,impl}.lisp: Move `string-to-symbol' to implementation.
[sod] / src / pset-impl.lisp
index e340389c3609f399d9dd69bd816de2fe974635df..60674ff8b0a712a43e3a0d1bbaa625925643be7a 100644 (file)
 
 (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)))))))))
+
 ;;;--------------------------------------------------------------------------
 ;;; Property representation.