parser: ComputeProdLocationVisitor remember the last token instead of the location
[nit.git] / src / parser / parser_work.nit
index 5652cf5..363faf4 100644 (file)
@@ -20,35 +20,26 @@ intrude import parser_prod
 # State of the parser automata as stored in the parser stack.
 private class State
        # The internal state number
-       readable writable var _state: Int
+       var state: Int
 
        # The node stored with the state in the stack
-       readable writable var _nodes: nullable Object
-
-       init(state: Int, nodes: nullable Object)
-       do
-               _state = state
-               _nodes = nodes
-       end
+       var nodes: nullable Object
 end
 
+# The parser of the Nit language.
 class Parser
        super TablesCapable
        # Associated lexer
-       var _lexer: Lexer
+       var lexer: Lexer
 
        # Stack of pushed states and productions
-       var _stack: Array[State]
+       private var stack = new Array[State]
 
        # Position in the stack
-       var _stack_pos: Int
+       private var stack_pos: Int = -1
 
-       # Create a new parser based on a given lexer
-       init(lexer: Lexer)
+       init
        do
-               _lexer = lexer
-               _stack = new Array[State]
-               _stack_pos = -1
                build_reduce_table
        end
 
@@ -83,8 +74,8 @@ class Parser
                _stack_pos = pos
                if pos < _stack.length then
                        var state = _stack[pos]
-                       state.state = numstate
-                       state.nodes = list_node
+                       state._state = numstate
+                       state._nodes = list_node
                else
                        _stack.push(new State(numstate, list_node))
                end
@@ -93,13 +84,13 @@ class Parser
        # The current state
        private fun state: Int
        do
-               return _stack[_stack_pos].state
+               return _stack[_stack_pos]._state
        end
 
        # Pop something from the stack state
        private fun pop: nullable Object
        do
-               var res = _stack[_stack_pos].nodes
+               var res = _stack[_stack_pos]._nodes
                _stack_pos = _stack_pos -1
                return res
        end
@@ -154,43 +145,52 @@ class Parser
                                return node
                        else if action_type == 3 then # ERROR
                                # skip injected tokens
-                               while token._location == null do token = lexer.next
-                               var node2 = new AParserError.init_parser_error("Syntax error: unexpected {token}.", token.location, token)
+                               while not isset token._location do token = lexer.next
+                               var node2 = new AParserError.init_parser_error("Syntax Error: unexpected {token}.", token.location, token)
                                var node = new Start(null, node2)
                                return node
                        end
                end
        end
 
-       var _reduce_table: Array[ReduceAction]
+       private var reduce_table: Array[ReduceAction] is noinit
        private fun build_reduce_table is abstract
 end
 
 redef class Prod
        # Location on the first token after the start of a production
-       # So outside the production for epilon production
-       var _first_location: nullable Location
+       # So outside the production for epsilon production
+       var first_location: nullable Location
+
+       # Join the text of all visited tokens
+       fun collect_text: String
+       do
+               var v = new TextCollectorVisitor
+               v.enter_visit(self)
+               assert v.text != ""
+               return v.text
+       end
 end
 
 # Find location of production nodes
 # Uses existing token locations to infer location of productions.
 private class ComputeProdLocationVisitor
        super Visitor
-       # Currenlty visited productions that need a first token
-       var _need_first_prods: Array[Prod] = new Array[Prod]
+       # Currently visited productions that need a first token
+       var need_first_prods = new Array[Prod]
 
        # Already visited epsilon productions that waits something after them
-       var _need_after_epsilons: Array[Prod] = new Array[Prod]
+       var need_after_epsilons = new Array[Prod]
 
-       # Location of the last visited token in the current production
-       var _last_location: nullable Location = null
+       # The last visited token in the current production
+       var last_token: nullable Token = null
 
        redef fun visit(n: ANode)
        do
                if n isa Token then
+                       if not isset n._location then return
                        var loc = n._location
-                       if loc == null then return
-                       _last_location = loc
+                       _last_token = n
 
                        # Add a first token to productions that need one
                        if not _need_first_prods.is_empty then
@@ -217,10 +217,13 @@ private class ComputeProdLocationVisitor
                        var startl = n._first_location
                        if startl != null then
                                # Non-epsilon production
-                               var endl = _last_location
-                               assert endl != null
+                               var endl = _last_token.location
 
-                               n.location = new Location(startl.file, startl.line_start, endl.line_end, startl.column_start, endl.column_end)
+                               if startl == endl then
+                                       n.location = startl
+                               else
+                                       n.location = new Location(startl.file, startl.line_start, endl.line_end, startl.column_start, endl.column_end)
+                               end
 
                                if not _need_after_epsilons.is_empty then
                                        var loc = new Location(endl.file, endl.line_end, endl.line_end, endl.column_end, endl.column_end)
@@ -236,11 +239,20 @@ private class ComputeProdLocationVisitor
                        end
                end
        end
+end
 
-       init do end
+private class TextCollectorVisitor
+       super Visitor
+       var text: String = ""
+       redef fun visit(n)
+       do
+               if n isa Token then text += n.text
+               n.visit_all(self)
+       end
 end
 
-# Each reduca action has its own class, this one is the root of the hierarchy.
+
+# Each reduce action has its own class, this one is the root of the hierarchy.
 private abstract class ReduceAction
        fun action(p: Parser) is abstract
        fun concat(l1, l2 : Array[Object]): Array[Object]
@@ -249,6 +261,5 @@ private abstract class ReduceAction
                l1.append(l2)
                return l1
        end
-       var _goto: Int
-       init(g: Int) do _goto = g
+       var goto: Int
 end