На уровне пользователя самый простой подход — написать оболочку, похожую на замыкание, которая будет вызывать трассировочные хуки, которые вы предоставляете до и после вызова основного кода, и которая затем будет возвращать результат оценки.
Грубый набросок этой идеи красным цветом выглядит следующим образом:
frame-of: function [
func [function!]
/local
match
][
parse spec-of :func [
collect any [
set match [not quote return: all-word!] keep (to word! match)
| skip
]
]
]
report: function [frame [block!]][
environment: construct collect [forall frame [keep to set-word! frame/1]]
also environment set environment reduce frame
]
trace: function [
'target [word!]
enter [block!]
leave [block!]
][
chain: reduce [
'do enter
'set/any quote 'result 'do body-of get target
'do leave
quote :result
]
new: func spec-of get target chain
info: context [
frame: bind frame-of get target :new
name: target
result: none
]
bind body-of :new info
set target :new
exit
]
После этого вы сможете:
enter: [print ['entering name 'with mold/flat body-of report frame]]
leave: [print [name 'returned result]]
trace foo enter leave
trace bar enter leave
Что, для вашего примера, дает:
>> bar/ris 7 yyy
entering bar with [x: 7 ris: true var: 'yyy]
entering foo with [val1: 7 val2: 2 local: false temp: none]
foo returned 14
bar returned 22
== 22
Имейте в виду, что это всего лишь PoC. Основная идея заключается в том, что исходная функция заменяется инструментальной версией, созданной посредством замыкания некоторого внутреннего пространства имен с отладочной информацией. Вы также можете добавить в смесь немного Red/System, чтобы получить детальный доступ к информации о времени выполнения, например, например. оценочный стек.
Я оставляю красивую печать с отступом и отключением трассировки в качестве упражнения для читателя ;)
person
9214
schedule
23.03.2021