From: Jean Privat Date: Thu, 26 Jun 2014 02:42:24 +0000 (-0400) Subject: Merge: ordered_tree: make OrderedTree implement Collection X-Git-Tag: v0.6.6~14 X-Git-Url: http://nitlanguage.org?hp=30c953aa48b4c89c2f55ab811134ec30e272d61a Merge: ordered_tree: make OrderedTree implement Collection OrderedTree now implement major Collection services Signed-off-by: Alexandre Terrasa Pull-Request: #524 Reviewed-by: Alexis Laferrière Reviewed-by: Lucas Bajolet Reviewed-by: Jean Privat --- diff --git a/.mailmap b/.mailmap index a3e389c..695a4ce 100644 --- a/.mailmap +++ b/.mailmap @@ -23,3 +23,5 @@ Romain Chanoir Clement de Figueiredo Christophe Gigax + +Julien Pagès diff --git a/benchmarks/bench_common.sh b/benchmarks/bench_common.sh new file mode 100644 index 0000000..c600732 --- /dev/null +++ b/benchmarks/bench_common.sh @@ -0,0 +1,87 @@ +#!/bin/bash +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# 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. + +# Common functions for all the bench scripts + +# Run a single command multiple time and store the execution times +# in the current $res file. +# +# $1: title of the command +# $2: long desription of the command +# rest: the command to execute +function bench_command() +{ + if [ "$dry_run" = "true" ]; then return; fi + local title="$1" + local desc="$2" + shift + shift + if test "$verbose" = true; then outputopts="/dev/stdout"; else outputopts="/dev/null"; fi + timeout="time.out" + echo "$title" > "$timeout" + echo "# $desc" >> "$timeout" + echo "\$ $@" >> "$timeout" + echo + echo "** [$title] $desc **" + echo " $ $@" + + # Execute the commands $count times + for i in `seq 1 "$count"`; do + /usr/bin/time -f "%U" -o "$timeout" -a "$@" > $outputopts 2>&1 || die "$1: failed" + echo -n "$i. " + tail -n 1 "$timeout" + done + + line=`compute_stats "$timeout"` + echo "$line ($res)" + echo $line >> "$res" +} + +# Run a simble command witout storing the execution time +# Used to display command on verbose and skip long executions when dry_run is given +# $@ command to execute +function run_command() +{ + if [ "$dry_run" = "true" ]; then return; fi + echo " $ $@" + "$@" || die "$@: failed" +} + +# Check if the test should be skiped according to its name +# $1: name of the test +# $2: description of the test +# $NOTSKIPED: arguments +function skip_test() +{ + if test -z "$NOTSKIPED"; then + echo "* $1" + return 0 + fi + if test "$NOTSKIPED" = "all"; then + : # Execute anyway + elif echo "$1" | egrep "$NOTSKIPED" >/dev/null 2>&1; then + : # Found one to execute + else + return 0 + fi + if test -n "$html"; then + echo >>"$html" "

$1

" + fi + echo "*" + echo "* $1 *****" + echo "*" + return 1 +} + diff --git a/benchmarks/bench_engines.sh b/benchmarks/bench_engines.sh index 55db63e..abc65e3 100755 --- a/benchmarks/bench_engines.sh +++ b/benchmarks/bench_engines.sh @@ -17,6 +17,7 @@ # TODO: cleanup and libify the helper-parts +source ./bench_common.sh source ./bench_plot.sh ## CONFIGURATION OPTIONS ## @@ -35,76 +36,6 @@ function die() died=1 } -# Run a single command multiple time and store the execution times -# in the current $res file. -# -# $1: title of the command -# $2: long desription of the command -# rest: the command to execute -function bench_command() -{ - if [ "$dry_run" = "true" ]; then return; fi - local title="$1" - local desc="$2" - shift - shift - if test "$verbose" = true; then outputopts="/dev/stdout"; else outputopts="/dev/null"; fi - timeout="time.out" - echo "$title" > "$timeout" - echo "# $desc" >> "$timeout" - echo "\$ $@" >> "$timeout" - echo - echo "** [$title] $desc **" - echo " $ $@" - - # Execute the commands $count times - for i in `seq 1 "$count"`; do - /usr/bin/time -f "%U" -o "$timeout" -a "$@" > $outputopts 2>&1 || die "$1: failed" - echo -n "$i. " - tail -n 1 "$timeout" - done - - line=`compute_stats "$timeout"` - echo "$line ($res)" - echo $line >> "$res" -} - -# Run a simble command witout storing the execution time -# Used to display command on verbose and skip long executions when dry_run is given -# $@ command to execute -function run_command() -{ - if [ "$dry_run" = "true" ]; then return; fi - echo " $ $@" - "$@" || die "$@: failed" -} - -# Check if the test should be skiped according to its name -# $1: name of the test -# $2: description of the test -# $NOTSKIPED: arguments -function skip_test() -{ - if test -z "$NOTSKIPED"; then - echo "* $1" - return 0 - fi - if test "$NOTSKIPED" = "all"; then - : # Execute anyway - elif echo "$1" | egrep "$NOTSKIPED" >/dev/null 2>&1; then - : # Found one to execute - else - return 0 - fi - if test -n "$html"; then - echo >>"$html" "

