* Should fix #437 by supporting the use of the Java FFI across many modules in global compilation.
* Should also work (but we need an example for it): `nitg cross_platform_prog.nit -m android`
Pull-Request: #456
Reviewed-by: Jean Privat <jean@pryen.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\""
_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
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
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
# 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
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
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
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
# 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
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
# 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
redef fun compile_c_code(compiler, compile_dir)
do
+ var android_project_root = android_project_root.as(not null)
# Compile C code (and thus Nit)
toolcontext.exec_and_check(["ndk-build", "-s", "-j", "4", "-C", android_project_root])
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
+
+
class ExternCFunction
super CFunction
- var method: AExternPropdef
+ var method: AMethPropdef
- init (method: AExternPropdef, mmodule: MModule)
+ init (method: AMethPropdef, mmodule: MModule)
do
self.method = method
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
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 )
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, mmodule: MModule) 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,
mmodule.insert_compiler_options
# Enable linking C callbacks to java native methods
- mmodule.ensure_linking_callback_methods(ffi_ccu, mmodule.ffi_callbacks[self])
+ mmodule.ensure_linking_callback_methods(ffi_ccu.as(not null), mmodule.ffi_callbacks[self])
# Java implementation code
var java_file = mmodule.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, mmodule, mainmodule, ccu)
do
end
end
-redef class AExternPropdef
+redef class AMethPropdef
private fun compile_ffi_support_to_c(v: AbstractCompilerVisitor)
do
var mmodule = mpropdef.mclassdef.mmodule
amodule.ensure_compile_ffi_wrapper
compile_ffi_method(mmodule)
+ assert self isa AExternPropdef
+
# nitni - Compile missing callbacks
mmodule.ensure_compile_nitni_base(v)
var ccu = mmodule.nitni_ccu.as(not null)
# 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
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
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.
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>"
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'>"
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'>"
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'>"
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
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'>"
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
var text: String writable
var title: nullable String writable
+ init do end
+
redef fun rendering do
add "<a href=\""
add href
var elts = new Array[TplConcernElt]
redef fun rendering do
+ if elts.is_empty then return
add "<ul>"
for elt in elts do
add elt
var name: String writable
var comment: nullable String writable
+ init do end
+
redef fun rendering do
add "<li>"
add "<a href=\"{anchor}\">{name}</a>"
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 "
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\">"
+++ /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
# 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
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)
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, 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
- 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
private fun mclass_intro_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 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
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 mclassdef.mmodule.public_owner == mclass.public_owner then continue
+ if owner == mclass.public_owner then continue
if mpropdef.mproperty.visibility < ctx.min_visibility then continue
res.add mpropdef
end
var stpl = new TplConcernList
for mmodule in mmodules do
# concerns list
- 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
+ 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
+ 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
+ mtpl.add cctpl
end
- stpl.elts.add mctpl
- # concern sectionm
- 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
- mtpl.add cctpl
-
var mprops = module_map[mmodule].to_a
prop_sorter.sort mprops
for mprop in mprops do mtpl.add tpl_mpropdef_article(mprop)
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)
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
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
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 \{")
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
# 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 ).
+#
+# 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 kernel
+
+class A
+ init do 1.output
+end
+
+class B
+ init do 2.output
+end
+
+class C
+ super A
+ super B
+
+ init do 3.output
+end
+
+class D
+ super A
+ super B
+
+ var i: Int
+end
+
+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
+
+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
init_linext
inline
nitg
-test_json
mnit
init_linext
inline
test_json
-pep8analysis_args
--- /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.
+++ /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
+++ /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(", ", ": ")}>"