linkfly (linkfly) wrote,
linkfly
linkfly

Устройство ASDF. Подсистема поиска. FIND-SYSTEM.

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

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

    Обобщённая ф-ия FIND-SYSTEM используется для поиска в оперативной памяти и на диске системы с именем NAME. Она возвращает объект, представляющий систему (экземпляр класса или подкласса SYSTEM). Сначала производится поиск в оперативной памяти уже определённой системы, конкретно в хэш-таблице связанной с символом *DEFINED-SYSTEMS*. Далее следует поиск файла с определением системы (файла с расширением *.asd). В случае, если система отсутствует в оперативной памяти или файл с её определением был обновлён - она загружается с помощью ф-ии LOAD-SYSDEF. Главный метод обобщённой ф-ии специализируется на объекте типа STRING, метод без специализации (или можно сказать специализирующийся на типе T) приводит имя параметра к унифицированной форме (к типу STRING) и передаёт управление соответствующему методу:

   (defmethod find-system (name &optional (error-p t))
      (find-system (coerce-name name) error-p)
)


    А метод специализирующийся на типе NULL просто сигнализирует об ошибке с сообщением: "NIL is not a valid system name".

    Рассмотрим по пунктам процесс поиска/загрузки главного метода ф-ии FIND-SYSTEM:

   (defmethod find-system ((name string) &optional (error-p t)) ...)

1. Тело функции заворачивается в макрос WITH-SYSTEM-DEFINITIONS. Смысл этого макроса в том, чтобы гарантировать наличие динамической переменной *SYSTEMS-BEING-DEFINED*, с которой связывается хэш-таблица, в которую попадают системы загружаемые в процессе поиска.

2. Организуется бесконечный цикл, на каждой итерации которого устанавливается рестарт REINITIALIZE-SOURCE-REGISTRY-AND-RETRY, при выборе которого переинициализируется динамическая переменная *SOURCE-REGISTRY*, посредством вызова ф-ии INITIALIZE-SOURCE-REGISTRY. Таким образом пользователю позволяется исправить ошибку (например поместить систему, что не была найдена в пути поиска систем) и продолжить поиск (или продолжить выполнение ф-ии, которая инициирует поиск системы, например ф-ию LOAD-SYSTEM).

