Merge: nitg: Added PNaCl support for Nit
authorJean Privat <jean@pryen.org>
Thu, 22 May 2014 23:28:01 +0000 (19:28 -0400)
committerJean Privat <jean@pryen.org>
Thu, 22 May 2014 23:28:01 +0000 (19:28 -0400)
Added pnacl_platform.nit in order to generate all minimum files when compiling the nit.
Added pnacl.nit, it's the module providing the tools for PNaCl support in Nit.

Modified nitg.nit to register the pnacl_platform.
Modified abstract_compiler.nit for a specific main generation and to add an option.

Signed-off-by: Djomanix <johan.kayser@viacesi.fr>

Pull-Request: #416
Reviewed-by: Jean Privat <jean@pryen.org>
Reviewed-by: Alexis Laferrière <alexis.laf@xymus.net>
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>

126 files changed:
benchmarks/bench_engines.sh
benchmarks/bench_languages.sh
contrib/github_merge.nit
contrib/pep8analysis/src/ast/rich_instructions.nit
contrib/pep8analysis/src/parser/parser_nodes.nit
examples/leapfrog/leapfrog_curses.nit
examples/shoot/src/shoot_logic.nit
examples/socket_client.nit
examples/socket_server.nit
examples/websocket_server.nit
lib/a_star.nit
lib/android/android.nit [new file with mode: 0644]
lib/android/log.nit [new file with mode: 0644]
lib/android/platform.nit [moved from lib/android.nit with 65% similarity]
lib/app.nit [new file with mode: 0644]
lib/github_api.nit
lib/java.nit
lib/json/.gitattributes [moved from lib/simple_json_reader/.gitattributes with 100% similarity]
lib/json/.gitignore [moved from lib/simple_json_reader/.gitignore with 100% similarity]
lib/json/Makefile [moved from lib/simple_json_reader/Makefile with 100% similarity]
lib/json/dynamic.nit [new file with mode: 0644]
lib/json/json.nit
lib/json/json_lexer.nit [moved from lib/simple_json_reader/json_lexer.nit with 100% similarity]
lib/json/json_parser.nit [moved from lib/simple_json_reader/json_parser.nit with 100% similarity]
lib/json/json_reader.nit [deleted file]
lib/json/json_writer.nit [deleted file]
lib/json/jsonable.nit [deleted file]
lib/json/static.nit [moved from lib/simple_json_reader/simple_json_reader.nit with 86% similarity]
lib/json_serialization.nit
lib/jvm.nit
lib/mnit/assets.nit
lib/mnit/mnit.nit
lib/mnit/mnit_app.nit [moved from lib/mnit/app.nit with 89% similarity]
lib/mnit_android/android_app.nit
lib/mnit_input.nit
lib/mpd.nit
lib/nitcc_runtime.nit
lib/perfect_hashing.nit [new file with mode: 0644]
lib/poset.nit
lib/signals.nit
lib/socket/socket.nit
lib/standard/bitset.nit [new file with mode: 0644]
lib/standard/collection/abstract_collection.nit
lib/standard/collection/sorter.nit
lib/standard/file.nit
lib/standard/kernel.nit
lib/standard/kernel_nit.h [new file with mode: 0644]
lib/standard/posix.nit
lib/standard/ropes.nit
lib/standard/standard.nit
lib/standard/stream.nit
lib/standard/string.nit
lib/template.nit
lib/trees/abstract_tree.nit [new file with mode: 0644]
lib/trees/bintree.nit [new file with mode: 0644]
lib/trees/rbtree.nit [new file with mode: 0644]
lib/trees/trees.nit [new file with mode: 0644]
lib/union_find.nit [new file with mode: 0644]
lib/websocket.nit
misc/vim/indent/nit.vim
misc/vim/syntax/nit.vim
share/nitdoc/css/main.css
src/Makefile
src/abstract_compiler.nit
src/android_platform.nit
src/astbuilder.nit
src/auto_super_init.nit
src/cached.nit
src/coloring.nit [new file with mode: 0644]
src/common_ffi/c.nit
src/common_ffi/common_ffi.nit
src/common_ffi/cpp.nit
src/common_ffi/ffi_base.nit
src/common_ffi/java.nit
src/compiler_ffi.nit
src/debugger.nit
src/debugger_commons.nit [deleted file]
src/doc_template.nit [new file with mode: 0644]
src/layout_builders.nit [deleted file]
src/mkcsrc
src/model/model.nit
src/model_utils.nit
src/modelize_property.nit
src/naive_interpreter.nit
src/network_debugger.nit [deleted file]
src/ngall.sh
src/nit.nit
src/nitdbg_client.nit
src/nitdoc.nit
src/nitlight.nit
src/nitni/nitni_base.nit
src/nitni/nitni_callbacks.nit
src/nitni/nitni_utilities.nit
src/nitx.nit
src/parser/parser_nodes.nit
src/parser_util.nit
src/rapid_type_analysis.nit
src/separate_compiler.nit
src/separate_erasure_compiler.nit
src/toolcontext.nit
src/transform.nit
src/typing.nit
src/websocket_debugger.nit [deleted file]
tests/base_init_combine.nit [moved from src/nitdbg_server.nit with 53% similarity]
tests/bench_netsim.nit
tests/error_spe_attr.nit
tests/nitg-e.skip
tests/nitg-g.skip
tests/nitg-s.skip
tests/sav/base_init_combine.res [new file with mode: 0644]
tests/sav/base_init_combine_alt1.res [new file with mode: 0644]
tests/sav/base_init_simple_alt1.res
tests/sav/error_needed_method_alt1.res
tests/sav/test_ffi_java_use_module.res [new file with mode: 0644]
tests/sav/test_hash_text.res [new file with mode: 0644]
tests/sav/test_json.res [deleted file]
tests/sav/test_json_static.res [moved from tests/sav/test_simple_json_reader.res with 100% similarity]
tests/sav/test_kill_process.res [new file with mode: 0644]
tests/sav/test_markdown_args1.res
tests/sav/test_parser_args7.res
tests/test_ffi_java_use_module.nit [moved from src/nitdbg_websocket_server.nit with 52% similarity]
tests/test_hash_text.nit [new file with mode: 0644]
tests/test_json.nit [deleted file]
tests/test_json_static.nit [moved from tests/test_simple_json_reader.nit with 56% similarity]
tests/test_kill_process.nit [new file with mode: 0644]
tests/test_signals.nit

index 4168579..55db63e 100755 (executable)
@@ -262,7 +262,6 @@ function bench_nitg-s_options()
 bench_nitg-s_options "slower" --hardening --no-inline-intern --no-union-attribute --no-shortcut-equal --no-shortcut-range "--no-gcc-directive likely" "--no-gcc-directive noreturn"
 bench_nitg-s_options "nocheck" --no-check-covariance --no-check-attr-isset --no-check-assert --no-check-autocast --no-check-other
 bench_nitg-s_options "faster" --inline-coloring-numbers --inline-some-methods --direct-call-monomorph "--inline-some-methods --direct-call-monomorph"
-bench_nitg-s_options "typing" NOALL --bm-typing --phand-typing
 
 function bench_nitg-e_options()
 {
@@ -291,7 +290,6 @@ function bench_nitg-e_options()
 bench_nitg-e_options "slower" --hardening --no-inline-intern --no-union-attribute --no-shortcut-equal --no-shortcut-range
 bench_nitg-e_options "nocheck" --no-check-covariance --no-check-attr-isset --no-check-assert --no-check-autocast --no-check-other --no-check-erasure-cast
 bench_nitg-e_options "faster" --inline-coloring-numbers
-bench_nitg-e_options "typing" NOALL --bm-typing # --phand-typing
 
 function bench_engines()
 {
index 5348c8d..d9db525 100755 (executable)
@@ -232,27 +232,6 @@ function bench_language()
        done
 
 <<XXX
-       tg="nitg-s-bm"
-       prepare_res $nitdir/$name-$tg.dat "$tg" "$tg"
-       for b in $seq; do
-               run_command ./nitg $nitdir/${t}_$b.nit --separate --bm-typing -o "$nitdir/${t}_$b.$tg.bin" --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
-               bench_command "$b" "" "$nitdir/${t}_$b.$tg.bin" $s
-       done
-
-       tg="nitg-s-pha"
-       prepare_res $nitdir/$name-$tg.dat "$tg" "$tg"
-       for b in $seq; do
-               run_command ./nitg $nitdir/${t}_$b.nit --separate --phand-typing -o "$nitdir/${t}_$b.$tg.bin" --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
-               bench_command "$b" "" "$nitdir/${t}_$b.$tg.bin" $s
-       done
-
-       tg="nitg-s-phm"
-       prepare_res $nitdir/$name-$tg.dat "$tg" "$tg"
-       for b in $seq; do
-               run_command ./nitg $nitdir/${t}_$b.nit --separate --phmod-typing -o "$nitdir/${t}_$b.$tg.bin" --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
-               bench_command "$b" "" "$nitdir/${t}_$b.$tg.bin" $s
-       done
-
        prepare_res $nitdir/$name-nitg-su.dat "nitg-su" "nitg-su"
        for b in $seq; do
                run_command ./nitg $nitdir/${t}_$b.nit --separate --no-check-covariance -o "$nitdir/${t}_$b.nitg-su.bin" --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
index 12cb829..3a056ad 100644 (file)
@@ -36,7 +36,12 @@ redef class GithubCurl
                prm["statuses"] = statuses
                print "{prm["title"]}: by {prm["user"].json_as_map["login"]} (# {prm["number"]})"
                print "\tmergable: {prm["mergeable"]}"
-               print "\tstatus: {prm["statuses"].json_as_a[0].json_as_map["state"]}"
+               var st = prm["statuses"].json_as_a
+               if not st.is_empty then
+                       print "\tstatus: {st[0].json_as_map["state"]}"
+               else
+                       print "\tstatus: not tested"
+               end
                return prm
        end
 
@@ -58,6 +63,10 @@ redef class GithubCurl
                var res = new Array[String]
                for l in logins do
                        var u = get_and_check("https://api.github.com/users/{l}").json_as_map
+                       if not u.has_key("name") then
+                               print "No public name for user {l}"
+                               continue
+                       end
                        var r = "{u["name"]} <{u["email"]}>"
                        res.add r
 
index 6989980..8049e34 100644 (file)
@@ -145,7 +145,8 @@ abstract class ARichBinaryInstruction
                _n_id = src.n_id
                parent = src.parent
 
-               init(src.location)
+               init
+               _location = src.location
        end
 end
 
@@ -156,7 +157,8 @@ abstract class ARichUnaryInstruction
                _n_id = src.n_id
                parent = src.parent
 
-               init(src.location)
+               init
+               _location = src.location
        end
 end
 
index 62efb2a..3399de0 100644 (file)
@@ -6,7 +6,7 @@ import location
 
 # Root of the AST hierarchy
 abstract class ANode
-       var _location: nullable Location
+       var _location: nullable Location = null
 
        # Location is set during AST building. Once built, location cannon be null
        # However, manual instanciated nodes may need mode care
@@ -96,10 +96,12 @@ end
 class AInstruction
        super Prod
     readable writable var _n_id: TId
+       init do end
 end
 class AOperand
        super Prod
     readable var _n_value: AValue
+       init do end
 end
 class AValue super Prod end
 class ADirective super Prod end
@@ -109,10 +111,12 @@ class AListing
     readable var _n_lines: List[ALine] = new List[ALine]
     readable var _n_label_decl: nullable ALabelDecl = null
     readable var _n_end_block: TEndBlock
+       init do end
 end
 class AEmptyLine
        super ALine
     readable var _n_eol: TEol
+       init do end
 end
 abstract class ANonEmptyLine
        super ALine
@@ -121,16 +125,19 @@ class AInstructionLine
        super ANonEmptyLine
     readable var _n_instruction: AInstruction
     readable var _n_eol: TEol
+       init do end
 end
 class ADirectiveLine
        super ANonEmptyLine
     readable var _n_directive: ADirective
     readable var _n_eol: TEol
+       init do end
 end
 class ALabelDecl
        super Prod
     readable var _n_id: TId
     readable var _n_colon: TColon
+       init do end
 end
 class AUnaryInstruction
        super AInstruction
@@ -138,6 +145,7 @@ end
 class ABinaryInstruction
        super AInstruction
     readable var _n_operand: AOperand
+       init do end
 end
 class AImmediateOperand
        super AOperand
@@ -146,61 +154,74 @@ class AAnyOperand
        super AOperand
     readable var _n_comma: TComma
     readable var _n_id: TId
+       init do end
 end
 class ALabelValue
        super AValue
     readable var _n_id: TId
+       init do end
 end
 class ANumberValue
        super AValue
     readable var _n_number: TNumber
+       init do end
 end
 class ACharValue
        super AValue
     readable var _n_char: TChar
+       init do end
 end
 class AStringValue
        super AValue
     readable var _n_string: TString
+       init do end
 end
 class AHexValue
        super AValue
     readable var _n_hex: THex
+       init do end
 end
 class AByteDirective
        super ADirective
     readable var _n_tk_byte: TTkByte
     readable var _n_value: AValue
+       init do end
 end
 class AWordDirective
        super ADirective
     readable var _n_tk_word: TTkWord
     readable var _n_value: AValue
+       init do end
 end
 class ABlockDirective
        super ADirective
     readable var _n_tk_block: TTkBlock
     readable var _n_value: AValue
+       init do end
 end
 class AAsciiDirective
        super ADirective
     readable var _n_tk_ascii: TTkAscii
     readable var _n_value: AValue
+       init do end
 end
 class AAddrssDirective
        super ADirective
     readable var _n_tk_addrss: TTkAddrss
     readable var _n_value: AValue
+       init do end
 end
 class AEquateDirective
        super ADirective
     readable var _n_tk_equate: TTkEquate
     readable var _n_value: AValue
+       init do end
 end
 class ABurnDirective
        super ADirective
     readable var _n_tk_burn: TTkBurn
     readable var _n_value: AValue
+       init do end
 end
 
 class Start
@@ -209,7 +230,7 @@ class Start
     readable var _n_eof: EOF
        init(n_base: nullable AListing, n_eof: EOF)
        do
-               super(null)
+               super
                _n_base = n_base
                _n_eof = n_eof
        end
index 0420277..da05bf8 100644 (file)
@@ -121,9 +121,9 @@ redef class PlayScene
                sys.nanosleep(0, 48000000)
 
                # Keyboard input
-               while stdin.poll_in do
-                       if stdin.eof then return
-                       var c = stdin.read_char
+               while sys.stdin.poll_in do
+                       if sys.stdin.eof then return
+                       var c = sys.stdin.read_char
                        if c == 'q'.ascii then
                                self.exists = false
                                return
index 907b8b1..3443a47 100644 (file)
@@ -209,7 +209,7 @@ class Missile
        super Shoot
 
        # The target aquired by the missile
-       var target: nullable Sprite
+       var target: nullable Sprite = null
 
        # When ttl is 0 then the angle stay fixed
        # The angle is updated toward the target if ttl>0
index d7659e7..0ba1913 100644 (file)
@@ -24,12 +24,15 @@ if args.length < 2 then
        return
 end
 
-var s = new Socket.stream_with_host(args[0], args[1].to_i)
+var s = new Socket.client(args[0], args[1].to_i)
 print "[HOST ADDRESS] : {s.address}"
-print "[HOST] : {s.host.as(not null)}"
-print "[PORT] : {s.port.to_s}"
-print "Connecting ... {s.connect.to_s}"
-print "Writing ... {s.write("Hello server !").to_s}"
-print "[Response from server] : {s.read.to_s}"
-print "Closing ... {s.close.to_s}"
-
+print "[HOST] : {s.host}"
+print "[PORT] : {s.port}"
+print "Connecting ... {s.connected}"
+if s.connected then
+       print "Writing ... Hello server !"
+       s.write("Hello server !")
+       print "[Response from server] : {s.read(100)}"
+       print "Closing ..."
+       s.close
+end
index 9df9d79..aa77a75 100644 (file)
@@ -24,10 +24,8 @@ if args.is_empty then
        return
 end
 
-var socket = new Socket.stream_with_port(args[0].to_i)
+var socket = new Socket.server(args[0].to_i, 1)
 print "[PORT] : {socket.port.to_s}"
-print "Binding ... {socket.bind.to_s}"
-print "Listening ... {socket.listen(3).to_s}"
 
 var clients = new Array[Socket]
 var max = socket
@@ -45,9 +43,10 @@ loop
        if fs.readset.is_set(socket) then
                var ns = socket.accept
                print "Accepting {ns.address} ... "
-               print "[Message from {ns.address}] : {ns.read}"
+               print "[Message from {ns.address}] : {ns.read(100)}"
                ns.write("Goodbye client.")
-               print "Closing {ns.address} ... {ns.close.to_s}"
+               print "Closing {ns.address} ..."
+               ns.close
        end
 end
 
index c011cf2..38029c3 100644 (file)
@@ -23,22 +23,23 @@ var sock = new WebSocket(8088, 1)
 
 var msg: String
 
-if not sock.listener.still_alive then
+if sock.listener.eof then
        print sys.errno.strerror
 end
 
 sock.accept
 
-while sock.listener.still_alive do
+while not sock.listener.eof do
        if not sock.connected then sock.accept
-       if stdin.poll_in then
+       if sys.stdin.poll_in then
                msg = gets
-               if msg == "exit" then sock.stop_server
+               printn "Received message : {msg}"
+               if msg == "exit" then sock.close
                if msg == "disconnect" then sock.disconnect_client
                sock.write(msg)
        end
        if sock.can_read(10) then
-               msg = sock.read
+               msg = sock.read_line
                if msg != "" then print msg
        end
 end
index 2f18583..c6f6329 100644 (file)
@@ -58,7 +58,7 @@ module a_star
 redef class Object
        protected fun debug_a_star: Bool do return false
        private fun debug(msg: String) do if debug_a_star then
-               stderr.write "a_star debug: {msg}\n"
+               sys.stderr.write "a_star debug: {msg}\n"
        end
 end
 
diff --git a/lib/android/android.nit b/lib/android/android.nit
new file mode 100644 (file)
index 0000000..0d9bfcb
--- /dev/null
@@ -0,0 +1,37 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# Android services and implementation of app.nit
+#
+# To use this module and compile for Android, you must install the
+# Android SDK (with API level 10) and NDK (with the API level 9).
+# The tools `android`, `ndk-build` and `ant` must be in your PATH.
+#
+# This module provides basic logging facilities, advanced logging can be
+# achieved by importing `android::log`.
+module android
+
+import platform
+private import log
+
+# Uses Android logs to print everything
+redef fun print(text) do log_write(priority_info, app.log_prefix.to_cstring, text.to_s.to_cstring)
+
+redef class App
+       redef fun log_error(msg) do log_write(priority_error, log_prefix.to_cstring, msg.to_cstring)
+
+       redef fun log_warning(msg) do log_write(priority_warn, log_prefix.to_cstring, msg.to_cstring)
+end
diff --git a/lib/android/log.nit b/lib/android/log.nit
new file mode 100644 (file)
index 0000000..30beb62
--- /dev/null
@@ -0,0 +1,53 @@
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# Advanced Android logging services
+module log
+
+import platform
+
+in "C" `{
+       #include <android/log.h>
+`}
+
+# Default Android log priority
+protected fun priority_default: Int do return 1
+
+# Verbose Android log priority
+protected fun priority_verbose: Int do return 2
+
+# Debug Android log priority
+protected fun priority_debug: Int do return 3
+
+# Info Android log priority
+protected fun priority_info: Int do return 4
+
+# Warn Android log priority
+protected fun priority_warn: Int do return 5
+
+# Error Android log priority
+protected fun priority_error: Int do return 6
+
+# Fatal Android log priority
+protected fun priority_fatal: Int do return 7
+
+# Silent Android log priority
+protected fun priority_silent: Int do return 8
+
+# Write `text` to Android log at priority `level` with tag `tag`
+protected fun log_write(level: Int, tag, text: NativeString) `{
+       __android_log_write(level, tag, text);
+`}
similarity index 65%
rename from lib/android.nit
rename to lib/android/platform.nit
index 91e9f66..9b8b189 100644 (file)
@@ -1,5 +1,7 @@
 # This file is part of NIT ( http://www.nitlanguage.org ).
 #
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
 # 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
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Targets the Android platform
-#
-# To use this module and compile for Android, you must install the
-# Android SDK (with API level 10) and NDK (with the API level 9).
-# The tools `android`, `ndk-build` and `ant` must be in your PATH.
-#
-# Will, in the near future, provide services specific to Android.
-module android is platform
+module platform is platform("android")
 
 import java
+import app
diff --git a/lib/app.nit b/lib/app.nit
new file mode 100644 (file)
index 0000000..b896dad
--- /dev/null
@@ -0,0 +1,44 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2011-2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# app.nit is a framework to create cross-platform applications
+#
+# The features offered by this modules are common to all platforms, but
+# may not be available on all devices.
+module app
+
+# App subclasses are cross-platform applications
+#
+# This class is redefed by plateform modules and so
+# App can be specialized directly in the user app.
+class App
+       private init do end
+
+       # Main entry point of your application
+       fun run do end
+
+       # Prefix to all log messages, used by `log_error`, `log_warning` and `log_info`.
+       fun log_prefix: String do return "app.nit"
+
+       # Helper function for logging errors
+       fun log_error(msg: String) do sys.stderr.write "{log_prefix} error: {msg}\n"
+
+       # Helper function for logging warnings
+       fun log_warning(msg: String) do sys.stderr.write "{log_prefix} warn: {msg}\n"
+end
+
+protected fun app: App do return once new App
+app.run
index b0240ca..d1a66e6 100644 (file)
@@ -17,7 +17,7 @@
 module github_api
 
 import curl
-import simple_json_reader
+import json::static
 
 # Specific Curl that know hot to talk to the github API
 class GithubCurl
index b27f627..de82015 100644 (file)
@@ -156,4 +156,11 @@ redef extern class JavaObject
                JNIEnv *env = Sys_jni_env(sys);
                (*env)->DeleteGlobalRef(env, recv);
        `}
+
+       # Delete this local reference
+       fun delete_local_ref import sys, Sys.jni_env `{
+               Sys sys = JavaObject_sys(recv);
+               JNIEnv *env = Sys_jni_env(sys);
+               (*env)->DeleteLocalRef(env, recv);
+       `}
 end
diff --git a/lib/json/dynamic.nit b/lib/json/dynamic.nit
new file mode 100644 (file)
index 0000000..ec3ba25
--- /dev/null
@@ -0,0 +1,226 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# Dynamic interface to read Json strings.
+#
+# `String::to_json_value` returns a `JsonValue` which can be queried
+# to get the underlying Json data. It can also be used as any Json types.
+module dynamic
+
+private import static
+import standard
+
+class JsonValue
+       var value: nullable Object
+
+       # Is this value null?
+       #
+       #     assert "null".to_json_value.is_null
+       #     assert not "123".to_json_value.is_null
+       fun is_null: Bool do return value == null
+
+       # Is this value an integer?
+       #
+       #     assert "123".to_json_value.is_int
+       #     assert not "1.23".to_json_value.is_int
+       #     assert not "\"str\"".to_json_value.is_int
+       fun is_int: Bool do return value isa Int
+
+       # Get this value as a `Int`
+       #
+       # require: `self.is_int`
+       #
+       #     assert "-10".to_json_value.to_i == -10
+       #     assert "123".to_json_value.to_i == 123
+       fun to_i: Int do return value.as(Int)
+
+       # Is this value a float?
+       #
+       #     assert "0.0".to_json_value.is_float
+       #     assert "123.456".to_json_value.is_float
+       #     assert not "123".to_json_value.is_float
+       fun is_float: Bool do return value isa Float
+
+       # Get this value as a `Float`
+       #
+       # require: `self.is_float`
+       #
+       #     assert "0.0".to_json_value.to_f == 0.0
+       #     assert "123.456".to_json_value.to_f == 123.456
+       fun to_f: Float do return value.as(Float)
+
+       # Is the value numeric?
+       #
+       #     assert "1.234".to_json_value.is_numeric
+       #     assert "1234".to_json_value.is_numeric
+       #     assert not "\"str\"".to_json_value.is_numeric
+       #     assert not "1.2.3.4".to_json_value.is_numeric
+       fun is_numeric: Bool do return is_int or is_float
+
+       # Get this value as a `Numeric`
+       #
+       # require: `self.is_numeric`
+       #
+       #     assert "1.234".to_json_value.to_numeric = 1.234
+       #     assert "1234".to_json_value.to_numeric = 1234
+       fun to_numeric: Numeric
+       do
+               if is_int then return to_i
+               return to_f
+       end
+
+       # Is this value a boolean?
+       #
+       #     assert "true".to_json_value.is_bool
+       #     assert "false".to_json_value.is_bool
+       fun is_bool: Bool do return value isa Bool
+
+       # Get this value as a `Bool`
+       #
+       # require: `self.is_bool`
+       #
+       #     assert "true".to_json_value.to_bool
+       #     assert not "false".to_json_value.to_bool
+       fun to_bool: Bool do return value.as(Bool)
+
+       # Is this value a string?
+       #
+       #     assert "\"str\"".to_json_value.is_string
+       #     assert not "123".to_json_value.is_string
+       fun is_string: Bool do return value isa String
+
+       # Get this value as a `String`
+       #
+       # If value is null, return "null", otherwise returns `value.to_s`. It is practical
+       # on most types, except maps which does not have a custom `to_s`.
+       #
+       #     assert "\"str\"".to_json_value.to_s == "str"
+       #     assert "123".to_json_value.to_s == "123"
+       #     assert "true".to_json_value.to_s == "true"
+       #     assert "[1, 2, 3]".to_json_value.to_s == "123"
+       redef fun to_s: String
+       do
+               if value == null then return "null"
+               return value.to_s
+       end
+
+       ### Objects
+
+       # Is this value a Json object (a map)?
+       #
+       #     assert """{"a": 123}""".to_json_value.is_map
+       #     assert not "123".to_json_value.is_map
+       fun is_map: Bool do return value isa HashMap[String, nullable Object]
+
+       # Get this value as a `Map[String, JsonValue]`
+       #
+       # require: `self.is_map`
+       fun to_map: Map[String, JsonValue] do
+               var value = value
+               assert value isa HashMap[String, nullable Object]
+
+               var map = new HashMap[String, JsonValue]
+               for k, v in value do map[k] = new JsonValue(v)
+               return map
+       end
+
+       ### Arrays
+
+       # Is this value an array?
+       #
+       #     assert "[]".to_json_value.is_array
+       #     assert "[1, 2, 3, 4, 5]".to_json_value.is_array
+       #     assert "[null, true, false, 0.0, 1, \"str\"]".to_json_value.is_array
+       #     assert """["a", "b", "c"]""".to_json_value.is_array
+       fun is_array: Bool do return value isa Array[nullable Object]
+
+       # Get this value as an `Array[JsonValue]`
+       #
+       # require: `self.is_array`
+       #
+       #     assert """["a", "b", "c"]""".to_json_value.to_a.join(", ") == "a, b, c"
+       fun to_a: Array[JsonValue]
+       do
+               var value = value
+               assert value isa Array[nullable Object]
+
+               var a = new Array[JsonValue]
+               for e in value do a.add(new JsonValue(e))
+               return a
+       end
+
+       # Iterator over the values of the array `self`
+       #
+       # require: `self.is_array`
+       #
+       #     var a = new Array[String]
+       #     for e in """["a", "b", "c"]""".to_json_value do a.add(e.to_s)
+       #     assert a[0] == "a"
+       #     assert a[1] == "b"
+       #     assert a[2] == "c"
+       fun iterator: Iterator[JsonValue] do return to_a.iterator
+
+       # Get value at index `key` on the array or map `self`
+       #
+       # require: `self.is_array or self.is_map`
+       # require: `self.is_array implies key isa Int`
+       #
+       #     assert """{"a": 123}""".to_json_value["a"].to_i == 123
+       #     assert """{"123": "a"}""".to_json_value[123].to_s == "a"
+       #     assert """{"John Smith": 1980}""".to_json_value[["John ", "Smith"]].to_i == 1980
+       #
+       #     assert """["a", "b", "c"]""".to_json_value[0].to_s == "a"
+       fun [](key: Object): JsonValue
+       do
+               var value = value
+               if value isa HashMap[String, nullable Object] then
+                       return new JsonValue(value[key.to_s])
+               else if value isa Array[nullable Object] then
+                       assert key isa Int
+                       return new JsonValue(value[key])
+               else abort
+       end
+
+       # Advanced query to get a value within the map `self` or it's children.
+       #
+       # A query is composed of the keys to each map seperated by '.'.
+       #
+       # require: `self.is_map`
+       #
+       #     assert """{"a": {"t": true, "f": false}}""".to_json_value.get("a").is_map
+       #     assert """{"a": {"t": true, "f": false}}""".to_json_value.get("a.t").to_bool
+       #     assert not """{"a": {"t": true, "f": false}}""".to_json_value.get("a.f").to_bool
+       #     assert """{"a": {"b": {"c": {"d": 123}}}}""".to_json_value.get("a.b.c.d").to_i == 123
+       fun get(query: String): JsonValue
+       do
+               var keys = query.split(".")
+               var value = value
+               for key in keys do
+                       assert value isa HashMap[String, nullable Object]
+                       value = value[key]
+               end
+               return new JsonValue(value)
+       end
+end
+
+redef class String
+       # Parse `self` to obtain a `JsonValue`
+       fun to_json_value: JsonValue
+       do
+               var value = json_to_nit_object
+               return new JsonValue(value)
+       end
+end
index 1e9522f..9353350 100644 (file)
@@ -1,6 +1,6 @@
 # This file is part of NIT ( http://www.nitlanguage.org ).
 #
-# Copyright 2012-2013 Alexis Laferrière <alexis.laf@xymus.net>
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Writing to and reading from the Json format.
-# Based on the json0 C library
+# Offers two APIs to manipulate read Json strings.
+#
+# The `dynamic` module provides a simple interface to get information
+# from a Json document. You must be careful as all services are provided on
+# each nodes and a wrongful use can `abort`.
+#
+# The `static` module converts a Json string to a nullable Nit object. The object
+# must then be type checked before it can be used.
 module json
 
-import jsonable
-import json_reader
-import json_writer
-
-redef class String
-       fun json_load_from_file : nullable Map[ String, nullable Jsonable ]
-       do
-               var f = new IFStream.open( self )
-               var data = f.read_all.json_to_object
-               f.close
-
-               return data.as(not null) # ( Map[ String, nullable Jsonable ] )
-       end
-end
+import static
+import dynamic
diff --git a/lib/json/json_reader.nit b/lib/json/json_reader.nit
deleted file mode 100644 (file)
index 6af4fb8..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Copyright 2012-2013 Alexis Laferrière <alexis.laf@xymus.net>
-#
-# This file is free software, which comes along with NIT.  This software is
-# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-# without  even  the implied warranty of  MERCHANTABILITY or  FITNESS FOR A 
-# PARTICULAR PURPOSE.  You can modify it is you want,  provided this header
-# is kept unaltered, and a notification of the changes is added.
-# You  are  allowed  to  redistribute it and sell it, alone or is a part of
-# another product.
-
-# Deserialisation from the Json format to Nit objects
-module json_reader
-
-intrude import jsonable
-
-in "C Header" `{
-       #define __STRICT_ANSI__
-       #include <json/json.h>
-`}
-
-redef class String
-       # Deserializes this String and return its value as a Map[String, nullable Jsonable]
-       # On error, null is returned.
-       fun json_to_object : nullable Map[String, nullable Jsonable] import NativeString.to_s, JsonObject.json_to_map `{
-               char *native_recv;
-               json_object *jobj;
-               nullable_Map_of_String_nullable_Jsonable map;
-
-               native_recv = String_to_cstring( recv );
-               jobj = json_tokener_parse( native_recv );
-               map = JsonObject_json_to_map( jobj );
-
-               /*json_object_put( jobj );*/
-               return map;
-       `}
-end
-
-redef extern class JsonObject
-       # Get this json object as a Map
-       private fun json_to_map : nullable Map[String, nullable Jsonable] import NativeString.to_s, String.to_cstring, HashMap[String,nullable Jsonable], HashMap[String,nullable Jsonable].[]=, json_cross, HashMap[String, nullable Jsonable].as(nullable Map[String, nullable Jsonable]) `{
-               HashMap_of_String_nullable_Jsonable map;
-               String nit_key;
-               nullable_Jsonable nit_val;
-               enum json_type type;
-
-               map = new_HashMap_of_String_nullable_Jsonable();
-
-               { /* prevents "mixed declaration and code" warning for C90 */
-               json_object_object_foreach( recv, key, val ) {
-                       nit_key = NativeString_to_s( key );
-
-                       if ( val == NULL ) type = json_type_null;
-                       else type = json_object_get_type( val );
-
-                       nit_val = JsonObject_json_cross( val, type );
-
-                       HashMap_of_String_nullable_Jsonable__index_assign( map, nit_key, nit_val );
-               }
-               }
-
-               return HashMap_of_String_nullable_Jsonable_as_nullable_Map_of_String_nullable_Jsonable( map );
-       `}
-
-       # Get this json object as a Bool
-       private fun json_to_bool : Bool `{
-               return json_object_get_boolean( recv );
-       `}
-
-       # Get this json object as a Float
-       private fun json_to_float : Float `{
-               return json_object_get_double( recv );
-       `}
-
-       # Get this json object as an Int
-       private fun json_to_int : Int `{
-               return json_object_get_int( recv );
-       `}
-
-       # Get this json object as a Sequence
-       private fun json_to_sequence : Sequence[nullable Jsonable] import Array[nullable Jsonable], Array[nullable Jsonable].push, json_cross, Array[nullable Jsonable].as(Sequence[nullable Jsonable]) `{
-               array_list* jlist;
-               json_object* jobj;
-               nullable_Jsonable obj;
-               Array_of_nullable_Jsonable dest;
-               int i;
-               int len;
-               enum json_type type;
-
-               jlist = json_object_get_array( recv );
-               len = json_object_array_length( recv );
-               dest = new_Array_of_nullable_Jsonable();
-               for ( i = 0; i < len; i ++ ) {
-                       jobj = json_object_array_get_idx( recv, i );
-                       if ( jobj == NULL ) type = json_type_null;
-                       else type = json_object_get_type( jobj );
-                       obj = JsonObject_json_cross( jobj, type );
-                       Array_of_nullable_Jsonable_push( dest, obj );
-               }
-
-               return Array_of_nullable_Jsonable_as_Sequence_of_nullable_Jsonable( dest );
-       `}
-
-       # Get this json object as a String
-       private fun json_to_string : String import NativeString.to_s `{
-               const char *cstring;
-               cstring = json_object_get_string( recv );
-               return NativeString_to_s( (char*)cstring );
-       `}
-
-       # Intermediate function to convert to gt this Json object as a given type.
-       # Imlemented in Nit because Nit should manage all possible typing-related work.
-       private fun json_cross( json_type : Int ) : nullable Jsonable
-       do
-               if json_type == 0 then # null
-                       return null
-               else if json_type == 1 then # Bool
-                       return json_to_bool
-               else if json_type == 2 then # Float
-                       return json_to_float
-               else if json_type == 3 then # Int
-                       return json_to_int
-               else if json_type == 4 then # Map
-                       return json_to_map
-               else if json_type == 5 then # Sequence
-                       return json_to_sequence
-               else if json_type == 6 then # String
-                       return json_to_string
-               else
-                       print "WARNING: Unrecongnized json object type id: {json_type}"
-                       return null
-               end
-       end
-end
diff --git a/lib/json/json_writer.nit b/lib/json/json_writer.nit
deleted file mode 100644 (file)
index fcbe7ea..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Copyright 2012-2013 Alexis Laferrière <alexis.laf@xymus.net>
-#
-# This file is free software, which comes along with NIT.  This software is
-# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-# without  even  the implied warranty of  MERCHANTABILITY or  FITNESS FOR A 
-# PARTICULAR PURPOSE.  You can modify it is you want,  provided this header
-# is kept unaltered, and a notification of the changes is added.
-# You  are  allowed  to  redistribute it and sell it, alone or is a part of
-# another product.
-
-# Serialisation from Nit objects to the Json format
-module json_writer
-
-intrude import jsonable
-
-in "C Header" `{
-       #define __STRICT_ANSI__
-       #include <json/json.h>
-`}
-
-redef interface Jsonable
-       # Get a JsonObject representing this instance, specific to the C library
-       private fun to_json_object : JsonObject is abstract
-end
-
-# Will ignore non-jsonable
-redef class Map[ K, V ]
-       # Get a json-formatted string of this map
-       fun to_pretty_json: String do return native_to_json(true)
-       fun to_json: String do return native_to_json(false)
-
-       fun native_to_json( pretty: Bool ): String import to_json_object, NativeString.to_s `{
-               json_object *jobj;
-               const char *json_native_string;
-               String json_string;
-
-               jobj = Map_of_Object_nullable_Object_to_json_object( recv );
-#ifdef JSON_C_TO_STRING_PRETTY
-               if ( pretty )
-                       json_native_string = json_object_to_json_string_ext( jobj, JSON_C_TO_STRING_PRETTY );
-               else
-                       json_native_string = json_object_to_json_string_ext( jobj, JSON_C_TO_STRING_PLAIN );
-#else
-               json_native_string = json_object_to_json_string( jobj );
-#endif
-               json_string = NativeString_to_s( (char*)json_native_string );
-               return json_string;
-       `}
-
-       redef fun to_json_object
-       do
-               var jobj = new JsonObject
-
-               var iter = iterator
-               while iter.is_ok do
-                       var key = iter.key
-                       if key isa String then
-                               var val = iter.item
-                               if val isa Jsonable then
-                                       var jsubobj = val.to_json_object
-                                       jobj.add( key, jsubobj )
-                               else if val == null then
-                                       jobj.add( key, null )
-                               else
-                                       print "WARNING: value \"{val}\" not jsonable, cannot be converted to json."
-                               end
-                       else
-                               print "WARNING: key \"{key}\" not a string, cannot be converted to json."
-                       end
-
-                       iter.next
-               end
-               return jobj
-       end
-end
-
-redef class SequenceRead[ E ]
-       redef fun to_json_object
-       do
-               var jarray = new JsonArray
-               for e in self do
-                       if e isa nullable Jsonable then
-                               if e == null then
-                                       jarray.push( null )
-                               else
-                                       var obj = e.to_json_object
-                                       jarray.push( obj )
-                               end
-                       else
-                               print "WARNING: element \"{e}\" not a Jsonable, cannot be converted to json."
-                       end
-               end
-
-               return jarray
-       end
-end
-
-redef class String
-       redef fun to_json_object import NativeString.to_s, String.to_cstring `{
-               char *native_recv = String_to_cstring( recv );
-               return json_object_new_string( native_recv );
-       `}
-end
-
-redef class Int
-       redef fun to_json_object `{
-               return json_object_new_int( recv );
-       `}
-end
-
-redef class Bool
-       redef fun to_json_object `{
-               return json_object_new_boolean( recv );
-       `}
-end
-
-redef class Float
-       redef fun to_json_object `{
-               return json_object_new_double( recv );
-       `}
-end
-
-redef class JsonObject
-       new `{ return json_object_new_object(); `}
-
-       # Add a key and value to the object
-       fun add( key : String, val : nullable JsonObject ) import String.to_cstring, JsonObject.as not nullable `{
-               char* native_key;
-
-               native_key = String_to_cstring( key );
-
-               if ( nullable_JsonObject_is_null(val) ) {
-                       json_object_object_add( recv, native_key, NULL );
-               } else {
-                       json_object *jobj;
-                       jobj = nullable_JsonObject_as_JsonObject( val );
-                       json_object_object_add( recv, native_key, jobj );
-               }
-       `}
-end
-
-private extern class JsonArray
-       super JsonObject
-
-       new `{ return json_object_new_array(); `}
-
-       fun push( val : nullable JsonObject ) `{
-               if ( nullable_JsonObject_is_null(val) )
-                       json_object_array_add( recv, NULL );
-               else
-                       json_object_array_add( recv, nullable_JsonObject_as_JsonObject(val) );
-       `}
-end
diff --git a/lib/json/jsonable.nit b/lib/json/jsonable.nit
deleted file mode 100644 (file)
index 6eb95ac..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Copyright 2012-2013 Alexis Laferrière <alexis.laf@xymus.net>
-#
-# 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.
-
-# Basic json related functionalities
-module jsonable is pkgconfig("json")
-
-in "C Header" `{
-       #define __STRICT_ANSI__
-       #include <json/json.h>
-`}
-
-# Type supported by the Json format
-interface Jsonable
-end
-
-# Main object type used by C library
-private extern class JsonObject `{ struct json_object* `}
-       # Give up ownership of this object and decrease the reference count.
-       fun put `{ json_object_put( recv ); `}
-
-       # Aquire ownership of this object and increase the reference count.
-       fun get `{ json_object_get( recv ); `}
-end
-
-redef class SequenceRead[ V ]
-       super Jsonable
-end
-
-redef class String
-       super Jsonable
-end
-
-# Can b converted to a Json object
-redef class Map[ K, V ]
-       super Jsonable
-end
-
-redef class Int
-       super Jsonable
-end
-
-redef class Bool
-       super Jsonable
-end
-
-redef class Float
-       super Jsonable
-end
similarity index 86%
rename from lib/simple_json_reader/simple_json_reader.nit
rename to lib/json/static.nit
index 3ebc5eb..3d3f0f0 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-module simple_json_reader
+# Static interface to get Nit objects from a Json string.
+#
+# `String::json_to_nit_object` returns an equivalent Nit object from
+# the Json source. This object can then be type checked by the usual
+# languages features (`isa` and `as`).
+module static
 
 import standard
 private import json_parser
@@ -132,11 +137,14 @@ redef class String
                var root_node = parser.parse
                if root_node isa NStart then
                        return root_node.n_0.to_nit_object
-               else
-                       assert root_node isa NLexerError
+               else if root_node isa NLexerError then
+                       var pos = root_node.position
+                       print "Json lexer error: {root_node.message} at {pos or else "<unknown>"} for {root_node}"
+                       return null
+               else if root_node isa NParserError then
                        var pos = root_node.position
                        print "Json parsing error: {root_node.message} at {pos or else "<unknown>"} for {root_node}"
                        return null
-               end
+               else abort
        end
 end
index b361f88..c06c3f4 100644 (file)
@@ -17,7 +17,7 @@
 module json_serialization
 
 import serialization
-import simple_json_reader
+import json::static
 
 class JsonSerializer
        super Serializer
index 8a07b2a..36d3189 100644 (file)
@@ -374,6 +374,16 @@ extern class JniEnv `{JNIEnv *`}
        fun string_to_jobject(string: String): JavaObject `{
                return (*recv)->NewStringUTF(recv, String_to_cstring(string));
        `}
+
+       # Pushes a local reference frame on the JNI stack
+       fun push_local_frame(capacity: Int): Bool `{
+               return (*recv)->PushLocalFrame(recv, capacity);
+       `}
+
+       # Pops the current local reference frame on the JNI stack
+       fun pop_local_frame `{
+               (*recv)->PopLocalFrame(recv, NULL);
+       `}
 end
 
 # used to initialize a JavaVM 
@@ -390,7 +400,7 @@ extern class JMethodID `{jmethodID`}
 end
 
 # Represens a jni jobject
-extern class JavaObject `{jobject`}
+extern class JavaObject in "Java" `{ java.lang.Object `}
 end
 
 # Represents a jni JNINNativeMethod
index d538f03..f0d1892 100644 (file)
@@ -17,7 +17,7 @@
 # Manages all assets usable by an Mnit app
 module assets
 
-import app
+import mnit_app
 import mnit_display
 
 # General asset
index 2afb92c..3e313d4 100644 (file)
@@ -17,7 +17,7 @@
 # General module for cross-compatibility between multiple platforms
 module mnit
 
-import app
+import mnit_app
 import opengles1
 import assets
 import numbers
similarity index 89%
rename from lib/mnit/app.nit
rename to lib/mnit/mnit_app.nit
index 4fb0fcf..68af697 100644 (file)
 # limitations under the License.
 
 # General Mnit application structure
-module app
+module mnit_app
 
+import ::app
 import mnit_display
 
 # An App instance serves as base to every Mnit projects.
 #
 # This class is redefed by plateforme modules and so
 # App can be specialized directly in the user app.
-abstract class App
+redef class App
        type IE: InputEvent
        type D: Display
        type I: Image
@@ -83,15 +84,6 @@ abstract class App
        # Called before destroying the window
        fun term_window do end
 
-       # Helper function for logging
-       fun log_error( msg: String ) do print "#nit error: {msg}"
-
-       # Helper function for logging
-       fun log_warning( msg: String ) do print "#nit warn: {msg}"
-
-       # Helper function for logging
-       fun log_info( msg: String ) do print "#nit info: {msg}"
-
        # Receive and deal with all inputs
        fun input( event: InputEvent ): Bool
        do
index a1dea52..1aef9ee 100644 (file)
@@ -373,13 +373,6 @@ extern class AndroidKeyEvent in "C" `{AInputEvent *`}
        fun is_search_key: Bool do return key_code == 84
 end
 
-redef class Object
-       # Uses Android logs for every print
-       redef fun print(text: Object) is extern import Object.to_s, String.to_cstring `{
-               __android_log_print(ANDROID_LOG_INFO, "mnit print", "%s", String_to_cstring(Object_to_s(text)));
-       `}
-end
-
 redef class App
        redef type IE: AndroidInputEvent
        redef type D: Opengles1Display
@@ -393,13 +386,6 @@ redef class App
        var eventqueue: ASensorEventQueue
        var sensors_support_enabled writable = false
 
-       redef fun log_warning(msg) is extern import String.to_cstring `{
-               LOGW("%s", String_to_cstring(msg));
-       `}
-       redef fun log_info(msg) is extern import String.to_cstring `{
-               LOGI("%s", String_to_cstring(msg));
-       `}
-
        redef fun init_window
        do
                super
index 0536660..cd6c59d 100644 (file)
@@ -37,7 +37,9 @@ interface PointerEvent
        fun depressed: Bool is abstract
 end
 
-# Pointer motion event, mais concern many events
+# A motion event on screen composed of many `PointerEvent`
+#
+# Example of a `MotionEvent` a gesture such as pinching using two fingers.
 interface MotionEvent
        super InputEvent
 
index fd8fa5d..9a56b95 100644 (file)
@@ -34,12 +34,11 @@ class MPDConnection
        do
                var p: nullable Socket = null
 
-               p = new Socket.stream_with_host(host, port)
-               p.connect
+               p = new Socket.client(host, port)
 
                sys.nanosleep(0,5000)
 
-               var rep = p.read
+               var rep = p.read(1024)
                assert not rep.is_empty
                if not rep.has_prefix("OK") then
                        print "MPD responded {rep}"
@@ -61,7 +60,7 @@ class MPDConnection
 
                socket.write(msg)
                sys.nanosleep(0,5000)
-               var rep = socket.read
+               var rep = socket.read(1024)
                if not rep.has_prefix("OK") then
                        print "Error: MPD responded {rep}"
                        socket.close
@@ -82,7 +81,7 @@ class MPDConnection
 
                # get current status
                socket.write("status\n")
-               var rep = socket.read
+               var rep = socket.read(1024)
                for l in rep.split_with("\n") do
                        var words = l.split_with(" ")
                        if words.length > 1 then
@@ -153,7 +152,7 @@ class MPDConnection
                var time: nullable Int = null
 
                socket.write("currentsong\n")
-               var rep = socket.read
+               var rep = socket.read(1024)
                for l in rep.split_with("\n") do
                        var words = l.split_with(" ")
                        if words.length > 1 then
index 5f05815..51ee0c8 100644 (file)
@@ -473,8 +473,9 @@ end
 # A parser error linked to a unexpected token
 class NParserError
        super NError
+
        # The unexpected token
-       var token: nullable NToken
+       var token: nullable NToken = null
 
        redef fun unexpected
        do
@@ -550,7 +551,7 @@ abstract class TestParser
                var filepath = args.shift
                var text
                if filepath == "-" then
-                       text = stdin.read_all
+                       text = sys.stdin.read_all
                else if filepath == "-e" then
                        if args.is_empty then
                                print "Error: -e need a text"
diff --git a/lib/perfect_hashing.nit b/lib/perfect_hashing.nit
new file mode 100644 (file)
index 0000000..9ac59f3
--- /dev/null
@@ -0,0 +1,204 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Julien Pagès <julien.pages@lirmm.fr>
+#
+# 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.
+
+# Perfect hashing and perfect numbering
+module perfect_hashing
+
+# Class for Perfect Hashing operations with perfect numbering
+# It also stores the free identifiers for the perfect numbering
+class Perfecthashing
+
+       # Union of interval for implementing perfect numbering
+       # Represents the interval of free identifiers
+       # A null value represents the upper bound of identifier
+       private var interval: List[Couple[nullable Int, nullable Int]]
+
+       # An array used as a temporary Hashtable for 
+       # checking there is no collision between identifiers
+       private var tempht: Array[nullable Int]
+
+       # Initialize the structure of free identifiers
+       init
+       do
+               # By default, all identifiers are available
+               interval = new List[Couple[nullable Int, nullable Int]]
+               interval.push(new Couple[nullable Int, nullable Int](0, null))
+               tempht = new Array[nullable Int]
+       end
+       
+       # Returns a mask composed by discriminants bits
+       # for these given identifiers 
+       # The mask + 1 value is the size of the hastable to create
+       fun phand(ids: Array[Int]): Int
+       do
+               var mask = 1
+
+               # If ids is null return 1
+               if ids.length == 0 then
+                       return mask
+               end
+
+               var orMask = 0
+               var andMask = 0
+               for i in ids do
+                       orMask = orMask.bin_or(i)
+                       andMask = andMask.bin_and(i)
+               end
+
+               mask = orMask.bin_xor(andMask)
+
+               # Re-initialize the hashtable with null values
+               for i in [0..mask+1] do tempht[i] = null
+
+               # Optimize the already computed mask
+               var newmask = 0
+               var i = mask.highest_bit
+               while i != 0 do
+                       if mask.getbit(i) == 1 then
+                               newmask = mask.bin_xor(1.lshift(i))
+                               
+                               # If there is no collision, replace the old mask
+                               if phandp(ids, newmask) then
+                                       mask = newmask
+                               end
+                       end
+
+                       i -= 1
+               end
+
+               return mask + 1
+       end
+
+       # Checks if the mask is a perfect hashing function for
+       # these identifiers
+       fun phandp(ids: Array[Int], mask: Int): Bool
+       do
+               for i in ids do
+                       var hv = i.bin_and(mask)
+                       if tempht[hv] == mask then
+                               return false
+                       else
+                               tempht[hv] = mask
+                       end
+               end
+       
+               return true
+       end
+
+       # Perfect numbering : give new free identifiers
+       # ids : identifiers to hash (super-classes)
+       # n : number of required free identifiers
+       # idc : This array will be filled with n free identifiers
+       # return the size of hashTable to create for theses identifiers (mask + 1)
+       #     var ph = new Perfecthashing
+       #     var idc = new Array[Int]
+       #     assert ph.pnand([3, 7, 10], 1, idc) == 6
+       #     assert idc[0] == 4
+       #     var idc1 = new Array[Int]
+       #     assert ph.pnand([3, 7, 10], 1, idc1) == 6
+       #     assert idc1[0] == 6
+       fun pnand(ids: Array[Int], n: Int, idc: Array[Int]): Int
+       do
+               var mask = phand(ids) -1
+               var i = 0
+               while n+ids.length > (1.lshift(mask.number_bits(1))) do
+                       # When there are not enough 1-bits
+                       if mask.getbit(i) == 0 then
+                               mask = mask.bin_xor(1.lshift(i))
+                       end
+                       i += 1
+               end
+
+               # Resetting hashtable
+               phandp(ids, mask)
+
+               # Fill the given array with n free identifiers
+               compute_least_free_ids(n, mask, idc)
+
+               return mask + 1
+       end
+
+
+       # Compute free identifiers for future perfect numbering
+       # n : number of required ids
+       # mask : perfect hashing parameter
+       # idc : This array will be filled with n free identifiers
+       private fun compute_least_free_ids(n: Int, mask: Int, idc: Array[Int])
+       do
+               while n != 0 do
+                       idc.push(first_valid_id(mask))
+                       n = n - 1
+               end
+       end
+
+       # Returns the first valid free identifier which correspond to this mask
+       private fun first_valid_id(mask: Int): Int
+       do
+               # Search for the first valid free identifier
+               var inter = interval.iterator
+               var found = false
+               var id = 0
+               while inter.is_ok and not found do
+                       var i = inter.item.first.as(not null)
+                       while i != inter.item.second and not found do
+                               # Tests if this id is free for this mask
+                               var hv = i.bin_and(mask)
+
+                               # If the hashtable if full, push an empty item 
+                               if hv >= tempht.length then
+                                       tempht.push(null)
+                               end
+
+                               if tempht[hv] != mask then
+                                       found = true
+                                       id = i
+                               end     
+                               i = i + 1
+                       end
+
+                       if not found then
+                               inter.next
+                       end
+               end
+
+               # Updates the structure of union of intervals
+               if id == inter.item.first then
+                       if inter.item.first == inter.item.second then
+                               inter.delete
+                       else
+                               inter.item.first += 1
+                       end
+               else 
+                       if id != inter.item.first and id != inter.item.second then
+                               # We need to split in two this interval
+                               var last = inter.item.second
+                               inter.item.second = id - 1
+                               inter.next
+
+                               var p = new Couple[nullable Int, nullable Int](id + 1, last)
+                               if inter.is_ok then
+                                       inter.insert_before(p)
+                               else
+                                       interval.push(p)
+                               end
+                       else
+                               inter.item.second = id - 1
+                       end
+               end
+
+               return id
+       end
+end
index 65695da..ac0765e 100644 (file)
@@ -163,6 +163,13 @@ class POSet[E: Object]
                if res != 0 then return res
                return elements[a].count <=> elements[b].count
        end
+
+       # Sort a sorted array of poset elements using linearization order
+       fun linearize(elements: Collection[E]): Array[E] do
+               var lin = elements.to_a
+               sort(lin)
+               return lin
+       end
 end
 
 # View of an objet in a poset
index 88e5950..89f4a1b 100644 (file)
@@ -24,6 +24,21 @@ module signals
        #include <stdio.h>
 
        /*
+               This guard prevents errors by the C compiler when the Nit code imports this
+               module but do not use handle_signal. When it is _not_ used, the C type
+               SignalHandler and C function SignalHandler_receive_signal are not generated.
+               Which does not please the C compiler. This guard ensure that we compile this
+               code only if the type SignalHandler has been defined.
+
+               This is a HACK, FIXME by:
+               * Adding the macro to the FFI spec, or
+               * Attach the callbacks to this code block (or the module itself)
+               * Avoid using Nit types and callbacks or use them only in the C implementation
+                 of Nit method.
+       */
+       #ifdef NIT_TYPE_SignalHandler
+
+       /*
                Structure to manage each possible signals
                are used in an array of 32 maximum signals.
                This array is global to the software.
@@ -49,22 +64,53 @@ module signals
                        }
                }
        }
+
+       #endif
 `}
 
 # Receives the callback from system when a given signal arise
 interface SignalHandler
-       # Called on any signal received
-       fun receive_signal(signal: Int) `{
-       `}
+       # Invoked after a call to `check_signals` if a signal has been raised
+       # (should be redefed by subclasses)
+       #
+       # Should be used by most signals except `sigkill` and `sigstop` since they
+       # cannot be caught, blocked or ignored.
+       #
+       #     class MyReceiver
+       #         super SignalHandler
+       #     
+       #         redef fun receive_signal(signal) do print "received safely {signal}"
+       #     end
+       #     
+       #     var r = new MyReceiver
+       #     r.handle_signal(sigint, true) # will call back when "check_signals" is called
+       #     # ...
+       #     check_signals # if a signal was received, it will invoke `r.receive_signal`
+       fun receive_signal(signal: Int) do end
 
-       # Called on any unsafe signal received
-       fun receive_signal_unsafe(signal: Int) `{
-       `}
+       # Called immediatly on receiving an unsafe signal (should be redefed by subclasses)
+       #
+       # Should be used for `sigkill` and `sigstop` since they cannot be caught,
+       # blocked or ignored.
+       #
+       # You should consider this methods as being fragile. It should be implemented in C
+       # and you should not do too much callbacks to Nit.
+       #
+       #     class MyReceiver
+       #         super SignalHandler
+       #     
+       #         redef fun receive_signal_unsafe(signal) do print "received unsafely {signal}"
+       #     end
+       #     
+       #     var r = new MyReceiver
+       #     r.handle_signal(sigsegv, false) # `r.receive_signal_unsafe` will be invoked on sigsegv
+       fun receive_signal_unsafe(signal: Int) do end
 
        # Set the receiver as the handler of the signal
-       # If safely, receiver will be called when check_signals in invoked
-       #    otherwise the receiver is invoked when the signal is raised, it may
-       #    crash the Nit system but is unavoidable for unstoppable signals
+       #
+       # If `safely`, receiver will be called when `check_signals` in invoked
+       # otherwise the receiver is invoked when the signal is raised, it may
+       # crash the Nit system but is unavoidable for unstoppable signals.
        fun handle_signal(signal: Int, safely: Bool) import
                receive_signal `{
                SignalHandler last_handler;
@@ -118,89 +164,6 @@ interface SignalHandler
                                SignalHandler_decr_ref(last_handler);
                }
        `}
-
-       # Hang up detected on controlling terminal or death of controlling process
-       fun sighup: Int do return 1
-       
-       # Issued if the user sends an interrupt signal
-       fun sigint: Int do return 2
-       
-       # Issued if the user sends a quit signal
-       fun sigquit: Int do return 3
-       
-       # Issued if the user attempts to execute an illegal, malformed, unknown, or privileged instruction
-       fun sigill: Int do return 4
-       
-       # Issued when an exception occurs: a condition that a debugger has requested to be informed of
-       fun sigtrap: Int do return 5
-       
-       # This signal is sent to a process to tell it to abort, i. e. to terminate
-       fun sigabrt: Int do return 6
-       
-       #This signal is sent to a process when it causes a bus error
-       fun sigbus: Int do return 7
-       
-       # Issued if an illegal mathematical operation is attempted
-       fun sigfpe: Int do return 8
-       
-       # If a process gets this signal it must quit immediately and will not perform any clean-up operations
-       fun sigkill: Int do return 9
-       
-       # Sent to a process to indicate user-defined conditions
-       fun sigusr1: Int do return 10
-       
-       # Sent to a process when it makes an invalid virtual memory reference, or segmentation fault
-       fun sigsegv: Int do return 11
-       
-       # Sent to a process to indicate user-defined conditions
-       fun sigusr2: Int do return 12
-       
-       # Sent to a process when it attempts to write to a pipe without a process connected to the other end
-       fun sigpipe: Int do return 13
-       
-       # Alarm Clock signal
-       fun sigalarm: Int do return 14
-       
-       # Software termination signal
-       fun sigterm: Int do return 15
-       
-       # Sent to a process when a child process terminates or is interrupted
-       fun sigchild: Int do return 17
-       
-       # Tell the operating system to continue (restart) a process previously paused by the SIGSTOP or SIGTSTP signal
-       fun sigcont: Int do return 18
-       
-       # Tell the operating system to stop a process
-       fun sigstop: Int do return 19
-       
-       # Sent to a process by its terminal to request it to stop temporarily
-       fun sigtstp: Int do return 20
-       
-       # Sent to a process when a socket has urgent or out-of-band data available to read
-       fun sigurg: Int do return 23
-       
-       # Sent to a process when it has used the CPU for a duration that exceeds a user-settable value
-       fun sigxcpu: Int do return 24
-       
-       # Sent to a process when it grows a file larger than the maximum allowed size
-       fun sigxfsz: Int do return 25
-       
-       # Virtual timer expired
-       fun sigvtalrm: Int do return 26
-       
-       # Profiling timer expired
-       fun sigprof: Int do return 27
-       
-       # Sent to a process when its controlling terminal changes its window size 
-       fun sigwinch: Int do return 28
-       
-       # Sent to a process when the system experiences a power failure
-       fun sigpwr: Int do return 30
-       
-       # Sent to a process when it passes a bad argument to a system call
-       fun sigsys: Int do return 31
-       
-       
 end
 
 redef interface Object
@@ -226,3 +189,95 @@ redef interface Object
        # can callback any instance of SignalHandler, not just this one
        protected fun set_alarm(sec: Int) `{ alarm(sec); `}
 end
+
+redef class Process
+       # Send a signal to the process
+       fun signal(signal: Int) do native_kill(id, signal)
+
+       # Send the kill signal to the process
+       fun kill do signal(sigkill)
+       
+       # Native implementation of `signal`
+       private fun native_kill(pid, signal: Int) `{ kill(pid, signal); `}
+end
+
+# Hang up detected on controlling terminal or death of controlling process
+protected fun sighup: Int do return 1
+
+# Issued if the user sends an interrupt signal
+protected fun sigint: Int do return 2
+
+# Issued if the user sends a quit signal
+protected fun sigquit: Int do return 3
+
+# Issued if the user attempts to execute an illegal, malformed, unknown, or privileged instruction
+protected fun sigill: Int do return 4
+
+# Issued when an exception occurs: a condition that a debugger has requested to be informed of
+protected fun sigtrap: Int do return 5
+
+# This signal is sent to a process to tell it to abort, i. e. to terminate
+protected fun sigabrt: Int do return 6
+
+# This signal is sent to a process when it causes a bus error
+protected fun sigbus: Int do return 7
+
+# Issued if an illegal mathematical operation is attempted
+protected fun sigfpe: Int do return 8
+
+# If a process gets this signal it must quit immediately and will not perform any clean-up operations
+protected fun sigkill: Int do return 9
+
+# Sent to a process to indicate user-defined conditions
+protected fun sigusr1: Int do return 10
+
+# Sent to a process when it makes an invalid virtual memory reference, or segmentation fault
+protected fun sigsegv: Int do return 11
+
+# Sent to a process to indicate user-defined conditions
+protected fun sigusr2: Int do return 12
+
+# Sent to a process when it attempts to write to a pipe without a process connected to the other end
+protected fun sigpipe: Int do return 13
+
+# Alarm Clock signal
+protected fun sigalarm: Int do return 14
+
+# Software termination signal
+protected fun sigterm: Int do return 15
+
+# Sent to a process when a child process terminates or is interrupted
+protected fun sigchild: Int do return 17
+
+# Tell the operating system to continue (restart) a process previously paused by the SIGSTOP or SIGTSTP signal
+protected fun sigcont: Int do return 18
+
+# Tell the operating system to stop a process
+protected fun sigstop: Int do return 19
+
+# Sent to a process by its terminal to request it to stop temporarily
+protected fun sigtstp: Int do return 20
+
+# Sent to a process when a socket has urgent or out-of-band data available to read
+protected fun sigurg: Int do return 23
+
+# Sent to a process when it has used the CPU for a duration that exceeds a user-settable value
+protected fun sigxcpu: Int do return 24
+
+# Sent to a process when it grows a file larger than the maximum allowed size
+protected fun sigxfsz: Int do return 25
+
+# Virtual timer expired
+protected fun sigvtalrm: Int do return 26
+
+# Profiling timer expired
+protected fun sigprof: Int do return 27
+
+# Sent to a process when its controlling terminal changes its window size 
+protected fun sigwinch: Int do return 28
+
+# Sent to a process when the system experiences a power failure
+protected fun sigpwr: Int do return 30
+
+# Sent to a process when it passes a bad argument to a system call
+protected fun sigsys: Int do return 31
index 8919dbc..8c96d17 100644 (file)
@@ -21,6 +21,10 @@ import socket_c
 
 # Portal for communication between two machines
 class Socket
+       super BufferedIStream
+       super OStream
+       super PollableIStream
+
        # IPv4 address the socket is connected to
        # Formatted as xxx.xxx.xxx.xxx
        var address: String
@@ -38,18 +42,16 @@ class Socket
        # Underlying C socket
        private var addrin: FFSocketAddrIn
 
-       # Guard for errors
-       # If the socket could not be created or if the socket was destroyed
-       # before a call needing the socket was made
-       # this flag will be set to false.
-       var still_alive = true # Note : HUGE SUCCESS
+       redef var end_reached = false
 
        # Creates a socket connection to host `thost` on port `port`
-       init stream_with_host(thost: String, tport: Int)
+       init client(thost: String, tport: Int)
        do
+               _buffer = new FlatBuffer
+               _buffer_pos = 0
                socket = new FFSocket.socket( new FFSocketAddressFamilies.af_inet, new FFSocketTypes.sock_stream, new FFSocketProtocolFamilies.pf_null )
                if socket.address_is_null then
-                       still_alive = false
+                       end_reached = true
                        return
                end
                socket.setsockopt(new FFSocketOptLevels.socket, new FFSocketOptNames.reuseaddr, 1)
@@ -58,14 +60,17 @@ class Socket
                address = addrin.address
                host = hostname.h_name
                port = addrin.port
+               if not end_reached then end_reached = not connect
        end
 
-       # Creates a server socket on port `tport`
-       init stream_with_port(tport: Int)
+       # Creates a server socket on port `tport`, with a connection queue of size `max`
+       init server(tport: Int, max: Int)
        do
+               _buffer = new FlatBuffer
+               _buffer_pos = 0
                socket = new FFSocket.socket( new FFSocketAddressFamilies.af_inet, new FFSocketTypes.sock_stream, new FFSocketProtocolFamilies.pf_null )
                if socket.address_is_null then
-                       still_alive = false
+                       end_reached = true
                        return
                end
                socket.setsockopt(new FFSocketOptLevels.socket, new FFSocketOptNames.reuseaddr, 1)
@@ -73,11 +78,15 @@ class Socket
                address = addrin.address
                port = addrin.port
                host = null
+               bind
+               listen(max)
        end
 
        # Creates a client socket, this is meant to be used by accept only
        private init primitive_init(h: FFSocketAcceptResult)
        do
+               _buffer = new FlatBuffer
+               _buffer_pos = 0
                socket = h.socket
                addrin = h.addrIn
                address = addrin.address
@@ -85,94 +94,106 @@ class Socket
                host = null
        end
 
+       redef fun poll_in do return ready_to_read(0)
+
        # Returns an array containing an enum of the events ready to be read
        #
        # event_types : Combination of several event types to watch
        #
        # timeout : Time in milliseconds before stopping listening for events on this socket
        #
-       private fun poll_in(event_types: Array[FFSocketPollValues], timeout: Int): Array[FFSocketPollValues] do
-               if not still_alive then return new Array[FFSocketPollValues]
+       private fun pollin(event_types: Array[FFSocketPollValues], timeout: Int): Array[FFSocketPollValues] do
+               if end_reached then return new Array[FFSocketPollValues]
                return socket.socket_poll(new PollFD(socket.descriptor, event_types), timeout)
        end
 
-       # Easier use of poll_in to check for something to read on all channels of any priority
+       # Easier use of pollin to check for something to read on all channels of any priority
        #
        # timeout : Time in milliseconds before stopping to wait for events
        #
        fun ready_to_read(timeout: Int): Bool
        do
-               if not still_alive then return false
+               if _buffer_pos < _buffer.length then return true
+               if eof then return false
                var events = new Array[FFSocketPollValues]
                events.push(new FFSocketPollValues.pollin)
-               events.push(new FFSocketPollValues.pollrdnorm)
-               events.push(new FFSocketPollValues.pollpri)
-               events.push(new FFSocketPollValues.pollrdband)
-               return poll_in(events, timeout).length != 0
+               return pollin(events, timeout).length != 0
        end
 
        # Checks if the socket still is connected
        #
        fun connected: Bool
        do
-               if not still_alive then return false
+               if eof then return false
                var events = new Array[FFSocketPollValues]
                events.push(new FFSocketPollValues.pollhup)
                events.push(new FFSocketPollValues.pollerr)
-               return poll_in(events, 0).length == 0
+               if pollin(events, 0).length == 0 then
+                       return true
+               else
+                       end_reached = true
+                       return false
+               end
        end
 
+       redef fun is_writable do return not end_reached
+
        # Establishes a connection to socket addrin
        #
-       # REQUIRES : self.still_alive
-       fun connect: Bool do
-               assert still_alive
+       # REQUIRES : not self.end_reached
+       private fun connect: Bool
+       do
+               assert not end_reached
                return socket.connect(addrin) >= 0
        end
 
-       # Write a message to connected socket
-       #
-       # Returns `true` if the `msg` was sent, `false` otherwise
-       #
-       # If not socket.sill_alive, false will be returned
-       fun write(msg: String): Bool do
-               if not still_alive then return false
-               return socket.write(msg) >= 0
+       # If socket.end_reached, nothing will happen
+       redef fun write(msg: Text)
+       do
+               if end_reached then return
+               socket.write(msg.to_s)
        end
 
-       # Read from connected socket
-       #
-       # If the socket is disconnected, an empty string will be returned
-       fun read: String do
-               if not still_alive then return ""
-               return socket.read
+       fun write_ln(msg: Text)
+       do
+               if end_reached then return
+               write(msg.to_s)
+               write("\n")
        end
 
-       # Close connection
-       #
-       # Returns : `true` if the close was successful, `false` otherwise
-       fun close: Bool do
-               if not still_alive then return true
+       redef fun fill_buffer
+       do
+               _buffer.clear
+               _buffer_pos = 0
+               if not connected then return
+               var read = socket.read
+               if read.length == 0 then
+                       close
+                       end_reached = true
+               end
+               _buffer.append(read)
+       end
+
+       redef fun close do
+               if end_reached then return
                if socket.close >= 0 then
-                       still_alive = false
-                       return true
+                       end_reached = true
                end
-               return false
        end
 
        # Associates the socket to a local address and port
        #
        # Returns : `true` if the socket could be bound, `false` otherwise
-       fun bind: Bool do
-               if not still_alive then return false
+       private fun bind: Bool do
+               if end_reached then return false
                return socket.bind(addrin) >= 0
        end
 
        # Sets the socket as ready to accept incoming connections, `size` is the maximum number of queued clients
        #
        # Returns : `true` if the socket could be set, `false` otherwise
-       fun listen(size: Int): Bool do
-               if not still_alive then return false
+       private fun listen(size: Int): Bool do
+               if end_reached then return false
                return socket.listen(size) >= 0
        end
 
@@ -181,9 +202,9 @@ class Socket
        #
        # Returns : the socket for communication with the client
        #
-       # REQUIRES : self.still_alive
+       # REQUIRES : not self.end_reached
        fun accept: Socket do
-               assert still_alive
+               assert not end_reached
                return new Socket.primitive_init(socket.accept)
        end
 
diff --git a/lib/standard/bitset.nit b/lib/standard/bitset.nit
new file mode 100644 (file)
index 0000000..6794dcb
--- /dev/null
@@ -0,0 +1,119 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Julien Pagès <julien.pages@lirmm.fr>
+#
+# 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.
+
+# Services to handle BitSet
+module bitset
+
+import collection
+import math
+import file
+
+in "C header" `{
+       #include <assert.h>
+`}
+
+# Add support of binary operations related 
+# to binary level of Integer
+# For compatibility reasons, xor, and, or methods 
+# are still in the math.nit module
+redef class Int
+
+       # Sets the i-bit of self to the given value
+       #     assert 11.setbit(0, 0) == 10
+       #     assert 10.setbit(0, 1) == 11 
+       fun setbit(index: Int, value: Int): Int `{
+               assert(index >= 0 && index < 32);
+
+               if(value == 1)
+                       return recv | (1 << index);
+               else
+                       return recv & ~(1 << index);
+       `}
+
+       # Returns the i-bit value of self Integer
+       #     assert 10.getbit(0) == 0
+       #     assert 10.getbit(3) == 1
+       fun getbit(index: Int): Int `{
+               assert(index >= 0 && index < 32);
+
+               int op = 1 << index;
+               
+               if((recv & op) == 0)
+                       return 0;
+               else
+                       return 1;
+       `}
+
+       # Give a binary representation of self Integer
+       fun bits : Array[Int]
+       do
+               var bits = new Array[Int].with_capacity(32) 
+               
+               for i in [0..32[
+               do
+                       bits[i] = getbit(i)
+               end
+
+               return bits
+       end
+
+       # Returns the number of bits of specified value (0 or 1)
+       # in self 
+       #     assert 10.number_bits(1) == 2
+       #     assert 10.number_bits(0) == 30
+       fun number_bits(value: Int): Int `{
+               assert(value == 0 || value == 1);
+
+               long int bound = 1L << 31;
+               int count = 0;
+               long int i;
+
+               if(value == 1)
+               {
+                       for(i=bound; i>0; i/=2)
+                       {
+                               if(recv & i)
+                                       count++;
+                       }
+               }
+               else
+               {
+                       for(i=bound; i>0; i/=2)
+                       {
+                               if(!(recv & i))
+                                       count++;
+                       }
+               }
+               return count;
+       `}
+
+       # Returns the position of the highest bit
+       # set to 1 in self (the rightest bit is at position 0)
+       #     assert 10.highest_bit == 3
+       #     assert 1.highest_bit == 0
+       fun highest_bit: Int `{ 
+               long int msb = 1L << 31;
+               int pos = 31;
+               
+               while(msb > 0 && !(recv & msb))
+               {
+                       msb /= 2;
+                       pos--;
+               }
+               
+               return pos;
+       `}
+end
index a08f7d4..d67d80e 100644 (file)
@@ -624,7 +624,7 @@ interface SequenceRead[E]
                var p = 0
                var i = iterator
                while i.is_ok do
-                       if p>pos and i.item == item then return i.index
+                       if p>=pos and i.item == item then return i.index
                        i.next
                        p += 1
                end
index beca2ca..b6319e1 100644 (file)
@@ -4,7 +4,7 @@
 #
 # This file is free software, which comes along with NIT.  This software is
 # distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-# without  even  the implied warranty of  MERCHANTABILITY or  FITNESS FOR A 
+# without  even  the implied warranty of  MERCHANTABILITY or  FITNESS FOR A
 # PARTICULAR PURPOSE.  You can modify it is you want,  provided this header
 # is kept unaltered, and a notification of the changes is added.
 # You  are  allowed  to  redistribute it and sell it, alone or is a part of
 # a custom `Comparator::compare` function.
 module sorter
 
+import range
 import array
 
 # This abstract class generalizes ways to sort an array
 interface Comparator[E]
        # Compare `a` and `b`.
        # Returns:
-       #       -1 if a < b
+       #       -1 if a < b
        #       0  if a = b
        #       1  if a > b
        fun compare(a: E, b: E): Int is abstract
 
        # Sort `array` using the `compare` function.
+       #
+       #     var s = new DefaultComparator[Int]
+       #     var a = [5, 2, 3, 1, 4]
+       #     s.sort(a)
+       #     assert a == [1, 2, 3, 4, 5]
        fun sort(array: Array[E]) do sub_sort(array, 0, array.length-1)
 
        # Sort `array` between `from` and `to` indices
@@ -42,8 +48,13 @@ interface Comparator[E]
        end
 
        # Quick-sort `array` between `from` and `to` indices
-       private fun quick_sort(array: Array[E], from: Int, to: Int)
-       do
+       # Worst case: O(n^2), Average case: O(n lg n)
+       #
+       #     var s = new DefaultComparator[Int]
+       #     var a = [5, 2, 3, 1, 4]
+       #     s.quick_sort(a, 0, a.length - 1)
+       #     assert a == [1, 2, 3, 4, 5]
+       fun quick_sort(array: Array[E], from: Int, to: Int) do
                var pivot = array[from]
                var i = from
                var j = to
@@ -61,9 +72,15 @@ interface Comparator[E]
                sub_sort(array, from, i-2)
                sub_sort(array, i, to)
        end
-       
+
        # Bubble-sort `array` between `from` and `to` indices
-       private fun bubble_sort(array: Array[E], from: Int, to: Int)
+       # Worst case: O(n^2), average case: O(n^2)
+       #
+       #     var s = new DefaultComparator[Int]
+       #     var a = [5, 2, 3, 1, 4]
+       #     s.bubble_sort(a, 0, a.length - 1)
+       #     assert a == [1, 2, 3, 4, 5]
+       fun bubble_sort(array: Array[E], from: Int, to: Int)
        do
                var i = from
                while i < to do
@@ -84,6 +101,108 @@ interface Comparator[E]
                        i += 1
                end
        end
+
+       # Insertion-sort `array` between `from` and `to` indices
+       # Worst case: O(n^2), average case: O(n^2)
+       #
+       #     var s = new DefaultComparator[Int]
+       #     var a = [5, 2, 3, 1, 4]
+       #     s.insertion_sort(a, 0, a.length - 1)
+       #     assert a == [1, 2, 3, 4, 5]
+       fun insertion_sort(array: Array[E], from: Int, to: Int) do
+               var last = array.length
+               for i in [from..to] do
+                       var j = i
+                       while j > 0 and compare(array[j], array[j - 1]) < 0 do
+                               array.swap_at(j, j - 1)
+                               j -= 1
+                       end
+               end
+       end
+
+       # Merge-sort `array` between `from` and `to` indices
+       # Worst case: O(n lg n), average: O(n lg n)
+       #
+       #     var s = new DefaultComparator[Int]
+       #     var a = [5, 2, 3, 1, 4]
+       #     s.merge_sort(a, 0, a.length - 1)
+       #     assert a == [1, 2, 3, 4, 5]
+       fun merge_sort(array: Array[E], from, to: Int) do
+               if from >= to then return
+               var mid = (to + from) / 2
+               merge_sort(array, from, mid)
+               merge_sort(array, mid + 1, to)
+               merge(array, from, mid, to)
+       end
+
+       private fun merge(array: Array[E], from, mid, to: Int) do
+               var l = new Array[E]
+               for i in [from..mid] do l.add array[i]
+               var r = new Array[E]
+               for i in [mid + 1..to] do r.add array[i]
+               var i = 0
+               var j = 0
+               for k in [from..to] do
+                       if i >= l.length then
+                               array[k] = r[j]
+                               j += 1
+                       else if j >= r.length then
+                               array[k] = l[i]
+                               i += 1
+                       else if compare(l[i], r[j]) <= 0 then
+                               array[k] = l[i]
+                               i += 1
+                       else
+                               array[k] = r[j]
+                               j += 1
+                       end
+               end
+       end
+
+       # Heap-sort `array` between `from` and `to` indices
+       # Worst case: O(n lg n), average: O(n lg n)
+       #
+       #     var s = new DefaultComparator[Int]
+       #     var a = [5, 2, 3, 1, 4]
+       #     s.heap_sort(a, 0, a.length - 1)
+       #     assert a == [1, 2, 3, 4, 5]
+       fun heap_sort(array: Array[E], from, to: Int) do
+               var size = build_heap(array)
+               for j in [from..to[ do
+                       array.swap_at(0, size)
+                       size -= 1
+                       heapify(array, 0, size)
+               end
+       end
+
+       private fun build_heap(array: Array[E]): Int do
+               var size = array.length - 1
+               var i = size / 2
+               while i >= 0 do
+                       heapify(array, i, size)
+                       i -= 1
+               end
+               return size
+       end
+
+       private fun heapify(array: Array[E], from, to: Int) do
+               var l = from * 2
+               var r = l + 1
+               var largest: Int
+               if l < to and compare(array[l], array[from]) > 0 then
+                       largest = l
+               else
+                       largest = from
+               end
+               if r < to and compare(array[r], array[largest]) > 0 then
+                       largest = r
+               end
+               if largest != from then
+                       array.swap_at(from, largest)
+                       heapify(array, largest, to)
+               end
+       end
+
 end
 
 # Deprecated class, use `Comparator` instead
index 5ff333c..27b2626 100644 (file)
@@ -34,26 +34,26 @@ redef class Object
        # Print `objects` on the standard output (`stdout`).
        protected fun printn(objects: Object...)
        do
-               stdout.write(objects.to_s)
+               sys.stdout.write(objects.to_s)
        end
 
        # Print an `object` on the standard output (`stdout`) and add a newline.
        protected fun print(object: Object)
        do
-               stdout.write(object.to_s)
-               stdout.write("\n")
+               sys.stdout.write(object.to_s)
+               sys.stdout.write("\n")
        end
 
        # Read a character from the standard input (`stdin`).
        protected fun getc: Char
        do
-               return stdin.read_char.ascii
+               return sys.stdin.read_char.ascii
        end
 
        # Read a line from the standard input (`stdin`).
        protected fun gets: String
        do
-               return stdin.read_line
+               return sys.stdin.read_line
        end
 
        # Return the working (current) directory
@@ -178,15 +178,15 @@ end
 
 class Stdin
        super IFStream
+       super PollableIStream
+
        private init do
                _file = new NativeFile.native_stdin
                path = "/dev/stdin"
                prepare_buffer(1)
        end
 
-       # Is these something to read? (non blocking)
-       # FIXME: should be generalized
-       fun poll_in: Bool is extern "file_stdin_poll_in"
+       redef fun poll_in: Bool is extern "file_stdin_poll_in"
 end
 
 class Stdout
@@ -524,11 +524,15 @@ private extern class NativeFile `{ FILE* `}
        new native_stderr is extern "file_NativeFileCapable_NativeFileCapable_native_stderr_0"
 end
 
-# Standard input.
-fun stdin: Stdin do return once new Stdin
+redef class Sys
+
+       # Standard input
+       var stdin: PollableIStream protected writable = new Stdin
 
-# Standard output.
-fun stdout: OFStream do return once new Stdout
+       # Standard output
+       var stdout: OStream protected writable = new Stdout
 
-# Standard output for error.
-fun stderr: OFStream do return once new Stderr
+       # Standard output for errors
+       var stderr: OStream protected writable = new Stderr
+
+end
index 30e8449..e62cbea 100644 (file)
@@ -602,7 +602,7 @@ end
 # Pointer classes are used to manipulate extern C structures.
 extern class Pointer
        # Is the address behind this Object at NULL?
-       fun address_is_null: Bool `{ return recv == NULL; `}
+       fun address_is_null: Bool is extern "address_is_null"
 
        # Free the memory pointed by this pointer
        fun free `{ free(recv); `}
diff --git a/lib/standard/kernel_nit.h b/lib/standard/kernel_nit.h
new file mode 100644 (file)
index 0000000..3a09c9c
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef __KERNEL_NIT_H
+#define __KERNEL_NIT_H
+/* This file is part of NIT ( http://www.nitlanguage.org ).
+ *
+ * This file is free software, which comes along with NIT.  This software is
+ * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without  even  the implied warranty of  MERCHANTABILITY or  FITNESS FOR A 
+ * PARTICULAR PURPOSE.  You can modify it is you want,  provided this header
+ * is kept unaltered, and a notification of the changes is added.
+ * You  are  allowed  to  redistribute it and sell it, alone or is a part of
+ * another product.
+ */
+
+#include <stdlib.h>
+
+#define address_is_null(x) ((x)==NULL)
+
+#endif
index 8c31cc5..f017649 100644 (file)
@@ -27,19 +27,32 @@ import string
 `}
 
 redef class Sys
+       # Set the real current user id of this process
        fun uid=(uid: Int): Bool `{ return setuid(uid); `}
+
+       # Current real user id of this process
        fun uid: Int `{ return getuid(); `}
 
+       # Set the current real group id of this process
        fun gid=(gid: Int): Bool `{ return setgid(gid); `}
+
+       # Current real group id of this process
        fun gid: Int `{ return getgid(); `}
 
+       # Set the effective user id of this process
        fun euid=(uid: Int): Bool `{ return seteuid(uid); `}
+
+       # The effective user id of this process
        fun euid: Int `{ return geteuid(); `}
 
+       # Set the effective group id of this process
        fun egid=(gid: Int): Bool `{ return setegid(gid); `}
+
+       # The effective group id of this process
        fun egid: Int `{ return getegid(); `}
 end
 
+# Information on a user account
 extern class Passwd `{struct passwd*`}
        # Get the `Passwd` of the user with the `uid`
        new from_uid(uid: Int) `{ return getpwuid(uid); `}
@@ -66,13 +79,24 @@ extern class Passwd `{struct passwd*`}
        fun shell: String import NativeString.to_s `{ return NativeString_to_s(recv->pw_shell); `}
 end
 
+# Information on a user group
 extern class Group `{struct group*`}
+       # Get a group from its id
        new from_gid(gid: Int) `{ return getgrgid(gid); `}
+
+       # Get a group from its name
        new from_name(name: String) import String.to_cstring `{ return getgrnam( String_to_cstring(name) ); `}
 
+       # Name of this ground
        fun name: String import NativeString.to_s `{ return NativeString_to_s(recv->gr_name); `}
+
+       # Encrypted password of this group
        fun passwd: String import NativeString.to_s `{ return NativeString_to_s(recv->gr_passwd); `}
+
+       # Id of this group
        fun gid: Int `{ return recv->gr_gid; `}
+
+       # List of the members of the group
        fun mem: Array[String] import Array[String], Array[String].add, NativeString.to_s `{
                char **mem;
                int m;
index ad093ae..8d507a1 100644 (file)
@@ -967,8 +967,8 @@ end
 private class ConcatNode
        super RopeNode
 
-       private var _left_child: nullable RopeNode
-       private var _right_child: nullable RopeNode
+       private var _left_child: nullable RopeNode = null
+       private var _right_child: nullable RopeNode = null
 
        private fun left_child: nullable RopeNode
        do
index d11fa21..6297038 100644 (file)
@@ -27,3 +27,4 @@ import collection
 import math
 import kernel
 import gc
+import bitset
index 932919b..507ba8d 100644 (file)
@@ -88,6 +88,15 @@ interface IStream
        fun eof: Bool is abstract
 end
 
+# IStream capable of declaring if readable without blocking
+interface PollableIStream
+       super IStream
+
+       # Is there something to read? (without blocking)
+       fun poll_in: Bool is abstract
+
+end
+
 # Abstract output stream
 interface OStream
        super IOS
@@ -146,24 +155,20 @@ abstract class BufferedIStream
 
        redef fun read(i)
        do
-               var s = new FlatBuffer.with_capacity(i)
-               var j = _buffer_pos
-               var k = _buffer.length
-               while i > 0 do
-                       if j >= k then
+               if _buffer.length == _buffer_pos then
+                       if not eof then
                                fill_buffer
-                               if eof then return s.to_s
-                               j = _buffer_pos
-                               k = _buffer.length
-                       end
-                       while j < k and i > 0 do
-                               s.add(_buffer.chars[j])
-                               j +=  1
-                               i -= 1
+                               return read(i)
                        end
+                       return ""
                end
-               _buffer_pos = j
-               return s.to_s
+               if _buffer_pos + i >= _buffer.length then
+                       var from = _buffer_pos
+                       _buffer_pos = _buffer.length
+                       return _buffer.substring_from(from).to_s
+               end
+               _buffer_pos += i
+               return _buffer.substring(_buffer_pos - i, i).to_s
        end
 
        redef fun read_all
index d09aadc..8531476 100644 (file)
@@ -532,11 +532,9 @@ abstract class Text
                if hash_cache == null then
                        # djb2 hash algorithm
                        var h = 5381
-                       var i = length - 1
 
                        for char in self.chars do
-                               h = (h * 32) + h + char.ascii
-                               i -= 1
+                               h = h.lshift(5) + h + char.ascii
                        end
 
                        hash_cache = h
@@ -862,18 +860,15 @@ class FlatString
        redef fun hash
        do
                if hash_cache == null then
-                       # djb2 hash algorythm
+                       # djb2 hash algorithm
                        var h = 5381
-                       var i = length - 1
+                       var i = index_from
 
                        var myitems = items
-                       var strStart = index_from
-
-                       i += strStart
 
-                       while i >= strStart do
-                               h = (h * 32) + h + self.items[i].ascii
-                               i -= 1
+                       while i <= index_to do
+                               h = h.lshift(5) + h + myitems[i].ascii
+                               i += 1
                        end
 
                        hash_cache = h
index d254c24..f8916b3 100644 (file)
@@ -79,9 +79,7 @@ module template
 #         end
 #         # ...
 #     end
-#     var l = new LnkTmpl
-#     l.text = "hello world"
-#     l.href = "hello.png"
+#     var l = new LnkTmpl("hello world", null, "hello.png")
 #     assert l.write_to_string == """<a href="hello.png">hello world</a>"""
 #
 class Template
diff --git a/lib/trees/abstract_tree.nit b/lib/trees/abstract_tree.nit
new file mode 100644 (file)
index 0000000..63ac67a
--- /dev/null
@@ -0,0 +1,67 @@
+# 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.
+
+# Introduce tree structures abstraction
+# Trees are a widely used abstract data type (ADT) or data structure
+# implementing this ADT that simulates a hierarchical tree structure,
+# with a root value and subtrees of children, represented as a set of linked nodes.
+module abstract_tree
+
+# Abstract tree map structure
+# * `K`: tree node key
+# * `E`: tree node value
+abstract class TreeMap[K: Comparable, E]
+       super Map[K, E]
+
+       # Type of nodes used in this tree implementation
+       protected type N: TreeNode[K, E]
+
+       # The `root` node of the tree (null if tree is empty)
+       protected var root: nullable N protected writable = null
+
+       # Display the tree in a gaphical windows
+       # Graphviz with a working -Txlib is expected
+       # Used for debugging
+       fun show_dot is abstract
+end
+
+# Node used in Tree implementation
+# nodes are used to store values
+# * `E`: type of value
+class TreeNode[K: Comparable, E]
+
+       # TreeNode type
+       type SELF: TreeNode[K, E]
+
+       # `key` for this node
+       var key: K
+
+       # `value` stored in the node
+       var value: E
+
+       # Direct parent of this node (null if the node is root)
+       var parent: nullable SELF writable = null
+
+       redef fun to_s do return "\{{value}\}"
+
+       # Return dot representation of this node
+       # Used for debugging by `AbstractTree::show_dot`
+       fun to_dot: String do
+               var res = new FlatBuffer
+               res.append "\"{self}\";\n"
+               if parent != null then res.append "\"{parent.as(not null)}\" -> \"{self}\"[dir=back];\n"
+               return res.to_s
+       end
+end
+
diff --git a/lib/trees/bintree.nit b/lib/trees/bintree.nit
new file mode 100644 (file)
index 0000000..235b298
--- /dev/null
@@ -0,0 +1,364 @@
+# 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.
+
+# Binary Tree data-structure
+# A binary tree is a tree data structure in which each node has at most two children
+# (referred to as the left child and the right child).
+# In a binary tree, the degree of each node can be at most two.
+# Binary trees are used to implement binary search trees and binary heaps,
+# and are used for efficient searching and sorting.
+module bintree
+
+import abstract_tree
+
+# Binary Tree Map
+#
+# Properties:
+#  * unique root
+#  * node.left.key < node.key
+#  * node.right.key > node.key
+#  * no duplicates allowed
+#
+# Operations:
+#  * search average O(lg n) worst O(n)
+#  * insert average O(lg n) worst O(n)
+#  * delete average O(lg n) worst O(n)
+#
+# Usage:
+#     var tree = new BinTreeMap[Int, String]
+#     tree[1] = "n1"
+#     assert tree.min == "n1"
+class BinTreeMap[K: Comparable, E]
+       super TreeMap[K, E]
+
+       redef type N: BinTreeNode[K, E]
+
+       # Get the node value associated to `key`
+       # O(n) in worst case, average is O(h) with h: tree height
+       #
+       #     var tree = new BinTreeMap[Int, String]
+       #     for i in [4, 2, 1, 5, 3] do tree[i] = "n{i}"
+       #     assert tree[1] == "n1"
+       redef fun [](key: K): E do
+               assert not_empty: root != null
+               var res = search_down(root.as(not null), key)
+               assert has_key: res != null
+               return res.value
+       end
+
+       protected fun search_down(from: N, key: K): nullable N do
+               if key == from.key then return from
+               if from.left != null and key < from.key then
+                       return search_down(from.left.as(not null), key)
+               else if from.right != null then
+                       return search_down(from.right.as(not null), key)
+               end
+               return null
+       end
+
+       # Get the node with the minimum key
+       # O(n) in worst case, average is O(h) with h: tree height
+       #
+       #     var tree = new BinTreeMap[Int, String]
+       #     for i in [4, 2, 1, 5, 3] do tree[i] = "n{i}"
+       #     assert tree.min == "n1"
+       fun min: E do
+               assert not_empty: root != null
+               return min_from(root.as(not null)).value
+       end
+
+       protected fun min_from(node: N): N do
+               if node.left == null then return node
+               return min_from(node.left.as(not null))
+       end
+
+       # Get the node with the maximum key
+       # O(n) in worst case, average is O(h) with h: tree height
+       #
+       #     var tree = new BinTreeMap[Int, String]
+       #     for i in [4, 2, 1, 5, 3, 6, 7, 8] do tree[i] = "n{i}"
+       #     assert tree.max == "n8"
+       fun max: E do
+               assert not_empty: root != null
+               return max_from(root.as(not null)).value
+       end
+
+       protected fun max_from(node: N): N do
+               if node.right == null then return node
+               return max_from(node.right.as(not null))
+       end
+
+       # Insert a new node in tree using `key` and `item`
+       # O(n) in worst case, average is O(h) with h: tree height
+       #
+       #     var tree = new BinTreeMap[Int, String]
+       #     tree[1] = "n1"
+       #     assert tree.max == "n1"
+       #     tree[3] = "n3"
+       #     assert tree.max == "n3"
+       redef fun []=(key, item) do
+               insert_node(new BinTreeNode[K, E](key, item))
+       end
+
+       protected fun insert_node(node: N) do
+               if root == null then
+                       root = node
+               else
+                       shift_down(root.as(not null), node)
+               end
+       end
+
+       # Push down the `node` in tree from a specified `from` index
+       protected fun shift_down(from, node: N) do
+               if node.key < from.key then
+                       if from.left == null then
+                               from.left = node
+                               node.parent = from
+                       else
+                               shift_down(from.left.as(not null), node)
+                       end
+               else if node.key > from.key then
+                       if from.right == null then
+                               from.right = node
+                               node.parent = from
+                       else
+                               shift_down(from.right.as(not null), node)
+                       end
+               end
+       end
+
+       # Delete node at `key` (also return the deleted node value)
+       # O(n) in worst case, average is O(h) with h: tree height
+       #
+       #     var tree = new BinTreeMap[Int, String]
+       #     tree[1] = "n1"
+       #     assert tree.max == "n1"
+       #     tree[3] = "n3"
+       #     assert tree.max == "n3"
+       #     tree.delete(3)
+       #     assert tree.max == "n1"
+       fun delete(key: K): nullable E do
+               assert is_empty: root != null
+               var node = search_down(root.as(not null), key)
+               if node == null then return null
+               if node.left == null then
+                       transplant(node, node.right)
+               else if node.right == null then
+                       transplant(node, node.left)
+               else
+                       var min = min_from(node.right.as(not null))
+                       if min.parent != node then
+                               transplant(min, min.right)
+                               min.right = node.right
+                               min.right.parent = min
+                       end
+                       transplant(node, min)
+                       min.left = node.left
+                       min.left.parent = min
+               end
+               return node.value
+       end
+
+       # Swap a `node` with the `other` in this Tree
+       # note: Nodes parents are updated, children still untouched
+       protected fun transplant(node, other: nullable N) do
+               if node == null then return
+               if node.parent == null then
+                       root = other
+               else if node == node.parent.left then
+                       node.parent.left = other
+               else
+                       node.parent.right = other
+               end
+               if other != null then other.parent = node.parent
+       end
+
+       # Perform left rotation on `node`
+       #
+       #     N             Y
+       #    / \     >     / \
+       #   a   Y         N   c
+       #      / \   <   / \
+       #     b   c     a   b
+       #
+       protected fun rotate_left(node: N) do
+               var y = node.right
+               node.right = y.left
+               if y.left != null then
+                       y.left.parent = node
+               end
+               y.parent = node.parent
+               if node.parent == null then
+                       root = y
+               else if node == node.parent.left then
+                       node.parent.left = y
+               else
+                       node.parent.right = y
+               end
+               y.left = node
+               node.parent = y
+       end
+
+       # Perform right rotation on `node`
+       #
+       #     N             Y
+       #    / \     >     / \
+       #   a   Y         N   c
+       #      / \   <   / \
+       #     b   c     a   b
+       #
+       protected fun rotate_right(node: N) do
+               var y = node.left
+               node.left = y.right
+               if y.right != null then
+                       y.right.parent = node
+               end
+               y.parent = node.parent
+               if node.parent == null then
+                       root = y
+               else if node == node.parent.right then
+                       node.parent.right = y
+               else
+                       node.parent.left = y
+               end
+               y.right = node
+               node.parent = y
+       end
+
+       # Sort the tree into an array
+       # O(n)
+       #
+       #     var tree = new BinTreeMap[Int, String]
+       #     for i in [4, 2, 1, 5, 3] do tree[i] = "n{i}"
+       #     assert tree.sort == ["n1", "n2", "n3", "n4", "n5"]
+       fun sort: Array[E] do
+               var sorted = new Array[E]
+               if root == null then return sorted
+               sort_down(root.as(not null), sorted)
+               return sorted
+       end
+
+       protected fun sort_down(node: N, sorted: Array[E]) do
+               if node.left != null then sort_down(node.left.as(not null), sorted)
+               sorted.add(node.value)
+               if node.right != null then sort_down(node.right.as(not null), sorted)
+       end
+
+       redef fun to_s do
+               var root = self.root
+               if root == null then return "[]"
+               return "[{print_tree(root)}]"
+       end
+
+       protected fun print_tree(node: N): String do
+               var s = new FlatBuffer
+               s.append(node.to_s)
+               if node.left != null then s.append(print_tree(node.left.as(not null)))
+               if node.right != null then s.append(print_tree(node.right.as(not null)))
+               return s.to_s
+       end
+
+       redef fun show_dot do
+               assert not_empty: root != null
+               var f = new OProcess("dot", "-Txlib")
+               f.write "digraph \{\n"
+               dot_down(root.as(not null), f)
+               f.write "\}\n"
+               f.close
+       end
+
+       protected fun dot_down(node: N, f: OProcess) do
+               if node.left != null then dot_down(node.left.as(not null), f)
+               f.write node.to_dot
+               if node.right != null then dot_down(node.right.as(not null), f)
+       end
+end
+
+# TreeNode used by BinTree
+class BinTreeNode[K: Comparable, E]
+       super TreeNode[K, E]
+
+       redef type SELF: BinTreeNode[K, E]
+
+       init(key: K, item: E) do
+               super(key, item)
+       end
+
+       private var left_node: nullable SELF = null
+
+       # `left` tree node child (null if node has no left child)
+       fun left: nullable SELF do return left_node
+
+       # set `left` child for this node (or null if left no child)
+       # ENSURE: node.key < key (only if node != null)
+       fun left=(node: nullable SELF) do
+               assert node != null implies node.key < key
+               left_node = node
+       end
+
+       private var right_node: nullable SELF = null
+
+       # `right` tree node child (null if node has no right child)
+       fun right: nullable SELF do return right_node
+
+       # set `right` child for this node (or null if right no child)
+       # ENSURE: node.key < key (only if node != null)
+       fun right=(node: nullable SELF) do
+               if node != null then
+                       assert node.key > key
+               end
+               right_node = node
+       end
+
+       # `parent` of the `parent` of this node (null if root)
+       fun grandparent: nullable SELF do
+               if parent == null then
+                       return null
+               else
+                       return parent.parent
+               end
+       end
+
+       # Other child of the `grandparent`
+       # `left` or `right` depends on the position of the current node against its parent
+       fun uncle: nullable SELF do
+               var g = grandparent
+               if g == null then
+                       return null
+               else
+                       if parent == g.left then
+                               return g.right
+                       else
+                               return g.left
+                       end
+               end
+       end
+
+       # Other child of the parent
+       # `left` or `right` depends on the position of the current node against its parent
+       fun sibling: nullable SELF do
+               if parent == null then
+                       return null
+               else if self == parent.left then
+                       return parent.right
+               else if self == parent.right then
+                       return parent.left
+               else
+                       return null
+               end
+       end
+
+       redef fun to_s do return "\{{key}: {value}\}"
+end
+
diff --git a/lib/trees/rbtree.nit b/lib/trees/rbtree.nit
new file mode 100644 (file)
index 0000000..ce17feb
--- /dev/null
@@ -0,0 +1,147 @@
+# 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.
+
+# A red–black tree is a data structure which is a type of self-balancing binary search tree.
+#
+# Balance is preserved by painting each node of the tree with one of two colors
+# (typically called 'red' and 'black') in a way that satisfies certain properties,
+# which collectively constrain how unbalanced the tree can become in the worst case.
+# When the tree is modified, the new tree is subsequently rearranged and repainted
+# to restore the coloring properties.
+# The properties are designed in such a way that this rearranging and recoloring
+# can be performed efficiently.
+#
+# The balancing of the tree is not perfect but it is good enough to allow it
+# to guarantee searching in O(log n) time, where n is the total number of elements in the tree.
+# The insertion and deletion operations, along with the tree rearrangement and recoloring,
+# are also performed in O(log n) time.
+module rbtree
+
+import bintree
+
+# Red-Black Tree Map
+# Properties of a Red-Black tree map:
+#  * every node is either red or black
+#  * root is black
+#  * every leaf (null) is black
+#  * if a node is red, then both its children are black
+#  * for each node, all simple path from the node to descendant
+#    leaves contain the same number of black nodes
+#
+# Operations:
+#  * search average O(lg n) worst O(lg n)
+#  * insert average O(lg n) worst O(lg n)
+#  * delete average O(lg n) worst O(lg n)
+class RBTreeMap[K: Comparable, E]
+       super BinTreeMap[K, E]
+
+       redef type N: RBTreeNode[K, E]
+
+       redef fun []=(key, item) do
+               insert_node(new RBTreeNode[K, E](key, item))
+       end
+
+       redef fun insert_node(node) do
+               super
+               insert_fixup_case1(node)
+       end
+
+       # Case 1: node is root
+       # color node as black
+       # it adds a black node on every path so we do nothing else
+       private fun insert_fixup_case1(node: N) do
+               if node.parent == null then
+                       node.is_red = false
+               else
+                       insert_fixup_case2(node)
+               end
+       end
+
+       # Case 2: parent is black
+       # it do not add black node so we do nothing else
+       private fun insert_fixup_case2(node: N) do
+               if node.parent.is_red then insert_fixup_case3(node)
+       end
+
+       # Case 3: node, parent and uncle are red
+       # this is a LLr or RRr conflict
+       # we recolor recursively the tree to the root
+       private fun insert_fixup_case3(node: N) do
+               if node.uncle != null and node.uncle.is_red then
+                       node.parent.is_red = false
+                       node.uncle.is_red = false
+                       node.grandparent.is_red = true
+                       insert_fixup_case1(node.grandparent.as(not null))
+               else
+                       insert_fixup_case4(node)
+               end
+       end
+
+       # Case 4: node and parent are red, uncle is black
+       # this is a LRb or RLb conflict
+       # we rotate the tree to balance it
+       private fun insert_fixup_case4(node: N) do
+               if node == node.parent.right and node.parent == node.grandparent.left then
+                       rotate_left(node.parent.as(not null))
+                       node = node.left.as(not null)
+               else if node == node.parent.left and node.parent == node.grandparent.right then
+                       rotate_right(node.parent.as(not null))
+                       node = node.right.as(not null)
+               end
+               insert_fixup_case5(node)
+       end
+
+       # Case 5: node and parent are red, uncle is black
+       # this is a LLb or RRb conflict
+       # we rotate the tree to balance it
+       private fun insert_fixup_case5(node: N) do
+               node.parent.is_red = false
+               node.grandparent.is_red = true
+               if node == node.parent.left then
+                       rotate_right(node.grandparent.as(not null))
+               else
+                       rotate_left(node.grandparent.as(not null))
+               end
+       end
+
+       # TODO implement RBTree::delete
+       redef fun delete(key) is abstract
+
+       redef fun dot_down(node, f) do
+               if node.left != null then dot_down(node.left.as(not null), f)
+               f.write node.to_dot
+               if node.parent != null then f.write "\"{node.parent.as(not null)}\" -> \"{node}\"[dir=back];\n"
+               if node.right != null then dot_down(node.right.as(not null), f)
+       end
+end
+
+# RedBlackTree node (can be red or black)
+class RBTreeNode[K: Comparable, E]
+       super BinTreeNode[K, E]
+
+       redef type SELF: RBTreeNode[K, E]
+
+       # Is the node red?
+       private var is_red = true
+
+       redef fun to_dot do
+               if is_red then
+                       return "\"{self}\"[style=filled,fillcolor=red,fontcolor=white];\n"
+               else
+                       return "\"{self}\"[style=filled,fillcolor=black,fontcolor=white];\n"
+               end
+
+       end
+end
+
diff --git a/lib/trees/trees.nit b/lib/trees/trees.nit
new file mode 100644 (file)
index 0000000..93716b5
--- /dev/null
@@ -0,0 +1,20 @@
+# 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.
+
+# General module for tree data structures
+module trees
+
+import abstract_tree
+import bintree
+import rbtree
diff --git a/lib/union_find.nit b/lib/union_find.nit
new file mode 100644 (file)
index 0000000..0134eb2
--- /dev/null
@@ -0,0 +1,193 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT.  This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without  even  the implied warranty of  MERCHANTABILITY or  FITNESS FOR A 
+# PARTICULAR PURPOSE.  You can modify it is you want,  provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You  are  allowed  to  redistribute it and sell it, alone or is a part of
+# another product.
+
+# union–find algorithm using an efficient disjoint-set data structure
+module union_find
+
+# Data structure to keeps track of elements partitioned into disjoint subsets
+#     var s = new DisjointSet[Int]
+#     s.add(1)
+#     s.add(2)
+#     assert not s.in_same_subset(1,2)
+#     s.union(1,2)
+#     assert s.in_same_subset(1,2)
+#
+# `in_same_subset` is transitive, reflexive and symetric
+#
+#     s.add(3)
+#     assert not s.in_same_subset(1,3)
+#     s.union(3,2)
+#     assert s.in_same_subset(1,3)
+#
+# Unkike theorical Disjoint-set data structures, the underling implementation is opaque
+# that makes the traditionnal `find` method unavailable for clients.
+# The methods `in_same_subset`, `to_partitions`, and their variations are offered instead.
+class DisjointSet[E: Object]
+       super SimpleCollection[E]
+
+       # The node in the hiearchical structure for each element
+       private var nodes = new HashMap[E, DisjointSetNode]
+
+       # Get the root node of an element
+       # require: `has(e)`
+       private fun find(e:E): DisjointSetNode
+       do
+               assert nodes.has_key(e)
+               var ne = nodes[e]
+               if ne.parent == ne then return ne
+               var res = nfind(ne)
+               nodes[e] = res
+               return res
+       end
+
+       # Get the root node of a node
+       # Use *path compression* to flatten the structure
+       # ENSURE: `result.parent == result`
+       private fun nfind(ne: DisjointSetNode): DisjointSetNode
+       do
+               var nf = ne.parent
+               if nf == ne then return ne
+               var ng = nfind(nf)
+               ne.parent = ng
+               return ng
+       end
+
+       # Is the element in the structure
+       #
+       #     var s = new DisjointSet[Int]
+       #     assert not s.has(1)
+       #     s.add(1)
+       #     assert s.has(1)
+       #     assert not s.has(2)
+       redef fun has(e: E): Bool
+       do
+               return nodes.has_key(e)
+       end
+
+       redef fun iterator do return nodes.keys.iterator
+
+       # Add a new element in the structure.
+       # Initially it is in its own disjoint subset
+       #
+       # ENSURE: `has(e)`
+       redef fun add(e:E)
+       do
+               if nodes.has_key(e) then return
+               var ne = new DisjointSetNode
+               nodes[e] = ne
+       end
+
+       # Are two elements in the same subset?
+       fun in_same_subset(e,f:E): Bool
+       do
+               return e == f or find(e) == find(f)
+       end
+
+       # Are all elements of `es` in the same subset?
+       #     var s = new DisjointSet[Int]
+       #     s.add_all([1,2,3,4,5,6])
+       #     s.union_all([1,2,3])
+       #     assert not s.all_in_same_subset([2,3,4])
+       #     s.union_all([1,4,5])
+       #     assert s.all_in_same_subset([2,3,4])
+       fun all_in_same_subset(es: Collection[E]): Bool
+       do
+               if es.is_empty then return true
+               var nf = find(es.first)
+               for e in es do
+                       var ne = find(e)
+                       if ne != nf then return false
+               end
+               return true
+       end
+
+       # Construct the current partitionning
+       #
+       #     var s = new DisjointSet[Int]
+       #     s.add_all([1,2,3,4,5,6])
+       #     s.union(1,2)
+       #     s.union(1,3)
+       #     s.union(4,5)
+       #     var p = s.to_partitions
+       #     assert p.length == 3
+       fun to_partitions: Collection[Set[E]]
+       do
+               return to_subpartition(self)
+       end
+
+       # Construct a partitionning on `es`, a subset of elements
+       #
+       #     var s = new DisjointSet[Int]
+       #     s.add_all([1,2,3,4,5,6])
+       #     s.union(1,2)
+       #     s.union(1,3)
+       #     s.union(4,5)
+       #     var p = s.to_subpartition([1,2,4])
+       #     assert p.length == 2
+       fun to_subpartition(es: Collection[E]): Collection[Set[E]]
+       do
+               var map = new HashMap[DisjointSetNode, Set[E]]
+               for e in es do
+                       var ne = find(e)
+                       var set = map.get_or_null(ne)
+                       if set == null then
+                               set = new HashSet[E]
+                               map[ne] = set
+                       end
+                       set.add(e)
+               end
+               return map.values
+       end
+
+       # Combine the subsets of `e` and `f`
+       # ENSURE: `in_same_subset(e,f)`
+       fun union(e,f:E)
+       do
+               var ne = find(e)
+               var nf = find(f)
+               if ne == nf then return
+
+               # merge them using *union by rank*
+               # attach the smaller tree to the root of the deeper tree
+               var er = ne.rank
+               var fr = nf.rank
+               if er < fr then
+                       ne.parent = nf
+                       nodes[e] = nf
+               else
+                       nf.parent = ne
+                       nodes[f] = ne
+                       if er == fr then
+                               # The only case where the deep is increased is when both are equals
+                               ne.rank = er+1
+                       end
+               end
+       end
+
+       # Combine the subsets of all elements of `es`
+       # ENSURE: `all_in_same_subset(cs)`
+       fun union_all(es:Collection[E])
+       do
+               if es.is_empty then return
+               var f = es.first
+               for e in es do union(e,f)
+       end
+end
+
+# A node in the hierarchical representation of subsets
+private class DisjointSetNode
+       # If parent == self then the node is a root
+       var parent: DisjointSetNode = self
+
+       # The rank to no desequilibrate the structure.
+       # The term rank is used instead of depth since
+       # path compression is used, see `DisjointSet::nfind`
+       var rank = 0
+end
index 5730c9d..3179014 100644 (file)
@@ -24,6 +24,9 @@ import base64
 
 # Websocket compatible server, works as an extra layer to the original Sockets
 class WebSocket
+       super BufferedIStream
+       super OStream
+       super PollableIStream
 
        # Client connection to the server
        var client: Socket
@@ -34,21 +37,15 @@ class WebSocket
        # Creates a new Websocket server listening on given port with `max_clients` slots available
        init(port: Int, max_clients: Int)
        do
-               listener = new Socket.stream_with_port(port)
-
-               if not listener.bind then
-                       return
-               end
-
-               if not listener.listen(1) then
-                       return
-               end
+               _buffer = new FlatBuffer
+               _buffer_pos = 0
+               listener = new Socket.server(port, max_clients)
        end
 
        # Accept an incoming connection and initializes the handshake
        fun accept
        do
-               assert listener.still_alive
+               assert not listener.eof
 
                client = listener.accept
 
@@ -66,7 +63,7 @@ class WebSocket
 
        # Disconnects the client if one is connected
        # And stops the server
-       fun stop_server
+       redef fun close
        do
                client.close
                listener.close
@@ -76,7 +73,7 @@ class WebSocket
        # See RFC 6455 for information
        private fun parse_handshake: Map[String,String]
        do
-               var recved = client.read
+               var recved = read_http_frame(new FlatBuffer)
                var headers = recved.split("\r\n")
                var headmap = new HashMap[String,String]
                for i in headers do
@@ -127,14 +124,21 @@ class WebSocket
                return ans_buffer.to_s
        end
 
+       # Reads an HTTP frame
+       protected fun read_http_frame(buf: Buffer): String
+       do
+               client.append_line_to(buf)
+               buf.chars.add('\n')
+               if buf.has_substring("\r\n\r\n", buf.length - 4) then return buf.to_s
+               return read_http_frame(buf)
+       end
+
        # Gets the message from the client, unpads it and reconstitutes the message
-       private fun unpad_message: String do
+       private fun unpad_message do
                var fin = false
-               var ret_buffer = new FlatBuffer
                while not fin do
-                       var msg = client.read
-                       if msg.length == 0 then return ""
-                       var iter = msg.chars.iterator
+                       var fst_char = client.read_char
+                       var snd_char = client.read_char
                        # First byte in msg is formatted this way :
                        # |(fin - 1bit)|(RSV1 - 1bit)|(RSV2 - 1bit)|(RSV3 - 1bit)|(opcode - 4bits)
                        # fin = Flag indicating if current frame is the last one
@@ -148,60 +152,54 @@ class WebSocket
                        #       %x9 denotes a ping
                        #       %xA denotes a pong
                        #       %xB-F are reserved for further control frames
-                       var fin_flag = iter.item.ascii.bin_and(128)
+                       var fin_flag = fst_char.bin_and(128)
                        if fin_flag != 0 then fin = true
-                       var opcode = iter.item.ascii.bin_and(15)
+                       var opcode = fst_char.bin_and(15)
                        if opcode == 9 then
-                               ret_buffer.add(138.ascii)
-                               ret_buffer.add(0.ascii)
-                               client.write(ret_buffer.to_s)
-                               return ""
+                               _buffer.add(138.ascii)
+                               _buffer.add('\0')
+                               client.write(_buffer.to_s)
+                               _buffer_pos += 2
+                               return
                        end
                        if opcode == 8 then
                                self.client.close
-                               return ""
+                               return
                        end
-                       iter.next
                        # Second byte is formatted this way :
                        # |(mask - 1bit)|(payload length - 7 bits)
                        # As specified, if the payload length is 126 or 127
                        # The next 16 or 64 bits contain an extended payload length
-                       var mask_flag = iter.item.ascii.bin_and(128)
-                       var mask: String
-                       var len = iter.item.ascii.bin_and(127)
+                       var mask_flag = snd_char.bin_and(128)
+                       var len = snd_char.bin_and(127)
                        var payload_ext_len = 0
                        if len == 126 then
-                               iter.next
-                               payload_ext_len = iter.item.ascii.lshift(8)
-                               iter.next
-                               payload_ext_len += iter.item.ascii
+                               payload_ext_len = client.read_char.lshift(8)
+                               payload_ext_len += client.read_char
                        else if len == 127 then
                                # 64 bits for length are not supported,
                                # only the last 32 will be interpreted as a Nit Integer
-                               for i in [0..4[ do iter.next
-                               payload_ext_len = iter.item.ascii.lshift(24)
-                               iter.next
-                               payload_ext_len += iter.item.ascii.lshift(16)
-                               iter.next
-                               payload_ext_len += iter.item.ascii.lshift(8)
-                               iter.next
-                               payload_ext_len += iter.item.ascii
+                               for i in [0..4[ do client.read_char
+                               payload_ext_len = client.read_char.lshift(24)
+                               payload_ext_len += client.read_char.lshift(16)
+                               payload_ext_len += client.read_char.lshift(8)
+                               payload_ext_len += client.read_char
                        end
                        if mask_flag != 0 then
-                               iter.next
-                               var startindex = iter.index
-                               mask = msg.substring(startindex,4)
                                if payload_ext_len != 0 then
-                                       ret_buffer.append(unmask_message(mask, msg.substring(startindex+4, payload_ext_len)))
+                                       var msg = client.read(payload_ext_len+4)
+                                       var mask = msg.substring(0,4)
+                                       _buffer.append(unmask_message(mask, msg.substring(4, payload_ext_len)))
                                else
                                        if len == 0 then
-                                               return ret_buffer.to_s
+                                               return
                                        end
-                                       ret_buffer.append(unmask_message(mask, msg.substring(startindex+4, len)))
+                                       var msg = client.read(len+4)
+                                       var mask = msg.substring(0,4)
+                                       _buffer.append(unmask_message(mask, msg.substring(4, len)))
                                end
                        end
                end
-               return ret_buffer.to_s
        end
 
        # Unmasks a message sent by a client
@@ -221,20 +219,26 @@ class WebSocket
        # Checks if a connection to a client is available
        fun connected: Bool do return client.connected
 
-       # Writes a text message to a client
-       fun write(msg: String)
+       redef fun write(msg: Text)
        do
-               client.write(frame_message(msg))
+               client.write(frame_message(msg.to_s))
        end
 
-       # Reads data from a Websocket client
-       fun read: String
+       redef fun is_writable do return client.connected
+
+       redef fun fill_buffer
        do
-               return unpad_message
+               _buffer.clear
+               _buffer_pos = 0
+               unpad_message
        end
 
+       redef fun end_reached do return _buffer_pos >= _buffer.length and client.eof
+
        # Is there some data available to be read ?
-       fun can_read(timeout: Int): Bool do return client.connected and client.ready_to_read(timeout)
+       fun can_read(timeout: Int): Bool do return client.ready_to_read(timeout)
+
+       redef fun poll_in do return client.poll_in
 
 end
 
index afaa93a..10c4a2e 100644 (file)
@@ -31,7 +31,6 @@ setlocal nocindent
 setlocal autoindent
 setlocal comments=:#
 setlocal indentkeys+==end,=else,=do,=var,0!,=then,=loop,=special,=class,=interface,=universal
-setlocal sw=8
 
 " Only define the function once.
 if exists("*GetNITIndent")
@@ -45,7 +44,7 @@ let s:outdent = '^\s*\(else\|then\|end\)\>'
 " At 0
 let s:no_indent = '^\s*\(class\|import\|special\)\>'
 
-let s:syng_strcom = '\<nit\%(String\|StringDelimiter\|Escape\|Comment\|Documentation\)\>'
+let s:syng_strcom = '\<NIT\(String\|StringDelimiter\|Escape\|Comment\|Documentation\)\>'
 
 " Check if the character at lnum:col is inside a string, comment, or is ascii.
 function s:IsInStringOrComment(lnum, col)
index 76db35d..8b68b53 100644 (file)
@@ -56,23 +56,25 @@ syn match NITClosure "!\h\w*"
 
 " Fallback highlight keywords
 syn match NITNull "\<\(null\)\>"
-syn match NITControl "\<\(init\|end\|not null\|not\|var\|do\|then\|else\|loop\)\>"
+syn match NITControl "\<\(init\|end\|not null\|not\|var\|do\|then\|else\|loop\|is\)\>"
 syn match NITKeyword "\<\(super\)\>"
 " Unmatchning error
 syn match Error "\<end\>"
 
 " Declarations, definitions and blocks
 syn region NITModuleDecl matchgroup=NITDefine start="\<\(import\|module\|package\)\>\s*" matchgroup=NONE end="\ze\(\s\|:\|(\|$\)"  oneline
-syn region NITClassBlock matchgroup=NITDefine start="\<\(class\|enum\|universal\|interface\|extern\)\>" matchgroup=NITDefine end="\<end\>" contains=ALL fold
+syn region NITClassBlock matchgroup=NITDefine start="\<\(class\|enum\|universal\|interface\|extern\)\>" matchgroup=NITDefine end="\<end\>" contains=ALLBUT,NITAnnotLine fold
 syn region NITFunctionDecl matchgroup=NITDefine start="\<fun\>\s*" matchgroup=NONE end="\ze\(\<do\>\|\s\|:\|(\|$\)"  oneline
 syn region NITTypeDecl matchgroup=NITDefine start="\<type\>\s*" matchgroup=NONE end="\ze\(\<do\>\|\s\|:\|(\|$\)"  oneline contained containedin=NITClassBlock
-syn region NITAttrDecl matchgroup=NITDefine start="\<var\>\s*\ze_" matchgroup=NONE end="\ze\(\<do\>\|\s\|:\|(\|$\)"  oneline contained containedin=NITClassBlock
+syn region NITAttrDecl matchgroup=NITDefine start="\<var\>\s*" matchgroup=NONE end="\ze\(\<do\>\|\s\|:\|(\|$\)"  oneline contained containedin=NITClassBlock
 syn region NITInitDecl matchgroup=NITDefine start="\<init\>\s*" matchgroup=NONE end="\ze\(\<do\>\|\s\|:\|(\|$\)"  oneline contained containedin=NITClassBlock
 syn match NITDefine "\<\(super\)\ze\s\+[A-Z]" contained containedin=NITClassBlock
 
-syn region NITStmtBlock matchgroup=NITControl start="\<\(do\|then\|else\|loop\)\>\ze\s*\(#\|$\)" matchgroup=NITControl end="^\s*\<\(end\|\zeelse\|\ze!\)\>" contains=ALLBUT,NITTypeDecl,NITAttrDecl,NITInitDecl
-syn region NITStmtBlock matchgroup=NITControl start="\<\(do\|then\|else\|loop\)\>" matchgroup=NITControl end="\<end\>" oneline
+syn region NITAnnotBlock matchgroup=NITControl start="\<is\>\ze\s*\(#\|$\)" matchgroup=NITControl end="\(\ze\<do\>\|\<end\>\)" transparent contains=ALL
+syn match NITAnnotLine "^\s*\zs\w\+" contained containedin=NITAnnotBlock
 
+syn region NITStmtBlock matchgroup=NITControl start="\<\(do\|then\|else\|loop\)\>\ze\s*\(#\|$\)" matchgroup=NITControl end="^\s*\<\(end\|\zeelse\|\ze!\)\>" contains=ALLBUT,NITTypeDecl,NITAttrDecl,NITInitDecl,NITAnnotLine
+syn region NITStmtBlock matchgroup=NITControl start="\<\(do\|then\|else\|loop\)\>" matchgroup=NITControl end="\<end\>" oneline
 if !exists("NIT_minlines")
        let NIT_minlines = 50
 endif
@@ -83,7 +85,7 @@ syn match  NITSharpBang       "\%^#!.*"
 syn match  NITComment  "#.*" contains=NITTodo
 
 " Keywords
-syn keyword NITKeyword  is abstract intern new
+syn keyword NITKeyword  abstract intern new
 syn keyword NITDefine   private public protected intrude readable writable redef
 syn keyword NITControl   if while for assert and or in as isa once break continue return abort
 syn keyword NITClass     nullable
@@ -100,6 +102,7 @@ hi def link NITTypeDecl                     Function
 hi def link NITAttrDecl                        Function
 hi def link NITInitDecl                        Function
 hi def link NITControl                 Statement
+hi def link NITAnnotLine               Statement
 hi def link NITLabel                   PreProc
 hi def link NITInclude                 Include
 hi def link NITNumber                  Number
index 1d9ddcf..4659036 100644 (file)
@@ -374,14 +374,14 @@ article .info .code {
 }\r
 \r
 .content section.concerns li {\r
-    margin-top: 20px;\r
+    margin-top: 10px;\r
 }\r
 \r
 .content section.concerns ul ul {\r
     padding-left: 20px;\r
 }\r
 \r
-.content section.concerns li li {\r
+.content section.concerns ul ul li {\r
     margin-top: 0;\r
 }\r
 \r
index 90d85c8..211287d 100644 (file)
 
 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
+nitg_0: ../c_src/nitg parser/parser.nit
+       @echo '***************************************************************'
+       @echo '* Compile nitg_0 from NIT source files                          *'
+       @echo '***************************************************************'
+       ./git-gen-version.sh
+       ../c_src/nitg ${NITCOPT} -o nitg_0 -v nitg.nit
+
+../bin/nitg: nitg_0 parser/parser.nit
        @echo '***************************************************************'
        @echo '* Compile nitg from NIT source files                          *'
        @echo '***************************************************************'
        ./git-gen-version.sh
-       ../c_src/nitg ${NITCOPT} -o ../bin/nitg -v nitg.nit
+       ./nitg_0 ${NITCOPT} -o ../bin/nitg -v nitg.nit
 
 ../bin/nitdoc: ../bin/nitg
        @echo '***************************************************************'
@@ -34,7 +41,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 +55,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                          *'
index 831311d..f16c5c5 100644 (file)
@@ -61,6 +61,8 @@ redef class ToolContext
        var opt_stacktrace: OptionString = new OptionString("Control the generation of stack traces", "--stacktrace")
        # --no-gcc-directives
        var opt_no_gcc_directive = new OptionArray("Disable a advanced gcc directives for optimization", "--no-gcc-directive")
+       # --release
+       var opt_release = new OptionBool("Compile in release mode and finalize application", "--release")
 
        redef init
        do
@@ -70,6 +72,7 @@ redef class ToolContext
                self.option_context.add_option(self.opt_typing_test_metrics, self.opt_invocation_metrics, self.opt_isset_checks_metrics)
                self.option_context.add_option(self.opt_stacktrace)
                self.option_context.add_option(self.opt_no_gcc_directive)
+               self.option_context.add_option(self.opt_release)
        end
 
        redef fun process_options(args)
@@ -1558,6 +1561,7 @@ redef class MMethodDef
        # Can the body be inlined?
        fun can_inline(v: VISITOR): Bool
        do
+               if is_abstract then return true
                var modelbuilder = v.compiler.modelbuilder
                if modelbuilder.mpropdef2npropdef.has_key(self) then
                        var npropdef = modelbuilder.mpropdef2npropdef[self]
@@ -1630,13 +1634,16 @@ redef class APropdef
        fun can_inline: Bool do return true
 end
 
-redef class AConcreteMethPropdef
+redef class AMethPropdef
        redef fun compile_to_c(v, mpropdef, arguments)
        do
-               for i in [0..mpropdef.msignature.arity[ do
-                       var variable = self.n_signature.n_params[i].variable.as(not null)
-                       v.assign(v.variable(variable), arguments[i+1])
+               if mpropdef.is_abstract then
+                       var cn = v.class_name_string(arguments.first)
+                       v.add("fprintf(stderr, \"Runtime error: Abstract method `%s` called on `%s`\", \"{mpropdef.mproperty.name.escape_to_c}\", {cn});")
+                       v.add_raw_abort
+                       return
                end
+
                # Call the implicit super-init
                var auto_super_inits = self.auto_super_inits
                if auto_super_inits != null then
@@ -1649,7 +1656,23 @@ redef class AConcreteMethPropdef
                                v.compile_callsite(auto_super_init, args)
                        end
                end
-               v.stmt(self.n_block)
+
+               var n_block = n_block
+               if n_block != null then
+                       for i in [0..mpropdef.msignature.arity[ do
+                               var variable = self.n_signature.n_params[i].variable.as(not null)
+                               v.assign(v.variable(variable), arguments[i+1])
+                       end
+                       v.stmt(n_block)
+               else if mpropdef.is_intern then
+                       compile_intern_to_c(v, mpropdef, arguments)
+               else if mpropdef.is_extern then
+                       if mpropdef.mproperty.is_init then
+                               compile_externinit_to_c(v, mpropdef, arguments)
+                       else
+                               compile_externmeth_to_c(v, mpropdef, arguments)
+                       end
+               end
        end
 
        redef fun can_inline
@@ -1661,10 +1684,8 @@ redef class AConcreteMethPropdef
                if nblock isa ABlockExpr and nblock.n_expr.length == 0 then return true
                return false
        end
-end
 
-redef class AInternMethPropdef
-       redef fun compile_to_c(v, mpropdef, arguments)
+       fun compile_intern_to_c(v: AbstractCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
        do
                var pname = mpropdef.mproperty.name
                var cname = mpropdef.mclassdef.mclass.name
@@ -1897,10 +1918,8 @@ redef class AInternMethPropdef
                v.add("printf(\"NOT YET IMPLEMENTED {class_name}:{mpropdef} at {location.to_s}\\n\");")
                debug("Not implemented {mpropdef}")
        end
-end
 
-redef class AExternMethPropdef
-       redef fun compile_to_c(v, mpropdef, arguments)
+       fun compile_externmeth_to_c(v: AbstractCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
        do
                var externname
                var nextern = self.n_extern
@@ -1929,10 +1948,8 @@ redef class AExternMethPropdef
                        v.ret(res)
                end
        end
-end
 
-redef class AExternInitPropdef
-       redef fun compile_to_c(v, mpropdef, arguments)
+       fun compile_externinit_to_c(v: AbstractCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
        do
                var externname
                var nextern = self.n_extern
@@ -2007,11 +2024,11 @@ redef class AClassdef
                if mpropdef == self.mfree_init then
                        var super_inits = self.super_inits
                        if super_inits != null then
-                               assert arguments.length == 1
+                               var args_of_super = arguments
+                               if arguments.length > 1 then args_of_super = [arguments.first]
                                for su in super_inits do
-                                       v.send(su, arguments)
+                                       v.send(su, args_of_super)
                                end
-                               return
                        end
                        var recv = arguments.first
                        var i = 1
@@ -2028,15 +2045,6 @@ redef class AClassdef
        end
 end
 
-redef class ADeferredMethPropdef
-       redef fun compile_to_c(v, mpropdef, arguments) do
-               var cn = v.class_name_string(arguments.first)
-               v.add("fprintf(stderr, \"Runtime error: Abstract method `%s` called on `%s`\", \"{mpropdef.mproperty.name.escape_to_c}\", {cn});")
-               v.add_raw_abort
-       end
-       redef fun can_inline do return true
-end
-
 redef class AExpr
        # Try to compile self as an expression
        # Do not call this method directly, use `v.expr` instead
@@ -2568,7 +2576,7 @@ redef class ASuperExpr
                if callsite != null then
                        # Add additionnals arguments for the super init call
                        if args.length == 1 then
-                               for i in [0..callsite.mproperty.intro.msignature.arity[ do
+                               for i in [0..callsite.msignature.arity[ do
                                        args.add(v.frame.arguments[i+1])
                                end
                        end
index 20493e5..6f762e0 100644 (file)
@@ -41,7 +41,7 @@ end
 class AndroidToolchain
        super MakefileToolchain
 
-       var android_project_root: String
+       var android_project_root: nullable String = null
 
        redef fun compile_dir
        do
@@ -52,12 +52,13 @@ class AndroidToolchain
 
        redef fun write_files(compiler, compile_dir, cfiles)
        do
+               var android_project_root = android_project_root.as(not null)
                var project = toolcontext.modelbuilder.android_project_for(compiler.mainmodule)
                var short_project_name = compiler.mainmodule.name
+               var release = toolcontext.opt_release.value
 
                var app_name = project.name
                if app_name == null then app_name = compiler.mainmodule.name
-               print app_name
 
                var app_package = project.java_package
                if app_package == null then app_package = "org.nitlanguage.{short_project_name}"
@@ -120,8 +121,7 @@ $(call import-module,android/native_app_glue)
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="{{{app_package}}}"
         android:versionCode="{{{project.version_code}}}"
-        android:versionName="{{{app_version}}}"
-        android:debuggable="true">
+        android:versionName="{{{app_version}}}">
 
     <!-- This is the platform API where NativeActivity was introduced. -->
     <uses-sdk android:minSdkVersion="9" />
@@ -129,7 +129,7 @@ $(call import-module,android/native_app_glue)
     <application
                android:label="@string/app_name"
                android:hasCode="true"
-               android:debuggable="true">
+               android:debuggable="{{{not release}}}">
 
         <!-- Our activity is the built-in NativeActivity framework class.
              This will take care of integrating with our NDK code. -->
@@ -185,9 +185,14 @@ $(call import-module,android/native_app_glue)
 
                ### Link to assets (for mnit and others)
                # This will be accessed from `android_project_root`
-               var mainmodule_dir = compiler.mainmodule.location.file.filename.dirname
-               var assets_dir = "{mainmodule_dir}/../assets"
-               if not assets_dir.file_exists then assets_dir = "{mainmodule_dir}/assets"
+               var assets_dir
+               if compiler.mainmodule.location.file != null then
+                       # it is a real file, use "{file}/../assets"
+                       assets_dir = "{compiler.mainmodule.location.file.filename.dirname}/../assets"
+               else
+                       # probably used -m, use "."
+                       assets_dir = "assets"
+               end
                if assets_dir.file_exists then
                        assets_dir = assets_dir.realpath
                        var target_assets_dir = "{android_project_root}/assets"
@@ -204,16 +209,29 @@ $(call import-module,android/native_app_glue)
 
        redef fun compile_c_code(compiler, compile_dir)
        do
+               var android_project_root = android_project_root.as(not null)
+               var release = toolcontext.opt_release.value
+
                # Compile C code (and thus Nit)
                toolcontext.exec_and_check(["ndk-build", "-s", "-j", "4", "-C", android_project_root], "Android project error")
 
                # Generate the apk
-               toolcontext.exec_and_check(["ant", "-q", "debug", "-f", android_project_root+"/build.xml"], "Android project error")
+               var args = ["ant", "-q", "-f", android_project_root+"/build.xml"]
+               if release then
+                       args.add "release"
+               else args.add "debug"
+               toolcontext.exec_and_check(args, "Android project error")
 
                # Move the apk to the target
                var outname = toolcontext.opt_output.value
                if outname == null then outname = "{compiler.mainmodule.name}.apk"
-               toolcontext.exec_and_check(["mv", "{android_project_root}/bin/{compiler.mainmodule.name}-debug.apk", outname], "Android project error")
+
+               var src_apk_suffix
+               if release then
+                       src_apk_suffix = "release-unsigned"
+               else src_apk_suffix = "debug"
+
+               toolcontext.exec_and_check(["mv", "{android_project_root}/bin/{compiler.mainmodule.name}-{src_apk_suffix}.apk", outname], "Android project error")
        end
 end
 
index afcffdf..3b5aceb 100644 (file)
@@ -36,17 +36,15 @@ class ASTBuilder
        end
 
        # Make a new instatiation
-       fun make_new(mtype: MClassType, constructor: MMethod, args: nullable Array[AExpr]): ANewExpr
+       fun make_new(callsite: CallSite, args: nullable Array[AExpr]): ANewExpr
        do
-               return new ANewExpr.make(mtype, constructor, args)
+               return new ANewExpr.make(callsite, args)
        end
 
        # Make a new message send
-       fun make_call(recv: AExpr, mmethod: MMethod, args: nullable Array[AExpr]): ACallExpr
+       fun make_call(recv: AExpr, callsite: CallSite, args: nullable Array[AExpr]): ACallExpr
        do
-               var mtype = mmethod.intro.msignature.return_mtype
-               if mtype != null then mtype = mtype.resolve_for(recv.mtype.as(not null), anchor, mmodule, true)
-               return new ACallExpr.make(recv, mmethod, args, mtype)
+               return new ACallExpr.make(recv, callsite, args)
        end
 
        # Make a new, empty, sequence of statements
@@ -230,7 +228,7 @@ redef class ADecIntExpr
 end
 
 redef class ANewExpr
-       private init make(mtype: MClassType, mmethod: MMethod, args: nullable Array[AExpr])
+       private init make(callsite: CallSite, args: nullable Array[AExpr])
        do
                _n_kwnew = new TKwnew
                _n_type = new AType.make
@@ -238,24 +236,24 @@ redef class ANewExpr
                if args != null then
                        n_args.n_exprs.add_all(args)
                end
-               callsite = new CallSite(self, mtype, mmethod.intro.mclassdef.mmodule, mtype, true, mmethod, mmethod.intro, mmethod.intro.msignature.as(not null), false)
-               self.mtype = mtype
+               self.callsite = callsite
+               self.mtype = callsite.recv
+               self.is_typed = true
        end
 end
 
 redef class ACallExpr
-       private init make(recv: AExpr, mmethod: MMethod, args: nullable Array[AExpr], t: nullable MType)
+       private init make(recv: AExpr, callsite: CallSite, args: nullable Array[AExpr])
        do
                self._n_expr = recv
-               recv.parent = self
                _n_args = new AListExprs
                _n_id = new TId
                if args != null then
                        self.n_args.n_exprs.add_all(args)
                end
                var mtype = recv.mtype.as(not null)
-               callsite = new CallSite(self, mtype, mmethod.intro.mclassdef.mmodule, mmethod.intro.mclassdef.bound_mtype, true, mmethod, mmethod.intro, mmethod.intro.msignature.as(not null), false)
-               self.mtype = t
+               self.callsite = callsite
+               self.mtype = callsite.msignature.return_mtype
                self.is_typed = true
        end
 end
index 8e210cc..c13fb36 100644 (file)
@@ -28,7 +28,7 @@ end
 
 private class AutoSuperInitPhase
        super Phase
-       redef fun process_npropdef(npropdef) do if npropdef isa AConcreteMethPropdef then npropdef.do_auto_super_init(toolcontext.modelbuilder)
+       redef fun process_npropdef(npropdef) do if npropdef isa AMethPropdef then npropdef.do_auto_super_init(toolcontext.modelbuilder)
 end
 
 private class AutoSuperInitVisitor
@@ -47,7 +47,7 @@ private class AutoSuperInitVisitor
 end
 
 
-redef class AConcreteMethPropdef
+redef class AMethPropdef
        # In case of constructor, the list of implicit auto super init constructors invoked (if needed)
        var auto_super_inits: nullable Array[CallSite] = null
 
index 0567a27..d7153e5 100644 (file)
@@ -46,7 +46,7 @@ private class CachedPhase
                # Do some validity checks and print errors if the annotation is used incorrectly
                var modelbuilder = toolcontext.modelbuilder
 
-               if not npropdef isa AConcreteMethPropdef then
+               if not npropdef isa AMethPropdef then
                        modelbuilder.error(npropdef, "Syntax error: only a function can be cached.")
                        return
                end
@@ -87,7 +87,7 @@ private class CachedPhase
                var real_mpropdef = new MMethodDef(mclassdef, new MMethod(mclassdef, "{name}<real>", private_visibility), location)
                real_mpropdef.msignature = mpropdef.msignature
                # FIXME: Again, if the engine require a real propdef even if it is empty
-               var real_npropdef = toolcontext.parse_propdef("fun real do end").as(AConcreteMethPropdef)
+               var real_npropdef = toolcontext.parse_propdef("fun real do end").as(AMethPropdef)
                associate_propdef(real_mpropdef, real_npropdef)
                # Note: the body is set at the last line of this function
 
diff --git a/src/coloring.nit b/src/coloring.nit
new file mode 100644 (file)
index 0000000..0b4532d
--- /dev/null
@@ -0,0 +1,392 @@
+# 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.
+
+module coloring
+
+import poset
+
+# Build a conflict graph from a POSet
+class POSetConflictGraph[E: Object]
+
+       # Core is composed by:
+       #  * elements that have mutiple direct parents
+       #  * parents of elements that have multiple direct parents
+       # REQUIRE: is_colored
+       var core = new HashSet[E]
+
+       # Border is composed by minimal elements of the core:
+       #  * that have multiple direct parents
+       #  * but whose subelements are all in single inheritance
+       # REQUIRE: is_colored
+       var border = new HashSet[E]
+
+       # The crown is composed by the elements that are:
+       #  * not part of the core nor the border
+       #  * are in single inheritance
+       # REQUIRE: is_colored
+       var crown = new HashSet[E]
+
+       # Conflict graph of the POSet
+       # Elements X and Y are in conflict if either:
+       #  * X and Y are the same element
+       #  * Y is a subelement of X
+       #  * X and Y have common sub elements
+       # REQUIRE: is_colored
+       var conflicts = new HashMap[E, Set[E]]
+
+       var poset: POSet[E]
+
+       init(poset: POSet[E]) do
+               self.poset = poset
+               extract_core
+               extract_border
+               extract_crown
+               compute_conflicts
+       end
+
+       # Compute the set of elements forming the core of the poset hierarchy.
+       private fun extract_core do
+               core.clear
+               for e in poset do
+                       if poset[e].direct_greaters.length > 1 then
+                               core.add_all(poset[e].greaters)
+                       end
+               end
+       end
+
+       # Compute the set of elements composing the border of the core
+       # Elements belonging to the `border` are removed from the `core`
+       private fun extract_border do
+               border.clear
+               for e in core do
+                       if not is_border(e) then continue
+                       border.add(e)
+               end
+               for e in border do core.remove(e)
+       end
+
+       private fun is_border(e: E): Bool do
+               for child in poset[e].direct_smallers do
+                       if core.has(child) then return false
+               end
+               return true
+       end
+
+       # Compute the set of elements belonging to the crown of the inheritance hierarchy.
+       private fun extract_crown do
+               crown.clear
+               for e in poset do
+                       if not core.has(e) and not border.has(e) then crown.add(e)
+               end
+       end
+
+       # Check for conflict in the core.
+       # Start from border and tag every ancestors
+       private fun compute_conflicts do
+               conflicts.clear
+               for e in border do add_conflicts(poset[e].greaters)
+       end
+
+       private fun add_conflict(e, o: E) do
+               if not conflicts.has_key(e) then conflicts[e] = new HashSet[E]
+               if not conflicts.has_key(o) then conflicts[o] = new HashSet[E]
+               conflicts[e].add(o)
+               conflicts[o].add(e)
+       end
+
+       private fun add_conflicts(es: Collection[E]) do
+               for e1 in es do
+                       for e2 in es do add_conflict(e1, e2)
+               end
+       end
+
+       # Used for debugging only
+       fun pretty_print do
+               #print "core: {core.join(" ")} ({core.length})"
+               #print "border: {border.join(" ")} ({border.length})"
+               #print "crown: {crown.join(" ")} ({crown.length})"
+               print "conflicts:"
+               for e, c in conflicts do print "  {e}: {c.join(" ")}"
+       end
+end
+
+# Colorize elements from a POSet
+# Two elements from a POSet cannot have the same color if they share common subelements
+#
+# Example:
+#       A
+#     / | \
+#    /  |  \
+#   B   C   D
+#   |  /|   |
+#   | / |   |
+#   |/  |   |
+#   E   F   G
+#   |
+#   H
+# Conflicts:
+#   A: {B, C, D, E, F, G, H}
+#   B: {A, C, E, H}
+#   C: {A, E, H, F}
+#   D: {A, G}
+#   E: {A, B, C, H}
+#   F: {A, C}
+#   G: {A, D}
+#   H: {A, B, C, E}
+# Possible colors:
+#   A:0, B:1, C: 2, D: 1, E: 3, F:3, G:2, H:4
+#
+# see:
+#      Ducournau, R. (2011).
+#      Coloring, a versatile technique for implementing object-oriented languages.
+#      Software: Practice and Experience, 41(6), 627–659.
+class POSetColorer[E: Object]
+
+       # Is the poset already colored?
+       var is_colored = false
+
+       # Resulting ids
+       # REQUIRE: is_colored
+       fun ids: Map[E, Int] do
+               assert is_colored
+               return ids_cache
+       end
+       private var ids_cache = new HashMap[E, Int]
+
+       # Resulting colors
+       # REQUIRE: is_colored
+       fun colors: Map[E, Int] do
+               assert is_colored
+               return colors_cache
+       end
+       private var colors_cache = new HashMap[E, Int]
+
+       # REQUIRE: is_colored
+       fun poset: POSet[E] do
+               assert is_colored
+               return poset_cache
+       end
+       private var poset_cache: POSet[E]
+
+       # REQUIRE: is_colored
+       fun conflicts: Map[E, Set[E]] do
+               assert is_colored
+               return conflicts_cache
+       end
+       private var conflicts_cache: Map[E, Set[E]]
+
+       private var graph: POSetConflictGraph[E]
+
+       init do end
+
+       # Start coloring on given POSet
+       fun colorize(poset: POSet[E]) do
+               poset_cache = poset
+               graph = new POSetConflictGraph[E](poset)
+               allocate_ids
+               compute_colors
+               conflicts_cache = graph.conflicts
+               is_colored = true
+       end
+
+       private fun allocate_ids do
+               ids_cache.clear
+               var elements = new HashSet[E].from(poset_cache.to_a)
+               for e in poset_cache.linearize(elements) do
+                       ids_cache[e] = ids_cache.length
+               end
+       end
+
+       # Colorize core, border and crown in that order
+       private fun compute_colors do
+               colors_cache.clear
+               colorize_core
+               colorize_set(graph.border)
+               colorize_set(graph.crown)
+       end
+
+       # Core elements cannot have the same color than:
+       #  * one of their parents
+       #  * one of their conflicting elements
+       private fun colorize_core do
+               for e in poset_cache.linearize(graph.core) do
+                       var color = min_color(e)
+                       var conflicts = graph.conflicts[e]
+                       while not is_color_free(color, conflicts) do
+                               color += 1
+                       end
+                       colors_cache[e] = color
+               end
+       end
+
+       # Other elements inherit color fron their direct parents
+       private fun colorize_set(set: Set[E]) do
+               for e in poset_cache.linearize(set) do colors_cache[e] = min_color(e)
+       end
+
+       # Get the next minimal color from direct parents
+       private fun min_color(e: E): Int do
+               var max_color = -1
+               for p in poset_cache[e].direct_greaters do
+                       if not colors_cache.has_key(p) then continue
+                       var color = colors_cache[p]
+                       if color > max_color then max_color = color
+               end
+               return max_color + 1
+       end
+
+       private fun is_color_free(color: Int, set: Collection[E]): Bool do
+               for e in set do
+                       if colors_cache.has_key(e) and colors_cache[e] == color then return false
+               end
+               return true
+       end
+
+       # Used for debugging only
+       fun pretty_print do
+               print "ids:"
+               for e, id in ids do print "  {e}: {id}"
+               print "colors:"
+               for e, c in colors do print "  {e}: {c}"
+       end
+end
+
+# Colorize a collection of buckets
+# Two elements cannot have the same color if they both appear in the same bucket
+# No coloring order is garantied
+#
+# Example:
+#      buckets[A] = {x1, x2}
+#   buckets[B] = {x1, x3, x4}
+#      buckets[C] = {x2, x3}
+# Conflicts:
+#      x1: {x2, x3, x4}
+#   x2: {x1, x3}
+#   x3: {x1, x2, x4}
+#   x4: {x1, x3}
+# Possible colors:
+#      x1: 0, x2: 1, x3: 2, x4: 1
+class BucketsColorer[H: Object, E: Object]
+       private var colors = new HashMap[E, Int]
+       private var conflicts = new HashMap[E, Set[E]]
+
+       init do end
+
+       # Start bucket coloring
+       fun colorize(buckets: Map[H, Set[E]]): Map[E, Int] do
+               compute_conflicts(buckets)
+               var min_color = 0
+               for holder, hbuckets in buckets do
+                       for bucket in hbuckets do
+                               if colors.has_key(bucket) then continue
+                               var color = min_color
+                               while not is_color_free(bucket, color) do
+                                       color += 1
+                               end
+                               colors[bucket] = color
+                               color = min_color
+                       end
+               end
+               return colors
+       end
+
+       private fun is_color_free(bucket: E, color: Int): Bool do
+               if conflicts.has_key(bucket) then
+                       for other in conflicts[bucket] do
+                               if colors.has_key(other) and colors[other] == color then return false
+                       end
+               end
+               return true
+       end
+
+       private fun compute_conflicts(buckets: Map[H, Set[E]]) do
+               conflicts.clear
+               for holder, hbuckets in buckets do
+                       for bucket in hbuckets do
+                               if not conflicts.has_key(bucket) then conflicts[bucket] = new HashSet[E]
+                               for obucket in hbuckets do
+                                       if obucket == bucket then continue
+                                       if not conflicts.has_key(obucket) then conflicts[obucket] = new HashSet[E]
+                                       conflicts[bucket].add(obucket)
+                                       conflicts[obucket].add(bucket)
+                               end
+                       end
+               end
+       end
+end
+
+# Colorize a collection of buckets using a poset and a conflict graph
+# Two elements cannot have the same color if they both appear in the same bucket
+# The use of a POSet hierarchy optimize the coloring
+# Buckets elements are colored using linearization order starting
+class POSetBucketsColorer[H: Object, E: Object]
+       private var colors = new HashMap[E, Int]
+       private var poset: POSet[H]
+       private var conflicts: Map[H, Set[H]]
+
+       init(poset: POSet[H], conflicts: Map[H, Set[H]]) do
+               self.poset = poset
+               self.conflicts = conflicts
+       end
+
+       # Colorize buckets using the POSet and conflict graph
+       fun colorize(buckets: Map[H, Set[E]]): Map[E, Int] do
+               colors.clear
+               for h in poset.linearize(buckets.keys) do
+                       var color = min_color(poset[h].direct_greaters, buckets)
+                       for bucket in buckets[h] do
+                               if colors.has_key(bucket) then continue
+                               while not is_color_free(color, h, buckets) do color += 1
+                               colors[bucket] = color
+                               color += 1
+                       end
+               end
+               return colors
+       end
+
+       # Get the next available color considering used colors by other buckets
+       private fun min_color(others: Collection[H], buckets: Map[H, Set[E]]): Int do
+               var min = -1
+               for holder in others do
+                       var color = max_color(holder, buckets)
+                       if color > min then min = color
+               end
+               return min + 1
+       end
+
+       # Return the max color used by a class
+       private fun max_color(holder: H, buckets: Map[H, Set[E]]): Int do
+               var max = -1
+               for bucket in buckets[holder] do
+                       if not colors.has_key(bucket) then continue
+                       var color = colors[bucket]
+                       if color > max then max = color
+               end
+               return max
+       end
+
+       # Check if the color is free for this holder
+       private fun is_color_free(color: Int, holder: H, buckets: Map[H, Set[E]]): Bool do
+               if not conflicts.has_key(holder) then return true
+               for conflict in conflicts[holder] do
+                       for bucket in buckets[conflict] do
+                               if not colors.has_key(bucket) then continue
+                               if colors[bucket] == color then return false
+                       end
+               end
+               return true
+       end
+end
+
+
index 17241bd..65b1a22 100644 (file)
@@ -28,7 +28,7 @@ class CLanguage
 
        redef fun identify_language(n) do return n.is_c
 
-       redef fun compile_module_block(block, ecc, nmodule)
+       redef fun compile_module_block(block, ecc, mmodule)
        do
                if block.is_c_header then
                        ecc.header_custom.add( block.location.as_line_pragma )
@@ -39,21 +39,21 @@ class CLanguage
                end
        end
 
-       redef fun compile_extern_method(block, m, ecc, nmodule)
+       redef fun compile_extern_method(block, m, ecc, mmodule)
        do
-               var fc = new ExternCFunction(m, nmodule.mmodule.as(not null))
+               var fc = new ExternCFunction(m, mmodule.as(not null))
                fc.decls.add( block.location.as_line_pragma )
                fc.exprs.add( block.code )
                ecc.add_exported_function( fc )
        end
 
-       redef fun compile_extern_class(block, m, ecc, nmodule) do end
+       redef fun compile_extern_class(block, m, ecc, mmodule) do end
 
        redef fun get_ftype(block, m) do return new ForeignCType(block.code)
 
-       redef fun compile_callback(callback, nmodule, mmodule, ecc)
+       redef fun compile_callback(callback, mmodule, mainmodule, ecc)
        do
-               callback.compile_callback_to_c(mmodule, ecc)
+               callback.compile_callback_to_c(mainmodule, ecc)
        end
 end
 
@@ -88,7 +88,7 @@ class ForeignCType
 end
 
 redef class NitniCallback
-       fun compile_callback_to_c(nmodule: MModule, ffi_ccu: CCompilationUnit) do end
+       fun compile_callback_to_c(mmodule: MModule, ffi_ccu: CCompilationUnit) do end
 end
 
 redef class Object
@@ -135,9 +135,9 @@ end
 class ExternCFunction
        super CFunction
 
-       var method: AExternPropdef
+       var method: AMethPropdef
 
-       init (method: AExternPropdef, mmodule: MModule)
+       init (method: AMethPropdef, mmodule: MModule)
        do
                self.method = method
 
index 48bd8e8..5b2c0d7 100644 (file)
@@ -36,31 +36,53 @@ import java
 redef class MModule
        # Does this module uses the FFI?
        var uses_ffi: Bool = false
-end
 
-redef class AModule
        # C compilation unit for the FFI files
        private var ffi_ccu: nullable CCompilationUnit = null
 
        # Foreign language used in this AModule
        private var present_languages = new HashSet[FFILanguage]
 
+       # Complete the compilation of the FFI code
+       fun finalize_ffi_wrapper(compdir: String, mainmodule: MModule)
+       do
+               for language in ffi_callbacks.keys do
+                       for callback in ffi_callbacks[language] do
+                               language.compile_callback(callback, self, mainmodule, ffi_ccu.as(not null))
+                       end
+
+                       language.compile_to_files(self, compdir)
+               end
+
+               # include dependancies FFI
+               for mod in header_dependencies do
+                       if mod.uses_ffi then ffi_ccu.header_custom.add("#include \"{mod.name}._ffi.h\"\n")
+               end
+
+               ffi_ccu.write_as_impl(self, compdir)
+               for filename in ffi_ccu.files do ffi_files.add(new ExternCFile(filename, c_compiler_options))
+       end
+end
+
+redef class AModule
+
        # Ensures all of the general foreign code of the module has been analyzed.
        # Manages header blocks, extern class types and foreign dependancies between modules
        fun ensure_compile_ffi_wrapper
        do
-               if ffi_ccu != null then return
+               var mmodule = mmodule
+               if mmodule == null or mmodule.ffi_ccu != null then return
 
                # ready extern code compiler
                var ffi_ccu = new CCompilationUnit
-               self.ffi_ccu = ffi_ccu
+               mmodule.ffi_ccu = ffi_ccu
 
                # generate code
                for block in n_extern_code_blocks do
                        var language = block.language
                        assert language != null
-                       present_languages.add(language)
-                       language.compile_module_block(block, ffi_ccu, self)
+                       mmodule.present_languages.add(language)
+                       language.compile_module_block(block, ffi_ccu, mmodule)
                end
 
                ffi_ccu.header_c_base.add( "#include \"{mmodule.name}._nitni.h\"\n" )
@@ -71,54 +93,30 @@ redef class AModule
                                mmodule.uses_ffi = true
                                var language = nclassdef.n_extern_code_block.language
                                assert language != null
-                               present_languages.add(language)
+                               mmodule.present_languages.add(language)
                                nclassdef.n_extern_code_block.language.compile_extern_class(
-                                       nclassdef.n_extern_code_block.as(not null), nclassdef, ffi_ccu, self)
-                       end
-               end
-       end
-
-       # Complete the compilation of the FFI code
-       fun finalize_ffi_wrapper(compdir: String, mainmodule: MModule)
-       do
-               ensure_compile_ffi_wrapper
-
-               for language in present_languages do if ffi_callbacks.keys.has(language) then
-                       for callback in ffi_callbacks[language] do
-                               language.compile_callback(callback, self, mainmodule, ffi_ccu.as(not null))
+                                       nclassdef.n_extern_code_block.as(not null), nclassdef, ffi_ccu, mmodule)
                        end
-
-                       language.compile_to_files(self, compdir)
-               end
-
-               # include dependancies FFI
-               for mod in mmodule.header_dependencies do
-                       if mod.uses_ffi then ffi_ccu.header_custom.add("#include \"{mod.name}._ffi.h\"\n")
                end
-
-               ffi_ccu.write_as_impl(self, compdir)
-               for filename in ffi_ccu.files do ffi_files.add(new ExternCFile(filename, mmodule.c_compiler_options))
        end
 end
 
-redef class AExternPropdef
+redef class AMethPropdef
        private var ffi_has_been_compiled = false
 
        # Compile the necessary wrapper around this extern method or constructor
-       fun compile_ffi_method(amodule: AModule)
+       fun compile_ffi_method(mmodule: MModule)
        do
                assert n_extern_code_block != null
 
                if ffi_has_been_compiled then return
                ffi_has_been_compiled = true
 
-               amodule.ensure_compile_ffi_wrapper
-
                var language = n_extern_code_block.language
                assert language != null
-               amodule.present_languages.add(language)
+               mmodule.present_languages.add(language)
                n_extern_code_block.language.compile_extern_method(
-                       n_extern_code_block.as(not null), self, amodule.ffi_ccu.as(not null), amodule)
+                       n_extern_code_block.as(not null), self, mmodule.ffi_ccu.as(not null), mmodule)
        end
 end
 
@@ -137,7 +135,7 @@ redef class VerifyNitniCallbacksPhase
 
                # Associate callbacks used by an extern method to its foreign language
                for callback in npropdef.foreign_callbacks.all do
-                       var map = npropdef.parent.parent.as(AModule).ffi_callbacks
+                       var map = npropdef.mpropdef.mclassdef.mmodule.ffi_callbacks
                        if not map.keys.has(lang) then map[lang] = new HashSet[NitniCallback]
                        map[lang].add(callback)
                end
index 6aa837d..c71d1c4 100644 (file)
@@ -24,11 +24,9 @@ redef class FFILanguageAssignationPhase
        var cpp_language: FFILanguage = new CPPLanguage(self)
 end
 
-redef class AModule
+redef class MModule
        private var cpp_file: nullable CPPCompilationUnit = null
-end
 
-redef class MModule
        var cpp_compiler_options writable = ""
 end
 
@@ -37,16 +35,16 @@ class CPPLanguage
 
        redef fun identify_language(n) do return n.is_cpp
 
-       redef fun compile_module_block(block, ecc, nmodule)
+       redef fun compile_module_block(block, ecc, mmodule)
        do
-               if nmodule.cpp_file == null then nmodule.cpp_file = new CPPCompilationUnit
+               if mmodule.cpp_file == null then mmodule.cpp_file = new CPPCompilationUnit
 
                if block.is_cpp_header then
-                       nmodule.cpp_file.header_custom.add(block.location.as_line_pragma)
-                       nmodule.cpp_file.header_custom.add(block.code)
+                       mmodule.cpp_file.header_custom.add(block.location.as_line_pragma)
+                       mmodule.cpp_file.header_custom.add(block.code)
                else if block.is_cpp_body then
-                       nmodule.cpp_file.body_custom.add( block.location.as_line_pragma )
-                       nmodule.cpp_file.body_custom.add( block.code )
+                       mmodule.cpp_file.body_custom.add( block.location.as_line_pragma )
+                       mmodule.cpp_file.body_custom.add( block.code )
                end
        end
 
@@ -54,11 +52,10 @@ class CPPLanguage
        # 1. The standard C implementation function (___impl) expected by the common FFI
        # 2. The indirection function (___cpp_impl_mid) is a C function, called from C but implemented as `extern "C"` in C++
        # 3. The actual C++ implementation function (___cpp_impl)
-       redef fun compile_extern_method(block, m, ecc, nmodule)
+       redef fun compile_extern_method(block, m, ecc, mmodule)
        do
-               if nmodule.cpp_file == null then nmodule.cpp_file = new CPPCompilationUnit
+               if mmodule.cpp_file == null then mmodule.cpp_file = new CPPCompilationUnit
 
-               var mmodule = nmodule.mmodule.as(not null)
                var mclass_type = m.parent.as(AClassdef).mclass.mclass_type
                var mproperty = m.mpropdef.mproperty
 
@@ -79,9 +76,9 @@ class CPPLanguage
                ## In C++ file (__ffi.cpp)
 
                # Declare the indirection function in C++
-               nmodule.cpp_file.header_decl.add("extern \"C\" \{\n")
-               nmodule.cpp_file.header_decl.add("{indirection_sig};\n")
-               nmodule.cpp_file.header_decl.add("\}\n")
+               mmodule.cpp_file.header_decl.add("extern \"C\" \{\n")
+               mmodule.cpp_file.header_decl.add("{indirection_sig};\n")
+               mmodule.cpp_file.header_decl.add("\}\n")
 
                # Implement the indirection function as extern in C++
                # Will convert C arguments to C++ and call the C++ implementation function.
@@ -106,42 +103,42 @@ class CPPLanguage
                end
                fc.exprs.add(mproperty.build_ccall(mclass_type, mmodule, "___cpp_impl", long_signature, cpp_call_context, "_for_cpp"))
                fc.exprs.add("\n")
-               nmodule.cpp_file.add_local_function(fc)
+               mmodule.cpp_file.add_local_function(fc)
 
                # Custom C++, the body of the Nit C++ method is copied to its own C++ function
                var cpp_signature = mproperty.build_csignature(mclass_type, mmodule, "___cpp_impl", long_signature, cpp_call_context)
                fc = new CFunction(cpp_signature)
                fc.decls.add( block.location.as_line_pragma )
                fc.exprs.add( block.code )
-               nmodule.cpp_file.add_local_function( fc )
+               mmodule.cpp_file.add_local_function( fc )
        end
 
-       redef fun compile_extern_class(block, m, ecc, nmodule) do end
+       redef fun compile_extern_class(block, m, ecc, mmodule) do end
 
        redef fun get_ftype(block, m) do return new ForeignCppType(block.code)
 
-       redef fun compile_to_files(nmodule, compdir)
+       redef fun compile_to_files(mmodule, compdir)
        do
-               var cpp_file = nmodule.cpp_file
+               var cpp_file = mmodule.cpp_file
                assert cpp_file != null
 
                # write .cpp and .hpp file
                cpp_file.header_custom.add("extern \"C\" \{\n")
-               cpp_file.header_custom.add("#include \"{nmodule.mmodule.name}._ffi.h\"\n")
+               cpp_file.header_custom.add("#include \"{mmodule.name}._ffi.h\"\n")
                cpp_file.header_custom.add("\}\n")
 
-               var file = cpp_file.write_to_files(nmodule, compdir)
+               var file = cpp_file.write_to_files(mmodule, compdir)
 
                # add complation to makefile
-               nmodule.ffi_files.add(file)
+               mmodule.ffi_files.add(file)
 
                # add linked option to support C++
-               nmodule.mmodule.c_linker_options = "{nmodule.mmodule.c_linker_options} -lstdc++"
+               mmodule.c_linker_options = "{mmodule.c_linker_options} -lstdc++"
        end
 
-       redef fun compile_callback(callback, nmodule, mmodule, ecc)
+       redef fun compile_callback(callback, mmodule, mainmodule, ecc)
        do
-               callback.compile_callback_to_cpp(nmodule, mmodule)
+               callback.compile_callback_to_cpp(mmodule, mainmodule)
        end
 end
 
@@ -159,18 +156,17 @@ end
 class CPPCompilationUnit
        super CCompilationUnit
 
-       fun write_to_files(amodule: AModule, compdir: String): ExternCppFile
+       fun write_to_files(mmodule: MModule, compdir: String): ExternCppFile
        do
-               var mmodule = amodule.mmodule.as(not null)
                var base_name = "{mmodule.name}._ffi"
 
                var h_file = "{base_name}.hpp"
-               var guard = "{amodule.cname.to_s.to_upper}_NIT_HPP"
+               var guard = "{mmodule.cname.to_s.to_upper}_NIT_HPP"
 
-               write_header_to_file(amodule, "{compdir}/{h_file}", new Array[String], guard)
+               write_header_to_file(mmodule, "{compdir}/{h_file}", new Array[String], guard)
 
                var c_file = "{base_name}.cpp"
-               write_body_to_file(amodule, "{compdir}/{c_file}", ["<string>", "<iostream>", "\"{h_file}\""])
+               write_body_to_file(mmodule, "{compdir}/{c_file}", ["<string>", "<iostream>", "\"{h_file}\""])
 
                files.add("{compdir}/{c_file}")
 
@@ -205,7 +201,7 @@ class ForeignCppType
 end
 
 redef class NitniCallback
-       fun compile_callback_to_cpp(nmodule: AModule, mmodule: MModule) do end
+       fun compile_callback_to_cpp(mmodule: MModule, mainmodule: MModule) do end
 end
 
 redef class Object
@@ -215,16 +211,16 @@ redef class Object
 end
 
 redef class MExplicitCall
-       redef fun compile_callback_to_cpp(nmodule, mmodule)
+       redef fun compile_callback_to_cpp(mmodule, mainmodule)
        do
                var mproperty = mproperty
                assert mproperty isa MMethod
 
-               var cpp_signature = mproperty.build_csignature(recv_mtype, mmodule, null, short_signature, from_cpp_call_context)
-               var ccall = mproperty.build_ccall(recv_mtype, mmodule, null, long_signature, from_cpp_call_context, null)
+               var cpp_signature = mproperty.build_csignature(recv_mtype, mainmodule, null, short_signature, from_cpp_call_context)
+               var ccall = mproperty.build_ccall(recv_mtype, mainmodule, null, long_signature, from_cpp_call_context, null)
                var fc = new CFunction(cpp_signature)
                fc.exprs.add(ccall)
-               nmodule.cpp_file.add_local_function( fc )
+               mmodule.cpp_file.add_local_function( fc )
        end
 end
 
index f190bb1..3b53826 100644 (file)
@@ -41,7 +41,7 @@ class FFILanguageAssignationPhase
 
        redef fun process_npropdef(npropdef)
        do
-               if npropdef isa AExternPropdef then
+               if npropdef isa AMethPropdef then
                        var code_block = npropdef.n_extern_code_block
                        if code_block != null then
                                verify_foreign_code_on_node( code_block )
@@ -74,7 +74,7 @@ class FFILanguageAssignationPhase
        end
 end
 
-redef class AModule
+redef class MModule
        var ffi_files = new Array[ExternFile]
 
        # Callbacks used by this module, classified by language
@@ -108,25 +108,25 @@ class FFILanguage
        fun identify_language(block: AExternCodeBlock ): Bool is abstract
 
        # Generate wrapper code for this module/header code block
-       fun compile_module_block(block: AExternCodeBlock, ecc: CCompilationUnit, nmodule: AModule) is abstract
+       fun compile_module_block(block: AExternCodeBlock, ecc: CCompilationUnit, mmodule: MModule) is abstract
 
        # Generate wrapper code for this extern method
-       fun compile_extern_method(block: AExternCodeBlock, m: AExternPropdef,
-               ecc: CCompilationUnit, nmodule: AModule) is abstract
+       fun compile_extern_method(block: AExternCodeBlock, m: AMethPropdef,
+               ecc: CCompilationUnit, nmodule: MModule) is abstract
 
        # Generate wrapper code for this extern class
        fun compile_extern_class(block: AExternCodeBlock, m: AClassdef,
-               ecc: CCompilationUnit, nmodule: AModule) is abstract
+               ecc: CCompilationUnit, mmodule: MModule) is abstract
 
        # Get the foreign type of this extern class definition
        fun get_ftype(block: AExternCodeBlock, m: AClassdef): ForeignType is abstract
 
        # Generate the code to offer this callback if foreign code
-       fun compile_callback(callback: NitniCallback, nmodule: AModule,
+       fun compile_callback(callback: NitniCallback, mmodule: MModule,
                mainmmodule: MModule, ecc: CCompilationUnit) is abstract
 
        # Complete compilation of generated code
-       fun compile_to_files(amodule: AModule, directory: String) do end
+       fun compile_to_files(mmodule: MModule, directory: String) do end
 end
 
 redef class TString
@@ -148,26 +148,26 @@ redef class TExternCodeSegment
 end
 
 redef class CCompilationUnit
-       fun write_as_impl( amodule: AModule, compdir: String )
+       fun write_as_impl(mmodule: MModule, compdir: String)
        do
-               var base_name = "{amodule.mmodule.name}._ffi"
+               var base_name = "{mmodule.name}._ffi"
 
                var h_file = "{base_name}.h"
-               var guard = "{amodule.cname.to_s.to_upper}_NIT_H"
-               write_header_to_file( amodule, "{compdir}/{h_file}", new Array[String], guard)
+               var guard = "{mmodule.cname.to_s.to_upper}_NIT_H"
+               write_header_to_file(mmodule, "{compdir}/{h_file}", new Array[String], guard)
 
                var c_file = "{base_name}.c"
-               write_body_to_file( amodule, "{compdir}/{c_file}", ["<stdlib.h>", "<stdio.h>", "\"{h_file}\""] )
+               write_body_to_file(mmodule, "{compdir}/{c_file}", ["<stdlib.h>", "<stdio.h>", "\"{h_file}\""])
 
                files.add( "{compdir}/{c_file}" )
        end
 
-       fun write_header_to_file(amodule: AModule, file: String, includes: Array[String], guard: String)
+       fun write_header_to_file(mmodule: MModule, file: String, includes: Array[String], guard: String)
        do
                var stream = new OFStream.open( file )
 
                # header comments
-               var module_info = "/*\n\tExtern implementation of Nit module {amodule.mmodule.name}\n*/\n"
+               var module_info = "/*\n\tExtern implementation of Nit module {mmodule.name}\n*/\n"
 
                stream.write( module_info )
 
@@ -183,11 +183,11 @@ redef class CCompilationUnit
                stream.close
        end
 
-       fun write_body_to_file(amodule: AModule, file: String, includes: Array[String])
+       fun write_body_to_file(mmodule: MModule, file: String, includes: Array[String])
        do
                var stream = new OFStream.open(file)
 
-               var module_info = "/*\n\tExtern implementation of Nit module {amodule.mmodule.name}\n*/\n"
+               var module_info = "/*\n\tExtern implementation of Nit module {mmodule.name}\n*/\n"
 
                stream.write( module_info )
                for incl in includes do stream.write( "#include {incl}\n" )
index 231527c..a03f67d 100644 (file)
@@ -32,23 +32,22 @@ class JavaLanguage
 
        redef fun identify_language(n) do return n.is_java
 
-       redef fun compile_module_block(block, ccu, nmodule)
+       redef fun compile_module_block(block, ccu, mmodule)
        do
-               nmodule.ensure_java_files
-               var java_file = nmodule.java_file
+               mmodule.ensure_java_files
+               var java_file = mmodule.java_file
                assert java_file != null
 
                java_file.header.add(block.code)
        end
 
-       redef fun compile_extern_method(block, m, ccu, nmodule)
+       redef fun compile_extern_method(block, m, ccu, mmodule)
        do
                ffi_ccu = ccu
-               nmodule.ensure_java_files
-               var java_file = nmodule.java_file
+               mmodule.ensure_java_files
+               var java_file = mmodule.java_file
                assert java_file != null
 
-               var mmodule = nmodule.mmodule.as(not null)
                var mclass_type = m.parent.as(AClassdef).mclass.mclass_type
                var mmethodef = m.mpropdef
                var mproperty = m.mpropdef.mproperty
@@ -61,11 +60,11 @@ class JavaLanguage
        jmethodID java_meth_id;
 
        // retrieve the current JVM
-       Sys sys = {{{mmodule.name}}}___Pointer_sys(NULL);
-       JNIEnv *nit_ffi_jni_env = {{{mmodule.name}}}___Sys_jni_env(sys);
+       Sys sys = Pointer_sys(NULL);
+       JNIEnv *nit_ffi_jni_env = Sys_jni_env(sys);
 
        // retrieve the implementation Java class
-       java_class = {{{mmodule.name}}}___Sys_load_jclass(sys, "{{{mmodule.impl_java_class_name}}}");
+       java_class = Sys_load_jclass(sys, "{{{mmodule.impl_java_class_name}}}");
        if (java_class == NULL) {
                fprintf(stderr, "Nit FFI with Java error: failed to load class.\\n");
                (*nit_ffi_jni_env)->ExceptionDescribe(nit_ffi_jni_env);
@@ -148,7 +147,7 @@ class JavaLanguage
 
                # Java implementation function in Java
                var java_csig = mproperty.build_csignature(mclass_type, mmodule, "___java_impl", long_signature, java_call_context)
-               nmodule.java_file.class_content.add """
+               mmodule.java_file.class_content.add """
        public static {{{java_csig}}} {
                // from Nit FII at: {{{block.location}}}
                {{{block.code}}}
@@ -156,38 +155,38 @@ class JavaLanguage
 """
        end
 
-       redef fun compile_extern_class(block, m, ccu, nmodule) do end
+       redef fun compile_extern_class(block, m, ccu, mmodule) do end
 
        redef fun get_ftype(block, m) do return new ForeignJavaType(block.code)
 
-       redef fun compile_to_files(nmodule, compdir)
+       redef fun compile_to_files(mmodule, compdir)
        do
                # Make sure we have a .java file
-               nmodule.ensure_java_files
+               mmodule.ensure_java_files
 
                # Needed compiler and linker options
-               nmodule.insert_compiler_options
+               mmodule.insert_compiler_options
 
                # Enable linking C callbacks to java native methods
-               nmodule.ensure_linking_callback_methods(ffi_ccu, nmodule.ffi_callbacks[self])
+               mmodule.ensure_linking_callback_methods(ffi_ccu.as(not null), mmodule.ffi_callbacks[self])
 
                # Java implementation code
-               var java_file = nmodule.java_file
+               var java_file = mmodule.java_file
                assert java_file != null
                var extern_java_file = java_file.write_to_files(compdir)
-               nmodule.ffi_files.add(extern_java_file)
+               mmodule.ffi_files.add(extern_java_file)
        end
 
-       var ffi_ccu: CCompilationUnit # HACK
+       var ffi_ccu: nullable CCompilationUnit = null # HACK
 
-       redef fun compile_callback(callback, nmodule, mainmodule, ccu)
+       redef fun compile_callback(callback, mmodule, mainmodule, ccu)
        do
                ffi_ccu = ccu
-               callback.compile_callback_to_java(nmodule, ccu)
+               callback.compile_callback_to_java(mmodule, mainmodule, ccu)
        end
 end
 
-redef class AModule
+redef class MModule
 
        # Pure java class source file
        private var java_file: nullable JavaClassTemplate = null
@@ -198,7 +197,7 @@ redef class AModule
                if java_file != null then return
 
                # Java implementation code
-               java_file = new JavaClassTemplate(mmodule.impl_java_class_name)
+               java_file = new JavaClassTemplate(impl_java_class_name)
        end
 
        # Compile C code to call JNI and link C callbacks implementations to Java extern methods
@@ -213,7 +212,7 @@ redef class AModule
 
                var jni_methods = new Array[String]
                for cb in callbacks do
-                       jni_methods.add_all(cb.jni_methods_declaration(mmodule.as(not null)))
+                       jni_methods.add_all(cb.jni_methods_declaration(self))
                end
 
                var cf = new CFunction("static void nit_ffi_with_java_register_natives(JNIEnv* env, jclass jclazz)")
@@ -237,12 +236,10 @@ redef class AModule
        # Tell the C compiler where to find jni.h and how to link with libjvm
        private fun insert_compiler_options
        do
-               mmodule.c_compiler_options = "{mmodule.c_compiler_options} -I $(JAVA_HOME)/include/"
-               mmodule.c_linker_options = "{mmodule.c_linker_options} -L $(JNI_LIB_PATH) -ljvm"
+               c_compiler_options = "{c_compiler_options} -I $(JAVA_HOME)/include/"
+               c_linker_options = "{c_linker_options} -L $(JNI_LIB_PATH) -ljvm"
        end
-end
 
-redef class MModule
        # Name of the generated Java class where to store all implementation methods of this module
        # as well as generated callbacks.
        private fun impl_java_class_name: String do return "Nit_{name}"
@@ -273,6 +270,12 @@ redef class AExternPropdef
                var modelbuilder = toolcontext.modelbuilder
                var mmodule = mpropdef.mclassdef.mmodule
 
+               # We use callbacks from the C FFI since they will be called from generated C
+               var c_language_visitor = toolcontext.ffi_language_assignation_phase.as(FFILanguageAssignationPhase).c_language
+               if not mmodule.ffi_callbacks.keys.has(c_language_visitor) then
+                       mmodule.ffi_callbacks[c_language_visitor] = new HashSet[NitniCallback]
+               end
+
                # Pointer::sys
                var pointer_class = modelbuilder.try_get_mclass_by_name(self, mmodule, "Pointer")
                assert pointer_class != null
@@ -281,7 +284,7 @@ redef class AExternPropdef
 
                var explicit_call = new MExplicitCall(pointer_class.mclass_type, pointer_sys_meth, mmodule)
                fcc.callbacks.add(explicit_call)
-               explicit_call.fill_type_for(fcc, mmodule)
+               mmodule.ffi_callbacks[c_language_visitor].add(explicit_call)
 
                # Sys::jni_env
                var sys_class = modelbuilder.try_get_mclass_by_name(self, mmodule, "Sys")
@@ -292,7 +295,7 @@ redef class AExternPropdef
 
                explicit_call = new MExplicitCall(sys_class.mclass_type, sys_jni_env_meth, mmodule)
                fcc.callbacks.add(explicit_call)
-               explicit_call.fill_type_for(fcc, mmodule)
+               mmodule.ffi_callbacks[c_language_visitor].add(explicit_call)
 
                # Sys::load_jclass
                var sys_jni_load_jclass_meth = modelbuilder.try_get_mproperty_by_name2(self, mmodule, sys_class.mclass_type, "load_jclass")
@@ -301,6 +304,7 @@ redef class AExternPropdef
 
                explicit_call = new MExplicitCall(sys_class.mclass_type, sys_jni_load_jclass_meth, mmodule)
                fcc.callbacks.add(explicit_call)
+               mmodule.ffi_callbacks[c_language_visitor].add(explicit_call)
                explicit_call.fill_type_for(fcc, mmodule)
        end
 end
@@ -384,33 +388,32 @@ end
 
 redef class NitniCallback
        # Compile C and Java code to implement this callback
-       fun compile_callback_to_java(nmodule: AModule, ccu: CCompilationUnit) do end
+       fun compile_callback_to_java(mmodule: MModule, mainmodule: MModule, ccu: CCompilationUnit) do end
 
        # Returns the list of C functions to link with extern Java methods, as required
        # to enable this callback from Java code.
        # 
-       # Return used by `AModule::ensure_linking_callback_methods`
+       # Return used by `MModule::ensure_linking_callback_methods`
        #
        # TODO we return an Array to support cast and other features like that
        fun jni_methods_declaration(from_module: MModule): Array[String] do return new Array[String]
 end
 
 redef class MExplicitCall
-       redef fun compile_callback_to_java(nmodule, ccu)
+       redef fun compile_callback_to_java(mmodule, mainmodule, ccu)
        do
                var mproperty = mproperty
                assert mproperty isa MMethod
-               var mmodule = nmodule.mmodule.as(not null)
 
                # In C, indirection implementing the Java extern methods
                var csignature = mproperty.build_c_implementation_signature(recv_mtype, mmodule, "___indirect", long_signature, from_java_call_context)
                var cf = new CFunction("JNIEXPORT {csignature}")
-               cf.exprs.add "\t{mproperty.build_ccall(recv_mtype, mmodule, null, long_signature, from_java_call_context, null)}\n"
+               cf.exprs.add "\t{mproperty.build_ccall(recv_mtype, mainmodule, null, long_signature, from_java_call_context, null)}\n"
                ccu.add_local_function cf
 
                # In Java, declare the extern method as a private static local method
-               var java_signature = mproperty.build_csignature(recv_mtype, mmodule, null, short_signature, java_call_context)
-               nmodule.java_file.class_content.add "private native static {java_signature};\n"
+               var java_signature = mproperty.build_csignature(recv_mtype, mainmodule, null, short_signature, java_call_context)
+               mmodule.java_file.class_content.add "private native static {java_signature};\n"
        end
 
        redef fun jni_methods_declaration(from_mmodule)
@@ -459,7 +462,8 @@ redef class MClassType
        redef fun java_type
        do
                var ftype = mclass.ftype
-               if ftype isa ForeignJavaType then return ftype.java_type
+               if ftype isa ForeignJavaType then return ftype.java_type.
+                       replace('/', ".").replace('$', ".").replace(' ', "")
                if mclass.name == "Bool" then return "boolean"
                if mclass.name == "Char" then return "char"
                if mclass.name == "Int" then return "int"
index 2583252..2ebf76d 100644 (file)
@@ -38,21 +38,22 @@ redef class MModule
                var v = compiler.new_visitor
                var n = nmodule(v)
                if n == null then return
-               n.finalize_ffi_wrapper(v.compiler.modelbuilder.compile_dir, v.compiler.mainmodule)
-               for file in n.ffi_files do v.compiler.extern_bodies.add(file)
+               n.ensure_compile_ffi_wrapper
+               finalize_ffi_wrapper(v.compiler.modelbuilder.compile_dir, v.compiler.mainmodule)
+               for file in ffi_files do v.compiler.extern_bodies.add(file)
 
                ensure_compile_nitni_base(v)
 
                nitni_ccu.header_c_types.add("#include \"{name}._ffi.h\"\n")
 
-               nitni_ccu.write_as_nitni(n, v.compiler.modelbuilder.compile_dir)
+               nitni_ccu.write_as_nitni(self, v.compiler.modelbuilder.compile_dir)
 
                for file in nitni_ccu.files do
                        v.compiler.extern_bodies.add(new ExternCFile(file, c_compiler_options))
                end
        end
 
-       fun ensure_compile_nitni_base(v: AbstractCompilerVisitor)
+       private fun ensure_compile_nitni_base(v: AbstractCompilerVisitor)
        do
                if nitni_ccu != null then return
 
@@ -68,10 +69,10 @@ redef class MModule
                return res
        end
 
-       var compiled_callbacks: Array[NitniCallback] = new Array[NitniCallback]
+       private var compiled_callbacks: Array[NitniCallback] = new Array[NitniCallback]
 
        # Returns true if callbacks has yet to be generated and register it as being generated
-       fun check_callback_compilation(cb: NitniCallback): Bool
+       private fun check_callback_compilation(cb: NitniCallback): Bool
        do
                var compiled = compiled_callbacks.has(cb)
                if not compiled then compiled_callbacks.add(cb)
@@ -79,8 +80,8 @@ redef class MModule
        end
 end
 
-redef class AExternPropdef
-       fun compile_ffi_support_to_c(v: AbstractCompilerVisitor)
+redef class AMethPropdef
+       private fun compile_ffi_support_to_c(v: AbstractCompilerVisitor)
        do
                var mmodule = mpropdef.mclassdef.mmodule
                var mainmodule = v.compiler.mainmodule
@@ -93,7 +94,10 @@ redef class AExternPropdef
                v.declare_once("{csignature};")
 
                # FFI part
-               compile_ffi_method(amodule)
+               amodule.ensure_compile_ffi_wrapper
+               compile_ffi_method(mmodule)
+
+               assert self isa AExternPropdef
 
                # nitni - Compile missing callbacks
                mmodule.ensure_compile_nitni_base(v)
@@ -124,13 +128,10 @@ redef class AExternPropdef
                # manage nitni callback set
                mmodule.foreign_callbacks.join(foreign_callbacks)
        end
-end
 
-redef class AExternMethPropdef
-       redef fun compile_to_c(v, mpropdef, arguments)
+       redef fun compile_externmeth_to_c(v, mpropdef, arguments)
        do
                var mmodule = mpropdef.mclassdef.mmodule
-               var amodule = v.compiler.modelbuilder.mmodule2nmodule[mmodule]
 
                # if using the old native interface fallback on previous implementation
                var nextern = self.n_extern
@@ -139,7 +140,7 @@ redef class AExternMethPropdef
                        return
                end
 
-               amodule.mmodule.uses_ffi = true
+               mmodule.uses_ffi = true
 
                var mclass_type = mpropdef.mclassdef.bound_mtype
 
@@ -190,13 +191,10 @@ redef class AExternMethPropdef
 
                compile_ffi_support_to_c(v)
        end
-end
 
-redef class AExternInitPropdef
-       redef fun compile_to_c(v, mpropdef, arguments)
+       redef fun compile_externinit_to_c(v, mpropdef, arguments)
        do
                var mmodule = mpropdef.mclassdef.mmodule
-               var amodule = v.compiler.modelbuilder.mmodule2nmodule[mmodule]
 
                # if using the old native interface fallback on previous implementation
                var nextern = self.n_extern
@@ -205,7 +203,7 @@ redef class AExternInitPropdef
                        return
                end
 
-               amodule.mmodule.uses_ffi = true
+               mmodule.uses_ffi = true
 
                var mclass_type = mpropdef.mclassdef.bound_mtype
 
@@ -248,16 +246,16 @@ redef class AExternInitPropdef
 end
 
 redef class CCompilationUnit
-       fun write_as_nitni(amodule: AModule, compdir: String)
+       fun write_as_nitni(mmodule: MModule, compdir: String)
        do
-               var base_name = "{amodule.mmodule.name}._nitni"
+               var base_name = "{mmodule.name}._nitni"
 
                var h_file = "{base_name}.h"
-               write_header_to_file( amodule, "{compdir}/{h_file}", new Array[String],
-                       "{amodule.cname.to_s.to_upper}_NITG_NITNI_H")
+               write_header_to_file( mmodule, "{compdir}/{h_file}", new Array[String],
+                       "{mmodule.cname.to_s.to_upper}_NITG_NITNI_H")
 
                var c_file = "{base_name}.c"
-               write_body_to_file( amodule, "{compdir}/{c_file}", ["\"{h_file}\""] )
+               write_body_to_file( mmodule, "{compdir}/{c_file}", ["\"{h_file}\""] )
 
                files.add( "{compdir}/{c_file}" )
        end
@@ -289,7 +287,7 @@ redef class AbstractCompilerVisitor
 end
 
 redef class MType
-       fun compile_extern_type(v: AbstractCompilerVisitor, ccu: CCompilationUnit)
+       private fun compile_extern_type(v: AbstractCompilerVisitor, ccu: CCompilationUnit)
        do
                assert not is_cprimitive
 
@@ -300,7 +298,7 @@ redef class MType
                ccu.header_c_types.add("#endif\n")
        end
 
-       fun compile_extern_helper_functions(v: AbstractCompilerVisitor, ccu: CCompilationUnit)
+       private fun compile_extern_helper_functions(v: AbstractCompilerVisitor, ccu: CCompilationUnit)
        do
                # actually, we do not need to do anything when using the bohem garbage collector
 
@@ -351,7 +349,7 @@ redef class MNullableType
 end
 
 redef class MExplicitCall
-       fun compile_extern_callback(v: AbstractCompilerVisitor, ccu: CCompilationUnit)
+       private fun compile_extern_callback(v: AbstractCompilerVisitor, ccu: CCompilationUnit)
        do
                var mproperty = mproperty
                assert mproperty isa MMethod
@@ -412,7 +410,7 @@ redef class MExplicitCall
 end
 
 redef class MExplicitSuper
-       fun compile_extern_callback(v: AbstractCompilerVisitor, ccu: CCompilationUnit)
+       private fun compile_extern_callback(v: AbstractCompilerVisitor, ccu: CCompilationUnit)
        do
                var mproperty = from.mproperty
                assert mproperty isa MMethod
@@ -462,7 +460,7 @@ redef class MExplicitSuper
 end
 
 redef class MExplicitCast
-       fun compile_extern_callbacks(v: AbstractCompilerVisitor, ccu: CCompilationUnit)
+       private fun compile_extern_callbacks(v: AbstractCompilerVisitor, ccu: CCompilationUnit)
        do
                var from = from
                var to = to
index 3fca8d5..c1ca4fb 100644 (file)
@@ -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)
@@ -278,7 +339,7 @@ class Debugger
                if self.modelbuilder.mpropdef2npropdef.has_key(mpropdef) then
                        var npropdef = self.modelbuilder.mpropdef2npropdef[mpropdef]
                        self.parameter_check(npropdef, mpropdef, args)
-                       if npropdef isa AConcreteMethPropdef then
+                       if npropdef isa AMethPropdef then
                                return npropdef.rt_call(self, mpropdef, args)
                        else
                                print "Error, invalid propdef to call at runtime !"
@@ -1364,7 +1425,7 @@ class Debugger
 
 end
 
-redef class AConcreteMethPropdef
+redef class AMethPropdef
 
        # Same as call except it will copy local variables of the parent frame to the frame defined in this call.
        # Not supposed to be used by anyone else than the Debugger.
diff --git a/src/debugger_commons.nit b/src/debugger_commons.nit
deleted file mode 100644 (file)
index dcfebbd..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Copyright 2013 Lucas Bajolet <lucas.bajolet@hotmail.com>
-#
-# 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]... <file.nit>...\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/doc_template.nit b/src/doc_template.nit
new file mode 100644 (file)
index 0000000..5084b01
--- /dev/null
@@ -0,0 +1,724 @@
+# 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.
+
+# HTML templates used by Nitdoc to generate API documentation
+# Pages are assembled using `Template`
+module doc_template
+
+import template
+
+# Full Nitdoc page template
+class TplNitdocPage
+       super Template
+
+       var head: TplHead writable
+       var body_attrs = new Array[TagAttribute] # attributes for body tag element
+       var topmenu: TplTopMenu writable
+       var sidebar: nullable TplSidebar writable
+       var content: Streamable writable
+       var footer: nullable TplFooter writable
+       var scripts = new Array[TplScript] # js scripts appended to body
+       init do end
+
+       redef fun rendering do
+               add "<!DOCTYPE html>"
+               add "<head>"
+               add head
+               add "</head>"
+               add "<body"
+               for attr in body_attrs do add attr
+               add ">"
+               add topmenu
+               if footer != null then
+                       add "<div class='page footed'>"
+               else
+                       add "<div class='page'>"
+               end
+               if sidebar != null then
+                       add sidebar.as(not null)
+               end
+               add content
+               add "</div>"
+               if footer != null then
+                       add footer.as(not null)
+               end
+               for script in scripts do
+                       add script
+               end
+               add "</body>"
+               add "</html>"
+       end
+end
+
+# general layout elements
+
+# <head> tag
+class TplHead
+       super Template
+
+       var title: String
+       var shareurl: String
+
+       init(title, shareurl: String) do
+               self.title = title
+               self.shareurl = shareurl
+       end
+
+       redef fun rendering do
+               add """
+<meta charset="utf-8"/>
+<link rel="stylesheet" href="{{{shareurl}}}/css/main.css" type="text/css"/>
+<link rel="stylesheet" href="{{{shareurl}}}/css/Nitdoc.UI.css" type="text/css"/>
+<link rel="stylesheet" href="{{{shareurl}}}/css/Nitdoc.QuickSearch.css" type="text/css"/>
+<link rel="stylesheet" href="{{{shareurl}}}/css/Nitdoc.GitHub.css" type="text/css"/>
+<link rel="stylesheet" href="{{{shareurl}}}/css/Nitdoc.ModalBox.css" type="text/css"/>
+<title>{{{title}}}</title>"""
+       end
+end
+
+# Top bar menu
+class TplTopMenu
+       super Template
+
+       private var elts = new Array[Streamable]
+
+       redef fun rendering do
+               add "<header>"
+               add "<nav class='main'>"
+               if not elts.is_empty then
+                       add "<ul>"
+                       for elt in elts do add(elt)
+                       add "</ul>"
+               end
+               add "</nav>"
+               add "</header>"
+       end
+
+       fun add_elt(href, name: String, is_active: Bool) do
+               elts.add(new TplTopMenuElt(href, name, is_active))
+       end
+
+       fun add_raw(content: Streamable) do
+               elts.add(content)
+       end
+end
+
+# A topmenu element
+private class TplTopMenuElt
+       super Template
+
+       var href: String
+       var name: String
+       var is_active: Bool
+
+       init(href, name: String, is_active: Bool) do
+               self.href = href
+               self.name = name
+               self.is_active = is_active
+       end
+
+       redef fun rendering do
+               if is_active then
+                       add """<li class="current">{{{name}}}</li>"""
+               else
+                       add """<li><a href="{{{href}}}">{{{name}}}</a></li>"""
+               end
+       end
+end
+
+# <footer> element
+class TplFooter
+       super Template
+
+       var content: Streamable writable
+
+       init(content: Streamable) do self.content = content
+
+       redef fun rendering do
+               add "<footer>"
+               add content
+               add "</footer>"
+       end
+end
+
+# sidebar layout
+
+# Sidebar <div>
+class TplSidebar
+       super Template
+
+       var boxes = new Array[TplSidebarBox]
+
+       redef fun rendering do
+               add """"<div class="sidebar">"""
+               for box in boxes do add box
+               add "</div>"
+       end
+end
+
+# A box that can be added to sidebar
+class TplSidebarBox
+       super Template
+
+       var name: String
+       var elts = new Array[TplSidebarGroup]
+
+       init(name: String) do self.name = name
+
+       redef fun rendering do
+               add """<nav class"properties filterable">"""
+               add """    <h3>{{{name}}}</h3>"""
+               for elt in elts do add elt
+               add "</nav>"
+       end
+end
+
+# A sidebar box group
+class TplSidebarGroup
+       super Template
+
+       var name: String
+       private var elts = new Array[Template]
+
+       init(name: String) do self.name = name
+
+       redef fun rendering do
+               if elts.is_empty then return
+               add "<h4>{name}</h4>"
+               add "<ul>"
+               for elt in elts do add elt
+               add "</ul>"
+       end
+
+       fun add_elt(content: Streamable, classes: Array[Streamable]) do
+               var tpl = new Template
+               tpl.add "<li {classes.join(" ")}>"
+               tpl.add content
+               tpl.add "</li>"
+               elts.add(tpl)
+       end
+
+       fun add_bullet(text, title, content: Streamable, classes: Array[Streamable]) do
+               var tpl = new Template
+               tpl.add "<span title='{title}'>{text}</span>"
+               tpl.add content
+               add_elt(tpl, classes)
+       end
+end
+
+# page layouts
+
+# Layout for Overview page
+class TplOverviewPage
+       super Template
+
+       var title: nullable Streamable writable
+       var text: nullable Streamable writable
+       var graph: nullable TplGraph writable
+       var modules = new Array[Streamable]
+       init do end
+
+       redef fun rendering do
+               add "<div class='content fullpage'>"
+               if title != null then add "<h1>{title}</h1>"
+               if text != null then add "<article class='overview'>{text}</article>"
+
+               if not modules.is_empty then
+                       add "<article class='overview'>"
+                       add "<h2>Modules</h2>"
+                       add "<ul>"
+                       for m in modules do
+                               add "<li>"
+                               add m
+                               add "</li>"
+                       end
+                       add "</ul>"
+               end
+               if not graph == null then add graph.as(not null)
+               add "</article>"
+               add "</div>"
+       end
+end
+
+# Layout for Search page
+class TplSearchPage
+       super Template
+
+       var title: nullable Streamable writable
+       var modules = new Array[Streamable]
+       var classes = new Array[Streamable]
+       var props = new Array[Streamable]
+       init do end
+
+       redef fun rendering do
+               add "<div class='content fullpage'>"
+               if title != null then add "<h1>{title}</h1>"
+               if not modules.is_empty then
+                       add "<article class='modules filterable'>"
+                       add "<h2>Modules</h2>"
+                       add "<ul>"
+                       for m in modules do
+                               add "<li>"
+                               add m
+                               add "</li>"
+                       end
+                       add "</ul>"
+                       add "</article>"
+               end
+               if not classes.is_empty then
+                       add "<article class='classes filterable'>"
+                       add "<h2>Classes</h2>"
+                       add "<ul>"
+                       for c in classes do
+                               add "<li>"
+                               add c
+                               add "</li>"
+                       end
+                       add "</ul>"
+                       add "</article>"
+               end
+               if not props.is_empty then
+                       add "<article class='properties filterable'>"
+                       add "<h2>Properties</h2>"
+                       add "<ul>"
+                       for p in props do
+                               add "<li>"
+                               add p
+                               add "</li>"
+                       end
+                       add "</ul>"
+                       add "</article>"
+               end
+               add "</div>"
+       end
+end
+
+# Layout for Module page
+class TplModulePage
+       super Template
+
+       var title: nullable Streamable writable
+       var subtitle: nullable Streamable writable
+       var definition: nullable TplDefinition writable
+       var graph: nullable TplGraph writable
+       var intros = new Array[TplArticle]
+       var redefs = new Array[TplArticle]
+       init do end
+
+       redef fun rendering do
+               add "<div class='content'>"
+               if title != null then
+                       add "<h1>"
+                       add title.as(not null)
+                       add "</h1>"
+               end
+               if subtitle != null then
+                       add "<div class='subtitle info'>"
+                       add subtitle.as(not null)
+                       add "</div>"
+               end
+               if definition != null then add definition.as(not null)
+               if graph != null then add graph.as(not null)
+               if not intros.is_empty then
+                       add "<section class='classes'>"
+                       add "<h2 class='section-header'>Introduced classes</h2>"
+                       for intro in intros do add intro
+                       add "</section>"
+               end
+               if not redefs.is_empty then
+                       add "<section class='classes'>"
+                       add "<h2 class='section-header'>Refined classes</h2>"
+                       for rdef in redefs do add rdef
+                       add "</section>"
+               end
+               add "</div>"
+       end
+end
+
+# Layout for Class page
+class TplClassPage
+       super Template
+
+       var title: nullable Streamable writable
+       var subtitle: nullable Streamable writable
+       var definition: nullable TplDefinition writable
+       var graph: nullable TplGraph writable
+       var concerns: nullable TplConcernList writable
+       var types = new Array[TplArticle]
+       var inits = new Array[TplArticle]
+       var methods = new Array[Streamable]
+
+       init do end
+
+       redef fun rendering do
+               add "<div class='content'>"
+               if title != null then
+                       add "<h1>"
+                       add title.as(not null)
+                       add "</h1>"
+               end
+               if subtitle != null then
+                       add "<div class='subtitle info'>"
+                       add subtitle.as(not null)
+                       add "</div>"
+               end
+               if definition != null then add definition.as(not null)
+               if graph != null then add graph.as(not null)
+
+               if concerns != null then
+                       add "<section class='concerns'>"
+                       add "<h2 class='section-header'>Concerns</h2>"
+                       add concerns.as(not null)
+                       add "</section>"
+               end
+               if not types.is_empty then
+                       add "<section class='types'>"
+                       add"<h2>Virtual Types</h2>"
+                       for t in types do add t
+                       add "</section>"
+               end
+               if not inits.is_empty then
+                       add "<section class='constructors'>"
+                       add"<h2>Constructors</h2>"
+                       for i in inits do add i
+                       add "</section>"
+               end
+               if not methods.is_empty then
+                       add "<section class='methods'>"
+                       add"<h2>Methods</h2>"
+                       for m in methods do add m
+                       add "</section>"
+               end
+               add "</div>"
+       end
+end
+
+# layout parts
+
+# A HTML tag attribute
+#  `<tag attr="value">`
+class TagAttribute
+       super Template
+
+       var name: String
+       var value: nullable String
+
+       init(name: String, value: nullable String) do
+               self.name = name
+               self.value = value
+       end
+
+       redef fun rendering do
+               if value == null then
+                       add(" {name}")
+               else
+                       add(" {name}=\"{value}\"")
+               end
+       end
+end
+
+# JS Script template
+class TplScript
+       super Template
+
+       var attrs = new Array[TagAttribute]
+       var content: nullable Streamable writable
+
+       init do
+               attrs.add(new TagAttribute("type", "text/javascript"))
+       end
+
+       redef fun rendering do
+               add "<script"
+               for attr in attrs do add attr
+               add ">"
+               if content != null then add content.as(not null)
+               add "</script>"
+       end
+end
+
+# JS script for Piwik Tracker
+class TplPiwikScript
+       super TplScript
+
+       var tracker_url: String
+       var site_id: String
+
+       init(tracker_url, site_id: String) do
+               super
+               self.tracker_url = tracker_url
+               self.site_id = site_id
+       end
+
+       redef fun rendering do
+               var tpl = new Template
+               tpl.add "<!-- Piwik -->"
+               tpl.add "var _paq = _paq || [];"
+               tpl.add " _paq.push([\"trackPageView\"]);"
+               tpl.add " _paq.push([\"enableLinkTracking\"]);"
+               tpl.add "(function() \{"
+               tpl.add " var u=((\"https:\" == document.location.protocol) ? \"https\" : \"http\") + \"://{tracker_url}\";"
+               tpl.add " _paq.push([\"setTrackerUrl\", u+\"piwik.php\"]);"
+               tpl.add " _paq.push([\"setSiteId\", \"{site_id}\"]);"
+               tpl.add " var d=document, g=d.createElement(\"script\"), s=d.getElementsByTagName(\"script\")[0]; g.type=\"text/javascript\";"
+               tpl.add " g.defer=true; g.async=true; g.src=u+\"piwik.js\"; s.parentNode.insertBefore(g,s);"
+               tpl.add "\})();"
+               content = tpl
+               super
+       end
+end
+
+# Graph image with clicable map
+class TplGraph
+       super Template
+
+       var name: String
+       var alt: String
+       var map: String
+
+       init(name, alt, map: String) do
+               self.name = name
+               self.alt = alt
+               self.map = map
+       end
+
+       redef fun rendering do
+               add "<article class='graph'>"
+               add "<img src='{name}.png' usemap='#{name}' style='margin:auto' alt='{alt}'/>"
+               add "</article>"
+               add map
+       end
+end
+
+# A page article (used for module, class, prop description)
+class TplArticle
+       super Template
+
+       var id: String writable
+       var classes = new HashSet[String]
+       var title: Template writable
+       var subtitle: Template writable
+       var content: nullable Template writable
+
+       init do end
+
+       redef fun rendering do
+               add "<article class='{classes.join(" ")}' id='{id}'>"
+               add "<h3 class='signature'>"
+               add title
+               add "</h3>"
+               add "<div class='info'>"
+               add subtitle
+               add "</div>"
+               if content != null then
+                       add content.as(not null)
+               end
+               add "</article>"
+       end
+end
+
+# A module / class / prop definition
+# Contains:
+# * namespace of the definition
+# * comment
+# * link to location
+class TplDefinition
+       super Template
+
+       var comment: nullable TplComment writable
+       var namespace: Streamable writable
+       var location: nullable Streamable writable
+       var github_area: nullable TplGithubArea writable
+
+       init do end
+
+       redef fun rendering do
+               add "<div class='description'>"
+               if github_area != null then
+                       add github_area.as(not null)
+               end
+               if comment == null then
+                       add "<p class='info inheritance'>"
+                       add "<span class=\"noComment\">no comment for </span>"
+               else
+                       add comment.as(not null)
+                       add "<p class='info inheritance'>"
+               end
+               add "definition in "
+               add namespace
+               if location != null then
+                       add " "
+                       add location.as(not null)
+               end
+               add "</p>"
+               add "</div>"
+       end
+end
+
+# Textarea used by Github comment edition plugin to store comments
+class TplGithubArea
+       super Template
+
+       var raw_comment: String writable
+       var raw_namespace: String writable
+       var location: String writable
+
+       init(raw_comment, raw_namespace, location: String) do
+               self.raw_comment = raw_comment
+               self.raw_namespace = raw_namespace
+               self.location = location
+       end
+
+       redef fun rendering do
+               add "<textarea"
+               add " class='baseComment'"
+               add " data-comment-namespace='{raw_namespace}'"
+               add " data-comment-location='{location}'>"
+               add raw_comment
+               add "</textarea>"
+       end
+end
+
+# Comment box
+class TplComment
+       super Template
+
+       var comment: Streamable writable
+
+       init(comment: Streamable) do self.comment = comment
+
+       redef fun rendering do
+               add "<div class='comment'>"
+               add comment
+               add "</div>"
+       end
+end
+
+# Comment box (for synopsys)
+class TplShortComment
+       super TplComment
+
+       redef fun rendering do
+               add "<div class='comment'>"
+               add "<div class='nitdoc'>"
+               add comment
+               add "</div>"
+               add "</div>"
+       end
+end
+
+# A html link (with optional title)
+class TplLink
+       super Template
+
+       var href: String writable
+       var text: String writable
+       var title: nullable String writable
+
+       init do end
+
+       redef fun rendering do
+               add "<a href=\""
+               add href
+               add "\""
+               if title != null then
+                       add " title=\""
+                       add title.as(not null)
+                       add "\""
+               end
+               add ">"
+               add text
+               add "</a>"
+       end
+end
+
+# Element to display in concerns list
+class TplConcernElt
+       super Template
+end
+
+# List of concerns
+class TplConcernList
+       super TplConcernElt
+
+       var elts = new Array[TplConcernElt]
+
+       redef fun rendering do
+               if elts.is_empty then return
+               add "<ul>"
+               for elt in elts do
+                       add elt
+               end
+               add "</ul>"
+       end
+end
+
+# Element of a list of concerns
+class TplConcernListElt
+       super TplConcernElt
+
+       var anchor: String writable
+       var name: String writable
+       var comment: nullable String writable
+
+       init do end
+
+       redef fun rendering do
+               add "<li>"
+               add "<a href=\"{anchor}\">{name}</a>"
+               if comment != null then
+                       add ": {comment.as(not null)}"
+               end
+               add "</li>"
+       end
+end
+
+# Section for topconcern
+class TplTopConcern
+       super Template
+
+       var anchor: String writable
+       var concern: TplLink writable
+
+       init do end
+
+       redef fun rendering do
+               add "<a id=\"{anchor}\"></a>"
+               add "<h3 class=\"concern-toplevel\">Methods refined in "
+               add concern
+               add "</h3>"
+       end
+end
+
+# Section for subconcern
+class TplConcern
+       super Template
+
+       var anchor: String writable
+       var concern: TplLink writable
+       var comment: nullable String writable
+
+       init do end
+
+       redef fun rendering do
+               add "<a id=\"{anchor}\"></a>"
+               add "<p class=\"concern-doc\">"
+               add concern
+               if comment != null then
+                       add ": "
+                       add comment.as(not null)
+               end
+               add "</p>"
+       end
+end
diff --git a/src/layout_builders.nit b/src/layout_builders.nit
deleted file mode 100644 (file)
index f7dc388..0000000
+++ /dev/null
@@ -1,751 +0,0 @@
-# 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.
-
-# Table layout builders
-# Tables are used to implement objects mecanisms like:
-#  * message sending
-#  * attribute accessing
-#  * typing
-#  * resolution (for generic types)
-# This module provides various layout for object tables:
-#  * coloring
-#  * binary matrix
-#  * perfect hashing (and & mod operators)
-module layout_builders
-
-import abstract_compiler
-
-# Layouts
-
-# A layout is the result of computation by builders
-# it contains necessary informations for basic table creation
-class Layout[E: Object]
-       # Ids or each element
-       var ids: Map[E, Int] = new HashMap[E, Int]
-       # Fixed positions of each element in all tables
-       var pos: Map[E, Int] = new HashMap[E, Int]
-end
-
-# A PHLayout is used everywere the builder used perfect hashing
-# it adds masks and hashes informations to std layout
-class PHLayout[HOLDER: Object, E: Object]
-       super Layout[E]
-       # Masks used by hash function
-       var masks: Map[HOLDER, Int] = new HashMap[HOLDER, Int]
-       # Positions of each element for each tables
-       var hashes: Map[HOLDER, Map[E, Int]] = new HashMap[HOLDER, Map[E, Int]]
-end
-
-# Builders
-
-# TypingLayoutBuilder is used to build a layout for typing tables (by type or by class)
-interface TypingLayoutBuilder[E: Object]
-       # Build typing table layout
-       # elements: the set of elements (classes or types) used in typing tables
-       fun build_layout(elements: Set[E]): Layout[E] is abstract
-       # Get the poset used for table layout construction
-       # REQUIRE: build_layout
-       fun poset: nullable POSet[E] is abstract
-end
-
-# Layout builder dedicated to vft, attribute & VT tables
-interface PropertyLayoutBuilder[E: PropertyLayoutElement]
-       # Build table layout for attributes, methods and virtual types
-       # elements: the associative map between classes and properties to use in table layout
-       fun build_layout(elements: Map[MClass, Set[E]]): Layout[E] is abstract
-end
-
-# Used to create a common ancestors to MProperty and MPropDef
-# Required for polymorphic calls
-# FIXME: there should be a better way
-interface PropertyLayoutElement end
-
-redef class MProperty
-       super PropertyLayoutElement
-end
-
-redef class MPropDef
-       super PropertyLayoutElement
-end
-
-# For resolution tables (generics)
-interface ResolutionLayoutBuilder
-       # Build resolution table layout
-       # elements: association between classes and resolved types
-       fun build_layout(elements: Map[MClassType, Set[MType]]): Layout[MType] is abstract
-end
-
-# POSet builders
-
-# A POSet builder build a poset for a set of MType or MClass
-# the resulting poset is used by the layout builders
-private abstract class POSetBuilder[E: Object]
-       private var mmodule: MModule
-       init(mmodule: MModule) do self.mmodule = mmodule
-       # Build the poset from `elements`
-       private fun build_poset(elements: Set[E]): POSet[E] is abstract
-end
-
-# A TypingLayoutBuilder used for MType based typing
-# such as in separate compilers
-private class MTypePOSetBuilder
-       super POSetBuilder[MType]
-       redef fun build_poset(elements) do
-               var poset = new POSet[MType]
-               for e in elements do
-                       poset.add_node(e)
-                       for o in elements do
-                               if e == o then continue
-                               if e.is_subtype(mmodule, null, o) then
-                                       poset.add_edge(e, o)
-                               end
-                       end
-               end
-               return poset
-       end
-end
-
-# A TypingLayoutBuilder used for MClass based typing
-# such as in erased compilers or used in property coloring
-private class MClassPOSetBuilder
-       super POSetBuilder[MClass]
-       redef fun build_poset(elements) do return mmodule.flatten_mclass_hierarchy
-end
-
-# Matrice computers
-
-# Abstract layout builder for resolution tables using Binary Matrix (BM)
-abstract class TypingBMizer[E: Object]
-       super TypingLayoutBuilder[E]
-
-       private var mmodule: MModule
-       private var poset_builder: POSetBuilder[E]
-       private var poset_cache: nullable POSet[E]
-
-       private init(mmodule: MModule, poset_builder: POSetBuilder[E]) do
-               self.mmodule = mmodule
-               self.poset_builder = poset_builder
-       end
-
-       redef fun poset do return poset_cache
-
-       # Compute mtypes ids and position using BM
-       redef fun build_layout(elements: Set[E]): Layout[E] do
-               var result = new Layout[E]
-               var ids = new HashMap[E, Int]
-               poset_cache = poset_builder.build_poset(elements)
-               var lin = poset.to_a
-               poset.sort(lin)
-               for element in lin do
-                       ids[element] = ids.length
-               end
-               result.ids = ids
-               result.pos = ids
-               return result
-       end
-end
-
-# Layout builder for typing tables based on classes using Binary Matrix (BM)
-class MTypeBMizer
-       super TypingBMizer[MType]
-       init(mmodule: MModule) do super(mmodule, new MTypePOSetBuilder(mmodule))
-end
-
-# Layout builder for typing tables based on types using Binary Matrix (BM)
-class MClassBMizer
-       super TypingBMizer[MClass]
-       init(mmodule: MModule) do super(mmodule, new MClassPOSetBuilder(mmodule))
-end
-
-# Layout builder for resolution tables using Binary Matrix (BM)
-class ResolutionBMizer
-       super ResolutionLayoutBuilder
-
-       init do end
-
-       redef fun build_layout(elements) do
-               var result = new Layout[MType]
-               var ids = new HashMap[MType, Int]
-               var color = 0
-               for mclasstype, mclasstypes in elements do
-                       for element in mclasstypes do
-                               if ids.has_key(element) then continue
-                               ids[element] = color
-                               color += 1
-                       end
-               end
-               result.ids = ids
-               result.pos = ids
-               return result
-       end
-end
-
-# Abstract Layout builder for mproperties using Binary Matrix (BM)
-class MPropertyBMizer[E: PropertyLayoutElement]
-       super PropertyLayoutBuilder[E]
-
-       var mmodule: MModule
-
-       init(mmodule: MModule) do self.mmodule = mmodule
-
-       redef fun build_layout(elements) do
-               var result = new Layout[E]
-               var ids = new HashMap[E, Int]
-               var lin = new Array[MClass]
-               lin.add_all(elements.keys)
-               self.mmodule.linearize_mclasses(lin)
-               for mclass in lin do
-                       for mproperty in elements[mclass] do
-                               if ids.has_key(mproperty) then continue
-                               ids[mproperty] = ids.length
-                       end
-               end
-               result.pos = ids
-               return result
-       end
-end
-
-# Colorers
-
-# Abstract Layout builder for typing table using coloration (CL)
-abstract class TypingColorer[E: Object]
-       super TypingLayoutBuilder[E]
-
-       private var core: Set[E] = new HashSet[E]
-       private var crown: Set[E] = new HashSet[E]
-       private var border: Set[E] = new HashSet[E]
-       private var coloration_result: Map[E, Int] = new HashMap[E, Int]
-
-       private var mmodule: MModule
-       private var poset_builder: POSetBuilder[E]
-       private var poset_cache: nullable POSet[E]
-
-       private init(mmodule: MModule, poset_builder: POSetBuilder[E]) do
-               self.mmodule = mmodule
-               self.poset_builder = poset_builder
-       end
-
-       redef fun poset do return poset_cache
-
-       # Compute the layout with coloring
-       redef fun build_layout(elements: Set[E]): Layout[E] do
-               poset_cache = poset_builder.build_poset(elements)
-               var result = new Layout[E]
-               result.ids = compute_ids(elements)
-               result.pos = colorize(elements)
-               return result
-       end
-
-       private fun compute_ids(elements: Set[E]): Map[E, Int] do
-               var ids = new HashMap[E, Int]
-               for element in reverse_linearize(elements) do
-                       ids[element] = ids.length
-               end
-               return ids
-       end
-
-       private fun colorize(elements: Set[E]): Map[E, Int] do
-               tag_elements(elements)
-               build_conflicts_graph
-               colorize_elements(core)
-               colorize_elements(border)
-               colorize_elements(crown)
-               return coloration_result
-       end
-
-       # Colorize a collection of elements
-       private fun colorize_elements(elements: Set[E]) do
-               var min_color = 0
-
-               var lin = reverse_linearize(elements)
-               for element in lin do
-                       var color = min_color
-                       while not self.is_color_free(element, elements, color) do
-                               color += 1
-                       end
-                       coloration_result[element] = color
-                       color = min_color
-               end
-       end
-
-       # Check if a related element to the element already use the color
-       private fun is_color_free(element: E, elements: Set[E], color: Int): Bool do
-               if conflicts_graph.has_key(element) then
-                       for st in conflicts_graph[element] do
-                               if coloration_result.has_key(st) and coloration_result[st] == color then return false
-                       end
-               end
-               for st in self.poset[element].greaters do
-                       if st == element then continue
-                       if coloration_result.has_key(st) and coloration_result[st] == color then return false
-               end
-               return true
-       end
-
-       # Tag elements as core, crown or border
-       private fun tag_elements(elements: Set[E]) do
-               for element in elements do
-                       # Check if sub elements are all in single inheritance
-                       var all_subelements_si = true
-                       for subelem in self.poset[element].smallers do
-                               if self.poset[subelem].direct_greaters.length > 1 then
-                                       all_subelements_si = false
-                                       break
-                               end
-                       end
-
-                       # Tag as core, crown or border
-                       if self.poset[element].direct_greaters.length > 1 then
-                               core.add_all(self.poset[element].greaters)
-                               if all_subelements_si then
-                                       border.add(element)
-                               end
-                       else if not all_subelements_si then
-                               core.add_all(self.poset[element].greaters)
-                       else
-                               crown.add(element)
-                       end
-               end
-       end
-
-       # Conflicts graph of elements hierarchy (two types are in conflict if they have common subelements)
-       private fun build_conflicts_graph do
-               self.conflicts_graph = new HashMap[E, HashSet[E]]
-               var core = reverse_linearize(self.core)
-               for t in core do
-                       for i in self.linear_extension(t) do
-                               if t == i then continue
-
-                               var lin_i = self.linear_extension(i)
-
-                               for j in self.linear_extension(t) do
-                                       if i == j or j == t then continue
-                                       var lin_j = self.linear_extension(j)
-
-                                       var d_ij = lin_i - lin_j
-                                       var d_ji = lin_j - lin_i
-
-                                       for ed1 in d_ij do
-                                               if not conflicts_graph.has_key(ed1) then conflicts_graph[ed1] = new HashSet[E]
-                                               # add ed1 x ed2 to conflicts graph
-                                               for ed2 in d_ji do conflicts_graph[ed1].add(ed2)
-                                       end
-                                       for ed1 in d_ij do
-                                               if not conflicts_graph.has_key(ed1) then conflicts_graph[ed1] = new HashSet[E]
-                                               # add ed1 x ed2 to conflicts graph
-                                               for ed2 in d_ji do conflicts_graph[ed1].add(ed2)
-                                       end
-                               end
-                       end
-               end
-       end
-
-       private var conflicts_graph: nullable HashMap[E, Set[E]]
-
-       # cache for linear_extensions
-       private var linear_extensions_cache: Map[E, Array[E]] = new HashMap[E, Array[E]]
-
-       # Return a linear_extension of super_elements of the element
-       private fun linear_extension(element: E): Array[E] do
-               if not self.linear_extensions_cache.has_key(element) then
-                       var supers = new HashSet[E]
-                       supers.add_all(self.poset[element].greaters)
-                       self.linear_extensions_cache[element] = self.linearize(supers)
-               end
-               return self.linear_extensions_cache[element]
-       end
-
-       private fun reverse_linearize(elements: Set[E]): Array[E] do
-               var lin = new Array[E]
-               lin.add_all(elements)
-               poset.sort(lin)
-               return lin
-       end
-       private fun linearize(elements: Set[E]): Array[E] do return reverse_linearize(elements).reversed
-end
-
-# Layout builder for typing tables based on types using coloration (CL)
-class MTypeColorer
-       super TypingColorer[MType]
-       init(mmodule: MModule) do super(mmodule, new MTypePOSetBuilder(mmodule))
-end
-
-# Layout builder for typing tables based on classes using coloration (CL)
-class MClassColorer
-       super TypingColorer[MClass]
-       init(mmodule: MModule) do super(mmodule, new MClassPOSetBuilder(mmodule))
-end
-
-# Abstract Layout builder for properties tables using coloration (CL)
-class MPropertyColorer[E: PropertyLayoutElement]
-       super PropertyLayoutBuilder[E]
-
-       private var mmodule: MModule
-       private var class_colorer: MClassColorer
-       private var coloration_result: Map[E, Int] = new HashMap[E, Int]
-
-       init(mmodule: MModule, class_colorer: MClassColorer) do
-               self.mmodule = mmodule
-               self.class_colorer = class_colorer
-       end
-
-       # Compute mclasses ids and position using BM
-       redef fun build_layout(elements: Map[MClass, Set[E]]): Layout[E] do
-               var result = new Layout[E]
-               result.pos = self.colorize(elements)
-               return result
-       end
-
-       private fun colorize(elements: Map[MClass, Set[E]]): Map[E, Int] do
-               self.colorize_core(elements)
-               self.colorize_crown(elements)
-               return self.coloration_result
-       end
-
-       # Colorize properties of the core hierarchy
-       private fun colorize_core(elements: Map[MClass, Set[E]]) do
-               var min_color = 0
-               for mclass in self.class_colorer.core do
-                       var color = min_color
-                       # check last color used by parents
-                       color = max_color(color, mclass.in_hierarchy(mmodule).direct_greaters, elements)
-                       # check max color used in conflicts
-                       if self.class_colorer.conflicts_graph.has_key(mclass) then
-                               color = max_color(color, self.class_colorer.conflicts_graph[mclass], elements)
-                       end
-                       colorize_elements(elements[mclass], color)
-               end
-       end
-
-       # Colorize properties of the crown hierarchy
-       private fun colorize_crown(elements: Map[MClass, Set[E]]) do
-               for mclass in self.class_colorer.crown do
-                       var parents = new HashSet[MClass]
-                       if mmodule.flatten_mclass_hierarchy.has(mclass) then
-                               parents.add_all(mclass.in_hierarchy(mmodule).direct_greaters)
-                       end
-                       colorize_elements(elements[mclass], max_color(0, parents, elements))
-               end
-       end
-
-       # Colorize a collection of mproperties given a starting color
-       private fun colorize_elements(elements: Collection[E], start_color: Int) do
-               for element in elements do
-                       if self.coloration_result.has_key(element) then continue
-                       self.coloration_result[element] = start_color
-                       start_color += 1
-               end
-       end
-
-       private fun max_color(min_color: Int, mclasses: Collection[MClass], elements: Map[MClass, Set[E]]): Int do
-               var max_color = min_color
-
-               for mclass in mclasses do
-                       for mproperty in elements[mclass] do
-                               var color = min_color
-                               if self.coloration_result.has_key(mproperty) then
-                                       color = self.coloration_result[mproperty]
-                                       if color >= max_color then max_color = color + 1
-                               end
-                       end
-               end
-               return max_color
-       end
-end
-
-# Layout builder for resolution tables using coloration (CL)
-class ResolutionColorer
-       super ResolutionLayoutBuilder
-
-       private var coloration_result: Map[MType, Int] = new HashMap[MType, Int]
-
-       init do end
-
-       # Compute resolved types colors
-       redef fun build_layout(elements) do
-               self.build_conflicts_graph(elements)
-               var result = new Layout[MType]
-               result.ids = self.compute_ids(elements)
-               result.pos = self.colorize_elements(elements)
-               return result
-       end
-
-       private fun compute_ids(elements: Map[MClassType, Set[MType]]): Map[MType, Int] do
-               var ids = new HashMap[MType, Int]
-               var color = 0
-               for mclasstype, mclasstypes in elements do
-                       for element in mclasstypes do
-                               if ids.has_key(element) then continue
-                               ids[element] = color
-                               color += 1
-                       end
-               end
-               return ids
-       end
-
-       # Colorize a collection of elements
-       private fun colorize_elements(elements: Map[MClassType, Set[MType]]): Map[MType, Int] do
-               var min_color = 0
-               for mclasstype, mclasstypes in elements do
-                       for element in mclasstypes do
-                               if self.coloration_result.has_key(element) then continue
-                               var color = min_color
-                               while not self.is_color_free(element, color) do
-                                       color += 1
-                               end
-                               coloration_result[element] = color
-                               color = min_color
-                       end
-               end
-               return self.coloration_result
-       end
-
-       # Check if a related element to the element already use the color
-       private fun is_color_free(element: MType, color: Int): Bool do
-               if conflicts_graph.has_key(element) then
-                       for st in conflicts_graph[element] do
-                               if coloration_result.has_key(st) and coloration_result[st] == color then return false
-                       end
-               end
-               return true
-       end
-
-       # look for unanchored types generated by the same type
-       private fun build_conflicts_graph(elements: Map[MClassType, Set[MType]]) do
-               for mclasstype, mtypes in elements do
-                       for mtype in mtypes do
-                               for otype in mtypes do
-                                       if otype == mtype then continue
-                                       self.add_conflict(mtype, otype)
-                               end
-                       end
-               end
-       end
-
-       private var conflicts_graph: Map[MType, Set[MType]] = new HashMap[MType, Set[MType]]
-
-       private fun add_conflict(mtype: MType, otype: MType) do
-               if mtype == otype then return
-               if not self.conflicts_graph.has_key(mtype) then  self.conflicts_graph[mtype] = new HashSet[MType]
-               self.conflicts_graph[mtype].add(otype)
-               if not self.conflicts_graph.has_key(otype) then  self.conflicts_graph[otype] = new HashSet[MType]
-               self.conflicts_graph[otype].add(mtype)
-       end
-end
-
-# Perfect Hashing (PH)
-# T = type of holder
-# U = type of elements to hash
-private class PerfectHasher[T: Object, U: Object]
-
-       var operator: PHOperator
-
-       init do end
-
-       # Compute mask for each holders
-       fun compute_masks(conflicts: Map[T, Set[U]], ids: Map[U, Int]): Map[T, Int] do
-               var masks = new HashMap[T, Int]
-               for mclasstype, mtypes in conflicts do
-                       masks[mclasstype] = compute_mask(mtypes, ids)
-               end
-               return masks
-       end
-
-       private fun compute_mask(mtypes: Set[U], ids: Map[U, Int]): Int do
-               var mask = 0
-               loop
-                       var used = new List[Int]
-                       for mtype in mtypes do
-                               var res = operator.op(mask, ids[mtype])
-                               if used.has(res) then
-                                       break
-                               else
-                                       used.add(res)
-                               end
-                       end
-                       if used.length == mtypes.length then break
-                       mask += 1
-               end
-               return mask
-       end
-
-       # Compute hash for each element in each holder
-       fun compute_hashes(elements: Map[T, Set[U]], ids: Map[U, Int], masks: Map[T, Int]): Map[T, Map[U, Int]] do
-               var hashes = new HashMap[T, Map[U, Int]]
-               for mclasstype, mtypes in elements do
-                       var mask = masks[mclasstype]
-                       var inhashes = new HashMap[U, Int]
-                       for mtype in mtypes do
-                               inhashes[mtype] = operator.op(mask, ids[mtype])
-                       end
-                       hashes[mclasstype] = inhashes
-               end
-               return hashes
-       end
-end
-
-# Abstract operator used for perfect hashing
-abstract class PHOperator
-       # hash `id` using `mask`
-       fun op(mask: Int, id:Int): Int is abstract
-end
-
-# Hashing using modulo (MOD) operator
-# slower but compact
-class PHModOperator
-       super PHOperator
-       init do end
-       redef fun op(mask, id) do return mask % id
-end
-
-# Hashing using binary and (AND) operator
-# faster but sparse
-class PHAndOperator
-       super PHOperator
-       init do end
-       redef fun op(mask, id) do return mask.bin_and(id)
-end
-
-# Layout builder for typing tables using perfect hashing (PH)
-class TypingHasher[E: Object]
-       super PerfectHasher[E, E]
-       super TypingLayoutBuilder[E]
-
-       private var mmodule: MModule
-       private var poset_builder: POSetBuilder[E]
-       private var poset_cache: nullable POSet[E]
-
-       private init(mmodule: MModule, poset_builder: POSetBuilder[E], operator: PHOperator) do
-               self.operator = operator
-               self.mmodule = mmodule
-               self.poset_builder = poset_builder
-       end
-
-       redef fun build_layout(elements: Set[E]): PHLayout[E, E] do
-               poset_cache = poset_builder.build_poset(elements)
-               var result = new PHLayout[E, E]
-               var conflicts = self.build_conflicts(elements)
-               result.ids = self.compute_ids
-               result.masks = self.compute_masks(conflicts, result.ids)
-               result.hashes = self.compute_hashes(conflicts, result.ids, result.masks)
-               return result
-       end
-
-       # Ids start from 1 instead of 0
-       private fun compute_ids: Map[E, Int] do
-               var ids = new HashMap[E, Int]
-               var lin = poset.to_a
-               poset.sort(lin)
-               for e in lin do
-                       ids[e] = ids.length + 1
-               end
-               return ids
-       end
-
-       private fun build_conflicts(elements: Set[E]): Map[E, Set[E]] do
-               var conflicts = new HashMap[E, Set[E]]
-               for e in elements do
-                       var supers = new HashSet[E]
-                       supers.add_all(self.poset[e].greaters)
-                       supers.add(e)
-                       conflicts[e] = supers
-               end
-               return conflicts
-       end
-end
-
-# Layout builder for typing tables with types using perfect hashing (PH)
-class MTypeHasher
-       super TypingHasher[MType]
-       init(operator: PHOperator, mmodule: MModule) do super(mmodule, new MTypePOSetBuilder(mmodule), operator)
-end
-
-# Layout builder for typing tables with classes using perfect hashing (PH)
-class MClassHasher
-       super TypingHasher[MClass]
-       init(operator: PHOperator, mmodule: MModule) do super(mmodule, new MClassPOSetBuilder(mmodule), operator)
-end
-
-# Abstract layout builder for properties tables using perfect hashing (PH)
-class MPropertyHasher[E: PropertyLayoutElement]
-       super PerfectHasher[MClass, E]
-       super PropertyLayoutBuilder[E]
-
-       var mmodule: MModule
-
-       init(operator: PHOperator, mmodule: MModule) do
-               self.operator = operator
-               self.mmodule = mmodule
-       end
-
-       fun build_poset(mclasses: Set[MClass]): POSet[MClass] do
-               var poset = new POSet[MClass]
-               for e in mclasses do
-                       poset.add_node(e)
-                       for o in mclasses do
-                               if e == o or not mmodule.flatten_mclass_hierarchy.has(e) then continue
-                               if e.in_hierarchy(mmodule) < o then poset.add_edge(e, o)
-                       end
-               end
-               return poset
-       end
-
-       redef fun build_layout(elements) do
-               var result = new PHLayout[MClass, E]
-               var ids = new HashMap[E, Int]
-               var mclasses = new HashSet[MClass]
-               mclasses.add_all(elements.keys)
-               var poset = build_poset(mclasses)
-               var lin = poset.to_a
-               poset.sort(lin)
-               for mclass in lin.reversed do
-                       for mproperty in elements[mclass] do
-                               if ids.has_key(mproperty) then continue
-                               ids[mproperty] = ids.length + 1
-                       end
-               end
-               result.ids = ids
-               result.pos = ids
-               result.masks = self.compute_masks(elements, ids)
-               result.hashes = self.compute_hashes(elements, ids, result.masks)
-               return result
-       end
-end
-
-# Layout builder for resolution tables using perfect hashing (PH)
-class ResolutionHasher
-       super PerfectHasher[MClassType, MType]
-       super ResolutionLayoutBuilder
-
-       init(operator: PHOperator) do self.operator = operator
-
-       # Compute resolved types masks and hashes
-       redef fun build_layout(elements) do
-               var result = new PHLayout[MClassType, MType]
-               var ids = new HashMap[MType, Int]
-               var color = 1
-               for mclasstype, mclasstypes in elements do
-                       for element in mclasstypes do
-                               if ids.has_key(element) then continue
-                               ids[element] = color
-                               color += 1
-                       end
-               end
-               result.ids = ids
-               result.pos = ids
-               result.masks = self.compute_masks(elements, ids)
-               result.hashes = self.compute_hashes(elements, ids, result.masks)
-               return result
-       end
-end
index a529c3d..a408697 100755 (executable)
@@ -4,8 +4,8 @@ out=c_src
 rm -r "$out/" 2> /dev/null
 set -e
 set -x
-src/nitg src/nitg.nit -v "$@" --compile-dir "$out" -o "$out/nitg" --no-cc
-cp "$out/nitg.mk" "$out/Makefile"
+src/nitg src/nith.nit --semi-global -v "$@" --compile-dir "$out" -o "$out/nitg" --no-cc
+cp "$out/nith.mk" "$out/Makefile"
 sed -i -e "s#../$out/##g" "$out/Makefile"
 
 # Copy all direct dependencies
index 47b0117..dbbec6d 100644 (file)
@@ -1472,6 +1472,15 @@ class MParameter
        # Is the parameter a vararg?
        var is_vararg: Bool
 
+       redef fun to_s
+       do
+               if is_vararg then
+                       return "{name}: {mtype}..."
+               else
+                       return "{name}: {mtype}"
+               end
+       end
+
        fun resolve_for(mtype: MType, anchor: nullable MClassType, mmodule: MModule, cleanup_virtual: Bool): MParameter
        do
                if not self.mtype.need_anchor then return self
@@ -1832,6 +1841,9 @@ class MMethodDef
 
        # Is the method definition intern?
        var is_intern writable = false
+
+       # Is the method definition extern?
+       var is_extern writable = false
 end
 
 # A local definition of an attribute
index 12b8907..a8be901 100644 (file)
@@ -20,6 +20,31 @@ module model_utils
 import modelbuilder
 
 redef class MModule
+
+       # The list of intro mclassdef in the module.
+       # with visibility >= to min_visibility
+       fun intro_mclassdefs(min_visibility: MVisibility): Set[MClassDef] do
+               var res = new HashSet[MClassDef]
+               for mclassdef in mclassdefs do
+                       if not mclassdef.is_intro then continue
+                       if mclassdef.mclass.visibility < min_visibility then continue
+                       res.add mclassdef
+               end
+               return res
+       end
+
+       # The list of redef mclassdef in the module.
+       # with visibility >= to min_visibility
+       fun redef_mclassdefs(min_visibility: MVisibility): Set[MClassDef] do
+               var res = new HashSet[MClassDef]
+               for mclassdef in mclassdefs do
+                       if mclassdef.is_intro then continue
+                       if mclassdef.mclass.visibility < min_visibility then continue
+                       res.add mclassdef
+               end
+               return res
+       end
+
        # Get the list of mclasses refined in 'self'.
        fun redef_mclasses: Set[MClass] do
                var mclasses = new HashSet[MClass]
@@ -265,6 +290,49 @@ redef class MAttribute
        fun is_nullable: Bool do return intro.static_mtype isa MNullableType
 end
 
+redef class MClassDef
+       # modifiers are keywords like redef, private etc.
+       fun modifiers: Array[String] do
+               var res = new Array[String]
+               if not is_intro then
+                       res.add "redef"
+               else
+                       res.add mclass.visibility.to_s
+               end
+               res.add mclass.kind.to_s
+               return res
+       end
+end
+
+redef class MPropDef
+       # modifiers are keywords like redef, private etc.
+       fun modifiers: Array[String] do
+               var res = new Array[String]
+               if not is_intro then
+                       res.add "redef"
+               else
+                       res.add mproperty.visibility.to_s
+               end
+               var mprop = self
+               if mprop isa MVirtualTypeDef then
+                       res.add "type"
+               else if mprop isa MMethodDef then
+                       if mprop.is_abstract then
+                               res.add "abstract"
+                       else if mprop.is_intern then
+                               res.add "intern"
+                       end
+                       if mprop.mproperty.is_init then
+                               res.add "init"
+                       else
+                               res.add "fun"
+                       end
+               end
+               return res
+       end
+end
+
+
 # Sorters
 
 # Sort mmodules by their name
index 9425fcf..56ff873 100644 (file)
@@ -105,41 +105,49 @@ redef class ModelBuilder
                                inhc = inhc2
                        end
                end
+
+               # Collect undefined attributes
+               var mparameters = new Array[MParameter]
+               var anode: nullable ANode = null
+               for npropdef in nclassdef.n_propdefs do
+                       if npropdef isa AAttrPropdef and npropdef.n_expr == null then
+                               if npropdef.mpropdef == null then return # Skip broken attribute
+                               var paramname = npropdef.mpropdef.mproperty.name.substring_from(1)
+                               var ret_type = npropdef.mpropdef.static_mtype
+                               if ret_type == null then return
+                               var mparameter = new MParameter(paramname, ret_type, false)
+                               mparameters.add(mparameter)
+                               if anode == null then anode = npropdef
+                       end
+               end
+               if anode == null then anode = nclassdef
+
                if combine.is_empty and inhc != null then
+                       if not mparameters.is_empty then
+                               self.error(anode,"Error: {mclassdef} cannot inherit constructors from {inhc} because there is attributes without initial values: {mparameters.join(", ")}")
+                               return
+                       end
+
                        # TODO: actively inherit the consturctor
                        self.toolcontext.info("{mclassdef} inherits all constructors from {inhc}", 3)
                        mclassdef.mclass.inherit_init_from = inhc
                        return
                end
+
                if not combine.is_empty and inhc != null then
                        self.error(nclassdef, "Error: Cannot provide a defaut constructor: conflict for {combine.join(", ")} and {inhc}")
                        return
                end
 
                if not combine.is_empty then
-                       nclassdef.super_inits = combine
-                       var mprop = new MMethod(mclassdef, "init", mclassdef.mclass.visibility)
-                       var mpropdef = new MMethodDef(mclassdef, mprop, nclassdef.location)
-                       var mparameters = new Array[MParameter]
-                       var msignature = new MSignature(mparameters, null)
-                       mpropdef.msignature = msignature
-                       mprop.is_init = true
-                       nclassdef.mfree_init = mpropdef
-                       self.toolcontext.info("{mclassdef} gets a free empty constructor {mpropdef}{msignature}", 3)
-                       return
-               end
-
-               # Collect undefined attributes
-               var mparameters = new Array[MParameter]
-               for npropdef in nclassdef.n_propdefs do
-                       if npropdef isa AAttrPropdef and npropdef.n_expr == null then
-                               if npropdef.mpropdef == null then return # Skip broken attribute
-                               var paramname = npropdef.mpropdef.mproperty.name.substring_from(1)
-                               var ret_type = npropdef.mpropdef.static_mtype
-                               if ret_type == null then return
-                               var mparameter = new MParameter(paramname, ret_type, false)
-                               mparameters.add(mparameter)
+                       if mparameters.is_empty and combine.length == 1 then
+                               # No need to create a local init, the inherited one is enough
+                               inhc = combine.first.intro_mclassdef.mclass
+                               mclassdef.mclass.inherit_init_from = inhc
+                               self.toolcontext.info("{mclassdef} inherits all constructors from {inhc}", 3)
+                               return
                        end
+                       nclassdef.super_inits = combine
                end
 
                var mprop = new MMethod(mclassdef, "init", mclassdef.mclass.visibility)
@@ -399,21 +407,23 @@ redef class AMethPropdef
 
        redef fun build_property(modelbuilder, nclassdef)
        do
-               var is_init = self isa AInitPropdef
+               var n_kwinit = n_kwinit
+               var n_kwnew = n_kwnew
+               var is_init = n_kwinit != null or n_kwnew != null
                var mclassdef = nclassdef.mclassdef.as(not null)
                var name: String
                var amethodid = self.n_methid
                var name_node: ANode
                if amethodid == null then
-                       if self isa AMainMethPropdef then
+                       if not is_init then
                                name = "main"
                                name_node = self
-                       else if self isa AConcreteInitPropdef then
+                       else if n_kwinit != null then
                                name = "init"
-                               name_node = self.n_kwinit
-                       else if self isa AExternInitPropdef then
+                               name_node = n_kwinit
+                       else if n_kwnew != null then
                                name = "init"
-                               name_node = self.n_kwnew
+                               name_node = n_kwnew
                        else
                                abort
                        end
@@ -436,7 +446,7 @@ redef class AMethPropdef
                        var mvisibility = new_property_visibility(modelbuilder, nclassdef, self.n_visibility)
                        mprop = new MMethod(mclassdef, name, mvisibility)
                        mprop.is_init = is_init
-                       mprop.is_new = self isa AExternInitPropdef
+                       mprop.is_new = n_kwnew != null
                        if not self.check_redef_keyword(modelbuilder, nclassdef, n_kwredef, false, mprop) then return
                else
                        if n_kwredef == null then
@@ -555,6 +565,7 @@ redef class AMethPropdef
                mpropdef.msignature = msignature
                mpropdef.is_abstract = self isa ADeferredMethPropdef
                mpropdef.is_intern = self isa AInternMethPropdef
+               mpropdef.is_extern = self isa AExternPropdef
        end
 
        redef fun check_signature(modelbuilder, nclassdef)
@@ -948,6 +959,7 @@ redef class ATypePropdef
 
                var mpropdef = new MVirtualTypeDef(mclassdef, mprop, self.location)
                self.mpropdef = mpropdef
+               modelbuilder.mpropdef2npropdef[mpropdef] = self
                set_doc(mpropdef)
        end
 
index 8f2d95b..e9d0a97 100644 (file)
@@ -572,11 +572,11 @@ redef class ANode
        private fun fatal(v: NaiveInterpreter, message: String)
        do
                if v.modelbuilder.toolcontext.opt_no_color.value == true then
-                       stderr.write("Runtime error: {message} ({location.file.filename}:{location.line_start})\n")
+                       sys.stderr.write("Runtime error: {message} ({location.file.filename}:{location.line_start})\n")
                else
-                       stderr.write("{location}: Runtime error: {message}\n{location.colored_line("0;31")}\n")
-                       stderr.write(v.stack_trace)
-                       stderr.write("\n")
+                       sys.stderr.write("{location}: Runtime error: {message}\n{location.colored_line("0;31")}\n")
+                       sys.stderr.write(v.stack_trace)
+                       sys.stderr.write("\n")
                end
                exit(1)
        end
@@ -591,23 +591,24 @@ redef class APropdef
        end
 end
 
-redef class AConcreteMethPropdef
+redef class AMethPropdef
+       super TablesCapable
 
        redef fun call(v, mpropdef, args)
        do
                var f = new Frame(self, self.mpropdef.as(not null), args)
-               call_commons(v, mpropdef, args, f)
+               var res = call_commons(v, mpropdef, args, f)
                v.frames.shift
                if v.returnmark == f then
                        v.returnmark = null
-                       var res = v.escapevalue
+                       res = v.escapevalue
                        v.escapevalue = null
                        return res
                end
-               return null
+               return res
        end
 
-       private fun call_commons(v: NaiveInterpreter, mpropdef: MMethodDef, arguments: Array[Instance], f: Frame)
+       private fun call_commons(v: NaiveInterpreter, mpropdef: MMethodDef, arguments: Array[Instance], f: Frame): nullable Instance
        do
                for i in [0..mpropdef.msignature.arity[ do
                        var variable = self.n_signature.n_params[i].variable
@@ -617,6 +618,11 @@ redef class AConcreteMethPropdef
 
                v.frames.unshift(f)
 
+               if mpropdef.is_abstract then
+                       v.fatal("Abstract method `{mpropdef.mproperty.name}` called on `{arguments.first.mtype}`")
+                       abort
+               end
+
                # Call the implicit super-init
                var auto_super_inits = self.auto_super_inits
                if auto_super_inits != null then
@@ -630,12 +636,15 @@ redef class AConcreteMethPropdef
                        end
                end
 
-               v.stmt(self.n_block)
+               if n_block != null then
+                       v.stmt(self.n_block)
+                       return null
+               else
+                       return intern_call(v, mpropdef, arguments)
+               end
        end
-end
 
-redef class AInternMethPropdef
-       redef fun call(v, mpropdef, args)
+       private fun intern_call(v: NaiveInterpreter, mpropdef: MMethodDef, args: Array[Instance]): nullable Instance
        do
                var pname = mpropdef.mproperty.name
                var cname = mpropdef.mclassdef.mclass.name
@@ -673,6 +682,7 @@ redef class AInternMethPropdef
                else if pname == "sys" then
                        return v.mainobj
                else if cname == "Int" then
+                       var recvval = args[0].to_i
                        if pname == "unary -" then
                                return v.int_instance(-args[0].to_i)
                        else if pname == "+" then
@@ -703,6 +713,13 @@ redef class AInternMethPropdef
                                return v.int_instance(args[0].to_i.lshift(args[1].to_i))
                        else if pname == "rshift" then
                                return v.int_instance(args[0].to_i.rshift(args[1].to_i))
+                       else if pname == "rand" then
+                               var res = recvval.rand
+                               return v.int_instance(res)
+                       else if pname == "native_int_to_s" then
+                               return v.native_string_instance(recvval.to_s)
+                       else if pname == "strerror_ext" then
+                               return v.native_string_instance(recvval.strerror)
                        end
                else if cname == "Char" then
                        var recv = args[0].val.as(Char)
@@ -745,6 +762,36 @@ redef class AInternMethPropdef
                                return v.bool_instance(recv >= args[1].to_f)
                        else if pname == "to_i" then
                                return v.int_instance(recv.to_i)
+                       else if pname == "cos" then
+                               return v.float_instance(args[0].to_f.cos)
+                       else if pname == "sin" then
+                               return v.float_instance(args[0].to_f.sin)
+                       else if pname == "tan" then
+                               return v.float_instance(args[0].to_f.tan)
+                       else if pname == "acos" then
+                               return v.float_instance(args[0].to_f.acos)
+                       else if pname == "asin" then
+                               return v.float_instance(args[0].to_f.asin)
+                       else if pname == "atan" then
+                               return v.float_instance(args[0].to_f.atan)
+                       else if pname == "sqrt" then
+                               return v.float_instance(args[0].to_f.sqrt)
+                       else if pname == "exp" then
+                               return v.float_instance(args[0].to_f.exp)
+                       else if pname == "log" then
+                               return v.float_instance(args[0].to_f.log)
+                       else if pname == "pow" then
+                               return v.float_instance(args[0].to_f.pow(args[1].to_f))
+                       else if pname == "rand" then
+                               return v.float_instance(args[0].to_f.rand)
+                       else if pname == "abs" then
+                               return v.float_instance(args[0].to_f.abs)
+                       else if pname == "hypot_with" then
+                               return v.float_instance(args[0].to_f.hypot_with(args[1].to_f))
+                       else if pname == "is_nan" then
+                               return v.bool_instance(args[0].to_f.is_nan)
+                       else if pname == "is_inf_extern" then
+                               return v.bool_instance(args[0].to_f.is_inf != 0)
                        end
                else if cname == "NativeString" then
                        var recvval = args.first.val.as(Buffer)
@@ -783,6 +830,24 @@ redef class AInternMethPropdef
                                return null
                        else if pname == "atoi" then
                                return v.int_instance(recvval.to_i)
+                       else if pname == "file_exists" then
+                               return v.bool_instance(recvval.to_s.file_exists)
+                       else if pname == "file_mkdir" then
+                               recvval.to_s.mkdir
+                               return null
+                       else if pname == "file_chdir" then
+                               recvval.to_s.chdir
+                               return null
+                       else if pname == "file_realpath" then
+                               return v.native_string_instance(recvval.to_s.realpath)
+                       else if pname == "get_environ" then
+                               var txt = recvval.to_s.environ
+                               return v.native_string_instance(txt)
+                       else if pname == "system" then
+                               var res = sys.system(recvval.to_s)
+                               return v.int_instance(res)
+                       else if pname == "atof" then
+                               return v.float_instance(recvval.to_f)
                        end
                else if pname == "calloc_string" then
                        return v.native_string_instance("!" * args[1].to_i)
@@ -802,71 +867,20 @@ redef class AInternMethPropdef
                                recvval.copy(0, args[2].to_i, args[1].val.as(Array[Instance]), 0)
                                return null
                        end
-               else if pname == "calloc_array" then
-                       var recvtype = args.first.mtype.as(MClassType)
-                       var mtype: MType
-                       mtype = recvtype.supertype_to(v.mainmodule, recvtype, v.mainmodule.get_primitive_class("ArrayCapable"))
-                       mtype = mtype.arguments.first
-                       var val = new Array[Instance].filled_with(v.null_instance, args[1].to_i)
-                       return new PrimitiveInstance[Array[Instance]](v.mainmodule.get_primitive_class("NativeArray").get_mtype([mtype]), val)
-               else if pname == "native_argc" then
-                       return v.int_instance(v.arguments.length)
-               else if pname == "native_argv" then
-                       var txt = v.arguments[args[1].to_i]
-                       return v.native_string_instance(txt)
-               end
-               fatal(v, "NOT YET IMPLEMENTED intern {mpropdef}")
-               abort
-       end
-end
-
-redef class AbstractArray[E]
-       fun copy(start: Int, len: Int, dest: AbstractArray[E], new_start: Int)
-       do
-               self.copy_to(start, len, dest, new_start)
-       end
-end
-
-redef class AExternInitPropdef
-       redef fun call(v, mpropdef, args)
-       do
-               var pname = mpropdef.mproperty.name
-               var cname = mpropdef.mclassdef.mclass.name
-               if pname == "native_stdout" then
-                       return new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, stdout)
-               else if pname == "native_stdin" then
-                       return new PrimitiveInstance[IStream](mpropdef.mclassdef.mclass.mclass_type, stdin)
-               else if pname == "native_stderr" then
-                       return new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, stderr)
-               else if pname == "io_open_read" then
-                       var a1 = args[1].val.as(Buffer)
-                       return new PrimitiveInstance[IStream](mpropdef.mclassdef.mclass.mclass_type, new IFStream.open(a1.to_s))
-               else if pname == "io_open_write" then
-                       var a1 = args[1].val.as(Buffer)
-                       return new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, new OFStream.open(a1.to_s))
-               end
-               fatal(v, "NOT YET IMPLEMENTED extern init {mpropdef}")
-               abort
-       end
-end
-
-redef class AExternMethPropdef
-       super TablesCapable
-       redef fun call(v, mpropdef, args)
-       do
-               var pname = mpropdef.mproperty.name
-               var cname = mpropdef.mclassdef.mclass.name
-               if cname == "Int" then
-                       var recvval = args.first.val.as(Int)
-                       if pname == "rand" then
-                               var res = recvval.rand
-                               return v.int_instance(res)
-                       else if pname == "native_int_to_s" then
-                               return v.native_string_instance(recvval.to_s)
-                       else if pname == "strerror_ext" then
-                               return v.native_string_instance(recvval.strerror)
-                       end
                else if cname == "NativeFile" then
+                       if pname == "native_stdout" then
+                               return new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, sys.stdout)
+                       else if pname == "native_stdin" then
+                               return new PrimitiveInstance[IStream](mpropdef.mclassdef.mclass.mclass_type, sys.stdin)
+                       else if pname == "native_stderr" then
+                               return new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, sys.stderr)
+                       else if pname == "io_open_read" then
+                               var a1 = args[1].val.as(Buffer)
+                               return new PrimitiveInstance[IStream](mpropdef.mclassdef.mclass.mclass_type, new IFStream.open(a1.to_s))
+                       else if pname == "io_open_write" then
+                               var a1 = args[1].val.as(Buffer)
+                               return new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, new OFStream.open(a1.to_s))
+                       end
                        var recvval = args.first.val
                        if pname == "io_write" then
                                var a1 = args[1].val.as(Buffer)
@@ -883,59 +897,18 @@ redef class AExternMethPropdef
                        else if pname == "address_is_null" then
                                return v.false_instance
                        end
-               else if cname == "NativeString" then
-                       var recvval = args.first.val.as(Buffer)
-                       if pname == "file_exists" then
-                               return v.bool_instance(recvval.to_s.file_exists)
-                       else if pname == "file_mkdir" then
-                               recvval.to_s.mkdir
-                               return null
-                       else if pname == "file_chdir" then
-                               recvval.to_s.chdir
-                               return null
-                       else if pname == "file_realpath" then
-                               return v.native_string_instance(recvval.to_s.realpath)
-                       else if pname == "get_environ" then
-                               var txt = recvval.to_s.environ
-                               return v.native_string_instance(txt)
-                       else if pname == "system" then
-                               var res = sys.system(recvval.to_s)
-                               return v.int_instance(res)
-                       else if pname == "atof" then
-                               return v.float_instance(recvval.to_f)
-                       end
-               else if cname == "Float" then
-                       if pname == "cos" then
-                               return v.float_instance(args[0].to_f.cos)
-                       else if pname == "sin" then
-                               return v.float_instance(args[0].to_f.sin)
-                       else if pname == "tan" then
-                               return v.float_instance(args[0].to_f.tan)
-                       else if pname == "acos" then
-                               return v.float_instance(args[0].to_f.acos)
-                       else if pname == "asin" then
-                               return v.float_instance(args[0].to_f.asin)
-                       else if pname == "atan" then
-                               return v.float_instance(args[0].to_f.atan)
-                       else if pname == "sqrt" then
-                               return v.float_instance(args[0].to_f.sqrt)
-                       else if pname == "exp" then
-                               return v.float_instance(args[0].to_f.exp)
-                       else if pname == "log" then
-                               return v.float_instance(args[0].to_f.log)
-                       else if pname == "pow" then
-                               return v.float_instance(args[0].to_f.pow(args[1].to_f))
-                       else if pname == "rand" then
-                               return v.float_instance(args[0].to_f.rand)
-                       else if pname == "abs" then
-                               return v.float_instance(args[0].to_f.abs)
-                       else if pname == "hypot_with" then
-                               return v.float_instance(args[0].to_f.hypot_with(args[1].to_f))
-                       else if pname == "is_nan" then
-                               return v.bool_instance(args[0].to_f.is_nan)
-                       else if pname == "is_inf_extern" then
-                               return v.bool_instance(args[0].to_f.is_inf != 0)
-                       end
+               else if pname == "calloc_array" then
+                       var recvtype = args.first.mtype.as(MClassType)
+                       var mtype: MType
+                       mtype = recvtype.supertype_to(v.mainmodule, recvtype, v.mainmodule.get_primitive_class("ArrayCapable"))
+                       mtype = mtype.arguments.first
+                       var val = new Array[Instance].filled_with(v.null_instance, args[1].to_i)
+                       return new PrimitiveInstance[Array[Instance]](v.mainmodule.get_primitive_class("NativeArray").get_mtype([mtype]), val)
+               else if pname == "native_argc" then
+                       return v.int_instance(v.arguments.length)
+               else if pname == "native_argv" then
+                       var txt = v.arguments[args[1].to_i]
+                       return v.native_string_instance(txt)
                else if pname == "native_argc" then
                        return v.int_instance(v.arguments.length)
                else if pname == "native_argv" then
@@ -965,11 +938,24 @@ redef class AExternMethPropdef
                else if pname == "address_is_null" then
                        return v.false_instance
                end
-               fatal(v, "NOT YET IMPLEMENTED extern {mpropdef}")
+               if mpropdef.is_intern then
+                       fatal(v, "NOT YET IMPLEMENTED intern {mpropdef}")
+               else if mpropdef.is_extern then
+                       fatal(v, "NOT YET IMPLEMENTED extern {mpropdef}")
+               else
+                       fatal(v, "NOT YET IMPLEMENTED <wat?> {mpropdef}")
+               end
                abort
        end
 end
 
+redef class AbstractArray[E]
+       fun copy(start: Int, len: Int, dest: AbstractArray[E], new_start: Int)
+       do
+               self.copy_to(start, len, dest, new_start)
+       end
+end
+
 redef class AAttrPropdef
        redef fun call(v, mpropdef, args)
        do
@@ -1008,25 +994,17 @@ redef class AAttrPropdef
        end
 end
 
-redef class ADeferredMethPropdef
-       redef fun call(v, mpropdef, args)
-       do
-               fatal(v, "Abstract method `{mpropdef.mproperty.name}` called on `{args.first.mtype}`")
-               abort
-       end
-end
-
 redef class AClassdef
        # Execute an implicit `mpropdef` associated with the current node.
        private fun call(v: NaiveInterpreter, mpropdef: MMethodDef, args: Array[Instance]): nullable Instance
        do
                var super_inits = self.super_inits
                if super_inits != null then
-                       assert args.length == 1
+                       var args_of_super = args
+                       if args.length > 1 then args_of_super = [args.first]
                        for su in super_inits do
-                               v.send(su, args)
+                               v.send(su, args_of_super)
                        end
-                       return null
                end
                var recv = args.first
                assert recv isa MutableInstance
@@ -1582,7 +1560,7 @@ redef class ASuperExpr
                if callsite != null then
                        # Add additionnals arguments for the super init call
                        if args.length == 1 then
-                               for i in [0..callsite.mproperty.intro.msignature.arity[ do
+                               for i in [0..callsite.msignature.arity[ do
                                        args.add(v.frame.arguments[i+1])
                                end
                        end
diff --git a/src/network_debugger.nit b/src/network_debugger.nit
deleted file mode 100644 (file)
index e8afc20..0000000
+++ /dev/null
@@ -1,231 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Copyright 2013 Lucas Bajolet <lucas.bajolet@gmail.com>
-#
-# 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
index 02e8d53..e6dd406 100755 (executable)
@@ -2,10 +2,16 @@
 rm nitg nitg_? hello_world 2>/dev/null
 set -x
 set -e
-time ../c_src/nitg nitg.nit -v -o nitg
-time ./nitg nitg.nit -v "$@" -o nitg_2
+make -C ../c_src
+sh git-gen-version.sh
+time ../c_src/nitg nitg.nit -v -o nitg_0
+time ./nitg_0 nitg.nit -v "$@" -o nitg_2
+cp nitg_2 nitg
 time ./nitg_2 nitg.nit -v "$@" -o nitg_3
 time ./nitg_3 nitg.nit -v "$@" -o nitg_4
 ./nitg_4 ../examples/hello_world.nit "$@" -o hello_world
 ./hello_world
 
+# save the last one; may be useful...
+cp ./nitg_4 nitg.good
+
index ad1a388..36c3815 100644 (file)
@@ -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]... <file.nit>...\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
index 4b01ecd..2355c5e 100644 (file)
@@ -52,63 +52,12 @@ redef class String
 
 end
 
-# Persistant connection to the debugger
-# Default port = 22125
-#
-class DebugClient
-
-       var debugger_connection: Socket
-
-       init (host: String, port: Int)
-       do
-               self.debugger_connection = new Socket.stream_with_host(host, port)
-               print "[HOST ADDRESS] : "+debugger_connection.address
-               print "[HOST] : "+debugger_connection.host.as(not null)
-               print "[PORT] : "+debugger_connection.port.to_s
-       end
-
-       init with_port (host: String, port: Int)
-       do
-               debugger_connection = new Socket.stream_with_host(host, port)
-       end
-
-       fun send_command(command: String)
-       do
-               debugger_connection.write(command+"\n")
-       end
-
-       fun connected: Bool
-       do
-               return self.debugger_connection.connected
-       end
-
-       fun ready: Bool
-       do
-               return debugger_connection.ready_to_read(40)
-       end
-
-       fun read_command: String
-       do
-               var buff = new FlatBuffer
-               while debugger_connection.ready_to_read(40) do buff.append(debugger_connection.read)
-               return buff.to_s
-       end
-
-       fun disconnect
-       do
-               debugger_connection.close
-       end
-
-end
-
 # Create a tool context to handle options and paths
 var toolcontext = new ToolContext
 toolcontext.tooldescription = "Usage: nitdbg_client [OPTION]...\nConnects to a nitdbg_server and controls it."
 toolcontext.accept_no_arguments = true
 toolcontext.process_options(args)
 
-var debug: DebugClient
-
 # If the port value is not an Int between 0 and 65535 (Mandatory according to the norm)
 # Print the usage
 if toolcontext.opt_debug_port.value < 0 or toolcontext.opt_debug_port.value > 65535 then
@@ -116,49 +65,28 @@ if toolcontext.opt_debug_port.value < 0 or toolcontext.opt_debug_port.value > 65
        return
 end
 
+var debug: Socket
+
 # An IPV4 address does always complies to this form : x.x.x.x
 # Where x is an integer whose value is >=0 and <= 255
 if toolcontext.opt_host_address.value != null then
        if toolcontext.opt_host_address.value.is_valid_ipv4_address then
-               debug = new DebugClient(toolcontext.opt_host_address.value.as(not null), toolcontext.opt_debug_port.value)
+               debug = new Socket.client(toolcontext.opt_host_address.value.as(not null), toolcontext.opt_debug_port.value)
        else
                toolcontext.option_context.usage
                return
        end
 else
-       debug = new DebugClient("127.0.0.1", toolcontext.opt_debug_port.value)
+       debug = new Socket.client("127.0.0.1", toolcontext.opt_debug_port.value)
 end
 
-var res = debug.debugger_connection.connect
-print "Connecting ... " + res.to_s
-if not res then exit 1
-
-var recv_cmd: String
-
-var written_cmd: String
+print "[HOST ADDRESS] : {debug.address}"
+print "[HOST] : {debug.host}"
+print "[PORT] : {debug.port}"
+print "Connecting ... {debug.connected}"
 
-var over = false
-
-while not over do
-       if stdin.poll_in then
-               written_cmd = gets
-               debug.send_command(written_cmd)
-               if written_cmd == "kill" then
-                       over = true
-               end
-       end
-
-       if not over and debug.ready then
-               recv_cmd = debug.read_command
-               var command_parts = recv_cmd.split("\n")
-               for i in command_parts do
-                       if i == "DBG DONE WORK ON SELF" then
-                               debug.send_command("CLIENT DBG DONE ACK")
-                               over = true
-                       end
-                       print i
-               end
-       end
+while debug.connected do
+       if stdin.poll_in then debug.write_ln(gets)
+       while debug.ready_to_read(50) do printn debug.read(200)
 end
 
-debug.disconnect
index 91f00b8..7fd49a4 100644 (file)
@@ -19,99 +19,54 @@ module nitdoc
 import model_utils
 import modelize_property
 import markdown
+import doc_template
 
 # The NitdocContext contains all the knowledge used for doc generation
 class NitdocContext
 
        private var toolcontext = new ToolContext
-       private var model: Model
        private var mbuilder: ModelBuilder
        private var mainmodule: MModule
-       private var class_hierarchy: POSet[MClass]
-       private var arguments: Array[String]
-       private var output_dir: nullable String
-       private var dot_dir: nullable String
-       private var share_dir: nullable String
-       private var source: nullable String
+       private var output_dir: String
        private var min_visibility: MVisibility
 
-       private var github_upstream: nullable String
-       private var github_basesha1: nullable String
-       private var github_gitdir: nullable String
+       private var opt_dir = new OptionString("output directory", "-d", "--dir")
+       private var opt_source = new OptionString("link for source (%f for filename, %l for first line, %L for last line)", "--source")
+       private var opt_sharedir = new OptionString("directory containing nitdoc assets", "--sharedir")
+       private var opt_shareurl = new OptionString("use shareurl instead of copy shared files", "--shareurl")
+       private var opt_nodot = new OptionBool("do not generate graphes with graphviz", "--no-dot")
+       private var opt_private = new OptionBool("also generate private API", "--private")
 
-       private var opt_dir = new OptionString("Directory where doc is generated", "-d", "--dir")
-       private var opt_source = new OptionString("What link for source (%f for filename, %l for first line, %L for last line)", "--source")
-       private var opt_sharedir = new OptionString("Directory containing the nitdoc files", "--sharedir")
-       private var opt_shareurl = new OptionString("Do not copy shared files, link JS and CSS file to share url instead", "--shareurl")
-       private var opt_nodot = new OptionBool("Do not generate graphes with graphviz", "--no-dot")
-       private var opt_private: OptionBool = new OptionBool("Generate the private API", "--private")
+       private var opt_custom_title = new OptionString("custom title for homepage", "--custom-title")
+       private var opt_custom_menu = new OptionString("custom items added in top menu (each item must be enclosed in 'li' tags)", "--custom-menu-items")
+       private var opt_custom_intro = new OptionString("custom intro text for homepage", "--custom-overview-text")
+       private var opt_custom_footer = new OptionString("custom footer text", "--custom-footer-text")
 
-       private var opt_custom_title: OptionString = new OptionString("Title displayed in the top of the Overview page and as suffix of all page names", "--custom-title")
-       private var opt_custom_menu_items: OptionString = new OptionString("Items displayed in menu before the 'Overview' item (Each item must be enclosed in 'li' tags)", "--custom-menu-items")
-       private var opt_custom_overview_text: OptionString = new OptionString("Text displayed as introduction of Overview page before the modules list", "--custom-overview-text")
-       private var opt_custom_footer_text: OptionString = new OptionString("Text displayed as footer of all pages", "--custom-footer-text")
+       private var opt_github_upstream = new OptionString("Git branch where edited commits will be pulled into (ex: user:repo:branch)", "--github-upstream")
+       private var opt_github_base_sha1 = new OptionString("Git sha1 of base commit used to create pull request", "--github-base-sha1")
+       private var opt_github_gitdir = new OptionString("Git working directory used to resolve path name (ex: /home/me/myproject/)", "--github-gitdir")
 
-       private var opt_github_upstream: OptionString = new OptionString("The branch where edited commits will be pulled into (ex: user:repo:branch)", "--github-upstream")
-       private var opt_github_base_sha1: OptionString = new OptionString("The sha1 of the base commit used to create pull request", "--github-base-sha1")
-       private var opt_github_gitdir: OptionString = new OptionString("The git working directory used to resolve path name (ex: /home/me/myproject/)", "--github-gitdir")
-
-       private var opt_piwik_tracker: OptionString = new OptionString("The URL of the Piwik tracker (ex: nitlanguage.org/piwik/)", "--piwik-tracker")
-       private var opt_piwik_site_id: OptionString = new OptionString("The site ID in Piwik tracker", "--piwik-site-id")
+       private var opt_piwik_tracker = new OptionString("Piwik tracker URL (ex: nitlanguage.org/piwik/)", "--piwik-tracker")
+       private var opt_piwik_site_id = new OptionString("Piwik site ID", "--piwik-site-id")
 
        init do
-               toolcontext.option_context.add_option(opt_dir)
-               toolcontext.option_context.add_option(opt_source)
-               toolcontext.option_context.add_option(opt_sharedir, opt_shareurl)
-               toolcontext.option_context.add_option(opt_nodot)
-               toolcontext.option_context.add_option(opt_private)
-               toolcontext.option_context.add_option(opt_custom_title)
-               toolcontext.option_context.add_option(opt_custom_footer_text)
-               toolcontext.option_context.add_option(opt_custom_overview_text)
-               toolcontext.option_context.add_option(opt_custom_menu_items)
-               toolcontext.option_context.add_option(opt_github_upstream)
-               toolcontext.option_context.add_option(opt_github_base_sha1)
-               toolcontext.option_context.add_option(opt_github_gitdir)
-               toolcontext.option_context.add_option(opt_piwik_tracker)
-               toolcontext.option_context.add_option(opt_piwik_site_id)
-               toolcontext.tooldescription = "Usage: nitdoc [OPTION]... <file.nit>...\nGenerates HTML pages of API documentation from Nit source files."
+               var opts = toolcontext.option_context
+               opts.add_option(opt_dir, opt_source, opt_sharedir, opt_shareurl, opt_nodot, opt_private)
+               opts.add_option(opt_custom_title, opt_custom_footer, opt_custom_intro, opt_custom_menu)
+               opts.add_option(opt_github_upstream, opt_github_base_sha1, opt_github_gitdir)
+               opts.add_option(opt_piwik_tracker, opt_piwik_site_id)
+
+               var tpl = new Template
+               tpl.add "Usage: nitdoc [OPTION]... <file.nit>...\n"
+               tpl.add "Generates HTML pages of API documentation from Nit source files."
+               toolcontext.tooldescription = tpl.write_to_string
                toolcontext.process_options(args)
-               self.arguments = toolcontext.option_context.rest
 
                self.process_options
-
-               model = new Model
-               mbuilder = new ModelBuilder(model, toolcontext)
-               # Here we load and process all modules passed on the command line
-               var mmodules = mbuilder.parse(arguments)
-               if mmodules.is_empty then return
-               mbuilder.run_phases
-
-               if mmodules.length == 1 then
-                       mainmodule = mmodules.first
-               else
-                       # We need a main module, so we build it by importing all modules
-                       mainmodule = new MModule(model, null, "<main>", new Location(null, 0, 0, 0, 0))
-                       mainmodule.set_imported_mmodules(mmodules)
-               end
-               self.class_hierarchy = mainmodule.flatten_mclass_hierarchy
+               self.parse(toolcontext.option_context.rest)
        end
 
        private fun process_options do
-               if opt_dir.value != null then
-                       output_dir = opt_dir.value
-               else
-                       output_dir = "doc"
-               end
-               if opt_sharedir.value != null then
-                       share_dir = opt_sharedir.value
-               else
-                       var dir = toolcontext.nit_dir
-                       share_dir = "{dir}/share/nitdoc"
-                       if dir == null or not share_dir.file_exists then
-                               print "Error: Cannot locate nitdoc share files. Uses --sharedir or envvar NIT_DIR"
-                               abort
-                       end
-               end
                if opt_private.value then
                        min_visibility = none_visibility
                else
@@ -124,25 +79,26 @@ class NitdocContext
                        if gh_upstream == null or gh_base_sha == null or gh_gitdir == null then
                                print "Error: Options {opt_github_upstream.names.first}, {opt_github_base_sha1.names.first} and {opt_github_gitdir.names.first} are required to enable the GitHub plugin"
                                abort
-                       else
-                               self.github_upstream = gh_upstream
-                               self.github_basesha1 = gh_base_sha
-                               self.github_gitdir = gh_gitdir
                        end
                end
-               source = opt_source.value
        end
 
-       fun generate_nitdoc do
-               # Create destination dir if it's necessary
-               if not output_dir.file_exists then output_dir.mkdir
-               if opt_shareurl.value == null then
-                       sys.system("cp -r {share_dir.to_s}/* {output_dir.to_s}/")
+       private fun parse(arguments: Array[String]) do
+               var model = new Model
+               mbuilder = new ModelBuilder(model, toolcontext)
+               var mmodules = mbuilder.parse(arguments)
+               if mmodules.is_empty then return
+               mbuilder.run_phases
+               if mmodules.length == 1 then
+                       mainmodule = mmodules.first
                else
-                       sys.system("cp -r {share_dir.to_s}/resources/ {output_dir.to_s}/resources/")
+                       mainmodule = new MModule(model, null, "<main>", new Location(null, 0, 0, 0, 0))
+                       mainmodule.set_imported_mmodules(mmodules)
                end
-               self.dot_dir = null
-               if not opt_nodot.value then self.dot_dir = output_dir.to_s
+       end
+
+       private fun generate_nitdoc do
+               init_output_dir
                overview
                search
                modules
@@ -150,220 +106,313 @@ class NitdocContext
                quicksearch_list
        end
 
+       private fun init_output_dir do
+               # location output dir
+               var output_dir = opt_dir.value
+               if output_dir == null then
+                       output_dir = "doc"
+               end
+               self.output_dir = output_dir
+               # create destination dir if it's necessary
+               if not output_dir.file_exists then output_dir.mkdir
+               # locate share dir
+               var sharedir = opt_sharedir.value
+               if sharedir == null then
+                       var dir = toolcontext.nit_dir
+                       if dir == null then
+                               print "Error: Cannot locate nitdoc share files. Uses --sharedir or envvar NIT_DIR"
+                               abort
+                       end
+                       sharedir = "{dir}/share/nitdoc"
+                       if not sharedir.file_exists then
+                               print "Error: Cannot locate nitdoc share files. Uses --sharedir or envvar NIT_DIR"
+                               abort
+                       end
+               end
+               # copy shared files
+               if opt_shareurl.value == null then
+                       sys.system("cp -r {sharedir.to_s}/* {output_dir.to_s}/")
+               else
+                       sys.system("cp -r {sharedir.to_s}/resources/ {output_dir.to_s}/resources/")
+               end
+
+       end
+
        private fun overview do
                var overviewpage = new NitdocOverview(self)
-               overviewpage.save("{output_dir.to_s}/index.html")
+               overviewpage.render.write_to_file("{output_dir.to_s}/index.html")
        end
 
        private fun search do
                var searchpage = new NitdocSearch(self)
-               searchpage.save("{output_dir.to_s}/search.html")
+               searchpage.render.write_to_file("{output_dir.to_s}/search.html")
        end
 
        private fun modules do
-               for mmodule in model.mmodules do
+               for mmodule in mbuilder.model.mmodules do
                        if mmodule.name == "<main>" then continue
                        var modulepage = new NitdocModule(mmodule, self)
-                       modulepage.save("{output_dir.to_s}/{mmodule.url}")
+                       modulepage.render.write_to_file("{output_dir.to_s}/{mmodule.nitdoc_url}")
                end
        end
 
        private fun classes do
                for mclass in mbuilder.model.mclasses do
                        var classpage = new NitdocClass(mclass, self)
-                       classpage.save("{output_dir.to_s}/{mclass.url}")
+                       classpage.render.write_to_file("{output_dir.to_s}/{mclass.nitdoc_url}")
                end
        end
 
        private fun quicksearch_list do
-               var file = new OFStream.open("{output_dir.to_s}/quicksearch-list.js")
-               file.write("var nitdocQuickSearchRawList = \{ ")
-               for mmodule in model.mmodules do
+               var quicksearch = new QuickSearch(self)
+               quicksearch.render.write_to_file("{output_dir.to_s}/quicksearch-list.js")
+       end
+end
+
+# Nitdoc QuickSearch list generator
+#
+# Create a JSON object containing links to:
+#  * modules
+#  * mclasses
+#  * mpropdefs
+# All entities are grouped by name to make the research easier.
+class QuickSearch
+
+       private var mmodules = new HashSet[MModule]
+       private var mclasses = new HashSet[MClass]
+       private var mpropdefs = new HashMap[String, Set[MPropDef]]
+
+       init(ctx: NitdocContext) do
+               for mmodule in ctx.mbuilder.model.mmodules do
                        if mmodule.name == "<main>" then continue
-                       file.write("\"{mmodule.name}\": [")
-                       file.write("\{txt: \"{mmodule.full_name}\", url:\"{mmodule.url}\" \},")
-                       file.write("],")
-               end
-               for mclass in model.mclasses do
-                       if mclass.visibility < min_visibility then continue
-                       file.write("\"{mclass.name}\": [")
-                       file.write("\{txt: \"{mclass.full_name}\", url:\"{mclass.url}\" \},")
-                       file.write("],")
-               end
-               var name2mprops = new HashMap[String, Set[MPropDef]]
-               for mproperty in model.mproperties do
-                       if mproperty.visibility < min_visibility then continue
-                       if mproperty isa MAttribute then continue
-                       if not name2mprops.has_key(mproperty.name) then name2mprops[mproperty.name] = new HashSet[MPropDef]
-                       name2mprops[mproperty.name].add_all(mproperty.mpropdefs)
+                       mmodules.add mmodule
                end
-               for mproperty, mpropdefs in name2mprops do
-                       file.write("\"{mproperty}\": [")
-                       for mpropdef in mpropdefs do
-                               file.write("\{txt: \"{mpropdef.full_name}\", url:\"{mpropdef.url}\" \},")
+               for mclass in ctx.mbuilder.model.mclasses do
+                       if mclass.visibility < ctx.min_visibility then continue
+                       mclasses.add mclass
+               end
+               for mproperty in ctx.mbuilder.model.mproperties do
+                       if mproperty.visibility < ctx.min_visibility then continue
+                       if mproperty isa MAttribute then continue
+                       if not mpropdefs.has_key(mproperty.name) then
+                               mpropdefs[mproperty.name] = new HashSet[MPropDef]
                        end
-                       file.write("],")
+                       mpropdefs[mproperty.name].add_all(mproperty.mpropdefs)
                end
-               file.write(" \};")
-               file.close
        end
 
+       fun render: Template do
+               var tpl = new Template
+               tpl.add "var nitdocQuickSearchRawList=\{ "
+               for mmodule in mmodules do
+                       tpl.add "\"{mmodule.name}\":["
+                       tpl.add "\{txt:\"{mmodule.full_name}\",url:\"{mmodule.nitdoc_url}\"\},"
+                       tpl.add "],"
+               end
+               for mclass in mclasses do
+                       var full_name = mclass.intro.mmodule.full_name
+                       tpl.add "\"{mclass.name}\":["
+                       tpl.add "\{txt:\"{full_name}\",url:\"{mclass.nitdoc_url}\"\},"
+                       tpl.add "],"
+               end
+               for mproperty, mprops in mpropdefs do
+                       tpl.add "\"{mproperty}\":["
+                       for mpropdef in mprops do
+                               var full_name = mpropdef.mclassdef.mclass.full_name
+                               tpl.add "\{txt:\"{full_name}\",url:\"{mpropdef.nitdoc_url}\"\},"
+                       end
+                       tpl.add "],"
+               end
+               tpl.add " \};"
+               return tpl
+       end
 end
 
 # Nitdoc base page
+# Define page structure and properties
 abstract class NitdocPage
 
-       var ctx: NitdocContext
-       var shareurl = "."
+       private var ctx: NitdocContext
+       private var shareurl = "."
 
        init(ctx: NitdocContext) do
                self.ctx = ctx
                if ctx.opt_shareurl.value != null then shareurl = ctx.opt_shareurl.value.as(not null)
        end
 
-       protected fun head do
-               append("<meta charset='utf-8'/>")
-               append("<link rel='stylesheet' href='{shareurl}/css/main.css' type='text/css'/>")
-               append("<link rel='stylesheet' href='{shareurl}/css/Nitdoc.UI.css' type='text/css''/>")
-               append("<link rel='stylesheet' href='{shareurl}/css/Nitdoc.QuickSearch.css' type='text/css'/>")
-               append("<link rel='stylesheet' href='{shareurl}/css/Nitdoc.GitHub.css' type='text/css'/>")
-               append("<link rel='stylesheet' href='{shareurl}/css/Nitdoc.ModalBox.css' type='text/css'/>")
-               var title = ""
-               if ctx.opt_custom_title.value != null then
-                       title = " | {ctx.opt_custom_title.value.to_s}"
+       # Render the page as a html template
+       fun render: Template do
+               var tpl = new TplNitdocPage
+               tpl.head = tpl_head
+               tpl.topmenu = tpl_topmenu
+               tpl.sidebar = tpl_sidebar
+               tpl.content = tpl_content
+               tpl.footer = tpl_footer
+
+               tpl.body_attrs.add(new TagAttribute("data-bootstrap-share", shareurl))
+               if ctx.opt_github_upstream.value != null and ctx.opt_github_base_sha1.value != null then
+                       tpl.body_attrs.add(new TagAttribute("data-github-upstream", ctx.opt_github_upstream.value))
+                       tpl.body_attrs.add(new TagAttribute("data-github-base-sha1", ctx.opt_github_base_sha1.value))
                end
-               append("<title>{self.title}{title}</title>")
+               var requirejs = new TplScript
+               requirejs.attrs.add(new TagAttribute("data-main", "{shareurl}/js/nitdoc"))
+               requirejs.attrs.add(new TagAttribute("src", "{shareurl}/js/lib/require.js"))
+               tpl.scripts.add requirejs
+
+               # piwik tracking
+               var tracker_url = ctx.opt_piwik_tracker.value
+               var site_id = ctx.opt_piwik_site_id.value
+               if tracker_url != null and site_id != null then
+                       tpl.scripts.add new TplPiwikScript(tracker_url, site_id)
+               end
+               return tpl
        end
 
-       protected fun menu do
-               if ctx.opt_custom_menu_items.value != null then
-                       append(ctx.opt_custom_menu_items.value.to_s)
+       # Page title string
+       fun tpl_title: String do
+               if ctx.opt_custom_title.value != null then
+                       return ctx.opt_custom_title.value.to_s
+               else
+                       return "Nitdoc"
                end
        end
 
-       protected fun title: String is abstract
+       # Page <head> template
+       fun tpl_head: TplHead do return new TplHead(tpl_title, shareurl)
 
-       protected fun header do
-               append("<header>")
-               append("<nav class='main'>")
-               append("<ul>")
-               menu
-               append("</ul>")
-               append("</nav>")
-               append("</header>")
+       # Top menu template
+       fun tpl_topmenu: TplTopMenu do
+               var topmenu = new TplTopMenu
+               var custom_elt = ctx.opt_custom_menu.value
+               if custom_elt != null then topmenu.add_raw(custom_elt)
+               return topmenu
        end
 
-       protected fun content is abstract
+       # Page sidebar template
+       # return null if no sidebar for this page
+       fun tpl_sidebar: nullable TplSidebar do return null
 
-       protected fun footer do
-               if ctx.opt_custom_footer_text.value != null then
-                       append("<footer>{ctx.opt_custom_footer_text.value.to_s}</footer>")
+       # Page content template
+       fun tpl_content: Template is abstract
+
+       # Page footer template
+       # return null if no footer for this page
+       fun tpl_footer: nullable TplFooter do
+               if ctx.opt_custom_footer.value != null then
+                       return new TplFooter(ctx.opt_custom_footer.value.to_s)
                end
+               return null
        end
 
-       # Generate a clickable graphviz image using a dot content
-       protected fun generate_dot(dot: String, name: String, alt: String) do
-               var output_dir = ctx.dot_dir
-               if output_dir == null then return
+       # Clickable graphviz image using dot format
+       # return null if no graph for this page
+       fun tpl_graph(dot: FlatBuffer, name: String, alt: String): nullable TplGraph do
+               if ctx.opt_nodot.value then return null
+               var output_dir = ctx.output_dir
                var file = new OFStream.open("{output_dir}/{name}.dot")
                file.write(dot)
                file.close
                sys.system("\{ test -f {output_dir}/{name}.png && test -f {output_dir}/{name}.s.dot && diff {output_dir}/{name}.dot {output_dir}/{name}.s.dot >/dev/null 2>&1 ; \} || \{ cp {output_dir}/{name}.dot {output_dir}/{name}.s.dot && dot -Tpng -o{output_dir}/{name}.png -Tcmapx -o{output_dir}/{name}.map {output_dir}/{name}.s.dot ; \}")
-               append("<article class='graph'>")
-               append("<img src='{name}.png' usemap='#{name}' style='margin:auto' alt='{alt}'/>")
-               append("</article>")
                var fmap = new IFStream.open("{output_dir}/{name}.map")
-               append(fmap.read_all)
+               var map = fmap.read_all
                fmap.close
+               return new TplGraph(name, alt, map)
        end
 
-       # Add a (source) link for a given location
-       protected fun show_source(l: Location): String
+       # A (source) link template for a given location
+       fun tpl_showsource(location: nullable Location): nullable String
        do
-               var source = ctx.source
-               if source == null then
-                       return "({l.file.filename.simplify_path})"
+               if location == null then return null
+               var source = ctx.opt_source.value
+               if source == null then return "({location.file.filename.simplify_path})"
+               # THIS IS JUST UGLY ! (but there is no replace yet)
+               var x = source.split_with("%f")
+               source = x.join(location.file.filename.simplify_path)
+               x = source.split_with("%l")
+               source = x.join(location.line_start.to_s)
+               x = source.split_with("%L")
+               source = x.join(location.line_end.to_s)
+               source = source.simplify_path
+               return " (<a target='_blank' title='Show source' href=\"{source.to_s}\">source</a>)"
+       end
+
+       # MClassDef description template
+       fun tpl_mclassdef_article(mclassdef: MClassDef): TplArticle do
+               var article = mclassdef.tpl_article
+               article.content = new Template
+               if not mclassdef.is_intro then
+                       # add intro synopsys
+                       var intro = mclassdef.mclass.intro
+                       var location = intro.location
+                       var sourcelink = tpl_showsource(location)
+                       var intro_def = intro.tpl_short_definition
+                       intro_def.location = sourcelink
+                       intro_def.github_area = tpl_github(intro.full_namespace, intro.mdoc, location)
+                       article.content.add intro_def
+               end
+               # add mclassdef full description
+               var location = mclassdef.location
+               var sourcelink = tpl_showsource(location)
+               var prop_def = mclassdef.tpl_definition
+               prop_def.location = sourcelink
+               prop_def.github_area = tpl_github(mclassdef.full_namespace, mclassdef.mdoc, location)
+               article.content.add prop_def
+               return article
+       end
+
+       # MPropDef description template
+       fun tpl_mpropdef_article(mpropdef: MPropDef): TplArticle do
+               var article = mpropdef.tpl_article
+               article.content = new Template
+               if not mpropdef.is_intro then
+                       # add intro synopsys
+                       var intro = mpropdef.mproperty.intro
+                       var location = intro.location
+                       var sourcelink = tpl_showsource(location)
+                       var intro_def = intro.tpl_short_definition
+                       intro_def.location = sourcelink
+                       intro_def.github_area = tpl_github(intro.full_namespace, intro.mdoc, location)
+                       article.content.add intro_def
+               end
+               # add mpropdef description
+               var location = mpropdef.location
+               var sourcelink = tpl_showsource(location)
+               var prop_def = mpropdef.tpl_definition
+               prop_def.location = sourcelink
+               prop_def.github_area = tpl_github(mpropdef.full_namespace, mpropdef.mdoc, location)
+               article.content.add prop_def
+               return article
+       end
+
+       # Github area (for Github comment edition plugin)
+       # return null if no github plugin for this page
+       fun tpl_github(namespace: String, mdoc: nullable MDoc, loc: nullable Location): nullable TplGithubArea do
+               if loc == null then return null
+               if ctx.opt_github_gitdir.value == null then return null
+               var gitdir = ctx.opt_github_gitdir.value.as(not null)
+               var location = loc.github(gitdir)
+               var comment: String
+               if mdoc != null then
+                       comment = mdoc.full_comment
                else
-                       # THIS IS JUST UGLY ! (but there is no replace yet)
-                       var x = source.split_with("%f")
-                       source = x.join(l.file.filename.simplify_path)
-                       x = source.split_with("%l")
-                       source = x.join(l.line_start.to_s)
-                       x = source.split_with("%L")
-                       source = x.join(l.line_end.to_s)
-                       source = source.simplify_path
-                       return " (<a target='_blank' title='Show source' href=\"{source.to_s}\">source</a>)"
-               end
-       end
-
-       # Render the page as a html string
-       protected fun render do
-               append("<!DOCTYPE html>")
-               append("<head>")
-               head
-               append("</head>")
-               append("<body")
-               append(" data-bootstrap-share='{shareurl}'")
-               if ctx.opt_github_upstream.value != null and ctx.opt_github_base_sha1.value != null then
-                       append(" data-github-upstream='{ctx.opt_github_upstream.value.as(not null)}'")
-                       append(" data-github-base-sha1='{ctx.opt_github_base_sha1.value.as(not null)}'")
-               end
-               append(">")
-               header
-               var footed = ""
-               if ctx.opt_custom_footer_text.value != null then footed = "footed"
-               append("<div class='page {footed}'>")
-               content
-               append("</div>")
-               footer
-               append("<script data-main=\"{shareurl}/js/nitdoc\" src=\"{shareurl}/js/lib/require.js\"></script>")
-
-               # piwik tracking
-               var tracker_url = ctx.opt_piwik_tracker.value
-               var site_id = ctx.opt_piwik_site_id.value
-               if tracker_url != null and site_id != null then
-                       append("<!-- Piwik -->")
-                       append("<script type=\"text/javascript\">")
-                       append("  var _paq = _paq || [];")
-                       append("  _paq.push([\"trackPageView\"]);")
-                       append("  _paq.push([\"enableLinkTracking\"]);")
-                       append("  (function() \{")
-                       append("    var u=((\"https:\" == document.location.protocol) ? \"https\" : \"http\") + \"://{tracker_url}\";")
-                       append("    _paq.push([\"setTrackerUrl\", u+\"piwik.php\"]);")
-                       append("    _paq.push([\"setSiteId\", \"{site_id}\"]);")
-                       append("    var d=document, g=d.createElement(\"script\"), s=d.getElementsByTagName(\"script\")[0]; g.type=\"text/javascript\";")
-                       append("    g.defer=true; g.async=true; g.src=u+\"piwik.js\"; s.parentNode.insertBefore(g,s);")
-                       append("  \})();")
-                       append(" </script>")
-                       append("<!-- End Piwik Code -->")
-               end
-               append("</body>")
-       end
-
-       # Append a string to the page
-       fun append(s: String) do out.write(s)
-
-       # Save html page in the specified file
-       fun save(file: String) do
-               self.out = new OFStream.open(file)
-               render
-               self.out.close
-       end
-       private var out: nullable OFStream
+                       comment = ""
+               end
+               return new TplGithubArea(comment, namespace, location)
+       end
 end
 
 # The overview page
+# Display a list of modules contained in program
 class NitdocOverview
        super NitdocPage
-       private var mbuilder: ModelBuilder
+
        private var mmodules = new Array[MModule]
 
        init(ctx: NitdocContext) do
                super(ctx)
-               self.mbuilder = ctx.mbuilder
                # get modules
                var mmodules = new HashSet[MModule]
-               for mmodule in mbuilder.model.mmodule_importation_hierarchy do
+               for mmodule in ctx.mbuilder.model.mmodule_importation_hierarchy do
                        if mmodule.name == "<main>" then continue
                        var owner = mmodule.public_owner
                        if owner != null then
@@ -378,46 +427,44 @@ class NitdocOverview
                sorter.sort(self.mmodules)
        end
 
-       redef fun title do return "Overview"
+       redef fun tpl_title do return "Overview | {super}"
 
-       redef fun menu do
-               super
-               append("<li class='current'>Overview</li>")
-               append("<li><a href='search.html'>Search</a></li>")
+       redef fun tpl_topmenu do
+               var topmenu = super
+               topmenu.add_elt("#", "Overview", true)
+               topmenu.add_elt("search.html", "Search", false)
+               return topmenu
        end
 
-       redef fun content do
-               append("<div class='content fullpage'>")
-               var title = "Overview"
+       redef fun tpl_content do
+               var tpl = new TplOverviewPage
+               # title
                if ctx.opt_custom_title.value != null then
-                       title = ctx.opt_custom_title.value.to_s
+                       tpl.title = ctx.opt_custom_title.value.to_s
+               else
+                       tpl.title = "Overview"
                end
-               append("<h1>{title}</h1>")
-               var text = ""
-               if ctx.opt_custom_overview_text.value != null then
-                       text = ctx.opt_custom_overview_text.value.to_s
+               # intro text
+               if ctx.opt_custom_intro.value != null then
+                       tpl.text = ctx.opt_custom_intro.value.to_s
                end
-               append("<article class='overview'>{text}</article>")
-               append("<article class='overview'>")
                # module list
-               append("<h2>Modules</h2>")
-               append("<ul>")
                for mmodule in mmodules do
-                       if mbuilder.mmodule2nmodule.has_key(mmodule) then
-                               var amodule = mbuilder.mmodule2nmodule[mmodule]
-                               append("<li>")
-                               mmodule.html_link(self)
-                               append("&nbsp;{amodule.short_comment}</li>")
+                       if mmodule.mdoc != null then
+                               var mtpl = new Template
+                               mtpl.add mmodule.tpl_link
+                               mtpl.add "&nbsp;"
+                               mtpl.add mmodule.mdoc.short_comment
+                               tpl.modules.add mtpl
                        end
                end
-               append("</ul>")
                # module graph
-               process_generate_dot
-               append("</article>")
-               append("</div>")
+               tpl.graph = tpl_dot
+               return tpl
        end
 
-       private fun process_generate_dot do
+       # Genrate dot and template for module hierarchy
+       fun tpl_dot: nullable TplGraph do
                # build poset with public owners
                var poset = new POSet[MModule]
                for mmodule in mmodules do
@@ -434,187 +481,170 @@ class NitdocOverview
                var op = new FlatBuffer
                op.append("digraph dep \{ rankdir=BT; node[shape=none,margin=0,width=0,height=0,fontsize=10]; edge[dir=none,color=gray]; ranksep=0.2; nodesep=0.1;\n")
                for mmodule in poset do
-                       op.append("\"{mmodule.name}\"[URL=\"{mmodule.url}\"];\n")
+                       op.append("\"{mmodule.name}\"[URL=\"{mmodule.nitdoc_url}\"];\n")
                        for omodule in poset[mmodule].direct_greaters do
                                op.append("\"{mmodule.name}\"->\"{omodule.name}\";\n")
                        end
                end
                op.append("\}\n")
-               generate_dot(op.to_s, "dep", "Modules hierarchy")
+               return tpl_graph(op, "dep", "Modules hierarchy")
        end
 end
 
 # The search page
+# Display a list of modules, classes and properties
 class NitdocSearch
        super NitdocPage
 
-       init(ctx: NitdocContext) do
-               super(ctx)
-       end
+       init(ctx: NitdocContext) do super(ctx)
 
-       redef fun title do return "Search"
+       redef fun tpl_title do return "Search | {super}"
 
-       redef fun menu do
-               super
-               append("<li><a href='index.html'>Overview</a></li>")
-               append("<li class='current'>Search</li>")
+       redef fun tpl_topmenu do
+               var topmenu = super
+               topmenu.add_elt("index.html", "Overview", false)
+               topmenu.add_elt("#", "Search", true)
+               return topmenu
        end
 
-       redef fun content do
-               append("<div class='content fullpage'>")
-               append("<h1>{title}</h1>")
-               module_column
-               classes_column
-               properties_column
-               append("</div>")
+       redef fun tpl_content do
+               var tpl = new TplSearchPage
+               # title
+               tpl.title = "Search"
+               # modules list
+               for mmodule in modules_list do
+                       tpl.modules.add mmodule.tpl_link
+               end
+               # classes list
+               for mclass in classes_list do
+                       tpl.classes.add mclass.tpl_link
+               end
+               # properties list
+               for mproperty in mprops_list do
+                       var m = new Template
+                       m.add mproperty.intro.tpl_link
+                       m.add " ("
+                       m.add mproperty.intro.mclassdef.mclass.tpl_link
+                       m.add ")"
+                       tpl.props.add m
+               end
+               return tpl
        end
 
-       # Add to content modules column
-       private fun module_column do
-               var sorted = ctx.mbuilder.model.mmodule_importation_hierarchy.to_a
-               var sorter = new MModuleNameSorter
-               sorter.sort(sorted)
-               append("<article class='modules filterable'>")
-               append("<h2>Modules</h2>")
-               append("<ul>")
-               for mmodule in sorted do
+       # Extract mmodule list to display (sorted by name)
+       private fun modules_list: Array[MModule] do
+               var sorted = new Array[MModule]
+               for mmodule in ctx.mbuilder.model.mmodule_importation_hierarchy do
                        if mmodule.name == "<main>" then continue
-                       append("<li>")
-                       mmodule.html_link(self)
-                       append("</li>")
+                       sorted.add mmodule
                end
-               append("</ul>")
-               append("</article>")
+               var sorter = new MModuleNameSorter
+               sorter.sort(sorted)
+               return sorted
        end
 
-       # Add to content classes modules
-       private fun classes_column do
-               var sorted = ctx.mbuilder.model.mclasses
-               var sorter = new MClassNameSorter
-               sorter.sort(sorted)
-               append("<article class='modules filterable'>")
-               append("<h2>Classes</h2>")
-               append("<ul>")
-               for mclass in sorted do
+       # Extract mclass list to display (sorted by name)
+       private fun classes_list: Array[MClass] do
+               var sorted = new Array[MClass]
+               for mclass in ctx.mbuilder.model.mclasses do
                        if mclass.visibility < ctx.min_visibility then continue
-                       append("<li>")
-                       mclass.html_link(self)
-                       append("</li>")
+                       sorted.add mclass
                end
-               append("</ul>")
-               append("</article>")
+               var sorter = new MClassNameSorter
+               sorter.sort(sorted)
+               return sorted
        end
 
-       # Insert the properties column of fullindex page
-       private fun properties_column do
-               var sorted = ctx.mbuilder.model.mproperties
-               var sorter = new MPropertyNameSorter
-               sorter.sort(sorted)
-               append("<article class='modules filterable'>")
-               append("<h2>Properties</h2>")
-               append("<ul>")
-               for mproperty in sorted do
+       # Extract mproperty list to display (sorted by name)
+       private fun mprops_list: Array[MProperty] do
+               var sorted = new Array[MProperty]
+               for mproperty in ctx.mbuilder.model.mproperties do
                        if mproperty.visibility < ctx.min_visibility then continue
                        if mproperty isa MAttribute then continue
-                       append("<li>")
-                       mproperty.intro.html_link(self)
-                       append(" (")
-                       mproperty.intro.mclassdef.mclass.html_link(self)
-                       append(")</li>")
+                       sorted.add mproperty
                end
-               append("</ul>")
-               append("</article>")
+               var sorter = new MPropertyNameSorter
+               sorter.sort(sorted)
+               return sorted
        end
-
 end
 
 # A module page
+# Display the list of introduced and redefined classes in module
 class NitdocModule
        super NitdocPage
 
        private var mmodule: MModule
-       private var mbuilder: ModelBuilder
-       private var local_mclasses = new HashSet[MClass]
-       private var intro_mclasses = new HashSet[MClass]
-       private var redef_mclasses = new HashSet[MClass]
+       private var intro_mclassdefs: Set[MClassDef]
+       private var redef_mclassdefs: Set[MClassDef]
+       private var sorted_intro_mclassdefs: Array[MClassDef]
+       private var sorted_redef_mclassdefs: Array[MClassDef]
 
        init(mmodule: MModule, ctx: NitdocContext) do
-               super(ctx)
                self.mmodule = mmodule
-               self.mbuilder = ctx.mbuilder
-               # get local mclasses
-               for m in mmodule.in_nesting.greaters do
-                       for mclassdef in m.mclassdefs do
-                               if mclassdef.mclass.visibility < ctx.min_visibility then continue
-                               if mclassdef.is_intro then
-                                       intro_mclasses.add(mclassdef.mclass)
-                               else
-                                       if mclassdef.mclass.mpropdefs_in_module(self).is_empty then continue
-                                       redef_mclasses.add(mclassdef.mclass)
-                               end
-                               local_mclasses.add(mclassdef.mclass)
-                       end
-               end
+               var sorter = new MClassDefNameSorter
+               intro_mclassdefs = in_nesting_intro_mclassdefs(ctx.min_visibility)
+               sorted_intro_mclassdefs = intro_mclassdefs.to_a
+               sorter.sort sorted_intro_mclassdefs
+               redef_mclassdefs = in_nesting_redef_mclassdefs(ctx.min_visibility)
+               sorted_redef_mclassdefs = redef_mclassdefs.to_a
+               sorter.sort sorted_redef_mclassdefs
+               super(ctx)
        end
 
-       redef fun title do
-               if mbuilder.mmodule2nmodule.has_key(mmodule) and not mbuilder.mmodule2nmodule[mmodule].short_comment.is_empty then
-                       var nmodule = mbuilder.mmodule2nmodule[mmodule]
-                       return "{mmodule.html_name} module | {nmodule.short_comment}"
+       redef fun tpl_title do
+               if mmodule.mdoc != null then
+                       return "{mmodule.nitdoc_name} module | {mmodule.mdoc.short_comment} | {super}"
                else
-                       return "{mmodule.html_name} module"
+                       return "{mmodule.nitdoc_name} module | {super}"
                end
        end
 
-       redef fun menu do
-               super
-               append("<li><a href='index.html'>Overview</a></li>")
-               append("<li class='current'>{mmodule.html_name}</li>")
-               append("<li><a href='search.html'>Search</a></li>")
+       redef fun tpl_topmenu do
+               var topmenu = super
+               topmenu.add_elt("index.html", "Overview", false)
+               topmenu.add_elt("#", "{mmodule.nitdoc_name}", true)
+               topmenu.add_elt("search.html", "Search", false)
+               return topmenu
        end
 
-       redef fun content do
-               append("<div class='sidebar'>")
-               classes_column
-               importation_column
-               append("</div>")
-               append("<div class='content'>")
-               module_doc
-               append("</div>")
+       redef fun tpl_sidebar do
+               var sidebar = new TplSidebar
+               tpl_sidebar_classes(sidebar)
+               tpl_sidebar_inheritance(sidebar)
+               return sidebar
        end
 
-       private fun classes_column do
-               var sorter = new MClassNameSorter
-               var sorted = new Array[MClass]
-               sorted.add_all(intro_mclasses)
-               sorted.add_all(redef_mclasses)
-               sorter.sort(sorted)
-               if not sorted.is_empty then
-                       append("<nav class='properties filterable'>")
-                       append("<h3>Classes</h3>")
-                       append("<h4>Classes</h4>")
-                       append("<ul>")
-                       for mclass in sorted do mclass.html_sidebar_item(self)
-                       append("</ul>")
-                       append("</nav>")
+       # Classes to display on sidebar
+       fun tpl_sidebar_classes(sidebar: TplSidebar) do
+               var box = new TplSidebarBox("Class Definitions")
+               var group = new TplSidebarGroup("Introductions")
+               for mclassdef in sorted_intro_mclassdefs do
+                       tpl_sidebar_item(mclassdef, group)
                end
+               box.elts.add group
+               group = new TplSidebarGroup("Refinements")
+               for mclassdef in sorted_redef_mclassdefs do
+                       if intro_mclassdefs.has(mclassdef.mclass.intro) then continue
+                       tpl_sidebar_item(mclassdef, group)
+               end
+               box.elts.add group
+               sidebar.boxes.add box
        end
 
-       private fun importation_column do
-               append("<nav>")
-               append("<h3>Module Hierarchy</h3>")
+       # Module inheritance to display on sidebar
+       fun tpl_sidebar_inheritance(sidebar: TplSidebar) do
+               var box = new TplSidebarBox("Module Hierarchy")
+               box.elts.add tpl_sidebar_group("Nested Modules", mmodule.in_nesting.direct_greaters.to_a)
                var dependencies = new Array[MModule]
                for dep in mmodule.in_importation.greaters do
-                       if dep == mmodule or dep.direct_owner == mmodule or dep.public_owner == mmodule then continue
+                       if dep == mmodule or
+                               dep.direct_owner == mmodule or
+                               dep.public_owner == mmodule then continue
                        dependencies.add(dep)
                end
-               if mmodule.in_nesting.direct_greaters.length > 0 then
-                       append("<h4>Nested Modules</h4>")
-                       display_module_list(mmodule.in_nesting.direct_greaters.to_a)
-               end
                if dependencies.length > 0 then
-                       append("<h4>All dependencies</h4>")
-                       display_module_list(dependencies)
+                       box.elts.add tpl_sidebar_group("All dependencies", dependencies)
                end
                var clients = new Array[MModule]
                for dep in mmodule.in_importation.smallers do
@@ -623,58 +653,47 @@ class NitdocModule
                        clients.add(dep)
                end
                if clients.length > 0 then
-                       append("<h4>All clients</h4>")
-                       display_module_list(clients)
+                       box.elts.add tpl_sidebar_group("All clients", clients)
                end
-               append("</nav>")
+               sidebar.boxes.add box
        end
 
-       private fun display_module_list(list: Array[MModule]) do
-               append("<ul>")
-               var sorter = new MModuleNameSorter
-               sorter.sort(list)
-               for m in list do
-                       append("<li>")
-                       m.html_link(self)
-                       append("</li>")
+       private fun tpl_sidebar_item(mclassdef: MClassDef, group: TplSidebarGroup) do
+               if mclassdef.is_intro then
+                       group.add_bullet("I", "Introduced", mclassdef.tpl_link_anchor, ["intro"])
+               else
+                       group.add_bullet("R", "Redefined", mclassdef.tpl_link_anchor, ["redef"])
                end
-               append("</ul>")
        end
 
-       private fun module_doc do
-               # title
-               append("<h1>{mmodule.html_name}</h1>")
-               append("<div class='subtitle info'>")
-               mmodule.html_signature(self)
-               append("</div>")
-               # comment
-               mmodule.html_comment(self)
-               process_generate_dot
-               # classes
+       private fun tpl_sidebar_group(name: String, elts: Array[MModule]): TplSidebarGroup do
+               var group = new TplSidebarGroup(name)
+               for elt in elts do
+                       group.add_elt(elt.tpl_link, new Array[String])
+               end
+               return group
+       end
+
+       redef fun tpl_content do
                var class_sorter = new MClassNameSorter
-               # intro
-               if not intro_mclasses.is_empty then
-                       var sorted = new Array[MClass]
-                       sorted.add_all(intro_mclasses)
-                       class_sorter.sort(sorted)
-                       append("<section class='classes'>")
-                       append("<h2 class='section-header'>Introduced classes</h2>")
-                       for mclass in sorted do mclass.html_full_desc(self)
-                       append("</section>")
-               end
-               # redefs
-               var redefs = new Array[MClass]
-               for mclass in redef_mclasses do if not intro_mclasses.has(mclass) then redefs.add(mclass)
-               class_sorter.sort(redefs)
-               if not redefs.is_empty then
-                       append("<section class='classes'>")
-                       append("<h2 class='section-header'>Refined classes</h2>")
-                       for mclass in redefs do mclass.html_full_desc(self)
-                       append("</section>")
-               end
-       end
-
-       private fun process_generate_dot do
+               var tpl = new TplModulePage
+               tpl.title = mmodule.nitdoc_name
+               tpl.subtitle = mmodule.tpl_signature
+               tpl.definition = mmodule.tpl_definition
+               var location = mmodule.location
+               tpl.definition.location = tpl_showsource(location)
+               tpl.definition.github_area = tpl_github(mmodule.full_namespace, mmodule.mdoc, location)
+               tpl.graph = tpl_dot
+               for mclassdef in sorted_intro_mclassdefs do tpl.intros.add tpl_mclassdef_article(mclassdef)
+               for mclassdef in sorted_redef_mclassdefs do
+                       if intro_mclassdefs.has(mclassdef.mclass.intro) then continue
+                       tpl.redefs.add tpl_mclassdef_article(mclassdef)
+               end
+               return tpl
+       end
+
+       # Genrate dot hierarchy for class inheritance
+       fun tpl_dot: nullable TplGraph do
                # build poset with public owners
                var poset = new POSet[MModule]
                for mmodule in self.mmodule.in_importation.poset do
@@ -709,367 +728,339 @@ class NitdocModule
                        if mmodule == self.mmodule then
                                op.append("\"{mmodule.name}\"[shape=box,margin=0.03];\n")
                        else
-                               op.append("\"{mmodule.name}\"[URL=\"{mmodule.url}\"];\n")
+                               op.append("\"{mmodule.name}\"[URL=\"{mmodule.nitdoc_url}\"];\n")
                        end
                        for omodule in poset[mmodule].direct_greaters do
                                op.append("\"{mmodule.name}\"->\"{omodule.name}\";\n")
                        end
                end
                op.append("\}\n")
-               generate_dot(op.to_s, name, "Dependency graph for module {mmodule.name}")
+               return tpl_graph(op, name, "Dependency graph for module {mmodule.name}")
+       end
+
+       private fun in_nesting_intro_mclassdefs(min_visibility: MVisibility): Set[MClassDef] do
+               var res = new HashSet[MClassDef]
+               for mmodule in self.mmodule.in_nesting.greaters do
+                       res.add_all mmodule.intro_mclassdefs(min_visibility)
+               end
+               return res
+       end
+
+       private fun in_nesting_redef_mclassdefs(min_visibility: MVisibility): Set[MClassDef] do
+               var res = new HashSet[MClassDef]
+               for mmodule in self.mmodule.in_nesting.greaters do
+                       res.add_all mmodule.redef_mclassdefs(min_visibility)
+               end
+               return res
        end
 end
 
 # A class page
+# Display a list properties defined or redefined for this class
 class NitdocClass
        super NitdocPage
 
        private var mclass: MClass
-       private var vtypes = new HashSet[MVirtualTypeDef]
-       private var consts = new HashSet[MMethodDef]
-       private var meths = new HashSet[MMethodDef]
-       private var inherited = new HashSet[MPropDef]
+       private var inherited_mpropdefs: Set[MPropDef]
+       private var intro_mpropdefs: Set[MPropDef]
+       private var redef_mpropdefs: Set[MPropDef]
+       private var all_mpropdefs: Set[MPropDef]
 
        init(mclass: MClass, ctx: NitdocContext) do
-               super(ctx)
                self.mclass = mclass
-               # load properties
-               var locals = new HashSet[MProperty]
+               super(ctx)
+               intro_mpropdefs = mclass_intro_mpropdefs
+               redef_mpropdefs = mclass_redef_mpropdefs
+               inherited_mpropdefs = in_nesting_inherited_mpropedefs
+               all_mpropdefs = new HashSet[MPropDef]
+               all_mpropdefs.add_all intro_mpropdefs
+               all_mpropdefs.add_all redef_mpropdefs
+               all_mpropdefs.add_all inherited_mpropdefs
+       end
+
+       private fun in_nesting_inherited_mpropedefs: Set[MPropDef] do
+               var res = new HashSet[MPropDef]
+               var local = mclass.local_mproperties(ctx.min_visibility)
+               for mprop in mclass.inherited_mproperties(ctx.mainmodule, ctx.min_visibility) do
+                       if local.has(mprop) then continue
+                       if mprop isa MMethod and mprop.is_init then continue
+                       res.add mprop.intro
+               end
+               return res
+       end
+
+       private fun mclass_intro_mpropdefs: Set[MPropDef] do
+               var res = new HashSet[MPropDef]
                for mclassdef in mclass.mclassdefs do
+                       var owner = mclassdef.mmodule.public_owner
+                       if owner == null then owner = mclassdef.mmodule
                        for mpropdef in mclassdef.mpropdefs do
-                               if mpropdef.mproperty.visibility < ctx.min_visibility then continue
-                               if mpropdef isa MVirtualTypeDef then vtypes.add(mpropdef)
-                               if mpropdef isa MMethodDef then
-                                       if mpropdef.mproperty.is_init then
-                                               consts.add(mpropdef)
-                                       else
-                                               meths.add(mpropdef)
-                                       end
-                               end
-                               locals.add(mpropdef.mproperty)
+                               if not mpropdef.is_intro then continue
+                               if owner != mclass.public_owner then continue
+                               var mprop = mpropdef.mproperty
+                               if mprop isa MMethod and mprop.is_init and mclass.is_abstract then continue
+                               if mprop.visibility < ctx.min_visibility then continue
+                               res.add mpropdef
                        end
                end
-               # get inherited properties
-               for pclass in mclass.in_hierarchy(ctx.mainmodule).greaters do
-                       if pclass == mclass then continue
-                       for pclassdef in pclass.mclassdefs do
-                               for mprop in pclassdef.intro_mproperties do
-                                       var mpropdef = mprop.intro
-                                       if mprop.visibility < ctx.min_visibility then continue # skip if not correct visibiility
-                                       if locals.has(mprop) then continue # skip if local
-                                       if mclass.name != "Object" and mprop.intro_mclassdef.mclass.name == "Object" and (mprop.visibility <= protected_visibility or mprop.intro_mclassdef.mmodule.public_owner == null or mprop.intro_mclassdef.mmodule.public_owner.name != "standard") then continue # skip toplevels
-                                       if mpropdef isa MVirtualTypeDef then vtypes.add(mpropdef)
-                                       if mpropdef isa MMethodDef then
-                                               if mpropdef.mproperty.is_init then
-                                                       consts.add(mpropdef)
-                                               else
-                                                       meths.add(mpropdef)
-                                               end
-                                       end
-                                       inherited.add(mpropdef)
-                               end
+               return res
+       end
+
+       private fun mclass_redef_mpropdefs: Set[MPropDef] do
+               var res = new HashSet[MPropDef]
+               for mclassdef in mclass.mclassdefs do
+                       if mclassdef == mclass.intro then continue
+                       var owner = mclassdef.mmodule.public_owner
+                       if owner == null then owner = mclassdef.mmodule
+                       for mpropdef in mclassdef.mpropdefs do
+                               if owner == mclass.public_owner then continue
+                               if mpropdef.mproperty.visibility < ctx.min_visibility then continue
+                               res.add mpropdef
                        end
                end
+               return res
        end
 
-       redef fun title do
-               var nclass = ctx.mbuilder.mclassdef2nclassdef[mclass.intro]
-               if nclass isa AStdClassdef then
-                       return "{mclass.html_name} class | {nclass.short_comment}"
+       redef fun tpl_title do
+               if mclass.mdoc != null then
+                       return "{mclass.nitdoc_name} class | {mclass.mdoc.short_comment} | {super}"
                else
-                       return "{mclass.html_name} class"
+                       return "{mclass.nitdoc_name} class | {super}"
                end
        end
 
-       redef fun menu do
-               super
-               append("<li><a href='index.html'>Overview</a></li>")
-               var public_owner = mclass.public_owner
-               if public_owner == null then
-                       append("<li>")
-                       mclass.intro_mmodule.html_link(self)
-                       append("</li>")
+       redef fun tpl_topmenu do
+               var topmenu = super
+               var mmodule: MModule
+               if mclass.public_owner == null then
+                       mmodule = mclass.intro_mmodule
                else
-                       append("<li>")
-                       public_owner.html_link(self)
-                       append("</li>")
+                       mmodule = mclass.public_owner.as(not null)
                end
-               append("<li class='current'>{mclass.html_name}</li>")
-               append("<li><a href='search.html'>Search</a></li>")
+               topmenu.add_elt("index.html", "Overview", false)
+               topmenu.add_elt("{mmodule.nitdoc_url}", "{mmodule.nitdoc_name}", false)
+               topmenu.add_elt("#", "{mclass.nitdoc_name}", true)
+               topmenu.add_elt("search.html", "Search", false)
+               return topmenu
        end
 
-       redef fun content do
-               append("<div class='sidebar'>")
-               properties_column
-               inheritance_column
-               append("</div>")
-               append("<div class='content'>")
-               class_doc
-               append("</div>")
+       redef fun tpl_sidebar do
+               var sidebar = new TplSidebar
+               tpl_sidebar_properties(sidebar)
+               tpl_sidebar_inheritance(sidebar)
+               return sidebar
        end
 
-       private fun properties_column do
+       # Property list to display in sidebar
+       fun tpl_sidebar_properties(sidebar: TplSidebar) do
+               var kind_map = sort_by_kind(all_mpropdefs)
                var sorter = new MPropDefNameSorter
-               append("<nav class='properties filterable'>")
-               append("<h3>Properties</h3>")
+               var box = new TplSidebarBox("Properties")
                # virtual types
-               if vtypes.length > 0 then
-                       var vts = new Array[MVirtualTypeDef]
-                       vts.add_all(vtypes)
-                       sorter.sort(vts)
-                       append("<h4>Virtual Types</h4>")
-                       append("<ul>")
-                       for mprop in vts do
-                               mprop.html_sidebar_item(self)
-                       end
-                       append("</ul>")
+               var elts = kind_map["type"].to_a
+               sorter.sort(elts)
+               var group = new TplSidebarGroup("Virtual Types")
+               for mprop in elts do
+                       tpl_sidebar_item(mprop, group)
                end
+               box.elts.add group
                # constructors
-               if consts.length > 0 then
-                       var cts = new Array[MMethodDef]
-                       cts.add_all(consts)
-                       sorter.sort(cts)
-                       append("<h4>Constructors</h4>")
-                       append("<ul>")
-                       for mprop in cts do
-                               if mprop.mproperty.name == "init" and mprop.mclassdef.mclass != mclass then continue
-                               mprop.html_sidebar_item(self)
-                       end
-                       append("</ul>")
+               elts = kind_map["init"].to_a
+               sorter.sort(elts)
+               group = new TplSidebarGroup("Constructors")
+               for mprop in elts do
+                       tpl_sidebar_item(mprop, group)
                end
+               box.elts.add group
                # methods
-               if meths.length > 0 then
-                       var mts = new Array[MMethodDef]
-                       mts.add_all(meths)
-                       sorter.sort(mts)
-                       append("<h4>Methods</h4>")
-                       append("<ul>")
-                       for mprop in mts do
-                               mprop.html_sidebar_item(self)
-                       end
-                       append("</ul>")
+               elts = kind_map["fun"].to_a
+               sorter.sort(elts)
+               group = new TplSidebarGroup("Methods")
+               for mprop in elts do
+                       tpl_sidebar_item(mprop, group)
                end
-               append("</nav>")
+               box.elts.add group
+               sidebar.boxes.add box
        end
 
-       private fun inheritance_column do
+       # Class inheritance to display in sidebar
+       fun tpl_sidebar_inheritance(sidebar: TplSidebar) do
                var sorted = new Array[MClass]
                var sorterp = new MClassNameSorter
-               append("<nav>")
-               append("<h3>Inheritance</h3>")
+               var box = new TplSidebarBox("Inheritance")
                var greaters = mclass.in_hierarchy(ctx.mainmodule).greaters.to_a
                if greaters.length > 1 then
                        ctx.mainmodule.linearize_mclasses(greaters)
-                       append("<h4>Superclasses</h4>")
-                       append("<ul>")
-                       for sup in greaters do
-                               if sup == mclass then continue
-                               append("<li>")
-                               sup.html_link(self)
-                               append("</li>")
-                       end
-                       append("</ul>")
+                       box.elts.add tpl_sidebar_group("Superclasses", greaters)
                end
                var smallers = mclass.in_hierarchy(ctx.mainmodule).smallers.to_a
                var direct_smallers = mclass.in_hierarchy(ctx.mainmodule).direct_smallers.to_a
                if smallers.length <= 1 then
-                       append("<h4>No Known Subclasses</h4>")
+                       box.elts.add(new TplSidebarGroup("No Known Subclasses"))
                else if smallers.length <= 100 then
                        ctx.mainmodule.linearize_mclasses(smallers)
-                       append("<h4>Subclasses</h4>")
-                       append("<ul>")
-                       for sub in smallers do
-                               if sub == mclass then continue
-                               append("<li>")
-                               sub.html_link(self)
-                               append("</li>")
-                       end
-                       append("</ul>")
+                       box.elts.add tpl_sidebar_group("Subclasses", smallers)
                else if direct_smallers.length <= 100 then
                        ctx.mainmodule.linearize_mclasses(direct_smallers)
-                       append("<h4>Direct Subclasses Only</h4>")
-                       append("<ul>")
-                       for sub in direct_smallers do
-                               if sub == mclass then continue
-                               append("<li>")
-                               sub.html_link(self)
-                               append("</li>")
-                       end
-                       append("</ul>")
+                       box.elts.add tpl_sidebar_group("Direct Subclasses Only", direct_smallers)
                else
-                       append("<h4>Too much Subclasses to list</h4>")
+                       box.elts.add(new TplSidebarGroup("Too much Subclasses to list"))
                end
-               append("</nav>")
+               sidebar.boxes.add box
        end
 
-       private fun class_doc do
-               # title
-               append("<h1>{mclass.html_name}{mclass.html_short_signature}</h1>")
-               append("<div class='subtitle info'>")
-               if mclass.visibility < public_visibility then append("{mclass.visibility.to_s} ")
-               append("{mclass.kind.to_s} ")
-               mclass.html_namespace(self)
-               append("{mclass.html_short_signature}</div>")
-               # comment
-               mclass.html_comment(self)
-               process_generate_dot
-               # concerns
-               var concern2meths = new ArrayMap[MModule, Array[MMethodDef]]
-               var sorted_meths = new Array[MMethodDef]
-               var sorted = new Array[MModule]
-               sorted_meths.add_all(meths)
-               ctx.mainmodule.linearize_mpropdefs(sorted_meths)
-               for meth in meths do
-                       if inherited.has(meth) then continue
-                       var mmodule = meth.mclassdef.mmodule
-                       if not concern2meths.has_key(mmodule) then
-                               sorted.add(mmodule)
-                               concern2meths[mmodule] = new Array[MMethodDef]
-                       end
-                       concern2meths[mmodule].add(meth)
+       private fun tpl_sidebar_item(mprop: MPropDef, group: TplSidebarGroup) do
+               if mprop.is_intro and mprop.mclassdef.mclass == mclass then
+                       group.add_bullet("I", "Introduced", mprop.tpl_link, ["intro"])
+               else if mprop.is_intro and mprop.mclassdef.mclass != mclass then
+                       group.add_bullet("H", "Inherited", mprop.tpl_link, ["inherit"])
+               else
+                       group.add_bullet("R", "Redefined", mprop.tpl_link, ["redef"])
                end
-               var sections = new ArrayMap[MModule, Array[MModule]]
-               for mmodule in concern2meths.keys do
-                       var owner = mmodule.public_owner
-                       if owner == null then owner = mmodule
-                       if not sections.has_key(owner) then sections[owner] = new Array[MModule]
-                       if owner != mmodule then sections[owner].add(mmodule)
-               end
-               append("<section class='concerns'>")
-               append("<h2 class='section-header'>Concerns</h2>")
-               append("<ul>")
-               for owner, mmodules in sections do
-                       var nowner = ctx.mbuilder.mmodule2nmodule[owner]
-                       append("<li>")
-                       if nowner.short_comment.is_empty then
-                               append("<a href=\"#{owner.anchor}\">{owner.html_name}</a>")
-                       else
-                               append("<a href=\"#{owner.anchor}\">{owner.html_name}</a>: {nowner.short_comment}")
-                       end
-                       if not mmodules.is_empty then
-                               append("<ul>")
-                               for mmodule in mmodules do
-                                       var nmodule = ctx.mbuilder.mmodule2nmodule[mmodule]
-                                       if nmodule.short_comment.is_empty then
-                                               append("<li><a href=\"#{mmodule.anchor}\">{mmodule.html_name}</a></li>")
-                                       else
-                                               append("<li><a href=\"#{mmodule.anchor}\">{mmodule.html_name}</a>: {nmodule.short_comment}</li>")
-                                       end
-                               end
-                               append("</ul>")
-                       end
-                       append("</li>")
+       end
+
+       private fun tpl_sidebar_group(name: String, elts: Array[MClass]): TplSidebarGroup do
+               var group = new TplSidebarGroup(name)
+               for elt in elts do
+                       if elt == mclass then continue
+                       group.add_elt(elt.tpl_link, new Array[String])
                end
-               append("</ul>")
-               append("</section>")
+               return group
+       end
+
+       redef fun tpl_content do
+               var intro = mclass.intro
+               var tpl = new TplClassPage
+               tpl.title = "{mclass.nitdoc_name}{mclass.tpl_short_signature}"
+               tpl.subtitle = mclass.tpl_namespace_with_signature
+               tpl.definition = intro.tpl_definition
+               var location = intro.location
+               tpl.definition.location = tpl_showsource(location)
+               tpl.definition.github_area = tpl_github(intro.full_namespace, intro.mdoc, location)
+               tpl.graph = tpl_dot
+
                # properties
                var prop_sorter = new MPropDefNameSorter
-               var lmmodule = new List[MModule]
-               var nclass = ctx.mbuilder.mclassdef2nclassdef[mclass.intro]
-               # virtual and formal types
-               var local_vtypes = new Array[MVirtualTypeDef]
-               for vt in vtypes do if not inherited.has(vt) then local_vtypes.add(vt)
-               if local_vtypes.length > 0 or mclass.arity > 0 then
-                       append("<section class='types'>")
-                       append("<h2>Formal and Virtual Types</h2>")
-                       # formal types
-                       if mclass.arity > 0 and nclass isa AStdClassdef then
-                               for ft, bound in mclass.parameter_types do
-                                       append("<article id='FT_{ft}'>")
-                                       append("<h3 class='signature' data-untyped-signature='{ft.to_s}'><span>{ft}: ")
-                                       bound.html_link(self)
-                                       append("</span></h3>")
-                                       append("<div class=\"info\">formal generic type</div>")
-                                       append("</article>")
-                               end
-                       end
-                       # virtual types
-                       prop_sorter.sort(local_vtypes)
-                       for prop in local_vtypes do prop.html_full_desc(self, self.mclass)
-                       append("</section>")
-               end
+               var kind_map = sort_by_kind(intro_mpropdefs)
+
+               # virtual types
+               var elts = kind_map["type"].to_a
+               prop_sorter.sort(elts)
+               for elt in elts do tpl.types.add tpl_mpropdef_article(elt)
+
                # constructors
-               var local_consts = new Array[MMethodDef]
-               for const in consts do if not inherited.has(const) then local_consts.add(const)
-               prop_sorter.sort(local_consts)
-               if local_consts.length > 0 then
-                       append("<section class='constructors'>")
-                       append("<h2 class='section-header'>Constructors</h2>")
-                       for prop in local_consts do prop.html_full_desc(self, self.mclass)
-                       append("</section>")
-               end
-               # methods
-               if not concern2meths.is_empty then
-                       append("<section class='methods'>")
-                       append("<h2 class='section-header'>Methods</h2>")
-                       for owner, mmodules in sections do
-                               append("<a id=\"{owner.anchor}\"></a>")
-                               if owner != mclass.intro_mmodule and owner != mclass.public_owner then
-                                       var nowner = ctx.mbuilder.mmodule2nmodule[owner]
-                                       append("<h3 class=\"concern-toplevel\">Methods refined in ")
-                                       owner.html_link(self)
-                                       append("</h3>")
-                                       append("<p class=\"concern-doc\">")
-                                       owner.html_link(self)
-                                       if not nowner.short_comment.is_empty then
-                                               append(": {nowner.short_comment}")
+               elts = kind_map["init"].to_a
+               prop_sorter.sort(elts)
+               for elt in elts do tpl.inits.add tpl_mpropdef_article(elt)
+
+               # intro methods
+               elts = kind_map["fun"].to_a
+               prop_sorter.sort(elts)
+               for elt in elts do tpl.methods.add tpl_mpropdef_article(elt)
+
+               # redef methods
+               kind_map = sort_by_kind(redef_mpropdefs)
+               var module_sorter = new MModuleNameSorter
+               var module_map = sort_by_mmodule(kind_map["fun"])
+               var owner_map = sort_by_public_owner(module_map.keys)
+               var owners = owner_map.keys.to_a
+               module_sorter.sort owners
+
+               var ctpl = new TplConcernList
+               var mtpl = new Template
+               for owner in owners do
+                       # concerns list
+                       var octpl = new TplConcernListElt
+                       octpl.anchor = "#{owner.nitdoc_anchor}"
+                       octpl.name = owner.nitdoc_name
+                       if owner.mdoc != null then
+                               octpl.comment = owner.mdoc.short_comment
+                       end
+                       ctpl.elts.add octpl
+                       # concern section
+                       var otpl = new TplTopConcern
+                       otpl.anchor = owner.nitdoc_anchor
+                       otpl.concern = owner.tpl_link
+                       mtpl.add otpl
+
+                       var mmodules = owner_map[owner].to_a
+                       module_sorter.sort mmodules
+                       var stpl = new TplConcernList
+                       for mmodule in mmodules do
+                               # concerns list
+                               if mmodule != owner then
+                                       var mctpl = new TplConcernListElt
+                                       mctpl.anchor = "#{mmodule.nitdoc_anchor}"
+                                       mctpl.name = mmodule.nitdoc_name
+                                       if mmodule.mdoc != null then
+                                               mctpl.comment = mmodule.mdoc.short_comment
                                        end
-                                       append("</p>")
-                               end
-                               if concern2meths.has_key(owner) then
-                                       var mmethods = concern2meths[owner]
-                                       prop_sorter.sort(mmethods)
-                                       for prop in mmethods do prop.html_full_desc(self, self.mclass)
-                               end
-                               for mmodule in mmodules do
-                                       append("<a id=\"{mmodule.anchor}\"></a>")
-                                       var nmodule = ctx.mbuilder.mmodule2nmodule[mmodule]
-                                       if mmodule != mclass.intro_mmodule and mmodule != mclass.public_owner then
-                                               append("<p class=\"concern-doc\">")
-                                               mmodule.html_link(self)
-                                               if not nmodule.short_comment.is_empty then
-                                                       append(": {nmodule.short_comment}")
-                                               end
-                                               append("</p>")
+                                       stpl.elts.add mctpl
+                                       # concern section
+                                       var cctpl = new TplConcern
+                                       cctpl.anchor = mmodule.nitdoc_anchor
+                                       cctpl.concern = mmodule.tpl_link
+                                       if mmodule.mdoc != null then
+                                               cctpl.comment = mmodule.mdoc.short_comment
                                        end
-                                       var mmethods = concern2meths[mmodule]
-                                       prop_sorter.sort(mmethods)
-                                       for prop in mmethods do prop.html_full_desc(self, self.mclass)
+                                       mtpl.add cctpl
                                end
+                               var mprops = module_map[mmodule].to_a
+                               prop_sorter.sort mprops
+                               for mprop in mprops do mtpl.add tpl_mpropdef_article(mprop)
                        end
-                       append("</section>")
-               end
-               # inherited properties
-               if inherited.length > 0 then
-                       var sorted_inherited = new Array[MPropDef]
-                       sorted_inherited.add_all(inherited)
-                       ctx.mainmodule.linearize_mpropdefs(sorted_inherited)
-                       var classes = new ArrayMap[MClass, Array[MPropDef]]
-                       for mmethod in sorted_inherited.reversed do
-                               var mclass = mmethod.mclassdef.mclass
-                               if not classes.has_key(mclass) then classes[mclass] = new Array[MPropDef]
-                               classes[mclass].add(mmethod)
-                       end
-                       append("<section class='inherited'>")
-                       append("<h2 class='section-header'>Inherited Properties</h2>")
-                       for c, mmethods in classes do
-                               prop_sorter.sort(mmethods)
-                               append("<p>Defined in ")
-                               c.html_link(self)
-                               append(": ")
-                               for i in [0..mmethods.length[ do
-                                       var mmethod = mmethods[i]
-                                       mmethod.html_link(self)
-                                       if i <= mmethods.length - 1 then append(", ")
+                       ctpl.elts.add stpl
+               end
+               if not owners.is_empty then
+                       tpl.concerns = ctpl
+               end
+               tpl.methods.add mtpl
+               return tpl
+       end
+
+       private fun sort_by_kind(mpropdefs: Set[MPropDef]): Map[String, Set[MPropDef]] do
+               var map = new HashMap[String, Set[MPropDef]]
+               map["type"] = new HashSet[MPropDef]
+               map["init"] = new HashSet[MPropDef]
+               map["fun"] = new HashSet[MPropDef]
+               for mpropdef in mpropdefs do
+                       if mpropdef isa MVirtualTypeDef then
+                               map["type"].add mpropdef
+                       else if mpropdef isa MMethodDef then
+                               if mpropdef.mproperty.is_init then
+                                       map["init"].add mpropdef
+                               else
+                                       map["fun"].add mpropdef
                                end
-                               append("</p>")
                        end
-                       append("</section>")
                end
+               return map
        end
 
-       private fun process_generate_dot do
-               var pe = ctx.class_hierarchy[mclass]
+       private fun sort_by_mmodule(mpropdefs: Collection[MPropDef]): Map[MModule, Set[MPropDef]] do
+               var map = new HashMap[MModule, Set[MPropDef]]
+               for mpropdef in mpropdefs do
+                       var mmodule = mpropdef.mclassdef.mmodule
+                       if not map.has_key(mmodule) then map[mmodule] = new HashSet[MPropDef]
+                       map[mmodule].add mpropdef
+               end
+               return map
+       end
+
+       private fun sort_by_public_owner(mmodules: Collection[MModule]): Map[MModule, Set[MModule]] do
+               var map = new HashMap[MModule, Set[MModule]]
+               for mmodule in mmodules do
+                       var owner = mmodule
+                       if mmodule.public_owner != null then owner = mmodule.public_owner.as(not null)
+                       if not map.has_key(owner) then map[owner] = new HashSet[MModule]
+                       map[owner].add mmodule
+               end
+               return map
+       end
+
+       # Generate dot hierarchy for classes
+       fun tpl_dot: nullable TplGraph do
+               var pe = mclass.in_hierarchy(ctx.mainmodule)
                var cla = new HashSet[MClass]
                var sm = new HashSet[MClass]
                var sm2 = new HashSet[MClass]
@@ -1093,7 +1084,7 @@ class NitdocClass
                        if c == mclass then
                                op.append("\"{c.name}\"[shape=box,margin=0.03];\n")
                        else
-                               op.append("\"{c.name}\"[URL=\"{c.url}\"];\n")
+                               op.append("\"{c.name}\"[URL=\"{c.nitdoc_url}\"];\n")
                        end
                        for c2 in pe.poset[c].direct_greaters do
                                if not cla.has(c2) then continue
@@ -1111,7 +1102,7 @@ class NitdocClass
                        end
                end
                op.append("\}\n")
-               generate_dot(op.to_s, name, "Dependency graph for class {mclass.name}")
+               return tpl_graph(op, name, "Dependency graph for class {mclass.name}")
        end
 end
 
@@ -1121,228 +1112,176 @@ end
 
 redef class MModule
        # Return the HTML escaped name of the module
-       private fun html_name: String do return name.html_escape
+       private fun nitdoc_name: String do return name.html_escape
+
+       private fun full_namespace: String do
+               if public_owner != null then
+                       return "{public_owner.nitdoc_name}::{nitdoc_name}"
+               end
+               return nitdoc_name
+       end
 
        # URL to nitdoc page
        #       module_owner_name.html
-       private fun url: String do
-               if url_cache == null then
-                       var res = new FlatBuffer
-                       res.append("module_")
-                       var mowner = public_owner
-                       if mowner != null then
-                               res.append("{public_owner.name}_")
-                       end
-                       res.append("{self.name}.html")
-                       url_cache = res.to_s
+       private fun nitdoc_url: String do
+               var res = new FlatBuffer
+               res.append("module_")
+               var mowner = public_owner
+               if mowner != null then
+                       res.append("{public_owner.name}_")
                end
-               return url_cache.as(not null)
+               res.append("{self.name}.html")
+               return res.to_s
        end
-       private var url_cache: nullable String
 
-       # html anchor id for the module in a nitdoc page
+       # html nitdoc_anchor id for the module in a nitdoc page
        #       MOD_owner_name
-       private fun anchor: String do
-               if anchor_cache == null then
-                       var res = new FlatBuffer
-                       res.append("MOD_")
-                       var mowner = public_owner
-                       if mowner != null then
-                               res.append("{public_owner.name}_")
-                       end
-                       res.append(self.name)
-                       anchor_cache = res.to_s
+       private fun nitdoc_anchor: String do
+               var res = new FlatBuffer
+               res.append("MOD_")
+               var mowner = public_owner
+               if mowner != null then
+                       res.append("{public_owner.name}_")
                end
-               return anchor_cache.as(not null)
+               res.append(self.name)
+               return res.to_s
        end
-       private var anchor_cache: nullable String
 
        # Return a link (html a tag) to the nitdoc module page
-       #       <a href="url" title="short_comment">html_name</a>
-       private fun html_link(page: NitdocPage) do
-               if html_link_cache == null then
-                       var res = new FlatBuffer
-                       if page.ctx.mbuilder.mmodule2nmodule.has_key(self) then
-                               res.append("<a href='{url}' title='{page.ctx.mbuilder.mmodule2nmodule[self].short_comment}'>{html_name}</a>")
-                       else
-                               res.append("<a href='{url}'>{html_name}</a>")
-                       end
-                       html_link_cache = res.to_s
+       private fun tpl_link: TplLink do
+               var tpl = new TplLink
+               tpl.href = nitdoc_url
+               tpl.text = nitdoc_name
+               if mdoc != null then
+                       tpl.title = mdoc.short_comment
                end
-               page.append(html_link_cache.as(not null))
+               return tpl
        end
-       private var html_link_cache: nullable String
 
        # Return the module signature decorated with html
-       #       <span>module html_full_namespace</span>
-       private fun html_signature(page: NitdocPage) do
-               page.append("<span>module ")
-               html_full_namespace(page)
-               page.append("</span>")
+       private fun tpl_signature: Template do
+               var tpl = new Template
+               tpl.add "<span>module "
+               tpl.add tpl_full_namespace
+               tpl.add "</span>"
+               return tpl
        end
 
        # Return the module full namespace decorated with html
-       #       <span>public_owner.html_namespace::html_link</span>
-       private fun html_full_namespace(page: NitdocPage) do
-               page.append("<span>")
+       private fun tpl_full_namespace: Template do
+               var tpl = new Template
+               tpl.add ("<span>")
                var mowner = public_owner
                if mowner != null then
-                       public_owner.html_namespace(page)
-                       page.append("::")
+                       tpl.add public_owner.tpl_namespace
+                       tpl.add "::"
                end
-               html_link(page)
-               page.append("</span>")
+               tpl.add tpl_link
+               tpl.add "</span>"
+               return tpl
        end
 
        # Return the module full namespace decorated with html
-       #       <span>public_owner.html_namespace</span>
-       private fun html_namespace(page: NitdocPage) do
-               page.append("<span>")
+       private fun tpl_namespace: Template do
+               var tpl = new Template
+               tpl.add "<span>"
                var mowner = public_owner
                if mowner != null then
-                       public_owner.html_namespace(page)
+                       tpl.add public_owner.tpl_namespace
                else
-                       html_link(page)
-               end
-               page.append("</span>")
-       end
-
-       # Return the full comment of the module decorated with html
-       private fun html_comment(page: NitdocPage) do
-               page.append("<div class='description'>")
-               if page.ctx.mbuilder.mmodule2nmodule.has_key(self) then
-                       var nmodule = page.ctx.mbuilder.mmodule2nmodule[self]
-                       if page.ctx.github_gitdir != null then
-                               var loc = nmodule.doc_location.github(page.ctx.github_gitdir.as(not null))
-                               page.append("<textarea class='baseComment' data-comment-namespace='{full_name}' data-comment-location='{loc}'>{nmodule.full_comment}</textarea>")
-                       end
-                       if nmodule.full_comment == "" then
-                               page.append("<p class='info inheritance'>")
-                               page.append("<span class=\"noComment\">no comment for </span>")
-                       else
-                               page.append("<div class='comment'>{nmodule.full_markdown}</div>")
-                               page.append("<p class='info inheritance'>")
-                       end
-                       page.append("definition in ")
-                       self.html_full_namespace(page)
-                       page.append(" {page.show_source(nmodule.location)}</p>")
+                       tpl.add tpl_link
                end
-               page.append("</div>")
+               tpl.add "</span>"
+               return tpl
        end
 
-       private fun has_mclassdef_for(mclass: MClass): Bool do
-               for mmodule in self.in_nesting.greaters do
-                       for mclassdef in mmodule.mclassdefs do
-                               if mclassdef.mclass == mclass then return true
-                       end
+       # Description with short comment
+       private fun tpl_short_definition: TplDefinition do
+               var tpl = new TplDefinition
+               tpl.namespace = tpl_namespace
+               if mdoc != null then
+                       tpl.comment = mdoc.tpl_short_comment
                end
-               return false
+               return tpl
        end
 
-       private fun has_mclassdef(mclassdef: MClassDef): Bool do
-               for mmodule in self.in_nesting.greaters do
-                       for oclassdef in mmodule.mclassdefs do
-                               if mclassdef == oclassdef then return true
-                       end
+       # Description with full comment
+       private fun tpl_definition: TplDefinition do
+               var tpl = new TplDefinition
+               tpl.namespace = tpl_namespace
+               if mdoc != null then
+                       tpl.comment = mdoc.tpl_comment
                end
-               return false
+               return tpl
        end
 end
 
 redef class MClass
        # Return the HTML escaped name of the module
-       private fun html_name: String do return name.html_escape
+       private fun nitdoc_name: String do return name.html_escape
 
        # URL to nitdoc page
        #       class_owner_name.html
-       private fun url: String do
+       private fun nitdoc_url: String do
                return "class_{public_owner}_{name}.html"
        end
 
-       # html anchor id for the class in a nitdoc page
+       # html nitdoc_anchor id for the class in a nitdoc page
        #       MOD_owner_name
-       private fun anchor: String do
-               if anchor_cache == null then
-                       anchor_cache = "CLASS_{public_owner.name}_{name}"
-               end
-               return anchor_cache.as(not null)
+       private fun nitdoc_anchor: String do
+               return "CLASS_{public_owner.name}_{name}"
        end
-       private var anchor_cache: nullable String
 
        # Return a link (with signature) to the nitdoc class page
-       #       <a href="url" title="short_comment">html_name(signature)</a>
-       private fun html_link(page: NitdocPage) do
-               if html_link_cache == null then
-                       var res = new FlatBuffer
-                       res.append("<a href='{url}'")
-                       if page.ctx.mbuilder.mclassdef2nclassdef.has_key(intro) then
-                               var nclass = page.ctx.mbuilder.mclassdef2nclassdef[intro]
-                               if nclass isa AStdClassdef then
-                                       res.append(" title=\"{nclass.short_comment}\"")
-                               end
-                       end
-                       res.append(">{html_name}{html_short_signature}</a>")
-                       html_link_cache = res.to_s
+       private fun tpl_link: TplLink do
+               var tpl = new TplLink
+               tpl.href = nitdoc_url
+               tpl.text = "{nitdoc_name}{tpl_short_signature.write_to_string}"
+               if intro.mdoc != null then
+                       tpl.title = intro.mdoc.short_comment
                end
-               page.append(html_link_cache.as(not null))
+               return tpl
        end
-       private var html_link_cache: nullable String
 
        # Return a short link (without signature) to the nitdoc class page
-       #       <a href="url" title="short_comment">html_name</a>
-       private fun html_short_link(page: NitdocPage) do
-               if html_short_link_cache == null then
-                       var res = new FlatBuffer
-                       res.append("<a href='{url}'")
-                       if page.ctx.mbuilder.mclassdef2nclassdef.has_key(intro) then
-                               var nclass = page.ctx.mbuilder.mclassdef2nclassdef[intro]
-                               if nclass isa AStdClassdef then
-                                       res.append(" title=\"{nclass.short_comment}\"")
-                               end
-                       end
-                       res.append(">{html_name}</a>")
-                       html_short_link_cache = res.to_s
-               end
-               page.append(html_short_link_cache.as(not null))
-       end
-       private var html_short_link_cache: nullable String
-
-       # Return a link (with signature) to the class anchor
-       #       <a href="url" title="short_comment">html_name</a>
-       private fun html_link_anchor(page: NitdocPage) do
-               if html_link_anchor_cache == null then
-                       var res = new FlatBuffer
-                       res.append("<a href='#{anchor}'")
-                       if page.ctx.mbuilder.mclassdef2nclassdef.has_key(intro) then
-                               var nclass = page.ctx.mbuilder.mclassdef2nclassdef[intro]
-                               if nclass isa AStdClassdef then
-                                       res.append(" title=\"{nclass.short_comment}\"")
-                               end
-                       end
-                       res.append(">{html_name}{html_short_signature}</a>")
-                       html_link_anchor_cache = res.to_s
+       private fun tpl_short_link: TplLink do
+               var tpl = new TplLink
+               tpl.href = nitdoc_url
+               tpl.text = nitdoc_name
+               if intro.mdoc != null then
+                       tpl.title = intro.mdoc.short_comment
+               end
+               return tpl
+       end
+
+       # Return a link (with signature) to the class nitdoc_anchor
+       private fun tpl_link_anchor: TplLink do
+               var tpl = new TplLink
+               tpl.href = "#{nitdoc_anchor}"
+               tpl.text = "{nitdoc_name}{tpl_short_signature.write_to_string}"
+               if intro.mdoc != null then
+                       tpl.title = intro.mdoc.short_comment
                end
-               page.append(html_link_anchor_cache.as(not null))
+               return tpl
        end
-       private var html_link_anchor_cache: nullable String
 
        # Return the generic signature of the class with bounds
-       #       [E: <a>MType</a>, F: <a>MType</a>]
-       private fun html_signature(page: NitdocPage) do
+       private fun tpl_signature: Template do
+               var tpl = new Template
                if arity > 0 then
-                       page.append("[")
+                       tpl.add "["
                        for i in [0..intro.parameter_names.length[ do
-                               page.append("{intro.parameter_names[i]}: ")
-                               intro.bound_mtype.arguments[i].html_link(page)
-                               if i < intro.parameter_names.length - 1 then page.append(", ")
+                               tpl.add "{intro.parameter_names[i]}: "
+                               tpl.add intro.bound_mtype.arguments[i].tpl_link
+                               if i < intro.parameter_names.length - 1 then tpl.add ", "
                        end
-                       page.append("]")
+                       tpl.add "]"
                end
+               return tpl
        end
 
        # Return the generic signature of the class without bounds
-       #       [E, F]
-       private fun html_short_signature: String do
+       private fun tpl_short_signature: String do
                if arity > 0 then
                        return "[{intro.parameter_names.join(", ")}]"
                else
@@ -1351,416 +1290,289 @@ redef class MClass
        end
 
        # Return the class namespace decorated with html
-       #       <span>intro_module::html_short_link</span>
-       private fun html_namespace(page: NitdocPage) do
-               intro_mmodule.html_namespace(page)
-               page.append("::<span>")
-               html_short_link(page)
-               page.append("</span>")
-       end
-
-       # Return a list item for the mclass
-       #       <li>html_link</li>
-       private fun html_sidebar_item(page: NitdocModule) do
-               if page.mmodule.in_nesting.greaters.has(intro.mmodule) then
-                       page.append("<li class='intro'>")
-                       page.append("<span title='Introduced'>I</span>")
-                       html_link_anchor(page)
-               else if page.mmodule.has_mclassdef_for(self) then
-                       page.append("<li class='redef'>")
-                       page.append("<span title='Redefined'>R</span>")
-                       html_link_anchor(page)
-               else
-                       page.append("<li class='inherit'>")
-                       page.append("<span title='Inherited'>H</span>")
-                       html_link(page)
-               end
-               page.append("</li>")
-       end
-
-       private fun html_full_desc(page: NitdocModule) do
-               var is_redef = not page.mmodule.in_nesting.greaters.has(intro.mmodule)
-               var redefs = mpropdefs_in_module(page)
-               if not is_redef or not redefs.is_empty then
-                       var classes = new Array[String]
-                       classes.add(kind.to_s)
-                       if is_redef then classes.add("redef")
-                       classes.add(visibility.to_s)
-                       page.append("<article class='{classes.join(" ")}' id='{anchor}'>")
-                       page.append("<h3 class='signature' data-untyped-signature='{html_name}{html_short_signature}'>")
-                       page.append("<span>")
-                       html_short_link(page)
-                       html_signature(page)
-                       page.append("</span></h3>")
-                       html_info(page)
-                       html_comment(page)
-                       page.append("</article>")
-               end
-       end
-
-       private fun html_info(page: NitdocModule) do
-               page.append("<div class='info'>")
-               if visibility < public_visibility then page.append("{visibility.to_s} ")
-               if not page.mmodule.in_nesting.greaters.has(intro.mmodule) then page.append("redef ")
-               page.append("{kind} ")
-               html_namespace(page)
-               page.append("{html_short_signature}</div>")
-       end
-
-       private fun html_comment(page: NitdocPage) do
-               page.append("<div class='description'>")
-               if page isa NitdocModule then
-                       page.mmodule.linearize_mclassdefs(mclassdefs)
-                       # comments for each mclassdef contained in current mmodule
-                       for mclassdef in mclassdefs do
-                               if not mclassdef.is_intro and not page.mmodule.mclassdefs.has(mclassdef) then continue
-                               if page.ctx.mbuilder.mclassdef2nclassdef.has_key(mclassdef) then
-                                       var nclass = page.ctx.mbuilder.mclassdef2nclassdef[mclassdef]
-                                       if nclass isa AStdClassdef then
-                                               if page.ctx.github_gitdir != null then
-                                                       var loc = nclass.doc_location.github(page.ctx.github_gitdir.as(not null))
-                                                       page.append("<textarea class='baseComment' data-comment-namespace='{mclassdef.mmodule.full_name}::{name}' data-comment-location='{loc}'>{nclass.full_comment}</textarea>")
-                                               end
-                                               if nclass.full_comment == "" then
-                                                       page.append("<p class='info inheritance'>")
-                                                       page.append("<span class=\"noComment\">no comment for </span>")
-                                               else
-                                                       page.append("<div class='comment'>{nclass.full_markdown}</div>")
-                                                       page.append("<p class='info inheritance'>")
-                                               end
-                                               if mclassdef.is_intro then
-                                                       page.append("introduction in ")
-                                               else
-                                                       page.append("refinement in ")
-                                               end
-                                               mclassdef.mmodule.html_full_namespace(page)
-                                               page.append(" {page.show_source(nclass.location)}</p>")
-                                       end
-                               end
-                       end
-               else
-                       # comments for intro
-                       if page.ctx.mbuilder.mclassdef2nclassdef.has_key(intro) then
-                               var nclass = page.ctx.mbuilder.mclassdef2nclassdef[intro]
-                               if nclass isa AStdClassdef then
-                                       if page.ctx.github_gitdir != null then
-                                               var loc = nclass.doc_location.github(page.ctx.github_gitdir.as(not null))
-                                               page.append("<textarea class='baseComment' data-comment-namespace='{intro.mmodule.full_name}::{name}' data-comment-location='{loc}'>{nclass.full_comment}</textarea>")
-                                       end
-                                       if nclass.full_comment == "" then
-                                               page.append("<p class='info inheritance'>")
-                                               page.append("<span class=\"noComment\">no comment for </span>")
-                                       else
-                                               page.append("<div class='comment'>{nclass.full_markdown}</div>")
-                                               page.append("<p class='info inheritance'>")
-                                       end
-                                       page.append("introduction in ")
-                                       intro.mmodule.html_full_namespace(page)
-                                       page.append(" {page.show_source(nclass.location)}</p>")
-                               end
-                       end
-               end
-               page.append("</div>")
-       end
-
-       private fun mpropdefs_in_module(page: NitdocModule): Array[MPropDef] do
-               var res = new Array[MPropDef]
-               page.mmodule.linearize_mclassdefs(mclassdefs)
-               for mclassdef in mclassdefs do
-                       if not page.mmodule.mclassdefs.has(mclassdef) then continue
-                       if mclassdef.is_intro then continue
-                       for mpropdef in mclassdef.mpropdefs do
-                               if mpropdef.mproperty.visibility < page.ctx.min_visibility then continue
-                               if mpropdef isa MAttributeDef then continue
-                               res.add(mpropdef)
-                       end
-               end
-               return res
+       private fun tpl_namespace: Template do
+               var tpl = new Template
+               tpl.add intro_mmodule.tpl_namespace
+               tpl.add "::<span>"
+               tpl.add tpl_short_link
+               tpl.add "</span>"
+               return tpl
+       end
+
+       private fun tpl_namespace_with_signature: Template do
+               var tpl = new Template
+               tpl.add intro.tpl_modifiers
+               tpl.add intro.mmodule.tpl_namespace
+               tpl.add "::"
+               tpl.add nitdoc_name
+               tpl.add tpl_signature
+               return tpl
        end
 end
 
 redef class MProperty
        # Escape name for html output
-       private fun html_name: String do return name.html_escape
+       private fun nitdoc_name: String do return name.html_escape
 
        # Return the property namespace decorated with html
-       #       <span>intro_module::intro_class::html_link</span>
-       private fun html_namespace(page: NitdocPage) do
-               intro_mclassdef.mclass.html_namespace(page)
-               page.append(intro_mclassdef.mclass.html_short_signature)
-               page.append("::<span>")
-               intro.html_link(page)
-               page.append("</span>")
+       private fun tpl_namespace: Template do
+               var tpl = new Template
+               tpl.add intro_mclassdef.mclass.tpl_namespace
+               tpl.add intro_mclassdef.mclass.tpl_short_signature
+               tpl.add "::<span>"
+               tpl.add intro.tpl_link
+               tpl.add "</span>"
+               return tpl
+       end
+
+       private fun tpl_signature: Template is abstract
+end
+
+redef class MMethod
+       redef fun tpl_signature do return intro.msignature.tpl_signature
+end
+
+redef class MVirtualTypeProp
+       redef fun tpl_signature do
+               var tpl = new Template
+               tpl.add ": "
+               tpl.add  intro.bound.tpl_link
+               return tpl
        end
 end
 
 redef class MType
        # Link to the type definition in the nitdoc page
-       private fun html_link(page: NitdocPage) is abstract
+       private fun tpl_link: Template is abstract
 end
 
 redef class MClassType
-       redef fun html_link(page) do mclass.html_link(page)
+       redef fun tpl_link do return mclass.tpl_link
 end
 
 redef class MNullableType
-       redef fun html_link(page) do
-               page.append("nullable ")
-               mtype.html_link(page)
+       redef fun tpl_link do
+               var tpl = new Template
+               tpl.add "nullable "
+               tpl.add mtype.tpl_link
+               return tpl
        end
 end
 
 redef class MGenericType
-       redef fun html_link(page) do
-               page.append("<a href='{mclass.url}'>{mclass.html_name}</a>[")
+       redef fun tpl_link: Template do
+               var tpl = new Template
+               tpl.add mclass.tpl_short_link
+               tpl.add "["
                for i in [0..arguments.length[ do
-                       arguments[i].html_link(page)
-                       if i < arguments.length - 1 then page.append(", ")
+                       tpl.add arguments[i].tpl_link
+                       if i < arguments.length - 1 then tpl.add ", "
                end
-               page.append("]")
+               tpl.add "]"
+               return tpl
        end
 end
 
 redef class MParameterType
-       redef fun html_link(page) do
+       redef fun tpl_link do
                var name = mclass.intro.parameter_names[rank]
-               page.append("<a href='{mclass.url}#FT_{name}' title='formal type'>{name}</a>")
+               var tpl = new TplLink
+               tpl.href = "{mclass.nitdoc_url}#FT_{name}"
+               tpl.text = name
+               tpl.title = "formal type"
+               return tpl
        end
 end
 
 redef class MVirtualType
-       redef fun html_link(page) do mproperty.intro.html_link(page)
+       redef fun tpl_link do return mproperty.intro.tpl_link
 end
 
 redef class MClassDef
        # Return the classdef namespace decorated with html
-       private fun html_namespace(page: NitdocPage) do
-               mmodule.html_full_namespace(page)
-               page.append("::<span>")
-               mclass.html_link(page)
-               page.append("</span>")
+       private fun tpl_namespace: Template do
+               var tpl = new Template
+               tpl.add mmodule.tpl_namespace
+               tpl.add "::<span>"
+               tpl.add mclass.tpl_link
+               tpl.add "</span>"
+               return tpl
+       end
+
+       private fun full_namespace: String do
+               return "{mmodule.full_namespace}::{mclass.nitdoc_name}"
+       end
+
+       private fun tpl_link_anchor: TplLink do return mclass.tpl_link_anchor
+
+       private fun tpl_article: TplArticle do
+               var tpl = new TplArticle
+               tpl.id = mclass.nitdoc_anchor
+               tpl.classes.add_all(tpl_css_classes)
+               tpl.title = new Template
+               tpl.title.add mclass.tpl_short_link
+               tpl.title.add mclass.tpl_signature
+               tpl.subtitle = new Template
+               tpl.subtitle.add tpl_modifiers
+               tpl.subtitle.add tpl_namespace
+               tpl.content = new Template
+               tpl.content.add tpl_definition
+               return tpl
+       end
+
+       private fun tpl_css_classes: Set[String] do
+               var set = new HashSet[String]
+               set.add_all mclass.intro.modifiers
+               set.add_all modifiers
+               return set
+       end
+
+       private fun tpl_modifiers: Template do
+               var tpl = new Template
+               for modifier in modifiers do
+                       if modifier == "public" then continue
+                       tpl.add "{modifier} "
+               end
+               return tpl
+       end
+
+       private fun tpl_short_definition: TplDefinition do
+               var tpl = new TplDefinition
+               tpl.namespace = mmodule.tpl_full_namespace
+               if mdoc != null then
+                       tpl.comment = mdoc.tpl_short_comment
+               end
+               return tpl
+       end
+
+       private fun tpl_definition: TplDefinition do
+               var tpl = new TplDefinition
+               tpl.namespace = mmodule.tpl_full_namespace
+               if mdoc != null then
+                       tpl.comment = mdoc.tpl_comment
+               end
+               return tpl
        end
 end
 
 redef class MPropDef
        # Return the full qualified name of the mpropdef
        #       module::classdef::name
-       private fun full_name: String do
-               return "{mclassdef.mclass.public_owner.name}::{mclassdef.mclass.name}::{mproperty.name}"
+       private fun tpl_namespace: Template do
+               var tpl = new Template
+               tpl.add mclassdef.tpl_namespace
+               tpl.add "::"
+               tpl.add mproperty.name
+               return tpl
+       end
+
+       private fun full_namespace: String do
+               return "{mclassdef.full_namespace}::{mproperty.nitdoc_name}"
        end
 
        # URL into the nitdoc page
-       #       class_owner_name.html#anchor
-       private fun url: String do
-               if url_cache == null then
-                       url_cache = "{mclassdef.mclass.url}#{anchor}"
-               end
-               return url_cache.as(not null)
+       #       class_owner_name.html#nitdoc_anchor
+       private fun nitdoc_url: String do
+               return "{mclassdef.mclass.nitdoc_url}#{nitdoc_anchor}"
        end
-       private var url_cache: nullable String
 
-       # html anchor id for the property in a nitdoc class page
+       # html nitdoc_anchor id for the property in a nitdoc class page
        #       PROP_mclass_propertyname
-       private fun anchor: String do
-               if anchor_cache == null then
-                       anchor_cache = "PROP_{mclassdef.mclass.public_owner.name}_{mproperty.name.replace(" ", "_")}"
-               end
-               return anchor_cache.as(not null)
+       private fun nitdoc_anchor: String do
+               return "PROP_{mclassdef.mclass.public_owner.nitdoc_name}_{mproperty.name.replace(" ", "_")}"
        end
-       private var anchor_cache: nullable String
 
        # Return a link to property into the nitdoc class page
-       #       <a href="url" title="short_comment">html_name</a>
-       private fun html_link(page: NitdocPage) do
-               if html_link_cache == null then
-                       var res = new FlatBuffer
-                       if page.ctx.mbuilder.mpropdef2npropdef.has_key(self) then
-                               var nprop = page.ctx.mbuilder.mpropdef2npropdef[self]
-                               res.append("<a href=\"{url}\" title=\"{nprop.short_comment}\">{mproperty.html_name}</a>")
-                       else
-                               res.append("<a href=\"{url}\">{mproperty.html_name}</a>")
-                       end
-                       html_link_cache = res.to_s
+       #       <a href="nitdoc_url" title="short_comment">nitdoc_name</a>
+       private fun tpl_link: TplLink do
+               var tpl = new TplLink
+               tpl.href = nitdoc_url
+               tpl.text = mproperty.nitdoc_name
+               if mproperty.intro.mdoc != null then
+                       tpl.title = mproperty.intro.mdoc.short_comment
                end
-               page.append(html_link_cache.as(not null))
+               return tpl
        end
-       private var html_link_cache: nullable String
 
-       # Return a list item for the mpropdef
-       #       <li>html_link</li>
-       private fun html_sidebar_item(page: NitdocClass) do
-               if is_intro and mclassdef.mclass == page.mclass then
-                       page.append("<li class='intro'>")
-                       page.append("<span title='Introduced'>I</span>")
-               else if is_intro and mclassdef.mclass != page.mclass then
-                       page.append("<li class='inherit'>")
-                       page.append("<span title='Inherited'>H</span>")
-               else
-                       page.append("<li class='redef'>")
-                       page.append("<span title='Redefined'>R</span>")
-               end
-               html_link(page)
-               page.append("</li>")
+       private fun tpl_article: TplArticle do
+               var tpl = new TplArticle
+               tpl.id = nitdoc_anchor
+               tpl.classes.add_all(tpl_css_classes)
+               tpl.title = new Template
+               tpl.title.add mproperty.nitdoc_name
+               tpl.title.add mproperty.tpl_signature
+               tpl.subtitle = new Template
+               tpl.subtitle.add tpl_modifiers
+               tpl.subtitle.add tpl_namespace
+               tpl.content = new Template
+               tpl.content.add tpl_definition
+               return tpl
        end
 
-       private fun html_full_desc(page: NitdocPage, ctx: MClass) is abstract
-       private fun html_info(page: NitdocPage, ctx: MClass) is abstract
+       private fun tpl_css_classes: Set[String] do
+               var set = new HashSet[String]
+               set.add_all mproperty.intro.modifiers
+               set.add_all modifiers
+               return set
+       end
 
-       private fun html_comment(page: NitdocPage) do
-               page.append("<div class='description'>")
-               if not is_intro then
-                       if page.ctx.mbuilder.mpropdef2npropdef.has_key(mproperty.intro) then
-                               var intro_nprop = page.ctx.mbuilder.mpropdef2npropdef[mproperty.intro]
-                               if page.ctx.github_gitdir != null then
-                                       var loc = intro_nprop.doc_location.github(page.ctx.github_gitdir.as(not null))
-                                       page.append("<textarea class='baseComment' data-comment-namespace='{mproperty.intro.mclassdef.mmodule.full_name}::{mproperty.intro.mclassdef.mclass.name}::{mproperty.name}' data-comment-location='{loc}'>{intro_nprop.full_comment}</textarea>")
-                               end
-                               if intro_nprop.full_comment.is_empty then
-                                       page.append("<p class='info inheritance'>")
-                                       page.append("<span class=\"noComment\">no comment for </span>")
-                               else
-                                       page.append("<div class='comment'>{intro_nprop.full_markdown}</div>")
-                                       page.append("<p class='info inheritance'>")
-                               end
-                               page.append("introduction in ")
-                               mproperty.intro.mclassdef.html_namespace(page)
-                               page.append(" {page.show_source(intro_nprop.location)}</p>")
-                       end
+       private fun tpl_modifiers: Template do
+               var tpl = new Template
+               for modifier in modifiers do
+                       if modifier == "public" then continue
+                       tpl.add "{modifier} "
                end
-               if page.ctx.mbuilder.mpropdef2npropdef.has_key(self) then
-                       var nprop = page.ctx.mbuilder.mpropdef2npropdef[self]
-                       if page.ctx.github_gitdir != null then
-                               var loc = nprop.doc_location.github(page.ctx.github_gitdir.as(not null))
-                               page.append("<textarea class='baseComment' data-comment-namespace='{mclassdef.mmodule.full_name}::{mclassdef.mclass.name}::{mproperty.name}' data-comment-location='{loc}'>{nprop.full_comment}</textarea>")
-                       end
-                       if nprop.full_comment == "" then
-                               page.append("<p class='info inheritance'>")
-                               page.append("<span class=\"noComment\">no comment for </span>")
-                       else
-                               page.append("<div class='comment'>{nprop.full_markdown}</div>")
-                               page.append("<p class='info inheritance'>")
-                       end
-                       if is_intro then
-                               page.append("introduction in ")
-                       else
-                               page.append("redefinition in ")
-                       end
-                       mclassdef.html_namespace(page)
-                       page.append(" {page.show_source(nprop.location)}</p>")
-               end
-               page.append("</div>")
+               return tpl
        end
-end
 
-redef class MMethodDef
-       redef fun html_full_desc(page, ctx) do
-               var classes = new Array[String]
-               var is_redef = mproperty.intro_mclassdef.mclass != ctx
-               if mproperty.is_init then
-                       classes.add("init")
-               else
-                       classes.add("fun")
-               end
-               if is_redef then classes.add("redef")
-               classes.add(mproperty.visibility.to_s)
-               page.append("<article class='{classes.join(" ")}' id='{anchor}'>")
-               if page.ctx.mbuilder.mpropdef2npropdef.has_key(self) then
-                       page.append("<h3 class='signature' data-untyped-signature='{mproperty.name}{msignature.untyped_signature(page)}'>")
-                       page.append("<span>{mproperty.html_name}")
-                       msignature.html_signature(page)
-                       page.append("</span></h3>")
-               else
-                       page.append("<h3 class='signature' data-untyped-signature='init{msignature.untyped_signature(page)}'>")
-                       page.append("<span>init")
-                       msignature.html_signature(page)
-                       page.append("</span></h3>")
-               end
-               html_info(page, ctx)
-               html_comment(page)
-               page.append("</article>")
-       end
-
-       redef fun html_info(page, ctx) do
-               page.append("<div class='info'>")
-               if mproperty.visibility < public_visibility then page.append("{mproperty.visibility.to_s} ")
-               if mproperty.intro_mclassdef.mclass != ctx then page.append("redef ")
-               if mproperty.is_init then
-                       page.append("init ")
-               else
-                       page.append("fun ")
+       private fun tpl_short_definition: TplDefinition do
+               var tpl = new TplDefinition
+               tpl.namespace = mclassdef.tpl_namespace
+               if mdoc != null then
+                       tpl.comment = mdoc.tpl_short_comment
                end
-               mproperty.html_namespace(page)
-               page.append("</div>")
+               return tpl
        end
-end
 
-redef class MVirtualTypeDef
-       redef fun html_full_desc(page, ctx) do
-               var is_redef = mproperty.intro_mclassdef.mclass != ctx
-               var classes = new Array[String]
-               classes.add("type")
-               if is_redef then classes.add("redef")
-               classes.add(mproperty.visibility.to_s)
-               page.append("<article class='{classes.join(" ")}' id='{anchor}'>")
-               page.append("<h3 class='signature' data-untyped-signature='{mproperty.name}'><span>{mproperty.html_name}: ")
-               bound.html_link(page)
-               page.append("</span></h3>")
-               html_info(page, ctx)
-               html_comment(page)
-               page.append("</article>")
-       end
-
-       redef fun html_info(page, ctx) do
-               page.append("<div class='info'>")
-               if mproperty.intro_mclassdef.mclass != ctx then page.append("redef ")
-               page.append("type ")
-               mproperty.html_namespace(page)
-               page.append("</div>")
+       private fun tpl_definition: TplDefinition do
+               var tpl = new TplDefinition
+               tpl.namespace = mclassdef.tpl_namespace
+               if mdoc != null then
+                       tpl.comment = mdoc.tpl_comment
+               end
+               return tpl
        end
 end
 
 redef class MSignature
-       private fun html_signature(page: NitdocPage) do
+       private fun tpl_signature: Template do
+               var tpl = new Template
                if not mparameters.is_empty then
-                       page.append("(")
+                       tpl.add "("
                        for i in [0..mparameters.length[ do
-                               mparameters[i].html_link(page)
-                               if i < mparameters.length - 1 then page.append(", ")
+                               tpl.add mparameters[i].tpl_link
+                               if i < mparameters.length - 1 then tpl.add ", "
                        end
-                       page.append(")")
+                       tpl.add ")"
                end
                if return_mtype != null then
-                       page.append(": ")
-                       return_mtype.html_link(page)
-               end
-       end
-
-       private fun untyped_signature(page: NitdocPage): String do
-               var res = new FlatBuffer
-               if not mparameters.is_empty then
-                       res.append("(")
-                       for i in [0..mparameters.length[ do
-                               res.append(mparameters[i].name)
-                               if i < mparameters.length - 1 then res.append(", ")
-                       end
-                       res.append(")")
+                       tpl.add ": "
+                       tpl.add return_mtype.tpl_link
                end
-               return res.to_s
+               return tpl
        end
 end
 
 redef class MParameter
-       private fun html_link(page: NitdocPage) do
-               page.append("{name}: ")
-               mtype.html_link(page)
-               if is_vararg then page.append("...")
+       private fun tpl_link: Template do
+               var tpl = new Template
+               tpl.add "{name}: "
+               tpl.add mtype.tpl_link
+               if is_vararg then tpl.add "..."
+               return tpl
        end
 end
 
-#
-# Nodes redefs
-#
-
 redef class Location
        fun github(gitdir: String): String do
                var base_dir = getcwd.join_path(gitdir).simplify_path
@@ -1770,104 +1582,24 @@ redef class Location
        end
 end
 
-redef class ADoc
-       private fun short_comment: String do
-               return n_comment.first.text.substring_from(2).replace("\n", "").html_escape
-       end
-
-       private fun full_comment: String do
-               var res = new FlatBuffer
-               for t in n_comment do
-                       var text = t.text
-                       text = text.substring_from(1)
-                       if text.chars.first == ' ' then text = text.substring_from(1)
-                       res.append(text.html_escape)
-               end
-               var str = res.to_s
-               return str.substring(0, str.length - 1)
-       end
-end
-
-redef class AModule
+redef class MDoc
        private fun short_comment: String do
-               if n_moduledecl != null and n_moduledecl.n_doc != null then
-                       return n_moduledecl.n_doc.short_comment
-               end
-               return ""
+               return content.first.html_escape
        end
 
        private fun full_comment: String do
-               if n_moduledecl != null and n_moduledecl.n_doc != null then
-                       return n_moduledecl.n_doc.full_comment
-               end
-               return ""
+               return content.join("\n").html_escape
        end
 
-       private fun full_markdown: String do
-               if n_moduledecl != null and n_moduledecl.n_doc != null then
-                       return n_moduledecl.n_doc.to_mdoc.full_markdown.write_to_string
-               end
-               return ""
+       private fun tpl_short_comment: TplShortComment do
+               return new TplShortComment(short_markdown)
        end
 
-       # The doc location or the first line of the block if doc node is null
-       private fun doc_location: Location do
-               if n_moduledecl != null and n_moduledecl.n_doc != null then
-                       return n_moduledecl.n_doc.location
-               end
-               var l = location
-               return new Location(l.file, l.line_start, l.line_start, l.column_start, l.column_start)
+       private fun tpl_comment: TplComment do
+               return new TplComment(full_markdown)
        end
 end
 
-redef class AStdClassdef
-       private fun short_comment: String do
-               if n_doc != null then return n_doc.short_comment
-               return ""
-       end
-
-       private fun full_comment: String do
-               if n_doc != null then return n_doc.full_comment
-               return ""
-       end
-
-       private fun full_markdown: String do
-               if n_doc != null then return n_doc.to_mdoc.full_markdown.write_to_string
-               return ""
-       end
-
-       # The doc location or the first line of the block if doc node is null
-       private fun doc_location: Location do
-               if n_doc != null then return n_doc.location
-               var l = location
-               return new Location(l.file, l.line_start, l.line_start, l.column_start, l.column_start)
-       end
-end
-
-redef class APropdef
-       private fun short_comment: String do
-               if n_doc != null then return n_doc.short_comment
-               return ""
-       end
-
-       private fun full_comment: String do
-               if n_doc != null then return n_doc.full_comment
-               return ""
-       end
-
-       private fun full_markdown: String do
-               if n_doc != null then return n_doc.to_mdoc.full_markdown.write_to_string
-               return ""
-       end
-
-       private fun doc_location: Location do
-               if n_doc != null then return n_doc.location
-               var l = location
-               return new Location(l.file, l.line_start, l.line_start, l.column_start, l.column_start)
-
-       end
-end
-
-
 var nitdoc = new NitdocContext
 nitdoc.generate_nitdoc
+
index 5f22329..85b2c1a 100644 (file)
@@ -27,11 +27,11 @@ var opt_full = new OptionBool("Process also imported modules", "--full")
 var opt_ast = new OptionBool("Generate specific HTML elements for each Node of the AST", "--ast")
 toolcontext.option_context.add_option(opt_fragment, opt_first_line, opt_last_line, opt_dir, opt_full)
 toolcontext.tooldescription = "Usage: nitlight [OPTION]... <file.nit>...\nGenerates HTML of highlited code from Nit source files."
+toolcontext.process_options(args)
 
 var model = new Model
 var modelbuilder = new ModelBuilder(model, toolcontext)
 
-toolcontext.process_options(args)
 var args = toolcontext.option_context.rest
 
 var mmodules = modelbuilder.parse(args)
index 896b579..391a2b0 100644 (file)
@@ -50,9 +50,9 @@ redef class MMethod
        end
 end
 
-redef class AModule
+redef class MModule
        # Mangled name of this module in C
-       fun cname: String do return mmodule.name
+       fun cname: String do return name
 end
 
 redef class MMethodDef
index efe3667..6f85029 100644 (file)
@@ -268,7 +268,7 @@ end
 
 redef class AExternCall
        # Verify this explicit declaration of call from C and collect all relevant callbacks
-       fun verify_and_collect(npropdef: AExternPropdef, callback_set: ForeignCallbackSet,
+       fun verify_and_collect(npropdef: AMethPropdef, callback_set: ForeignCallbackSet,
                toolcontext: ToolContext) is abstract
 end
 
index 8cacbf1..5c5b9c1 100644 (file)
@@ -113,7 +113,8 @@ redef class MMethod
                end
 
                for p in signature.mparameters do
-                       cparams.add(call_context.cast_to(p.mtype, "{p.name}{param_suffix}"))
+                       var param_mtype = p.mtype.resolve_for(recv_mtype, recv_mtype, from_mmodule, true)
+                       cparams.add(call_context.cast_to(param_mtype, "{p.name}{param_suffix}"))
                end
 
                var joined_cparams = cparams.join(", ")
index 532914c..0e0d345 100644 (file)
@@ -101,7 +101,7 @@ class NitIndex
 
        fun prompt do
                printn ">> "
-               search(stdin.read_line)
+               search(sys.stdin.read_line)
        end
 
        fun search(entry: String) do
@@ -694,10 +694,9 @@ redef class MMethodDef
                if not mproperty.is_init then res.append("fun ")
                res.append(mproperty.to_console.bold)
                if msignature != null then res.append(msignature.to_console)
-               # FIXME: modifiers should be accessible via the model
-               #if self isa ADeferredMethPropdef then ret = "{ret} is abstract"
-               #if self isa AInternMethPropdef then ret = "{ret} is intern"
-               #if self isa AExternMethPropdef then ret = "{ret} is extern"
+               if is_abstract then res.append " is abstract"
+               if is_intern then res.append " is intern"
+               if is_extern then res.append " is extern"
                return res.to_s
        end
 end
index 6f60b77..edabf23 100644 (file)
@@ -179,11 +179,11 @@ abstract class Token
 
        # The previous token in the Lexer.
        # May have disapeared in the AST
-       var prev_token: nullable Token
+       var prev_token: nullable Token = null
 
        # The next token in the Lexer.
        # May have disapeared in the AST
-       var next_token: nullable Token
+       var next_token: nullable Token = null
 
        redef fun to_s: String do
                return "'{text}'"
@@ -620,6 +620,7 @@ class AModule
        readable var _n_imports: ANodes[AImport] = new ANodes[AImport](self)
        readable var _n_extern_code_blocks: ANodes[AExternCodeBlock] = new ANodes[AExternCodeBlock](self)
        readable var _n_classdefs: ANodes[AClassdef] = new ANodes[AClassdef](self)
+       init do end
 end
 
 # The declaration of the module with the documentation, name, and annotations
@@ -628,6 +629,7 @@ class AModuledecl
        readable writable var _n_doc: nullable ADoc = null
        readable writable var _n_kwmodule: TKwmodule
        readable writable var _n_name: AModuleName
+       init do end
 end
 
 # A import clause of a module
@@ -641,6 +643,7 @@ class AStdImport
        readable writable var _n_visibility: AVisibility
        readable writable var _n_kwimport: TKwimport
        readable writable var _n_name: AModuleName
+       init do end
 end
 
 # The special import clause of the kernel module. eg `import end`
@@ -649,6 +652,7 @@ class ANoImport
        readable writable var _n_visibility: AVisibility
        readable writable var _n_kwimport: TKwimport
        readable writable var _n_kwend: TKwend
+       init do end
 end
 
 # A visibility modifier
@@ -666,21 +670,26 @@ end
 class APrivateVisibility
        super AVisibility
        readable writable var _n_kwprivate: TKwprivate
+       init do end
 end
 class AProtectedVisibility
        super AVisibility
        readable writable var _n_kwprotected: TKwprotected
+       init do end
 end
 class AIntrudeVisibility
        super AVisibility
        readable writable var _n_kwintrude: TKwintrude
+       init do end
 end
 
 # A class definition
 # While most definition are `AStdClassdef`
 # There is tow special case of class definition
-abstract class AClassdef super Prod
+abstract class AClassdef
+       super Prod
        readable var _n_propdefs: ANodes[APropdef] = new ANodes[APropdef](self)
+       init do end
 end
 
 # A standard class definition with a name, superclasses and properties
@@ -696,6 +705,7 @@ class AStdClassdef
        readable var _n_superclasses: ANodes[ASuperclass] = new ANodes[ASuperclass](self)
        readable writable var _n_kwend: TKwend
        redef fun hot_location do return n_id.location
+       init do end
 end
 
 # The implicit class definition of the implicit main method
@@ -715,24 +725,29 @@ end
 class AConcreteClasskind
        super AClasskind
        readable writable var _n_kwclass: TKwclass
+       init do end
 end
 class AAbstractClasskind
        super AClasskind
        readable writable var _n_kwabstract: TKwabstract
        readable writable var _n_kwclass: TKwclass
+       init do end
 end
 class AInterfaceClasskind
        super AClasskind
        readable writable var _n_kwinterface: TKwinterface
+       init do end
 end
 class AEnumClasskind
        super AClasskind
        readable writable var _n_kwenum: TKwenum
+       init do end
 end
 class AExternClasskind
        super AClasskind
        readable writable var _n_kwextern: TKwextern
        readable writable var _n_kwclass: nullable TKwclass = null
+       init do end
 end
 
 # The definition of a formal generic parameter type. eg `X: Y`
@@ -741,6 +756,7 @@ class AFormaldef
        readable writable var _n_id: TClassid
        # The bound of the parameter type
        readable writable var _n_type: nullable AType = null
+       init do end
 end
 
 # A super-class. eg `super X`
@@ -748,20 +764,21 @@ class ASuperclass
        super Prod
        readable writable var _n_kwsuper: TKwsuper
        readable writable var _n_type: AType
+       init do end
 end
 
 # The definition of a property
 abstract class APropdef
        super Prod
        readable writable var _n_doc: nullable ADoc = null
+       readable writable var _n_kwredef: nullable TKwredef = null
+       readable writable var _n_visibility: nullable AVisibility = null
 end
 
 # A definition of an attribute
 # For historical reason, old-syle and new-style attributes use the same `ANode` sub-class
 class AAttrPropdef
        super APropdef
-       readable writable var _n_kwredef: nullable TKwredef = null
-       readable writable var _n_visibility: AVisibility
        readable writable var _n_kwvar: TKwvar
 
        # The identifier for an old-style attribute (null if new-style)
@@ -780,19 +797,29 @@ class AAttrPropdef
        do
                if n_id != null then return n_id.location else return n_id2.location
        end
+       init do end
 end
 
 # A definition of all kind of method (including constructors)
 abstract class AMethPropdef
        super APropdef
-       readable writable var _n_kwredef: nullable TKwredef = null
-       readable writable var _n_visibility: nullable AVisibility
+       readable writable var _n_kwmeth: nullable TKwmeth = null
+       readable writable var _n_kwinit: nullable TKwinit = null
+       readable writable var _n_kwnew: nullable TKwnew = null
        readable writable var _n_methid: nullable AMethid = null
-       readable writable var _n_signature: nullable ASignature
+       readable writable var _n_signature: nullable ASignature = null
+       readable writable var _n_block: nullable AExpr = null
+       readable writable var _n_extern: nullable TString = null
+       readable writable var _n_extern_calls: nullable AExternCalls = null
+       readable writable var _n_extern_code_block: nullable AExternCodeBlock = null
        redef fun hot_location
        do
                if n_methid != null then
                        return n_methid.location
+               else if n_kwinit != null then
+                       return n_kwinit.location
+               else if n_kwnew != null then
+                       return n_kwnew.location
                else
                        return location
                end
@@ -803,34 +830,26 @@ end
 # *deferred* is a old synonynmous of *abstract* that comes from PRM, that comes from Eiffel.
 class ADeferredMethPropdef
        super AMethPropdef
-       readable writable var _n_kwmeth: TKwmeth
 end
 
 # A method marked intern
 class AInternMethPropdef
        super AMethPropdef
-       readable writable var _n_kwmeth: TKwmeth
 end
 
 # A method of a constructor marked extern
 abstract class AExternPropdef
        super AMethPropdef
-       readable writable var _n_extern: nullable TString = null
-       readable writable var _n_extern_calls: nullable AExternCalls = null
-       readable writable var _n_extern_code_block: nullable AExternCodeBlock = null
 end
 
 # A method marked extern
 class AExternMethPropdef
        super AExternPropdef
-       readable writable var _n_kwmeth: TKwmeth
 end
 
 # A method with a body
 class AConcreteMethPropdef
        super AMethPropdef
-       readable writable var _n_kwmeth: nullable TKwmeth
-       readable writable var _n_block: nullable AExpr = null
 end
 
 # A constructor
@@ -842,15 +861,12 @@ end
 class AConcreteInitPropdef
        super AConcreteMethPropdef
        super AInitPropdef
-       readable writable var _n_kwinit: TKwinit
-       redef fun hot_location do return n_kwinit.location
 end
 
 # A constructor marked extern (defined with the `new` keyword)
 class AExternInitPropdef
        super AExternPropdef
        super AInitPropdef
-       readable writable var _n_kwnew: TKwnew
 end
 
 # The implicit main method
@@ -863,6 +879,7 @@ class AExternCalls
        super Prod
        readable writable var _n_kwimport: TKwimport
        readable var _n_extern_calls: ANodes[AExternCall] = new ANodes[AExternCall](self)
+       init do end
 end
 abstract class AExternCall
        super Prod
@@ -873,20 +890,24 @@ end
 class ALocalPropExternCall
        super APropExternCall
        readable writable var _n_methid: AMethid
+       init do end
 end
 class AFullPropExternCall
        super APropExternCall
        readable writable var _n_type: AType
        readable writable var _n_dot: nullable TDot = null
        readable writable var _n_methid: AMethid
+       init do end
 end
 class AInitPropExternCall
        super APropExternCall
        readable writable var _n_type: AType
+       init do end
 end
 class ASuperExternCall
        super AExternCall
        readable writable var _n_kwsuper: TKwsuper
+       init do end
 end
 abstract class ACastExternCall
        super AExternCall
@@ -897,12 +918,14 @@ class ACastAsExternCall
        readable writable var _n_dot: nullable TDot = null
        readable writable var _n_kwas: TKwas
        readable writable var _n_to_type: AType
+       init do end
 end
 class AAsNullableExternCall
        super ACastExternCall
        readable writable var _n_type: AType
        readable writable var _n_kwas: TKwas
        readable writable var _n_kwnullable: TKwnullable
+       init do end
 end
 class AAsNotNullableExternCall
        super ACastExternCall
@@ -910,16 +933,16 @@ class AAsNotNullableExternCall
        readable writable var _n_kwas: TKwas
        readable writable var _n_kwnot: TKwnot
        readable writable var _n_kwnullable: TKwnullable
+       init do end
 end
 
 # A definition of a virtual type
 class ATypePropdef
        super APropdef
-       readable writable var _n_kwredef: nullable TKwredef = null
-       readable writable var _n_visibility: AVisibility
        readable writable var _n_kwtype: TKwtype
        readable writable var _n_id: TClassid
        readable writable var _n_type: AType
+       init do end
 end
 
 # A `writable` or `readable` modifier
@@ -927,18 +950,21 @@ abstract class AAble
        super Prod
        readable writable var _n_visibility: nullable AVisibility = null
        readable writable var _n_kwredef: nullable TKwredef = null
+       init do end
 end
 
 # A `readable` modifier
 class AReadAble
        super AAble
        readable writable var _n_kwreadable: TKwreadable
+       init do end
 end
 
 # A `writable` modifier
 class AWriteAble
        super AAble
        readable writable var _n_kwwritable: TKwwritable
+       init do end
 end
 
 # The identifier of a method in a method declaration.
@@ -949,78 +975,96 @@ end
 class AIdMethid
        super AMethid
        readable writable var _n_id: TId
+       init do end
 end
 class APlusMethid
        super AMethid
        readable writable var _n_plus: TPlus
+       init do end
 end
 class AMinusMethid
        super AMethid
        readable writable var _n_minus: TMinus
+       init do end
 end
 class AStarMethid
        super AMethid
        readable writable var _n_star: TStar
+       init do end
 end
 class ASlashMethid
        super AMethid
        readable writable var _n_slash: TSlash
+       init do end
 end
 class APercentMethid
        super AMethid
        readable writable var _n_percent: TPercent
+       init do end
 end
 class AEqMethid
        super AMethid
        readable writable var _n_eq: TEq
+       init do end
 end
 class ANeMethid
        super AMethid
        readable writable var _n_ne: TNe
+       init do end
 end
 class ALeMethid
        super AMethid
        readable writable var _n_le: TLe
+       init do end
 end
 class AGeMethid
        super AMethid
        readable writable var _n_ge: TGe
+       init do end
 end
 class ALtMethid
        super AMethid
        readable writable var _n_lt: TLt
+       init do end
 end
 class AGtMethid
        super AMethid
        readable writable var _n_gt: TGt
+       init do end
 end
 class ALlMethid
        super AMethid
        readable writable var _n_ll: TLl
+       init do end
 end
 class AGgMethid
        super AMethid
        readable writable var _n_gg: TGg
+       init do end
 end
 class ABraMethid
        super AMethid
        readable writable var _n_obra: TObra
        readable writable var _n_cbra: TCbra
+       init do end
 end
 class AStarshipMethid
        super AMethid
        readable writable var _n_starship: TStarship
+       init do end
 end
 class AAssignMethid
        super AMethid
        readable writable var _n_id: TId
        readable writable var _n_assign: TAssign
+       init do end
 end
 class ABraassignMethid
        super AMethid
        readable writable var _n_obra: TObra
        readable writable var _n_cbra: TCbra
        readable writable var _n_assign: TAssign
+       init do end
 end
 
 # A signature in a method definition. eg `(x,y:X,z:Z):T`
@@ -1030,6 +1074,7 @@ class ASignature
        readable var _n_params: ANodes[AParam] = new ANodes[AParam](self)
        readable writable var _n_cpar: nullable TCpar = null
        readable writable var _n_type: nullable AType = null
+       init do end
 end
 
 # A parameter definition in a signature. eg `x:X`
@@ -1038,6 +1083,7 @@ class AParam
        readable writable var _n_id: TId
        readable writable var _n_type: nullable AType = null
        readable writable var _n_dotdotdot: nullable TDotdotdot = null
+       init do end
 end
 
 # A static type. eg `nullable X[Y]`
@@ -1050,6 +1096,7 @@ class AType
 
        # Type arguments for a generic type
        readable var _n_types: ANodes[AType] = new ANodes[AType](self)
+       init do end
 end
 
 # A label at the end of a block or in a break/continue statement. eg `label x`
@@ -1057,6 +1104,7 @@ class ALabel
        super Prod
        readable writable var _n_kwlabel: TKwlabel
        readable writable var _n_id: TId
+       init do end
 end
 
 # Expression and statements
@@ -1071,6 +1119,7 @@ class ABlockExpr
        super AExpr
        readable var _n_expr: ANodes[AExpr] = new ANodes[AExpr](self)
        readable writable var _n_kwend: nullable TKwend = null
+       init do end
 end
 
 # A declaration of a local variable. eg `var x: X = y`
@@ -1083,6 +1132,7 @@ class AVardeclExpr
 
        # The initial value, if any
        readable writable var _n_expr: nullable AExpr = null
+       init do end
 end
 
 # A `return` statement. eg `return x`
@@ -1090,12 +1140,14 @@ class AReturnExpr
        super AExpr
        readable writable var _n_kwreturn: nullable TKwreturn = null
        readable writable var _n_expr: nullable AExpr = null
+       init do end
 end
 
 # Something that has a label.
 abstract class ALabelable
        super Prod
        readable writable var _n_label: nullable ALabel = null
+       init do end
 end
 
 # A `break` statement.
@@ -1104,12 +1156,14 @@ class ABreakExpr
        super ALabelable
        readable writable var _n_kwbreak: TKwbreak
        readable writable var _n_expr: nullable AExpr = null
+       init do end
 end
 
 # An `abort` statement
 class AAbortExpr
        super AExpr
        readable writable var _n_kwabort: TKwabort
+       init do end
 end
 
 # A `continue` statement
@@ -1118,6 +1172,7 @@ class AContinueExpr
        super ALabelable
        readable writable var _n_kwcontinue: nullable TKwcontinue = null
        readable writable var _n_expr: nullable AExpr = null
+       init do end
 end
 
 # A `do` statement
@@ -1126,6 +1181,7 @@ class ADoExpr
        super ALabelable
        readable writable var _n_kwdo: TKwdo
        readable writable var _n_block: nullable AExpr = null
+       init do end
 end
 
 # A `if` statement
@@ -1135,6 +1191,7 @@ class AIfExpr
        readable writable var _n_expr: AExpr
        readable writable var _n_then: nullable AExpr = null
        readable writable var _n_else: nullable AExpr = null
+       init do end
 end
 
 # A `if` expression
@@ -1146,6 +1203,7 @@ class AIfexprExpr
        readable writable var _n_then: AExpr
        readable writable var _n_kwelse: TKwelse
        readable writable var _n_else: AExpr
+       init do end
 end
 
 # A `while` statement
@@ -1156,6 +1214,7 @@ class AWhileExpr
        readable writable var _n_expr: AExpr
        readable writable var _n_kwdo: TKwdo
        readable writable var _n_block: nullable AExpr = null
+       init do end
 end
 
 # A `loop` statement
@@ -1164,6 +1223,7 @@ class ALoopExpr
        super ALabelable
        readable writable var _n_kwloop: TKwloop
        readable writable var _n_block: nullable AExpr = null
+       init do end
 end
 
 # A `for` statement
@@ -1175,6 +1235,7 @@ class AForExpr
        readable writable var _n_expr: AExpr
        readable writable var _n_kwdo: TKwdo
        readable writable var _n_block: nullable AExpr = null
+       init do end
 end
 
 # An `assert` statement
@@ -1184,6 +1245,7 @@ class AAssertExpr
        readable writable var _n_id: nullable TId = null
        readable writable var _n_expr: AExpr
        readable writable var _n_else: nullable AExpr = null
+       init do end
 end
 
 # Whatever is a simple assignment. eg `= something`
@@ -1191,6 +1253,7 @@ abstract class AAssignFormExpr
        super AExpr
        readable writable var _n_assign: TAssign
        readable writable var _n_value: AExpr
+       init do end
 end
 
 # Whatever is a combined assignment. eg `+= something`
@@ -1198,12 +1261,14 @@ abstract class AReassignFormExpr
        super AExpr
        readable writable var _n_assign_op: AAssignOp
        readable writable var _n_value: AExpr
+       init do end
 end
 
 # A `once` expression. eg `once x`
 class AOnceExpr
        super AProxyExpr
        readable writable var _n_kwonce: TKwonce
+       init do end
 end
 
 # A polymorphic invocation of a method
@@ -1212,6 +1277,7 @@ abstract class ASendExpr
        super AExpr
        # The receiver of the method invocation
        readable writable var _n_expr: AExpr
+       init do end
 end
 
 # A binary operation on a method
@@ -1220,6 +1286,7 @@ abstract class ABinopExpr
        # The second operand of the operation
        # Note: the receiver (`n_expr`) is the first operand
        readable writable var _n_expr2: AExpr
+       init do end
 end
 
 # Something that is boolean expression
@@ -1232,6 +1299,7 @@ class AOrExpr
        super ABoolExpr
        readable writable var _n_expr: AExpr
        readable writable var _n_expr2: AExpr
+       init do end
 end
 
 # A `and` expression
@@ -1239,6 +1307,7 @@ class AAndExpr
        super ABoolExpr
        readable writable var _n_expr: AExpr
        readable writable var _n_expr2: AExpr
+       init do end
 end
 
 # A `or else` expression
@@ -1246,6 +1315,7 @@ class AOrElseExpr
        super ABoolExpr
        readable writable var _n_expr: AExpr
        readable writable var _n_expr2: AExpr
+       init do end
 end
 
 # A `implies` expression
@@ -1253,6 +1323,7 @@ class AImpliesExpr
        super ABoolExpr
        readable writable var _n_expr: AExpr
        readable writable var _n_expr2: AExpr
+       init do end
 end
 
 # A `not` expression
@@ -1260,6 +1331,7 @@ class ANotExpr
        super ABoolExpr
        readable writable var _n_kwnot: TKwnot
        readable writable var _n_expr: AExpr
+       init do end
 end
 
 # A `==` expression
@@ -1307,6 +1379,7 @@ class AIsaExpr
        super ABoolExpr
        readable writable var _n_expr: AExpr
        readable writable var _n_type: AType
+       init do end
 end
 
 # A `+` expression
@@ -1343,6 +1416,7 @@ end
 class AUminusExpr
        super ASendExpr
        readable writable var _n_minus: TMinus
+       init do end
 end
 
 # An explicit instantiation. eg `new T`
@@ -1354,6 +1428,7 @@ class ANewExpr
        # The name of the named-constructor, if any
        readable writable var _n_id: nullable TId = null
        readable writable var _n_args: AExprs
+       init do end
 end
 
 # Whatever is a old-style attribute access
@@ -1365,6 +1440,8 @@ abstract class AAttrFormExpr
 
        # The name of the attribute
        readable writable var _n_id: TAttrid
+
+       init do end
 end
 
 # The read of an attribute. eg `x._a`
@@ -1387,6 +1464,7 @@ abstract class ACallFormExpr
 
        # The arguments of the call
        readable writable var _n_args: AExprs
+       init do end
 end
 
 # A complex setter call (standard or brackets)
@@ -1430,6 +1508,7 @@ class ASuperExpr
        readable writable var _n_qualified: nullable AQualified = null
        readable writable var _n_kwsuper: TKwsuper
        readable writable var _n_args: AExprs
+       init do end
 end
 
 # A call to the `init` constructor.
@@ -1438,12 +1517,14 @@ class AInitExpr
        super ASendExpr
        readable writable var _n_kwinit: TKwinit
        readable writable var _n_args: AExprs
+       init do end
 end
 
 # Whatever looks-like a call of the brackets `[]` operator.
 abstract class ABraFormExpr
        super ASendExpr
        readable writable var _n_args: AExprs
+       init do end
 end
 
 # A call of the brackets operator. eg `x[y,z]`
@@ -1461,6 +1542,7 @@ end
 abstract class AVarFormExpr
        super AExpr
        readable writable var _n_id: TId
+       init do end
 end
 
 # A complex setter call of the bracket operator. eg `x[y,z]+=t`
@@ -1494,6 +1576,7 @@ abstract class ARangeExpr
        super AExpr
        readable writable var _n_expr: AExpr
        readable writable var _n_expr2: AExpr
+       init do end
 end
 
 # A closed literal range. eg `[x..y]`
@@ -1501,6 +1584,7 @@ class ACrangeExpr
        super ARangeExpr
        readable writable var _n_obra: TObra
        readable writable var _n_cbra: TCbra
+       init do end
 end
 
 # An open literal range. eg `[x..y[`
@@ -1508,18 +1592,21 @@ class AOrangeExpr
        super ARangeExpr
        readable writable var _n_obra: TObra
        readable writable var _n_cbra: TObra
+       init do end
 end
 
 # A literal array. eg. `[x,y,z]`
 class AArrayExpr
        super AExpr
        readable writable var _n_exprs: AExprs
+       init do end
 end
 
 # A read of `self` 
 class ASelfExpr
        super AExpr
        readable writable var _n_kwself: nullable TKwself
+       init do end
 end
 
 # When there is no explicit receiver, `self` is implicit
@@ -1531,16 +1618,19 @@ end
 class ATrueExpr
        super ABoolExpr
        readable writable var _n_kwtrue: TKwtrue
+       init do end
 end
 # A `false` boolean literal constant
 class AFalseExpr
        super ABoolExpr
        readable writable var _n_kwfalse: TKwfalse
+       init do end
 end
 # A `null` literal constant
 class ANullExpr
        super AExpr
        readable writable var _n_kwnull: TKwnull
+       init do end
 end
 # An integer literal
 class AIntExpr
@@ -1550,26 +1640,31 @@ end
 class ADecIntExpr
        super AIntExpr
        readable writable var _n_number: TNumber
+       init do end
 end
 # An integer literal in hexadecimal format
 class AHexIntExpr
        super AIntExpr
        readable writable var _n_hex_number: THexNumber
+       init do end
 end
 # A float literal
 class AFloatExpr
        super AExpr
        readable writable var _n_float: TFloat
+       init do end
 end
 # A character literal
 class ACharExpr
        super AExpr
        readable writable var _n_char: TChar
+       init do end
 end
 # A string literal
 abstract class AStringFormExpr
        super AExpr
        readable writable var _n_string: Token
+       init do end
 end
 
 # A simple string. eg. `"abc"`
@@ -1597,6 +1692,7 @@ end
 class ASuperstringExpr
        super AExpr
        readable var _n_exprs: ANodes[AExpr] = new ANodes[AExpr](self)
+       init do end
 end
 
 # A simple parenthesis. eg `(x)`
@@ -1604,12 +1700,14 @@ class AParExpr
        super AProxyExpr
        readable writable var _n_opar: TOpar
        readable writable var _n_cpar: TCpar
+       init do end
 end
 
 # Whatevej just contains (and mimic) an other expression
 abstract class AProxyExpr
        super AExpr
        readable writable var _n_expr: AExpr
+       init do end
 end
 
 # A type cast. eg `x.as(T)`
@@ -1620,6 +1718,7 @@ class AAsCastExpr
        readable writable var _n_opar: nullable TOpar = null
        readable writable var _n_type: AType
        readable writable var _n_cpar: nullable TCpar = null
+       init do end
 end
 
 # A as-not-null cast. eg `x.as(not null)`
@@ -1631,18 +1730,21 @@ class AAsNotnullExpr
        readable writable var _n_kwnot: TKwnot
        readable writable var _n_kwnull: TKwnull
        readable writable var _n_cpar: nullable TCpar = null
+       init do end
 end
 
 # A is-set check of old-style attributes. eg `isset x._a`
 class AIssetAttrExpr
        super AAttrFormExpr
        readable writable var _n_kwisset: TKwisset
+       init do end
 end
 
 # A list of expression separated with commas (arguments for instance)
 abstract class AExprs
        super Prod 
        readable var _n_exprs: ANodes[AExpr] = new ANodes[AExpr](self)
+       init do end
 end
 
 class ADebugTypeExpr
@@ -1651,6 +1753,7 @@ class ADebugTypeExpr
        readable writable var _n_kwtype: TKwtype
        readable writable var _n_expr: AExpr
        readable writable var _n_type: AType
+       init do end
 end
 
 # A simple list of expressions
@@ -1663,6 +1766,7 @@ class AParExprs
        super AExprs
        readable writable var _n_opar: TOpar
        readable writable var _n_cpar: TCpar
+       init do end
 end
 
 # A list of expressions enclosed in brackets
@@ -1670,6 +1774,7 @@ class ABraExprs
        super AExprs
        readable writable var _n_obra: TObra
        readable writable var _n_cbra: TCbra
+       init do end
 end
 
 # A complex assignment operator. eg `+=`
@@ -1679,10 +1784,12 @@ end
 class APlusAssignOp
        super AAssignOp
        readable writable var _n_pluseq: TPluseq
+       init do end
 end
 class AMinusAssignOp
        super AAssignOp
        readable writable var _n_minuseq: TMinuseq
+       init do end
 end
 
 class AModuleName
@@ -1690,22 +1797,26 @@ class AModuleName
        readable writable var _n_quad: nullable TQuad = null
        readable var _n_path: ANodes[TId] = new ANodes[TId](self)
        readable writable var _n_id: TId
+       init do end
 end
 class AInLanguage
        super Prod
        readable writable var _n_kwin: TKwin
        readable writable var _n_string: TString
+       init do end
 end
 class AExternCodeBlock
        super Prod
        readable writable var _n_in_language: nullable AInLanguage = null
        readable writable var _n_extern_code_segment: TExternCodeSegment
+       init do end
 end
 class AQualified
        super Prod
        readable writable var _n_quad: nullable TQuad = null
        readable var _n_id: ANodes[TId] = new ANodes[TId](self)
        readable writable var _n_classid: nullable TClassid = null
+       init do end
 end
 
 # A documentation of a definition
@@ -1713,6 +1824,7 @@ end
 class ADoc
        super Prod
        readable var _n_comment: ANodes[TComment] = new ANodes[TComment](self)
+       init do end
 end
 
 class AAnnotations
@@ -1721,6 +1833,7 @@ class AAnnotations
        readable writable var _n_opar: nullable TOpar = null
        readable var _n_items: ANodes[AAnnotation] = new ANodes[AAnnotation](self)
        readable writable var _n_cpar: nullable TCpar = null
+       init do end
 end
 class AAnnotation
        super Prod
@@ -1728,6 +1841,7 @@ class AAnnotation
        readable writable var _n_opar: nullable TOpar = null
        readable var _n_args: ANodes[AAtArg] = new ANodes[AAtArg](self)
        readable writable var _n_cpar: nullable TCpar = null
+       init do end
 end
 abstract class AAtArg
        super Prod
@@ -1735,10 +1849,12 @@ end
 class ATypeAtArg
        super AAtArg
        readable writable var _n_type: AType
+       init do end
 end
 class AExprAtArg
        super AAtArg
        readable writable var _n_expr: AExpr
+       init do end
 end
 class AAtAtArg
        super AAtArg
@@ -1746,6 +1862,7 @@ end
 abstract class AAtid
        super Prod
        readable writable var _n_id: Token
+       init do end
 end
 class AIdAtid
        super AAtid
index 32fe720..55ff3f7 100644 (file)
@@ -69,7 +69,7 @@ redef class ToolContext
        do
                var mod_string = "do\n{string}\nend"
                var nmodule = parse_module(mod_string)
-               var nblock = nmodule.n_classdefs.first.n_propdefs.first.as(AMainMethPropdef).n_block.as(ABlockExpr).n_expr.first.as(ADoExpr).n_block.as(not null)
+               var nblock = nmodule.n_classdefs.first.n_propdefs.first.as(AMethPropdef).n_block.as(ABlockExpr).n_expr.first.as(ADoExpr).n_block.as(not null)
                return nblock
        end
 
@@ -79,7 +79,7 @@ redef class ToolContext
        do
                var mod_string = "var dummy = \n{string}"
                var nmodule = parse_module(mod_string)
-               var nexpr = nmodule.n_classdefs.first.n_propdefs.first.as(AMainMethPropdef).n_block.as(ABlockExpr).n_expr.first.as(AVardeclExpr).n_expr.as(not null)
+               var nexpr = nmodule.n_classdefs.first.n_propdefs.first.as(AMethPropdef).n_block.as(ABlockExpr).n_expr.first.as(AVardeclExpr).n_expr.as(not null)
                return nexpr
        end
 
@@ -120,7 +120,7 @@ redef class ToolContext
                tree = (new Parser(lexer)).parse
                eof = tree.n_eof
                if not eof isa AError then
-                       var ntype = tree.n_base.n_classdefs.first.n_propdefs.first.as(AMainMethPropdef).n_block.as(ABlockExpr).n_expr.first.as(AVardeclExpr).n_type.n_types.first
+                       var ntype = tree.n_base.n_classdefs.first.n_propdefs.first.as(AMethPropdef).n_block.as(ABlockExpr).n_expr.first.as(AVardeclExpr).n_type.n_types.first
                        return ntype
                end
                error = eof
@@ -143,7 +143,7 @@ redef class ToolContext
                tree = (new Parser(lexer)).parse
                eof = tree.n_eof
                if not eof isa AError then
-                       var nexpr = tree.n_base.n_classdefs.first.n_propdefs.first.as(AMainMethPropdef).n_block.as(ABlockExpr).n_expr.first.as(AVardeclExpr).n_expr.as(AParExpr).n_expr
+                       var nexpr = tree.n_base.n_classdefs.first.n_propdefs.first.as(AMethPropdef).n_block.as(ABlockExpr).n_expr.first.as(AVardeclExpr).n_expr.as(AParExpr).n_expr
                        return nexpr
                end
                if eof.location > error.location then error = eof
@@ -156,7 +156,8 @@ redef class ToolContext
                tree = (new Parser(lexer)).parse
                eof = tree.n_eof
                if not eof isa AError then
-                       var nblock = tree.n_base.n_classdefs.first.n_propdefs.first.as(AMainMethPropdef).n_block.as(ABlockExpr).n_expr.first.as(ADoExpr).n_block.as(not null)
+                       var nblock = tree.n_base.n_classdefs.first.n_propdefs.first.as(AMethPropdef).n_block.as(ABlockExpr).n_expr.first.as(ADoExpr).n_block.as(ABlockExpr)
+                       nblock.n_kwend = null # drop injected token
                        return nblock
                end
                if eof.location > error.location then error = eof
@@ -180,7 +181,7 @@ redef class ToolContext
                loop
                        printn prompt
                        printn " "
-                       var s = stdin.read_line
+                       var s = sys.stdin.read_line
                        if s == "" then continue
                        if s.chars.first == ':' then
                                var res = new TString
index a40ca22..b2683c2 100644 (file)
@@ -203,6 +203,7 @@ class RapidTypeAnalysis
 
                while not todo.is_empty do
                        var mmethoddef = todo.shift
+                       var mmeth = mmethoddef.mproperty
                        #print "# visit {mmethoddef}"
                        var v = new RapidTypeVisitor(self, mmethoddef.mclassdef.bound_mtype, mmethoddef)
 
@@ -218,18 +219,18 @@ class RapidTypeAnalysis
                                v.add_monomorphic_send(vararg, self.modelbuilder.force_get_primitive_method(node, "with_native", vararg.mclass, self.mainmodule))
                        end
 
-
-                       for i in [0..mmethoddef.msignature.arity[ do
-                               var origtype = mmethoddef.mproperty.intro.msignature.mparameters[i].mtype
+                       var sig = mmethoddef.msignature.as(not null)
+                       var osig = mmeth.intro.msignature.as(not null)
+                       for i in [0..sig.arity[ do
+                               var origtype = osig.mparameters[i].mtype
                                if not origtype.need_anchor then continue # skip non covariant stuff
-                               var paramtype = mmethoddef.msignature.mparameters[i].mtype
-                               #paramtype = v.cleanup_type(paramtype).as(not null)
+                               var paramtype = sig.mparameters[i].mtype
                                add_cast(paramtype)
                        end
 
                        if not modelbuilder.mpropdef2npropdef.has_key(mmethoddef) then
                                # It is an init for a class?
-                               if mmethoddef.mproperty.name == "init" then
+                               if mmeth.name == "init" then
                                        var nclassdef = self.modelbuilder.mclassdef2nclassdef[mmethoddef.mclassdef]
                                        var super_inits = nclassdef.super_inits
                                        if super_inits != null then
@@ -247,27 +248,23 @@ class RapidTypeAnalysis
 
                        var npropdef = modelbuilder.mpropdef2npropdef[mmethoddef]
 
-                       if npropdef isa AConcreteMethPropdef then
+                       if npropdef isa AMethPropdef  then
                                var auto_super_inits = npropdef.auto_super_inits
                                if auto_super_inits != null then
                                        for auto_super_init in auto_super_inits do
                                                v.add_callsite(auto_super_init)
                                        end
                                end
-                       else if npropdef isa AInternMethPropdef or
-                         (npropdef isa AExternMethPropdef and npropdef.n_extern != null) then
+                       end
+
+                       if mmeth.is_new then
+                               v.add_type(v.receiver)
+                       else if mmethoddef.is_intern or mmethoddef.is_extern then
                                # UGLY: We force the "instantation" of the concrete return type if any
                                var ret = mmethoddef.msignature.return_mtype
                                if ret != null and ret isa MClassType and ret.mclass.kind != abstract_kind and ret.mclass.kind != interface_kind then
                                        v.add_type(ret)
                                end
-                       else if npropdef isa AExternMethPropdef then
-                               var nclassdef = npropdef.parent.as(AClassdef)
-                               v.enter_visit(npropdef)
-                       else if npropdef isa AExternInitPropdef then
-                               v.add_type(v.receiver)
-                       else
-
                        end
 
                        v.enter_visit(npropdef)
index f7863c6..fe9000c 100644 (file)
@@ -16,7 +16,7 @@
 module separate_compiler
 
 import abstract_compiler
-import layout_builders
+import coloring
 import rapid_type_analysis
 
 # Add separate compiler specific options
@@ -40,13 +40,7 @@ redef class ToolContext
        # --semi-global
        var opt_semi_global = new OptionBool("Enable all semi-global optimizations", "--semi-global")
        # --no-colo-dead-methods
-       var opt_no_colo_dead_methods = new OptionBool("Do not colorize dead methods", "--no-colo-dead-methods")
-       # --use-naive-coloring
-       var opt_bm_typing: OptionBool = new OptionBool("Colorize items incrementaly, used to simulate binary matrix typing", "--bm-typing")
-       # --use-mod-perfect-hashing
-       var opt_phmod_typing: OptionBool = new OptionBool("Replace coloration by perfect hashing (with mod operator)", "--phmod-typing")
-       # --use-and-perfect-hashing
-       var opt_phand_typing: OptionBool = new OptionBool("Replace coloration by perfect hashing (with and operator)", "--phand-typing")
+       var opt_colo_dead_methods = new OptionBool("Force colorization of dead methods", "--colo-dead-methods")
        # --tables-metrics
        var opt_tables_metrics: OptionBool = new OptionBool("Enable static size measuring of tables used for vft, typing and resolution", "--tables-metrics")
 
@@ -58,10 +52,7 @@ redef class ToolContext
                self.option_context.add_option(self.opt_no_union_attribute)
                self.option_context.add_option(self.opt_no_shortcut_equate)
                self.option_context.add_option(self.opt_inline_coloring_numbers, opt_inline_some_methods, opt_direct_call_monomorph, opt_skip_dead_methods, opt_semi_global)
-               self.option_context.add_option(self.opt_no_colo_dead_methods)
-               self.option_context.add_option(self.opt_bm_typing)
-               self.option_context.add_option(self.opt_phmod_typing)
-               self.option_context.add_option(self.opt_phand_typing)
+               self.option_context.add_option(self.opt_colo_dead_methods)
                self.option_context.add_option(self.opt_tables_metrics)
        end
 
@@ -163,10 +154,11 @@ class SeparateCompiler
        private var undead_types: Set[MType] = new HashSet[MType]
        private var live_unresolved_types: Map[MClassDef, Set[MType]] = new HashMap[MClassDef, HashSet[MType]]
 
-       private var type_layout: nullable Layout[MType]
-       private var resolution_layout: nullable Layout[MType]
-       protected var method_layout: nullable Layout[PropertyLayoutElement]
-       protected var attr_layout: nullable Layout[MAttribute]
+       private var type_ids: Map[MType, Int]
+       private var type_colors: Map[MType, Int]
+       private var opentype_colors: Map[MType, Int]
+       protected var method_colors: Map[PropertyLayoutElement, Int]
+       protected var attr_colors: Map[MAttribute, Int]
 
        init(mainmodule: MModule, mmbuilder: ModelBuilder, runtime_type_analysis: nullable RapidTypeAnalysis) do
                super(mainmodule, mmbuilder)
@@ -184,19 +176,7 @@ class SeparateCompiler
                # With resolution_table_table, all live type resolution are stored in a big table: resolution_table
                self.header.add_decl("struct type \{ int id; const char *name; int color; short int is_nullable; const struct types *resolution_table; int table_size; int type_table[]; \}; /* general C type representing a Nit type. */")
                self.header.add_decl("struct instance \{ const struct type *type; const struct class *class; nitattribute_t attrs[]; \}; /* general C type representing a Nit instance. */")
-
-               if modelbuilder.toolcontext.opt_phmod_typing.value or modelbuilder.toolcontext.opt_phand_typing.value then
-                       self.header.add_decl("struct types \{ int mask; const struct type *types[]; \}; /* a list types (used for vts, fts and unresolved lists). */")
-               else
-                       self.header.add_decl("struct types \{ int dummy; const struct type *types[]; \}; /* a list types (used for vts, fts and unresolved lists). */")
-               end
-
-               if modelbuilder.toolcontext.opt_phmod_typing.value then
-                       self.header.add_decl("#define HASH(mask, id) ((mask)%(id))")
-               else if modelbuilder.toolcontext.opt_phand_typing.value then
-                       self.header.add_decl("#define HASH(mask, id) ((mask)&(id))")
-               end
-
+               self.header.add_decl("struct types \{ int dummy; const struct type *types[]; \}; /* a list types (used for vts, fts and unresolved lists). */")
                self.header.add_decl("typedef struct instance val; /* general C type representing a Nit instance. */")
        end
 
@@ -279,30 +259,14 @@ class SeparateCompiler
 
        # colorize classe properties
        fun do_property_coloring do
-               var mclasses = new HashSet[MClass].from(modelbuilder.model.mclasses)
 
                var rta = runtime_type_analysis
 
                # Layouts
-               var method_layout_builder: PropertyLayoutBuilder[PropertyLayoutElement]
-               var attribute_layout_builder: PropertyLayoutBuilder[MAttribute]
-               #FIXME PH and BM layouts too slow for large programs
-               #if modelbuilder.toolcontext.opt_bm_typing.value then
-               #       method_layout_builder = new MMethodBMizer(self.mainmodule)
-               #       attribute_layout_builder = new MAttributeBMizer(self.mainmodule)
-               #else if modelbuilder.toolcontext.opt_phmod_typing.value then
-               #       method_layout_builder = new MMethodHasher(new PHModOperator, self.mainmodule)
-               #       attribute_layout_builder = new MAttributeHasher(new PHModOperator, self.mainmodule)
-               #else if modelbuilder.toolcontext.opt_phand_typing.value then
-               #       method_layout_builder = new MMethodHasher(new PHAndOperator, self.mainmodule)
-               #       attribute_layout_builder = new MAttributeHasher(new PHAndOperator, self.mainmodule)
-               #else
-
-               var class_layout_builder = new MClassColorer(self.mainmodule)
-               class_layout_builder.build_layout(mclasses)
-               method_layout_builder = new MPropertyColorer[PropertyLayoutElement](self.mainmodule, class_layout_builder)
-               attribute_layout_builder = new MPropertyColorer[MAttribute](self.mainmodule, class_layout_builder)
-               #end
+               var mclasses = new HashSet[MClass].from(modelbuilder.model.mclasses)
+               var poset = mainmodule.flatten_mclass_hierarchy
+               var colorer = new POSetColorer[MClass]
+               colorer.colorize(poset)
 
                # The dead methods, still need to provide a dead color symbol
                var dead_methods = new Array[MMethod]
@@ -315,7 +279,7 @@ class SeparateCompiler
                        mattributes[mclass] = new HashSet[MAttribute]
                        for mprop in self.mainmodule.properties(mclass) do
                                if mprop isa MMethod then
-                                       if modelbuilder.toolcontext.opt_no_colo_dead_methods.value and rta != null and not rta.live_methods.has(mprop) then
+                                       if not modelbuilder.toolcontext.opt_colo_dead_methods.value and rta != null and not rta.live_methods.has(mprop) then
                                                dead_methods.add(mprop)
                                                continue
                                        end
@@ -356,9 +320,10 @@ class SeparateCompiler
                end
 
                # methods coloration
-               self.method_layout = method_layout_builder.build_layout(mmethods)
-               self.method_tables = build_method_tables(mclasses, super_calls)
-               self.compile_color_consts(method_layout.pos)
+               var meth_colorer = new POSetBucketsColorer[MClass, PropertyLayoutElement](poset, colorer.conflicts)
+               method_colors = meth_colorer.colorize(mmethods)
+               method_tables = build_method_tables(mclasses, super_calls)
+               compile_color_consts(method_colors)
 
                # attribute null color to dead methods and supercalls
                for mproperty in dead_methods do
@@ -370,13 +335,13 @@ class SeparateCompiler
                end
 
                # attributes coloration
-               self.attr_layout = attribute_layout_builder.build_layout(mattributes)
-               self.attr_tables = build_attr_tables(mclasses)
-               self.compile_color_consts(attr_layout.pos)
+               var attr_colorer = new POSetBucketsColorer[MClass, MAttribute](poset, colorer.conflicts)
+               attr_colors = attr_colorer.colorize(mattributes)
+               attr_tables = build_attr_tables(mclasses)
+               compile_color_consts(attr_colors)
        end
 
        fun build_method_tables(mclasses: Set[MClass], super_calls: Set[MMethodDef]): Map[MClass, Array[nullable MPropDef]] do
-               var layout = self.method_layout
                var tables = new HashMap[MClass, Array[nullable MPropDef]]
                for mclass in mclasses do
                        var table = new Array[nullable MPropDef]
@@ -393,8 +358,8 @@ class SeparateCompiler
                                if parent == mclass then continue
                                for mproperty in self.mainmodule.properties(parent) do
                                        if not mproperty isa MMethod then continue
-                                       if not layout.pos.has_key(mproperty) then continue
-                                       var color = layout.pos[mproperty]
+                                       if not method_colors.has_key(mproperty) then continue
+                                       var color = method_colors[mproperty]
                                        if table.length <= color then
                                                for i in [table.length .. color[ do
                                                        table[i] = null
@@ -420,8 +385,8 @@ class SeparateCompiler
                        # then override with local properties
                        for mproperty in self.mainmodule.properties(mclass) do
                                if not mproperty isa MMethod then continue
-                               if not layout.pos.has_key(mproperty) then continue
-                               var color = layout.pos[mproperty]
+                               if not method_colors.has_key(mproperty) then continue
+                               var color = method_colors[mproperty]
                                if table.length <= color then
                                        for i in [table.length .. color[ do
                                                table[i] = null
@@ -444,7 +409,7 @@ class SeparateCompiler
                        end
                        # insert super calls in table according to receiver
                        for supercall in supercalls do
-                               var color = layout.pos[supercall]
+                               var color = method_colors[supercall]
                                if table.length <= color then
                                        for i in [table.length .. color[ do
                                                table[i] = null
@@ -459,7 +424,6 @@ class SeparateCompiler
        end
 
        fun build_attr_tables(mclasses: Set[MClass]): Map[MClass, Array[nullable MPropDef]] do
-               var layout = self.attr_layout
                var tables = new HashMap[MClass, Array[nullable MPropDef]]
                for mclass in mclasses do
                        var table = new Array[nullable MPropDef]
@@ -473,7 +437,7 @@ class SeparateCompiler
                                if parent == mclass then continue
                                for mproperty in self.mainmodule.properties(parent) do
                                        if not mproperty isa MAttribute then continue
-                                       var color = layout.pos[mproperty]
+                                       var color = attr_colors[mproperty]
                                        if table.length <= color then
                                                for i in [table.length .. color[ do
                                                        table[i] = null
@@ -490,7 +454,7 @@ class SeparateCompiler
                        # then override with local properties
                        for mproperty in self.mainmodule.properties(mclass) do
                                if not mproperty isa MAttribute then continue
-                               var color = layout.pos[mproperty]
+                               var color = attr_colors[mproperty]
                                if table.length <= color then
                                        for i in [table.length .. color[ do
                                                table[i] = null
@@ -509,29 +473,23 @@ class SeparateCompiler
 
        # colorize live types of the program
        private fun do_type_coloring: POSet[MType] do
+               # Collect types to colorize
+               var live_types = runtime_type_analysis.live_types
+               var live_cast_types = runtime_type_analysis.live_cast_types
                var mtypes = new HashSet[MType]
-               mtypes.add_all(self.runtime_type_analysis.live_types)
-               mtypes.add_all(self.runtime_type_analysis.live_cast_types)
+               mtypes.add_all(live_types)
+               mtypes.add_all(live_cast_types)
                for c in self.box_kinds.keys do
                        mtypes.add(c.mclass_type)
                end
 
-               # Typing Layout
-               var layout_builder: TypingLayoutBuilder[MType]
-               if modelbuilder.toolcontext.opt_bm_typing.value then
-                       layout_builder = new MTypeBMizer(self.mainmodule)
-               else if modelbuilder.toolcontext.opt_phmod_typing.value then
-                       layout_builder = new MTypeHasher(new PHModOperator, self.mainmodule)
-               else if modelbuilder.toolcontext.opt_phand_typing.value then
-                       layout_builder = new MTypeHasher(new PHAndOperator, self.mainmodule)
-               else
-                       layout_builder = new MTypeColorer(self.mainmodule)
-               end
-
-               # colorize types
-               self.type_layout = layout_builder.build_layout(mtypes)
-               var poset = layout_builder.poset.as(not null)
-               self.type_tables = self.build_type_tables(poset)
+               # Compute colors
+               var poset = poset_from_mtypes(mtypes)
+               var colorer = new POSetColorer[MType]
+               colorer.colorize(poset)
+               type_ids = colorer.ids
+               type_colors = colorer.colors
+               type_tables = build_type_tables(poset)
 
                # VT and FT are stored with other unresolved types in the big resolution_tables
                self.compile_resolution_tables(mtypes)
@@ -539,19 +497,27 @@ class SeparateCompiler
                return poset
        end
 
+       private fun poset_from_mtypes(mtypes: Set[MType]): POSet[MType] do
+               var poset = new POSet[MType]
+               for e in mtypes do
+                       poset.add_node(e)
+                       for o in mtypes do
+                               if e == o then continue
+                               if e.is_subtype(mainmodule, null, o) then
+                                       poset.add_edge(e, o)
+                               end
+                       end
+               end
+               return poset
+       end
+
        # Build type tables
        fun build_type_tables(mtypes: POSet[MType]): Map[MType, Array[nullable MType]] do
                var tables = new HashMap[MType, Array[nullable MType]]
-               var layout = self.type_layout
                for mtype in mtypes do
                        var table = new Array[nullable MType]
                        for sup in mtypes[mtype].greaters do
-                               var color: Int
-                               if layout isa PHLayout[MType, MType] then
-                                       color = layout.hashes[mtype][sup]
-                               else
-                                       color = layout.pos[sup]
-                               end
+                               var color = type_colors[sup]
                                if table.length <= color then
                                        for i in [table.length .. color[ do
                                                table[i] = null
@@ -584,18 +550,9 @@ class SeparateCompiler
                end
 
                # Compute the table layout with the prefered method
-               var resolution_builder: ResolutionLayoutBuilder
-               if modelbuilder.toolcontext.opt_bm_typing.value then
-                       resolution_builder = new ResolutionBMizer
-               else if modelbuilder.toolcontext.opt_phmod_typing.value then
-                       resolution_builder = new ResolutionHasher(new PHModOperator)
-               else if modelbuilder.toolcontext.opt_phand_typing.value then
-                       resolution_builder = new ResolutionHasher(new PHAndOperator)
-               else
-                       resolution_builder = new ResolutionColorer
-               end
-               self.resolution_layout = resolution_builder.build_layout(mtype2unresolved)
-               self.resolution_tables = self.build_resolution_tables(mtype2unresolved)
+               var colorer = new BucketsColorer[MType, MType]
+               opentype_colors = colorer.colorize(mtype2unresolved)
+               resolution_tables = self.build_resolution_tables(mtype2unresolved)
 
                # Compile a C constant for each collected unresolved type.
                # Either to a color, or to -1 if the unresolved type is dead (no live receiver can require it)
@@ -605,8 +562,8 @@ class SeparateCompiler
                end
                var all_unresolved_types_colors = new HashMap[MType, Int]
                for t in all_unresolved do
-                       if self.resolution_layout.pos.has_key(t) then
-                               all_unresolved_types_colors[t] = self.resolution_layout.pos[t]
+                       if opentype_colors.has_key(t) then
+                               all_unresolved_types_colors[t] = opentype_colors[t]
                        else
                                all_unresolved_types_colors[t] = -1
                        end
@@ -622,16 +579,10 @@ class SeparateCompiler
 
        fun build_resolution_tables(elements: Map[MClassType, Set[MType]]): Map[MClassType, Array[nullable MType]] do
                var tables = new HashMap[MClassType, Array[nullable MType]]
-               var layout = self.resolution_layout
                for mclasstype, mtypes in elements do
                        var table = new Array[nullable MType]
                        for mtype in mtypes do
-                               var color: Int
-                               if layout isa PHLayout[MClassType, MType] then
-                                       color = layout.hashes[mclasstype][mtype]
-                               else
-                                       color = layout.pos[mtype]
-                               end
+                               var color = opentype_colors[mtype]
                                if table.length <= color then
                                        for i in [table.length .. color[ do
                                                table[i] = null
@@ -668,7 +619,6 @@ class SeparateCompiler
        fun compile_type_to_c(mtype: MType)
        do
                assert not mtype.need_anchor
-               var layout = self.type_layout
                var is_live = mtype isa MClassType and runtime_type_analysis.live_types.has(mtype)
                var is_cast_live = runtime_type_analysis.live_cast_types.has(mtype)
                var c_name = mtype.c_name
@@ -683,7 +633,7 @@ class SeparateCompiler
 
                # type id (for cast target)
                if is_cast_live then
-                       v.add_decl("{layout.ids[mtype]},")
+                       v.add_decl("{type_ids[mtype]},")
                else
                        v.add_decl("-1, /*CAST DEAD*/")
                end
@@ -693,11 +643,7 @@ class SeparateCompiler
 
                # type color (for cast target)
                if is_cast_live then
-                       if layout isa PHLayout[MType, MType] then
-                               v.add_decl("{layout.masks[mtype]},")
-                       else
-                               v.add_decl("{layout.pos[mtype]},")
-                       end
+                       v.add_decl("{type_colors[mtype]},")
                else
                        v.add_decl("-1, /*CAST DEAD*/")
                end
@@ -733,7 +679,7 @@ class SeparateCompiler
                                if stype == null then
                                        v.add_decl("-1, /* empty */")
                                else
-                                       v.add_decl("{layout.ids[stype]}, /* {stype} */")
+                                       v.add_decl("{type_ids[stype]}, /* {stype} */")
                                end
                        end
                        v.add_decl("\},")
@@ -752,19 +698,13 @@ class SeparateCompiler
                        mclass_type = mtype.as(MClassType)
                end
 
-               var layout = self.resolution_layout
-
                # extern const struct resolution_table_X resolution_table_X
                self.provide_declaration("resolution_table_{mtype.c_name}", "extern const struct types resolution_table_{mtype.c_name};")
 
                # const struct fts_table_X fts_table_X
                var v = new_visitor
                v.add_decl("const struct types resolution_table_{mtype.c_name} = \{")
-               if layout isa PHLayout[MClassType, MType] then
-                       v.add_decl("{layout.masks[mclass_type]},")
-               else
-                       v.add_decl("0, /* dummy */")
-               end
+               v.add_decl("0, /* dummy */")
                v.add_decl("\{")
                for t in self.resolution_tables[mclass_type] do
                        if t == null then
@@ -775,7 +715,7 @@ class SeparateCompiler
                                # the value stored is tv.
                                var tv = t.resolve_for(mclass_type, mclass_type, self.mainmodule, true)
                                # FIXME: What typeids means here? How can a tv not be live?
-                               if self.type_layout.ids.has_key(tv) then
+                               if type_ids.has_key(tv) then
                                        v.require_declaration("type_{tv.c_name}")
                                        v.add_decl("&type_{tv.c_name}, /* {t}: {tv} */")
                                else
@@ -1476,11 +1416,7 @@ class SeparateCompilerVisitor
                        var recv = self.frame.arguments.first
                        var recv_type_info = self.type_info(recv)
                        self.require_declaration(mtype.const_color)
-                       if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
-                               return self.new_expr("NEW_{mtype.mclass.c_name}({recv_type_info}->resolution_table->types[HASH({recv_type_info}->resolution_table->mask, {mtype.const_color})])", mtype)
-                       else
-                               return self.new_expr("NEW_{mtype.mclass.c_name}({recv_type_info}->resolution_table->types[{mtype.const_color}])", mtype)
-                       end
+                       return self.new_expr("NEW_{mtype.mclass.c_name}({recv_type_info}->resolution_table->types[{mtype.const_color}])", mtype)
                end
                compiler.undead_types.add(mtype)
                self.require_declaration("type_{mtype.c_name}")
@@ -1527,11 +1463,7 @@ class SeparateCompilerVisitor
                        hardening_live_open_type(mtype)
                        link_unresolved_type(self.frame.mpropdef.mclassdef, mtype)
                        self.require_declaration(mtype.const_color)
-                       if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
-                               self.add("{type_struct} = {recv_type_info}->resolution_table->types[HASH({recv_type_info}->resolution_table->mask, {mtype.const_color})];")
-                       else
-                               self.add("{type_struct} = {recv_type_info}->resolution_table->types[{mtype.const_color}];")
-                       end
+                       self.add("{type_struct} = {recv_type_info}->resolution_table->types[{mtype.const_color}];")
                        if compiler.modelbuilder.toolcontext.opt_typing_test_metrics.value then
                                self.compiler.count_type_test_unresolved[tag] += 1
                                self.add("count_type_test_unresolved_{tag}++;")
@@ -1566,9 +1498,6 @@ class SeparateCompilerVisitor
                        self.add("\} else \{")
                end
                var value_type_info = self.type_info(value)
-               if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
-                       self.add("{cltype} = HASH({value_type_info}->color, {idtype});")
-               end
                self.add("if({cltype} >= {value_type_info}->table_size) \{")
                self.add("{res} = 0;")
                self.add("\} else \{")
@@ -1756,11 +1685,7 @@ class SeparateCompilerVisitor
                        var recv = self.frame.arguments.first
                        var recv_type_info = self.type_info(recv)
                        self.require_declaration(mtype.const_color)
-                       if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
-                               return self.new_expr("NEW_{mtype.mclass.c_name}({length}, {recv_type_info}->resolution_table->types[HASH({recv_type_info}->resolution_table->mask, {mtype.const_color})])", mtype)
-                       else
-                               return self.new_expr("NEW_{mtype.mclass.c_name}({length}, {recv_type_info}->resolution_table->types[{mtype.const_color}])", mtype)
-                       end
+                       return self.new_expr("NEW_{mtype.mclass.c_name}({length}, {recv_type_info}->resolution_table->types[{mtype.const_color}])", mtype)
                end
                compiler.undead_types.add(mtype)
                self.require_declaration("type_{mtype.c_name}")
@@ -2006,10 +1931,14 @@ redef class MClass
        end
 end
 
+interface PropertyLayoutElement end
+
 redef class MProperty
+       super PropertyLayoutElement
        fun const_color: String do return "COLOR_{c_name}"
 end
 
 redef class MPropDef
+       super PropertyLayoutElement
        fun const_color: String do return "COLOR_{c_name}"
 end
index 4116d97..1942898 100644 (file)
@@ -67,7 +67,7 @@ redef class ModelBuilder
                                compiler.compile_class_to_c(mclass)
                        end
                end
-               compiler.compile_color_consts(compiler.vt_layout.pos)
+               compiler.compile_color_consts(compiler.vt_colors)
 
                # The main function of the C
                compiler.new_file("{mainmodule.name}.main")
@@ -91,30 +91,21 @@ end
 class SeparateErasureCompiler
        super SeparateCompiler
 
-       private var class_layout: nullable Layout[MClass]
-       protected var vt_layout: nullable Layout[MVirtualTypeProp]
+       private var class_ids: Map[MClass, Int]
+       private var class_colors: Map[MClass, Int]
+       protected var vt_colors: Map[MVirtualTypeProp, Int]
 
        init(mainmodule: MModule, mmbuilder: ModelBuilder, runtime_type_analysis: nullable RapidTypeAnalysis) do
                super
 
+               # Class coloring
                var mclasses = new HashSet[MClass].from(mmbuilder.model.mclasses)
-
-               var layout_builder: TypingLayoutBuilder[MClass]
-               var class_colorer = new MClassColorer(mainmodule)
-               if modelbuilder.toolcontext.opt_phmod_typing.value then
-                       layout_builder = new MClassHasher(new PHModOperator, mainmodule)
-                       class_colorer.build_layout(mclasses)
-               else if modelbuilder.toolcontext.opt_phand_typing.value then
-                       layout_builder = new MClassHasher(new PHAndOperator, mainmodule)
-                       class_colorer.build_layout(mclasses)
-               else if modelbuilder.toolcontext.opt_bm_typing.value then
-                       layout_builder = new MClassBMizer(mainmodule)
-                       class_colorer.build_layout(mclasses)
-               else
-                       layout_builder = class_colorer
-               end
-               self.class_layout = layout_builder.build_layout(mclasses)
-               self.class_tables = self.build_class_typing_tables(mclasses)
+               var poset = mainmodule.flatten_mclass_hierarchy
+               var colorer = new POSetColorer[MClass]
+               colorer.colorize(poset)
+               class_ids = colorer.ids
+               class_colors = colorer.colors
+               class_tables = self.build_class_typing_tables(mclasses)
 
                # lookup vt to build layout with
                var vts = new HashMap[MClass, Set[MVirtualTypeProp]]
@@ -128,13 +119,12 @@ class SeparateErasureCompiler
                end
 
                # vt coloration
-               var vt_coloring = new MPropertyColorer[MVirtualTypeProp](mainmodule, class_colorer)
-               var vt_layout = vt_coloring.build_layout(vts)
-               self.vt_tables = build_vt_tables(mclasses, vt_layout)
-               self.vt_layout = vt_layout
+               var vt_colorer = new POSetBucketsColorer[MClass, MVirtualTypeProp](poset, colorer.conflicts)
+               vt_colors = vt_colorer.colorize(vts)
+               vt_tables = build_vt_tables(mclasses)
        end
 
-       fun build_vt_tables(mclasses: Set[MClass], layout: Layout[MProperty]): Map[MClass, Array[nullable MPropDef]] do
+       fun build_vt_tables(mclasses: Set[MClass]): Map[MClass, Array[nullable MPropDef]] do
                var tables = new HashMap[MClass, Array[nullable MPropDef]]
                for mclass in mclasses do
                        var table = new Array[nullable MPropDef]
@@ -148,7 +138,7 @@ class SeparateErasureCompiler
                                if parent == mclass then continue
                                for mproperty in self.mainmodule.properties(parent) do
                                        if not mproperty isa MVirtualTypeProp then continue
-                                       var color = layout.pos[mproperty]
+                                       var color = vt_colors[mproperty]
                                        if table.length <= color then
                                                for i in [table.length .. color[ do
                                                        table[i] = null
@@ -165,7 +155,7 @@ class SeparateErasureCompiler
                        # then override with local properties
                        for mproperty in self.mainmodule.properties(mclass) do
                                if not mproperty isa MVirtualTypeProp then continue
-                               var color = layout.pos[mproperty]
+                               var color = vt_colors[mproperty]
                                if table.length <= color then
                                        for i in [table.length .. color[ do
                                                table[i] = null
@@ -185,7 +175,6 @@ class SeparateErasureCompiler
        # Build class tables
        fun build_class_typing_tables(mclasses: Set[MClass]): Map[MClass, Array[nullable MClass]] do
                var tables = new HashMap[MClass, Array[nullable MClass]]
-               var layout = self.class_layout
                for mclass in mclasses do
                        var table = new Array[nullable MClass]
                        var supers = new Array[MClass]
@@ -193,12 +182,7 @@ class SeparateErasureCompiler
                                supers = mclass.in_hierarchy(mainmodule).greaters.to_a
                        end
                        for sup in supers do
-                               var color: Int
-                               if layout isa PHLayout[MClass, MClass] then
-                                       color = layout.hashes[mclass][sup]
-                               else
-                                       color = layout.pos[sup]
-                               end
+                               var color = class_colors[sup]
                                if table.length <= color then
                                        for i in [table.length .. color[ do
                                                table[i] = null
@@ -217,19 +201,7 @@ class SeparateErasureCompiler
                self.header.add_decl("struct class \{ int id; const char *name; int box_kind; int color; const struct vts_table *vts_table; const struct type_table *type_table; nitmethod_t vft[]; \}; /* general C type representing a Nit class. */")
                self.header.add_decl("struct type_table \{ int size; int table[]; \}; /* colorized type table. */")
                self.header.add_decl("struct vts_entry \{ short int is_nullable; const struct class *class; \}; /* link (nullable or not) between the vts and is bound. */")
-
-               if self.vt_layout isa PHLayout[MClass, MVirtualTypeProp] then
-                       self.header.add_decl("struct vts_table \{ int mask; const struct vts_entry vts[]; \}; /* vts list of a C type representation. */")
-               else
-                       self.header.add_decl("struct vts_table \{ int dummy; const struct vts_entry vts[]; \}; /* vts list of a C type representation. */")
-               end
-
-               if modelbuilder.toolcontext.opt_phmod_typing.value then
-                       self.header.add_decl("#define HASH(mask, id) ((mask)%(id))")
-               else if modelbuilder.toolcontext.opt_phand_typing.value then
-                       self.header.add_decl("#define HASH(mask, id) ((mask)&(id))")
-               end
-
+               self.header.add_decl("struct vts_table \{ int dummy; const struct vts_entry vts[]; \}; /* vts list of a C type representation. */")
                self.header.add_decl("typedef struct instance \{ const struct class *class; nitattribute_t attrs[1]; \} val; /* general C type representing a Nit instance. */")
        end
 
@@ -257,15 +229,10 @@ class SeparateErasureCompiler
 
                # Build class vft
                v.add_decl("const struct class class_{c_name} = \{")
-               v.add_decl("{self.class_layout.ids[mclass]},")
+               v.add_decl("{class_ids[mclass]},")
                v.add_decl("\"{mclass.name}\", /* class_name_string */")
                v.add_decl("{self.box_kind_of(mclass)}, /* box_kind */")
-               var layout = self.class_layout
-               if layout isa PHLayout[MClass, MClass] then
-                       v.add_decl("{layout.masks[mclass]},")
-               else
-                       v.add_decl("{layout.pos[mclass]},")
-               end
+               v.add_decl("{class_colors[mclass]},")
                if not is_dead then
                        if build_class_vts_table(mclass) then
                                v.require_declaration("vts_table_{c_name}")
@@ -307,7 +274,7 @@ class SeparateErasureCompiler
                        if msuper == null then
                                v.add_decl("-1, /* empty */")
                        else
-                               v.add_decl("{self.class_layout.ids[msuper]}, /* {msuper} */")
+                               v.add_decl("{self.class_ids[msuper]}, /* {msuper} */")
                        end
                end
                v.add_decl("\}")
@@ -383,12 +350,7 @@ class SeparateErasureCompiler
 
                var v = new_visitor
                v.add_decl("const struct vts_table vts_table_{mclass.c_name} = \{")
-               if self.vt_layout isa PHLayout[MClass, MVirtualTypeProp] then
-                       #TODO redo this when PHPropertyLayoutBuilder will be implemented
-                       #v.add_decl("{vt_masks[mclass]},")
-               else
-                       v.add_decl("0, /* dummy */")
-               end
+               v.add_decl("0, /* dummy */")
                v.add_decl("\{")
 
                for vt in self.vt_tables[mclass] do
@@ -570,11 +532,7 @@ class SeparateErasureCompilerVisitor
                        var entry = self.get_name("entry")
                        self.add("struct vts_entry {entry};")
                        self.require_declaration(mtype.mproperty.const_color)
-                       if self.compiler.as(SeparateErasureCompiler).vt_layout isa PHLayout[MClass, MVirtualTypeProp] then
-                               self.add("{entry} = {recv_ptr}vts_table->vts[HASH({recv_ptr}vts_table->mask, {mtype.mproperty.const_color})];")
-                       else
-                               self.add("{entry} = {recv_ptr}vts_table->vts[{mtype.mproperty.const_color}];")
-                       end
+                       self.add("{entry} = {recv_ptr}vts_table->vts[{mtype.mproperty.const_color}];")
                        self.add("{cltype} = {entry}.class->color;")
                        self.add("{idtype} = {entry}.class->id;")
                        if maybe_null and accept_null == "0" then
@@ -598,9 +556,6 @@ class SeparateErasureCompilerVisitor
                        self.add("{res} = {accept_null};")
                        self.add("\} else \{")
                end
-               if self.compiler.as(SeparateErasureCompiler).class_layout isa PHLayout[MClass, MClass] then
-                       self.add("{cltype} = HASH({class_ptr}color, {idtype});")
-               end
                self.add("if({cltype} >= {class_ptr}type_table->size) \{")
                self.add("{res} = 0;")
                self.add("\} else \{")
index b9ba9e8..5b9d020 100644 (file)
@@ -90,9 +90,9 @@ class ToolContext
 
                        for m in messages do
                                if opt_no_color.value then
-                                       stderr.write("{m}\n")
+                                       sys.stderr.write("{m}\n")
                                else
-                                       stderr.write("{m.to_color_string}\n")
+                                       sys.stderr.write("{m.to_color_string}\n")
                                end
                        end
 
index 06bdcb6..6bd37b0 100644 (file)
@@ -171,16 +171,13 @@ redef class AArrayExpr
        #     t
        redef fun accept_transform_visitor(v)
        do
-               var mtype = self.mtype.as(MClassType)
                var nblock = v.builder.make_block
 
-               var meth = v.get_method(self, "with_capacity", mtype.mclass)
-               var nnew = v.builder.make_new(mtype, meth, [v.builder.make_int(n_exprs.n_exprs.length)])
+               var nnew = v.builder.make_new(with_capacity_callsite.as(not null), [v.builder.make_int(n_exprs.n_exprs.length)])
                nblock.add nnew
 
-               var madd = v.get_method(self, "push", mtype.mclass)
                for nexpr in self.n_exprs.n_exprs do
-                       var nadd = v.builder.make_call(nnew.make_var_read, madd, [nexpr])
+                       var nadd = v.builder.make_call(nnew.make_var_read, push_callsite.as(not null), [nexpr])
                        nblock.add nadd
                end
                var nres = nnew.make_var_read
@@ -190,45 +187,11 @@ redef class AArrayExpr
        end
 end
 
-redef class ASuperstringExpr
-       # `"x{y}z"` is replaced with
-       #
-       #     var t = new Array[Object].with_capacity(3)
-       #     t.add("x")
-       #     t.add(y)
-       #     t.add("z")
-       #     t.to_s
-       redef fun accept_transform_visitor(v)
-       do
-               if true then return # FIXME: transformation disabled for the moment
-
-               var nblock = v.builder.make_block
-
-               var arraytype = v.get_class(self, "Array").get_mtype([v.get_class(self, "Object").mclass_type])
-               var meth = v.get_method(self, "with_capacity", arraytype.mclass)
-               var nnew = v.builder.make_new(arraytype, meth, [v.builder.make_int(n_exprs.length)])
-               nblock.add nnew
-
-               var madd = v.get_method(self, "add", arraytype.mclass)
-               for nexpr in self.n_exprs do
-                       var nadd = v.builder.make_call(nnew.make_var_read, madd, [nexpr])
-                       nblock.add nadd
-               end
-
-               var mtos = v.get_method(self, "to_s", arraytype.mclass)
-               var ntos = v.builder.make_call(nnew.make_var_read, mtos, null)
-               nblock.add ntos
-
-               replace_with(nblock)
-       end
-end
-
 redef class ACrangeExpr
        # `[x..y]` is replaced with `new Range[X](x,y)`
        redef fun accept_transform_visitor(v)
        do
-               var mtype = self.mtype.as(MClassType)
-               replace_with(v.builder.make_new(mtype, init_callsite.mproperty, [n_expr, n_expr2]))
+               replace_with(v.builder.make_new(init_callsite.as(not null), [n_expr, n_expr2]))
        end
 end
 
@@ -236,8 +199,7 @@ redef class AOrangeExpr
        # `[x..y[` is replaced with `new Range[X].without_last(x,y)`
        redef fun accept_transform_visitor(v)
        do
-               var mtype = self.mtype.as(MClassType)
-               replace_with(v.builder.make_new(mtype, init_callsite.mproperty, [n_expr, n_expr2]))
+               replace_with(v.builder.make_new(init_callsite.as(not null), [n_expr, n_expr2]))
        end
 end
 
@@ -270,12 +232,12 @@ redef class ASendReassignFormExpr
                        write_args.add(a.make_var_read)
                end
 
-               var nread = v.builder.make_call(n_expr.make_var_read, callsite.mproperty, read_args)
+               var nread = v.builder.make_call(n_expr.make_var_read, callsite.as(not null), read_args)
 
-               var nnewvalue = v.builder.make_call(nread, reassign_callsite.mproperty, [n_value])
+               var nnewvalue = v.builder.make_call(nread, reassign_callsite.as(not null), [n_value])
 
                write_args.add(nnewvalue)
-               var nwrite = v.builder.make_call(n_expr.make_var_read, write_callsite.mproperty, write_args)
+               var nwrite = v.builder.make_call(n_expr.make_var_read, write_callsite.as(not null), write_args)
                nblock.add(nwrite)
 
                replace_with(nblock)
@@ -290,7 +252,7 @@ redef class AVarReassignExpr
 
                var nread = v.builder.make_var_read(variable, read_type.as(not null))
 
-               var nnewvalue = v.builder.make_call(nread, reassign_callsite.mproperty, [n_value])
+               var nnewvalue = v.builder.make_call(nread, reassign_callsite.as(not null), [n_value])
                var nwrite = v.builder.make_var_assign(variable, nnewvalue)
 
                replace_with(nwrite)
@@ -306,7 +268,7 @@ redef class AAttrReassignExpr
                var attribute = self.mproperty.as(not null)
 
                var nread = v.builder.make_attr_read(n_expr.make_var_read, attribute)
-               var nnewvalue = v.builder.make_call(nread, reassign_callsite.mproperty, [n_value])
+               var nnewvalue = v.builder.make_call(nread, reassign_callsite.as(not null), [n_value])
                var nwrite = v.builder.make_attr_assign(n_expr.make_var_read, attribute, nnewvalue)
                nblock.add(nwrite)
 
index 9cae36f..fd0197d 100644 (file)
@@ -79,16 +79,6 @@ private class TypeVisitor
                return res
        end
 
-       # Retrieve the signature of a `MMethodDef` resolved for a specific call.
-       # This method is an helper to symplify the query on the model.
-       #
-       # Note: `for_self` indicates if the reciever is self or not.
-       # If yes, virtual types are not resolved.
-       fun resolve_signature_for(mmethoddef: MMethodDef, recv: MType, for_self: Bool): MSignature
-       do
-               return self.resolve_for(mmethoddef.msignature.as(not null), recv, for_self).as(MSignature)
-       end
-
        # Check that `sub` is a subtype of `sup`.
        # If `sub` is not a valud suptype, then display an error on `node` an return null.
        # If `sub` is a safe subtype of `sup` then return `sub`.
@@ -260,7 +250,8 @@ private class TypeVisitor
                end
 
 
-               var msignature = self.resolve_signature_for(mpropdef, recvtype, recv_is_self)
+               var msignature = mpropdef.msignature.as(not null)
+               msignature = resolve_for(msignature, recvtype, recv_is_self).as(MSignature)
 
                var erasure_cast = false
                var rettype = mpropdef.msignature.return_mtype
@@ -479,17 +470,17 @@ redef class APropdef
        var selfvariable: nullable Variable
 end
 
-redef class AConcreteMethPropdef
+redef class AMethPropdef
        redef fun do_typing(modelbuilder: ModelBuilder)
        do
+               var nblock = self.n_block
+               if nblock == null then return
+
                var nclassdef = self.parent.as(AClassdef)
                var mpropdef = self.mpropdef.as(not null)
                var v = new TypeVisitor(modelbuilder, nclassdef, mpropdef)
                self.selfvariable = v.selfvariable
 
-               var nblock = self.n_block
-               if nblock == null then return
-
                var mmethoddef = self.mpropdef.as(not null)
                for i in [0..mmethoddef.msignature.arity[ do
                        var mtype = mmethoddef.msignature.mparameters[i].mtype
@@ -1069,6 +1060,9 @@ redef class ASuperstringExpr
 end
 
 redef class AArrayExpr
+       var with_capacity_callsite: nullable CallSite
+       var push_callsite: nullable CallSite
+
        redef fun accept_typing(v)
        do
                var mtypes = new Array[nullable MType]
@@ -1086,7 +1080,12 @@ redef class AArrayExpr
                end
                var mclass = v.get_mclass(self, "Array")
                if mclass == null then return # Forward error
-               self.mtype = mclass.get_mtype([mtype])
+               var array_mtype = mclass.get_mtype([mtype])
+
+               with_capacity_callsite = v.get_method(self, array_mtype, "with_capacity", false)
+               push_callsite = v.get_method(self, array_mtype, "push", false)
+
+               self.mtype = array_mtype
        end
 end
 
@@ -1455,7 +1454,8 @@ redef class ASuperExpr
                # FIXME: covariance of return type in linear extension?
                var superprop = superprops.first
 
-               var msignature = v.resolve_signature_for(superprop, recvtype, true)
+               var msignature = superprop.msignature.as(not null)
+               msignature = v.resolve_for(msignature, recvtype, true).as(MSignature)
                var args = self.n_args.to_a
                if args.length > 0 then
                        v.check_signature(self, args, mproperty.name, msignature)
@@ -1501,7 +1501,9 @@ redef class ASuperExpr
                        return
                end
 
-               var msignature = v.resolve_signature_for(superprop, recvtype, true)
+               var msignature = superprop.msignature.as(not null)
+               msignature = v.resolve_for(msignature, recvtype, true).as(MSignature)
+
                var callsite = new CallSite(self, recvtype, v.mmodule, v.anchor, true, superprop.mproperty, superprop, msignature, false)
                self.callsite = callsite
 
diff --git a/src/websocket_debugger.nit b/src/websocket_debugger.nit
deleted file mode 100644 (file)
index d4b4878..0000000
+++ /dev/null
@@ -1,209 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Copyright 2014 Lucas Bajolet <r4pass@hotmail.com>
-#
-# 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
-
similarity index 53%
rename from src/nitdbg_server.nit
rename to tests/base_init_combine.nit
index 135a94c..e30298f 100644 (file)
@@ -1,7 +1,5 @@
 # This file is part of NIT ( http://www.nitlanguage.org ).
 #
-# Copyright 2013 Lucas Bajolet <lucas.bajolet@hotmail.com>
-#
 # 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
 # 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 kernel
+
+class A
+       init do 1.output
+end
+
+class B
+       init do 2.output
+end
+
+class C
+       super A
+       super B
 
-import network_debugger
-import debugger_commons
+       init do 3.output
+end
 
-redef class InterpretCommons
+class D
+       super A
+       super B
 
-       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
+       var i: Int
+end
 
-               modelbuilder.run_debugger_network_mode(mainmodule.as(not null),arguments.as(not null),toolcontext.opt_debug_port.value)
+class E
+       super A
+       super B
+
+       var i: Int
+       init(i: Int) do
+               self.i = i
+               i.output
        end
+end
 
+class F
+       super E
+       #alt1# var z: Int
 end
 
-(new InterpretCommons).launch
+var a = new A
+var b = new B
+var c = new C
+var d = new D(4)
+var e = new E(5)
+var f = new F(6)
index ca5debe..ae42bee 100644 (file)
@@ -32,6 +32,7 @@ class WakeUpNode
                _scheduler.add_event(self, d)
        end
        var _scheduler: Scheduler
+       init do end
 end
 
 class NodeSource
index 75feb69..e589ec7 100644 (file)
@@ -15,9 +15,9 @@
 # limitations under the License.
 
 class A
-       var _a: Int
+       var _a: Int = 1
 end
 class B
        super A
-       redef var _a: Object
+       redef var _a: Object = 2
 end
index a2d517e..6aac93a 100644 (file)
@@ -2,6 +2,5 @@ init_inherit
 init_linext
 inline
 test_json
-pep8analysis_args
 converter
 pnacl
index 966fd62..c626285 100644 (file)
@@ -2,6 +2,5 @@ init_inherit
 init_linext
 inline
 nitg
-test_json
 mnit
 pnacl
index a2d517e..6aac93a 100644 (file)
@@ -2,6 +2,5 @@ init_inherit
 init_linext
 inline
 test_json
-pep8analysis_args
 converter
 pnacl
diff --git a/tests/sav/base_init_combine.res b/tests/sav/base_init_combine.res
new file mode 100644 (file)
index 0000000..d210e23
--- /dev/null
@@ -0,0 +1,13 @@
+1
+2
+1
+2
+3
+1
+2
+1
+2
+5
+1
+2
+6
diff --git a/tests/sav/base_init_combine_alt1.res b/tests/sav/base_init_combine_alt1.res
new file mode 100644 (file)
index 0000000..5759dba
--- /dev/null
@@ -0,0 +1 @@
+alt/base_init_combine_alt1.nit:52,6: Error: base_init_combine_alt1#F cannot inherit constructors from E because there is attributes without initial values: z: Int
index 8ac105d..4b258f9 100644 (file)
@@ -1 +1 @@
-alt/base_init_simple_alt1.nit:15,8--11: Error: No property B::init3 is inherited. Remove the redef keyword to define a new property.
+alt/base_init_simple_alt1.nit:15,13--17: Error: No property B::init3 is inherited. Remove the redef keyword to define a new property.
index 15cb0ac..c3555bf 100644 (file)
@@ -1 +1,2 @@
-alt/error_needed_method_alt1.nit:46,9--14: Fatal Error: Array must have a property named with_capacity.
+alt/error_needed_method_alt1.nit:46,9--14: Error: Method 'with_capacity' doesn't exists in Array[Int].
+alt/error_needed_method_alt1.nit:46,9--14: Error: Method 'push' doesn't exists in Array[Int].
diff --git a/tests/sav/test_ffi_java_use_module.res b/tests/sav/test_ffi_java_use_module.res
new file mode 100644 (file)
index 0000000..f9585e2
--- /dev/null
@@ -0,0 +1,5 @@
+777
+asdf
+From Nit
+11
+12346
diff --git a/tests/sav/test_hash_text.res b/tests/sav/test_hash_text.res
new file mode 100644 (file)
index 0000000..310e632
--- /dev/null
@@ -0,0 +1,8 @@
+true
+true
+true
+true
+true
+true
+true
+true
diff --git a/tests/sav/test_json.res b/tests/sav/test_json.res
deleted file mode 100644 (file)
index 146e88b..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-{"int":"1234","float":"0.123","str":"str","null": null}
-{"int":1234,"float":0.123400,"str":"str","null":null}
-{"arr":"123","obj":"{"int":"123","float":"-234.45"}"}
-{"arr":[1,2,3],"obj":{"int":123,"float":-234.449997}}
-{"arr":"12.3str","obj":"{"int":"123","float":"-234.45"}"}
-{"arr":[1,2.300000,null,"str"],"obj":{"int":123,"float":-234.449997}}
diff --git a/tests/sav/test_kill_process.res b/tests/sav/test_kill_process.res
new file mode 100644 (file)
index 0000000..27ba77d
--- /dev/null
@@ -0,0 +1 @@
+true
index b6f1b43..ae5bfb0 100644 (file)
@@ -55,12 +55,7 @@ same paragraph</p><p>Other paragraph with <code class="nitcode"><span class="nit
 but long
 bullet</li></ul><pre class="nitcode"><span class="nitcode"><span class="nc_k"></span><span class="nc_i">some</span>
 <span class="nc_i">block</span>
-<span class="nc_k"></span>some
-block
 </span></pre><p>a first example</p><pre class="nitcode"><span class="nitcode"><span class="nc_k"></span><span class="nc_k">assert</span> <span class="nc_l">1</span> <span class="nc_o">+</span> <span class="nc_l">1</span> <span class="nc_o">==</span> <span class="nc_l">2</span>
-<span class="nc_k"></span>assert 1 + 1 == 2
 </span></pre><p>and a last example to illustrate the <code class="nitcode"><span class="nitcode"><span class="nc_i">to_s</span></span></code> method on <code class="nitcode"><span class="nitcode"><span class="nc_k"></span><span class="nc_v nc_i"></span><span class="nc_t"></span><span class="nc_t">A</span></span></code>.</p><pre class="nitcode"><span class="nitcode"><span class="nc_k"></span><span class="nc_k">var</span> <span class="nc_v nc_i">a</span> = <span class="nc_k">new</span> <span class="nc_t">A</span>
 <span class="nc_k">assert</span> <span class="nc_i">a</span><span class="nc_o">.</span><span class="nc_i">to_s</span> <span class="nc_o">==</span> <span class="nc_s">&quot;A&quot;</span>
-<span class="nc_k"></span>var a = new A
-assert a.to_s == &quot;A&quot;
 </span></pre></div></body></html>
\ No newline at end of file
index 16b4a6c..dc855e5 100644 (file)
@@ -9,7 +9,6 @@
         AImplicitSelfExpr 1,7
         TId "world" 1,7--11
         AListExprs 1,11
-  TKwend "" 1,1--0
 --> AStringExpr 1,1--13
   TString "\"hello world\"" 1,1--13
 --> ABlockExpr 1,1--0
@@ -25,7 +24,6 @@
       AImplicitSelfExpr 1,15
       TId "p" 1,15
       AListExprs 1,15
-  TKwend "" 1,1--0
 --> AModule 1,1--12
   ATopClassdef 1,1--12
     AConcreteMethPropdef 1,1--12
@@ -53,7 +51,6 @@
         TId "p" 2,1
         AListExprs 2,1
       TKwend "end" 3,1--3
-  TKwend "" 1,1--0
 --> ... ... ... ... AModule 1,1--5,3
   ATopClassdef 1,1--5,3
     AConcreteMethPropdef 1,1--5,3
similarity index 52%
rename from src/nitdbg_websocket_server.nit
rename to tests/test_ffi_java_use_module.nit
index d8c23ca..cb87397 100644 (file)
@@ -1,6 +1,6 @@
 # This file is part of NIT ( http://www.nitlanguage.org ).
 #
-# Copyright 2014 Lucas Bajolet <r4pass@hotmail.com>
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # 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
+module test_ffi_java_use_module
 
-import websocket_debugger
-import debugger_commons
+import test_ffi_java_callbacks
 
-redef class InterpretCommons
+fun bar(msg: String) import String.to_java_string in "Java" `{
+       java.lang.String java_msg = String_to_java_string(msg);
+       System.out.println(java_msg);
+`}
 
-       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
+var a = new A
+a.foo
+print(a.getter(11.1))
+print(a.getter(12345.689))
 
-               modelbuilder.run_debugger_network_mode(mainmodule.as(not null),arguments.as(not null),toolcontext.opt_debug_port.value)
-       end
-
-end
-
-(new InterpretCommons).launch
+bar("asdf")
diff --git a/tests/test_hash_text.nit b/tests/test_hash_text.nit
new file mode 100644 (file)
index 0000000..e655dd8
--- /dev/null
@@ -0,0 +1,32 @@
+# 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.
+
+var x = "string__NativeString__to_s_with_length"
+
+var y = "string" + "__" + "NativeString" + "__" + "to_s_with_length"
+
+var z = new FlatBuffer.from("string") + "__" + "NativeString" + "__" + "to_s_with_length"
+
+var a = ["string", "NativeString", "to_s_with_length"].join("__")
+
+print x.hash == y.hash
+print y.hash == z.hash
+print z.hash == a.hash
+print a.hash == x.hash
+
+print x.substring(8,12).hash == y.substring(8,12).hash
+print y.substring(8,12).hash == z.substring(8,12).hash
+print z.substring(8,12).hash == a.substring(8,12).hash
+print a.substring(8,12).hash == x.substring(8,12).hash
+
diff --git a/tests/test_json.nit b/tests/test_json.nit
deleted file mode 100644 (file)
index fadb6cc..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Copyright 2012-2013 Alexis Laferrière <alexis.laf@xymus.net>
-#
-# 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 test_json
-
-import json
-
-redef class HashMap[K,V]
-       redef fun to_s
-       do
-               var es = new Array[String]
-               for k, v in self do
-                       if v != null then
-                               es.add( "\"{k}\":\"{v}\"" )
-                       else
-                               es.add( "\"{k}\": null" )
-                       end
-               end
-               return "\{{es.join(",")}\}"
-       end
-end
-
-redef class String
-       fun parse_and_display
-       do
-               var json_map = json_to_object
-               if json_map != null then
-                       print json_map
-                       print json_map.to_json.replace(" ","")
-
-                       # only available for libjson0 v0.10
-                       # print json_map.to_pretty_json
-               else
-                       print "Conversion to json failed."
-               end
-       end
-end
-
-fun print_usage do print "Usage: json input.json"
-
-if args.length == 1 then
-       var input_path = args.first
-       var input_file = new IFStream.open( input_path )
-       var input_text = input_file.read_all
-       input_file.close
-
-       input_text.parse_and_display
-else
-       var s = "\{\"int\":1234, \"float\":0.1234, \"str\":\"str\", \"null\":null\}"
-       s.parse_and_display
-
-       s = "\{\"arr\":[1,2,3], \"obj\":\{\"int\":123, \"float\":-234.45\}\}"
-       s.parse_and_display
-
-       s = "\{\"arr\":[1,2.3,null,\"str\"], \"obj\":\{\"int\":123, \"float\":-234.45\}\}"
-       s.parse_and_display
-end
similarity index 56%
rename from tests/test_simple_json_reader.nit
rename to tests/test_json_static.nit
index f38cbaa..b510725 100644 (file)
@@ -1,4 +1,20 @@
-import simple_json_reader
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+import json::static
 
 redef class HashMap[K,V]
        redef fun to_s do return "<HashMap {join(", ", ": ")}>"
diff --git a/tests/test_kill_process.nit b/tests/test_kill_process.nit
new file mode 100644 (file)
index 0000000..21728c1
--- /dev/null
@@ -0,0 +1,32 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+import signals
+import realtime
+
+var clock = new Clock
+var p = new Process("sleep", "10")
+
+# Send some signals
+p.signal(sigalarm)
+p.kill
+
+# Wait for it to die
+p.wait
+var lapse = clock.lapse
+
+# Let's be generous here, as long as it does not take 5 secs out of 10 it's OK
+print lapse.sec < 5
index e3bfb56..80069cb 100644 (file)
@@ -37,8 +37,8 @@ class MyAlarmReceiver
 end
 
 var r = new MyReceiver
-r.handle_signal( r.sigint, true ) # will call back when "check_signals" is called
-r.handle_signal( r.sigsegv, false ) # the only way to receive a sigsegv
+r.handle_signal(sigint, true) # will call back when "check_signals" is called
+r.handle_signal(sigsegv, false) # the only way to receive a sigsegv
 
 var ar = new MyAlarmReceiver
 set_alarm( 1 ) # calls C "alarm()"