Class: TaskJuggler::TextParser::Rule

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

Overview

The TextParserRule holds the basic elment of the syntax description. Each rule has a name and a set of patterns. The parser uses these rules to parse the input files. The first token of a pattern must resolve to a terminal token. The resolution can run transitively over a set of rules. The first tokens of each pattern of a rule must resolve to a terminal symbol and all terminals must be unique in the scope that they appear in. The parser uses this first token to select the next pattern it uses for the syntactical analysis. A rule can be marked as repeatable and/or optional. In this case the syntax element described by the rule may occur 0 or multiple times in the parsed file.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name) ⇒ Rule

Create a new syntax rule called name.



33
34
35
36
37
38
39
40
41
# File 'lib/taskjuggler/TextParser/Rule.rb', line 33

def initialize(name)
  @name = name
  @patterns = []
  @repeatable = false
  @optional = false
  @keyword = nil

  flushCache
end

Instance Attribute Details

#docObject (readonly)

Returns the value of attribute doc.



30
31
32
# File 'lib/taskjuggler/TextParser/Rule.rb', line 30

def doc
  @doc
end

#keywordObject (readonly)

Returns the value of attribute keyword.



30
31
32
# File 'lib/taskjuggler/TextParser/Rule.rb', line 30

def keyword
  @keyword
end

#nameObject (readonly)

Returns the value of attribute name.



30
31
32
# File 'lib/taskjuggler/TextParser/Rule.rb', line 30

def name
  @name
end

#optionalObject (readonly)

Returns the value of attribute optional.



30
31
32
# File 'lib/taskjuggler/TextParser/Rule.rb', line 30

def optional
  @optional
end

#patternsObject (readonly)

Returns the value of attribute patterns.



30
31
32
# File 'lib/taskjuggler/TextParser/Rule.rb', line 30

def patterns
  @patterns
end

#repeatableObject (readonly)

Returns the value of attribute repeatable.



30
31
32
# File 'lib/taskjuggler/TextParser/Rule.rb', line 30

def repeatable
  @repeatable
end

Instance Method Details

#addPattern(pattern) ⇒ Object

Add a new pattern to the Rule. It should be of type TextParser::Pattern.



52
53
54
# File 'lib/taskjuggler/TextParser/Rule.rb', line 52

def addPattern(pattern)
  @patterns << pattern
end

#addTransitionsToState(states, rules, stateStack, sourceState, loopBack) ⇒ Object

Return a Hash of all state transitions caused by the 1st token of each pattern of this rule.



95
96
97
98
99
100
101
# File 'lib/taskjuggler/TextParser/Rule.rb', line 95

def addTransitionsToState(states, rules, stateStack, sourceState,
                          loopBack)
  @patterns.each do |pattern|
    pattern.addTransitionsToState(states, rules, stateStack.dup,
                                  sourceState, self, 0, loopBack)
  end
end

#dumpObject



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/taskjuggler/TextParser/Rule.rb', line 177

def dump
  puts "Rule: #{name} #{@optional ? "[optional]" : ""} " +
       "#{@repeatable ? "[repeatable]" : ""}"
  @patterns.length.times do |i|
    puts "  Pattern: \"#{@patterns[i]}\""
    unless @transitions[i]
      puts "No transitions for this pattern!"
      next
    end

    @transitions[i].each do |key, rule|
      if key[0] == ?_
        token = "\"" + key.slice(1, key.length - 1) + "\""
      else
        token = key.slice(1, key.length - 1)
      end
      puts "    #{token} -> #{rule.name}"
    end
  end
  puts
end

#flushCacheObject



43
44
45
46
47
48
# File 'lib/taskjuggler/TextParser/Rule.rb', line 43

def flushCache
  # A rule is considered to describe optional tokens in case the @optional
  # flag is set or all of the patterns reference optional rules again.
  # This variable caches the transitively determined optional value.
  @transitiveOptional = nil
end

#generateStates(rules) ⇒ Object



81
82
83
84
85
86
87
88
89
90
91
# File 'lib/taskjuggler/TextParser/Rule.rb', line 81

def generateStates(rules)
  # First, add an entry State for this rule. Entry states are never
  # reached by normal state transitions. They are only used as (re-)start
  # states.
  states = [ State.new(self) ]

  @patterns.each do |pattern|
    states += pattern.generateStates(self, rules)
  end
  states
