< Previous | Next >
April 21, 2010 9:40 PM CDT by psilord in category Lisp

Coloring Inside the Lines

The topic of parenthesis paralysis arose in some circles I frequent in relation to Lisp. This is a semi-mythical notion that somehow the use of parentheses in Lisp contributes to cognitive difficulty or the seizing of thought. It is usually used as an excuse not to learn Lisp or make fun of it.

Related to this idea, a person by the name of Alessio Stalla hacked the Lisp reader to try and present a syntax that is more "newbie friendly". The actual hack is pretty cool.

His altering of the syntax of lisp made it look like what follows. I have some fundamental disagreements about the syntax--in particular the if expression consequence and alternate both being grouped by the { } characters associated with the if form. But that conversation is for another day...

with-output-to-string (str) {
  print #\c str;
  if (> foo 45) {
    progn { print 3; print 4; }
    print 5;

This generated some discussion and I decided to extend a post I had done in Usenet into a blog entry.

I've hacked scheme for a long time and lisp for a little while. I believe there is such a thing as parenthesis-paralysis. After some careful introspection upon it over the years, I've come to a belief about how it arises and presents.

It appears to me to happen because of two concepts:

  1. Indention style
  2. Destructuring bind, as performed by a human reading code.

Indention style, especially in lisp, is extremely important and emacs/slime is the only thing that culturally "does it correctly out of the box". It does it correctly, because the cultural indention style of Lisp appears to be exactly defined as what SLIME produces!

Most editor's notion of auto-indention is that when you hit return, you align with the first non-whitespace character on the previous line OR you just indent X columns. Combine this with a regular Joe's idea of indention being TAB, and you have a disastrous situation. For example suppose my tab stops are set to 4 in the following example. Every place you see a period is where I hit tab:

(let ((thing 42)
.   (stuff 99)
.   (qux 100))
.   (format t "Hi~%"))

Looks like crap doesn't it?

In other block structured languages, a simple tab is sufficient for code readability, e.g., C:

void foo(void)
.   int thing = 42;
.   int stuff = 99;
.   int qux = 100

.   printf("Hi\n");

Notice, from a mental model of indention, I did exactly the same behavior. I indented the bindings, left a space, then indented the body. People use the same mental model of indention for similar languages. This realization is the key to why people entering lisp for the first time have such a hard time about it.

Let's take a look at Alessio Stalla's precipitating example. If your tab stop is set to 2, then this is exactly how you would type it using a regular editor's default notion of indention and the TAB key.

with-output-to-string (str) {
. print #\c str;
. if (> foo 45) {
. . progn { print 3; print 4; }
. . print 5;
. }

We can hypothesize that the author's mental model of code indention appears to follow to the default behavior of their editor and that they write in block structured imperative languages more often than not. I believe the author of the code view this indention model as "correct". I put that in quotes, since it is purely subjective.

In C, C++, PHP, perl, Java, Python, Fortran 90, etc, etc, etc, applying the same mental indention model is just fine and leads to pretty readable code. Specifically in python, it is enshrined.

In Lisp (and somewhat scheme), the default behavior of the editor and/or the mental model of indention is completely wrong. Why? Reason number 2.

Humans use visual whitespace and alignments of similar boundary markers to block off semantically related entities. This helps them to destructure the forms into semantically meaningful sections or elements.

The correctly indented lisp form for the above let form:

(let ((thing 42)
      (stuff 99)
      (qux 100))

  (format t "Hi~%"))

You can see how the parentheses of the binding forms are aligned with each other. The ( which "sticks out" on the left is the demarcation of the beginning of the binding list. The fact the (format ...) is indented to the left of the bindings, but the right of the let states the bindings are over and tells you this is the body of the let.

Another one, more complex in lisp (done with the mental model of Algol-style indention):

(do ((x 0 (1+ x))
.   (y 10 (1- y))
.   (z 0 (1+ z)))
.   ((zerop y) (+ x z))

.   (format t "Hi!~%"))

That is terrible, since the test condition vanishes into the step forms. Get rid of the newline in the middle and it is a train wreck. The problem is that this is how editors want to do it by default! I've seen the modern generation of programmers lately. They use pico, notepad, gedit, or kde/gnome stuff (mere toy code editors to me) to write their code and they don't even realize there are others to choose from that are much better. The editors all do this ham fisted auto-indent behavior and can't really be taught otherwise. I can't imagine this while writing lisp. I would go insane. (Arguably, I may be insane, but that's for the courts to figure out.)

Here is the correctly indented do form. Notice how the "nubs" of the left side parentheses on the do visual block allow the eye to disambiguate the step and test forms.

(do ((x 0 (1+ x))
     (y 10 (1- y))
     (z 0 (1+ z)))
    ((zerop y) (+ x z))

  (format t "Hi~%"))

The crux of the indention issue is that culturally, lisp doesn't indent at the same quanta of indention as other languages over the various semantic forms of the language. Sometimes you need 1/4 of an indention, or 1/2 of one, or a one space difference. Programmers, when presented with such a problem, spend their time laboriously aligning (instead of code writing) parenthesis (often mixing tabs and spaces) so everything looks right--because their editor doesn't do it for them! This is the first part of the paralysis. If they don't know what looks right to begin with, they simply self converge to a self-consistent form of indention and write all their code in it.

The paralysis continues when, not having been grounded in the cultural indention style of lisp or not having an editor that performs it automatically, you start reading other people's code. If you get unlucky and read a collection of people's code that never learned the correct cultural style (each having their own style), then the destructuring process gets amazingly difficult to do. You end up reading character by character, parenthesis by parenthesis, trying to figure out where semantic forms start and end. The most powerful visual/spatial recognizer in your head (like 1/4 of your brain matter is devoted to it!) sits completely idle!

I hacked my emacs/SLIME syntax coloring to be very detailed and show many different classes of semantic ideas: comments, ANSI functions, macros, special forms, type names, special variables, constants, etc, etc, etc to all be color coordinated with each other using color theory to give me insight into what I've written--and whether I'm writing it correctly!

The most important change I did was to make the parenthesis color nearly the same as the background color. In a sense they vanish and I'm left with the spatial blocks as an indention structure, which works just fine. I can always resolve a specific parenthesis from the background if I have to to disambiguate a form. Usually, if I screwed something up, the indention level of my code base goes wrong and it is pretty easy to find where I missed a parenthesis.

Oddly, lisp is the only language for which I do this, all others are just white text on a black background and I prefer it that way. Syntax/Semantics highlighting is distracting to me in non lisp languages. It is a requirement for lisp!

After determined use of the colorizing/indention system slime and my hacks provide me, I occasionally find that looking at non-colorized, but correctly indented Lisp, is hard. The parentheses make a visual heaviness that is hard to ignore; I almost read it as ALL CAPS style yelling. If I'm looking at non-colorized and non-culturally indented lisp, I revert to the "hunt and peck" method of trying to destructure the semantic forms in my head. It gets frustrating very quickly.

I honestly believe parenthesis-paralysis is real. The right editor will make the paralysis completely disappear, but the wrong editor will accentuate it.

As a treat (maybe I'm using an esoteric definition of the word...), here is some horrendously written emacs lisp which augments the Lisp syntax highlighter in a certain color theme to in fact delineate various portions of the language to me. It is by no means the whole of what I want out of a Lisp IDE, but is a tiny step that saves me some heartache.

I searched through emacs' color themes for a long time, and mostly came to the conclusion that most of those theme designers had never opened, let alone been in the same state as, a book on color theory or color perception. Bold claims? Sure, but I'm an idiot writing a blog, and that should be normal fare on the Internet. This is why I don't have a comment section.

What I did was started with the idea of warm colors being near to the viewer, cool colors being far. I also took into consideration complimentary colors, color intensity, and a Western view of the general meaning of bare colors. Each axis: warm to cool, color to compliment, and low to high intensity, cultural meaning of color, has a reason to exist in the syntax highlighting. Once you are aware of these meanings it becomes much easier to visually process the code and get a handle of the dependencies in the code. This design isn't finished yet, and over time I'm evolving it as I see what I actually care about when writing Lisp.

Here are some rules about the things I wanted to emphasize or ensure I could easily separate on my screen. These rules are not the complete set I wish to do in my source, just the ones I was generally able to do given the tools I had. Also, things like special forms and macros get the same color, because I haven't found a reason to separate them.

Once one has the concrete plan about what one cares about in the Lisp code, you go and start assigning colors. Emphasizing means higher intensity, and separating means putting the concepts into color compliment domains. Choosing colors on the grey/brown intensity scale mean you only care about emphasis in between them, but they don't exist as compliments to other things. A complimentary concept is like code and comments or special variables and non-special variables. Use of warm and cool colors can give a sense of depth in the code allowing once to inspect code quickly for important things, which should be up front.

So, given the semantic plan and color knowledge, I went and assigned colors. This is what I made.

Screenshot 1: Some code out of the MD5 implementation by Pierre R. Mai. Notice how the coloring regularizes the text and makes it easy for your eye to wander over the color blocks inspecting what is present.

Colorized Text

Screenshot 2: Some code out of the MIDI library implementation by Mathieu Chabanne, Camille Constant, Emmanuel Necibar, Stephanie Recco, Robert Strandh, David Lewis, Marcus Pearce, and Christophe Rhodes. If I were looking at this code, the special variable *time* would be most important to me. Good thing it is a high intensity color.

Colorized Text

This code was generated by me scraping the Common Lisp Hyperspec web pages, munging the symbols and whatnot into the form you see below, and then insufficiently reading the emacs lisp programming manual. It is built on top of the comidia color theme, but I suspect if you change the colors can be customized to another theme. There are some errors in the highlighting like 1+ doesn't get recognized probably because it looks like a +1+ constant in terms of the regexes and I haven't figure out exactly how to fix it. There are other limitations and omissions, like ,@*foo* not being highlighted correctly that I need to figure out as well. I fix them when they annoy me enough.

There are some tasks like highlighting certain grouping parentheses when the point is not in the extent of them that I have no idea how to do. Some of the complex highlighting I want which is more semantics based, e.g., any symbol in a condition spot in a handler-case is colored a specific color but only if it actually exists in the source, and symbols used in functional places should be colored color A, but if used in another namespace are colored according to that namespace, is impossible to do in emacs since the language structure is not fully realized in the editor. Because this simplistic highlighter is semanticly ignorant, if you have a habit of choosing common lisp symbols and using them in other namespaces, this syntax highlighter is probably going to overly upset you.

As for me, I use the non-terminal mode of emacs and I don't intersect namespace boundaries on the same symbol. I don't care if this doesn't work in terminal mode since I will most likely never use that mode. If you decide to use it, good luck.

Frankly, the most useful thing out of this code is the 978 common lisp symbols that have been categorized for your use in a different piece of code.

All the code I wrote in this blog post is under the *spins the wheel* Modified BSD License.

;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; set up a color theme that is good enough for now.
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(when (require 'color-theme nil 'noerror)

;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Set up some highlighting rules for all known ANSI common lisp functions and
;; macro names, special operators, etc. This assumes color-theme-comidia.
;; This is always tinkerable....
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defface ansi-lisp-boolean
  '((t (:foreground "white")))
  "Color all of the ANSI Common Lisp Booleans this specific color")

(defface ansi-lisp-constant
  '((t (:foreground "orchid1")))
  "Color all of the ANSI Common Lisp Constants this specific color")

(defface ansi-lisp-declaration
  '((t (:foreground "indianred2")))
  "Color all of the ANSI Common Lisp Declarations this specific color")

(defface ansi-lisp-condition-type
  '((t (:foreground "indianred2")))
  "Color all of the ANSI Common Lisp Condition Types this specific color")

(defface ansi-lisp-function
  '((t (:foreground "pale green")))
  "Color all of the ANSI Common Lisp Functions this specific color")

(defface ansi-lisp-generic-function
  '((t (:foreground "cyan"))) ; same as the comida color-theme which I use.
  "Color all of the ANSI Common Lisp Generic Functions this specific color")

(defface ansi-lisp-macro
  '((t (:foreground "cyan"))) ; same as comida color-theme which I use.
  "Color all of the ANSI Common Lisp Macros this specific color")

(defface ansi-lisp-special-operator
  '((t (:foreground "cyan"))) ; same as macros and as the comida color-theme.
  "Color all of the ANSI Common Lisp Special Operators this specific color")

(defface ansi-lisp-type
  '((t (:foreground "red")))
  "Color all of the ANSI Common Lisp Types this specific color")

(defface ansi-lisp-unknown
  '((t (:foreground "red")))
  "Color all of the ANSI Common Lisp  this specific color")

(defface ansi-lisp-global-variable
  '((t (:foreground "yellow2")))
  "Color all of the ANSI Common Lisp Globals this specific color")

(defface ansi-lisp-expression
  '((t (:foreground "indianred1")))
  "Color all of the ANSI Common Lisp Expressions (like declare) this specific color")

(defface ansi-lisp-parenthesis
  '((t (:foreground "#4d4d3d")))  ; grey25, but with more yellow in it
  "Color all of the ANSI Common Lisp Parenthesis")

(defface ansi-lisp-numbers
  '((t (:foreground "orchid1")))
  "Color all of the ANSI Common Lisp Numbers")

;;; These are functions which produce the individual entries for each kind of
;;; symbol name according to what face they should have.

(defun ansi-boolean (x)
    'string "\\<\\(" (symbol-name x) "\\)\\>") 0 ''ansi-lisp-boolean))

(defun ansi-constant (x)
    'string "\\<\\(" (symbol-name x) "\\)\\>") 0 ''ansi-lisp-constant))

(defun ansi-declaration (x)
    'string "\\<\\(" (symbol-name x) "\\)\\>") 0 ''ansi-lisp-declaration))

(defun ansi-condition-type (x)
    'string "\\<\\(" (symbol-name x) "\\)\\>") 0 ''ansi-lisp-condition-type))

(defun ansi-function (x)
    'string "\\<\\(" (symbol-name x) "\\)\\>") 0 ''ansi-lisp-function))

(defun ansi-generic-function (x)
    'string "\\<\\(" (symbol-name x) "\\)\\>") 0 ''ansi-lisp-generic-function))

(defun ansi-macro (x)
    'string "\\<\\(" (symbol-name x) "\\)\\>") 0 ''ansi-lisp-macro))

(defun ansi-special-operator (x)
    'string "\\<\\(" (symbol-name x) "\\)\\>") 0 ''ansi-lisp-special-operator))

(defun ansi-type (x)
    'string "\\<\\(" (symbol-name x) "\\)\\>") 0 ''ansi-lisp-type))

(defun ansi-unknown (x)
    'string "\\<\\(" (symbol-name x) "\\)\\>") 0 ''ansi-lisp-unknown))

(defun ansi-global-variable (x)
    'string "\\<\\(" (symbol-name x) "\\)\\>") 0 ''ansi-lisp-global-variable))

(defun ansi-expression (x)
                                        ; used for things like declare
    'string "\\<\\(" (symbol-name x) "\\)\\>") 0 ''ansi-lisp-expression))

(when t ;; sometimes I need to disable this whole thing....
  (add-hook 'lisp-mode-hook
            (lambda ()
                ;; Conventional Constant Variables
                '(("\\<\\([+][^ +]*[+]\\)\\>" 0 #'ansi-lisp-constant))

                ;; Conventional Global Variables, including ANSI ones
                '(("\\<\\([*][^ *]*[*]\\)\\>" 0 #'ansi-lisp-global-variable))

                ;; Lisp Numbers, simple ones, just integers
                '(("\\<\\([+-]?[0-9]+\\)\\>" 0 #'ansi-lisp-numbers))

                ;; I'm a psycho and want my parentheis color to be controlled.
                '(("\\([()]\\)" 0 #'ansi-lisp-parenthesis))

                ;; These are often important to see, but I don't know how to
                ;; highlight the matching parenthesis with it
                ;;'(("\\([#][']\\)" 0 'ansi-lisp-boolean))

                (mapcar #'ansi-boolean
                        '(nil t))

                (mapcar #'ansi-constant '(array-dimension-limit
                        array-rank-limit array-total-size-limit
                        boole-1 boole-2 boole-and boole-andc1
                        boole-andc2 boole-c1 boole-c2 boole-clr
                        boole-eqv boole-ior boole-nand boole-nor
                        boole-orc1 boole-orc2 boole-set boole-xor
                        call-arguments-limit char-code-limit
                        lambda-list-keywords lambda-parameters-limit
                        least-positive-single-float long-float-epsilon
                        most-negative-fixnum most-negative-long-float
                        most-positive-fixnum most-positive-long-float
                        multiple-values-limit pi short-float-epsilon

                (mapcar #'ansi-declaration '(type compilation-speed
                        debug declaration dynamic-extent ftype
                        ignorable ignore inline notinline optimize
                        safety space special speed))

                (mapcar #'ansi-condition-type '(arithmetic-error
                        cell-error condition control-error
                        division-by-zero end-of-file file-error
                        floating-point-underflow package-error
                        parse-error print-not-readable program-error
                        reader-error serious-condition
                        simple-condition simple-error
                        simple-type-error simple-warning
                        storage-condition stream-error style-warning
                        type-error unbound-slot unbound-variable
                        undefined-function warning))

                (mapcar #'ansi-function '(- / \* \+ abort and atom bit
                        character complex cons continue eql error
                        float list logical-pathname member mod
                        muffle-warning not null pathname rational
                        store-value string use-value values vector /=
                        1- 1\+ < <= = > >= abs acons acos acosh adjoin
                        adjust-array adjustable-array-p alpha-char-p
                        alphanumericp append apply apropos
                        apropos-list aref arithmetic-error-operands
                        arithmetic-error-operation array-dimension
                        array-dimensions array-displacement
                        array-element-type array-has-fill-pointer-p
                        array-in-bounds-p array-rank
                        array-row-major-index array-total-size arrayp
                        ash asin asinh assoc assoc-if assoc-if-not
                        atan atanh bit-and bit-andc1 bit-andc2 bit-eqv
                        bit-ior bit-nand bit-nor bit-not bit-orc1
                        bit-orc2 bit-vector-p bit-xor boole
                        both-case-p boundp break
                        broadcast-stream-streams butlast byte
                        byte-position byte-size caaaar caaadr caaar
                        caadar caaddr caadr caar cadaar cadadr cadar
                        caddar cadddr caddr cadr call-next-method car
                        cdaaar cdaadr cdaar cdadar cdaddr cdadr cdar
                        cddaar cddadr cddar cdddar cddddr cdddr cddr
                        cdr ceiling cell-error-name cerror char
                        char-code char-downcase char-equal
                        char-greaterp char-int char-lessp char-name
                        char-not-equal char-not-greaterp
                        char-not-lessp char-upcase char/= char< char<=
                        char= char> char>= characterp cis class-of
                        clear-input clear-output close clrhash
                        code-char coerce compile compile-file
                        compile-file-pathname compiled-function-p
                        compiler-macro compiler-macro-function
                        complement complexp compute-restarts
                        concatenate concatenated-stream-streams
                        conjugate consp constantly constantp
                        copy-alist copy-list copy-pprint-dispatch
                        copy-readtable copy-seq copy-structure
                        copy-symbol copy-tree cos cosh count count-if
                        count-if-not decode-float
                        decode-universal-time delete delete-duplicates
                        delete-file delete-if delete-if-not
                        delete-package denominator deposit-field
                        describe describe-object digit-char
                        digit-char-p directory directory-namestring
                        disassemble documentation dpb dribble
                        echo-stream-output-stream ed eighth elt
                        encode-universal-time endp enough-namestring
                        ensure-generic-function eq equal equalp eval
                        evenp every exp export expt fboundp fceiling
                        fdefinition ffloor fifth file-author
                        file-error-pathname file-length
                        file-namestring file-position
                        file-string-length file-write-date fill
                        fill-pointer find find-all-symbols find-class
                        find-if find-if-not find-package find-restart
                        find-symbol finish-output first float-digits
                        float-precision float-radix float-sign floatp
                        floor fmakunbound force-output format fourth
                        fresh-line fround ftruncate funcall
                        function-lambda-expression functionp gcd
                        gensym gentemp get get-decoded-time
                        get-internal-real-time get-internal-run-time
                        get-macro-character get-output-stream-string
                        get-properties get-setf-expansion
                        get-universal-time getf gethash graphic-char-p
                        hash-table-count hash-table-p
                        hash-table-rehash-threshold hash-table-size
                        hash-table-test host-namestring identity
                        imagpart import input-stream-p inspect
                        integer-decode-float integer-length integerp
                        interactive-stream-p intern intersection
                        invalid-method-error invoke-debugger
                        invoke-restart invoke-restart-interactively
                        isqrt keywordp last lcm ldb ldb-test ldiff
                        length lisp-implementation-type
                        lisp-implementation-version list-all-packages
                        list-length list\* listen listp load
                        load-logical-pathname-translations log logand
                        logandc1 logandc2 logbitp logcount logeqv
                        logical-pathname-translations logior lognand
                        lognor lognot logorc1 logorc2 logtest logxor
                        long-site-name lower-case-p machine-instance
                        machine-type machine-version macro-function
                        macroexpand macroexpand-1 make-array
                        make-broadcast-stream make-concatenated-stream
                        make-condition make-dispatch-macro-character
                        make-echo-stream make-hash-table make-list
                        make-load-form-saving-slots make-package
                        make-pathname make-random-state make-sequence
                        make-string make-string-input-stream
                        make-string-output-stream make-symbol
                        make-synonym-stream make-two-way-stream
                        makunbound map map-into mapc mapcan mapcar
                        mapcon maphash mapl maplist mask-field max
                        member-if member-if-not merge merge-pathnames
                        method-combination-error min minusp mismatch
                        name-char namestring nbutlast nconc
                        next-method-p nintersection ninth notany
                        notevery nreconc nreverse nset-difference
                        nset-exclusive-or nstring-capitalize
                        nstring-downcase nstring-upcase nsublis nsubst
                        nsubst-if nsubst-if-not nsubstitute
                        nsubstitute-if nsubstitute-if-not nth nthcdr
                        numberp numerator nunion oddp open
                        open-stream-p output-stream-p
                        package-error-package package-name
                        package-nicknames package-shadowing-symbols
                        package-use-list package-used-by-list packagep
                        pairlis parse-integer parse-namestring
                        pathname-device pathname-directory
                        pathname-host pathname-match-p pathname-name
                        pathname-type pathname-version pathnamep
                        peek-char phase plusp position position-if
                        position-if-not pprint pprint-dispatch
                        pprint-fill pprint-indent pprint-linear
                        pprint-newline pprint-tab pprint-tabular prin1
                        prin1-to-string princ princ-to-string print
                        print-not-readable-object print-object
                        probe-file proclaim provide random
                        random-state-p rassoc rassoc-if rassoc-if-not
                        rationalize rationalp read read-byte read-char
                        read-char-no-hang read-delimited-list
                        read-from-string read-line
                        read-preserving-whitespace read-sequence
                        readtable-case readtablep realp realpart
                        reduce rem remhash remove remove-duplicates
                        remove-if remove-if-not remprop rename-file
                        rename-package replace require rest
                        restart-name revappend reverse room round
                        row-major-aref rplaca rplacd sbit scale-float
                        schar search second set set-difference
                        set-dispatch-macro-character set-exclusive-or
                        set-macro-character set-pprint-dispatch
                        set-syntax-from-char seventh shadow
                        shadowing-import short-site-name signal signum
                        simple-string-p simple-vector-p sin sinh sixth
                        sleep slot-boundp slot-exists-p
                        slot-makunbound slot-value software-type
                        software-version some sort special-operator-p
                        sqrt stable-sort standard-char-p
                        stream-element-type stream-error-stream
                        stream-external-format streamp
                        string-capitalize string-downcase string-equal
                        string-greaterp string-left-trim string-lessp
                        string-not-equal string-not-greaterp
                        string-not-lessp string-right-trim string-trim
                        string-upcase string/= string< string<=
                        string= string> string>= stringp structure
                        sublis subseq subsetp subst subst-if
                        subst-if-not substitute substitute-if
                        substitute-if-not subtypep svref sxhash
                        symbol-function symbol-name symbol-package
                        symbol-plist symbol-value symbolp
                        synonym-stream-symbol tailp tan tanh tenth
                        terpri third translate-logical-pathname
                        translate-pathname tree-equal truename
                        truncate two-way-stream-input-stream
                        two-way-stream-output-stream type-error-datum
                        type-error-expected-type type-of typep
                        unbound-slot-instance unexport unintern union
                        unread-char unuse-package
                        upgraded-complex-part-type upper-case-p
                        use-package user-homedir-pathname values-list
                        variable vector-pop vector-push
                        vector-push-extend vectorp warn
                        wild-pathname-p write write-byte write-char
                        write-line write-sequence write-string
                        write-to-string y-or-n-p yes-or-no-p zerop))

                (mapcar #'ansi-generic-function '(add-method
                        allocate-instance change-class class-name
                        compute-applicable-methods find-method
                        function-keywords initialize-instance
                        make-instance make-instances-obsolete
                        make-load-form method-qualifiers
                        no-applicable-method no-next-method
                        reinitialize-instance remove-method
                        shared-initialize slot-missing slot-unbound

                (mapcar #'ansi-macro '(lambda or setf assert
                        call-method case ccase check-type cond
                        ctypecase decf declaim defclass defconstant
                        defgeneric define-compiler-macro
                        define-condition define-method-combination
                        define-modify-macro define-setf-expander
                        define-symbol-macro defmacro defmethod
                        defpackage defparameter defsetf defstruct
                        deftype defun defvar destructuring-bind do
                        do-all-symbols do-external-symbols do-symbols
                        do\* dolist dotimes ecase etypecase formatter
                        handler-bind handler-case ignore-errors
                        in-package incf loop loop-finish make-method
                        multiple-value-bind multiple-value-list
                        multiple-value-setq nth-value otherwise pop
                        pprint-logical-block pprint-pop
                        print-unreadable-object prog prog1 prog2
                        prog\* psetf psetq push pushnew remf
                        restart-bind restart-case return rotatef
                        shiftf step time trace typecase unless untrace
                        when with-accessors with-compilation-unit
                        with-input-from-string with-open-file
                        with-open-stream with-output-to-string
                        with-package-iterator with-simple-restart
                        with-slots with-standard-io-syntax))

                (mapcar #'ansi-special-operator '(function block catch
                        eval-when flet go if labels let let\*
                        load-time-value locally macrolet
                        multiple-value-call multiple-value-prog1 progn
                        progv quote return-from setq symbol-macrolet
                        tagbody the throw unwind-protect))

                (mapcar #'ansi-type '(array base-char base-string
                        bignum bit-vector boolean broadcast-stream
                        built-in-class class compiled-function
                        concatenated-stream double-float echo-stream
                        extended-char file-stream fixnum
                        generic-function hash-table integer keyword
                        long-float method number package random-state
                        ratio readtable real restart satisfies
                        sequence short-float signed-byte simple-array
                        simple-base-string simple-bit-vector
                        simple-string simple-vector single-float
                        standard-char standard-class
                        standard-generic-function standard-method
                        standard-object stream string-stream
                        structure-class structure-object symbol
                        synonym-stream two-way-stream unsigned-byte))

                (mapcar #'ansi-unknown

                (mapcar #'ansi-global-variable '(// /// \*\* \*\*\*
                        \*break-on-signals\* \*compile-file-pathname\*
                        \*compile-file-truename\* \*compile-print\*
                        \*compile-verbose\* \*debug-io\*
                        \*default-pathname-defaults\* \*error-output\*
                        \*features\* \*gensym-counter\*
                        \*load-pathname\* \*load-print\*
                        \*load-truename\* \*load-verbose\*
                        \*macroexpand-hook\* \*modules\* \*package\*
                        \*print-array\* \*print-base\* \*print-case\*
                        \*print-circle\* \*print-escape\*
                        \*print-gensym\* \*print-length\*
                        \*print-level\* \*print-lines\*
                        \*print-pprint-dispatch\* \*print-pretty\*
                        \*print-radix\* \*print-readably\*
                        \*print-right-margin\* \*query-io\*
                        \*random-state\* \*read-base\*
                        \*read-default-float-format\* \*read-eval\*
                        \*read-suppress\* \*readtable\*
                        \*standard-input\* \*standard-output\*
                        \*terminal-io\* \*trace-output\* \+\+ \+\+\+))

                (mapcar #'ansi-expression


End of Line.

< Previous | Next >