Существует множество способов выполнить такую проверку типов ...
Один из предлагаемых вами вариантов - изменить исходный код (строку) для вставки дополнительных проверок типов предварительных условий.
Ключевым моментом этого подхода является то, что вам придется вставить проверку типа в нужном месте. Это означает, что необходимо каким-то образом проанализировать исходный источник (или, по крайней мере, селектор и аргументы), чтобы найти его точный диапазон (и имена аргументов).
См. Метод initPattern:return:
в Parser
и его отправителях. Вы найдете довольно низкоуровневый (не самый красивый) код, который заполняет блок (переданный через return: keyword) с sap
массивом из 3 объектов: селектор метода, аргументы метода и приоритет метода (код, сообщающий, еслиметод связан с одинарным, двоичным или ключевым сообщением). Оттуда вы получите достаточно материала для выполнения манипуляций с исходным кодом (вставьте строку в другую с помощью copyReplace:from:to:with:
).
Не стесняйтесь писать небольшие фрагменты кода и выполнять в отладчике (выберите код дляотладка, затем используйте меню отладки или ALT + Shift + D). Также широко используйте инспекторов, чтобы лучше понять, как все это работает!
Другое решение состоит в том, чтобы проанализировать все абстрактное синтаксическое дерево (AST) исходного кода и манипулировать этим AST для вставки проверок типов. Обычно анализатор создает AST, поэтому посмотрите, как он работает. Из модифицированного AST вы можете затем сгенерировать новый CompiledMethod
(инструкции байт-кода) и установить его в methodDictionary
- см. Исходный код compile:
и следуйте отправленным сообщениям, пока не обнаружите generateMethodFromNode:trailer:
. Это немного сложнее и имеет плохой побочный эффект: исходный код теперь не совпадает с генерируемым кодом, что может стать проблемой, если вы захотите отладить метод (к счастью, Squeak может использовать декомпилированный код вместо исходного кода). code!).
Наконец, вы также можете организовать альтернативный компилятор и парсер для некоторых ваших классов (см. compilerClass
и / или parserClass
). Альтернативный TypeHintParser
будет принимать измененный синтаксис с подсказками типов в исходном коде (когда-то это было реализовано с подсказками типов после аргументов внутри угловых скобок foo: x <Integer> bar: y <Number>
). И альтернативный TypeHintCompiler
организует автоматическую компиляцию предварительных условий с учетом этих подсказок типа. Поскольку в этом случае вы будете очень продвинуты в Squeak, вы также создадите специальное отображение между индексом исходного кода и байт-кодами, чтобы иметь в своем роде отлаженный отладчик и даже специальный класс Decompiler, который мог бы распознавать проверки типов предварительных условий и преобразовывать их обратно в подсказки типов на всякий случай.
Мой совет - начать с первого предлагаемого вами подхода.
РЕДАКТИРОВАТЬ
Я забыл сказать, есть еще одинКстати, но в настоящее время он доступен в Pharo, а не в Squeak: компилятор Pharo (с именем OpalCompiler
) преобразовывает инструкции байт-кода в объекты (имена классов, начинающиеся с IR) на этапе генерации. Таким образом, также возможно напрямую манипулировать инструкциями байт-кода путем правильного взлома на этом этапе ... Я почти уверен, что мы можем найти примеры использования. Вероятно, самая продвинутая техника.