Вверх ↑
Ответов: 4628
Рейтинг: 749
#1: 2014-04-01 11:18:58 ЛС | профиль | цитата
GreM, в Hub добавлен такой контроль, ибо существует комбинация, при которой HiAsm уходит в безусловную рекурсию. На хабе это наиболее хорошо заметно, а именно:
- имеется хаб с несколькими входами и одним и более выходов
- подключить, например, кнопку к первому входу
- подключить любой из выходов хаба к любому другому входу
- скомпилировать, получим сообщение о недопустимости такого соединения. Теперь если в хабе убрать этот контроль, при компиляции HiAsm вырубится.

Более универсально определение проблемы: если у компонента есть несколько методов, которые вызывают одно и то же событие, то недопустимо из этого события вызывать любой из этих методов. Это справедливо даже если к событию подключено любое количество других компонентов, при условии, что в этих компонентах метод вызывает событие напрямую.
То-есть, такую защиту, как у хаба, придется ставить и в другие компоненты. Или зашить прямо в кодогенератор.

Ошибка не возникает (точнее, возникает редко), когда событие генерируется в методе Init() компонента (характерно для визуальных компонентов, и других, в которых "событие" возникает из системы, а не как реакция на вызов метода компонента).

Пример кода, приводящего к ошибке:


#hws
func doMethod1(_data)
...
event(MyEvent)
...
end
func doMethod2(_data)
...
event(MyEvent)
...
end
Возможная корректная реализация:


#hws
func Init()
fvar(old, tmp)

tmp = block.reggen()
old = block.select(tmp)

println('void ', my_test_method, '(){')
block.inclvl()
event(MyEvent)
block.declvl()
println('}')

MoveBlockTo(BLK_METHODS)
block.select(old)
end

func doMethod1(_data)
...
println(my_test_method, '();') // Здесь мы уже не вызываем событие кодогенератора, а заставляем в рантайм выполниться коду события, который был сгенерирован ранее
...
end
func doMethod2(_data)
...
println(my_test_method, '();')
...
end
Недостаток этого способа - сложно оптимально передать данные из потока "сквозь" компонент на событие, потому что у разных методов данные могут быть разных типов и код для их обработки требуется разный. Для решения этой проблемы мы используем класс Memory, который преобразовывает тип данных в runtime, что не очень оптимально с точки зрения производительности и контроля типов при кодогенерации. Хотя передавать неизменные данные со входа на выход требуется редко.

Ошибка может исчезать при перестановке компонентов. Я пока конкретно с этим не сталкивался, но ясно, что порядок инициализации компонентов влияет на порядок вызова методов-событий и может приводить к вполне работоспособным комбинациям.



карма: 26

1
Голосовали:GreM