antlr4 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +27 -0
  3. data/README.md +46 -0
  4. data/lib/antlr4.rb +262 -0
  5. data/lib/antlr4/BufferedTokenStream.rb +306 -0
  6. data/lib/antlr4/CommonTokenFactory.rb +53 -0
  7. data/lib/antlr4/CommonTokenStream.rb +56 -0
  8. data/lib/antlr4/FileStream.rb +14 -0
  9. data/lib/antlr4/InputStream.rb +82 -0
  10. data/lib/antlr4/IntervalSet.rb +341 -0
  11. data/lib/antlr4/LL1Analyzer.rb +177 -0
  12. data/lib/antlr4/Lexer.rb +335 -0
  13. data/lib/antlr4/ListTokenSource.rb +140 -0
  14. data/lib/antlr4/Parser.rb +562 -0
  15. data/lib/antlr4/ParserInterpreter.rb +149 -0
  16. data/lib/antlr4/ParserRuleContext.rb +162 -0
  17. data/lib/antlr4/PredictionContext.rb +690 -0
  18. data/lib/antlr4/Recognizer.rb +162 -0
  19. data/lib/antlr4/RuleContext.rb +226 -0
  20. data/lib/antlr4/Token.rb +124 -0
  21. data/lib/antlr4/TokenFactory.rb +3 -0
  22. data/lib/antlr4/TokenSource.rb +4 -0
  23. data/lib/antlr4/TokenStream.rb +3 -0
  24. data/lib/antlr4/TraceListener.rb +23 -0
  25. data/lib/antlr4/atn/ATN.rb +133 -0
  26. data/lib/antlr4/atn/ATNConfig.rb +146 -0
  27. data/lib/antlr4/atn/ATNConfigSet.rb +215 -0
  28. data/lib/antlr4/atn/ATNDeserializationOptions.rb +62 -0
  29. data/lib/antlr4/atn/ATNDeserializer.rb +604 -0
  30. data/lib/antlr4/atn/ATNSimulator.rb +43 -0
  31. data/lib/antlr4/atn/ATNState.rb +253 -0
  32. data/lib/antlr4/atn/ATNType.rb +22 -0
  33. data/lib/antlr4/atn/LexerATNSimulator.rb +612 -0
  34. data/lib/antlr4/atn/LexerAction.rb +311 -0
  35. data/lib/antlr4/atn/LexerActionExecutor.rb +134 -0
  36. data/lib/antlr4/atn/ParserATNSimulator.rb +1622 -0
  37. data/lib/antlr4/atn/PredictionMode.rb +525 -0
  38. data/lib/antlr4/atn/SemanticContext.rb +355 -0
  39. data/lib/antlr4/atn/Transition.rb +297 -0
  40. data/lib/antlr4/base.rb +60 -0
  41. data/lib/antlr4/dfa/DFA.rb +128 -0
  42. data/lib/antlr4/dfa/DFASerializer.rb +77 -0
  43. data/lib/antlr4/dfa/DFAState.rb +133 -0
  44. data/lib/antlr4/error.rb +151 -0
  45. data/lib/antlr4/error/DiagnosticErrorListener.rb +136 -0
  46. data/lib/antlr4/error/ErrorListener.rb +109 -0
  47. data/lib/antlr4/error/ErrorStrategy.rb +742 -0
  48. data/lib/antlr4/tree/Chunk.rb +31 -0
  49. data/lib/antlr4/tree/ParseTreeMatch.rb +105 -0
  50. data/lib/antlr4/tree/ParseTreePattern.rb +70 -0
  51. data/lib/antlr4/tree/ParseTreePatternMatcher.rb +334 -0
  52. data/lib/antlr4/tree/RuleTagToken.rb +39 -0
  53. data/lib/antlr4/tree/TokenTagToken.rb +38 -0
  54. data/lib/antlr4/tree/Tree.rb +204 -0
  55. data/lib/antlr4/tree/Trees.rb +111 -0
  56. data/lib/antlr4/version.rb +5 -0
  57. data/lib/antlr4/xpath/XPath.rb +354 -0
  58. data/lib/double_key_map.rb +78 -0
  59. data/lib/java_symbols.rb +24 -0
  60. data/lib/uuid.rb +87 -0
  61. data/test/test_intervalset.rb +664 -0
  62. data/test/test_tree.rb +140 -0
  63. data/test/test_uuid.rb +122 -0
  64. metadata +109 -0
