Хотел бы обрисовать некоторую канву для понимания, чего я хочу.

Сейчас мне нужно наполнить окружение Ada 95 библиотеками, сделанными как мне удобно.

Это сильные ссылки, сделанные правильно.

Правильность можно увидеть здесь на 134ой строке.

      ----------------------------
-- Sample_Referenced.Plus --
----------------------------

function Plus
(Left : access Sample_Referenced;
Right : Sample_Reference'Class)
return Sample_Limited_Reference
is
Right_Access : constant Sample_Access := Operations.Get (Right);
begin
return Create (Left.Value_Field + Right_Access.Value_Field);
end Plus;


То чувство, когда OSDN поддерживает адский синтаксис, а собственный форум — нет



Во многих других реализациях здесь всё ссылки будут голыми, но в правильной обнажается только одна, Left : access Sample_Referenced, или часто это будет «Object», по которой производится диспетчеризация. И результат тоже не голый. Соответственно, обёртки, реализующие сильную ссылку, обнажают только один указатель, а не все.

При помощи таких ссылок мне понадобятся сначала потоки. Абстрактный поток и одна реализация, которая заворачивает Ada.Streams.Stream_IO.File_Type. Деструктор этой реализации должен закрывать File_Type.

Чтобы такой поток можно было применять со стандартными адскими встроенными атрибутами, понадобится обёртка, заворачивающая сильную ссылку (по идее, ничего не стоит, кроме +1 указателя-тега) и делегирующую ей вызовы своих методов. Ещё будет полезно сделать более легковесную обёртку, с access дискриминантом на сильную ссылку, и тоже с делегацией. Это должно решить все вопросы интеграции с другим адским кодом.

Поверх потоков делается аналог http://docwiki.embarcadero.com/Libraries/R…ses.TTextReader и его потомок TStreamReader, декодирующий UTF-8. Всё с использованием сильных ссылок. То есть, Stream_Reader заключает в себе сильную ссылку на Stream.

Соглашение об именовании: сильные ссылки (обёртки) называются как-нибудь попроще, например, Text_Reader, а в названии реализации есть суффикс _Referenced, например, Text_Reader_Referenced.

Sample_Reference / Sample_Referenced в примере не соответствуют этому соглашению. По этому правилу следовало бы назвать Sample / Sample_Referenced, но вот не стал.

Про Юникод: Ada 95 не поддерживает UTF-32 нативно, то есть, литералы такие писать нельзя так просто, но всё равно должен быть UTF-32. У меня есть частичная реализация UTF-32 для AdaMagic, где Wide_Wide_Character объявлен как новый численный тип. Не знаю, как ещё сделать тип, который видим извне как перечисляемый, то есть, в for, case и in работает. Если требуется написать литерал, это может выглядеть так: Wide_Wide_Character'Val (Wide_Character'Pos ('(')). Увы. Для текстовых строк, может быть, придётся сделать генератор выражений типа Wide_Wide_Character'Val (34), Wide_Wide_Character'Val (65), … GNAT, будучи совместимым с Ada 95, поддерживает UTF-32 как-то так, и мы тоже справимся.


Дальше начинается интересное. Получив абстрактный Text_Reader, я бы хотел иметь возможность сохранять точки останова парсера. Точка останова — это, грубо, позиция в тексте. Но на эту точку останова навешены события при уничтожении. Точка останова даёт возможность читать текст с сохранённой позиции снова и снова. Это возможно за счёт того, что есть некий буфер, и этот буфер отслеживает, где есть точки останова, например, сбалансированным деревом. Если какой-то чтец забегает вперёд, то новые данные подгружаются из Text_Reader и добавляются в буфер, и отдаются чтецу.

Это примерно похоже на интерфейс парсер-комбинаторов:
String → (Type, String)

То есть, парсер-комбинатор берёт на вход недочитанную строку, пытается прочитать из неё то, что умеет читать, и возвращает пару из прочитанного значения типа Type, и String с тем, что осталось.

Например, жадное чтение числового литерала сработает так: "123, abc, …" → (123, ", abc, …")

Точки останова, которые я хочу, чтобы были — это как раз String на входе и на выходе. В Haskell String — это ленивый список символов, в нашем случае это «буфер+Text_Reader+облако точек останова».

Когда точки останова уничтожаются, текст, который остался позади, можно выбросить. Не знаю, получится ли, но хотелось бы попытаться писать так, чтобы точка останова в начале файла не висела в памяти до победного, а освобождалась как можно раньше, и так по всему или почти по всему коду. Например, в программном интерфейсе это может выражаться в том, что процедуры, читающие отдельные блоки, принимают на вход точку останова не в режиме in, а в режиме in out с возможностью уничтожения как только стало понятно, что в данном конкретном месте может сработать только этот конкретный блок и никакой другой. Например, в C, если прочитано "void something (void) {", то после "{" уже точно понятно, что это процедура.

Есть ещё идея поверх Text_Reader сделать лексер, чтоб производил поток лексем, и точки останова уже в потоке лексем, а не потоке UTF-32 символов оставлять.

Задача не предполагает написания кода. Ознакомление и дискуссия