Максим Витальевич решил изучить новый язык программирования. Один его знакомый порекомендовал изучить язык Rust, так как он самый перспективный. Да, язык действительно воодушевляет, но заставляет столкнуться с суровой реальностью — великим и могучим borrow checker.
Сказать, что Максим Витальевич был в некоторой растерянности, это ничего не сказать. Чтобы выйти из данной ситуации и разобраться с borrow checker, Максим Витальевич решил упростить язык.
Новый язык поддерживает только заранее определенный набор функций. Всего в языке доступно $$$n$$$ функций, описание каждой имеет следующий синтаксис:
<char> := "a" | "b" | ... | "z"
<name> := <char> | <char> <name>
<nameOrRefName> := <name> | "&" <name>
<argument> := <nameOrRefName>
<arguments> := <argument> | <argument> ", " <arguments>
<functionName> := <nameOrRefName>
<functionArguments> := "" | <arguments>
<function> := "fn " <functionName> "(" <functionArguments> ")"
Таким образом, <function> является описанием функции. Можно заметить, что имя функции может быть как «name», так и «&name». В первом случае, функция возвращает значение, во втором случае — ссылку. Примеры корректных функций:
fn input() // Функция input, возвращает значение и не содержит аргументов.
fn sum(a, b) // Функция sum, возвращает значение и принимает два аргумента по значению.
fn add(&a, &b) // Функция add, возвращает значение и принимает аргументы по ссылке.
fn &ref(a) // Функция ref, возвращает ссылку и принимает аргумент по значению.
fn assign(a, &b) // Функция assign, возвращает значение и принимает первый аргумент
// по значению, а второй по ссылке.
Приведем также некорректные примеры (такие примеры не могут встречаться во входных данных):
&fn funcd() // Неверный порядок символов.
fn funcb(a, b&) // Неверный порядок символов.
fn funcc(&&a) // Нельзя получить ссылку на ссылку.
fn &&funca() // Нельзя вернуть ссылку на ссылку.
fn fn() // Используется fn в качестве имени.
fn funce(fn) // Используется fn в качестве имени.
fn funcf(a, a) // Одинаковые имена аргументов.
fn funcg(a, &a) // Одинаковые имена аргументов.
Чтобы реализовать некоторую программу, в языке доступна конструкция «<declare>» — объявление новой переменной (или ссылки). Можно описать синтаксис следующим образом:
<callArguments> := <expression> | <expression> ", " <callArguments>
<functionCallArguments> := "" | <callArguments>
<functionCall> := <name> "(" <functionCallArguments> ")"
<expression> := <nameOrRefName> | <functionCall>
<declare> := <name> " := " <expression>
Приведем корректные примеры использования конструкции:
a := input() // Определяем переменную со значением результата input().
b := input()
c := a // Приcваиваем новой переменной старое значение.
d := add(&b, &c) // Вызываем функцию с передачей аргументов по ссылке.
e := add(ref(b), ref(c))
f := &e
Приведем некорректные примеры использования конструкции (такие примеры не могут встречаться во входных данных):
a := &input() // Нельзя получить ссылку на результат функции.
fn := a // Нельзя использовать fn в качестве имени.
&b := c // Нельзя объявлять имя-ссылку.
Максим Витальевич считает, что такой синтаксис довольно простой, поэтому синтаксических ошибок при использовании языка он допустить не может.
Однако Максим Витальевич может допустить следующие ошибки:
Последний пункт рассмотрим поподробнее. В языке Максима Витальевича предусмотрен собственный механизм borrow checker. Суть заключается в том, что все переменные, которые используются по значению, перемещаются и перестают быть доступными. Рассмотрим следующий пример:
a := input() // a является значением.
b := sum(a, a) // Ошибка!
В этом случае переменная «a» передается по значению 2 раза, однако после первого же использования она перестает быть доступна, таким образом возникает ошибка. В то же время:
a := input() // a является значением.
b := sum(&a, &a) // Корректно, если sum принимает ссылки. Переменная a
// остается доступной, так как не была использована по значению.
После объявления переменной с тем же именем (:=), старая переменная (если она является значением) считается перемещенной и перестает быть доступной начиная со следующей строки.
Для ссылок действуют следующие правила:
Рассмотрим следующие примеры:
a := input()
b := a
c := &a // Ошибка, переменная a была перемещена.
a := input()
b := &a
c := move(a) // Аналогично c := a. В любом случае переменная a перемещается.
d := b // Ошибка, переменная b является ссылкой на значение a, которое было перемещено.
a := input()
b := &a
c := call(a, b) // Ошибка. Переменная a была перемещена, поэтому ссылку использовать нельзя.
a := input()
b := &a
a := a // Старое значение переменной a перемещено.
c := clone(b) // Ошибка, переменная b ссылается на старую переменную a, которая
// была перемещена в предыдущей строке.
Так как Максим Витальевич придумал язык и хочет его использовать, он просит вас реализовать программу, которая будет проверять код Максима Витальевича на наличие ошибок.
В первой строке задано число $$$n$$$ — количетсво функций.
В следующих $$$n$$$ строках заданы описания функций в соответсвии с описанным синтаксисом. Гарантируется, что все имена функций уникальны, и все имена аргументов у каждой функции так же уникальны.
В следующей строке задано число $$$m$$$ — количество строк в коде Максима Витальевича.
В следующих $$$m$$$ строках заданы конструкции объявления новой переменной в соответсвии с описанием синтаксиса.
Гарантируется, что суммарная длина строк не превышает $$$100\,000$$$. Во входных данных не содержится лишних пробелов, а также не может быть пробелов меньше, чем описано в синтаксисе языка.
$$$$$$ 1 \le n \le 20 $$$$$$ $$$$$$ 1 \le m \le 100 $$$$$$
В единственной строке выведите «Valid», если программа является корректной.
В противном случае выведите «Error in line N» (без кавычек), где N — номер первой строки с ошибкой в коде Максима Витальевича.
Нумерация строк начинается с $$$1$$$.
3 fn input() fn clone(&a) fn sum(a, b) 5 a := input() b := input() br := &b s := sum(a, b) bc := clone(br)
Error in line 5
2 fn input() fn clone(&a) 3 a := input() a := &a b := clone(a)
Error in line 3
2 fn &input() fn sum(&a, &b) 3 a := input() b := sum(a, a) c := sum(a, &b)
Valid
В первом тестовом примере в пятой строке используется ссылка «br» на перемещенное в четвертой строке значение.
Во втором тестовом примере в третей строке используется значение переменной «a», однако она уже была перемещена в предыдущей строке.