Оберон-клуб «ВЄДАsoft»

Твердыня модульных языков
Текущее время: 16 окт 2018, 01:47

Часовой пояс: UTC + 2 часа




Начать новую тему Ответить на тему  [ Сообщений: 11 ]  На страницу 1, 2  След.
Автор Сообщение
СообщениеДобавлено: 05 окт 2018, 21:52 
Не в сети

Сообщения: 240
Сейчас я наверняка по невежеству какой-нибудь бред сделаю. Но я хочу функцию S, которая для любого аргумента возвращает его строковое представление.

Только давайте сразу не будем тратить время на терминологические дискуссии. Я хочу функцию, подобную ENTIER или LONG, которая записывается одинаково, но принимает аргументы разных типов (не обязательно записи). Такую функцию можно назвать перегруженной, ad-hoc полиморфной, обобщённой, да хоть пирогом назвать. Главное, чтобы все понимали, о чём речь. Как её называть правильно - я не хочу обсуждать, т.к. это, во многом, вопрос клановой принадлежности.

По идее, если есть добровольцы, то можно этим заняться. Если нет, то я сейчас буду делать разведку, а потом попробую найти исполнителя за деньги. Такая функция нужна для REPL (цчвп).

По сути есть два подхода:

а) смотреть, как сделаны другие полиморфные функции.

В BlackBoxComponentBuilder уже есть полиморфные функции. Экзотическая среди них - ENTIER, которая вызывает примитив entierfn. Её хорошо изучать, т.к. она встречается в малом количестве мест. Ищем в исходниках и находим вот что:

Код: "OBERON"
  1.  
  2. MODULE DevCPB;
  3. ...
  4. entierfn = 5; (* задаётся код функции *)
  5. ...
  6. (** видимо, это - кусок компилятора *)
  7. | entierfn: (*ENTIER*)
  8. IF (x.class = Ntype) OR (x.class = Nproc) THEN err(126)
  9. ELSIF f IN realSet THEN Convert(x, DevCPT.int64typ)
  10. ELSE err(111)
  11. END ;
  12. x.typ := DevCPT.int64typ
  13.  


Код: "OBERON"
  1.  
  2. MODULE DevCPT;
  3. ...
  4. (* DRY заплакал - пусть плачет *)
  5. entierfn = 5;
  6. ...
  7. (** это похоже на регистрацию функции как известной компилятору *)
  8. EnterProc("ENTIER", entierfn);
  9.  

Вот и всё. Пока неясно, легко ли сделать функцию S из этого.

Вот нашёл баг (или не баг) про это: https://github.com/Oleg-N-Cher/OfrontPlus/issues/43 - ENTIER(ЛитералЧисла) всегда LONG.
Также нашёл описание компилятора, правда, там негусто. http://obertone.ru/bb/dev/cpt


Последний раз редактировалось budden 06 окт 2018, 17:37, всего редактировалось 1 раз.

Вернуться к началу
 Профиль  
Ответить с цитатой  
СообщениеДобавлено: 05 окт 2018, 22:01 
Не в сети

Сообщения: 240
Второй вариант: DevDebug умеет структурно показывать любую переменную, значит, он содержит нечто, достаточное для реализации функции S. Попробуем порыться.
Код: "OBERON"
  1.  
  2. DevDebug -
  3. (** Прекрасное начало *)
  4. PROCEDURE ShowGlobalVariables
  5. ShowGlobals
  6. // как-то получаем некую ссылку на переменную - это пока пропустим
  7. ShowVar
  8. // и тут идёт простыня с выбором по некоему f, которое, очевидно, кодирует тип. Это и
  9. // есть нужное нам тело ф-ии S. Осталось понять, как раздобыть f из компилятора и сгенерировать вызов ShowVar. Но не думаю, что это прямо просто.
  10.  


Вернуться к началу
 Профиль  
Ответить с цитатой  
СообщениеДобавлено: 05 окт 2018, 22:09 
Не в сети

Сообщения: 240
Где используется ShowVar?
StdDebug.ShowStack , DevDebug.ShowStack, DevDebug.ShowGlobals,
DevRtDebug.ShowStack, DevRTDebug.ShowGlobals, DevTypeLibs.ShowLibrary

Уффф. Теперь надо разбираться, можно ли вызвать какую-то функцию отладчика из самого кода, не из обработчика Trap и не из отладчика. И как это сделать (параметров очень много).


Вернуться к началу
 Профиль  
Ответить с цитатой  
СообщениеДобавлено: 05 окт 2018, 22:13 
Не в сети

Сообщения: 240
Теперь РТФМ. Заказные сбои. Вот что нам должно помочь. Хотя, может быть, полазить просто в ObxTrap.Do* ? Ну, недаром ящик чёрный. 13 и 777. ХОрошо хоть, не 666 (или это такой тонкий намёк, но прямо написать постеснялись?)
Код: "OBERON"
  1.  
  2. MODULE ю; IMPORT ObxTrap;
  3. PROCEDURE щ*;
  4. VAR ь:LONGINT;
  5. BEGIN
  6. ObxTrap.Do;
  7. END щ; END ю.
  8.  

так вызовем Trap. А где же обработчик? Он явно должен вызывать ShowStack. Этот, наверно: StdDebug.Trap?

И ещё вот что: Kernel.InstallTrapViewer(Trap)


Вернуться к началу
 Профиль  
Ответить с цитатой  
СообщениеДобавлено: 05 окт 2018, 23:45 
Не в сети