end

#optional?(rules) ⇒ Boolean

Return true if the rule describes optional elements. The evaluation recursively descends into the pattern if necessary and stores the result to be reused for later calls.

Returns:

  • (Boolean)


64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/taskjuggler/TextParser/Rule.rb', line 64

def optional?(rules)
  # If we have a cached result, use this.
  return @transitiveOptional if @transitiveOptional

  # If the rule is marked optional, then it is optional.
  if @optional
    return @transitiveOptional = true
  end

  # If all patterns describe optional content, then this rule is optional
  # as well.
  @transitiveOptional = true
  @patterns.each do |pat|
    return @transitiveOptional = false unless pat.optional?(rules)
  end
end

#pattern(idx) ⇒ Object

Return a reference the pattern of this Rule.



151
152
153
# File 'lib/taskjuggler/TextParser/Rule.rb', line 151

def pattern(idx)
  @patterns[idx]
end

#setArg(idx, doc) ⇒ Object

Add a description for a pattern element of the last added pattern.



119
120
121
122
# File 'lib/taskjuggler/TextParser/Rule.rb', line 119

def setArg(idx, doc)
  raise 'No pattern defined yet' if @patterns.empty?
  @patterns[-1].setArg(idx, doc)
end

#setDoc(keyword, doc) ⇒ Object

Add a description for the syntax elements of this Rule. doc is a RichText and keyword is a unique name of this Rule. To avoid ambiguouties, an optional scope can be appended, separated by a dot (E.g. name.scope).



113
114
115
116
# File 'lib/taskjuggler/TextParser/Rule.rb', line 113

def setDoc(keyword, doc)
  raise 'No pattern defined yet' if @patterns.empty?
  @patterns[-1].setDoc(keyword, doc)
end

#setExample(file, tag) ⇒ Object

Add a reference to a code example. file is the name of the file. tag is a tag within the file that specifies a part of this file.



146
147
148
# File 'lib/taskjuggler/TextParser/Rule.rb', line 146

def setExample(file, tag)
  @patterns[-1].setExample(file, tag)
end

#setLastSyntaxToken(idx) ⇒ Object

Specify the index idx of the last token to be used for the syntax documentation. All subsequent tokens will be ignored.



126
127
128
129
130
# File 'lib/taskjuggler/TextParser/Rule.rb', line 126

def setLastSyntaxToken(idx)
  raise 'No pattern defined yet' if @patterns.empty?
  raise 'Token index too large' if idx >= @patterns[-1].tokens.length
  @patterns[-1].setLastSyntaxToken(idx)
end

#setOptionalObject

Mark the rule as an optional element of the syntax.



57
58
59
# File 'lib/taskjuggler/TextParser/Rule.rb', line 57

def setOptional
  @optional = true
end

#setRepeatableObject

Mark the syntax element described by this Rule as a repeatable element that can occur once or more times in sequence.



105
106
107
# File 'lib/taskjuggler/TextParser/Rule.rb', line 105

def setRepeatable
  @repeatable = true
end

#setSeeAlso(also) ⇒ Object

Add a reference to another rule for documentation purposes.



139
140
141
142
# File 'lib/taskjuggler/TextParser/Rule.rb', line 139

def setSeeAlso(also)
  raise 'No pattern defined yet' if @patterns.empty?
  @patterns[-1].setSeeAlso(also)
end

#setSupportLevel(level) ⇒ Object

Specify the support level of the current pattern.



133
134
135
136
# File 'lib/taskjuggler/TextParser/Rule.rb', line 133

def setSupportLevel(level)
  raise 'No pattern defined yet' if @patterns.empty?
  @patterns[-1].setSupportLevel(level)
end

#to_syntax(stack, docs, rules, skip) ⇒ Object



155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/taskjuggler/TextParser/Rule.rb', line 155

def to_syntax(stack, docs, rules, skip)
  str = ''
  str << '[' if @optional || @repeatable
  str << '(' if @patterns.length > 1
  first = true
  pStr = ''
  @patterns.each do |pat|
    if first
      first = false
    else
      pStr << ' | '
    end
    pStr << pat.to_syntax_r(stack, docs, rules, skip)
  end
  return '' if pStr == ''
  str << pStr
  str << '...' if @repeatable
  str << ')' if @patterns.length > 1
  str << ']' if @optional || @repeatable
  str
end