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