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