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_)9ExplicitSemicolons::ExplicitSemicolons(Stage &next_) 10 : IntermediateStage(next_) {} 11 process(const Token & t)12void 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)62void ExplicitSemicolons::visit_aliasrule(const AliasRule &n) { 63 next.visit_aliasrule(n); 64 set_pending_semi(); 65 } visit_constdecl(const ConstDecl & n)66void ExplicitSemicolons::visit_constdecl(const ConstDecl &n) { 67 next.visit_constdecl(n); 68 set_pending_semi(); 69 } visit_function(const Function & n)70void ExplicitSemicolons::visit_function(const Function &n) { 71 next.visit_function(n); 72 set_pending_semi(); 73 } visit_propertyrule(const PropertyRule & n)74void ExplicitSemicolons::visit_propertyrule(const PropertyRule &n) { 75 next.visit_propertyrule(n); 76 set_pending_semi(); 77 } visit_ruleset(const Ruleset & n)78void ExplicitSemicolons::visit_ruleset(const Ruleset &n) { 79 next.visit_ruleset(n); 80 set_pending_semi(); 81 } visit_simplerule(const SimpleRule & n)82void ExplicitSemicolons::visit_simplerule(const SimpleRule &n) { 83 next.dispatch(n); 84 set_pending_semi(); 85 } visit_startstate(const StartState & n)86void ExplicitSemicolons::visit_startstate(const StartState &n) { 87 next.visit_startstate(n); 88 set_pending_semi(); 89 } visit_typedecl(const TypeDecl & n)90void ExplicitSemicolons::visit_typedecl(const TypeDecl &n) { 91 next.visit_typedecl(n); 92 set_pending_semi(); 93 } visit_vardecl(const VarDecl & n)94void ExplicitSemicolons::visit_vardecl(const VarDecl &n) { 95 next.visit_vardecl(n); 96 set_pending_semi(); 97 } 98 finalise()99void 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()115void ExplicitSemicolons::flush() { 116 for (const Token &t : pending) 117 next.process(t); 118 pending.clear(); 119 } 120 set_pending_semi()121void 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