parser

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

 

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

Ответ

G_Z 30.11.2019 03:41 / 30.11.2019 03:44

Второй метод работает со странностями. Если указать key:
То в результате поедут ключи
Это из-за перекрытия имени переменной именем, переданным в аргументах.
Исправляется более уникальными именами на ключ-значение:
^hash.foreach[key;value]{
—>
^hash.foreach[_key;_value]{
Пересечение всё равно не исключено, конечно, но уже менее вероятно.
И вторая - если метод ничего не находит - он возвращает ключи с которых были хэши
Я это вылечил проверкой что из рекурсии что-то пришло
Да, правильно.

Исправленные методы:
@select[hash;key_name;value_name;condition;options][locals]
$result[^hash::create[]]

$recursive(^options.recursive.bool(false))
$index(0)

^hash.foreach[_key;_value]{
	^if($_value is hash && $recursive){
		^result.add[^select[$_value;$key_name;$value_name]{
			$caller.$key_name[$$key_name]
			$caller.$value_name[$$value_name]

			$condition
		}[$options]]
	}{
		$caller.$key_name[$_key]
		$caller.$value_name[$_value]

		^if($condition){
			^result.add[^hash.at($index)[hash]]
		}
	}

	^index.inc[]
}


@select[hash;key_name;value_name;condition;options][locals]
$result[^hash::create[]]

$recursive(^options.recursive.bool(false))
$index(0)

^hash.foreach[_key;_value]{
	^if($_value is hash && $recursive){
		$selected[^select[$_value;$key_name;$value_name]{
			$caller.$key_name[$$key_name]
			$caller.$value_name[$$value_name]

			$condition
		}[$options]]

		^if($selected){
			$selected[$.$_key[$selected]]
		}
	}{
		$caller.$key_name[$_key]
		$caller.$value_name[$_value]

		^if($condition){
			$selected[^hash.at($index)[hash]]
		}
	}

	^result.add[$selected]

	^index.inc[]
}
Эту конструкцию
$caller.$key_name[$$key_name]
Я не пойму наверное никогда
Распишу подробно, может кому пригодится.

Это установка локальной переменной, только с хитростью для рекурсии.

$condition работает в контексте того метода, который вызвал @select (в примере это @main[]).
Значит @select'у нужно с любого уровня рекурсии установить локальные переменные с ключом и значением в вызывающем методе.

Например:
@main[]
^select[
	$.a[
		$.b(2)
	]
][key;value]($value == 2)
Для $.a отработает первая ветка if'а (для рекурсивного случая) и метод позовёт сам себя.
Но предварительно мы оборачиваем $condition в ещё один junction, контекстом которого будет первый @select (@main[] (0) —> @select[] (1)).

Вот рекурсивный вызов для $.b (@main[] (0) —> @select[] (1) —> @select[] (2)).
Значением не является хэш, рекурсии нет, отрабатывает вторая ветка if'а для «плоского» случая.

Сначала в $caller (@select[] (1)) мы установим локальные переменные:
$caller.$key_name[$_key]
$caller.$value_name[$_value]
Там будут [1]:
$key[b]
$value[2]
Но контекст $condition@main[] (0), нужно пойти выше к нему, фактически в $caller.caller, и установить key-value там, но ведь у нас рекурсия, а значит глубину мы не знаем.
Код $condition($value == 2) будет выполняться в контексте @main[] (0), а там этих переменных ещё нет.

Срабатывает junction-обёртка из @select[] (1):
{
	$caller.$key_name[$$key_name]
	$caller.$value_name[$$value_name]
	
	$condition
}
Контекст junction-обёртки — @select[] (1), в котором есть нужные переменные (#1).
А $caller для @select[] (1)@main[] (0), который нам и нужен.
$key_name[key]
$value_name[value]

$$key_name   —> $key
$$value_name —> $value
Таким образом, установим в @main[] (псевдокод, до точки — метод-контекст):
$main.key[$local.key]
$main.value[$local.value]
и получим в @main[] (0):
$key[b]
$value[2]
После чего, код $condition($value == 2) в контексте @main[] (0) успешно отработает и вернёт true.

То есть, это комбинация трёх «трюков»:
1. установки локальных переменных вызывающим методам через $caller ($caller.var[…]);
2. обёртка junction-code с одним контекстом в junction-code с другим контекстом ({$code});
3. доступ к переменной по имени, находящемуся в переменной ($$var).

Пока писал, аж сам понял!