model-clients: use `is_root_init` instead of `.name == "init"`
[nit.git] / src / interpreter / debugger.nit
index 308eba6..8723ed7 100644 (file)
@@ -119,9 +119,9 @@ redef class ToolContext
        end
 
        # -d
-       var opt_debugger_mode: OptionBool = new OptionBool("Launches the target program with the debugger attached to it", "-d")
+       var opt_debugger_mode = new OptionBool("Launches the target program with the debugger attached to it", "-d")
        # -c
-       var opt_debugger_autorun: OptionBool = new OptionBool("Launches the target program with the interpreter, such as when the program fails, the debugging prompt is summoned", "-c")
+       var opt_debugger_autorun = new OptionBool("Launches the target program with the interpreter, such as when the program fails, the debugging prompt is summoned", "-c")
 
        redef init
        do
@@ -270,19 +270,8 @@ class Debugger
        end
 
        # Same as a regular call but for a runtime injected module
-       #
        fun rt_call(mpropdef: MMethodDef, args: Array[Instance]): nullable Instance
        do
-               args = call_commons(mpropdef, args)
-               return rt_call_without_varargs(mpropdef, args)
-       end
-
-       # Common code to call and this function
-       #
-       # Call only executes the variadic part, this avoids
-       # double encapsulation of variadic parameters into an Array
-       fun rt_call_without_varargs(mpropdef: MMethodDef, args: Array[Instance]): nullable Instance
-       do
                if self.modelbuilder.toolcontext.opt_discover_call_trace.value and not self.discover_call_trace.has(mpropdef) then
                        self.discover_call_trace.add mpropdef
                        self.debug("Discovered {mpropdef}")
@@ -300,7 +289,7 @@ class Debugger
                                print "Error, invalid propdef to call at runtime !"
                                return null
                        end
-               else if mproperty.name == "init" then
+               else if mproperty.is_root_init then
                        var nclassdef = self.modelbuilder.mclassdef2nclassdef[mpropdef.mclassdef]
                        self.parameter_check(nclassdef, mpropdef, args)
                        return nclassdef.call(self, mpropdef, args)
@@ -337,7 +326,6 @@ class Debugger
                        var mmod = e.mmodule
                        if mmod != null then
                                self.mainmodule = mmod
-                               var local_classdefs = mmod.mclassdefs
                                var sys_type = mmod.sys_type
                                if sys_type == null then
                                        print "Fatal error, cannot find Class Sys !\nAborting"
@@ -404,7 +392,6 @@ class Debugger
                var identifiers_in_instruction = get_identifiers_in_current_instruction(n.location.text)
 
                for i in identifiers_in_instruction do
-                       var variable = seek_variable(i, frame)
                        for j in self.traces do
                                if j.is_variable_traced_in_frame(i, frame) then
                                        n.debug("Traced variable {i} used")
@@ -470,7 +457,7 @@ class Debugger
        #
        # Returns a boolean value, representing whether or not to
        # continue reading commands from the console input
-       fun process_debug_command(command:String): Bool
+       fun process_debug_command(command: String): Bool
        do
                # Step-out command
                if command == "finish"
@@ -483,10 +470,17 @@ class Debugger
                # Step-over command
                else if command == "n" then
                        return step_over
+               # Shows help
+               else if command == "help" then
+                       help
+                       return true
                # Opens a new NitIndex prompt on current model
                else if command == "nitx" then
                        new NitIndex.with_infos(modelbuilder, self.mainmodule).prompt
                        return true
+               else if command == "bt" or command == "backtrack" then
+                       print stack_trace
+                       return true
                # Continues execution until the end
                else if command == "c" then
                        return continue_exec
@@ -508,32 +502,31 @@ class Debugger
                        print stack_trace
                        exit(0)
                else
-                       var parts_of_command = command.split_with(' ')
+                       var parts = command.split_with(' ')
+                       var cname = parts.first
                        # Shows the value of a variable in the current frame
-                       if parts_of_command[0] == "p" or parts_of_command[0] == "print" then
-                               print_command(parts_of_command)
+                       if cname == "p" or cname == "print" then
+                               print_command(parts)
                        # Places a breakpoint on line x of file y
-                       else if parts_of_command[0] == "break" or parts_of_command[0] == "b"
-                       then
-                               process_place_break_fun(parts_of_command)
+                       else if cname == "break" or cname == "b" then
+                               process_place_break_fun(parts)
                        # Removes a breakpoint on line x of file y
-                       else if parts_of_command[0] == "d" or parts_of_command[0] == "delete" then
-                               process_remove_break_fun(parts_of_command)
+                       else if cname == "d" or cname == "delete" then
+                               process_remove_break_fun(parts)
                        # Sets an alias for a variable
-                       else if parts_of_command.length == 3 and parts_of_command[1] == "as"
-                       then
-                               add_alias(parts_of_command[0], parts_of_command[2])
+                       else if parts.length == 2 and parts[1] == "as" then
+                               process_alias(parts)
                        # Modifies the value of a variable in the current frame
