parser

Написать ответ на текущее сообщение

 

 
   команды управления поиском

Ответ

G_Z 02.12.2019 03:32 / 02.12.2019 03:36

Имхо, тогда уж что-нибудь совсем маловероятное, типа _key_149571943;_value_149571943, т.к. _key и _value все таки применяются, а ошибку эту не зная ее природы фиг найдешь, если ключи совпали.
Против этого должна помочь передача $caller'а в опциях (ниже пример; это и в целом упрощает код).
Тогда переменные не будут устанавливаться вызвавшему рекурсивно @select'у, а сразу в метод, из которого был первый вызов.
Почему понятно, $condition в ветке с рекурсией мы не проверяем, а просто прокидываем вглубь. Поэтому ключи, в которых не значения, а вложенные хэши мы просто пропускаем. Если проверить $condition до рекурсии, то мы получим ошибку несовпадения типов $value, в общем случае
^json:string[^select[$hash][key;value]($key eq 'b' && $value == '3')
Условие $value == '3' — странное.
Логичнее $value == 3, и оно будет выполняться для вложенного хэша с тремя ключами.
Либо $value eq '3', которое завершится исключением при попадании в значение чего-либо, неприводимого к строке.
Упадет, когда в ключе окажется хэш
В ключе не может быть хэша, только в значении.
Ключ всегда строка.

Если требуется проверять и ключ и значение, то да — сразу идти в рекурсию нельзя, сначала нужно проверить ключ.
И да, в значение может попасть хэш.
И не только он, а объект любого типа, в том числе объект пользовательского класса.

В общем случае можно ограничить сравнение прямо в выражении:
($key eq 'b' && $value is string && $value eq '3')
Но в целом лучше продумать требования к подобным случаям.
Можно, к примеру, сбрасывать $value в void при попадании туда данных нежелательных типов.

Пример исправленного метода «плоского» результата.
@select[hash;key_name;value_name;condition;options][locals]
$result[^hash::create[]]

$recursive(^options.recursive.bool(false))
^if(def $options.caller){
	$_caller[$options.caller]
}{
	$_caller[$caller.self]
}

$index(0)

^hash.foreach[_key;_value]{
	$_caller.$key_name[$_key]
	$_caller.$value_name[$_value]

	^if($condition){
		^result.add[^hash.at($index)[hash]]
	}($_value is hash && $recursive){
		^result.add[^select[$_value;$key_name;$value_name]($condition)[
			^hash::create[$options]
			$.caller[$caller.self]
		]]
	}

	^index.inc[]
}
P. S. А ещё в хэше могут быть рекурсивные ссылки на любой ключ, в том числе на сам хэш.
Обход такого хэша приведёт к зацикливанию.