Peter Siebel - Practical Common Lisp

Здесь есть возможность читать онлайн «Peter Siebel - Practical Common Lisp» весь текст электронной книги совершенно бесплатно (целиком полную версию без сокращений). В некоторых случаях можно слушать аудио, скачать через торрент в формате fb2 и присутствует краткое содержание. Год выпуска: 2005, ISBN: 2005, Издательство: Apress, Жанр: Программирование, на английском языке. Описание произведения, (предисловие) а так же отзывы посетителей доступны на портале библиотеки ЛибКат.

Practical Common Lisp: краткое содержание, описание и аннотация

Предлагаем к чтению аннотацию, описание, краткое содержание или предисловие (зависит от того, что написал сам автор книги «Practical Common Lisp»). Если вы не нашли необходимую информацию о книге — напишите в комментариях, мы постараемся отыскать её.

Practical Common Lisp — читать онлайн бесплатно полную книгу (весь текст) целиком

Ниже представлен текст книги, разбитый по страницам. Система сохранения места последней прочитанной страницы, позволяет с удобством читать онлайн бесплатно книгу «Practical Common Lisp», без необходимости каждый раз заново искать на чём Вы остановились. Поставьте закладку, и сможете в любой момент перейти на страницу, на которой закончили чтение.

Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

You can make the distinction between the two flavors of macros implicit: when you define a FOO macro, the parameter list can include an &attributesparameter. If it does, the macro form will be parsed like a regular cons form, and the macro function will be passed two values, a plist of attributes and a list of expressions that make up the body of the form. A macro form without an &attributesparameter won't be parsed for attributes, and the macro function will be invoked with a single argument, a list containing the body expressions. The former is useful for what are essentially HTML templates. For example:

(define-html-macro :mytag (&attributes attrs &body body)

`((:div :class "mytag" ,@attrs) ,@body))

HTML> (html (:mytag "Foo"))

Foo

NIL

HTML> (html (:mytag :id "bar" "Foo"))

Foo

NIL

HTML> (html ((:mytag :id "bar") "Foo"))

Foo

NIL

The latter kind of macro is more useful for writing macros that manipulate the forms in their body. This type of macro can function as a kind of HTML control construct. As a trivial example, consider the following macro that implements an :ifconstruct:

(define-html-macro :if (test then else)

`(if ,test (html ,then) (html ,else)))

This macro allows you to write this:

(:p (:if (zerop (random 2)) "Heads" "Tails"))

instead of this slightly more verbose version:

(:p (if (zerop (random 2)) (html "Heads") (html "Tails")))

To determine which kind of macro you should generate, you need a function that can parse the parameter list given to define-html-macro. This function returns two values, the name of the &attributesparameter, or NIL if there was none, and a list containing all the elements of argsafter removing the &attributesmarker and the subsequent list element. [320] Note that &attributes is just another symbol; there's nothing intrinsically special about names that start with & .

(defun parse-html-macro-lambda-list (args)

(let ((attr-cons (member '&attributes args)))

(values

(cadr attr-cons)

(nconc (ldiff args attr-cons) (cddr attr-cons)))))

HTML> (parse-html-macro-lambda-list '(a b c))

NIL

(A B C)

HTML> (parse-html-macro-lambda-list '(&attributes attrs a b c))

ATTRS

(A B C)

HTML> (parse-html-macro-lambda-list '(a b c &attributes attrs))

ATTRS

(A B C)

The element following &attributesin the parameter list can also be a destructuring parameter list.

HTML> (parse-html-macro-lambda-list '(&attributes (&key x y) a b c))

(&KEY X Y)

(A B C)

Now you're ready to write define-html-macro. Depending on whether there was an &attributesparameter specified, you need to generate one form or the other of HTML macro so the main macro simply determines which kind of HTML macro it's defining and then calls out to a helper function to generate the right kind of code.

(defmacro define-html-macro (name (&rest args) &body body)

(multiple-value-bind (attribute-var args)

(parse-html-macro-lambda-list args)

(if attribute-var

(generate-macro-with-attributes name attribute-var args body)

(generate-macro-no-attributes name args body))))

The functions that actually generate the expansion look like this:

(defun generate-macro-with-attributes (name attribute-args args body)

(with-gensyms (attributes form-body)

(if (symbolp attribute-args) (setf attribute-args `(&rest ,attribute-args)))

`(eval-when (:compile-toplevel :load-toplevel :execute)

(setf (get ',name 'html-macro-wants-attributes) t)

(setf (get ',name 'html-macro)

(lambda (,attributes ,form-body)

(destructuring-bind (,@attribute-args) ,attributes

(destructuring-bind (,@args) ,form-body

,@body)))))))

(defun generate-macro-no-attributes (name args body)

(with-gensyms (form-body)

`(eval-when (:compile-toplevel :load-toplevel :execute)

(setf (get ',name 'html-macro-wants-attributes) nil)

(setf (get ',name 'html-macro)

(lambda (,form-body)

(destructuring-bind (,@args) ,form-body ,@body)))))

The macro functions you'll define accept either one or two arguments and then use DESTRUCTURING-BIND to take them apart and bind them to the parameters defined in the call to define-html-macro. In both expansions you need to save the macro function in the name's property list under html-macroand a boolean indicating whether the macro takes an &attributesparameter under the property html-macro-wants-attributes. You use that property in the following function, expand-macro-form, to determine how the macro function should be invoked:

(defun expand-macro-form (form)

(if (or (consp (first form))

(get (first form) 'html-macro-wants-attributes))

(multiple-value-bind (tag attributes body) (parse-cons-form form)

(funcall (get tag 'html-macro) attributes body))

(destructuring-bind (tag &body body) form

(funcall (get tag 'html-macro) body))))

The last step is to integrate macros by adding a clause to the dispatching COND in the top-level processfunction.

(defun process (processor form)

(cond

((special-form-p form) (process-special-form processor form))

((macro-form-p form) (process processor (expand-macro-form form)))

((sexp-html-p form) (process-sexp-html processor form))

((consp form) (embed-code processor form))

(t (embed-value processor form))))

This is the final version of process.

The Public API

Now, at long last, you're ready to implement the htmlmacro, the main entry point to the FOO compiler. The other parts of FOO's public API are emit-htmland with-html-output, which I discussed in the previous chapter, and define-html-macro, which I discussed in the previous section. The define-html-macromacro needs to be part of the public API because FOO's users will want to write their own HTML macros. On the other hand, define-html-special-operatorisn't part of the public API because it requires too much knowledge of FOO's internals to define a new special operator. And there should be very little that can't be done using the existing language and special operators. [321] The one element of the underlying language-processing infrastructure that's not currently exposed through special operators is the indentation. If you wanted to make FOO more flexible, albeit at the cost of making its API that much more complex, you could add special operators for manipulating the underlying indenting printer. But it seems like the cost of having to explain the extra special operators would outweigh the rather small gain in expressiveness.

Читать дальше
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

Похожие книги на «Practical Common Lisp»

Представляем Вашему вниманию похожие книги на «Practical Common Lisp» списком для выбора. Мы отобрали схожую по названию и смыслу литературу в надежде предоставить читателям больше вариантов отыскать новые, интересные, ещё непрочитанные произведения.


Отзывы о книге «Practical Common Lisp»

Обсуждение, отзывы о книге «Practical Common Lisp» и просто собственные мнения читателей. Оставьте ваши комментарии, напишите, что Вы думаете о произведении, его смысле или главных героях. Укажите что конкретно понравилось, а что нет, и почему Вы так считаете.

x