Yume
crtp_walker.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "ast/ast.hpp"
4#include <llvm/Support/Casting.h>
5#include <type_traits>
6
7namespace yume {
8
9template <typename T>
10concept OnlyStmt = std::derived_from<T, ast::Stmt> && !std::derived_from<T, ast::Expr>;
11
12/// A helper template to walk the Abstract Syntax Tree (AST), utilizing the Curiously Recurring Template Pattern (CRTP).
13/**
14 * A class inheriting from `CRTPWalker` must declare the methods `body_expression` and `body_statement`, which take the
15 * base classes `Expr` and `Stmt` respectively. Those methods should delegate to the same methods defined in the
16 * `CRTPWalker`.
17 * Then, the class must define any number of template methods named `expression` and `statement`, which take a subclass
18 * of `Expr` and `Stmt` respectively. The way this is done in `Compiler` and `TypeWalker` is to define a template base
19 * in the header, with a fallback implementation (which should usually throw) for any cases that are unhandled. Then,
20 * for each AST node subclass that the deriving class knows how to handle, define a template specialization taking that
21 * specific subclass in the implementation file.
22 */
23template <typename Derived> struct CRTPWalker {
24
25public:
26 auto body_statement(ast::Stmt& stat, auto&&... args) {
27 auto kind = stat.kind();
28 switch (kind) {
29 case ast::K_Compound: return conv_statement<ast::Compound>(stat, args...);
30 case ast::K_While: return conv_statement<ast::WhileStmt>(stat, args...);
31 case ast::K_If: return conv_statement<ast::IfStmt>(stat, args...);
32 case ast::K_Return: return conv_statement<ast::ReturnStmt>(stat, args...);
33 case ast::K_VarDecl: return conv_statement<ast::VarDecl>(stat, args...);
34 case ast::K_ConstDecl: return conv_statement<ast::ConstDecl>(stat, args...);
35 case ast::K_FnDecl: return conv_statement<ast::FnDecl>(stat, args...);
36 case ast::K_StructDecl: return conv_statement<ast::StructDecl>(stat, args...);
37 case ast::K_CtorDecl: return conv_statement<ast::CtorDecl>(stat, args...);
38 default: (static_cast<Derived*>(this))->body_expression(llvm::cast<ast::Expr>(stat), args...);
39 }
40 }
41
42 auto body_expression(ast::Expr& expr, auto&&... args) {
43 auto kind = expr.kind();
44 switch (kind) {
45 case ast::K_Number: return conv_expression<ast::NumberExpr>(expr, args...);
46 case ast::K_String: return conv_expression<ast::StringExpr>(expr, args...);
47 case ast::K_Char: return conv_expression<ast::CharExpr>(expr, args...);
48 case ast::K_Bool: return conv_expression<ast::BoolExpr>(expr, args...);
49 case ast::K_Call: return conv_expression<ast::CallExpr>(expr, args...);
50 case ast::K_BinaryLogic: return conv_expression<ast::BinaryLogicExpr>(expr, args...);
51 case ast::K_Var: return conv_expression<ast::VarExpr>(expr, args...);
52 case ast::K_Const: return conv_expression<ast::ConstExpr>(expr, args...);
53 case ast::K_Lambda: return conv_expression<ast::LambdaExpr>(expr, args...);
54 case ast::K_Assign: return conv_expression<ast::AssignExpr>(expr, args...);
55 case ast::K_Ctor: return conv_expression<ast::CtorExpr>(expr, args...);
56 // case ast::K_Dtor: return conv_expression<ast::DtorExpr>(expr, args...);
57 case ast::K_Slice: return conv_expression<ast::SliceExpr>(expr, args...);
58 case ast::K_FieldAccess: return conv_expression<ast::FieldAccessExpr>(expr, args...);
59 case ast::K_ImplicitCast: return conv_expression<ast::ImplicitCastExpr>(expr, args...);
60 case ast::K_TypeExpr: return conv_expression<ast::TypeExpr>(expr, args...);
61 default: return (static_cast<Derived*>(this))->template expression(expr, args...);
62 }
63 }
64
65private:
66 template <std::derived_from<ast::Expr> T> auto conv_expression(ast::Expr& expr, auto... args) {
67 return (static_cast<Derived*>(this))->expression(llvm::cast<T>(expr), args...);
68 }
69
70 template <OnlyStmt T> void conv_statement(ast::Stmt& stat, auto... args) {
71 return (static_cast<Derived*>(this))->statement(llvm::cast<T>(stat), args...);
72 }
73};
74} // namespace yume
auto kind() const -> Kind
Definition: ast.hpp:272
Expressions have an associated value and type.
Definition: ast.hpp:438
Statements make up most things in source code.
Definition: ast.hpp:297
@ K_Bool
BoolExpr
Definition: ast.hpp:62
@ K_String
StringExpr
Definition: ast.hpp:63
@ K_If
IfStmt
Definition: ast.hpp:45
@ K_BinaryLogic
BinaryLogicExpr
Definition: ast.hpp:67
@ K_Assign
AssignExpr
Definition: ast.hpp:72
@ K_ConstDecl
ConstDecl
Definition: ast.hpp:55
@ K_Number
NumberExpr
Definition: ast.hpp:60
@ K_ImplicitCast
ImplicitCastExpr
Definition: ast.hpp:74
@ K_Slice
SliceExpr
Definition: ast.hpp:70
@ K_FieldAccess
FieldAccessExpr
Definition: ast.hpp:73
@ K_Var
VarExpr
Definition: ast.hpp:64
@ K_Call
CallExpr
Definition: ast.hpp:66
@ K_TypeExpr
TypeExpr
Definition: ast.hpp:75
@ K_Compound
Compound
Definition: ast.hpp:43
@ K_VarDecl
VarDecl
Definition: ast.hpp:54
@ K_Char
CharExpr
Definition: ast.hpp:61
@ K_Return
ReturnStmt
Definition: ast.hpp:46
@ K_FnDecl
FnDecl
Definition: ast.hpp:51
@ K_CtorDecl
CtorDecl
Definition: ast.hpp:52
@ K_While
WhileStmt
Definition: ast.hpp:44
@ K_Const
ConstExpr
Definition: ast.hpp:65
@ K_StructDecl
StructDecl
Definition: ast.hpp:53
@ K_Lambda
LambdaExpr
Definition: ast.hpp:71
@ K_Ctor
CtorExpr
Definition: ast.hpp:68
Definition: ast.cpp:8
A helper template to walk the Abstract Syntax Tree (AST), utilizing the Curiously Recurring Template ...
Definition: crtp_walker.hpp:23
auto body_statement(ast::Stmt &stat, auto &&... args)
Definition: crtp_walker.hpp:26
auto body_expression(ast::Expr &expr, auto &&... args)
Definition: crtp_walker.hpp:42