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