@@ -0,0 +1,149 @@
1
+
2
+ # A parser simulator that mimics what ANTLR's generated
3
+ # parser code does. A ParserATNSimulator is used to make
4
+ # predictions via adaptivePredict but this class moves a pointer through the
5
+ # ATN to simulate parsing. ParserATNSimulator just
6
+ # makes us efficient rather than having to backtrack, for example.
7
+ #
8
+ # This properly creates parse trees even for left recursive rules.
9
+ #
10
+ # We rely on the left recursive rule invocation and special predicate
11
+ # transitions to make left recursive rules work.
12
+ #
13
+ # See TestParserInterpreter for examples.
14
+
15
+ class ParserInterpreter < Parser
16
+
17
+ attr_accessor :parentContextStack, :atn, :grammarFileName
18
+ attr_accessor :tokenNames, :ruleNames, :decisionToDFA,:sharedContextCache
19
+ attr_accessor :parentContextStack ,:pushRecursionContextStates , :interp
20
+ def initialize(grammarFileName, tokenNames, ruleNames, atn, input)
21
+ super(input)
22
+ self.grammarFileName = grammarFileName
23
+ self.atn = atn
24
+ self.tokenNames = tokenNames
25
+ self.ruleNames = ruleNames
26
+ self.decisionToDFA = atn.decisionToState.map {|state| DFA.new(state) }
27
+ self.sharedContextCache = PredictionContextCache.new()
28
+ self.parentContextStack = Array.new
29
+ # identify the ATN states where pushNewRecursionContext must be called
30
+ self.pushRecursionContextStates = Set.new()
31
+ atn.states.each do |state|
32
+ next if not state.kind_of? StarLoopEntryState
33
+ if state.precedenceRuleDecision
34
+ self.pushRecursionContextStates.add(state.stateNumber)
35
+ end
36
+ end
37
+ # get atn simulator that knows how to do predictions
38
+ self.interp = ParserATNSimulator.new(self, atn, self.decisionToDFA, self.sharedContextCache)
39
+ end
40
+ # Begin parsing at startRuleIndex#
41
+ def parse(startRuleIndex)
42
+ startRuleStartState = self.atn.ruleToStartState[startRuleIndex]
43
+ rootContext = InterpreterRuleContext.new(nil, ATNState::INVALID_STATE_NUMBER, startRuleIndex)
44
+ if startRuleStartState.isPrecedenceRule
45
+ self.enterRecursionRule(rootContext, startRuleStartState.stateNumber, startRuleIndex, 0)
46
+ else
47
+ self.enterRule(rootContext, startRuleStartState.stateNumber, startRuleIndex)
48
+ end
49
+ while true
50
+ p = self.getATNState()
51
+ if p.stateType==ATNState::RULE_STOP
52
+ # pop; return from rule
53
+ if self.ctx.length==0
54
+ if startRuleStartState.isPrecedenceRule
55
+ result = self.ctx
56
+ parentContext = self.parentContextStack.pop()
57
+ self.unrollRecursionContexts(parentContext.a)
58
+ return result
59
+ else
60
+ self.exitRule()
61
+ return rootContext
62
+ end
63
+ end
64
+ self.visitRuleStopState(p)
65
+ else
66
+ begin
67
+ self.visitState(p)
68
+ rescue RecognitionException => e
69
+ self.state = self.atn.ruleToStopState[p.ruleIndex].stateNumber
70
+ self.ctx.exception = e
71
+ self.errHandler.reportError(self, e)
72
+ self.errHandler.recover(self, e)
73
+ end
74
+ end
75
+ end
76
+ end
77
+ def enterRecursionRule(localctx, state, ruleIndex, precedence)
78
+ self.parentContextStack.push([self.ctx, localctx.invokingState])
79
+ super(localctx, state, ruleIndex, precedence)
80
+ end
81
+ def getATNState
82
+ return self.atn.states[self.state]
83
+ end
84
+
85
+ def visitState(p)
86
+ edge = 0
87
+ if p.transitions.length() > 1
88
+ self.errHandler.sync(self)
89
+ edge = self.interp.adaptivePredict(self.input, p.decision, self.ctx)
90
+ else
91
+ edge = 1
92
+ end
93
+
94
+ transition = p.transitions[edge - 1]
95
+ tt = transition.serializationType
96
+ if tt==Transition::EPSILON then
97
+
98
+ if self.pushRecursionContextStates[p.stateNumber] and not transition.target.kind_of? LoopEndState
99
+ t = self.parentContextStack[-1]
100
+ ctx = InterpreterRuleContext.new(t[0], t[1], self.ctx.ruleIndex)
101
+ self.pushNewRecursionContext(ctx, self.atn.ruleToStartState[p.ruleIndex].stateNumber, self.ctx.ruleIndex)
102
+ end
103
+ elsif tt==Transition::ATOM
104
+ self.match(transition.label)
105
+ elsif [ Transition::RANGE, Transition::SET, Transition::NOT_SET].member? tt
106
+ if not transition.matches(self.input.LA(1), Token::MIN_USER_TOKEN_TYPE, 0xFFFF)
107
+ self.errHandler.recoverInline(self)
108
+ end
109
+ self.matchWildcard()
110
+ elsif tt==Transition::WILDCARD
111
+ self.matchWildcard()
112
+ elsif tt==Transition::RULE
113
+ ruleStartState = transition.target
114
+ ruleIndex = ruleStartState.ruleIndex
115
+ ctx = InterpreterRuleContext(self.ctx, p.stateNumber, ruleIndex)
116
+ if ruleStartState.isPrecedenceRule
117
+ self.enterRecursionRule(ctx, ruleStartState.stateNumber, ruleIndex, transition.precedence)
118
+ else
119
+ self.enterRule(ctx, transition.target.stateNumber, ruleIndex)
120
+ end
121
+ elsif tt==Transition::PREDICATE
122
+ if not self.sempred(self.ctx, transition.ruleIndex, transition.predIndex)
123
+ raise FailedPredicateException.new(self)
124
+ end
125
+ elsif tt==Transition::ACTION
126
+ self.action(self.ctx, transition.ruleIndex, transition.actionIndex)
127
+ elsif tt==Transition::PRECEDENCE
128
+ if not self.precpred(self.ctx, transition.precedence)
129
+ msg = "precpred(ctx, #{transition.precedence})"
130
+ raise FailedPredicateException.new(self, msg)
131
+ end
132
+ else
133
+ raise UnsupportedOperationException.new("Unrecognized ATN transition type.")
134
+ end
135
+ self.state = transition.target.stateNumber
136
+ end
137
+ def visitRuleStopState(p) # p:ATNState)
138
+ ruleStartState = self.atn.ruleToStartState[p.ruleIndex]
139
+ if ruleStartState.isPrecedenceRule then
140
+ parentContext = self.parentContextStack.pop()
141
+ self.unrollRecursionContexts(parentContext.a)
142
+ self.state = parentContext[1]
143
+ else
144
+ self.exitRule()
145
+ end
146
+ ruleTransition = self.atn.states[self.state].transitions[0]
147
+ self.state = ruleTransition.followState.stateNumber
148
+ end
149
+ end
@@ -0,0 +1,162 @@
1
+ #* A rule invocation record for parsing.
2
+ #
3
+ # Contains all of the information about the current rule not stored in the
4
+ # RuleContext. It handles parse tree children list, Any ATN state
5
+ # tracing, and the default values available for rule indications:
6
+ # start, stop, rule index, current alt number, current
7
+ # ATN state.
8
+ #
9
+ # Subclasses made for each rule and grammar track the parameters,
10
+ # return values, locals, and labels specific to that rule. These
11
+ # are the objects that are returned from rules.
12
+ #
13
+ # Note text is not an actual field of a rule return value; it is computed
14
+ # from start and stop using the input stream's toString() method. I
15
+ # could add a ctor to this so that we can pass in and store the input
16
+ # stream, but I'm not sure we want to do that. It would seem to be undefined
17
+ # to get the .text property anyway if the rule matches tokens from multiple
18
+ # input streams.
19
+ #
20
+ # I do not use getters for fields of objects that are used simply to
21
+ # group values such as this aggregate. The getters/setters are there to
22
+ # satisfy the superclass interface.
23
+
24
+
25
+ class ParserRuleContext < RuleContext
26
+
27
+ attr_accessor :children, :start, :stop, :exception
28
+ attr_accessor :parser
29
+ def initialize(parent= nil, invoking_state_number= nil)
30
+ super(parent, invoking_state_number)
31
+ #* If we are debugging or building a parse tree for a visitor,
32
+ # we need to track all of the tokens and rule invocations associated
33
+ # with this rule's context. This is empty for parsing w/o tree constr.
34
+ # operation because we don't the need to track the details about
35
+ # how we parse this rule.
36
+ #/
37
+ @children = Array.new
38
+ @start = nil
39
+ @stop = nil
40
+ # The exception that forced this rule to return. If the rule successfully
41
+ # completed, this is {@code null}.
42
+ @exception =nil
43
+ end
44
+
45
+ #* COPY a ctx (I'm deliberately not using copy constructor)#/
46
+ def copyFrom(ctx)
47
+ # from RuleContext
48
+ self.parentCtx = ctx.parentCtx
49
+ self.invokingState = ctx.invokingState
50
+ self.children = Array.new
51
+ self.start = ctx.start
52
+ self.stop = ctx.stop
53
+ end
54
+
55
+ # Double dispatch methods for listeners
56
+ def enterRule(listener)
57
+ end
58
+ def exitRule(listener)
59
+ end
60
+
61
+ #* Does not set parent link; other add methods do that#/
62
+ def addChild(child)
63
+ self.children.push(child)
64
+ return child
65
+ end
66
+ #* Used by enterOuterAlt to toss out a RuleContext previously added as
67
+ # we entered a rule. If we have # label, we will need to remove
68
+ # generic ruleContext object.
69
+ #/
70
+ def removeLastChild()
71
+ self.children.delete_at(-1)
72
+ end
73
+ def addTokenNode(token)
74
+ node = TerminalNodeImpl.new(token) #XXX
75
+ self.addChild(node)
76
+ node.parentCtx = self
77
+ return node
78
+ end
79
+
80
+ def addErrorNode(badToken)
81
+ node = ErrorNodeImpl.new(badToken)
82
+ self.addChild(node)
83
+ node.parentCtx = self
84
+ return node
85
+ end
86
+
87
+ def getChild(i, type=nil )
88
+ if type.nil?
89
+ if self.children.length >= i then
90
+ return self.children[i]
91
+ end
92
+ else
93
+ for child in self.getChildren() do
94
+ next if not child.kind_of? type
95
+ return child if i==0
96
+ i = i - 1
97
+ end
98
+ end
99
+ return nil
100
+ end
101
+ def getChildren
102
+ @children
103
+ end
104
+ def getToken(ttype, i)
105
+ self.getChildren().each do |child|
106
+ next if not child.kind_of? TerminalNode
107
+ next if child.symbol.type != ttype
108
+ return child if i==0
109
+ i -= 1
110
+ i = i - 1
111
+ end
112
+ return nil
113
+ end
114
+ def getTokens(ttype)
115
+ return Array.new if self.getChildren().empty?
116
+ self.getChildren().map do |child|
117
+ next if not child.kind_of? TerminalNode
118
+ next if child.symbol.type != ttype
119
+ child
120
+ end.compact
121
+ end
122
+
123
+ def getTypedRuleContext(ctxType, i)
124
+ return self.getChild(i, ctxType)
125
+ end
126
+ def getTypedRuleContexts(ctxType)
127
+ return Array.new if self.getChildren().empty?
128
+ self.getChildren.map do |child|
129
+ next if not child.kind_of? ctxType
130
+ child
131
+ end.compact
132
+ end
133
+ def getChildCount
134
+ return self.children.length
135
+ end
136
+
137
+ def getSourceInterval
138
+ if self.start.nil? or self.stop.nil? then
139
+ return Antlr4::INVALID_INTERVAL
140
+ else
141
+ return [self.start.tokenIndex, self.stop.tokenIndex]
142
+ end
143
+ end
144
+ def to_s
145
+ p = nil
146
+ if parentCtx then
147
+ p = parentCtx.to_s
148
+ end
149
+ "#{self.class}:[#{invokingState}]#{p}"
150
+ end
151
+ end
152
+
153
+ # RuleContext.set_empty(ParserRuleContext.new())
154
+
155
+ class InterpreterRuleContext < ParserRuleContext
156
+
157
+ attr_accessor :ruleIndex
158
+ def initialize(parent, invokingStateNumber, rule_index)
159
+ super(parent, invokingStateNumber)
160
+ @ruleIndex = rule_index
161
+ end
162
+ end
@@ -0,0 +1,690 @@
1
+
2
+ class PredictionContext
3
+
4
+ # Represents {@code $} in local context prediction, which means wildcard.
5
+ # {@code#+x =#}.
6
+ @@EMPTY = nil
7
+ def self.EMPTY
8
+ @@EMPTY = EmptyPredictionContext.new if @@EMPTY.nil?
9
+ @@EMPTY
10
+ end
11
+ # Represents {@code $} in an array in full context mode, when {@code $}
12
+ # doesn't mean wildcard: {@code $ + x = [$,x]}. Here,
13
+ # {@code $} = {@link #EMPTY_RETURN_STATE}.
14
+ EMPTY_RETURN_STATE = 0x7FFFFFFF
15
+ def self.EMPTY_RETURN_STATE
16
+ PredictionContext::EMPTY_RETURN_STATE
17
+ end
18
+
19
+ @@globalNodeCount = 1
20
+ @@id = @@globalNodeCount
21
+
22
+ # Stores the computed hash code of this {@link PredictionContext}. The hash
23
+ # code is computed in parts to match the following reference algorithm.
24
+ #
25
+ # <pre>
26
+ # private int referenceHashCode() {
27
+ # int hash = {@link MurmurHash#initialize MurmurHash.initialize}({@link #INITIAL_HASH});
28
+ #
29
+ # for (int i = 0; i &lt; {@link #size()}; i++) {
30
+ # hash = {@link MurmurHash#update MurmurHash.update}(hash, {@link #getParent getParent}(i));
31
+ # }
32
+ #
33
+ # for (int i = 0; i &lt; {@link #size()}; i++) {
34
+ # hash = {@link MurmurHash#update MurmurHash.update}(hash, {@link #getReturnState getReturnState}(i));
35
+ # }
36
+ #
37
+ # hash = {@link MurmurHash#finish MurmurHash.finish}(hash, 2# {@link #size()});
38
+ # return hash;
39
+ # }
40
+ # </pre>
41
+ #/
42
+ attr_reader :cachedHashCode
43
+ def initialize(_cachedHashCode)
44
+ @cachedHashCode = _cachedHashCode
45
+ end
46
+
47
+ # This means only the {@link #EMPTY} context is in set.
48
+ def isEmpty
49
+ self.equal? PredictionContext.EMPTY
50
+ end
51
+ def hasEmptyPath
52
+ return self.getReturnState(self.length - 1) == PredictionContext::EMPTY_RETURN_STATE
53
+ end
54
+ def hash
55
+ return self.cachedHashCode
56
+ end
57
+ def self.calculateEmptyHashCode
58
+ "".hash
59
+ end
60
+ def self.calculateHashCode(parent, returnState)
61
+ "#{parent}#{returnState}".hash
62
+ end
63
+ end
64
+
65
+ # Used to cache {@link PredictionContext} objects. Its used for the shared
66
+ # context cash associated with contexts in DFA states. This cache
67
+ # can be used for both lexers and parsers.
68
+ class PredictionContextCache
69
+
70
+ attr_reader :cache
71
+ def initialize
72
+ @cache = Hash.new
73
+ end
74
+
75
+ # Add a context to the cache and return it. If the context already exists,
76
+ # return that one instead and do not add a new context to the cache.
77
+ # Protect shared cache from unsafe thread access.
78
+ #
79
+ def add(ctx)
80
+ if ctx.equal? PredictionContext.EMPTY then
81
+ return PredictionContext.EMPTY
82
+ end
83
+ existing = self.cache[ctx]
84
+ return existing if existing
85
+ self.cache[ctx] = ctx
86
+ return ctx
87
+ end
88
+ def get(ctx)
89
+ return self.cache[ctx]
90
+ end
91
+ def length
92
+ return self.cache.length
93
+ end
94
+ end
95
+
96
+ class SingletonPredictionContext < PredictionContext
97
+
98
+ def self.create(parent, returnState)
99
+ if returnState == PredictionContext::EMPTY_RETURN_STATE and parent.nil? then
100
+ # someone can pass in the bits of an array ctx that mean $
101
+ return PredictionContext.EMPTY
102
+ else
103
+ return SingletonPredictionContext.new(parent, returnState)
104
+ end
105
+ end
106
+
107
+ attr_reader :parentCtx, :returnState
108
+ attr_accessor :cache_string
109
+ def initialize( parent, returnState)
110
+ #assert returnState!=ATNState.INVALID_STATE_NUMBER
111
+ if parent.nil? then
112
+ hashCode = PredictionContext.calculateEmptyHashCode
113
+ else
114
+ hashCode = PredictionContext.calculateHashCode(parent, returnState)
115
+ end
116
+ super(hashCode)
117
+ @parentCtx = parent
118
+ @returnState = returnState
119
+ end
120
+
121
+ def length
122
+ return 1
123
+ end
124
+
125
+ def getParent(index)
126
+ # assert index == 0
127
+ return self.parentCtx
128
+ end
129
+
130
+ def getReturnState(index)
131
+ #assert index == 0
132
+ return self.returnState
133
+ end
134
+
135
+ def eql?(other)
136
+ self == other
137
+ end
138
+ def ==(other)
139
+ return true if self.equal?(other)
140
+ return false unless self.class == other.class
141
+ if self.hash != other.hash
142
+ false # can't be same if hash is different
143
+ else
144
+ self.returnState == other.returnState and \
145
+ (self.parentCtx.equal?(other.parentCtx) \
146
+ or self.parentCtx==other.parentCtx )
147
+ end
148
+ end
149
+ def hash
150
+ return self.cachedHashCode
151
+ end
152
+
153
+ def to_s
154
+ @cache_string = mk_string if @cache_string.nil?
155
+ return @cache_string
156
+ end
157
+ def mk_string
158
+ if @parentCtx.nil? then
159
+ if @returnState == PredictionContext::EMPTY_RETURN_STATE
160
+ return "$"
161
+ else
162
+ return @returnState.to_s
163
+ end
164
+ else
165
+ return "#{@returnState} #{@parentCtx}"
166
+ end
167
+ end
168
+ end
169
+ class EmptyPredictionContext < SingletonPredictionContext
170
+
171
+ def initialize(h=nil)
172
+ super(nil, PredictionContext::EMPTY_RETURN_STATE )
173
+ @cachedHashCode = "".hash
174
+ end
175
+
176
+ def isEmpty
177
+ true
178
+ end
179
+
180
+ def getParent(index)
181
+ nil
182
+ end
183
+
184
+ def getReturnState(index)
185
+ PredictionContext::EMPTY_RETURN_STATE # self.returnState
186
+ end
187
+
188
+ # def ==(other)
189
+ # self.equal? other
190
+ # end
191
+
192
+ def to_s
193
+ "$"
194
+ end
195
+ end
196
+
197
+ class ArrayPredictionContext < PredictionContext
198
+ # Parent can be null only if full ctx mode and we make an array
199
+ # from {@link #EMPTY} and non-empty. We merge {@link #EMPTY} by using null parent and
200
+ # returnState == {@link #EMPTY_RETURN_STATE}.
201
+
202
+ def initialzie(parents, returnStates)
203
+ super(PredictionContext.calculateHashCode(parents, returnStates))
204
+ # assert parents is not None and len(parents)>0
205
+ # assert returnStates is not None and len(returnStates)>0
206
+ self.parents = parents
207
+ self.returnStates = returnStates
208
+ end
209
+
210
+ def isEmpty
211
+ # since EMPTY_RETURN_STATE can only appear in the last position, we
212
+ # don't need to verify that size==1
213
+ return self.returnStates[0]==PredictionContext::EMPTY_RETURN_STATE
214
+ end
215
+
216
+ def length
217
+ return self.returnStates.length()
218
+ end
219
+
220
+ def getParent(index)
221
+ return self.parents[index]
222
+ end
223
+ def getReturnState(index)
224
+ return self.returnStates[index]
225
+ end
226
+ def eql?(other)
227
+ self == other
228
+ end
229
+ def ==(other)
230
+ return false if self.class != other.class
231
+ return true if self.equal?(other)
232
+ if self.hash != other.hash
233
+ false # can't be same if hash is different
234
+ else
235
+ self.returnStates==other.returnStates and self.parents==other.parents
236
+ end
237
+ end
238
+
239
+ def to_s
240
+ if self.isEmpty()
241
+ return "[]"
242
+ end
243
+ StringIO.open do |buf|
244
+ buf.write("[")
245
+ for i in 0..self.returnStates.length-1 do
246
+ buf.write(", ") if i>0
247
+ if self.returnStates[i]==PredictionContext::EMPTY_RETURN_STATE
248
+ buf.write("$")
249
+ next
250
+ end
251
+ buf.write(self.returnStates[i].to_s)
252
+ if not self.parents[i].nil?
253
+ buf.write(' ')
254
+ buf.write(self.parents[i].to_s())
255
+ end
256
+ end
257
+ buf.write("]")
258
+ return buf.string()
259
+ end
260
+ end
261
+ end
262
+ # Convert a {@link RuleContext} tree to a {@link PredictionContext} graph.
263
+ # Return {@link #EMPTY} if {@code outerContext} is empty or null.
264
+ #/
265
+
266
+ module PredictionContextFunctions
267
+
268
+ def self.included(klass)
269
+ klass.send(:include, PredictionContextFunctions::Methods )
270
+ klass.send(:extend, PredictionContextFunctions::Methods )
271
+ end
272
+
273
+ module Methods
274
+ def PredictionContextFromRuleContext(atn, outerContext=nil)
275
+ outerContext = RuleContext.EMPTY if outerContext.nil?
276
+
277
+ # if we are in RuleContext of start rule, s, then PredictionContext
278
+ # is EMPTY. Nobody called us. (if we are empty, return empty)
279
+ if outerContext.parentCtx.nil? or RuleContext.EMPTY == outerContext
280
+ return PredictionContext.EMPTY
281
+ end
282
+
283
+ # If we have a parent, convert it to a PredictionContext graph
284
+ parent = PredictionContextFromRuleContext(atn, outerContext.parentCtx)
285
+ state = atn.states[outerContext.invokingState]
286
+ transition = state.transitions[0]
287
+ return SingletonPredictionContext.create(parent, transition.followState.stateNumber)
288
+ end
289
+
290
+
291
+ def calculateListsHashCode(parents, returnStates)
292
+ str_parents = parents.map{|parent| parent.to_s }
293
+ str_rs = returnStates.map{|r| r.to_s }
294
+ return [str_parents,str_rs].flatten.join('').hash
295
+ end
296
+ #def merge(a:PredictionContext, b:PredictionContext, rootIsWildcard:bool, mergeCache:dict):
297
+ def merge(a, b, rootIsWildcard, mergeCache)
298
+ #assert a is not None and b is not None # must be empty context, never null
299
+
300
+ # share same graph if both same
301
+ return a if a==b
302
+
303
+ if a.kind_of? SingletonPredictionContext and b.kind_of? SingletonPredictionContext
304
+ return mergeSingletons(a, b, rootIsWildcard, mergeCache)
305
+ end
306
+
307
+ # At least one of a or b is array
308
+ # If one is $ and rootIsWildcard, return $ as# wildcard
309
+ if rootIsWildcard then
310
+ return a if a.kind_of? EmptyPredictionContext
311
+ return b if b.kind_of? EmptyPredictionContext
312
+ end
313
+ # convert singleton so both are arrays to normalize
314
+ if a.kind_of? SingletonPredictionContext
315
+ a = ArrayPredictionContext.new(a)
316
+ end
317
+ if b.kind_of? SingletonPredictionContext
318
+ b = ArrayPredictionContext.new(b)
319
+ end
320
+ return mergeArrays(a, b, rootIsWildcard, mergeCache)
321
+ end
322
+
323
+ #
324
+ # Merge two {@link SingletonPredictionContext} instances.
325
+ #
326
+ # <p>Stack tops equal, parents merge is same; return left graph.<br>
327
+ # <embed src="images/SingletonMerge_SameRootSamePar.svg" type="image/svg+xml"/></p>
328
+ #
329
+ # <p>Same stack top, parents differ; merge parents giving array node, then
330
+ # remainders of those graphs. A new root node is created to point to the
331
+ # merged parents.<br>
332
+ # <embed src="images/SingletonMerge_SameRootDiffPar.svg" type="image/svg+xml"/></p>
333
+ #
334
+ # <p>Different stack tops pointing to same parent. Make array node for the
335
+ # root where both element in the root point to the same (original)
336
+ # parent.<br>
337
+ # <embed src="images/SingletonMerge_DiffRootSamePar.svg" type="image/svg+xml"/></p>
338
+ #
339
+ # <p>Different stack tops pointing to different parents. Make array node for
340
+ # the root where each element points to the corresponding original
341
+ # parent.<br>
342
+ # <embed src="images/SingletonMerge_DiffRootDiffPar.svg" type="image/svg+xml"/></p>
343
+ #
344
+ # @param a the first {@link SingletonPredictionContext}
345
+ # @param b the second {@link SingletonPredictionContext}
346
+ # @param rootIsWildcard {@code true} if this is a local-context merge,
347
+ # otherwise false to indicate a full-context merge
348
+ # @param mergeCache
349
+ #/
350
+ #def mergeSingletons(a:SingletonPredictionContext, b:SingletonPredictionContext, rootIsWildcard:bool, mergeCache:dict):
351
+ def mergeSingletons(a, b, rootIsWildcard, mergeCache)
352
+ if mergeCache then
353
+ previous = mergeCache.get(a,b)
354
+ if not previous.nil?
355
+ return previous
356
+ end
357
+ previous = mergeCache.get(b,a)
358
+ if not previous.nil?
359
+ return previous
360
+ end
361
+ end
362
+ rootMerge = mergeRoot(a, b, rootIsWildcard)
363
+ if rootMerge then
364
+ if mergeCache then
365
+ mergeCache.put(a, b, rootMerge)
366
+ end
367
+ return rootMerge
368
+ end
369
+
370
+ if a.returnState==b.returnState then
371
+ parent = merge(a.parentCtx, b.parentCtx, rootIsWildcard, mergeCache)
372
+ # if parent is same as existing a or b parent or reduced to a parent, return it
373
+ return a if parent == a.parentCtx # ax + bx = ax, if a=b
374
+ return b if parent == b.parentCtx # ax + bx = bx, if a=b
375
+ # else: ax + ay = a'[x,y]
376
+ # merge parents x and y, giving array node with x,y then remainders
377
+ # of those graphs. dup a, a' points at merged array
378
+ # new joined parent so create new singleton pointing to it, a'
379
+ a_ = SingletonPredictionContext.create(parent, a.returnState)
380
+ mergeCache.put(a, b, a_) if mergeCache
381
+ return a_
382
+ else # a != b payloads differ
383
+ # see if we can collapse parents due to $+x parents if local ctx
384
+ singleParent = nil
385
+ if a.equal?(b) or (a.parentCtx and a.parentCtx==b.parentCtx) # ax + bx = [a,b]x
386
+ singleParent = a.parentCtx
387
+ end
388
+ if not singleParent.nil? # parents are same
389
+ # sort payloads and use same parent
390
+ payloads = [ a.returnState, b.returnState ]
391
+ if a.returnState > b.returnState then
392
+ payloads[0] = b.returnState
393
+ payloads[1] = a.returnState
394
+ end
395
+ parents = [singleParent, singleParent]
396
+ a_ = ArrayPredictionContext.new(parents, payloads)
397
+ mergeCache.put(a, b, a_) if mergeCache
398
+ return a_
399
+ end
400
+ # parents differ and can't merge them. Just pack together
401
+ # into array; can't merge.
402
+ # ax + by = [ax,by]
403
+ payloads = [ a.returnState, b.returnState ]
404
+ parents = [ a.parentCtx, b.parentCtx ]
405
+ if a.returnState > b.returnState # sort by payload
406
+ payloads[0] = b.returnState
407
+ payloads[1] = a.returnState
408
+ parents = [ b.parentCtx, a.parentCtx ]
409
+ end
410
+ a_ = ArrayPredictionContext.new(parents, payloads)
411
+ mergeCache.put(a, b, a_) if mergeCache
412
+ return a_
413
+ end
414
+ end
415
+
416
+
417
+ #
418
+ # Handle case where at least one of {@code a} or {@code b} is
419
+ # {@link #EMPTY}. In the following diagrams, the symbol {@code $} is used
420
+ # to represent {@link #EMPTY}.
421
+ #
422
+ # <h2>Local-Context Merges</h2>
423
+ #
424
+ # <p>These local-context merge operations are used when {@code rootIsWildcard}
425
+ # is true.</p>
426
+ #
427
+ # <p>{@link #EMPTY} is superset of any graph; return {@link #EMPTY}.<br>
428
+ # <embed src="images/LocalMerge_EmptyRoot.svg" type="image/svg+xml"/></p>
429
+ #
430
+ # <p>{@link #EMPTY} and anything is {@code #EMPTY}, so merged parent is
431
+ # {@code #EMPTY}; return left graph.<br>
432
+ # <embed src="images/LocalMerge_EmptyParent.svg" type="image/svg+xml"/></p>
433
+ #
434
+ # <p>Special case of last merge if local context.<br>
435
+ # <embed src="images/LocalMerge_DiffRoots.svg" type="image/svg+xml"/></p>
436
+ #
437
+ # <h2>Full-Context Merges</h2>
438
+ #
439
+ # <p>These full-context merge operations are used when {@code rootIsWildcard}
440
+ # is false.</p>
441
+ #
442
+ # <p><embed src="images/FullMerge_EmptyRoots.svg" type="image/svg+xml"/></p>
443
+ #
444
+ # <p>Must keep all contexts; {@link #EMPTY} in array is a special value (and
445
+ # null parent).<br>
446
+ # <embed src="images/FullMerge_EmptyRoot.svg" type="image/svg+xml"/></p>
447
+ #
448
+ # <p><embed src="images/FullMerge_SameRoot.svg" type="image/svg+xml"/></p>
449
+ #
450
+ # @param a the first {@link SingletonPredictionContext}
451
+ # @param b the second {@link SingletonPredictionContext}
452
+ # @param rootIsWildcard {@code true} if this is a local-context merge,
453
+ # otherwise false to indicate a full-context merge
454
+ #/
455
+ #def mergeRoot(a:SingletonPredictionContext, b:SingletonPredictionContext, rootIsWildcard:bool):
456
+ def mergeRoot(a, b, rootIsWildcard)
457
+ if rootIsWildcard
458
+ return PredictionContext.EMPTY if PredictionContext.EMPTY == a ## + b =#
459
+ return PredictionContext.EMPTY if PredictionContext.EMPTY == b # a +# =#
460
+ else
461
+ if PredictionContext.EMPTY == a and PredictionContext.EMPTY == b then
462
+ return PredictionContext.EMPTY # $ + $ = $
463
+ elsif PredictionContext.EMPTY == a # $ + x = [$,x]
464
+ payloads = [ b.returnState, PredictionContext::EMPTY_RETURN_STATE ]
465
+ parents = [ b.parentCtx, nil ]
466
+ return ArrayPredictionContext.new(parents, payloads)
467
+ elsif PredictionContext.EMPTY == b # x + $ = [$,x] ($ is always first if present)
468
+ payloads = [ a.returnState, PredictionContext::EMPTY_RETURN_STATE ]
469
+ parents = [ a.parentCtx, nil ]
470
+ return ArrayPredictionContext.new(parents, payloads)
471
+ end
472
+ end
473
+ return nil
474
+ end
475
+
476
+ #
477
+ # Merge two {@link ArrayPredictionContext} instances.
478
+ #
479
+ # <p>Different tops, different parents.<br>
480
+ # <embed src="images/ArrayMerge_DiffTopDiffPar.svg" type="image/svg+xml"/></p>
481
+ #
482
+ # <p>Shared top, same parents.<br>
483
+ # <embed src="images/ArrayMerge_ShareTopSamePar.svg" type="image/svg+xml"/></p>
484
+ #
485
+ # <p>Shared top, different parents.<br>
486
+ # <embed src="images/ArrayMerge_ShareTopDiffPar.svg" type="image/svg+xml"/></p>
487
+ #
488
+ # <p>Shared top, all shared parents.<br>
489
+ # <embed src="images/ArrayMerge_ShareTopSharePar.svg" type="image/svg+xml"/></p>
490
+ #
491
+ # <p>Equal tops, merge parents and reduce top to
492
+ # {@link SingletonPredictionContext}.<br>
493
+ # <embed src="images/ArrayMerge_EqualTop.svg" type="image/svg+xml"/></p>
494
+ #/
495
+ #def mergeArrays(a:ArrayPredictionContext, b:ArrayPredictionContext, rootIsWildcard:bool, mergeCache:dict):
496
+ def mergeArrays(a, b, rootIsWildcard, mergeCache)
497
+ if mergeCache
498
+ previous = mergeCache.get(a,b)
499
+ return previous unless previous.nil?
500
+ previous = mergeCache.get(b,a)
501
+ return previous unless previous.nil?
502
+ end
503
+ # merge sorted payloads a + b => M
504
+ i = 0 # walks a
505
+ j = 0 # walks b
506
+ k = 0 # walks target M array
507
+
508
+ mergedReturnStates = Array.new(a.returnState.length + b.returnStates.length)
509
+ mergedParents = Array.new(mergedReturnStates.length)
510
+ # walk and merge to yield mergedParents, mergedReturnStates
511
+ while i<a.returnStates.length and j<b.returnStates.length do
512
+ a_parent = a.parents[i]
513
+ b_parent = b.parents[j]
514
+ if a.returnStates[i]==b.returnStates[j] then
515
+ # same payload (stack tops are equal), must yield merged singleton
516
+ payload = a.returnStates[i]
517
+ # $+$ = $
518
+ bothDollars = (payload == PredictionContext::EMPTY_RETURN_STATE and \
519
+ a_parent.nil? and b_parent.nil? )
520
+ ax_ax = ( ! a_parent.nil? and ! b_parent.nil?) and a_parent==b_parent # ax+ax -> ax
521
+ if bothDollars or ax_ax
522
+ mergedParents[k] = a_parent # choose left
523
+ mergedReturnStates[k] = payload
524
+ else # ax+ay -> a'[x,y]
525
+ mergedParent = merge(a_parent, b_parent, rootIsWildcard, mergeCache)
526
+ mergedParents[k] = mergedParent
527
+ mergedReturnStates[k] = payload
528
+ end
529
+ i = i + 1 # hop over left one as usual
530
+ j = j + 1 # but also skip one in right side since we merge
531
+ elsif a.returnStates[i]<b.returnStates[j] # copy a[i] to M
532
+ mergedParents[k] = a_parent
533
+ mergedReturnStates[k] = a.returnStates[i]
534
+ i = i + 1
535
+ else # b > a, copy b[j] to M
536
+ mergedParents[k] = b_parent
537
+ mergedReturnStates[k] = b.returnStates[j]
538
+ j = j + 1
539
+ end
540
+ k = k + 1
541
+ end
542
+ # copy over any payloads remaining in either array
543
+ if i < a.returnStates.length then
544
+ for p in i..a.returnStates.length()-1 do
545
+ mergedParents[k] = a.parents[p]
546
+ mergedReturnStates[k] = a.returnStates[p]
547
+ k = k + 1
548
+ end
549
+ else
550
+ for p in j..b.returnStates.length()-1 do
551
+ mergedParents[k] = b.parents[p]
552
+ mergedReturnStates[k] = b.returnStates[p]
553
+ k = k + 1
554
+ end
555
+ end
556
+
557
+ # trim merged if we combined a few that had same stack tops
558
+ if k < mergedParents.length() # write index < last position; trim
559
+ if k == 1 # for just one merged element, return singleton top
560
+ a_ = SingletonPredictionContext.create(mergedParents[0], mergedReturnStates[0])
561
+ mergeCache.put(a,b,a_) if mergeCache
562
+ return a_
563
+ end
564
+ mergedParents = mergedParents[0..k-1]
565
+ mergedReturnStates = mergedReturnStates[0..k-1]
566
+ end
567
+ capM = ArrayPredictionContext.new(mergedParents, mergedReturnStates)
568
+
569
+ # if we created same array as a or b, return that instead
570
+ # TODO: track whether this is possible above during merge sort for speed
571
+ if capM==a
572
+ mergeCache.put(a,b,a) if mergeCache
573
+ return a
574
+ end
575
+ if capM==b
576
+ mergeCache.put(a,b,b) if mergeCache
577
+ return b
578
+ end
579
+ combineCommonParents(mergedParents)
580
+
581
+ mergeCache.put(a,b,capM) if mergeCache
582
+ return capM
583
+ end
584
+
585
+ #
586
+ # Make pass over all <em>M</em> {@code parents}; merge any {@code equals()}
587
+ # ones.
588
+ #/
589
+ def combineCommonParents(parents)
590
+ uniqueParents = Hash.new
591
+
592
+ parents.each{|parent|
593
+ if not uniqueParents.has_key? parent
594
+ uniqueParents[parent] = parent
595
+ end
596
+ }
597
+ parents.each_index {|p|
598
+ parents[p] = uniqueParents[parents[p]]
599
+ }
600
+ end
601
+ def getCachedPredictionContext(context, contextCache, visited)
602
+ if context.isEmpty()
603
+ return context
604
+ end
605
+ existing = visited[context]
606
+ return existing unless existing.nil?
607
+ existing = contextCache.get(context)
608
+ if not existing.nil? then
609
+ visited[context] = existing
610
+ return existing
611
+ end
612
+ changed = false
613
+ parents = Array.new context.length()
614
+ parents.each_index do |i|
615
+ parent = getCachedPredictionContext(context.getParent(i), contextCache, visited)
616
+ if changed or parent != context.getParent(i)
617
+ if not changed then
618
+ parents = Array.new context.length()
619
+ context.each_index {|j| #for j in range(0, len(context)):
620
+ parents[j] = context.getParent(j)
621
+ }
622
+ changed = true
623
+ end
624
+ parents[i] = parent
625
+ end
626
+ end
627
+ if not changed
628
+ contextCache.add(context)
629
+ visited[context] = context
630
+ return context
631
+ end
632
+ updated = nil
633
+ if parents.length == 0
634
+ updated = PredictionContext.EMPTY
635
+ elsif parents.length == 1
636
+ updated = SingletonPredictionContext.create(parents[0], context.getReturnState(0))
637
+ else
638
+ updated = ArrayPredictionContext.new(parents, context.returnStates)
639
+ end
640
+
641
+ contextCache.add(updated)
642
+ visited[updated] = updated
643
+ visited[context] = updated
644
+
645
+ return updated
646
+ end
647
+
648
+ # # extra structures, but cut/paste/morphed works, so leave it.
649
+ # # seems to do a breadth-first walk
650
+ # public static List<PredictionContext> getAllNodes(PredictionContext context) {
651
+ # Map<PredictionContext, PredictionContext> visited =
652
+ # new IdentityHashMap<PredictionContext, PredictionContext>();
653
+ # Deque<PredictionContext> workList = new ArrayDeque<PredictionContext>();
654
+ # workList.add(context);
655
+ # visited.put(context, context);
656
+ # List<PredictionContext> nodes = new ArrayList<PredictionContext>();
657
+ # while (!workList.isEmpty()) {
658
+ # PredictionContext current = workList.pop();
659
+ # nodes.add(current);
660
+ # for (int i = 0; i < current.size(); i++) {
661
+ # PredictionContext parent = current.getParent(i);
662
+ # if ( parent!=null && visited.put(parent, parent) == null) {
663
+ # workList.push(parent);
664
+ # }
665
+ # }
666
+ # }
667
+ # return nodes;
668
+ # }
669
+ # ter's recursive version of Sam's getAllNodes()
670
+ def getAllContextNodes(context, nodes=nil, visited=nil)
671
+ if nodes.nil?
672
+ nodes = Array.new
673
+ return getAllContextNodes(context, nodes, visited)
674
+ elsif visited.nil?
675
+ visited = Hash.new
676
+ return getAllContextNodes(context, nodes, visited)
677
+ else
678
+ if context.nil? or visited.has_key? context
679
+ return nodes
680
+ end
681
+ visited[context] = context
682
+ nodes.add(context)
683
+ for i in 0..context.length do
684
+ getAllContextNodes(context.getParent(i), nodes, visited)
685
+ end
686
+ return nodes
687
+ end
688
+ end
689
+ end
690
+ end