Squeak (smalltallk), как «вставить» строку в строку - PullRequest
3 голосов
/ 11 декабря 2019

Я пишу класс с именем "MyObject". один из методов класса:

addTo: aCodeString assertType: aTypeCollection

когда метод вызывается с aCodeString, я хочу добавить (во время выполнения) новый метод к классу "MyObject", который aCodeString является его исходным кодоми вставьте код проверки типа в исходный код. например, если я позвоню addTo: assertType: так:

a := MyObject new.
a addTo:  'foo: a boo:b baz: c
    ^(a*b+c)'
assertType: #(SmallInteger SmallInteger SmallInteger).

Я ожидаю, что смогу написать позже:

answer := (a foo: 2 boo: 5 baz: 10). 

и получить 20 в answer. и если я напишу:

a foo: 'someString' boo: 5 baz: 10.

Я получу правильное сообщение, потому что 'someString' не является SmallInteger.

Я знаю, как написать код проверки типа, и я знаю, что добавитьметод к классу во время выполнения я могу использовать метод 'compile' из класса Behavior.

проблема в том, что я хочу добавить код проверки типа в исходный код. Я не очень знаком со всеми классами писка, поэтому я не уверен, что лучше отредактировать aCodeString как строку внутри addTo: assertType:, а затем использовать compile: (и я не знаю , как), или есть способ внедрить код в существующий метод класса Behavior или другого скриптового класса.

В общем, я спрашиваю, как я могу вставить строку всуществующей строки или для вставки кода в существующий метод.

1 Ответ

3 голосов
/ 12 декабря 2019

Существует множество способов выполнить такую ​​проверку типов ...

Один из предлагаемых вами вариантов - изменить исходный код (строку) для вставки дополнительных проверок типов предварительных условий.

Ключевым моментом этого подхода является то, что вам придется вставить проверку типа в нужном месте. Это означает, что необходимо каким-то образом проанализировать исходный источник (или, по крайней мере, селектор и аргументы), чтобы найти его точный диапазон (и имена аргументов).

См. Метод 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) на этапе генерации. Таким образом, также возможно напрямую манипулировать инструкциями байт-кода путем правильного взлома на этом этапе ... Я почти уверен, что мы можем найти примеры использования. Вероятно, самая продвинутая техника.

...