parser: `Visitor::visit` does not accepts `null`
[nit.git] / src / parser / xss / parser.xss
index c72018f..e2fabc5 100644 (file)
@@ -33,7 +33,7 @@ private class State
 end
 
 class Parser
-special ParserTable
+       super TablesCapable
        # Associated lexer
        var _lexer: Lexer
 
@@ -49,8 +49,6 @@ special ParserTable
                _lexer = lexer
                _stack = new Array[State]
                _stack_pos = -1
-               build_goto_table
-               build_action_table
                build_reduce_table
        end
 
@@ -58,24 +56,24 @@ special ParserTable
        private fun go_to(index: Int): Int
        do
                var state = state
-               var table = _goto_table[index]
                var low = 1
-               var high = table.length/2 - 1
+               var high = parser_goto(index, 0) - 1
 
                while low <= high do
                        var middle = (low + high) / 2
-                       var subindex = middle * 2
+                       var subindex = middle * 2 + 1 # +1 because parser_goto(index, 0) is the length
 
-                       if state < table[subindex] then
+                       var goal = parser_goto(index, subindex)
+                       if state < goal then
                                high = middle - 1
-                       else if state > table[subindex] then
+                       else if state > goal then
                                low = middle + 1
                        else
-                               return table[subindex + 1]
+                               return parser_goto(index, subindex+1)
                        end
                end
 
-               return table[1] # Default value
+               return parser_goto(index, 2) # Default value
        end
 
        # Push someting in the state stack
@@ -118,26 +116,27 @@ special ParserTable
                                return new Start(null, token)
                        end
 
+                       var state = self.state
                        var index = token.parser_index
-                       var table = _action_table[state]
-                       var action_type = table[1]
-                       var action_value = table[2]
+                       var action_type = parser_action(state, 2)
+                       var action_value = parser_action(state, 3)
 
                        var low = 1
-                       var high = table.length/3 - 1
+                       var high = parser_action(state, 0) - 1
 
                        while low <= high do
                                var middle = (low + high) / 2
-                               var subindex = middle * 3
+                               var subindex = middle * 3 + 1 # +1 because parser_action(state, 0) is the length
 
-                               if index < table[subindex] then
+                               var goal = parser_action(state, subindex)
+                               if index < goal then
                                        high = middle - 1
-                               else if index > table[subindex] then
+                               else if index > goal then
                                        low = middle + 1
                                else
-                                       action_type = table[subindex + 1]
-                                       action_value = table[subindex + 2]
-                                       high = low -1 # break
+                                       action_type = parser_action(state, subindex+1)
+                                       action_value = parser_action(state, subindex+2)
+                                       break
                                end
                        end
 
@@ -154,13 +153,11 @@ special ParserTable
                                (new ComputeProdLocationVisitor).enter_visit(node)
                                return node
                        else if action_type == 3 then # ERROR
-                               var node2 = new PError.init_error("Syntax error: unexpected token.", token.location)
+                               var node2 = new PParserError.init_parser_error("Syntax error: unexpected {token}.", token.location, token)
                                var node = new Start(null, node2)
                                return node
                        end
-                       if false then break # FIXME remove once unreach loop exits are in c_src
                end
-               abort # FIXME remove once unreach loop exits are in c_src
        end
 
        var _reduce_table: Array[ReduceAction]
@@ -168,7 +165,7 @@ special ParserTable
        do
                _reduce_table = new Array[ReduceAction].with_items(
 $ foreach {rules/rule}
-                       new ReduceAction@index[-sep ','-]
+                       new ReduceAction@index(@leftside)[-sep ','-]
 $ end foreach
                )
        end
@@ -187,7 +184,7 @@ end
 # Find location of production nodes
 # Uses existing token locations to infer location of productions.
 private class ComputeProdLocationVisitor
-special Visitor
+       super Visitor
        # Currenlty visited productions that need a first token
        var _need_first_prods: Array[Prod] = new Array[Prod]
 
@@ -200,29 +197,31 @@ special Visitor
        # Location of the last visited token in the current production
        var _last_location: nullable Location = null
 
-       redef fun visit(n: nullable PNode)
+       redef fun visit(n: PNode)
        do
-               if n == null then
-                       return
-               else if n isa Token then
+               if n isa Token then
                        var loc = n.location
                        _last_location = loc
 
                        # Add a first token to productions that need one
-                       for no in _need_first_prods do
-                               no._first_location = loc
+                       if not _need_first_prods.is_empty then
+                               for no in _need_first_prods do
+                                       no._first_location = loc
+                               end
+                               _need_first_prods.clear
                        end
-                       _need_first_prods.clear
 
                        # Find location for already visited epsilon production that need one
