Spicy
builder.h
1 // Copyright (c) 2020-2021 by the Zeek Project. See LICENSE for details.
2 
3 #pragma once
4 
5 #include <map>
6 #include <memory>
7 #include <string>
8 #include <utility>
9 #include <vector>
10 
11 #include <hilti/ast/builder/declaration.h>
12 #include <hilti/ast/builder/expression.h>
13 #include <hilti/ast/ctor.h>
14 #include <hilti/ast/statements/all.h>
15 
16 namespace hilti {
17 class Context;
18 } // namespace hilti
19 
20 namespace hilti::builder {
21 
22 class Builder {
23 public:
24  Builder(std::shared_ptr<hilti::Context> context)
25  : _context(std::move(context)), _our_block(statement::Block()), _block(*_our_block) {}
26 
27  Statement block() {
28  assert(_our_block);
29  return *_our_block;
30  }
31 
32  Expression addTmp(const std::string& prefix, const Expression& init);
33  Expression addTmp(const std::string& prefix, const Type& t, const std::vector<Expression>& args = {});
34  Expression addTmp(const std::string& prefix, const Type& t, const Expression& init);
35 
36  void addLocal(ID id, Type t, Meta m = Meta()) {
37  _block._add(builder::local(std::move(id), std::move(t), std::move(m)));
38  }
39 
40  void addLocal(ID id, Expression init, Meta m = Meta()) {
41  _block._add(builder::local(std::move(id), std::move(init), std::move(m)));
42  }
43 
44  void addLocal(ID id, Type t, Expression init, Meta m = Meta()) {
45  _block._add(builder::local(std::move(id), std::move(t), std::move(init), std::move(m)));
46  }
47 
48  void addLocal(ID id, Type t, std::vector<hilti::Expression> args, Meta m = Meta()) {
49  _block._add(builder::local(std::move(id), std::move(t), std::move(args), std::move(m)));
50  }
51 
52  void addExpression(const Expression& expr) { _block._add(statement::Expression(expr, expr.meta())); }
53 
54  void addAssert(Expression cond, std::string msg, Meta m = Meta()) {
55  _block._add(statement::Assert(std::move(cond), builder::string(std::move(msg)), std::move(m)));
56  }
57 
58  void addAssign(Expression dst, Expression src, const Meta& m = Meta()) {
59  _block._add(statement::Expression(builder::assign(std::move(dst), std::move(src), m), m));
60  }
61 
62  void addSumAssign(Expression dst, Expression src, const Meta& m = Meta()) {
63  _block._add(statement::Expression(builder::sumAssign(std::move(dst), std::move(src), m), m));
64  }
65 
66  void addAssign(ID dst, Expression src, const Meta& m = Meta()) {
67  _block._add(statement::Expression(builder::assign(builder::id(std::move(dst)), std::move(src), m), m));
68  }
69 
70  void addBreak(Meta m = Meta()) { _block._add(statement::Break(std::move(m))); }
71 
72  void addContinue(Meta m = Meta()) { _block._add(statement::Continue(std::move(m))); }
73 
74  void addSumAssign(ID dst, Expression src, const Meta& m = Meta()) {
75  _block._add(statement::Expression(builder::sumAssign(builder::id(std::move(dst)), std::move(src), m), m));
76  }
77 
78  void addCall(ID id, std::vector<Expression> v, const Meta& m = Meta()) {
79  _block._add(statement::Expression(builder::call(std::move(id), std::move(v), m), m));
80  }
81 
82  void addMemberCall(Expression self, const ID& id, std::vector<Expression> v, const Meta& m = Meta()) {
83  _block._add(statement::Expression(builder::memberCall(std::move(self), id, std::move(v), m), m));
84  }
85 
86  void addComment(std::string comment,
87  hilti::statement::comment::Separator separator = hilti::statement::comment::Separator::Before,
88  const Meta& m = Meta()) {
89  comment = util::replace(comment, "\n", "");
90  _block._add(statement::Comment(std::move(comment), separator, m));
91  }
92 
93  void addReturn(Expression e, Meta m = Meta()) { _block._add(statement::Return(std::move(e), std::move(m))); }
94 
95  void addReturn(Ctor c, const Meta& m = Meta()) {
96  _block._add(statement::Return(expression::Ctor(std::move(c), m), m));
97  }
98 
99  void addReturn(Meta m = Meta()) { _block._add(statement::Return(std::move(m))); }
100 
101  void addThrow(Expression excpt, Meta m = Meta()) { _block._add(statement::Throw(std::move(excpt), std::move(m))); }
102  void addRethrow(Meta m = Meta()) { _block._add(statement::Throw(std::move(m))); }
103 
104  void addDebugMsg(const std::string& stream, const std::string& fmt, std::vector<Expression> args = {});
105  void addDebugIndent(const std::string& stream);
106  void addDebugDedent(const std::string& stream);
107 
108  void addPrint(const std::vector<Expression>& exprs) { addCall("hilti::print", exprs); }
109  void addPrint(const Expression& expr) { addCall("hilti::print", {expr}); }
110 
111  auto addWhile(const statement::Declaration& init, Expression cond, Meta m = Meta()) {
112  _block._add(statement::While(init.declaration(), std::move(cond), statement::Block(), {}, std::move(m)));
113  return newBuilder(lastStatement<statement::While>()._bodyNode());
114  }
115 
116  auto addWhile(Expression cond, Meta m = Meta()) {
117  _block._add(statement::While(std::move(cond), statement::Block(), {}, std::move(m)));
118  return newBuilder(lastStatement<statement::While>()._bodyNode());
119  }
120 
121  auto addWhileElse(const statement::Declaration& init, Expression cond, Meta m = Meta()) {
122  _block._add(statement::While(init.declaration(), std::move(cond), statement::Block(), statement::Block(),
123  std::move(m)));
124  return std::make_pair(newBuilder(lastStatement<statement::While>()._bodyNode()),
125  newBuilder(lastStatement<statement::While>()._elseNode()));
126  }
127 
128  auto addWhileElse(Expression cond, Meta m = Meta()) {
129  _block._add(statement::While(std::move(cond), statement::Block(), statement::Block(), std::move(m)));
130  return std::make_pair(newBuilder(lastStatement<statement::While>()._bodyNode()),
131  newBuilder(lastStatement<statement::While>()._elseNode()));
132  }
133 
134  auto addIf(const statement::Declaration& init, Expression cond, Meta m = Meta()) {
135  _block._add(statement::If(init.declaration(), std::move(cond), statement::Block(), {}, std::move(m)));
136  return newBuilder(lastStatement<statement::If>()._trueNode());
137  }
138 
139  auto addIf(const statement::Declaration& init, Meta m = Meta()) {
140  _block._add(statement::If(init.declaration(), {}, statement::Block(), {}, std::move(m)));
141  return newBuilder(lastStatement<statement::If>()._trueNode());
142  }
143 
144  auto addIf(Expression cond, Meta m = Meta()) {
145  _block._add(statement::If(std::move(cond), statement::Block(), {}, std::move(m)));
146  return newBuilder(lastStatement<statement::If>()._trueNode());
147  }
148 
149  auto addIfElse(const statement::Declaration& init, Expression cond, Meta m = Meta()) {
150  _block._add(
151  statement::If(init.declaration(), std::move(cond), statement::Block(), statement::Block(), std::move(m)));
152  return std::make_pair(newBuilder(lastStatement<statement::If>()._trueNode()),
153  newBuilder(lastStatement<statement::If>()._falseNode()));
154  }
155 
156  auto addIfElse(const statement::Declaration& init, Meta m = Meta()) {
157  _block._add(statement::If(init.declaration(), {}, statement::Block(), statement::Block(), std::move(m)));
158  return std::make_pair(newBuilder(lastStatement<statement::If>()._trueNode()),
159  newBuilder(lastStatement<statement::If>()._falseNode()));
160  }
161 
162  auto addIfElse(Expression cond, Meta m = Meta()) {
163  _block._add(statement::If(std::move(cond), statement::Block(), statement::Block(), std::move(m)));
164  return std::make_pair(newBuilder(lastStatement<statement::If>()._trueNode()),
165  newBuilder(lastStatement<statement::If>()._falseNode()));
166  }
167 
168  auto addBlock(Meta m = Meta()) {
169  _block._add(statement::Block({}, std::move(m)));
170  return newBuilder(_block._lastStatementNode());
171  }
172 
173  class SwitchProxy {
174  public:
175  SwitchProxy(Builder* b, statement::Switch& s) : _builder(b), _switch(s) {} // NOLINT
176 
177  auto addCase(Expression expr, Meta m = Meta()) { return _addCase({std::move(expr)}, std::move(m)); }
178 
179  auto addCase(std::vector<Expression> exprs, Meta m = Meta()) {
180  return _addCase(std::move(exprs), std::move(m));
181  }
182 
183  auto addDefault(Meta m = Meta()) { return _addCase({}, std::move(m)); }
184 
185  private:
186  std::shared_ptr<Builder> _addCase(std::vector<Expression> exprs, Meta m = Meta()) {
187  _switch._addCase(statement::switch_::Case(std::move(exprs), statement::Block(), std::move(m)));
188  return _builder->newBuilder(_switch._lastCaseNode().as<statement::switch_::Case>()._bodyNode());
189  }
190 
191  Builder* _builder;
192  statement::Switch& _switch;
193  };
194 
195  auto addSwitch(Expression cond, Meta m = Meta()) {
196  _block._add(statement::Switch(std::move(cond), {}, std::move(m)));
197  return SwitchProxy(this, lastStatement<statement::Switch>());
198  }
199 
200  auto addSwitch(const statement::Declaration& init, Expression cond, Meta m = Meta()) {
201  _block._add(statement::Switch(init.declaration(), std::move(cond), {}, std::move(m)));
202  return SwitchProxy(this, lastStatement<statement::Switch>());
203  }
204 
205  class TryProxy {
206  public:
207  TryProxy(Builder* b, statement::Try& s) : _builder(b), _try(&s) {} //NOLINT(google-runtime-references)
208 
209  auto addCatch(declaration::Parameter p, Meta m = Meta()) {
210  _try->_addCatch(statement::try_::Catch(std::move(p), statement::Block(), std::move(m)));
211  return _builder->newBuilder(_try->_lastCatchNode().as<statement::try_::Catch>()._bodyNode());
212  }
213 
214  auto addCatch(Meta m = Meta()) {
215  _try->_addCatch(statement::try_::Catch(statement::Block(), std::move(m)));
216  return _builder->newBuilder(_try->_lastCatchNode().as<statement::try_::Catch>()._bodyNode());
217  }
218 
219  TryProxy(const TryProxy&) = default;
220  TryProxy(TryProxy&&) = default;
221  TryProxy() = delete;
222  ~TryProxy() = default;
223  TryProxy& operator=(const TryProxy&) = default;
224  TryProxy& operator=(TryProxy&&) noexcept = default;
225 
226  private:
227  Builder* _builder;
228  statement::Try* _try;
229  };
230 
231  auto addTry(Meta m = Meta()) {
232  _block._add(statement::Try(statement::Block(), {}, std::move(m)));
233  return std::make_pair(newBuilder(lastStatement<statement::Try>()._bodyNode()),
234  TryProxy(this, lastStatement<statement::Try>()));
235  }
236 
237  bool empty() const { return _block.statements().empty() && _tmps.empty(); }
238 
239 private:
240  friend class SwitchProxy;
241 
242  Builder(std::shared_ptr<hilti::Context> context, Statement& s) // NOLINT
243  : _context(std::move(context)), _block(s.as<statement::Block>()) {}
244 
245  template<typename T>
246  T& lastStatement() {
247  return _block._lastStatementNode().as<T>();
248  }
249 
250  std::shared_ptr<Builder> newBuilder(Node& n) { // NOLINT
251  return std::shared_ptr<Builder>(new Builder(_context, n.template as<Statement>()));
252  }
253 
254  std::shared_ptr<hilti::Context> _context;
255  std::optional<statement::Block> _our_block;
256  statement::Block& _block;
257 
258  std::map<std::string, int> _tmps;
259 };
260 
261 } // namespace hilti::builder
std::string replace(const std::string &s, const std::string &o, const std::string &n)
Definition: util.cc:69
Definition: declaration.h:14
Definition: throw.h:14
Definition: try.h:20
Definition: comment.h:19
Definition: expression.h:14
Definition: break.h:14
Definition: builder.h:205
Definition: try.h:52
Definition: builder.h:173
void _add(Statement s)
Definition: block.h:27
Definition: builder.h:22
Definition: meta.h:18
Definition: return.h:14
auto & _lastStatementNode()
Definition: block.h:30
Definition: block.h:15
Definition: parameter.h:45
Definition: builder.h:20
Definition: switch.h:83
Definition: node.h:97
Definition: assert.h:22
void _addCase(switch_::Case case_)
Definition: switch.h:136
Definition: continue.h:14
Definition: ctor.h:14
Definition: switch.h:34
Definition: id.h:18
Definition: if.h:16
Definition: while.h:16
auto & _lastCaseNode()
Definition: switch.h:133