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, std::vector<Expression> v, const Meta& m = Meta()) {
81  _block._add(statement::Expression(builder::call(std::move(id), std::move(v), m), m));
82  }
83 
84  void addMemberCall(Expression self, const ID& id, std::vector<Expression> v, const Meta& m = Meta()) {
85  _block._add(statement::Expression(builder::memberCall(std::move(self), id, std::move(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, Meta m = Meta()) {
198  _block._add(statement::Switch(std::move(cond), {}, std::move(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  class TryProxy {
208  public:
209  TryProxy(Builder* b, statement::Try& s) : _builder(b), _try(&s) {} //NOLINT(google-runtime-references)
210 
211  auto addCatch(declaration::Parameter p, Meta m = Meta()) {
212  _try->_addCatch(statement::try_::Catch(std::move(p), statement::Block(), std::move(m)));
213  return _builder->newBuilder(_try->_lastCatchNode().as<statement::try_::Catch>()._bodyNode());
214  }
215 
216  auto addCatch(Meta m = Meta()) {
217  _try->_addCatch(statement::try_::Catch(statement::Block(), std::move(m)));
218  return _builder->newBuilder(_try->_lastCatchNode().as<statement::try_::Catch>()._bodyNode());
219  }
220 
221  TryProxy(const TryProxy&) = default;
222  TryProxy(TryProxy&&) = default;
223  TryProxy() = delete;
224  ~TryProxy() = default;
225  TryProxy& operator=(const TryProxy&) = default;
226  TryProxy& operator=(TryProxy&&) noexcept = default;
227 
228  private:
229  Builder* _builder;
230  statement::Try* _try;
231  };
232 
233  auto addTry(Meta m = Meta()) {
234  _block._add(statement::Try(statement::Block(), {}, std::move(m)));
235  return std::make_pair(newBuilder(lastStatement<statement::Try>()._bodyNode()),
236  TryProxy(this, lastStatement<statement::Try>()));
237  }
238 
239  bool empty() const { return _block.statements().empty() && _tmps.empty(); }
240 
241 private:
242  friend class SwitchProxy;
243 
244  Builder(std::weak_ptr<hilti::Context> context, Statement& s) // NOLINT
245  : _context(std::move(context)), _block(s.as<statement::Block>()) {}
246 
247  template<typename T>
248  T& lastStatement() {
249  return _block._lastStatementNode().as<T>();
250  }
251 
252  std::shared_ptr<Builder> newBuilder(Node& n) { // NOLINT
253  return std::shared_ptr<Builder>(new Builder(_context, n.template as<Statement>()));
254  }
255 
256  std::weak_ptr<hilti::Context> _context;
257  std::optional<statement::Block> _our_block;
258  statement::Block& _block;
259 
260  std::map<std::string, int> _tmps;
261 };
262 
263 } // namespace hilti::builder
std::string replace(const std::string &s, const std::string &o, const std::string &n)
Definition: util.cc:68
Definition: declaration.h:14
Definition: throw.h:14
Definition: try.h:21
Definition: comment.h:19
Definition: expression.h:14
Definition: break.h:14
Definition: builder.h:207
Definition: try.h:47
Definition: builder.h:175
void _add(Statement s)
Definition: block.h:27
Definition: builder.h:22
Definition: meta.h:18
Definition: return.h:14
Definition: type.h:159
auto & _lastStatementNode()
Definition: block.h:30
Definition: block.h:15
Definition: parameter.h:47
Definition: builder.h:20
Definition: switch.h:81
Definition: node.h:113
Definition: assert.h:22
void _addCase(switch_::Case case_)
Definition: switch.h:122
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:119