$1

" - fi - echo "*" - echo "* $1 *****" - echo "*" - return 1 -} - # HELPER FOR NIT # # Run standards benchs on a compiler command diff --git a/benchmarks/bench_languages.sh b/benchmarks/bench_languages.sh index d9db525..fea39ff 100755 --- a/benchmarks/bench_languages.sh +++ b/benchmarks/bench_languages.sh @@ -17,6 +17,7 @@ # TODO: cleanup and libify the helper-parts +source ./bench_common.sh source ./bench_plot.sh ## CONFIGURATION OPTIONS ## @@ -33,74 +34,6 @@ function die() died=1 } -# Run a single command multiple time and store the execution times -# in the current $res file. -# -# $1: title of the command -# $2: long desription of the command -# rest: the command to execute -function bench_command() -{ - if [ "$dry_run" = "true" ]; then return; fi - local title="$1" - local desc="$2" - shift - shift - if test "$verbose" = true; then outputopts="/dev/stdout"; else outputopts="/dev/null"; fi - timeout="time.out" - echo "$title" > "$timeout" - echo "# $desc" >> "$timeout" - echo "\$ $@" >> "$timeout" - echo - echo "** [$title] $desc **" - echo " $ $@" - - # Execute the commands $count times - for i in `seq 1 "$count"`; do - (ulimit -t 300; /usr/bin/time -f "%U" -o "$timeout" -a "$@") > $outputopts 2>&1 || die "$1: failed" - echo -n "$i. " - tail -n 1 "$timeout" - done - - line=`compute_stats "$timeout"` - echo "$line ($res)" - echo $line >> "$res" - rm $timeout -} - -# Run a simple command witout storing the execution time -# Used to display command on verbose and skip long executions when dry_run is given -# $@ command to execute -function run_command() -{ - if [ "$dry_run" = "true" ]; then return; fi - echo " $ $@" - (ulimit -t 180; "$@") || die "$@: failed" -} - -# Check if the test should be skiped according to its name -# $1: name of the test -# $2: description of the test -# $NOTSKIPED: arguments -function skip_test() -{ - if test -z "$NOTSKIPED"; then - echo "* $1" - return 0 - fi - if test "$NOTSKIPED" = "all"; then - : # Execute anyway - elif echo "$1" | egrep "$NOTSKIPED" >/dev/null 2>&1; then - : # Found one to execute - else - return 0 - fi - echo "*" - echo "* $1 *****" - echo "*" - return 1 -} - ## HANDLE OPTIONS ## function usage() diff --git a/c_src/Makefile b/c_src/Makefile index 1453943..d94866c 100644 --- a/c_src/Makefile +++ b/c_src/Makefile @@ -1,8 +1,22 @@ CC = ccache cc -CFLAGS = -g -O2 +CFLAGS = -g -O2 -Wno-unused-value -Wno-switch CINCL = -I "clib" LDFLAGS ?= -LDLIBS ?= -lm -lgc -lunwind +LDLIBS ?= -lm -lgc + +NEED_LIBUNWIND := YesPlease +uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') +ifeq ($(uname_S),Darwin) + NEED_LIBUNWIND := +endif + +clang_check := $(shell sh -c '$(CC) -v 2>&1 | grep -q clang; echo $$?') +ifeq ($(clang_check), 0) + CFLAGS += -Qunused-arguments +endif +ifdef NEED_LIBUNWIND + LDLIBS += -lunwind +endif all: nitg diff --git a/lib/ropes_debug.nit b/lib/ropes_debug.nit index b9ba5ab..a122a02 100644 --- a/lib/ropes_debug.nit +++ b/lib/ropes_debug.nit @@ -53,13 +53,24 @@ redef class Concat end end +redef class FlatText + fun to_dot(s: String): String is abstract +end + redef class FlatString - fun to_dot(s: String): String + redef fun to_dot(s: String): String do return s + "n{object_id} [label=\"FlatString\\nindex_from = {index_from}\\nindex_to = {index_to}\\nNativeString = {items.to_s_with_length(items.cstring_length)}\"];\n" end end +redef class FlatBuffer + redef fun to_dot(s: String): String + do + return s + "n{object_id} [label=\"FlatBuffer\\length = {length}\\ncapacity = {capacity}\\nitems = {items.to_s_with_length(items.cstring_length)}\"];\n" + end +end + redef class RopeString redef fun to_dot(filepath: String) do diff --git a/lib/standard/ropes.nit b/lib/standard/ropes.nit index 45c1cbd..7bc4154 100644 --- a/lib/standard/ropes.nit +++ b/lib/standard/ropes.nit @@ -44,6 +44,11 @@ end private abstract class RopeNode # Length of the node var length = 0 + + # Transforms the current node to a Leaf. + # This might be costly to invoke since this produces a FlatString concatenation. + # Can be used internally to limit the growth of the Rope when working with small leaves. + fun to_leaf: Leaf is abstract end # Node that represents a concatenation between two nodes (of any RopeNode type) @@ -51,40 +56,47 @@ private class Concat super RopeNode # Left child of the node - var _left: nullable RopeNode = null + var left: nullable RopeNode # Right child of the node - var _right: nullable RopeNode = null - - fun left: nullable RopeNode do return _left - fun right: nullable RopeNode do return _right + var right: nullable RopeNode - fun left=(l: RopeNode) + init(l: nullable RopeNode, r: nullable RopeNode) do - _left = l - length = l.length - if _right != null then length += _right.length + left = l + right = r + if l != null then length += l.length + if r != null then length += r.length end - fun right=(r: RopeNode) + redef fun to_leaf do - _right = r - length = r.length - if _left != null then length += _left.length + if left == null then + if right == null then return new StringLeaf("".as(FlatString)) + return right.to_leaf + end + if right == null then return left.as(not null).to_leaf + return new StringLeaf((left.to_leaf.str.as(FlatString) + right.to_leaf.str.as(FlatString)).as(FlatString)) end end # Leaf of a Rope, contains a FlatString -private class Leaf +private abstract class Leaf super RopeNode # Encapsulated FlatString in the leaf node - var str: FlatString + var str: FlatText + +end + +private class StringLeaf + super Leaf init(val: FlatString) do self.str = val length = str.length end + redef fun to_leaf do return self end # Basic structure, binary tree with a root node. @@ -104,7 +116,7 @@ abstract class Rope # Creates a new Rope with `s` as root init from(s: String) do - if s isa RopeString then root = s.root else root = new Leaf(s.as(FlatString)) + if s isa RopeString then root = s.root else root = new StringLeaf(s.as(FlatString)) end private init from_root(r: RopeNode) @@ -276,36 +288,40 @@ class RopeString var path = node_at(pos) - var last_concat = new Concat + var last_concat: Concat if path.offset == 0 then - last_concat.right = path.leaf - if str isa FlatString then last_concat.left = new Leaf(str) else last_concat.left = str.as(RopeString).root + if str isa FlatString then + last_concat = new Concat(new StringLeaf(str), path.leaf) + else + last_concat = new Concat(str.as(RopeString).root, path.leaf) + end else if path.offset == path.leaf.length then - if str isa FlatString then last_concat.right = new Leaf(str) else last_concat.right = str.as(RopeString).root - last_concat.left = path.leaf + if str isa FlatString then + last_concat = new Concat(path.leaf, new StringLeaf(str)) + else + last_concat = new Concat(path.leaf, str.as(RopeString).root) + end else var s = path.leaf.str var l_half = s.substring(0, s.length - path.offset) var r_half = s.substring_from(s.length - path.offset) - var cct = new Concat - cct.right = new Leaf(r_half.as(FlatString)) - last_concat.left = new Leaf(l_half.as(FlatString)) - if str isa FlatString then last_concat.right = new Leaf(str) else last_concat.right = str.as(RopeString).root - cct.left = last_concat - last_concat = cct + var cct: Concat + var ll = new StringLeaf(l_half.as(FlatString)) + if str isa FlatString then + cct = new Concat(ll, new StringLeaf(str)) + else + cct = new Concat(ll, str.as(RopeString).root) + end + last_concat = new Concat(cct, new StringLeaf(r_half.as(FlatString))) end for i in path.stack.reverse_iterator do - var nod = new Concat if i.left then - nod.right = i.node.right.as(not null) - nod.left = last_concat + last_concat = new Concat(last_concat, i.node.right) else - nod.left = i.node.left.as(not null) - nod.right = last_concat + last_concat = new Concat(i.node.left, last_concat) end - last_concat = nod end return new RopeString.from_root(last_concat) @@ -324,17 +340,25 @@ class RopeString # Builds a new path from root to the rightmost node with s appended private fun append_to_path(node: RopeNode, s: String): RopeNode do - var cct = new Concat + var cct: Concat if node isa Leaf then - cct.left = node - if s isa FlatString then cct.right = new Leaf(s) else cct.right = s.as(RopeString).root - else if node isa Concat then - var right = node.right - if node.left != null then cct.left = node.left.as(not null) + if s isa FlatString then + cct = new Concat(node, new StringLeaf(s)) + else + cct = new Concat(node, s.as(RopeString).root) + end + else + var n = node.as(Concat) + var right = n.right + var lft = n.left.as(not null) if right == null then - if s isa FlatString then cct.right = new Leaf(s) else cct.right = s.as(RopeString).root + if s isa FlatString then + cct = new Concat(lft, new StringLeaf(s)) + else + cct = new Concat(lft, s.as(RopeString).root) + end else - cct.right = append_to_path(right, s) + cct = new Concat(lft, append_to_path(right, s)) end end return cct @@ -364,17 +388,13 @@ class RopeString var lf = path.leaf var offset = path.offset - if path.leaf.str.length - offset > len then lf = new Leaf(lf.str.substring(offset,len).as(FlatString)) else lf = new Leaf(lf.str.substring_from(offset).as(FlatString)) + if path.leaf.str.length - offset > len then lf = new StringLeaf(lf.str.substring(offset,len).as(FlatString)) else lf = new StringLeaf(lf.str.substring_from(offset).as(FlatString)) var nod: RopeNode = lf for i in path.stack.reverse_iterator do if i.right then continue - var tmp = new Concat - tmp.left = nod - var r = i.node.right - if r != null then tmp.right = r - nod = tmp + nod = new Concat(nod, i.node.right) end var ret = new RopeString @@ -383,15 +403,11 @@ class RopeString path = ret.node_at(len-1) offset = path.offset - nod = new Leaf(path.leaf.str.substring(0, offset+1).as(FlatString)) + nod = new StringLeaf(path.leaf.str.substring(0, offset+1).as(FlatString)) for i in path.stack.reverse_iterator do if i.left then continue - var tmp = new Concat - tmp.right = nod - var l = i.node.left - if l != null then tmp.left = l - nod = tmp + nod = new Concat(i.node.left, nod) end ret.root = nod diff --git a/src/Makefile b/src/Makefile index 211287d..2ca0fb7 100644 --- a/src/Makefile +++ b/src/Makefile @@ -15,6 +15,7 @@ # limitations under the License. NITCOPT= +OLDNITCOPT= --no-stacktrace all: ../bin/nitdoc ../bin/nitmetrics ../bin/nitg ../bin/nit ../bin/nitx ../bin/nitunit ../bin/nitlight ../bin/nitls ../bin/nitdbg_client @@ -23,7 +24,7 @@ nitg_0: ../c_src/nitg parser/parser.nit @echo '* Compile nitg_0 from NIT source files *' @echo '***************************************************************' ./git-gen-version.sh - ../c_src/nitg ${NITCOPT} -o nitg_0 -v nitg.nit + ../c_src/nitg ${OLDNITCOPT} -o nitg_0 -v nitg.nit ../bin/nitg: nitg_0 parser/parser.nit @echo '***************************************************************' diff --git a/src/abstract_compiler.nit b/src/abstract_compiler.nit index 99b84be..e8d0179 100644 --- a/src/abstract_compiler.nit +++ b/src/abstract_compiler.nit @@ -320,10 +320,28 @@ class MakefileToolchain if libs != null then linker_options.add_all(libs) end + makefile.write("CC = ccache cc\nCFLAGS = -g -O2 -Wno-unused-value -Wno-switch\nCINCL = {cc_includes}\nLDFLAGS ?= \nLDLIBS ?= -lm -lgc {linker_options.join(" ")}\n\n") + var ost = toolcontext.opt_stacktrace.value - if ost == "libunwind" or ost == "nitstack" then linker_options.add("-lunwind") + if ost == "libunwind" or ost == "nitstack" then makefile.write("NEED_LIBUNWIND := YesPlease\n") + + # Dynamic adaptations + # While `platform` enable complex toolchains, they are statically applied + # For a dynamic adaptsation of the compilation, the generated Makefile should check and adapt things itself + + # Check and adapt the targeted system + makefile.write("uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')\n") + makefile.write("ifeq ($(uname_S),Darwin)\n") + # remove -lunwind since it is already included on macosx + makefile.write("\tNEED_LIBUNWIND :=\n") + makefile.write("endif\n\n") + + # Check and adapt for the compiler used + # clang need an additionnal `-Qunused-arguments` + makefile.write("clang_check := $(shell sh -c '$(CC) -v 2>&1 | grep -q clang; echo $$?')\nifeq ($(clang_check), 0)\n\tCFLAGS += -Qunused-arguments\nendif\n") + + makefile.write("ifdef NEED_LIBUNWIND\n\tLDLIBS += -lunwind\nendif\n") - makefile.write("CC = ccache cc\nCFLAGS = -g -O2\nCINCL = {cc_includes}\nLDFLAGS ?= \nLDLIBS ?= -lm -lgc {linker_options.join(" ")}\n\n") makefile.write("all: {outpath}\n\n") var ofiles = new Array[String] diff --git a/src/debugger.nit b/src/debugger.nit index 697f86b..75486cb 100644 --- a/src/debugger.nit +++ b/src/debugger.nit @@ -23,7 +23,6 @@ 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 @@ -124,23 +123,11 @@ 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 @@ -158,12 +145,8 @@ 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 @@ -176,53 +159,11 @@ 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 diff --git a/src/debugger_socket.nit b/src/debugger_socket.nit new file mode 100644 index 0000000..07cf16d --- /dev/null +++ b/src/debugger_socket.nit @@ -0,0 +1,121 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Copyright 2014 Johan Kayser +# +# 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. + +# Debugging of a nit program using sockets. +module debugger_socket + +intrude import debugger +import websocket + +redef class ToolContext + # --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_socket_mode) + self.option_context.add_option(self.opt_websocket_mode) + self.option_context.add_option(self.opt_debug_port) + end +end + +redef class ModelBuilder + # Execute the program from the entry point (Sys::main) of the `mainmodule` + # `arguments` are the command-line arguments in order + # REQUIRE that: + # 1. the AST is fully loaded. + # 2. the model is fully built. + # 3. the instructions are fully analysed. + redef fun run_debugger(mainmodule: MModule, arguments: Array[String]) + do + var time0 = get_time + self.toolcontext.info("*** START INTERPRETING ***", 1) + + 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 + + redef fun run_debugger_autorun(mainmodule: MModule, arguments: Array[String]) + do + var time0 = get_time + self.toolcontext.info("*** START INTERPRETING ***", 1) + + 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 diff --git a/src/global_compiler.nit b/src/global_compiler.nit index 8c6ac6c..9e79281 100644 --- a/src/global_compiler.nit +++ b/src/global_compiler.nit @@ -124,8 +124,8 @@ class GlobalCompiler # Compile class names (for the class_name and output_class_name methods) protected fun compile_class_names do var v = new_visitor - self.header.add_decl("extern const char const * class_names[];") - v.add("const char const * class_names[] = \{") + self.header.add_decl("extern const char *class_names[];") + v.add("const char *class_names[] = \{") for t in self.runtime_type_analysis.live_types do v.add("\"{t}\", /* {self.classid(t)} */") end diff --git a/src/mkcsrc b/src/mkcsrc index a408697..7ba4466 100755 --- a/src/mkcsrc +++ b/src/mkcsrc @@ -21,3 +21,6 @@ done perl -i -npe 's#"\.\./.*?([^/]*.h)"#"\1"#' "$out"/*.[ch] perl -i -npe 's#\S*/([^/]*.[ch])#\1#' "$out/Makefile" perl -i -npe 's#\.\./clib#.#' "$out/Makefile" + +# Remove old compilation flags +sed -i -e 's/OLDNITCOPT=.*/OLDNITCOPT=/' src/Makefile diff --git a/src/model/mmodule.nit b/src/model/mmodule.nit index 60a7c92..18e835d 100644 --- a/src/model/mmodule.nit +++ b/src/model/mmodule.nit @@ -69,7 +69,7 @@ end # A Nit module is usually associated with a Nit source file. class MModule - super MEntity + super MConcern # The model considered var model: Model @@ -84,7 +84,7 @@ class MModule var mgroup: nullable MGroup # The short name of the module - var name: String + redef var name: String # The origin of the definition var location: Location @@ -221,4 +221,6 @@ class MModule abort end end + + redef fun parent_concern do return mgroup end diff --git a/src/model/model.nit b/src/model/model.nit index 6732a16..7481338 100644 --- a/src/model/model.nit +++ b/src/model/model.nit @@ -33,6 +33,7 @@ import poset import location import mmodule import mdoc +import ordered_tree private import more_collections redef class Model @@ -106,6 +107,35 @@ redef class Model # The only null type var null_type: MNullType = new MNullType(self) + + # Build an ordered tree with from `concerns` + fun concerns_tree(mconcerns: Collection[MConcern]): ConcernsTree do + var seen = new HashSet[MConcern] + var res = new ConcernsTree + + var todo = new Array[MConcern] + todo.add_all mconcerns + + while not todo.is_empty do + var c = todo.pop + if seen.has(c) then continue + var pc = c.parent_concern + if pc == null then + res.add(null, c) + else + res.add(pc, c) + todo.add(pc) + end + seen.add(c) + end + + return res + end +end + +# An OrderedTree that can be easily refined for display purposes +class ConcernsTree + super OrderedTree[MConcern] end redef class MModule @@ -302,7 +332,7 @@ class MClass # The short name of the class # In Nit, the name of a class cannot evolve in refinements - var name: String + redef var name: String # The canonical name of the class # Example: `"owner::module::MyClass"` @@ -463,6 +493,9 @@ class MClassDef self.to_s = "{mmodule}#{mclass}" end + # Actually the name of the `mclass` + redef fun name do return mclass.name + # All declared super-types # FIXME: quite ugly but not better idea yet var supertypes: Array[MClassType] = new Array[MClassType] @@ -1514,7 +1547,7 @@ abstract class MProperty var intro_mclassdef: MClassDef # The (short) name of the property - var name: String + redef var name: String # The canonical name of the property # Example: "owner::my_module::MyClass::my_method" @@ -1799,6 +1832,9 @@ abstract class MPropDef self.to_s = "{mclassdef}#{mproperty}" end + # Actually the name of the `mproperty` + redef fun name do return mproperty.name + # Internal name combining the module, the class and the property # Example: "mymodule#MyClass#mymethod" redef var to_s: String diff --git a/src/model/model_base.nit b/src/model/model_base.nit index 39df50b..666ce8e 100644 --- a/src/model/model_base.nit +++ b/src/model/model_base.nit @@ -25,6 +25,15 @@ end # A named and possibly documented entity in the model. # This class is usefull to generalize presentation of entities to the human. abstract class MEntity + # The short (unqualified) name of this model entity + fun name: String is abstract +end + +# Something that represents a concern +abstract class MConcern + super MEntity + # The concern that contains `self` or null if `self` is the root of the concern hierarchy + fun parent_concern: nullable MConcern is abstract end # A visibility (for modules, class and properties) diff --git a/src/model/mproject.nit b/src/model/mproject.nit index cad2e39..7bd502e 100644 --- a/src/model/mproject.nit +++ b/src/model/mproject.nit @@ -21,10 +21,10 @@ import poset # A Nit project, thas encompass a product class MProject - super MEntity + super MConcern # The name of the project - var name: String + redef var name: String # The model of the project var model: Model @@ -44,15 +44,18 @@ class MProject model.mprojects.add(self) model.mproject_by_name.add_one(name, self) end + + # MProject are always roots of the concerns hierarchy + redef fun parent_concern do return null end # A group of modules in a project class MGroup - super MEntity + super MConcern # The name of the group # empty name for a default group in a single-module project - var name: String + redef var name: String # The englobing project var mproject: MProject @@ -74,6 +77,9 @@ class MGroup # nesting group (see `parent`) is bigger var in_nesting: POSetElement[MGroup] + # Is `self` the root of its project? + fun is_root: Bool do return mproject.root == self + # The filepath (usualy a directory) of the group, if any var filepath: nullable String writable @@ -89,6 +95,11 @@ class MGroup end end + redef fun parent_concern do + if not is_root then return parent + return mproject + end + redef fun to_s do return name end diff --git a/src/model_utils.nit b/src/model_utils.nit index b2c741b..be3fd4d 100644 --- a/src/model_utils.nit +++ b/src/model_utils.nit @@ -19,6 +19,50 @@ module model_utils import modelbuilder +redef class MGroup + fun in_nesting_intro_mclasses(min_visibility: MVisibility): Set[MClass] do + var res = new HashSet[MClass] + var lst = in_nesting.direct_smallers + for mmodule in mmodules do res.add_all mmodule.filter_intro_mclasses(min_visibility) + for mgrp in lst do res.add_all mgrp.in_nesting_intro_mclasses(min_visibility) + return res + end + + fun in_nesting_redef_mclasses(min_visibility: MVisibility): Set[MClass] do + var res = new HashSet[MClass] + var lst = in_nesting.direct_smallers + for mmodule in mmodules do res.add_all mmodule.filter_redef_mclasses(min_visibility) + for mgrp in lst do res.add_all mgrp.in_nesting_redef_mclasses(min_visibility) + return res + end + + fun in_nesting_intro_mclassdefs(min_visibility: MVisibility): Set[MClassDef] do + var res = new HashSet[MClassDef] + var lst = in_nesting.direct_smallers + for mmodule in mmodules do res.add_all mmodule.intro_mclassdefs(min_visibility) + for mgrp in lst do res.add_all mgrp.in_nesting_intro_mclassdefs(min_visibility) + return res + end + + fun in_nesting_redef_mclassdefs(min_visibility: MVisibility): Set[MClassDef] do + var res = new HashSet[MClassDef] + var lst = in_nesting.direct_smallers + for mmodule in mmodules do res.add_all mmodule.redef_mclassdefs(min_visibility) + for mgrp in lst do res.add_all mgrp.in_nesting_redef_mclassdefs(min_visibility) + return res + end + + # Collect nested modules + fun collect_mmodules: Set[MModule] do + var res = new HashSet[MModule] + res.add_all mmodules + for mgroup in in_nesting.direct_smallers do + res.add_all mgroup.collect_mmodules + end + return res + end +end + redef class MModule # The list of intro mclassdef in the module. @@ -45,6 +89,17 @@ redef class MModule return res end + # The list of intro mclass in the module. + # with visibility >= to min_visibility + fun filter_intro_mclasses(min_visibility: MVisibility): Set[MClass] do + var res = new HashSet[MClass] + for mclass in intro_mclasses do + if mclass.visibility < min_visibility then continue + res.add mclass + end + return res + end + # Get the list of mclasses refined in 'self'. fun redef_mclasses: Set[MClass] do var mclasses = new HashSet[MClass] @@ -54,6 +109,16 @@ redef class MModule return mclasses end + # Get the list of mclasses refined in 'self'. + fun filter_redef_mclasses(min_visibility: MVisibility): Set[MClass] do + var mclasses = new HashSet[MClass] + for c in mclassdefs do + if c.mclass.visibility < min_visibility then continue + if not c.is_intro then mclasses.add(c.mclass) + end + return mclasses + end + # Get the list of all mclasses imported by 'self'. fun imported_mclasses: Set[MClass] do var mclasses = new HashSet[MClass] @@ -67,7 +132,7 @@ redef class MModule fun in_nesting_intro_mclasses(min_visibility: MVisibility): Set[MClass] do var res = new HashSet[MClass] for mmodule in in_nesting.greaters do - for mclass in mmodule.intro_mclasses do + for mclass in mmodule.filter_intro_mclasses(min_visibility) do if mclass.visibility < min_visibility then continue res.add mclass end @@ -78,7 +143,7 @@ redef class MModule fun in_nesting_redef_mclasses(min_visibility: MVisibility): Set[MClass] do var res = new HashSet[MClass] for mmodule in self.in_nesting.greaters do - for mclass in mmodule.redef_mclasses do + for mclass in mmodule.filter_redef_mclasses(min_visibility) do if mclass.visibility < min_visibility then continue res.add mclass end diff --git a/src/nit.nit b/src/nit.nit index 36c3815..dc48db8 100644 --- a/src/nit.nit +++ b/src/nit.nit @@ -19,6 +19,7 @@ module nit import naive_interpreter import debugger +import debugger_socket # Create a tool context to handle options and paths var toolcontext = new ToolContext diff --git a/tests/emscripten.skip b/tests/emscripten.skip new file mode 100644 index 0000000..c782ec0 --- /dev/null +++ b/tests/emscripten.skip @@ -0,0 +1,2 @@ +init_inherit +init_linext diff --git a/tests/emscripten_nodejs.nit b/tests/emscripten_nodejs.nit new file mode 100644 index 0000000..5ada70d --- /dev/null +++ b/tests/emscripten_nodejs.nit @@ -0,0 +1,13 @@ +import emscripten +redef class IFStream + redef fun fill_buffer + do + print "NOT YET IMPLEMENTED" + abort + end + redef init open(f) + do + print "NOT YET IMPLEMENTED" + abort + end +end diff --git a/tests/sav/emscripten/emscripten_nodejs.res b/tests/sav/emscripten/emscripten_nodejs.res new file mode 100644 index 0000000..e69de29 diff --git a/tests/sav/emscripten/fixme/base_attr_gen_alt1.res b/tests/sav/emscripten/fixme/base_attr_gen_alt1.res new file mode 100644 index 0000000..b4de394 --- /dev/null +++ b/tests/sav/emscripten/fixme/base_attr_gen_alt1.res @@ -0,0 +1 @@ +11 diff --git a/tests/sav/emscripten/fixme/base_conflict_submodule_name.res b/tests/sav/emscripten/fixme/base_conflict_submodule_name.res new file mode 100644 index 0000000..4ad3dc3 --- /dev/null +++ b/tests/sav/emscripten/fixme/base_conflict_submodule_name.res @@ -0,0 +1 @@ +UNDEFINED diff --git a/tests/sav/emscripten/fixme/base_conflict_submodule_name_alt1.res b/tests/sav/emscripten/fixme/base_conflict_submodule_name_alt1.res new file mode 100644 index 0000000..4ad3dc3 --- /dev/null +++ b/tests/sav/emscripten/fixme/base_conflict_submodule_name_alt1.res @@ -0,0 +1 @@ +UNDEFINED diff --git a/tests/sav/emscripten/fixme/base_conflict_submodule_name_alt2.res b/tests/sav/emscripten/fixme/base_conflict_submodule_name_alt2.res new file mode 100644 index 0000000..4ad3dc3 --- /dev/null +++ b/tests/sav/emscripten/fixme/base_conflict_submodule_name_alt2.res @@ -0,0 +1 @@ +UNDEFINED diff --git a/tests/sav/emscripten_nodejs.res b/tests/sav/emscripten_nodejs.res new file mode 100644 index 0000000..174d681 --- /dev/null +++ b/tests/sav/emscripten_nodejs.res @@ -0,0 +1 @@ +Not executable (platform?) diff --git a/tests/sav/nitg-s/fixme/base_attr_gen_alt1.res b/tests/sav/nitg-s/fixme/base_attr_gen_alt1.res index 2c8186c..4ad3dc3 100644 --- a/tests/sav/nitg-s/fixme/base_attr_gen_alt1.res +++ b/tests/sav/nitg-s/fixme/base_attr_gen_alt1.res @@ -1 +1 @@ -Caught signal : Segmentation fault +UNDEFINED diff --git a/tests/sav/nitg-sg/fixme/base_attr_gen_alt1.res b/tests/sav/nitg-sg/fixme/base_attr_gen_alt1.res index 2c8186c..4ad3dc3 100644 --- a/tests/sav/nitg-sg/fixme/base_attr_gen_alt1.res +++ b/tests/sav/nitg-sg/fixme/base_attr_gen_alt1.res @@ -1 +1 @@ -Caught signal : Segmentation fault +UNDEFINED diff --git a/tests/tests.sh b/tests/tests.sh index b8ecd0a..6cfb9be 100755 --- a/tests/tests.sh +++ b/tests/tests.sh @@ -19,6 +19,7 @@ # Set lang do default to avoid failed tests because of locale export LANG=C +export LC_ALL=C export NIT_TESTING=true unset NIT_DIR @@ -318,6 +319,11 @@ case $engine in niti) enginebinname=nit ;; + emscripten) + enginebinname=nitg + OPT="-m emscripten_nodejs.nit --semi-global $OPT" + savdirs="sav/nitg-sg/" + ;; nitc) echo "disabled engine $engine" exit 0 @@ -409,6 +415,11 @@ for ii in "$@"; do inputs=/dev/null fi + ffout="$ff.bin" + if [ "$engine" = "emscripten" ]; then + ffout="$ff.bin.js" + fi + if [ "$engine" = "niti" ]; then cat > "./$ff.bin" < "$ff.cmp.err" > "$ff.compile.log" + $TIMEOUT $NITC --no-color $OPT -o "$ffout" "$i" $includes $nocc 2> "$ff.cmp.err" > "$ff.compile.log" ERR=$? if [ "x$verbose" = "xtrue" ]; then cat "$ff.compile.log" cat >&2 "$ff.cmp.err" fi fi + if [ "$engine" = "emscripten" ]; then + echo > "./$ff.bin" "nodejs $ffout \"\$@\"" + chmod +x "$ff.bin" + if grep "Fatal Error: more than one primitive class" "$ff.compile.log" > /dev/null; then + echo " [skip] do no not imports kernel" + echo >>$xml "" + continue + fi + fi if [ "$ERR" != 0 ]; then echo -n "! " cat "$ff.compile.log" "$ff.cmp.err" > "$ff.res"