-                       for no in _need_after_epsilons do
-                               # Epsilon production that is in the middle of a non-epsilon production
-                               # The epsilon production has both a token before and after it
-                               var endl = loc
-                               var startl = no._last_location
-                               no.location = new Location(endl.file, startl.line_end, endl.line_start, startl.column_end, endl.column_start)
+                       if not _need_after_epsilons.is_empty then
+                               for no in _need_after_epsilons do
+                                       # Epsilon production that is in the middle of a non-epsilon production
+                                       # The epsilon production has both a token before and after it
+                                       var endl = loc
+                                       var startl = no._last_location
+                                       no.location = new Location(endl.file, startl.line_end, endl.line_start, startl.column_end, endl.column_start)
+                               end
+                               _need_after_epsilons.clear
                        end
-                       _need_after_epsilons.clear
                else
                        assert n isa Prod
                        _need_first_prods.add(n)
@@ -241,19 +240,23 @@ special Visitor
 
                                n.location = new Location(startl.file, startl.line_start, endl.line_end, startl.column_start, endl.column_end)
 
-                               for no in _need_before_epsilons do
-                                       # Epsilon production that starts the current non-epsilon production
-                                       #var startl = n.location
-                                       no.location = new Location(startl.file, startl.line_start, startl.line_start, startl.column_start, startl.column_start)
+                               if not _need_before_epsilons.is_empty then
+                                       var loc = new Location(startl.file, startl.line_start, startl.line_start, startl.column_start, startl.column_start)
+                                       for no in _need_before_epsilons do
+                                               # Epsilon production that starts the current non-epsilon production
+                                               no.location = loc
+                                       end
+                                       _need_before_epsilons.clear
                                end
-                               _need_before_epsilons.clear
 
-                               for no in _need_after_epsilons do
-                                       # Epsilon production that finishes the current non-epsilon production
-                                       #var endl = n.location
-                                       no.location = new Location(endl.file, endl.line_end, endl.line_end, endl.column_end, endl.column_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)
+                                       for no in _need_after_epsilons do
+                                               # Epsilon production that finishes the current non-epsilon production
+                                               no.location = loc
+                                       end
+                                       _need_after_epsilons.clear
                                end
-                               _need_after_epsilons.clear
                        else
                                # No first token means epsilon production (or "throw all my tokens" production)
                                # So, it must be located it later
@@ -280,11 +283,13 @@ private abstract class ReduceAction
                l1.append(l2)
                return l1
        end
+       var _goto: Int
+       init(g: Int) do _goto = g
 end
 
 $ foreach {rules/rule}
 private class ReduceAction@index
-special ReduceAction
+       super ReduceAction
        redef fun action(p: Parser)
        do
                                        var node_list: nullable Object = null
@@ -313,6 +318,7 @@ $     when {@cmd='MAKELIST'}
                                        var ${translate(@result,"ABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwxyz")} = new Array[Object]
 $     end
 $     when {@cmd='MAKENODE'}
+$      if {count(arg)!=0}
                                        var ${translate(@result,"ABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwxyz")}: nullable @etype = new @etype.init_${translate(@etype,"ABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwxyz")}(
 $       foreach {arg}
 $           if @null
@@ -322,6 +328,9 @@ $           else
 $           end
 $       end foreach
                                        )
+$      else
+                                       var ${translate(@result,"ABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwxyz")}: nullable @etype = new @etype.init_${translate(@etype,"ABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwxyz")}
+$      end
 $     end
 $     when {@cmd='RETURNNODE'}
 $       if @null
@@ -335,51 +344,40 @@ $     when {@cmd='RETURNLIST'}
 $     end
 $   end choose
 $   end foreach
-                                       p.push(p.go_to(@leftside), node_list)
+                                       p.push(p.go_to(_goto), node_list)
        end
-init do end
 end
 $ end foreach
 $ end template
 
-$ template make_parser_tables()
-# Parser that build a full AST
-abstract class ParserTable
-       var _action_table: Array[Array[Int]]
-       private fun build_action_table
-       do
-               _action_table = once [
+$ template make_parser_table()
 $ foreach {parser_data/action_table/row}
-                       action_table_row${position()}[-sep ','-]
+static int parser_action_row${position()}[] = {
+       ${count(action)},
+$   foreach {action}
+       @from, @action, @to[-sep ','-]
+$   end foreach
+};
 $ end foreach
-               ]
-       end
 
+const int* const parser_action_table[] = {
 $ foreach {parser_data/action_table/row}
-       private fun action_table_row${position()}: Array[Int]
-       do
-               return [
-$   foreach {action}
-                               @from, @action, @to[-sep ','-]
-$   end foreach
-                       ]
-       end
+       parser_action_row${position()}[-sep ','-]
 $ end foreach
+};
 
-       var _goto_table: Array[Array[Int]]
-       private fun build_goto_table
-       do
-               _goto_table = once [
 $ foreach {parser_data/goto_table/row}
-                       [
+static int parser_goto_row${position()}[] = {
+       ${count(goto)},
 $   foreach {goto}
-                               @from, @to[-sep ','-]
+       @from, @to[-sep ','-]
 $   end foreach
-                       ][-sep ','-]
+};
 $ end foreach
-               ]
-       end
 
-       init do end
-end
+const int* const parser_goto_table[] = {
+$ foreach {parser_data/goto_table/row}
+       parser_goto_row${position()}[-sep ','-]
+$ end foreach
+};
 $ end template