Сообщения: 240
Естественно, наивное
Код: "OBERON"
  1.  
  2. MODULE ю; IMPORT ObxTrap, DevDebug, TextModels, StdLog, Views ;
  3. PROCEDURE щ*;
  4. VAR ь:LONGINT; v: Views.View;
  5. BEGIN
  6. ь := 100500;
  7. (* ObxTrap.Do; *)
  8.  
  9. DevDebug.out.ConnectTo(
  10. TextModels.CloneOf(StdLog.buf));
  11. DevDebug.ShowStack;
  12.  
  13. DevDebug.OpenViewer(DevDebug.out.rider.Base(),
  14. "Ю", DevDebug.NewModRuler());
  15.  
  16. DevDebug.out.ConnectTo(NIL);
  17.  
  18. END щ; END ю.
  19.  
  20. (* "ю.щ()"
  21.  
  22. *)
  23.  

не сработало. Видимо, нужна какая-то ф-я, которая имитирует trap и проставляет осмысленные значения для переменных типа Kernel.fp. Подобная TrapHandler. Может быть, есть обработчики каких-то других прерываний. из которых можно взять эту инфу.

Но это всё - не то. Потому что S(2 + 2) имеет дело не с переменной, а с выражением. Это нужно решать на уровне компилятора, и только простыню с развязкой по типам нужно брать из ShowVar.


Вернуться к началу
 Профиль  
Ответить с цитатой  
СообщениеДобавлено: 05 окт 2018, 23:47 
Не в сети

Сообщения: 240
Итог темы на данный момент - придётся завести тему в "коммерческом использовании :) ". Или ещё покопаться. На самом деле, совершенно некогда. То, что я сейчас покопался - преступление против работодателей и семьи...


Вернуться к началу
 Профиль  
Ответить с цитатой  
СообщениеДобавлено: 08 окт 2018, 15:11 
Не в сети
Администратор
Аватара пользователя

Сообщения: 79
Бандит, пару часов покопался в Блэкбоксе. Да это же настоящее успокоение души :) Должно же быть место в жизни для хобби.


Вернуться к началу
 Профиль  
Ответить с цитатой  
СообщениеДобавлено: 12 окт 2018, 11:26 
Не в сети

Сообщения: 240
Но мне кажется, что я в полном тупике насчёт массивов. Для встроенных типов можно определить эн записей. А что делать с ARRAY OF T для произвольного T? В принципе-то, ситуация такая:
Код: "OBERON"
  1.  
  2. MODULE цчвп100500;
  3. TYPE Типчик = ARRAY OF НекаяЗапись;
  4. VAR Варвар: VARIANT;
  5. BEGIN
  6. Out.Anything(Выражение, возвращающее Типчик);
  7. Варвар := V(Выражение, возвращающее Типчик);
  8. END.
  9.  

Для печати мы можем сделать именно полиморфную функцию, которая читает экземпляр Типчик и превращает его в строку. Но вот записать типчик в Варвар я не вижу как. Потому что нужная для него запись должна быть где-то определена как:
Код: "OBERON"
  1.  
  2. TYPE ОбёрткаДляТипчика = RECORD
  3. Данные: POINTER TO Типчик;
  4. END;
  5.  

Здесь мы не обойдёмся никаким обобщённым
Код: "OBERON"
  1.  
  2. TYPE ОбёрткаДляЛюбогомассива = RECORD
  3. Данные: POINTER TO ANYARRAY;
  4. END;
  5.  

Ввиду несуществования типа ANYARRAY.
И чё делать теперь?


Вернуться к началу
 Профиль  
Ответить с цитатой  
СообщениеДобавлено: 12 окт 2018, 12:30 
Не в сети

Сообщения: 240
Можно, конечно, не отступать от изначальной цели. А цель у нас - не варианты, а полиморфные функции. Но на самом деле варианты тоже хочется.


Вернуться к началу
 Профиль  
Ответить с цитатой  
СообщениеДобавлено: 12 окт 2018, 17:55 
Не в сети

Сообщения: 240
Пока что вот до чего докопался на тему полиморфизма и массивов - русская документация на модуль Kernel, тип Block:
Код: "OBERON"
  1.  
  2. Block = POINTER TO RECORD [untagged]
  3. tag: Type;
  4. last: INTEGER; (* arrays: last element *)
  5. actual: INTEGER; (* arrays: used during mark phase *)
  6. first: INTEGER (* arrays: first element *)
  7. END;
  8.  

Цитата:
Поле tag располагается по смещению -4 от указателя на динамический объект. Для объектов-записей тег хранит адрес описателя типа Kernel.Type. Для объектов-массивов тег хранит адрес описателя базового элемента (для элементарных типов в ядре объявлены псевдоописатели, имеющие идентичный размер), к которому прибавляется бит {1} (т.е. выполняется побитовый OR с числом 2). Поскольку адреса описателей выровнены по смещению 4 и более байт, такая метка позволяет однозначно идентифицировать в памяти динамический объект, являющийся массивом.

Похоже, из этого следует, что можно создать тип ANYARRAY и даже ANYARRAY_OR_ANYREC. Единственное, мне тут не понравилось слово "динамического". Поскольку объект в теории (не знаю, как в ББЦБ) может быть размещён статически и на стеке, то это ещё не вся картина. Можно было бы попробовать положиться на сборщик мусора для анализа структуры кучи, но он консервативный, а значит, и он знает о памяти не всё, что нужно. Видимо, эта информация откроется не раньше, чем будет полностью понятен формат стека и структура "статической" памяти, если таковая есть.

Комбинируя статическую и динамическую информацию о типе, наверное, так можно создать и искомый вариант, только уж жить в эту пору прекрасную...


Вернуться к началу
 Профиль  
Ответить с цитатой  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 11 ]  На страницу 1, 2  След.

Часовой пояс: UTC + 2 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 2


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
cron
Создано на основе phpBB® Forum Software © phpBB Group
Тех.поддержка phpBB