-                       else if parts_of_command.length >= 3 and parts_of_command[1] == "=" then
-                               process_mod_function(parts_of_command)
+                       else if parts.length == 3 and parts[1] == "=" then
+                               process_mod_function(parts)
                        # Traces the modifications on a variable
-                       else if parts_of_command.length >= 2 and parts_of_command[0] == "trace" then
-                               process_trace_command(parts_of_command)
+                       else if cname == "trace" then
+                               process_trace_command(parts)
                        # Untraces the modifications on a variable
-                       else if parts_of_command.length == 2 and parts_of_command[0] == "untrace" then
-                               process_untrace_command(parts_of_command)
+                       else if cname == "untrace" then
+                               process_untrace_command(parts)
                        else
-                               print "Unknown command \"{command}\""
+                               bad_command(command)
                        end
                end
                return true
@@ -624,72 +617,89 @@ class Debugger
        # Prints the demanded variable in the command
        #
        # The name of the variable in in position 1 of the array 'parts_of_command'
-       fun print_command(parts_of_command: Array[String])
+       fun print_command(parts: Array[String])
        do
-               if parts_of_command[1] == "*" then
+               if parts.length != 2 then
+                       bad_command(parts.join(" "))
+                       return
+               end
+               if parts[1] == "*" then
                        var map_of_instances = frame.map
 
-                       var keys = map_of_instances.iterator
-
                        var self_var = seek_variable("self", frame)
                        print "self: {self_var.to_s}"
 
                        for instance in map_of_instances.keys do
                                print "{instance.to_s}: {map_of_instances[instance].to_s}"
                        end
-               else if parts_of_command[1] == "stack" then
-                       print self.stack_trace
-               else if parts_of_command[1].chars.has('[') and parts_of_command[1].chars.has(']') then
-                       process_array_command(parts_of_command)
+               else if parts[1].chars.has('[') and parts[1].chars.has(']') then
+                       process_array_command(parts)
                else
-                       var instance = seek_variable(get_real_variable_name(parts_of_command[1]), frame)
+                       var instance = seek_variable(get_real_variable_name(parts[1]), frame)
 
                        if instance != null
                        then
                                print_instance(instance)
                        else
-                               print "Cannot find variable {parts_of_command[1]}"
+                               print "Cannot find variable {parts[1]}"
                        end
                end
        end
 
+       # Process the input command to set an alias for a variable
+       fun process_alias(parts: Array[String]) do
+               if parts.length != 3 then
+                       bad_command(parts.join(" "))
+                       return
+               end
+               add_alias(parts.first, parts.last)
+       end
+
        # Processes the input string to know where to put a breakpoint
-       fun process_place_break_fun(parts_of_command: Array[String])
+       fun process_place_break_fun(parts: Array[String])
        do
-               var bp = get_breakpoint_from_command(parts_of_command)
+               if parts.length != 3 then
+                       bad_command(parts.join(" "))
+                       return
+               end
+               var bp = get_breakpoint_from_command(parts)
                if bp != null then
                        place_breakpoint(bp)
                end
        end
 
        # Returns a breakpoint containing the informations stored in the command
-       fun get_breakpoint_from_command(parts_of_command: Array[String]): nullable Breakpoint
+       fun get_breakpoint_from_command(parts: Array[String]): nullable Breakpoint
        do
-               if parts_of_command[1].is_numeric then
-                       return new Breakpoint(parts_of_command[1].to_i, curr_file)
-               else if parts_of_command.length >= 3 and parts_of_command[2].is_numeric then
-                       return new Breakpoint(parts_of_command[2].to_i, parts_of_command[1])
+               if parts[1].is_numeric then
+                       return new Breakpoint(parts[1].to_i, curr_file)
+               else if parts.length >= 3 and parts[2].is_numeric then
+                       return new Breakpoint(parts[2].to_i, parts[1])
                else
                        return null
                end
        end
 
        # Processes the command of removing a breakpoint on specified line and file
-       fun process_remove_break_fun(parts_of_command: Array[String])
+       fun process_remove_break_fun(parts: Array[String])
        do
-               if parts_of_command[1].is_numeric then
-                       remove_breakpoint(self.curr_file, parts_of_command[1].to_i)
-               else if parts_of_command.length >= 3 and parts_of_command[2].is_numeric then
-                       remove_breakpoint(parts_of_command[1], parts_of_command[2].to_i)
+               if parts.length != 2 then
+                       bad_command(parts.join(" "))
+                       return
+               end
+               if parts[1].is_numeric then
+                       remove_breakpoint(self.curr_file, parts[1].to_i)
+               else if parts.length >= 3 and parts[2].is_numeric then
+                       remove_breakpoint(parts[1], parts[2].to_i)
                end
        end
 
        # Processes an array print command
-       fun process_array_command(parts_of_command: Array[String])
+       fun process_array_command(parts: Array[String])
        do
