class TaskJuggler::TextParser::State
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.
Attributes
Public Class Methods
# 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
Public Instance Methods
This method adds the actual StateTransition
to this State
.
# 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
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.
# 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
Return a comma separated list of token strings that would trigger transitions for this State
.
# 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
Convert the State
data into a human readable form. Used for debugging only.
# 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
Find the transition that matches token.
# 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