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