-               var index_of_first_brace = parts_of_command[1].chars.index_of('[')
-               var variable_name = get_real_variable_name(parts_of_command[1].substring(0,index_of_first_brace))
-               var braces = parts_of_command[1].substring_from(index_of_first_brace)
+               var index_of_first_brace = parts[1].chars.index_of('[')
+               var variable_name = get_real_variable_name(parts[1].substring(0,index_of_first_brace))
+               var braces = parts[1].substring_from(index_of_first_brace)
 
                var indexes = remove_braces(braces)
 
@@ -717,27 +727,32 @@ class Debugger
        # Processes the modification function to modify a variable dynamically
        #
        # Command of type variable = value
-       fun process_mod_function(parts_of_command: Array[String])
+       fun process_mod_function(parts: Array[String])
        do
-               parts_of_command[0] = get_real_variable_name(parts_of_command[0])
-               var parts_of_variable = parts_of_command[0].split_with(".")
+               if parts.length != 3 then
+                       bad_command(parts.join(" "))
+                       return
+               end
+               var p0 = parts[0]
+               p0 = get_real_variable_name(p0)
+               var parts_of_variable = p0.split_with(".")
 
                if parts_of_variable.length > 1 then
                        var last_part = parts_of_variable.pop
-                       var first_part = parts_of_command[0].substring(0,parts_of_command[0].length - last_part.length - 1)
+                       var first_part = p0.substring(0,p0.length - last_part.length - 1)
                        var papa = seek_variable(first_part, frame)
 
                        if papa != null and papa isa MutableInstance then
                                var attribute = get_attribute_in_mutable_instance(papa, last_part)
 
                                if attribute != null then
-                                       modify_argument_of_complex_type(papa, attribute, parts_of_command[2])
+                                       modify_argument_of_complex_type(papa, attribute, parts[2])
                                end
                        end
                else
                        var target = seek_variable(parts_of_variable[0], frame)
                        if target != null then
-                               modify_in_frame(target, parts_of_command[2])
+                               modify_in_frame(target, parts[2])
                        end
                end
        end
@@ -745,42 +760,46 @@ class Debugger
        # Processes the untrace variable command
        #
        # Command pattern : "untrace variable"
-       fun process_untrace_command(parts_of_command: Array[String])
+       fun process_untrace_command(parts: Array[String])
        do
-               var variable_name = get_real_variable_name(parts_of_command[1])
+               if parts.length != 2 then
+                       bad_command(parts.join(" "))
+                       return
+               end
+               var variable_name = get_real_variable_name(parts[1])
                if untrace_variable(variable_name) then
-                       print "Untraced variable {parts_of_command[1]}"
+                       print "Untraced variable {parts[1]}"
                else
-                       print "{parts_of_command[1]} is not traced"
+                       print "{parts[1]} is not traced"
                end
        end
 
        # Processes the trace variable command
        #
        # Command pattern : "trace variable [break/print]"
-       fun process_trace_command(parts_of_command: Array[String])
+       fun process_trace_command(parts: Array[String])
        do
-               var variable_name = get_real_variable_name(parts_of_command[1])
+               if parts.length != 3 then
+                       bad_command(parts.join(" "))
+                       return
+               end
+               var variable_name = get_real_variable_name(parts[1])
                var breaker:Bool
 
                if seek_variable(variable_name, frame) == null then
-                       print "Cannot find a variable called {parts_of_command[1]}"
+                       print "Cannot find a variable called {parts[1]}"
                        return
                end
 
-               if parts_of_command.length == 3 then
-                       if parts_of_command[2] == "break" then
-                               breaker = true
-                       else
-                               breaker = false
-                       end
+               if parts[2] == "break" then
+                       breaker = true
                else
                        breaker = false
                end
 
                trace_variable(variable_name, breaker)
 
-               print "Successfully tracing {parts_of_command[1]}"
+               print "Successfully tracing {parts[1]}"
        end
 
        #######################################################################
@@ -873,14 +892,12 @@ class Debugger
 
                var trigger_char_escape = false
                var trigger_string_escape = false
-               var trigger_concat_in_string = false
 
                for i in instruction.chars do
                        if trigger_char_escape then
                                if i == '\'' then trigger_char_escape = false
                        else if trigger_string_escape then
                                if i == '{' then
-                                       trigger_concat_in_string = true
                                        trigger_string_escape = false
                                else if i == '\"' then trigger_string_escape = false
                        else
@@ -898,7 +915,6 @@ class Debugger
                                else if i == '\"' then
                                        trigger_string_escape = true
                                else if i == '}' then
-                                       trigger_concat_in_string = false
                                        trigger_string_escape = true
                                else
                                        if instruction_buffer.length > 0 and not instruction_buffer.is_numeric and not (instruction_buffer.chars[0] >= 'A' and instruction_buffer.chars[0] <= 'Z') then result_array.push(instruction_buffer.to_s)
@@ -1125,8 +1141,6 @@ class Debugger
        do
                var collection_length_attribute = get_attribute_in_mutable_instance(collection, "length")
 
-               var real_collection_length: nullable Int = null
-
                if collection_length_attribute != null then
                        var primitive_length_instance = collection.attributes[collection_length_attribute]
                        if primitive_length_instance isa PrimitiveInstance[Int] then