Что касается «осведомленности языка о коде», я не видел лучшего, чем Lisp и его макро-средство, в частности Common Lisp. Но дело в том, что в большинстве случаев тип объекта неизвестен во время компиляции или во время макрорасширения. Для литералов типы известны, поэтому вы можете найти примеры агрессивных макросов, которые проверяют, является ли объект литералом, и, если да, обрабатывают его одним способом - возможно, в зависимости от его типа - и в противном случае подготавливают обнаруженную переменную. для проверки типа во время выполнения.
Вот пример, который я адаптировал из библиотеки CLLIB (часть CLOCC em > библиотека) несколько лет назад. Цель состоит в том, чтобы предоставить функции, которые будут вырезать строку префикса из некоторой другой строки с совпадающим префиксом. Префикс может быть известен во время макрорасширения, а может и нет. Если это так, мы можем провести оптимизацию: сначала вычислить длину префикса и встроить ее как литерал, чтобы она не пересчитывалась при каждом вызове сгенерированной функции. Сначала макрос пугает, но фактически сгенерированный код невелик.
(defmacro after-prefix-core (comparison-op prefix string &optional length)
"Similar to cllib:string-beg-with-cs."
(flet ((chop (prefix prefix-length string string-length)
`(when (and (>= ,string-length ,prefix-length)
(,comparison-op ,prefix ,string :end2 ,prefix-length))
(subseq ,string ,prefix-length ,string-length))))
(let* ((gstring (gensym "STRING-"))
(gstring-length (gensym "STRING-LENGTH-")))
`(let* ((,gstring ,string)
(,gstring-length ,(or length `(length ,gstring))))
,(if (stringp prefix)
;; Constant -- length known at expansion time.
(let ((prefix-length (length prefix)))
(chop prefix prefix-length gstring gstring-length))
;; Other form -- length not known at expansion time.
(let ((gprefix (gensym "PREFIX-"))
(gprefix-length (gensym "PREFIX-LENGTH-")))
`(let* ((,gprefix ,prefix)
(,gprefix-length (length ,gprefix)))
,(chop gprefix gprefix-length gstring gstring-length))))))))
(defmacro after-prefix (prefix string &optional length)
"Similar to cllib:string-beg-with."
`(after-prefix-core string-equal ,prefix ,string ,length))
(defmacro after-prefix-cs (prefix string &optional length)
"Similar to cllib:string-beg-with-cs."
`(after-prefix-core string= ,prefix ,string ,length))
Посмотреть форму
(if (stringp prefix)
в центре? Это проверка первого аргумента во время расширения макроса, и, в зависимости от того, является ли аргумент литералом или символом, его тип может быть известен или не известен. Если тип является символом, мы предполагаем, что нам следует дождаться времени выполнения, чтобы пересмотреть его как переменную, указывающую на какое-то другое значение.
Вот расширение формы (after-prefix foo bar)
:
(LET* ((#:STRING-5340 BAR) (#:STRING-LENGTH-5341 (LENGTH #:STRING-5340)))
(LET* ((#:PREFIX-5342 FOO) (#:PREFIX-LENGTH-5343 (LENGTH #:PREFIX-5342)))
(WHEN
(AND (>= #:STRING-LENGTH-5341 #:PREFIX-LENGTH-5343)
(STRING-EQUAL #:PREFIX-5342 #:STRING-5340 :END2 #:PREFIX-LENGTH-5343))
(SUBSEQ #:STRING-5340 #:PREFIX-LENGTH-5343 #:STRING-LENGTH-5341))))
Обратите внимание, что переменная #:PREFIX-LENGTH-5343
привязана к вычисленной длине FOO
, привязанной здесь к переменной #:PREFIX-5342
.
Теперь посмотрите на расширение формы (after-prefix "foo" bar)
, где префикс теперь является строковым литералом:
(LET* ((#:STRING-5463 BAR) (#:STRING-LENGTH-5464 (LENGTH #:STRING-5463)))
(WHEN (AND (>= #:STRING-LENGTH-5464 3) (STRING-EQUAL "foo" #:STRING-5463 :END2 3))
(SUBSEQ #:STRING-5463 3 #:STRING-LENGTH-5464)))
Теперь невозможно вычислить длину «foo»; он встроен как 3.
В этом примере может показаться, что это слишком много работы, но способность делать такие вещи - хорошая сила, как выражается в вашем вопросе.
person
seh
schedule
21.11.2009
if
может быть определено во время компиляции. Не уверен, что это полностью отвечает на ваш вопрос. - person Mark Ransom   schedule 11.11.2009