Skip to content

Instantly share code, notes, and snippets.

@neworderofjamie
Created February 29, 2024 10:40
Show Gist options
  • Save neworderofjamie/f8903409eb03ea3ded0ac1e9064131e0 to your computer and use it in GitHub Desktop.
Save neworderofjamie/f8903409eb03ea3ded0ac1e9064131e0 to your computer and use it in GitHub Desktop.
#include <iostream>
#include <memory>
#include <string>
#include <vector>
// Forward declarations
class NoAnnotation;
template<typename A = NoAnnotation>
class Literal;
template<typename A = NoAnnotation>
class Binary;
class NoAnnotation
{
};
class TypeAnnotation
{
public:
TypeAnnotation(const std::string &type) : m_Type(type)
{}
const std::string &getType() const{ return m_Type; }
private:
std::string m_Type;
};
// Visitor
template<typename A = NoAnnotation>
class Visitor
{
public:
virtual void visit(const Binary<A> &binary) = 0;
virtual void visit(const Literal<A> &literal) = 0;
};
//---------------------------------------------------------------------------
// GeNN::Transpiler::Expression::Base
//---------------------------------------------------------------------------
template<typename A = NoAnnotation>
class Base : public A
{
public:
using A::A;
virtual void accept(Visitor<A> &visitor) const = 0;
};
//---------------------------------------------------------------------------
// GeNN::Transpiler::Expression::Acceptable
//---------------------------------------------------------------------------
template<typename T, typename A = NoAnnotation>
class Acceptable : public Base<A>
{
public:
using Base<A>::Base;
virtual void accept(Visitor<A> &visitor) const final
{
visitor.visit(static_cast<const T&>(*this));
}
};
template<typename A = NoAnnotation>
using ExpressionPtr = std::unique_ptr<Base<A> const> ;
template<typename A = NoAnnotation>
using ExpressionList = std::vector<ExpressionPtr<A>>;
//---------------------------------------------------------------------------
// GeNN::Transpiler::Expression::Binary
//---------------------------------------------------------------------------
template<typename A>
class Binary : public Acceptable<Binary<A>, A>
{
public:
template<typename... PolicyArgs>
Binary(ExpressionPtr<A> left, ExpressionPtr<A> right, PolicyArgs&&... policyArgs)
: Acceptable<Binary<A>, A>(std::forward<PolicyArgs>(policyArgs)...), m_Left(std::move(left)), m_Right(std::move(right))
{}
const Base<A> *getLeft() const { return m_Left.get(); }
const Base<A> *getRight() const { return m_Right.get(); }
private:
ExpressionPtr<A> m_Left;
ExpressionPtr<A> m_Right;
};
//---------------------------------------------------------------------------
// GeNN::Transpiler::Expression::Literal
//---------------------------------------------------------------------------
template<typename A>
class Literal : public Acceptable<Literal<A>, A>
{
public:
template<typename... PolicyArgs>
Literal(int value, PolicyArgs&&... policyArgs)
: Acceptable<Literal<A>, A>(std::forward<PolicyArgs>(policyArgs)...), m_Value(value)
{}
int getValue() const { return m_Value; }
private:
int m_Value;
};
class TestVisitor : public Visitor<>
{
public:
virtual void visit(const Binary<> &binary)
{
std::cout << "Visiting binary" << std::endl;
binary.getLeft()->accept(*this);
binary.getRight()->accept(*this);
}
virtual void visit(const Literal<> &literal)
{
std::cout << "Visiting literal value:" << literal.getValue() << std::endl;
}
};
class AnnotatingVisitor : public Visitor<>
{
public:
virtual void visit(const Binary<> &binary)
{
std::cout << "Annotating binary" << std::endl;
binary.getLeft()->accept(*this);
auto leftExpression = std::move(m_CurrentExpression);
binary.getRight()->accept(*this);
auto rightExpression = std::move(m_CurrentExpression);
m_CurrentExpression = std::make_unique<Binary<TypeAnnotation>>(std::move(leftExpression), std::move(rightExpression), "int");
}
virtual void visit(const Literal<> &literal)
{
std::cout << "Annotating literal" << std::endl;
m_CurrentExpression = std::make_unique<Literal<TypeAnnotation>>(literal.getValue(), "int");
}
ExpressionPtr<TypeAnnotation> annotate(const Base<> *expression)
{
expression->accept(*this);
return std::move(m_CurrentExpression);
}
private:
ExpressionPtr<TypeAnnotation> m_CurrentExpression;
};
class TypeVisitor : public Visitor<TypeAnnotation>
{
public:
virtual void visit(const Binary<TypeAnnotation> &binary)
{
std::cout << "Visiting binary (" << binary.getType() << ")" << std::endl;
binary.getLeft()->accept(*this);
binary.getRight()->accept(*this);
}
virtual void visit(const Literal<TypeAnnotation> &literal)
{
std::cout << "Visiting literal value:" << literal.getValue() << "(" << literal.getType() << ")" << std::endl;
}
};
int main()
{
auto a = std::make_unique<Literal<>>(1);
auto b = std::make_unique<Literal<>>(2);
auto c = std::make_unique<Binary<>>(std::move(a), std::move(b));
TestVisitor visitor;
c->accept(visitor);
AnnotatingVisitor annotator;
auto annotated = annotator.annotate(c.get());
TypeVisitor typeVisitor;
annotated->accept(typeVisitor);
/*{
auto a = std::make_unique<Literal<TypeAnnotation>>(1, "int");
auto b = std::make_unique<Literal<TypeAnnotation>>(2, "int");
auto c = std::make_unique<Binary<TypeAnnotation>>(std::move(a), std::move(b), "int");
TypeVisitor visitor;
visitor.visit(*c);
}*/
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment