Spicy
switch.h
1 // Copyright (c) 2020-2021 by the Zeek Project. See LICENSE for details.
2 
3 #pragma once
4 
5 #include <cstddef>
6 #include <string>
7 #include <utility>
8 #include <vector>
9 
10 #include <hilti/ast/declarations/local-variable.h>
11 #include <hilti/ast/expression.h>
12 #include <hilti/ast/expressions/id.h>
13 #include <hilti/ast/expressions/unresolved-operator.h>
14 #include <hilti/ast/statement.h>
15 
16 namespace hilti::statement {
17 
18 class Switch;
19 
20 namespace switch_ {
21 
22 using Default = struct {};
23 
34 class Case : public NodeBase {
35 public:
36  Case(hilti::Expression expr, Statement body, Meta m = Meta())
37  : NodeBase(nodes(std::move(body), std::move(expr)), std::move(m)), _end_exprs(2) {}
38  Case(std::vector<hilti::Expression> exprs, Statement body, Meta m = Meta())
39  : NodeBase(nodes(std::move(body), std::move(exprs)), std::move(m)),
40  _end_exprs(static_cast<int>(children().size())) {}
41  Case(Default /*unused*/, Statement body, Meta m = Meta())
42  : NodeBase(nodes(std::move(body)), std::move(m)), _end_exprs(1) {}
43  Case() = default;
44 
45  auto expressions() const { return children<hilti::Expression>(1, _end_exprs); }
46  auto preprocessedExpressions() const { return children<hilti::Expression>(_end_exprs, -1); }
47  const auto& body() const { return child<Statement>(0); }
48 
49  bool isDefault() const { return expressions().empty(); }
50 
52  auto& _bodyNode() { return children()[0]; }
53 
55  auto properties() const { return node::Properties{}; }
56 
57  bool operator==(const Case& other) const { return expressions() == other.expressions() && body() == other.body(); }
58 
59 private:
60  friend class hilti::statement::Switch;
61 
62  void _preprocessExpressions(const std::string& id) {
63  children().erase(children().begin() + _end_exprs, children().end());
64  children().reserve(static_cast<size_t>(_end_exprs) * 2); // avoid resizing/invalidation below on emplace
65 
66  for ( const auto& e : expressions() ) {
67  hilti::Expression n =
68  expression::UnresolvedOperator(operator_::Kind::Equal, {expression::UnresolvedID(ID(id)), e}, e.meta());
69 
70  children().emplace_back(std::move(n));
71  }
72  }
73 
74  int _end_exprs{};
75 };
76 
77 inline Node to_node(Case c) { return Node(std::move(c)); }
78 
79 } // namespace switch_
80 
82 class Switch : public NodeBase, public hilti::trait::isStatement {
83 public:
84  Switch(hilti::Expression cond, const std::vector<switch_::Case>& cases, const Meta& m = Meta())
85  : Switch(hilti::declaration::LocalVariable(hilti::ID("__x"), std::move(cond), true, m), cases, m) {}
86 
87  Switch(const hilti::Declaration& cond, const std::vector<switch_::Case>& cases, Meta m = Meta())
88  : NodeBase(nodes(cond, cases), std::move(m)) {
89  if ( ! cond.isA<declaration::LocalVariable>() )
90  logger().internalError("initialization for 'switch' must be a local declaration");
91  }
92 
93  const auto& condition() const { return children()[0].as<hilti::declaration::LocalVariable>(); }
94  auto conditionRef() const { return NodeRef(children()[0]); }
95  auto cases() const { return children<switch_::Case>(1, -1); }
96 
98  for ( const auto& c : children<switch_::Case>(1, -1) ) {
99  if ( c.isDefault() )
100  return c;
101  }
102  return {};
103  }
104 
105  void preprocessCases() {
106  if ( _preprocessed )
107  return;
108 
109  for ( auto c = children().begin() + 1; c != children().end(); c++ )
110  c->as<switch_::Case>()._preprocessExpressions(condition().id());
111 
112  _preprocessed = true;
113  }
114 
115  bool operator==(const Switch& other) const {
116  return condition() == other.condition() && default_() == other.default_() && cases() == other.cases();
117  }
118 
120  auto& _lastCaseNode() { return children().back(); }
121 
123  void _addCase(switch_::Case case_) {
124  addChild(std::move(case_));
125  _preprocessed = false;
126  }
127 
129  auto isEqual(const Statement& other) const { return node::isEqual(this, other); }
130 
132  auto properties() const { return node::Properties{}; }
133 
134 private:
135  bool _preprocessed = false;
136 };
137 
138 } // namespace hilti::statement
Definition: local-variable.h:18
auto isEqual(const Statement &other) const
Definition: switch.h:129
Definition: declaration.h:54
Definition: unresolved-operator.h:16
auto properties() const
Definition: switch.h:55
const auto & children() const
Definition: node.h:472
void addChild(Node n)
Definition: node.h:461
Definition: meta.h:19
Definition: optional-ref.h:22
Definition: statement.h:14
Definition: switch.h:82
std::map< std::string, node::detail::PropertyValue > Properties
Definition: node.h:98
Definition: node.h:112
Definition: node-ref.h:45
void _addCase(switch_::Case case_)
Definition: switch.h:123
auto & _bodyNode()
Definition: switch.h:52
auto & meta() const
Definition: node.h:476
Definition: switch.h:34
auto properties() const
Definition: switch.h:132
Definition: id.h:18
Definition: node.h:360
auto & _lastCaseNode()
Definition: switch.h:120