From: Lucas Bajolet Date: Fri, 2 May 2014 19:49:19 +0000 (-0400) Subject: debugger: Removed network versions of debugger, now handled via options X-Git-Tag: v0.6.6~86^2~2 X-Git-Url: http://nitlanguage.org debugger: Removed network versions of debugger, now handled via options Signed-off-by: Lucas Bajolet --- diff --git a/src/Makefile b/src/Makefile index 90d85c8..ecfa44e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -16,7 +16,7 @@ NITCOPT= -all: ../bin/nitdoc ../bin/nitmetrics ../bin/nitg ../bin/nit ../bin/nitx ../bin/nitunit ../bin/nitlight ../bin/nitls ../bin/nitdbg_server ../bin/nitdbg_client +all: ../bin/nitdoc ../bin/nitmetrics ../bin/nitg ../bin/nit ../bin/nitx ../bin/nitunit ../bin/nitlight ../bin/nitls ../bin/nitdbg_client ../bin/nitg: ../c_src/nitg parser/parser.nit @echo '***************************************************************' @@ -34,7 +34,7 @@ all: ../bin/nitdoc ../bin/nitmetrics ../bin/nitg ../bin/nit ../bin/nitx ../bin/n ../bin/nitmetrics: ../bin/nitg @echo '***************************************************************' - @echo '* Compile nitmetrics from NIT source files *' + @echo '* Compile nitmetrics from NIT source files *' @echo '***************************************************************' ./git-gen-version.sh ../bin/nitg ${NITCOPT} -o ../bin/nitmetrics -v nitmetrics.nit @@ -48,18 +48,11 @@ all: ../bin/nitdoc ../bin/nitmetrics ../bin/nitg ../bin/nit ../bin/nitx ../bin/n ../bin/nitdbg_client : ../bin/nitg @echo '***************************************************************' - @echo '* Compile nitdbg_client from NIT source files *' + @echo '* Compile nitdbg_client from NIT source files *' @echo '***************************************************************' ./git-gen-version.sh ../bin/nitg ${NITCOPT} -o ../bin/nitdbg_client -v nitdbg_client.nit -../bin/nitdbg_server : ../bin/nitg - @echo '***************************************************************' - @echo '* Compile nitdbg_server from NIT source files *' - @echo '***************************************************************' - ./git-gen-version.sh - ../bin/nitg ${NITCOPT} -o ../bin/nitdbg_server -v nitdbg_server.nit - ../bin/nitx: ../bin/nitg @echo '***************************************************************' @echo '* Compile nitx from NIT source files *' diff --git a/src/debugger.nit b/src/debugger.nit index 3fca8d5..cd77425 100644 --- a/src/debugger.nit +++ b/src/debugger.nit @@ -23,6 +23,7 @@ import nitx intrude import local_var_init intrude import scope intrude import toolcontext +import websocket redef class Model # Cleans the model to remove a module and what it defines when semantic analysis fails on injected code @@ -110,7 +111,7 @@ redef class ToolContext for m in messages do if m.text.search("Warning") == null then had_error = true - stderr.write("{m.to_color_string}\n") + sys.stderr.write("{m.to_color_string}\n") end end @@ -123,11 +124,23 @@ redef class ToolContext # -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") + # --socket + var opt_socket_mode = new OptionBool("Launches the target program with raw output on the network via sockets", "--socket") + + # --websocket + var opt_websocket_mode = new OptionBool("Launches the target program with output on the network via websockets", "--websocket") + + # --port + var opt_debug_port: OptionInt = new OptionInt("Sets the debug port (Defaults to 22125) - Must be contained between 0 and 65535", 22125, "--port") + redef init do super self.option_context.add_option(self.opt_debugger_mode) self.option_context.add_option(self.opt_debugger_autorun) + self.option_context.add_option(self.opt_socket_mode) + self.option_context.add_option(self.opt_websocket_mode) + self.option_context.add_option(self.opt_debug_port) end end @@ -145,8 +158,12 @@ redef class ModelBuilder var interpreter = new Debugger(self, mainmodule, arguments) + set_stdstreams + init_naive_interpreter(interpreter, mainmodule) + close_stdstreams + var time1 = get_time self.toolcontext.info("*** END INTERPRETING: {time1-time0} ***", 2) end @@ -159,11 +176,53 @@ redef class ModelBuilder var interpreter = new Debugger(self, mainmodule, arguments) interpreter.autocontinue = true + set_stdstreams + init_naive_interpreter(interpreter, mainmodule) + close_stdstreams + var time1 = get_time self.toolcontext.info("*** END INTERPRETING: {time1-time0} ***", 2) end + + redef fun run_naive_interpreter(mmod, args) + do + set_stdstreams + super + end + + fun set_stdstreams + do + if self.toolcontext.opt_socket_mode.value then + var sock = new Socket.server(toolcontext.opt_debug_port.value, 1) + var ns = sock.accept + sock.close + sys.set_io(ns,ns,ns) + else if self.toolcontext.opt_websocket_mode.value then + var websock = new WebSocket(toolcontext.opt_debug_port.value, 1) + websock.accept + sys.set_io(websock,websock,websock) + end + end + + fun close_stdstreams + do + if sys.stdin isa WebSocket or sys.stdin isa Socket then + sys.stdin.close + sys.stdout.close + sys.stderr.close + end + end +end + +redef class Sys + private fun set_io(istream: PollableIStream, ostream: OStream, errstream: OStream) + do + self.stdin = istream + self.stdout = ostream + self.stderr = ostream + end end # The class extending `NaiveInterpreter` by adding debugging methods @@ -223,6 +282,8 @@ class Debugger var old = frame.current_node frame.current_node = n + if sys.stdin.poll_in then process_debug_command(gets) + if not self.autocontinue then if not n isa ABlockExpr then steps_fun_call(n) diff --git a/src/debugger_commons.nit b/src/debugger_commons.nit deleted file mode 100644 index dcfebbd..0000000 --- a/src/debugger_commons.nit +++ /dev/null @@ -1,73 +0,0 @@ -# This file is part of NIT ( http://www.nitlanguage.org ). -# -# Copyright 2013 Lucas Bajolet -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -module debugger_commons - -import modelbuilder -import frontend -import transform - -class InterpretCommons - - var model: nullable Model - var modelbuilder: nullable ModelBuilder - var toolcontext: nullable ToolContext - var mainmodule: nullable MModule - var arguments: nullable Array[String] - - init - do - end - - fun launch - do - # Create a tool context to handle options and paths - toolcontext = new ToolContext - toolcontext.tooldescription = "Usage: nit [OPTION]... ...\nInterprets and debbugs Nit programs." - # Add an option "-o" to enable compatibilit with the tests.sh script - var opt = new OptionString("compatibility (does noting)", "-o") - toolcontext.option_context.add_option(opt) - var opt_mixins = new OptionArray("Additionals module to min-in", "-m") - toolcontext.option_context.add_option(opt_mixins) - # We do not add other options, so process them now! - toolcontext.process_options(args) - - # We need a model to collect stufs - var model = new Model - self.model = model - # An a model builder to parse files - modelbuilder = new ModelBuilder(model, toolcontext.as(not null)) - - arguments = toolcontext.option_context.rest - var progname = arguments.first - - # Here we load an process all modules passed on the command line - var mmodules = modelbuilder.parse([progname]) - mmodules.add_all modelbuilder.parse(opt_mixins.value) - modelbuilder.run_phases - - if toolcontext.opt_only_metamodel.value then exit(0) - - # Here we launch the interpreter on the main module - if mmodules.length == 1 then - mainmodule = mmodules.first - else - mainmodule = new MModule(model, null, mmodules.first.name, mmodules.first.location) - mainmodule.set_imported_mmodules(mmodules) - end - end - -end diff --git a/src/network_debugger.nit b/src/network_debugger.nit deleted file mode 100644 index e8afc20..0000000 --- a/src/network_debugger.nit +++ /dev/null @@ -1,231 +0,0 @@ -# This file is part of NIT ( http://www.nitlanguage.org ). -# -# Copyright 2013 Lucas Bajolet -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Network debugger for a nit program, based on the original debugger -# Replaces access to stdin/stdout to send data on the network to the client concerned -module network_debugger - -import socket -intrude import debugger - -redef class ToolContext - - var opt_debug_port: OptionInt = new OptionInt("Sets the debug port (Defaults to 22125) - Must be contained between 0 and 65535", 22125, "--port") - - redef init - do - super - self.option_context.add_option(self.opt_debug_port) - end - -end - -redef class ModelBuilder - fun run_debugger_network_mode(mainmodule: MModule, arguments: Array[String], port: Int) - do - var time0 = get_time - self.toolcontext.info("*** START INTERPRETING ***", 1) - - var interpreter = new NetworkDebugger(self, mainmodule, arguments, port) - - init_naive_interpreter(interpreter, mainmodule) - - var time1 = get_time - self.toolcontext.info("*** END INTERPRETING: {time1-time0} ***", 2) - - interpreter.disconnect_routine - - interpreter.ns.close - interpreter.socket.close - end -end - -# Extends the debugger by adding new network capabilities for remote debugging -class NetworkDebugger - super Debugger - - # Represents the connexion with a particular client (Actually the only one accepted at the moment) - private var ns: Socket - - # Socket for the server, supposed to listen for incoming request from a client - private var socket: Socket - - # Initializes the debugger, waits for a client to connect - # Then starts debugging as usual - init(modelbuilder: ModelBuilder, mainmodule: MModule, arguments: Array[String], port: Int) - do - print "Listening on port {port}" - - socket = new Socket.stream_with_port(port) - - socket.bind - socket.listen(1) - - ns = socket.accept - - socket.close - - print "Client connected" - - stdin.connection = ns - - if stdout isa Stdout then - (stdout.as(Stdout)).connection = ns - else - ns.close - abort - end - - super - end - - # Provokes the disconnection of the client - # Used when debugging is over - fun disconnect_routine - do - print "DBG DONE WORK ON SELF" - - var cliOverResp = "" - - while cliOverResp != "CLIENT DBG DONE ACK" do - cliOverResp = gets - end - end - - # Checks on every call if the client has sent a command before continuing debugging - redef fun stmt(n) - do - if stdin.poll_in then - var command = gets - if command == "stop" then - n.debug("Stopped by client") - while process_debug_command(gets) do end - else - process_debug_command(command) - end - end - - super(n) - end - -end - -redef class ANode - - # Breaks automatically when encountering an error - # Permits the injunction of commands before crashing - # Disconnects from the client before crashing - redef private fun fatal(v: NaiveInterpreter, message: String) - do - if v isa Debugger then - print "An error was encountered, the program will stop now." - self.debug(message) - while v.process_debug_command(gets) do end - end - - if v isa NetworkDebugger then - v.disconnect_routine - stdin.connection.close - end - - super - end -end - -# Replaces Stdin to read on the network -redef class Stdin - - # Represents the connection with a client - var connection: nullable Socket = null - - # Used to store data that has been read from the connection - var buf: Buffer = new FlatBuffer - var buf_pos: Int = 0 - - # Checks if data is available for reading - redef fun poll_in - do - return connection.ready_to_read(0) - end - - # Reads the whole content of the buffer - # Blocking if the buffer is empty - redef fun read_all - do - var loc_buf = new FlatBuffer - if connection.ready_to_read(0) then buf.append(connection.read) - for i in [buf_pos .. buf.length-1] do loc_buf.add(buf.chars[i]) - buf.clear - buf_pos = 0 - return loc_buf.to_s - end - - # Reads a single char on the incoming buffer - # If the buffer is empty, the call is blocking - redef fun read_char - do - if connection.ready_to_read(0) then buf.append(connection.read) - if buf_pos >= buf.length then - buf.clear - buf_pos = 0 - #Blocking call - buf.append(connection.read) - end - buf_pos += 1 - return buf.chars[buf_pos-1].ascii - end - - # Reads a line on the network if available - # Stops at the first encounter of a \n character - # If the buffer is empty, the read_line call is blocking - redef fun read_line - do - var line_buf = new FlatBuffer - if connection.ready_to_read(0) then buf.append(connection.read) - var has_found_eol: Bool = false - loop - if buf_pos >= buf.length then - buf.clear - buf_pos = 0 - # Blocking call - buf.append(connection.read) - end - buf_pos += 1 - if buf.chars[buf_pos-1] == '\n' then break - line_buf.add(buf.chars[buf_pos-1]) - end - return line_buf.to_s - end -end - -# Replaces Stdout to write on the network -redef class Stdout - - # Connection with the client object - var connection: nullable Socket = null - - # Writes a string on the network if available, else - # it is written in the standard output (Terminal) - redef fun write(s) - do - if connection != null then - connection.write(s.to_s) - else - super - end - end - -end diff --git a/src/nit.nit b/src/nit.nit index ad1a388..36c3815 100644 --- a/src/nit.nit +++ b/src/nit.nit @@ -19,24 +19,51 @@ module nit import naive_interpreter import debugger -import debugger_commons - -redef class InterpretCommons - - redef fun launch - do - super - var self_mm = mainmodule.as(not null) - var self_args = arguments.as(not null) - if toolcontext.opt_debugger_autorun.value then - modelbuilder.run_debugger_autorun(self_mm, self_args) - else if toolcontext.opt_debugger_mode.value then - modelbuilder.run_debugger(self_mm, self_args) - else - modelbuilder.run_naive_interpreter(self_mm, self_args) - end - end +# Create a tool context to handle options and paths +var toolcontext = new ToolContext +toolcontext.tooldescription = "Usage: nit [OPTION]... ...\nInterprets and debbugs Nit programs." +# Add an option "-o" to enable compatibilit with the tests.sh script +var opt = new OptionString("compatibility (does noting)", "-o") +toolcontext.option_context.add_option(opt) +var opt_mixins = new OptionArray("Additionals module to min-in", "-m") +toolcontext.option_context.add_option(opt_mixins) +# We do not add other options, so process them now! +toolcontext.process_options(args) + +# We need a model to collect stufs +var model = new Model +# An a model builder to parse files +var modelbuilder = new ModelBuilder(model, toolcontext.as(not null)) + +var arguments = toolcontext.option_context.rest +var progname = arguments.first + +# Here we load an process all modules passed on the command line +var mmodules = modelbuilder.parse([progname]) +mmodules.add_all modelbuilder.parse(opt_mixins.value) +modelbuilder.run_phases + +if toolcontext.opt_only_metamodel.value then exit(0) + +var mainmodule: nullable MModule + +# Here we launch the interpreter on the main module +if mmodules.length == 1 then + mainmodule = mmodules.first +else + mainmodule = new MModule(model, null, mmodules.first.name, mmodules.first.location) + mainmodule.set_imported_mmodules(mmodules) +end + +var self_mm = mainmodule.as(not null) +var self_args = arguments.as(not null) + +if toolcontext.opt_debugger_autorun.value then + modelbuilder.run_debugger_autorun(self_mm, self_args) +else if toolcontext.opt_debugger_mode.value then + modelbuilder.run_debugger(self_mm, self_args) +else + modelbuilder.run_naive_interpreter(self_mm, self_args) end -(new InterpretCommons).launch diff --git a/src/nitdbg_server.nit b/src/nitdbg_server.nit deleted file mode 100644 index 135a94c..0000000 --- a/src/nitdbg_server.nit +++ /dev/null @@ -1,38 +0,0 @@ -# This file is part of NIT ( http://www.nitlanguage.org ). -# -# Copyright 2013 Lucas Bajolet -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Network debugger for a nit program (server part) -module nitdbg_server - -import network_debugger -import debugger_commons - -redef class InterpretCommons - - redef fun launch - do - super - if toolcontext.opt_debug_port.value < 0 or toolcontext.opt_debug_port.value > 65535 then - toolcontext.option_context.usage - return - end - - modelbuilder.run_debugger_network_mode(mainmodule.as(not null),arguments.as(not null),toolcontext.opt_debug_port.value) - end - -end - -(new InterpretCommons).launch diff --git a/src/nitdbg_websocket_server.nit b/src/nitdbg_websocket_server.nit deleted file mode 100644 index d8c23ca..0000000 --- a/src/nitdbg_websocket_server.nit +++ /dev/null @@ -1,38 +0,0 @@ -# This file is part of NIT ( http://www.nitlanguage.org ). -# -# Copyright 2014 Lucas Bajolet -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Network debugger for a nit program (server part) -module nitdbg_websocket_server - -import websocket_debugger -import debugger_commons - -redef class InterpretCommons - - redef fun launch - do - super - if toolcontext.opt_debug_port.value < 0 or toolcontext.opt_debug_port.value > 65535 then - toolcontext.option_context.usage - return - end - - modelbuilder.run_debugger_network_mode(mainmodule.as(not null),arguments.as(not null),toolcontext.opt_debug_port.value) - end - -end - -(new InterpretCommons).launch diff --git a/src/websocket_debugger.nit b/src/websocket_debugger.nit deleted file mode 100644 index d4b4878..0000000 --- a/src/websocket_debugger.nit +++ /dev/null @@ -1,209 +0,0 @@ -# This file is part of NIT ( http://www.nitlanguage.org ). -# -# Copyright 2014 Lucas Bajolet -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Network debugger for a nit program, based on the original debugger -# Replaces access to stdin/stdout to send data on the network to the client concerned -module websocket_debugger - -import websocket -intrude import debugger - -redef class ToolContext - - var opt_debug_port: OptionInt = new OptionInt("Sets the debug port (Defaults to 22125) - Must be contained between 0 and 65535", 22125, "--port") - - redef init - do - super - self.option_context.add_option(self.opt_debug_port) - end - -end - -redef class ModelBuilder - fun run_debugger_network_mode(mainmodule: MModule, arguments: Array[String], port: Int) - do - var time0 = get_time - self.toolcontext.info("*** START INTERPRETING ***", 1) - - var interpreter = new NetworkDebugger(self, mainmodule, arguments, port) - - init_naive_interpreter(interpreter, mainmodule) - - var time1 = get_time - self.toolcontext.info("*** END INTERPRETING: {time1-time0} ***", 2) - - interpreter.ns.stop_server - end -end - -# Extends the debugger by adding new network capabilities for remote debugging -class NetworkDebugger - super Debugger - - # Represents the connexion with a particular client (Actually the only one accepted at the moment) - private var ns: WebSocket - - # Initializes the debugger, waits for a client to connect - # Then starts debugging as usual - init(modelbuilder: ModelBuilder, mainmodule: MModule, arguments: Array[String], port: Int) - do - print "Listening on port {port}" - - ns = new WebSocket(port, 1) - - ns.accept - - print "Client connected" - - stdin.connection = ns - - if stdout isa Stdout then - (stdout.as(Stdout)).connection = ns - else - ns.stop_server - abort - end - - super - end - - # Checks on every call if the client has sent a command before continuing debugging - redef fun stmt(n) - do - if stdin.poll_in then - var command = gets - if command == "stop" then - n.debug("Stopped by client") - while process_debug_command(gets) do end - else - process_debug_command(command) - end - end - - super(n) - end - -end - -redef class ANode - - # Breaks automatically when encountering an error - # Permits the injunction of commands before crashing - # Disconnects from the client before crashing - redef private fun fatal(v: NaiveInterpreter, message: String) - do - if v isa Debugger then - print "An error was encountered, the program will stop now." - self.debug(message) - while v.process_debug_command(gets) do end - end - - if v isa NetworkDebugger then - stdin.connection.stop_server - end - - super - end -end - -# Replaces Stdin to read on the network -redef class Stdin - - # Represents the connection with a client - var connection: nullable WebSocket = null - - # Used to store data that has been read from the connection - var buf: Buffer = new FlatBuffer - var buf_pos: Int = 0 - - # Checks if data is available for reading - redef fun poll_in - do - return connection.can_read(0) - end - - # Reads the whole content of the buffer - # Blocking if the buffer is empty - redef fun read_all - do - var loc_buf = new FlatBuffer - if connection.can_read(0) then buf.append(connection.read) - for i in [buf_pos .. buf.length-1] do loc_buf.add(buf.chars[i]) - buf.clear - buf_pos = 0 - return loc_buf.to_s - end - - # Reads a single char on the incoming buffer - # If the buffer is empty, the call is blocking - redef fun read_char - do - if connection.can_read(0) then buf.append(connection.read) - if buf_pos >= buf.length then - buf.clear - buf_pos = 0 - #Blocking call - buf.append(connection.read) - end - buf_pos += 1 - return buf.chars[buf_pos-1].ascii - end - - # Reads a line on the network if available - # Stops at the first encounter of a \n character - # If the buffer is empty, the read_line call is blocking - redef fun read_line - do - var line_buf = new FlatBuffer - if connection.can_read(0) then - buf.append(connection.read) - end - var has_found_eol: Bool = false - loop - if buf_pos >= buf.length then - buf.clear - buf_pos = 0 - # Blocking call - buf.append(connection.read) - end - buf_pos += 1 - if buf.chars[buf_pos-1] == '\n' then break - line_buf.add(buf.chars[buf_pos-1]) - end - return line_buf.to_s - end -end - -# Replaces Stdout to write on the network -redef class Stdout - - # Connection with the client object - var connection: nullable WebSocket = null - - # Writes a string on the network if available, else - # it is written in the standard output (Terminal) - redef fun write(s) - do - if connection != null then - connection.write(s.to_s) - else - super - end - end - -end -