1 #include <cassert>
2 #include <cstddef>
3 #include "location.hh"
4 #include <iostream>
5 #include <memory>
6 #include <rumur/Decl.h>
7 #include <rumur/Expr.h>
8 #include <rumur/Property.h>
9 #include <rumur/Ptr.h>
10 #include <rumur/Rule.h>
11 #include <rumur/Stmt.h>
12 #include <rumur/except.h>
13 #include <rumur/traverse.h>
14 #include <string>
15 #include <vector>
16
17 namespace rumur {
18
19 namespace {
20 /* A traversal pass that checks any return statements within a rule do not
21 * have a trailing expression.
22 */
23 class ReturnChecker : public ConstTraversal {
24
25 public:
26 /* Avoid recursing into functions, that may have return statements with an
27 * expression.
28 */
visit_function(const Function &)29 void visit_function(const Function &) final {}
visit_functioncall(const FunctionCall &)30 void visit_functioncall(const FunctionCall &) final {}
visit_procedurecall(const ProcedureCall &)31 void visit_procedurecall(const ProcedureCall &) final {}
32
visit_return(const Return & n)33 void visit_return(const Return &n) final {
34 if (n.expr != nullptr)
35 throw Error("return statement in rule or startstate returns a value",
36 n.loc);
37
38 // No need to recurse into the return statement's child.
39 }
40
check(const Node & n)41 static void check(const Node &n) {
42 ReturnChecker c;
43 c.dispatch(n);
44 }
45
46 virtual ~ReturnChecker() = default;
47 };
48 } // namespace
49
Rule(const std::string & name_,const location & loc_)50 Rule::Rule(const std::string &name_, const location &loc_)
51 : Node(loc_), name(name_) {}
52
flatten() const53 std::vector<Ptr<Rule>> Rule::flatten() const { return {Ptr<Rule>(clone())}; }
54
AliasRule(const std::vector<Ptr<AliasDecl>> & aliases_,const std::vector<Ptr<Rule>> & rules_,const location & loc_)55 AliasRule::AliasRule(const std::vector<Ptr<AliasDecl>> &aliases_,
56 const std::vector<Ptr<Rule>> &rules_, const location &loc_)
57 : Rule("", loc_), rules(rules_) {
58
59 aliases = aliases_;
60 }
61
clone() const62 AliasRule *AliasRule::clone() const { return new AliasRule(*this); }
63
visit(BaseTraversal & visitor)64 void AliasRule::visit(BaseTraversal &visitor) {
65 visitor.visit_aliasrule(*this);
66 }
67
visit(ConstBaseTraversal & visitor) const68 void AliasRule::visit(ConstBaseTraversal &visitor) const {
69 visitor.visit_aliasrule(*this);
70 }
71
flatten() const72 std::vector<Ptr<Rule>> AliasRule::flatten() const {
73 std::vector<Ptr<Rule>> rs;
74 for (const Ptr<Rule> &r : rules) {
75 for (Ptr<Rule> &f : r->flatten()) {
76 f->aliases.insert(f->aliases.begin(), aliases.begin(), aliases.end());
77 rs.push_back(f);
78 }
79 }
80 return rs;
81 }
82
SimpleRule(const std::string & name_,const Ptr<Expr> & guard_,const std::vector<Ptr<Decl>> & decls_,const std::vector<Ptr<Stmt>> & body_,const location & loc_)83 SimpleRule::SimpleRule(const std::string &name_, const Ptr<Expr> &guard_,
84 const std::vector<Ptr<Decl>> &decls_,
85 const std::vector<Ptr<Stmt>> &body_,
86 const location &loc_)
87 : Rule(name_, loc_), guard(guard_), decls(decls_), body(body_) {}
88
clone() const89 SimpleRule *SimpleRule::clone() const { return new SimpleRule(*this); }
90
validate() const91 void SimpleRule::validate() const { ReturnChecker::check(*this); }
92
visit(BaseTraversal & visitor)93 void SimpleRule::visit(BaseTraversal &visitor) {
94 visitor.visit_simplerule(*this);
95 }
96
visit(ConstBaseTraversal & visitor) const97 void SimpleRule::visit(ConstBaseTraversal &visitor) const {
98 visitor.visit_simplerule(*this);
99 }
100
StartState(const std::string & name_,const std::vector<Ptr<Decl>> & decls_,const std::vector<Ptr<Stmt>> & body_,const location & loc_)101 StartState::StartState(const std::string &name_,
102 const std::vector<Ptr<Decl>> &decls_,
103 const std::vector<Ptr<Stmt>> &body_,
104 const location &loc_)
105 : Rule(name_, loc_), decls(decls_), body(body_) {}
106
clone() const107 StartState *StartState::clone() const { return new StartState(*this); }
108
validate() const109 void StartState::validate() const { ReturnChecker::check(*this); }
110
visit(BaseTraversal & visitor)111 void StartState::visit(BaseTraversal &visitor) {
112 visitor.visit_startstate(*this);
113 }
114
visit(ConstBaseTraversal & visitor) const115 void StartState::visit(ConstBaseTraversal &visitor) const {
116 visitor.visit_startstate(*this);
117 }
118
PropertyRule(const std::string & name_,const Property & property_,const location & loc_)119 PropertyRule::PropertyRule(const std::string &name_, const Property &property_,
120 const location &loc_)
121 : Rule(name_, loc_), property(property_) {}
122
clone() const123 PropertyRule *PropertyRule::clone() const { return new PropertyRule(*this); }
124
visit(BaseTraversal & visitor)125 void PropertyRule::visit(BaseTraversal &visitor) {
126 visitor.visit_propertyrule(*this);
127 }
128
visit(ConstBaseTraversal & visitor) const129 void PropertyRule::visit(ConstBaseTraversal &visitor) const {
130 visitor.visit_propertyrule(*this);
131 }
132
Ruleset(const std::vector<Quantifier> & quantifiers_,const std::vector<Ptr<Rule>> & rules_,const location & loc_)133 Ruleset::Ruleset(const std::vector<Quantifier> &quantifiers_,
134 const std::vector<Ptr<Rule>> &rules_, const location &loc_)
135 : Rule("", loc_), rules(rules_) {
136 quantifiers = quantifiers_;
137 }
138
clone() const139 Ruleset *Ruleset::clone() const { return new Ruleset(*this); }
140
validate() const141 void Ruleset::validate() const {
142 for (const Quantifier &q : quantifiers) {
143 if (!q.constant())
144 throw Error("non-constant quantifier expression as ruleset parameter",
145 q.loc);
146 }
147 }
148
visit(BaseTraversal & visitor)149 void Ruleset::visit(BaseTraversal &visitor) { visitor.visit_ruleset(*this); }
150
visit(ConstBaseTraversal & visitor) const151 void Ruleset::visit(ConstBaseTraversal &visitor) const {
152 visitor.visit_ruleset(*this);
153 }
154
flatten() const155 std::vector<Ptr<Rule>> Ruleset::flatten() const {
156 std::vector<Ptr<Rule>> rs;
157 for (const Ptr<Rule> &r : rules) {
158 for (Ptr<Rule> &f : r->flatten()) {
159 for (const Quantifier &q : quantifiers)
160 f->quantifiers.push_back(q);
161 rs.push_back(f);
162 }
163 }
164 return rs;
165 }
166
167 } // namespace rumur
168