File: ExplicitSemicolons.cc

package info (click to toggle)
rumur 2026.03.11-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,664 kB
  • sloc: cpp: 18,723; ansic: 3,824; python: 1,578; objc: 1,542; yacc: 568; sh: 331; lex: 241; lisp: 15; makefile: 5
file content (129 lines) | stat: -rw-r--r-- 3,287 bytes parent folder | download | duplicates (3)
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));
}