86 lines
2.7 KiB
Common Lisp
86 lines
2.7 KiB
Common Lisp
;; objective-lisp: Object-oriented syntactic sugar for Lisp
|
|
;; ~keith
|
|
|
|
(defpackage objective-lisp
|
|
(:use common-lisp)
|
|
(:export +open-construct-char+ +close-construct-char+ +method-char+
|
|
read-construct-contents
|
|
destructure-construct
|
|
read-method-name
|
|
read-open-construct
|
|
read-unexpected))
|
|
|
|
(in-package objective-lisp)
|
|
|
|
(defparameter +open-construct-char+ #\[)
|
|
(defparameter +close-construct-char+ #\])
|
|
(defparameter +method-char+ #\.)
|
|
|
|
;; DONE
|
|
;; (setf (slot-value object 'slot) value)
|
|
;; => (setf [object slot] value)
|
|
|
|
;; DONE
|
|
;; (setf (slot-value (slot-value object 'slot-a) 'slot-b) value)
|
|
;; => (setf [object slot-a slot-b] value)
|
|
|
|
;; TODO
|
|
;; (object-method object args...)
|
|
;; => [object (.method args...)]
|
|
|
|
(defun read-construct-contents (stream end-char)
|
|
"Read the contents of an objective-lisp construct."
|
|
(loop until (char= (peek-char t stream t nil t) end-char)
|
|
collect (read stream t nil t)
|
|
; Skip over end-char
|
|
finally (read-char stream t nil t)))
|
|
|
|
(defun quote-if-symbol (x)
|
|
"Quote x if it's a symbol, return it verbatim otherwise."
|
|
(if (symbolp x) `(quote ,x) x))
|
|
|
|
(defun method-call-p (x)
|
|
"Check if x is a sexpr of the form (.method args...)"
|
|
(and (consp x) (consp (car x)) (eq (caar x) :method-call)))
|
|
|
|
(defun destructure-construct (construct)
|
|
"Recursively destructure an objective-lisp construct."
|
|
(cond
|
|
; Nothing left to destructure, return car
|
|
((not (cdr construct))
|
|
(car construct))
|
|
; Method call [object (.method args...)]
|
|
; => [object ((:method-call . method) args...)]
|
|
((method-call-p (cadr construct))
|
|
(let ((method-call (cadr construct)))
|
|
(destructure-construct
|
|
(cons `(,(cdar method-call) ,(car construct) ,@(cdr method-call))
|
|
(cddr construct)))
|
|
))
|
|
; Slot access [object slot]
|
|
(t
|
|
(destructure-construct
|
|
(cons `(slot-value ,(car construct) ,(quote-if-symbol (cadr construct)))
|
|
(cddr construct)))
|
|
)))
|
|
|
|
(defun read-method-name (stream char)
|
|
"Read an objective-lisp method name."
|
|
(declare (ignore char))
|
|
(cons :method-call (read stream t nil t)))
|
|
|
|
(defun read-open-construct (stream char)
|
|
"Read an objective-lisp construct."
|
|
(declare (ignore char))
|
|
(let ((*readtable* (copy-readtable)))
|
|
(set-macro-character +method-char+ 'read-method-name
|
|
t) ; non-terminating so (12.34) doesn't become (12 (:method-call . 34))
|
|
(destructure-construct (read-construct-contents stream +close-construct-char+))))
|
|
|
|
(defun read-unexpected (stream char)
|
|
(declare (ignore stream))
|
|
(error "Unexpected character ~S" char))
|
|
|
|
(set-macro-character +open-construct-char+ 'read-open-construct)
|
|
(set-macro-character +close-construct-char+ 'read-unexpected)
|