linkfly (linkfly) wrote,
linkfly
linkfly

Устройство ASDF. Подсистема загрузки. FIND-COMPONENT.

(сказаное ниже относится к версии 2.019.2)

Это 13-ая статья цикла.
Первая статья.
Архитектура ASDF.
Предыдущая статья.

    Обобщённый метод FIND-COMPONENT весьма функционален и имеет не простую логику работы. Его объявление выглядит так:  

(defgeneric* find-component (base path)
  (:documentation "Finds the component with PATH starting from BASE module;
          if BASE is nil, then the component is assumed to be a system."
)
)


В общих чертах логика работы FIND-COMPONENT следующая:
 - если и BASE и PATH равны NIL, тогда результат NIL.
 - если BASE или PATH равны NIL (но не одновременно), то результатом будет то, что не равно NIL.
 - если мы передали MODULE и STRING, значит мы заполняем слот COMPONENTS-BY-NAME (переданного модуля) хэш-таблицей (в которой ключами будут имена а значениями объекты класса COMPONENT. Объекты берутся из слота COMPONENTS.
 - если в качестве BASE передали строку, тогда мы ищем систему по этой строке и если нашли, то ищем компонент уже в ней. Если передали в BASE символ, то делаем тоже самое, предварительно превратив символ в строку.

Дальнейшие варианты комбинаций параметров приводят в итоге к уже обозначенным вызовам:

 - если параметры не равны NIL и второй параметр - символ, то превратить его в строку и повторить поиск.
 - если параметр BASE представляет собой список, то вызвать поиск с первым элементом этого списка в качестве параметра BASE, а в качестве параметра PATH передать текущий список PATH, но с добавленным в голову хвостом списка BASE.
 - и наконец, самое сложное: если PATH (ну собственно на то он и PATH) представляет собой список то вызвать поиск, предварительно поискав элемент в котором будет вестись поиск, то есть предварительно вычислив значение первого аргумента. А вычисляется он с помощью того же поиска, в таком вот вызове:

    (find-component module (car name))

    ... чтобы не создавать прецендента для путаницы я взял код как есть, name в данном контексте это и есть PATH

    И далее, найдя по первому элементу PATH, компонент  в текущем модуле, сокращаем путь поиска и идем дальше но уже в найденном компоненте. Да в общем-то ничего сложного, вот таблица с помощью которой можно себе представить механизм передачи управления:

(module cons)           -> (t null)          ;; (find-component (find-component module
                                                          ;;                                                       (car name))
                                  -> (t cons)        ;;                            (cdr name))

(component null)       -> component

(component symbol) -> (component string) ;; (find-component component
                                                                     ;;                           (coerce-name name))

(cons t)                      -> (null cons)   ;; (find-component (car base)
                                  -> (t cons)        ;;                           (cons (cdr base) path))

(null null)                   -> nil

(null t)                       -> (t null)          ;; (find-component path nil)

(symbol t)                 -> (string t)

(string t)                   -> (system t)    ;; system = (find-system base nil)

(module string)        -> component  ;; (unless (slot-boundp module 'components-by-name)
                                                        ;;       (compute-module-components-by-name module))
                                                        ;; (values
                                                        ;;    (gethash name
                                                        ;;                 (module-components-by-name module)))

Лирическое отступление.
    Сразу приходит мысль: а не стоило ли как-то инкапсулировать логику поиска от применения обобщённых ф-ий (generic functions)? Не знаю, возможно. Но вот завернуть эти все дела в макрос разбирающий простенький DSL или какое-нибудь расширение принципа работы case или написать макрос обёртку над применениями typecase'a, в общем это наверное можно "отрефакторить". Должен заметить, что я ни в коей мере не хочу сказать, что код плохой и его надо срочно менять. А делаю всего лишь осторожное предположение, о том что (возможно!) есть необходимость небольшого рефакторинга. Тем не менее, решение рабочее а проект прямо так скажем - "фундаментальный" в мире Лиспа. А в настоящем не "игрушечном" проекте всегда есть место для рефакторинга.

--------------------------------------------
Продолжение следует ...
Tags: asdf, lisp, programming, лисп, программирование
Subscribe
  • Post a new comment

    Error

    default userpic

    Your reply will be screened

    When you submit the form an invisible reCAPTCHA check will be performed.
    You must follow the Privacy Policy and Google Terms of use.
  • 0 comments