3. С помощью MULTIPLE-VALUE-BIND определется локальный контекст для переменных FOUND-SYSTEM, PATHNAME, PREFIOUS-TIME:

   (multiple-value-bind (foundp found-system pathname previous previous-time)
        (locate-system name)
      (declare (ignore foundp))
      ...
)


    Как видно, для их связывания используется множественное значение возвращаемое ф-ей LOCATE-SYSTEM.

    LOCATE-SYSTEM
    3.1 Ф-ия LOCATE-SYSTEM ищет систему в оперативной памяти, при необходимости загружая определение системы с диска. Логика работы в следующем:

        3.1.1 Сначала производится поиск ф-ией SYSTEM-REGISTERED-P, которая просматривает хэш-таблицу *DEFINED-SYSTEMS*. Если система была найдена, то локальная переменная IN-MEMORY получает пару из временной отметки и объекта системы:

        (let (...
                (in-memory (system-registered-p name))
         ...
)


        3.1.2 Локальная переменная PREVIOUS получает найденную систему из поля cdr пары IN-MEMORY.

        3.1.3 Локальная PREVIOUS-TIME получает временную отметку, которую берёт поле car пары IN-MEMORY.

        3.1.4 Затем производится поиск объекта системы или пути к файлу с её определением (файлу *.asd) с помощью ф-ии SEARCH-FOR-SYSTEM-DEFINITION. Эта ф-ия обращается сначала к ф-ии FIND-SYSTEM-IF-BEING-DEFINED, которая просматривает упоминавшийся выше хэш *SYSTEMS-BEING-DEFINED* (тот самый, гарантию существования которого обеспечивает макрос WITH-SYSTEM-DEFINITIONS). Если система не была найдена, то производится поиск файла с её определением, сначала в *central-registry* c помощью ф-ии SYSDEF-CENTRAL-REGISTRY-SEARCH, а затем в *SOURCE-REGISTRY* с помощью ф-ии SYSDEF-SOURCE-REGISTRY-SEARCH. Примечательный момент: если и на этот раз не удалось найти систему, то с помощью вызова ф-ии SYSDEF-FIND-ASDF происходит проверка, не саму ли ASDF-систему пытаются найти и если это так - то создаётся и возвращается объект системы с именем "asdf". Найденный путь или система связывается с локальной FOUND. Если была найдена система, а не путь - то результат также связывается с локальной FOUND-SYSTEM.
                      
        3.1.5 С локальной PATHNAME связывается путь к файлу с определением системы. Если система уже загружена в оперативную память, то путь к файлу с определением вычисляется с помощью ф-ии SYSTEM-SOURCE-FILE.

        3.1.6 Локальная FOUNDP связывается со значением T если что-либо было найдено (система или путь к её определению).

        3.1.7 Если путь PATHNAME был вычислен, не является абсолютным и представляет собой символическую ссылку, то он вычисляется в реальный путь, который становится новым значением pathname. Если система была найдена (путь брался из объекта системы), то слот объекта системы SOURCE-FILE получает новый реальный путь к файлу с её определением.

        3.1.8 Если система была найдена в оперативной памяти и её путь не равен, найденному в путях поиска, файлу с определением системы, то найденный путь становится новым путём к файлу определения системы и локальная previous-time приравнивается к NIL.

        3.1.9 Формируется результат:

            (values foundp found-system pathname previous previous-time)

    Итак, с помощью LOCATE-SYSTEM и MULTIPLE-VALUE-BIND было создано локальное окружение в котором определены переменные FOUND-SYSTEM, PATHNAME, PREVIOUS, PREVIOUS-TIME.

    3.2 Если системы не было найдено в оперативной памяти и поиск с помощью SEARCH-FOR-SYSTEM-DEFINITION выдал объект системы (ф-ия FIND-SYSTEM-IF-BEING-DEFINED нашла систему в *SYSTEMS-BEING-DEFINED*, то есть, среди определяемых в данных момент систем), то производится регистрация системы с помощью ф-и REGISTER-SYSTEM. Ф-ия не делает ничего волшебного, а всего лишь проверяет что имя системы является строкой и гарантирует наличие пары (временная_отметка . объект_системы) в хэше *DEFINED-SYSTEMS*.

    3.3 Проверка на актуальность файла с определением системы. Если файл *.asd был изменён, то инициируется перезагрузка системы - вызывается ф-ия LOAD-SYSDEF. Она загружает файл с определением как обычный лисп-файл, только в, специально созданный для этого, временный пакет (который, после загрузки системы удаляет).

    3.4 По завершении, ф-ия FIND-SYSTEM актуализирует (если нужно) временную метку системы и возвращает, свою главную цель - объект системы.
----------------------------------------------------------------------------------------------------------------

     Ф-ии поиска по хэш-таблицам *CENTRAL-REGISTRY* и *SOURCE-REGISTRY*

SYSDEF-CENTRAL-REGISTRY-SEARCH.
(defun* sysdef-central-registry-search (system) ...)

1. Создаётся локальное окружение с переменной name, содержащей имя системы (в унифицированном с помощью COERCE-NAME виде), переменной TO-REMOVE, которая будет накапливать элементы для удаления из *CENTRAL-REGISTRY* и переменной TO-REPLACE, которая будет накапливать пары вида (текущий-эл. новый-эл.), для последующей перезаписи элементов в *CENTRAL-REGISTRY*.

2. Организуется цикл внутри формы UNWIND-PROTECT, которая обеспечивает обязательное выполнение "очищающих" (cleanup) форм, независимо от успешности выполнения итераций цикла. В cleanup части UNWIND-PROTECT две формы: 1-ая удаляет те элементы из *CENTRAL-REGISTRY*, которые присутствуют в локальной TO-REMOVE, 2-ая заменяет элементы в *CENTRAL-REGISTRY*, руководствуясь парами из локальной TO-REPLACE. Собственно цикл организуются по списку в *CENTRAL-REGISTRY*.

3. На каждой итерации цикла происходит обработка элемента из *CENTRAL-REGISTRY*. Предполагается что этот элемент является типом STRING или типом PATHNAME, а также может быть символьным выражением (sexpr), вычисляющимся (с помощью ф-ии EVAL) в элемент типа STRING или PATHNAME.

    3.1 Если подготовленный элемент не равен NIL, то производится проверка на то, что он является директорией.

        3.1.1 Если это так, формируется предполагаемый путь к файлу *.asd из имени системы и этой директории. Сформированный путь проверяется на валидность и в случае успеха, происходит выход из ф-ии SYSDEF-CENTRAL-REGISTRY-SEARCH, а сформированный путь возвращается в качестве результата.

        3.1.2 Если это не так, то формируется сообщение об ошибке и вызывается ф-ия ERROR с этим сообщением в контексте установленных рестартов REMOVE-ENTRY-FROM-REGISTRY и COERCE-ENTRY-TO-DIRECTORY:

            - REMOVE-ENTRY-FROM-REGISTRY - если пользователь выберет этот рестарт, то элемент будет занесёт в локальную переменную TO-REMOVE для последующего удаления из *CENTRAL-REGISTRY*.

            - COERCE-ENTRY-TO-DIRECTORY - если будет выбран этот рестарт то будет произведена попытка преобразования элемента в правильный путь с помощью ф-ии ENSURE-DIRECTORY-PATHNAME и пара из старого и нового пути будет добавлена в локальную TO-REPLACE для последующей перезаписи в cleanup форме UNWIND-PROTECT.

SYSDEF-SOURCE-REGISTRY-SEARCH.
(defun* sysdef-source-registry-search (system) ...)

    Ф-ия сначала обеспечивает инициализацию *SOURCE-REGISTRY* (с помощью ф-ии ENSURE-SOURCE-REGISTRY) хэш-таблицей с ключами из имён систем и значениями из путей к файлам с определениями этих систем. Затем из хэш-таблицы *SOURCE-REGISTRY* извлекается путь к лисп-системе стандартным, для получения значения по ключу из хэш-таблицы, способом. В качестве ключа используется имя системы:

    (values (gethash (coerce-name system) *source-registry*))

    Логика работы ф-ии ENSURE-SOURCE-REGISTRY состоит в следующем:

1. Если значение в *SOURCE-REGISTRY* не является хэш-таблицей то для её инициализации вызывается ф-ия INITIALIZE-SOURCE-REGISTRY.

2. Эта ф-ия инициализирует *SOURCE-REGISTRY* пустой хэш-таблицей и вызывает ф-ию COMPUTE-SOURCE-REGISTRY для её заполнения. Логика работы этой ф-ии - тема для отдельной статьи.

-------------------------------------------
Продолжение следует ...
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