Допустим, у нас есть язык, поддерживающий такой синтаксис:
scalar = MyScalarType arg1 arg2
vector = @MyScalarType
arg11 arg12
arg21 arg22
Если непонятно, то во втором случае создаётся массив из трёх элементов типа "MyScalarType" и для каждого элемента вызывается конструктор с двумя аргументами argXY. Такой вот синтаксический сахар для объявления разного рода гомогенных таблиц и матриц, чтобы не дублировать имя типа. Для скалярного случая у нас получается такое дерево:
Binding()
> Id()
> Instance
>> Type()
>> Arg()
>> Arg()
Для векторного,
если делать в лоб, то
Binding()
> Id()
> ArrayInstance()
>> Type()
>> ArrayElementInstance()
>>> Arg()
>>> Arg()
>>> Arg()
>> ArrayElementInstance()
>>> Arg()
>>> Arg()
Это ведёт к избыточному коду в кодогенераторе, потому что
Instance() и
ArrayElementInstance() суть одно и то же, только во втором случае тип у нас объявлен неявно. И в идеале во втором случае хочется получить такое дерево:
Binding()
> Id()
> ArrayInstance()
>> Type()
>> Instance()
>>> Type()
>>> Arg()
>>> Arg()
>> Instance()
>>> Type()
>>> Arg()
>>> Arg()
И вопрос в том, как передать тип элементов вниз по дереву?
У меня в голове несколько идей:
Создать общий тип узла конструктора TypedInstance(), извлекать информацию о типе и передавать её в Instance(). При этом ни Instance(), ни ArrayInstance() не добавляются в дереве, а участвуют только в разборе.
Скалярное построение оставить как есть, а при разборе вектороного объявления создавать искусственные узлы на вершине стека, передавая туда информацию о типе.
Сделать наличие типа для Instance() опциональным, и передавать тип вниз на этапе кодогенерации.
Но все кажутся какими-то уродливыми. Может кто-то занимался написанием компиляторов или интерпретаторов и подскажет, есть ли стандартное, красивое решение для этой задачи?