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>
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()
{
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()
{
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\""
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
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
_n_id = src.n_id
parent = src.parent
- init(src.location)
+ init
+ _location = src.location
end
end
_n_id = src.n_id
parent = src.parent
- init(src.location)
+ init
+ _location = src.location
end
end
# 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
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
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
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
class ABinaryInstruction
super AInstruction
readable var _n_operand: AOperand
+ init do end
end
class AImmediateOperand
super AOperand
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
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
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
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
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
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
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
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
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
--- /dev/null
+# 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
--- /dev/null
+# 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);
+`}
# 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
--- /dev/null
+# 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
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
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
--- /dev/null
+# 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
# 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
+++ /dev/null
-# 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
+++ /dev/null
-# 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
+++ /dev/null
-# 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
# 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
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
module json_serialization
import serialization
-import simple_json_reader
+import json::static
class JsonSerializer
super Serializer
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
end
# Represens a jni jobject
-extern class JavaObject `{jobject`}
+extern class JavaObject in "Java" `{ java.lang.Object `}
end
# Represents a jni JNINNativeMethod
# Manages all assets usable by an Mnit app
module assets
-import app
+import mnit_app
import mnit_display
# General asset
# General module for cross-compatibility between multiple platforms
module mnit
-import app
+import mnit_app
import opengles1
import assets
import numbers
# 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
# 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
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
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
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
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}"
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
# 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
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
# 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
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"
--- /dev/null
+# 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
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
#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.
}
}
}
+
+ #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;
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
# 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
# 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
# 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)
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)
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
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
#
# 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
--- /dev/null
+# 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
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
#
# 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
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
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
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
# 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
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
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
# 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); `}
--- /dev/null
+#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
`}
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); `}
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;
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
import math
import kernel
import gc
+import bitset
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
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
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
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
# 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
--- /dev/null
+# 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
+
--- /dev/null
+# 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
+
--- /dev/null
+# 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
+
--- /dev/null
+# 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
--- /dev/null
+# 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
# 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
# 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
# Disconnects the client if one is connected
# And stops the server
- fun stop_server
+ redef fun close
do
client.close
listener.close
# 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
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
# %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
# 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
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")
" 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)
" 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
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
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
}\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
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 '***************************************************************'
../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
../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 *'
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
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)
# 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]
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
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
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
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
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
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
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
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
class AndroidToolchain
super MakefileToolchain
- var android_project_root: String
+ var android_project_root: nullable String = null
redef fun compile_dir
do
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}"
<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" />
<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. -->
### 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"
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
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
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
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
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
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
# 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
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
--- /dev/null
+# 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
+
+
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 )
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
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
class ExternCFunction
super CFunction
- var method: AExternPropdef
+ var method: AMethPropdef
- init (method: AExternPropdef, mmodule: MModule)
+ init (method: AMethPropdef, mmodule: MModule)
do
self.method = method
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" )
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
# 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
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
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
# 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
## 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.
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
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}")
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
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
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 )
end
end
-redef class AModule
+redef class MModule
var ffi_files = new Array[ExternFile]
# Callbacks used by this module, classified by language
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
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 )
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" )
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
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);
# 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}}}
"""
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
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
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)")
# 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}"
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
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")
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")
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
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)
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"
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
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)
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
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)
# 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
return
end
- amodule.mmodule.uses_ffi = true
+ mmodule.uses_ffi = true
var mclass_type = mpropdef.mclassdef.bound_mtype
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
return
end
- amodule.mmodule.uses_ffi = true
+ mmodule.uses_ffi = true
var mclass_type = mpropdef.mclassdef.bound_mtype
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
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
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
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
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
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
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
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
# -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
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
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
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)
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 !"
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.
+++ /dev/null
-# 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
--- /dev/null
+# 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
+++ /dev/null
-# 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
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
# 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
# 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
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]
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
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)
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
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
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)
var mpropdef = new MVirtualTypeDef(mclassdef, mprop, self.location)
self.mpropdef = mpropdef
+ modelbuilder.mpropdef2npropdef[mpropdef] = self
set_doc(mpropdef)
end
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
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
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
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
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
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)
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)
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)
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)
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
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
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
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
+++ /dev/null
-# 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
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
+
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
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
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
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
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
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
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(" {amodule.short_comment}</li>")
+ if mmodule.mdoc != null then
+ var mtpl = new Template
+ mtpl.add mmodule.tpl_link
+ mtpl.add " "
+ 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
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
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
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]
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
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
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
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
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
+
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)
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
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
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(", ")
fun prompt do
printn ">> "
- search(stdin.read_line)
+ search(sys.stdin.read_line)
end
fun search(entry: String) do
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
# 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}'"
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
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
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`
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
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
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
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`
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`
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)
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
# *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
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
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
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
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
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
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.
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`
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`
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]`
# 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`
super Prod
readable writable var _n_kwlabel: TKwlabel
readable writable var _n_id: TId
+ init do end
end
# Expression and statements
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`
# The initial value, if any
readable writable var _n_expr: nullable AExpr = null
+ init do end
end
# A `return` statement. eg `return x`
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.
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
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
super ALabelable
readable writable var _n_kwdo: TKwdo
readable writable var _n_block: nullable AExpr = null
+ init do end
end
# A `if` statement
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
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
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
super ALabelable
readable writable var _n_kwloop: TKwloop
readable writable var _n_block: nullable AExpr = null
+ init do end
end
# A `for` statement
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
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`
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`
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
super AExpr
# The receiver of the method invocation
readable writable var _n_expr: AExpr
+ init do end
end
# A binary operation on a method
# 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
super ABoolExpr
readable writable var _n_expr: AExpr
readable writable var _n_expr2: AExpr
+ init do end
end
# A `and` expression
super ABoolExpr
readable writable var _n_expr: AExpr
readable writable var _n_expr2: AExpr
+ init do end
end
# A `or else` expression
super ABoolExpr
readable writable var _n_expr: AExpr
readable writable var _n_expr2: AExpr
+ init do end
end
# A `implies` expression
super ABoolExpr
readable writable var _n_expr: AExpr
readable writable var _n_expr2: AExpr
+ init do end
end
# A `not` expression
super ABoolExpr
readable writable var _n_kwnot: TKwnot
readable writable var _n_expr: AExpr
+ init do end
end
# A `==` expression
super ABoolExpr
readable writable var _n_expr: AExpr
readable writable var _n_type: AType
+ init do end
end
# A `+` expression
class AUminusExpr
super ASendExpr
readable writable var _n_minus: TMinus
+ init do end
end
# An explicit instantiation. eg `new T`
# 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
# The name of the attribute
readable writable var _n_id: TAttrid
+
+ init do end
end
# The read of an attribute. eg `x._a`
# The arguments of the call
readable writable var _n_args: AExprs
+ init do end
end
# A complex setter call (standard or brackets)
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.
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]`
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`
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]`
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[`
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
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
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"`
class ASuperstringExpr
super AExpr
readable var _n_exprs: ANodes[AExpr] = new ANodes[AExpr](self)
+ init do end
end
# A simple parenthesis. eg `(x)`
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)`
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)`
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
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
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
super AExprs
readable writable var _n_obra: TObra
readable writable var _n_cbra: TCbra
+ init do end
end
# A complex assignment operator. eg `+=`
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
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
class ADoc
super Prod
readable var _n_comment: ANodes[TComment] = new ANodes[TComment](self)
+ init do end
end
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
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
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
abstract class AAtid
super Prod
readable writable var _n_id: Token
+ init do end
end
class AIdAtid
super AAtid
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
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
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
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
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
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
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)
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
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)
module separate_compiler
import abstract_compiler
-import layout_builders
+import coloring
import rapid_type_analysis
# Add separate compiler specific options
# --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")
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
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)
# 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
# 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]
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
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
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]
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
# 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
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
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]
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
# 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
# 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)
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
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)
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
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
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
# 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
# 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
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("\},")
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
# 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
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}")
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}++;")
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 \{")
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}")
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
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")
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]]
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]
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
# 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
# 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]
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
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
# 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}")
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("\}")
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
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
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 \{")
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
# 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
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
# `[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
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)
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)
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)
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`.
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
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
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]
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
# 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)
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
+++ /dev/null
-# 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
-
# 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)
_scheduler.add_event(self, d)
end
var _scheduler: Scheduler
+ init do end
end
class NodeSource
# 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
init_linext
inline
test_json
-pep8analysis_args
converter
pnacl
init_linext
inline
nitg
-test_json
mnit
pnacl
init_linext
inline
test_json
-pep8analysis_args
converter
pnacl
--- /dev/null
+1
+2
+1
+2
+3
+1
+2
+1
+2
+5
+1
+2
+6
--- /dev/null
+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
-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.
-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].
--- /dev/null
+777
+asdf
+From Nit
+11
+12346
--- /dev/null
+true
+true
+true
+true
+true
+true
+true
+true
+++ /dev/null
-{"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}}
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">"A"</span>
-<span class="nc_k"></span>var a = new A
-assert a.to_s == "A"
</span></pre></div></body></html>
\ No newline at end of file
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
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
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
# 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")
--- /dev/null
+# 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
+
+++ /dev/null
-# 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
-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(", ", ": ")}>"
--- /dev/null
+# 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
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()"