Class: TaskJuggler::TextParser::State

Inherits:
Object
  • Object
show all
Defined in:
lib/taskjuggler/TextParser/State.rb

Overview

This State objects describes a state of the TextParser FSM. A State captures the position in the syntax description that the parser is currently at. A position is defined by the Rule, the Pattern and the index of the current token of that Pattern. An index of 0 means, we’ve just read the 1st token of the pattern. States which have no Pattern describe the start of rule. The parser has not yet identified the first token, so it doesn’t know the Pattern yet.

The actual data of a State is the list of possible StateTransitions to other states and a boolean flag that specifies if Reduce operations are valid for this State or not. The transitions are hashed by the token that would trigger this transition.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(rule, pattern = nil, index = 0) ⇒ State

Returns a new instance of State.



85
86
87
88
89
90
91
92
93
94
# File 'lib/taskjuggler/TextParser/State.rb', line 85

def initialize(rule, pattern = nil, index = 0)
  @rule = rule
  @pattern = pattern
  @index = index
  # Starting states are always reduceable. Other states may or may not be
  # reduceable. For now, we assume they are not.
  @noReduce = !pattern.nil?

  @transitions = {}
end

Instance Attribute Details

#indexObject (readonly)

Returns the value of attribute index.



82
83
84
# File 'lib/taskjuggler/TextParser/State.rb', line 82

def index
  @index
end

#noReduceObject

Returns the value of attribute noReduce.



83
84
85
# File 'lib/taskjuggler/TextParser/State.rb', line 83

def noReduce
  @noReduce
end

#patternObject (readonly)

Returns the value of attribute pattern.



82
83
84
# File 'lib/taskjuggler/TextParser/State.rb', line 82

def pattern
  @pattern
end

#ruleObject (readonly)

Returns the value of attribute rule.



82
83
84
# File 'lib/taskjuggler/TextParser/State.rb', line 82

def rule
  @rule
end

#transitionsObject (readonly)

Returns the value of attribute transitions.



82
83
84
# File 'lib/taskjuggler/TextParser/State.rb', line 82

def transitions
  @transitions
end

Instance Method Details

#addTransition(token, nextState, stateStack, loopBack) ⇒ Object

This method adds the actual StateTransition to this State.



111
112
113
114
115
116
117
118
119
# File 'lib/taskjuggler/TextParser/State.rb', line 111

def addTransition(token, nextState, stateStack, loopBack)
  tr = StateTransition.new(token, nextState, stateStack, loopBack)
  if @transitions.include?(tr.tokenType)
    raise "Ambiguous transition for #{tr.tokenType} in \n#{self}\n" +
          "The following transition both match:\n" +
          "  #{tr}\n  #{@transitions[tr.tokenType]}"
  end
  @transitions[tr.tokenType] = tr
end

#addTransitions(states, rules) ⇒ Object

Complete the StateTransition list. We can only call this function after all State objects for the syntax have been created. So we can’t make this part of the constructor.



99
100
101
102
103
104
105
106
107
108
# File 'lib/taskjuggler/TextParser/State.rb', line 99

def addTransitions(states, rules)
  if @pattern
    # This is an normal state node.
    @pattern.addTransitionsToState(states, rules, [], self,
                                   @rule, @index + 1, false)
  else
    # This is a start node.
    @rule.addTransitionsToState(states, rules, [], self, false)
  end
end

#expectedTokensObject

Return a comma separated list of token strings that would trigger transitions for this State.



136
137
138
139
140
141
142
# File 'lib/taskjuggler/TextParser/State.rb', line 136

def expectedTokens
  tokens = []
  @transitions.each_key do |t|
    tokens << "#{t.is_a?(String) ? "'#{t}'" : ":#{t}"}"
  end
  tokens
end

#to_s(short = false) ⇒ Object

Convert the State data into a human readable form. Used for debugging only.



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/taskjuggler/TextParser/State.rb', line 146

def to_s(short = false)
  if short
    if @pattern
      str = "#{rule.name} " +
            "#{rule.patterns.index(@pattern)} #{@index}"
    else
      str = "#{rule.name} (Starting Node)"
    end
  else
    if @pattern
      str = "=== State: #{rule.name} " +
            "#{rule.patterns.index(@pattern)} #{@index}" +
            " #{@noReduce ? '' : '(R)'}" +
            " #{'=' * 40}\nPattern: #{@pattern}\n"
    else
      str = "=== State: #{rule.name} (Starting Node) #{'=' * 30}\n"
    end

    @transitions.each do |type, target|
      targetStr = target ? target.to_s : "<EOF>"
      str += "  #{type.is_a?(String) ? "'#{type}'" : ":#{type}"}" +
             " => #{targetStr}\n"
    end
    str += "#{'=' * 76}\n"
  end
  str
end

#transition(token) ⇒ Object

Find the transition that matches token.



122
123
124
125
126
127
128
129
130
131
132
# File 'lib/taskjuggler/TextParser/State.rb', line 122

def transition(token)
  if token[0] == :ID
    # The scanner cannot differentiate between IDs and literals that look
    # like IDs. So we look for literals first and then for IDs.
    @transitions[token[1]] || @transitions[:ID]
  elsif token[0] == :LITERAL
    @transitions[token[1]]
  else
    @transitions[token[0]]
  end
end