1 #include "ExplicitSemicolons.h"
2 #include <cassert>
3 #include <cstddef>
4 #include <ctype.h>
5 #include <rumur/rumur.h>
6 
7 using namespace rumur;
8 
ExplicitSemicolons(Stage & next_)9 ExplicitSemicolons::ExplicitSemicolons(Stage &next_)
10     : IntermediateStage(next_) {}
11 
process(const Token & t)12 void ExplicitSemicolons::process(const Token &t) {
13 
14   // if this is a message to ourselves, update our state
15   if (t.type == Token::SUBJ && t.subject == this) {
16     assert(!state.empty() &&
17            "message to shift state when we have no pending next state");
18     pending_semi = state.front();
19     state.pop();
20     return;
21   }
22 
23   // if we are not waiting on a semi-colons, we can simply output this character
24   if (!pending_semi) {
25     assert(pending.empty());
26     next.process(t);
27     return;
28   }
29 
30   switch (t.type) {
31 
32   case Token::CHAR:
33     // if this is white space, keep accruing pending characters
34     if (t.character.size() == 1 && isspace(t.character.c_str()[0])) {
35       pending.push_back(t);
36       return;
37     }
38     break;
39 
40   // if this was a shift message to another Stage, accrue it
41   case Token::SUBJ:
42     pending.push_back(t);
43     return;
44   }
45 
46   // if we reached here, we know one way or another we are done accruing
47   pending_semi = false;
48 
49   // the semi-colon was either explicit already if this character itself is a
50   // semi-colon, or it was omitted otherwise
51   if (t.type == Token::CHAR && t.character != ";")
52     next << ";";
53 
54   // flush the accrued white space and shift messages
55   flush();
56 
57   next.process(t);
58 }
59 
60 // each of these need to simply passthrough to the next stage in the pipeline
61 // and note that we then have a pending semi-colon
visit_aliasrule(const AliasRule & n)62 void ExplicitSemicolons::visit_aliasrule(const AliasRule &n) {
63   next.visit_aliasrule(n);
64   set_pending_semi();
65 }
visit_constdecl(const ConstDecl & n)66 void ExplicitSemicolons::visit_constdecl(const ConstDecl &n) {
67   next.visit_constdecl(n);
68   set_pending_semi();
69 }
visit_function(const Function & n)70 void ExplicitSemicolons::visit_function(const Function &n) {
71   next.visit_function(n);
72   set_pending_semi();
73 }
visit_propertyrule(const PropertyRule & n)74 void ExplicitSemicolons::visit_propertyrule(const PropertyRule &n) {
75   next.visit_propertyrule(n);
76   set_pending_semi();
77 }
visit_ruleset(const Ruleset & n)78 void ExplicitSemicolons::visit_ruleset(const Ruleset &n) {
79   next.visit_ruleset(n);
80   set_pending_semi();
81 }
visit_simplerule(const SimpleRule & n)82 void ExplicitSemicolons::visit_simplerule(const SimpleRule &n) {
83   next.dispatch(n);
84   set_pending_semi();
85 }
visit_startstate(const StartState & n)86 void ExplicitSemicolons::visit_startstate(const StartState &n) {
87   next.visit_startstate(n);
88   set_pending_semi();
89 }
visit_typedecl(const TypeDecl & n)90 void ExplicitSemicolons::visit_typedecl(const TypeDecl &n) {
91   next.visit_typedecl(n);
92   set_pending_semi();
93 }
visit_vardecl(const VarDecl & n)94 void ExplicitSemicolons::visit_vardecl(const VarDecl &n) {
95   next.visit_vardecl(n);
96   set_pending_semi();
97 }
98 
finalise()99 void ExplicitSemicolons::finalise() {
100 
101   // apply any unconsumed updates
102   while (!state.empty()) {
103     pending_semi = state.front();
104     state.pop();
105   }
106 
107   // if we have a pending semi-colon, we know we are never going to see one now
108   if (pending_semi)
109     next << ";";
110   pending_semi = false;
111 
112   flush();
113 }
114 
flush()115 void ExplicitSemicolons::flush() {
116   for (const Token &t : pending)
117     next.process(t);
118   pending.clear();
119 }
120 
set_pending_semi()121 void ExplicitSemicolons::set_pending_semi() {
122 
123   // queue the update to take effect in the future
124   state.push(true);
125 
126   // put a message in the pipeline to tell ourselves to later shift this state
127   // into .pending_semi
128   top->process(Token(this));
129 }
130