Merge branch 'master' into doc
authorMark Wooding <mdw@distorted.org.uk>
Sun, 30 Aug 2015 09:58:38 +0000 (10:58 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sun, 20 Sep 2015 10:50:25 +0000 (11:50 +0100)
* master:
  src/utilities.lisp, src/optparse.lisp: Move locatives to `utilities'.
  src/c-types-proto.lisp: Fix docstring.
  src/parser/parser-proto.lisp: Export `combine-parser-failures'.
  src/utilities.lisp: Move `define-on-demand-slot' to the right section.
  src/codegen-impl.lisp: Rename some `inst' slots.
  src/codegen-{proto,impl}.lisp: Make *temporary-index* be a module var.
  src/class-make-proto.lisp: Choose Lisp metaclass more cleverly.
  src/class-make-impl.lisp: Abstract out the guts of `guess-metaclass'.
  src/c-types-impl.lisp: Fix arg list in `c-function-type' instance init.
  src/lexer-bits.lisp: Delete crufty old file.

src/c-types-impl.lisp
src/c-types-proto.lisp
src/class-make-impl.lisp
src/class-make-proto.lisp
src/codegen-impl.lisp
src/codegen-proto.lisp
src/lexer-bits.lisp [deleted file]
src/optparse.lisp
src/parser/parser-proto.lisp
src/utilities.lisp

index 4a0f6e2..ed65110 100644 (file)
 (export '(c-function-type c-function-arguments))
 (defclass c-function-type (c-type)
   ((subtype :initarg :subtype :type c-type :reader c-type-subtype)
-   (arguments :initarg :arguments :type list :reader c-function-arguments))
+   (arguments :type list :reader c-function-arguments))
   (:documentation
    "C function types.  The subtype is the return type, as implied by the C
     syntax for function declarations."))
 
+(defmethod shared-initialize :after
+    ((type c-function-type) slot-names &key (arguments nil argsp))
+  (declare (ignore slot-names))
+  (when argsp
+    (setf (slot-value type 'arguments)
+         (if (and arguments
+                  (null (cdr arguments))
+                  (not (eq (car arguments) :ellipsis))
+                  (eq (argument-type (car arguments)) c-type-void))
+             nil
+             arguments))))
+
 ;; Constructor function.
 
 (export 'make-function-type)
 (defun make-function-type (subtype arguments)
   "Return a new function type, returning SUBTYPE and accepting ARGUMENTS."
   (make-instance 'c-function-type :subtype subtype
-                :arguments (if (and arguments
-                                    (null (cdr arguments))
-                                    (not (eq (car arguments) :ellipsis))
-                                    (eq (argument-type (car arguments))
-                                        c-type-void))
-                               nil
-                               arguments)))
+                :arguments arguments))
 
 ;; Comparison protocol.
 
index b9b61bf..edadd64 100644 (file)
    "Produce a `commentified' version of the argument.
 
    The default behaviour is that temporary argument names are simply omitted
-   (NIL is returned); otherwise, `/*...*/' markers are wrapped around the
+   (nil is returned); otherwise, `/*...*/' markers are wrapped around the
    printable representation of the argument.")
   (:method ((name null)) nil)
   (:method ((name t)) (format nil "/*~A*/" name)))
index 878f813..29a30c1 100644 (file)
 ;;;--------------------------------------------------------------------------
 ;;; Classes.
 
+(defun maximum (items order what)
+  "Return a maximum item according to the non-strict partial ORDER."
+  (reduce (lambda (best this)
+           (cond ((funcall order best this) best)
+                 ((funcall order this best) this)
+                 (t (error "Unable to choose best ~A." what))))
+         items))
+
 (defmethod guess-metaclass ((class sod-class))
   "Default metaclass-guessing function for classes.
 
    Return the most specific metaclass of any of the CLASS's direct
    superclasses."
-  (do ((supers (sod-class-direct-superclasses class) (cdr supers))
-       (meta nil (let ((candidate (sod-class-metaclass (car supers))))
-                  (cond ((null meta) candidate)
-                        ((sod-subclass-p meta candidate) meta)
-                        ((sod-subclass-p candidate meta) candidate)
-                        (t (error "Unable to choose metaclass for `~A'"
-                                  class))))))
-      ((endp supers) meta)))
+  (maximum (mapcar #'sod-class-metaclass
+                  (sod-class-direct-superclasses class))
+          #'sod-subclass-p
+          (format nil "metaclass for `~A'" class)))
 
 (defmethod shared-initialize :after ((class sod-class) slot-names &key pset)
   "Specific behaviour for SOD class initialization.
@@ -66,7 +70,8 @@
   ;; If no metaclass, guess one in a (Lisp) class-specific way.
   (default-slot-from-property (class 'metaclass slot-names)
       (pset :metaclass :id meta (find-sod-class meta))
-    (guess-metaclass class))
+    (and (sod-class-direct-superclasses class)
+        (guess-metaclass class)))
 
   ;; If no chain-link, then start a new chain here.
   (default-slot-from-property (class 'chain-link slot-names)
index c04727c..8b024bd 100644 (file)
 
   (with-default-error-location (location)
     (let* ((pset (property-set pset))
-          (class (make-instance (get-property pset :lisp-metaclass :symbol
-                                              'sod-class)
+          (best-class (or (get-property pset :lisp-metaclass :symbol nil)
+                          (if superclasses
+                              (maximum (mapcar #'class-of superclasses)
+                                       #'subtypep
+                                       (format nil "Lisp metaclass for ~A"
+                                               name))
+                              'sod-class)))
+          (class (make-instance best-class
                                 :name name
                                 :superclasses superclasses
                                 :location (file-location location)
index 170f4a8..d988b12 100644 (file)
   ((in-use-p :initarg :in-use-p :initform nil
             :type boolean :accessor var-in-use-p)))
 
+(define-module-var *temporary-index* 0
+  "Index for temporary name generation.
+
+   This is automatically reset to zero before the output functions are
+   invoked to write a file.  This way, we can ensure that the same output
+   file is always produced from the same input.")
+
+(define-clear-the-decks reset-codegen-index
+  (setf *temporary-index* 0))
+
 (defmethod commentify-argument-name ((name temporary-name))
   nil)
 
 ;; package.  The `definst' machinery will symbolicate the various associated
 ;; methods correctly despite this subterfuge.
 
-(definst if (stream :export t) (#1=#:condition consequent alternative)
-  (format-compound-statement (stream consequent alternative)
+(definst if (stream :export t) (#1=#:cond conseq alt)
+  (format-compound-statement (stream conseq alt)
     (format stream "if (~A)" #1#))
-  (when alternative
-    (format-compound-statement (stream alternative)
+  (when alt
+    (format-compound-statement (stream alt)
       (write-string "else" stream))))
 
-(definst while (stream :export t) (#1=#:condition body)
+(definst while (stream :export t) (#1=#:cond body)
   (format-compound-statement (stream body)
     (format stream "while (~A)" #1#)))
 
-(definst do-while (stream :export t) (body #1=#:condition)
+(definst do-while (stream :export t) (body #1=#:cond)
   (format-compound-statement (stream body :space)
     (write-string "do" stream))
   (format stream "while (~A);" #1#))
index 535839c..6b1f947 100644 (file)
   (:documentation
    "Base class for temporary variable and argument names."))
 
-;; Important variables.
-
-(defparameter *temporary-index* 0
-  "Index for temporary name generation.
-
-   This is automatically reset to zero before the output functions are
-   invoked to write a file.  This way, we can ensure that the same output
-   file is always produced from the same input.")
-
-(define-clear-the-decks reset-codegen-index
-  (setf *temporary-index* 0))
-
 ;; Important temporary names.
 
 (export '(*sod-ap* *sod-master-ap*))
diff --git a/src/lexer-bits.lisp b/src/lexer-bits.lisp
deleted file mode 100644 (file)
index b671164..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-(cl:in-package #:sod)
-
-(defun play-fetch-token (string)
-  (with-parser-context (string-parser :string string)
-    (labels ((digit (radix)
-              (parse (filter (lambda (ch)
-                               (digit-char-p ch radix)))))
-            (number (radix &optional (initial 0))
-              (parse (many (a initial (+ (* radix a) it))
-                       (digit radix))))
-            (numeric (radix sigil)
-              (parse (seq ((first (peek (seq ((nil (funcall sigil))
-                                              (d (digit radix)))
-                                          d)))
-                           (result (number radix first)))
-                       result))))
- (multiple-value-call #'values
-    (loop
-       (parse :whitespace)
-
-       (cond-parse ()
-
-        ;; Give up at end-of-file.
-        (:eof
-         (return (values :eof nil)))
-
-        ;; Pick out comments.
-        ((peek (and #\/ #\*))
-         (parse (skip-many ()          ; this may fail at eof; don't worry
-                  (and (skip-many () (not #\*))
-                       (skip-many (:min 1) #\*))
-                  (not #\/)))
-         (if-parse :eof ()
-           (cerror* "Unterminated comment")
-           (parse :any)))
-        ((and (peek (seq (#\/ #\/)))
-              (skip-many () (not #\newline))
-              (or :eof #\newline)))
-
-        ;; Quoted strings and characters.
-        ((or #\' #\")
-         (let ((quote it)
-               (out (make-string-output-stream)))
-           (parse (skip-many ()
-                    (or (seq ((ch (satisfies (lambda (ch)
-                                               (and (char/= ch #\\)
-                                                    (char/= ch quote))))))
-                          (write-char ch out))
-                        (seq (#\\ (ch :any))
-                          (write-char ch out)))))
-           (if-parse :eof ()
-             (cerror* "Unterminated ~:[string~;character~] constant"
-                      (char= quote #\'))
-             (parse :any))
-           (let ((string (get-output-stream-string out)))
-             (ecase quote
-               (#\" (return (values :string string)))
-               (#\' (case (length string)
-                      (0 (cerror* "Empty character constant")
-                         (return (values :char #\?)))
-                      (1 (return (values :char (char string 0))))
-                      (t (cerror* "Multiple characters in ~
-                                   character constant")
-                         (return (values :char (char string 0))))))))))
-
-        ;; Identifiers.
-        ((seq ((first (satisfies (lambda (ch)
-                                   (or (char= ch #\_)
-                                       (alpha-char-p ch)))))
-               (ident (many (out (let ((s (make-string-output-stream)))
-                                   (write-char first s)
-                                   s)
-                                 (progn (write-char it out) out)
-                             :final (get-output-stream-string out))
-                        (satisfies (lambda (ch)
-                                     (or (char= ch #\_)
-                                         (alphanumericp ch)))))))
-           (return (values :id ident))))
-
-        ;; Numbers -- uses the machinery in the labels above.
-        ((or (seq (#\0
-                   (i (or (numeric 8 (parser () (or #\o #\O)))
-                          (numeric 16 (parser () (or #\x #\X)))
-                          (number 8))))
-               i)
-             (seq ((first (digit 10))
-                   (rest (number 10 first)))
-               rest))
-         (return (values :integer it)))
-
-        ;; Special separator tokens.
-        ("..."
-         (return (values :ellipsis :ellipsis)))
-
-        ;; Anything else is a standalone delimiter character.
-        (:any
-         (return (values it it)))))
-    (parse (list () :any))))))
index 70bb012..a2ac290 100644 (file)
   (do-case2-like 'ecase vform clauses))
 
 ;;;--------------------------------------------------------------------------
-;;; Locatives.
-
-(export '(loc locp))
-(defstruct (loc (:predicate locp) (:constructor make-loc (reader writer)))
-  "Locative data type.  See `locf' and `ref'."
-  (reader nil :type function)
-  (writer nil :type function))
-
-(export 'locf)
-(defmacro locf (place &environment env)
-  "Slightly cheesy locatives.
-
-   (locf PLACE) returns an object which, using the `ref' function, can be
-   used to read or set the value of PLACE.  It's cheesy because it uses
-   closures rather than actually taking the address of something.  Also,
-   unlike Zetalisp, we don't overload `car' to do our dirty work."
-  (multiple-value-bind
-      (valtmps valforms newtmps setform getform)
-      (get-setf-expansion place env)
-    `(let* (,@(mapcar #'list valtmps valforms))
-       (make-loc (lambda () ,getform)
-                (lambda (,@newtmps) ,setform)))))
-
-(export 'ref)
-(declaim (inline ref (setf ref)))
-(defun ref (loc)
-  "Fetch the value referred to by a locative."
-  (funcall (loc-reader loc)))
-(defun (setf ref) (new loc)
-  "Store a new value in the place referred to by a locative."
-  (funcall (loc-writer loc) new))
-
-(export 'with-locatives)
-(defmacro with-locatives (locs &body body)
-  "Evaluate BODY with implicit locatives.
-
-   LOCS is a list of items of the form (SYM [LOC-EXPR]), where SYM is a
-   symbol and LOC-EXPR evaluates to a locative.  If LOC-EXPR is omitted, it
-   defaults to SYM.  As an abbreviation for a common case, LOCS may be a
-   symbol instead of a list.
-
-   The BODY is evaluated in an environment where each SYM is a symbol macro
-   which expands to (ref LOC-EXPR) -- or, in fact, something similar which
-   doesn't break if LOC-EXPR has side-effects.  Thus, references, including
-   `setf' forms, fetch or modify the thing referred to by the LOC-EXPR.
-   Useful for covering over where something uses a locative."
-  (setf locs (mapcar (lambda (item)
-                      (cond ((atom item) (list item item))
-                            ((null (cdr item)) (list (car item) (car item)))
-                            (t item)))
-                    (if (listp locs) locs (list locs))))
-  (let ((tt (mapcar (lambda (l) (declare (ignore l)) (gensym)) locs))
-       (ll (mapcar #'cadr locs))
-       (ss (mapcar #'car locs)))
-    `(let (,@(mapcar (lambda (tmp loc) `(,tmp ,loc)) tt ll))
-       (symbol-macrolet (,@(mapcar (lambda (sym tmp)
-                                    `(,sym (ref ,tmp))) ss tt))
-        ,@body))))
-
-;;;--------------------------------------------------------------------------
 ;;; Standard error-reporting functions.
 
 (export 'moan)
index d458e70..4bd1ae4 100644 (file)
@@ -77,6 +77,7 @@
 ;;;--------------------------------------------------------------------------
 ;;; Utilities.
 
+(export 'combine-parser-failures)
 (defun combine-parser-failures (failures)
   "Combine the failure indicators listed in FAILURES.
 
index 98d314a..d1755da 100644 (file)
            body)))
 
 ;;;--------------------------------------------------------------------------
+;;; Locatives.
+
+(export '(loc locp))
+(defstruct (loc (:predicate locp) (:constructor make-loc (reader writer)))
+  "Locative data type.  See `locf' and `ref'."
+  (reader nil :type function)
+  (writer nil :type function))
+
+(export 'locf)
+(defmacro locf (place &environment env)
+  "Slightly cheesy locatives.
+
+   (locf PLACE) returns an object which, using the `ref' function, can be
+   used to read or set the value of PLACE.  It's cheesy because it uses
+   closures rather than actually taking the address of something.  Also,
+   unlike Zetalisp, we don't overload `car' to do our dirty work."
+  (multiple-value-bind
+      (valtmps valforms newtmps setform getform)
+      (get-setf-expansion place env)
+    `(let* (,@(mapcar #'list valtmps valforms))
+       (make-loc (lambda () ,getform)
+                (lambda (,@newtmps) ,setform)))))
+
+(export 'ref)
+(declaim (inline ref (setf ref)))
+(defun ref (loc)
+  "Fetch the value referred to by a locative."
+  (funcall (loc-reader loc)))
+(defun (setf ref) (new loc)
+  "Store a new value in the place referred to by a locative."
+  (funcall (loc-writer loc) new))
+
+(export 'with-locatives)
+(defmacro with-locatives (locs &body body)
+  "Evaluate BODY with implicit locatives.
+
+   LOCS is a list of items of the form (SYM [LOC-EXPR]), where SYM is a
+   symbol and LOC-EXPR evaluates to a locative.  If LOC-EXPR is omitted, it
+   defaults to SYM.  As an abbreviation for a common case, LOCS may be a
+   symbol instead of a list.
+
+   The BODY is evaluated in an environment where each SYM is a symbol macro
+   which expands to (ref LOC-EXPR) -- or, in fact, something similar which
+   doesn't break if LOC-EXPR has side-effects.  Thus, references, including
+   `setf' forms, fetch or modify the thing referred to by the LOC-EXPR.
+   Useful for covering over where something uses a locative."
+  (setf locs (mapcar (lambda (item)
+                      (cond ((atom item) (list item item))
+                            ((null (cdr item)) (list (car item) (car item)))
+                            (t item)))
+                    (if (listp locs) locs (list locs))))
+  (let ((tt (mapcar (lambda (l) (declare (ignore l)) (gensym)) locs))
+       (ll (mapcar #'cadr locs))
+       (ss (mapcar #'car locs)))
+    `(let (,@(mapcar (lambda (tmp loc) `(,tmp ,loc)) tt ll))
+       (symbol-macrolet (,@(mapcar (lambda (sym tmp)
+                                    `(,sym (ref ,tmp))) ss tt))
+        ,@body))))
+
+;;;--------------------------------------------------------------------------
 ;;; Anaphorics.
 
 (export 'it)
            `((defun (setf ,from) (value object)
                (setf (,to object) value))))))
 
-(export 'define-on-demand-slot)
-(defmacro define-on-demand-slot (class slot (instance) &body body)
-  "Defines a slot which computes its initial value on demand.
-
-   Sets up the named SLOT of CLASS to establish its value as the implicit
-   progn BODY, by defining an appropriate method on `slot-unbound'."
-  (with-gensyms (classvar slotvar)
-    `(defmethod slot-unbound
-        (,classvar (,instance ,class) (,slotvar (eql ',slot)))
-       (declare (ignore ,classvar))
-       (setf (slot-value ,instance ',slot) (progn ,@body)))))
-
 ;;;--------------------------------------------------------------------------
 ;;; CLOS hacking.
 
        (setf (slot-value ,instance ,slot)
             (progn ,@value)))))
 
+(export 'define-on-demand-slot)
+(defmacro define-on-demand-slot (class slot (instance) &body body)
+  "Defines a slot which computes its initial value on demand.
+
+   Sets up the named SLOT of CLASS to establish its value as the implicit
+   progn BODY, by defining an appropriate method on `slot-unbound'."
+  (with-gensyms (classvar slotvar)
+    `(defmethod slot-unbound
+        (,classvar (,instance ,class) (,slotvar (eql ',slot)))
+       (declare (ignore ,classvar))
+       (setf (slot-value ,instance ',slot) (progn ,@body)))))
+
 ;;;----- That's all, folks --------------------------------------------------