Проверка инвариантов
Проверка описанных инвариантов для каждой операции осуществляется путем
обхода дерева операций и вызова реализованных для каждой операции
функций вида verify<OpType>(OpType op), где OpType – класс-адаптер
для конкретной операции. Эти функции, в свою очередь, выполняют
последовательность вызовов методов-характеризаторов, а также могут иметь
какую-либо дополнительную логику проверки. Характеризатор представляет
из себя класс, пример которого приведен ниже.
struct HasOperands {
static bool verify(const Operation::Ptr &op, SemantizerContext &ctx, size_t numOperands);
};
Вызов указанных методов, в свою очередь, осуществляется не напрямую, а с
помощью вспомогательного класса TraitVerifier.
class TraitVerifier {
public:
TraitVerifier(const Operation::Ptr &op, SemantizerContext &ctx) : op(op), ctx(ctx), acc(true){};
bool verified() const;
template <typename Trait, typename... Args>
TraitVerifier &verify(Args... args);
};
Этот класс позволяет строить цепочки проверок следующего вида, что дает возможность не выполнять проверки после того, как одна из них в цепочке была провалена:
verifier.verify<HasOperands>(0)
.verify<HasResults>(0)
.verify<HasAttributes>(2)
.verify<HasNthAttrOfType<std::string>>(0)
.verify<HasNthAttrOfType<FunctionType>>(1);