llvm-journey

LLVM Journey
git clone git://0xff.ir/g/llvm-journey.git
Log | Files | Refs | README | LICENSE

kaleidoscope_ast.hpp (4421B)


      1 
      2 #pragma once
      3 
      4 #include <cassert>
      5 #include <memory>
      6 #include <string>
      7 #include <vector>
      8 
      9 namespace kal {
     10 
     11 struct Number;
     12 struct Variable;
     13 struct BinaryOp;
     14 struct Call;
     15 struct Prototype;
     16 struct Function;
     17 
     18 std::string
     19 to_string(const Number&);
     20 
     21 std::string
     22 to_string(const Variable&);
     23 
     24 std::string
     25 to_string(const BinaryOp&);
     26 
     27 std::string
     28 to_string(const Call&);
     29 
     30 std::string
     31 to_string(const Prototype&);
     32 
     33 std::string
     34 to_string(const Function&);
     35 
     36 //---
     37 
     38 enum class NodeType
     39 {
     40   None = -1,
     41   Number,
     42   Variable,
     43   BinaryOp,
     44   Call,
     45   Prototype,
     46   Function,
     47 };
     48 
     49 template<typename T>
     50 inline NodeType
     51 node_type(const T&)
     52 {
     53   return NodeType::None;
     54 }
     55 
     56 template<>
     57 inline NodeType
     58 node_type(const Number&)
     59 {
     60   return NodeType::Number;
     61 }
     62 
     63 template<>
     64 inline NodeType
     65 node_type(const Variable&)
     66 {
     67   return NodeType::Variable;
     68 }
     69 
     70 template<>
     71 inline NodeType
     72 node_type(const BinaryOp&)
     73 {
     74   return NodeType::BinaryOp;
     75 }
     76 
     77 template<>
     78 inline NodeType
     79 node_type(const Call&)
     80 {
     81   return NodeType::Call;
     82 }
     83 
     84 template<>
     85 inline NodeType
     86 node_type(const Prototype&)
     87 {
     88   return NodeType::Prototype;
     89 }
     90 
     91 template<>
     92 inline NodeType
     93 node_type(const Function&)
     94 {
     95   return NodeType::Function;
     96 }
     97 
     98 //---
     99 
    100 // https://youtu.be/QGcVXgEVMJg?t=49m13s
    101 class ASTNode
    102 {
    103 public:
    104   ASTNode() = default;
    105   ~ASTNode() = default;
    106 
    107   template<typename T>
    108   ASTNode(T value)
    109     : self_{ std::make_shared<Model<T>>(std::move(value)) }
    110   {}
    111 
    112   friend std::string to_string(const ASTNode& n)
    113   {
    114     assert(n.self_ != nullptr);
    115 
    116     return n.self_->to_string();
    117   }
    118 
    119   friend NodeType node_type(const ASTNode& n)
    120   {
    121     assert(n.self_ != nullptr);
    122 
    123     return n.self_->node_type();
    124   }
    125 
    126   template<typename T>
    127   friend bool cast(const ASTNode& n, T& val)
    128   {
    129     if (!n.self_)
    130       return false;
    131 
    132     auto p = dynamic_cast<const Model<T>*>(n.self_.get());
    133 
    134     if (p)
    135       val = p->value_;
    136 
    137     return p != nullptr;
    138   }
    139 
    140   friend bool operator==(const ASTNode& x, const ASTNode& y)
    141   {
    142     assert(x.self_ != nullptr && y.self_ != nullptr);
    143 
    144     return x.self_->to_string() == y.self_->to_string(); // FIXME
    145   }
    146 
    147   friend bool operator!=(const ASTNode& x, const ASTNode& y)
    148   {
    149     return !(x == y);
    150   }
    151 
    152 private:
    153   struct Concept
    154   {
    155     virtual ~Concept() = default;
    156     virtual std::string to_string(void) const = 0;
    157     virtual NodeType node_type(void) const = 0;
    158   };
    159 
    160   template<typename T>
    161   struct Model final : Concept
    162   {
    163     Model(T value)
    164       : value_(std::move(value))
    165     {}
    166 
    167     std::string to_string(void) const override
    168     {
    169       using kal::to_string; // FIXME
    170 
    171       return to_string(value_);
    172     }
    173 
    174     NodeType node_type(void) const override
    175     {
    176       using kal::node_type;
    177 
    178       return node_type(value_);
    179     }
    180 
    181     T value_;
    182   };
    183 
    184   std::shared_ptr<const Concept> self_;
    185 };
    186 
    187 template<typename T>
    188 bool
    189 cast(const ASTNode& n, T& val);
    190 
    191 struct Number
    192 {
    193   double value;
    194 
    195   friend bool operator==(const Number& x, const Number& y)
    196   {
    197     return x.value == y.value; // CHECKME floating-point eq?
    198   }
    199   friend bool operator!=(const Number& x, const Number& y) { return !(x == y); }
    200 };
    201 
    202 struct Variable
    203 {
    204   std::string name;
    205 
    206   friend bool operator==(const Variable& x, const Variable& y)
    207   {
    208     return x.name == y.name;
    209   }
    210   friend bool operator!=(const Variable& x, const Variable& y)
    211   {
    212     return !(x == y);
    213   }
    214 };
    215 
    216 struct BinaryOp
    217 {
    218   char op;
    219   ASTNode lhs;
    220   ASTNode rhs;
    221 
    222   friend bool operator==(const BinaryOp& x, const BinaryOp& y)
    223   {
    224     return x.op == y.op && x.lhs == x.rhs;
    225   }
    226   friend bool operator!=(const BinaryOp& x, const BinaryOp& y)
    227   {
    228     return !(x == y);
    229   }
    230 };
    231 
    232 struct Call
    233 {
    234   std::string callee;
    235   std::vector<ASTNode> args;
    236 
    237   friend bool operator==(const Call& x, const Call& y)
    238   {
    239     return x.callee == y.callee && x.args == y.args;
    240   }
    241   friend bool operator!=(const Call& x, const Call& y) { return !(x == y); }
    242 };
    243 
    244 struct Prototype
    245 {
    246   std::string name;
    247   std::vector<std::string> params;
    248 
    249   friend bool operator==(const Prototype& x, const Prototype& y)
    250   {
    251     return x.name == y.name && x.params == y.params;
    252   }
    253   friend bool operator!=(const Prototype& x, const Prototype& y)
    254   {
    255     return !(x == y);
    256   }
    257 };
    258 
    259 struct Function
    260 {
    261   Prototype proto;
    262   ASTNode body;
    263 
    264   friend bool operator==(const Function& x, const Function& y)
    265   {
    266     return x.proto == y.proto && x.body == y.body;
    267   }
    268   friend bool operator!=(const Function& x, const Function& y)
    269   {
    270     return !(x == y);
    271   }
    272 };
    273 
    274 } // namespace kal