# Classic moles game
#
# This is a minimal practical example of the mnit framework.
-module moles
+module moles is
+ app_name("Crazy Groundhogs")
+end
import mnit
android:
mkdir -p bin
- ../../bin/nitg -o bin/simple.apk src/simple_android.nit
+ ../../bin/nitg -o bin/simple.apk src/complete_simple_android.nit
clean:
rm -rf bin
--- /dev/null
+#FIXME: Improper way of resolving unjustified metadata conflict
+module complete_simple_android is
+ app_name("test all")
+ java_package("org.nitlanguage.test_all")
+ app_version(1, 0)
+end
+
+import test_bundle
+import test_audio
+import test_shared_preferences
+import test_assets_and_resources
+import test_target_api
import simple
import mnit_android
-import android::bundle
-import android::shared_preferences
-import android::assets_and_resources
-import android::audio
+import serialization
in "Java" `{
import android.content.Context;
`}
redef class App
- var soundsp: Sound
- var soundmp: Sound
-
- redef fun init_window
- do
- super
- manage_audio_mode
- # retrieve sound
- soundsp = load_sound("sound.ogg")
- soundmp = load_music("xylofon.ogg")
- default_mediaplayer.looping = true
- default_mediaplayer.prepare
- soundmp.play
- end
-
redef fun input( ie )
do
if ie isa PointerEvent and ie.depressed then
- do_java_stuff
- test_bundle
- test_shared_preferences
- soundsp.play
- test_assets
- test_resources
+ test_java_ffi
end
return super
end
- #testing the assets manager
- fun test_assets
- do
- assert asset_manager.bitmap("fighter.png") != null
- end
-
- #testing the resources manager
- fun test_resources do
- assert resource_manager.string("string_test") == "string test"
- assert resource_manager.boolean("test_bool") == true
- assert resource_manager.dimension("test_dimen_1") != null
- assert resource_manager.dimension("test_dimen_2") != null
- end
-
- fun test_bundle
- do
- var bundle = new Bundle(self)
-
- bundle["anInt"] = 1
- bundle["aFloat"] = 1.1
- bundle["aString"] = "A string"
- bundle["aBool"] = true
-
- var int_array = new Array[Int]
- var bool_array = new Array[Bool]
-
- var value = true
-
- for i in [0..5] do
- int_array.add(i)
- bool_array.add(value)
- value = not value
- end
-
- bundle["anArrayOfInt"] = int_array
- bundle["anArrayOfBool"] = bool_array
-
- assert bundle.int("anInt", 0) == 1
- assert bundle.int("wrongInt", 0) == 0
- assert bundle.float("aFloat", 0.0) == 1.1
- assert bundle.float("wrongFloat", 0.0) == 0.0
- assert bundle.string("aString") == "A string"
- assert bundle.string("wrongString") == null
- assert bundle.bool("aBool", false)
- assert bundle.bool("wrongBool", false) == false
-
- var int_array_test = bundle.array_of_int("anArrayOfInt")
- var bool_array_test = bundle.array_of_bool("anArrayOfBool")
-
- value = true
-
- for i in [0..5] do
- assert int_array_test[i] == i
- assert bool_array_test[i] == value
- value = not value
- end
-
- assert bundle.size == 6
- assert bundle.has("aBool")
- assert not bundle.is_empty
-
- bundle.remove("aString")
- bundle.remove("anArrayOfBool")
-
- assert bundle.string("aString") == null
- assert bundle.array_of_bool("anArrayOfBool") == null
-
- # Serializable tests
- var p1 = new Point(10, 10)
- bundle["aPoint"] = p1
- var p2 = bundle.deserialize("aPoint")
-
- assert p1.to_s == p2.to_s
-
- var point_array = new Array[Point]
-
- for i in [0..5] do point_array.add(new Point(i, i))
-
- bundle["anArrayOfPoint"] = point_array
-
- var deserialized_point_array = bundle.deserialize_array("anArrayOfPoint")
-
- for i in [0..5] do
- var point = new Point(i, i)
- assert deserialized_point_array[i].to_s == point.to_s
- end
-
- bundle.clear
-
- assert bundle.keys.is_empty
- assert bundle.is_empty
- end
-
- fun test_shared_preferences
- do
- # Private mode tests
- var sp = new SharedPreferences.privately(self, "test")
- sp.add_bool("a_boolean", true)
- sp.add_float("a_float", 66.6)
- sp.add_int("an_int", 666)
- sp.add_int("a_second_int", 666777)
- sp.add_long("a_long", 6666666666)
- sp.add_string("a_string", "A string")
- sp["another_int"] = 85
- sp["yet_another_string"] = "Another string"
- sp.remove("a_second_int")
-
- # Serialized object test
- var my_point = new Point(10, 10)
- sp["a_point"] = my_point
- var my_deserialized_point = sp["a_point"]
- assert my_point.to_s == my_deserialized_point.to_s
-
- assert sp.bool("a_boolean", false) == true
- assert sp.bool("wrong_boolean", false) == false
- assert sp.float("a_float", 0.0) != 0.0
- assert sp.float("wrong_float", 0.0) == 0.0
- assert sp.int("an_int", 0) == 666
- assert sp.int("a_second_int", 0) == 0
- assert sp.long("a_long", 0) == 6666666666
- assert sp.long("wrong_long", 0) == 0
- assert sp.string("a_string", "ERROR!") == "A string"
- assert sp.string("wrong_string", "ERROR!") == "ERROR!"
- assert sp.long("another_int", 0) == 85
- assert sp.string("yet_another_string", "ERROR!") == "Another string"
- assert sp.has("an_int") == true
- assert sp.has("a_second_int") == false
-
- sp.clear
- assert sp.all == null
-
- sp.destroy
- end
-
- fun do_java_stuff import native_activity in "Java" `{
+ fun test_java_ffi import native_activity in "Java" `{
// + Log (no context needed)
android.util.Log.d("mnit_simple", "Java within NIT!!!");
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Romain Chanoir <romain.chanoir@viacesi.fr>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Test for the asserts_and_resources module of App.nit framework
+module test_assets_and_resources
+
+import simple_android
+import android::assets_and_resources
+
+redef class App
+ redef fun input( ie )
+ do
+ if ie isa PointerEvent and ie.depressed then
+ test_assets
+ test_resources
+ end
+ return super
+ end
+
+ # Testing the assets manager
+ fun test_assets
+ do
+ assert asset_manager.bitmap("fighter.png") != null
+ end
+
+ # Testing the resources manager
+ fun test_resources do
+ assert resource_manager.string("string_test") == "string test"
+ assert resource_manager.boolean("test_bool") == true
+ assert resource_manager.dimension("test_dimen_1") != null
+ assert resource_manager.dimension("test_dimen_2") != null
+ end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Romain Chanoir <romain.chanoir@viacesi.fr>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Test for the audio module of App.nit framework
+module test_audio
+
+import simple_android
+import android::audio
+
+redef class App
+ var soundsp: Sound
+ var soundmp: Sound
+
+ redef fun init_window
+ do
+ super
+ manage_audio_mode
+
+ # Retrieve sound
+ soundsp = load_sound("sound.ogg")
+ soundmp = load_music("xylofon.ogg")
+ default_mediaplayer.looping = true
+ default_mediaplayer.prepare
+ soundmp.play
+ end
+
+ redef fun input( ie )
+ do
+ if ie isa PointerEvent and ie.depressed then
+ soundsp.play
+ end
+ return super
+ end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Frédéric Vachon <fredvac@gmail.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Test for the bundle module of App.nit framework
+module test_bundle
+
+import simple_android
+import android::bundle
+
+redef class App
+ redef fun input ( ie )
+ do
+ if ie isa PointerEvent and ie.depressed then
+ test_bundle
+ end
+ return super
+ end
+
+ fun test_bundle
+ do
+ var bundle = new Bundle(self)
+
+ bundle["anInt"] = 1
+ bundle["aFloat"] = 1.1
+ bundle["aString"] = "A string"
+ bundle["aBool"] = true
+
+ var int_array = new Array[Int]
+ var bool_array = new Array[Bool]
+
+ var value = true
+
+ for i in [0..5] do
+ int_array.add(i)
+ bool_array.add(value)
+ value = not value
+ end
+
+ bundle["anArrayOfInt"] = int_array
+ bundle["anArrayOfBool"] = bool_array
+
+ assert bundle.int("anInt", 0) == 1
+ assert bundle.int("wrongInt", 0) == 0
+ assert bundle.float("aFloat", 0.0) == 1.1
+ assert bundle.float("wrongFloat", 0.0) == 0.0
+ assert bundle.string("aString") == "A string"
+ assert bundle.string("wrongString") == null
+ assert bundle.bool("aBool", false)
+ assert bundle.bool("wrongBool", false) == false
+
+ var int_array_test = bundle.array_of_int("anArrayOfInt")
+ var bool_array_test = bundle.array_of_bool("anArrayOfBool")
+
+ value = true
+
+ for i in [0..5] do
+ assert int_array_test[i] == i
+ assert bool_array_test[i] == value
+ value = not value
+ end
+
+ assert bundle.size == 6
+ assert bundle.has("aBool")
+ assert not bundle.is_empty
+
+ bundle.remove("aString")
+ bundle.remove("anArrayOfBool")
+
+ assert bundle.string("aString") == null
+ assert bundle.array_of_bool("anArrayOfBool") == null
+
+ # Serializable tests
+ var p1 = new Point(10, 10)
+ bundle["aPoint"] = p1
+ var p2 = bundle.deserialize("aPoint")
+
+ assert p1.to_s == p2.to_s
+
+ var point_array = new Array[Point]
+
+ for i in [0..5] do point_array.add(new Point(i, i))
+
+ bundle["anArrayOfPoint"] = point_array
+
+ var deserialized_point_array = bundle.deserialize_array("anArrayOfPoint")
+
+ for i in [0..5] do
+ var point = new Point(i, i)
+ assert deserialized_point_array[i].to_s == point.to_s
+ end
+
+ bundle.clear
+
+ assert bundle.keys.is_empty
+ assert bundle.is_empty
+ end
+end
+
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Frédéric Vachon <fredvac@gmail.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Test for the shared_preferences module of App.nit framework
+module test_shared_preferences
+
+import simple_android
+import android::shared_preferences
+
+redef class App
+ redef fun input ( ie )
+ do
+ if ie isa PointerEvent and ie.depressed then
+ test_shared_preferences
+ end
+ return super
+ end
+
+ fun test_shared_preferences
+ do
+ # Private mode tests
+ var sp = new SharedPreferences.privately(self, "test")
+ sp.add_bool("a_boolean", true)
+ sp.add_float("a_float", 66.6)
+ sp.add_int("an_int", 666)
+ sp.add_int("a_second_int", 666777)
+ sp.add_long("a_long", 6666666666)
+ sp.add_string("a_string", "A string")
+ sp["another_int"] = 85
+ sp["yet_another_string"] = "Another string"
+ sp.remove("a_second_int")
+
+ # Serialized object test
+ var my_point = new Point(10, 10)
+ sp["a_point"] = my_point
+ var my_deserialized_point = sp["a_point"]
+ assert my_point.to_s == my_deserialized_point.to_s
+
+ assert sp.bool("a_boolean", false) == true
+ assert sp.bool("wrong_boolean", false) == false
+ assert sp.float("a_float", 0.0) != 0.0
+ assert sp.float("wrong_float", 0.0) == 0.0
+ assert sp.int("an_int", 0) == 666
+ assert sp.int("a_second_int", 0) == 0
+ assert sp.long("a_long", 0) == 6666666666
+ assert sp.long("wrong_long", 0) == 0
+ assert sp.string("a_string", "ERROR!") == "A string"
+ assert sp.string("wrong_string", "ERROR!") == "ERROR!"
+ assert sp["another_int"] == 85
+ assert sp["yet_another_string"] == "Another string"
+ assert sp.has("an_int") == true
+ assert sp.has("a_second_int") == false
+
+ sp.clear
+ assert sp.all == null
+
+ sp.destroy
+ end
+end
# Test for the API level related annotations
module test_target_api is
- min_sdk_version(10)
- max_sdk_version(19)
- target_sdk_version(11)
+ min_api_version(10)
+ max_api_version(19)
+ target_api_version(11)
end
import simple_android
redef type SELF: NativeResources
fun get_assets:NativeAssetManager in "Java" `{ return recv.getAssets(); `}
- fun get_color(id: Int): Int in "Java" `{ return recv.getColor(id); `}
- fun get_boolean(id: Int): Bool in "Java" `{ return recv.getBoolean(id); `}
- fun get_dimension(id: Int): Int in "Java" `{ return (int)recv.getDimension(id); `}
- fun get_drawable(id: Int): NativeDrawable in "Java" `{ return recv.getDrawable(id); `}
+ fun get_color(id: Int): Int in "Java" `{ return recv.getColor((int)id); `}
+ fun get_boolean(id: Int): Bool in "Java" `{ return recv.getBoolean((int)id); `}
+ fun get_dimension(id: Int): Int in "Java" `{ return (int)recv.getDimension((int)id); `}
+ fun get_drawable(id: Int): NativeDrawable in "Java" `{ return recv.getDrawable((int)id); `}
fun get_identifier(name, def_type, def_package: JavaString): Int in "Java" `{ return recv.getIdentifier(name, def_type, def_package); `}
- fun get_integer(id: Int): Int in "Java" `{ return recv.getInteger(id); `}
- fun get_string(id: Int): JavaString in "Java" `{ return recv.getString(id); `}
- fun get_resource_entry_name(resid: Int): JavaString in "Java" `{ return recv.getResourceEntryName(resid); `}
- fun get_resource_name(resid: Int): JavaString in "Java" `{ return recv.getResourceName(resid); `}
- fun get_resource_pakage_name(resid: Int): JavaString in "Java" `{ return recv.getResourcePackageName(resid); `}
- fun get_resource_type_name(resid: Int): JavaString in "Java" `{ return recv.getResourceTypeName(resid); `}
+ fun get_integer(id: Int): Int in "Java" `{ return recv.getInteger((int)id); `}
+ fun get_string(id: Int): JavaString in "Java" `{ return recv.getString((int)id); `}
+ fun get_resource_entry_name(resid: Int): JavaString in "Java" `{ return recv.getResourceEntryName((int)resid); `}
+ fun get_resource_name(resid: Int): JavaString in "Java" `{ return recv.getResourceName((int)resid); `}
+ fun get_resource_pakage_name(resid: Int): JavaString in "Java" `{ return recv.getResourcePackageName((int)resid); `}
+ fun get_resource_type_name(resid: Int): JavaString in "Java" `{ return recv.getResourceTypeName((int)resid); `}
end
# Resource manager for android resources placed in the `res` folder of your app
# Create a NativeBitmap using a resource ID and the NativeResources
# Called by the ResourceManager
- new from_resources(res: NativeResources, id: Int) in "Java" `{ return BitmapFactory.decodeResource(res, id); `}
+ new from_resources(res: NativeResources, id: Int) in "Java" `{ return BitmapFactory.decodeResource(res, (int)id); `}
fun width: Int in "Java" `{ return recv.getWidth(); `}
fun height: Int in "Java" `{ return recv.getHeight(); `}
end
redef type SELF: NativeAudioManager
fun mode: Int in "Java" `{ return recv.getMode(); `}
- fun mode=(i: Int) in "Java" `{ recv.setMode(i); `}
+ fun mode=(i: Int) in "Java" `{ recv.setMode((int)i); `}
fun wired_headset_on: Bool in "Java" `{ return recv.isWiredHeadsetOn(); `}
fun wired_headset_on=(b: Bool) in "Java" `{ recv.setWiredHeadsetOn(b); `}
fun speakerphone_on: Bool in "Java" `{ return recv.isSpeakerphoneOn(); `}
}
`}
- fun create(context: NativeActivity, id: Int): NativeMediaPlayer in "Java" `{ return recv.create(context, id); `}
+ fun create(context: NativeActivity, id: Int): NativeMediaPlayer in "Java" `{ return recv.create(context, (int)id); `}
fun pause in "Java" `{ recv.pause(); `}
fun stop in "Java" `{ recv.stop(); `}
fun playing: Bool in "Java" `{ return recv.isPlaying(); `}
fun looping=(b: Bool) in "Java" `{ recv.setLooping(b); `}
fun volume=(vol: Float) in "Java" `{ recv.setVolume((float)vol, (float)vol); `}
fun both_volume(left_volume, right_volume: Float) in "Java" `{ recv.setVolume((float)left_volume, (float)right_volume); `}
- fun stream_type=(stream_type: Int) in "Java" `{ recv.setAudioStreamType(stream_type); `}
+ fun stream_type=(stream_type: Int) in "Java" `{ recv.setAudioStreamType((int)stream_type); `}
fun data_source_fd(fd: NativeFileDescriptor, start_offset, length: Int) in "Java" `{
try {
recv.setDataSource(fd, start_offset, length);
redef type SELF: NativeSoundPool
new(max_streams, stream_type, src_quality: Int) in "Java" `{
- return new SoundPool(max_streams, stream_type, src_quality);
+ return new SoundPool((int)max_streams, (int)stream_type, (int)src_quality);
`}
- fun load_asset_fd(afd: NativeAssetFileDescriptor, priority: Int): Int in "Java" `{ return recv.load(afd, priority); `}
- fun load_id(context: NativeActivity, resid, priority: Int): Int in "Java" `{ return recv.load(context, resid, priority); `}
- fun load_path(path: JavaString, priority: Int): Int in "Java" `{ return recv.load(path, priority); `}
+ fun load_asset_fd(afd: NativeAssetFileDescriptor, priority: Int): Int in "Java" `{ return recv.load(afd, (int)priority); `}
+ fun load_id(context: NativeActivity, resid, priority: Int): Int in "Java" `{ return recv.load(context, (int)resid, (int)priority); `}
+ fun load_path(path: JavaString, priority: Int): Int in "Java" `{ return recv.load(path, (int)priority); `}
fun play(sound_id: Int, left_volume, right_volume: Float, priority, l: Int, rate: Float): Int in "Java" `{
- return recv.play(sound_id, (float)left_volume, (float)right_volume, priority, l, (float)rate);
+ return recv.play((int)sound_id, (float)left_volume, (float)right_volume, (int)priority, (int)l, (float)rate);
`}
- fun pause(stream_id: Int) in "Java" `{ recv.pause(stream_id); `}
+ fun pause(stream_id: Int) in "Java" `{ recv.pause((int)stream_id); `}
fun auto_pause in "Java" `{ recv.autoPause(); `}
fun auto_resume in "Java" `{ recv.autoResume(); `}
- fun resume(stream_id: Int) in "Java" `{ recv.resume(stream_id); `}
- fun set_loop(stream_id, l: Int) in "Java" `{ recv.setLoop(stream_id, l); `}
- fun set_priority(stream_id, priority: Int) in "Java" `{ recv.setPriority(stream_id, priority); `}
- fun set_rate(stream_id: Int, rate: Float) in "Java" `{ recv.setRate(stream_id, (float)rate); `}
- fun set_volume(stream_id: Int, left_volume, right_volume: Float) in "Java" `{ recv.setVolume(stream_id, (float)left_volume, (float)right_volume); `}
- fun stop(stream_id: Int) in "Java" `{ recv.stop(stream_id); `}
- fun unload(sound_id: Int): Bool in "Java" `{ return recv.unload(sound_id); `}
+ fun resume(stream_id: Int) in "Java" `{ recv.resume((int)stream_id); `}
+ fun set_loop(stream_id, l: Int) in "Java" `{ recv.setLoop((int)stream_id, (int)l); `}
+ fun set_priority(stream_id, priority: Int) in "Java" `{ recv.setPriority((int)stream_id, (int)priority); `}
+ fun set_rate(stream_id: Int, rate: Float) in "Java" `{ recv.setRate((int)stream_id, (float)rate); `}
+ fun set_volume(stream_id: Int, left_volume, right_volume: Float) in "Java" `{ recv.setVolume((int)stream_id, (float)left_volume, (float)right_volume); `}
+ fun stop(stream_id: Int) in "Java" `{ recv.stop((int)stream_id); `}
+ fun unload(sound_id: Int): Bool in "Java" `{ return recv.unload((int)sound_id); `}
end
fun put_integer_array_list(key: JavaString, value: Array[Int])
import Array[Int].length, Array[Int].[] in "Java" `{
ArrayList<Integer> java_array =
- new ArrayList<Integer>(Array_of_Int_length(value));
+ new ArrayList<Integer>((int) Array_of_Int_length(value));
for(int i=0; i < java_array.size(); ++i)
java_array.add((int) Array_of_Int__index(value, i));
`}
fun put_string_array_list(key: JavaString, value: Array[JavaString])
import Array[JavaString].length, Array[JavaString].[] in "Java" `{
- ArrayList<String> java_array = new ArrayList<String>(Array_of_JavaString_length(value));
+ ArrayList<String> java_array = new ArrayList<String>((int)Array_of_JavaString_length(value));
for(int i=0; i < java_array.size(); ++i)
java_array.add(Array_of_JavaString__index(value, i));
fun put_char_sequence_array_list(key: JavaString, value: Array[JavaString])
import Array[JavaString].length, Array[JavaString].[] in "Java" `{
ArrayList<CharSequence> java_array =
- new ArrayList<CharSequence>(Array_of_JavaString_length(value));
+ new ArrayList<CharSequence>((int)Array_of_JavaString_length(value));
for(int i=0; i < java_array.size(); ++i)
java_array.add(Array_of_JavaString__index(value, i));
`}
fun put_boolean_array(key: JavaString, value: Array[Bool])
import Array[Bool].length, Array[Bool].[] in "Java" `{
- boolean[] java_array = new boolean[Array_of_Bool_length(value)];
+ boolean[] java_array = new boolean[(int)Array_of_Bool_length(value)];
for(int i=0; i < java_array.length; ++i)
java_array[i] = Array_of_Bool__index(value, i);
`}
fun put_byte_array(key: JavaString, value: Array[Int])
import Array[Int].length, Array[Int].[] in "Java" `{
- byte[] java_array = new byte[Array_of_Int_length(value)];
+ byte[] java_array = new byte[(int)Array_of_Int_length(value)];
for(int i=0; i < java_array.length; ++i)
java_array[i] = (byte) Array_of_Int__index(value, i);
`}
fun put_short_array(key: JavaString, value: Array[Int])
import Array[Int].length, Array[Int].[] in "Java" `{
- short[] java_array = new short[Array_of_Int_length(value)];
+ short[] java_array = new short[(int)Array_of_Int_length(value)];
for(int i=0; i < java_array.length; ++i)
java_array[i] = (short) Array_of_Int__index(value, i);
`}
fun put_char_array(key: JavaString, value: Array[Char])
import Array[Char].length, Array[Char].[] in "Java" `{
- char[] java_array = new char[Array_of_Char_length(value)];
+ char[] java_array = new char[(int)Array_of_Char_length(value)];
for(int i=0; i < java_array.length; ++i)
java_array[i] = Array_of_Char__index(value, i);
`}
fun put_int_array(key: JavaString, value: Array[Int])
import Array[Int].length, Array[Int].[] in "Java" `{
- int[] java_array = new int[Array_of_Int_length(value)];
+ int[] java_array = new int[(int)Array_of_Int_length(value)];
for(int i=0; i < java_array.length; ++i)
java_array[i] = (int) Array_of_Int__index(value, i);
`}
fun put_long_array(key: JavaString, value: Array[Int])
import Array[Int].length, Array[Int].[] in "Java" `{
- long[] java_array = new long[Array_of_Int_length(value)];
+ long[] java_array = new long[(int)Array_of_Int_length(value)];
for(int i=0; i < java_array.length; ++i)
java_array[i] = Array_of_Int__index(value, i);
`}
fun put_float_array(key: JavaString, value: Array[Float])
import Array[Float].length, Array[Float].[] in "Java" `{
- float[] java_array = new float[Array_of_Float_length(value)];
+ float[] java_array = new float[(int)Array_of_Float_length(value)];
for(int i=0; i < java_array.length; ++i)
java_array[i] = (float) Array_of_Float__index(value, i);
`}
fun put_double_array(key: JavaString, value: Array[Float])
import Array[Float].length, Array[Float].[] in "Java" `{
- double[] java_array = new double[Array_of_Float_length(value)];
+ double[] java_array = new double[(int)Array_of_Float_length(value)];
for(int i=0; i < java_array.length; ++i)
java_array[i] = Array_of_Float__index(value, i);
`}
fun put_string_array(key: JavaString, value: Array[JavaString])
import Array[JavaString].length, Array[JavaString].[] in "Java" `{
- String[] java_array = new String[Array_of_JavaString_length(value)];
+ String[] java_array = new String[(int)Array_of_JavaString_length(value)];
for(int i=0; i < java_array.length; ++i)
java_array[i] = Array_of_JavaString__index(value, i);
`}
fun put_char_sequence_array(key: JavaString, value: Array[JavaString])
import Array[JavaString].length, Array[JavaString].[] in "Java" `{
- CharSequence[] java_array = new CharSequence[Array_of_JavaString_length(value)];
+ CharSequence[] java_array = new CharSequence[(int)Array_of_JavaString_length(value)];
for(int i=0; i < java_array.length; ++i)
java_array[i] = Array_of_JavaString__index(value, i);
`}
fun get_int(key: JavaString): Int in "Java" `{ return recv.getInt(key); `}
fun get_int_with_def_value(key: JavaString, def_value: Int): Int in "Java" `{
- return (int) recv.getInt(key, (int) def_value);
+ return recv.getInt(key, (int) def_value);
`}
- # FIXME: Get rid of the int cast as soon as the ffi is fixed
- fun get_long(key: JavaString): Int in "Java" `{ return (int) recv.getLong(key); `}
- # FIXME: Get rid of the int cast as soon as the ffi is fixed
+ fun get_long(key: JavaString): Int in "Java" `{ return recv.getLong(key); `}
fun get_long_with_def_value(key: JavaString, def_value: Int): Int in "Java" `{
- return (int) recv.getLong(key);
+ return recv.getLong(key);
`}
fun get_float(key: JavaString): Float in "Java" `{
return (float) recv.getFloat(key);
if (java_array == null) return nit_array;
for(int i=0; i < java_array.length; ++i)
- Array_of_Int_add(nit_array, (int) java_array[i]);
+ Array_of_Int_add(nit_array, java_array[i]);
return nit_array;
`}
if (java_array == null) return nit_array;
for(int i=0; i < java_array.length; ++i)
- Array_of_Int_add(nit_array, (int) java_array[i]);
+ Array_of_Int_add(nit_array, java_array[i]);
return nit_array;
`}
if (java_array == null) return nit_array;
for(int i=0; i < java_array.length; ++i)
- Array_of_Int_add(nit_array, (int) java_array[i]);
+ Array_of_Int_add(nit_array, java_array[i]);
return nit_array;
`}
`}
fun write(one_byte: Int) in "Java" `{
try {
- recv.write(one_byte);
+ recv.write((byte)one_byte);
}catch(IOException e){
e.printStackTrace();
}
fun get_int(key: JavaString, def_value: Int): Int in "Java" `{
int return_value;
try {
- return_value = recv.getInt(key, def_value);
+ return_value = recv.getInt(key, (int)def_value);
} catch (ClassCastException e) {
return def_value;
}
return return_value;
`}
- #FIXME: Get rid of the `int` cast when the ffi is fixed
fun get_long(key: JavaString, def_value: Int): Int in "Java" `{
long return_value;
try {
return recv.putFloat(key, (float) value);
`}
fun put_int(key: JavaString, value: Int): NativeSharedPreferencesEditor in "Java" `{
- return recv.putInt(key, value);
+ return recv.putInt(key, (int)value);
`}
fun put_long(key: JavaString, value: Int): NativeSharedPreferencesEditor in "Java" `{
return recv.putLong(key, value);
// Uses default SharedPreferences if file_name is an empty String
if (file_name.equals("")) {
- sp = context.getPreferences( mode);
+ sp = context.getPreferences((int)mode);
} else {
- sp = context.getSharedPreferences(file_name, mode);
+ sp = context.getSharedPreferences(file_name, (int)mode);
}
SharedPreferences.Editor editor = sp.edit();
end
# Retrieve all nodes with specified `lbl`
+ #
+ # var client = new Neo4jClient("http://localhost:7474")
+ # #
+ # var andres = new NeoNode
+ # andres.labels.add_all(["Human", "Male"])
+ # client.save_node(andres)
+ # var kate = new NeoNode
+ # kate.labels.add_all(["Human", "Female"])
+ # client.save_node(kate)
+ # #
+ # var nodes = client.nodes_with_label("Human")
+ # assert nodes.has(andres)
+ # assert nodes.has(kate)
fun nodes_with_label(lbl: String): Array[NeoNode] do
var res = get("{base_url}/db/data/label/{lbl}/nodes")
var nodes = new Array[NeoNode]
return nodes
end
+ # Retrieve nodes belonging to all the specified `labels`.
+ #
+ # var client = new Neo4jClient("http://localhost:7474")
+ # #
+ # var andres = new NeoNode
+ # andres.labels.add_all(["Human", "Male"])
+ # client.save_node(andres)
+ # var kate = new NeoNode
+ # kate.labels.add_all(["Human", "Female"])
+ # client.save_node(kate)
+ # #
+ # var nodes = client.nodes_with_labels(["Human", "Male"])
+ # assert nodes.has(andres)
+ # assert not nodes.has(kate)
+ fun nodes_with_labels(labels: Array[String]): Array[NeoNode] do
+ assert not labels.is_empty
+ var res = cypher(new CypherQuery.from_string("MATCH (n:{labels.join(":")}) RETURN n"))
+ var nodes = new Array[NeoNode]
+ for json in res.as(JsonObject)["data"].as(JsonArray) do
+ var obj = json.as(JsonArray).first.as(JsonObject)
+ var node = load_node(obj["self"].to_s)
+ node.internal_properties = obj["data"].as(JsonObject)
+ nodes.add node
+ end
+ return nodes
+ end
+
# Perform a `CypherQuery`
# see: CypherQuery
fun cypher(query: CypherQuery): Jsonable do
end
end
+ # Create a `NeoNode` or a `NeoEdge` in batch mode.
+ fun save_entity(nentity: NeoEntity) do
+ if nentity isa NeoNode then
+ save_node(nentity)
+ else if nentity isa NeoEdge then
+ save_edge(nentity)
+ else abort
+ end
+
# Create a node in batch mode also create labels and edges
fun save_node(node: NeoNode) do
if node.id != null or node.batch_id != null then return
# Mainly generated method to return the next instance of the givent
# class by name
- fun deserialize_class(class_name: String): Object do abort
+ fun deserialize_class(class_name: String): Object do
+ print "Error: doesn't know how to deserialize class \"{class_name}\""
+ abort
+ end
end
# Instances of this class can be passed to `Serializer::serialize`
end
# C function to convert an nit Int to a NativeString (char*)
- private fun native_int_to_s(len: Int): NativeString is extern "native_int_to_s"
+ private fun native_int_to_s: NativeString is extern "native_int_to_s"
# return displayable int in base 10 and signed
#
# assert 1.to_s == "1"
# assert (-123).to_s == "-123"
redef fun to_s do
- var len = digit_count(10)
- return native_int_to_s(len).to_s_with_length(len)
+ return native_int_to_s.to_s
end
# return displayable int in hexadecimal
#include "string_nit.h"
// Integer to NativeString method
-char* native_int_to_s(int recv, int len){
- char* str = malloc(len + 1);
- sprintf(str, "%d", recv);
+char* native_int_to_s(long recv){
+ int len = snprintf(NULL, 0, "%ld", recv);
+ char* str = malloc(len);
+ sprintf(str, "%ld", recv);
return str;
}
* another product.
*/
-char* native_int_to_s(int recv, int len);
+char* native_int_to_s(long recv);
#endif
redef class AAttrPropdef
redef fun compile_to_c(v, mpropdef, arguments)
do
- if arguments.length == 1 then
- var res = v.read_attribute(self.mpropdef.mproperty, arguments.first)
+ if mpropdef == mreadpropdef then
+ assert arguments.length == 1
+ var res
+ if is_lazy then
+ var nexpr = n_expr
+ assert nexpr != null
+ var set
+ var ret = self.mpropdef.static_mtype
+ var useiset = ret.ctype == "val*" and not ret isa MNullableType
+ var guard = self.mlazypropdef.mproperty
+ if useiset then
+ set = v.isset_attribute(self.mpropdef.mproperty, arguments.first)
+ else
+ set = v.read_attribute(guard, arguments.first)
+ end
+ v.add("if(likely({set})) \{")
+ res = v.read_attribute(self.mpropdef.mproperty, arguments.first)
+ v.add("\} else \{")
+ var value = v.expr(nexpr, self.mpropdef.static_mtype)
+ v.write_attribute(self.mpropdef.mproperty, arguments.first, value)
+ v.assign(res, value)
+ if not useiset then
+ var true_v = v.new_expr("1", v.bool_type)
+ v.write_attribute(guard, arguments.first, true_v)
+ end
+ v.add("\}")
+ else
+ res = v.read_attribute(self.mpropdef.mproperty, arguments.first)
+ end
v.assign(v.frame.returnvar.as(not null), res)
- else
+ else if mpropdef == mwritepropdef then
+ assert arguments.length == 2
v.write_attribute(self.mpropdef.mproperty, arguments.first, arguments[1])
+ if is_lazy then
+ var ret = self.mpropdef.static_mtype
+ var useiset = ret.ctype == "val*" and not ret isa MNullableType
+ if not useiset then
+ v.write_attribute(self.mlazypropdef.mproperty, arguments.first, v.new_expr("1", v.bool_type))
+ end
+ end
+ else
+ abort
end
end
fun init_expr(v: AbstractCompilerVisitor, recv: RuntimeVariable)
do
var nexpr = self.n_expr
- if nexpr != null then
+ if nexpr != null and not is_lazy then
var oldnode = v.current_node
v.current_node = self
var old_frame = v.frame
res_dir = "res"
end
if res_dir.file_exists then
+ # copy the res folder to .nit_compile
res_dir = res_dir.realpath
var target_res_dir = "{android_project_root}"
- if target_res_dir.file_exists then
- # copy the res folder to .nit_compile
- toolcontext.exec_and_check(["cp", "-R", res_dir, target_res_dir], "Android project error")
- end
+ toolcontext.exec_and_check(["cp", "-R", res_dir, target_res_dir], "Android project error")
+ else
+ # Create our own custom `res/values/string.xml` with the App name
+"""<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="app_name">{{{app_name}}}</string>
+</resources>""".write_to_file "{dir}/res/values/strings.xml"
end
-
end
redef fun write_makefile(compiler, compile_dir, cfiles)
redef class ToolContext
var extern_classes_typing_phase_ast: Phase = new ExternClassesTypingPhaseAst(self, [ffi_language_assignation_phase])
- var extern_classes_typing_phase_model: Phase = new ExternClassesTypingPhaseModel(self, [extern_classes_typing_phase_ast, modelize_class_phase])
+ var extern_classes_typing_phase_model: Phase = new ExternClassesTypingPhaseModel(self,
+ [extern_classes_typing_phase_ast, modelize_class_phase, modelize_property_phase])
end
# Assigns the `ftype` to class definitions, work on the AST only
replace('/', ".").replace('$', ".").replace(' ', "").replace('\n',"")
if mclass.name == "Bool" then return "boolean"
if mclass.name == "Char" then return "char"
- if mclass.name == "Int" then return "int"
+ if mclass.name == "Int" then return "long"
if mclass.name == "Float" then return "double"
return super
end
if ftype isa ForeignJavaType then return "jobject"
if mclass.name == "Bool" then return "jboolean"
if mclass.name == "Char" then return "jchar"
- if mclass.name == "Int" then return "jint"
+ if mclass.name == "Int" then return "jlong"
if mclass.name == "Float" then return "jdouble"
return super
end
end
if mclass.name == "Bool" then return "Z"
if mclass.name == "Char" then return "C"
- if mclass.name == "Int" then return "I"
+ if mclass.name == "Int" then return "J"
if mclass.name == "Float" then return "D"
return super
end
if ftype isa ForeignJavaType then return "Object"
if mclass.name == "Bool" then return "Boolean"
if mclass.name == "Char" then return "Char"
- if mclass.name == "Int" then return "Int"
+ if mclass.name == "Int" then return "Long"
if mclass.name == "Float" then return "Double"
return super
end
# Force easy warnings before intraproc-errors
phases.add_edge(scope_phase, simple_misc_analysis_phase)
# Code genrated by the serialization phase must be analyzed for literals
- phases.add_edge(literal_phase, serialization_phase)
+ phases.add_edge(literal_phase, serialization_phase_pre_model)
+ phases.add_edge(modelize_class_phase, serialization_phase_pre_model)
return true
end
end
assert mtype isa MClassType
var sc = mtype.mclass
if not parents.has(sc) or sc == objectclass then
- warning(ntype, "Warning: superfluous super-class {mtype} in class {mclassdef.mclass}.")
+ # Skip the warning on generated code
+ if ntype.location.file != null and not ntype.location.file.filename.is_empty then
+ warning(ntype, "Warning: superfluous super-class {mtype} in class {mclassdef.mclass}.")
+ end
else if not seen_parents.has_key(sc) then
seen_parents[sc] = ntype
else
# Is the node tagged `noinit`?
var noinit = false
+ # Is the node taggeg lazy?
+ var is_lazy = false
+
+ # The guard associated to a lasy attribute.
+ # Because some engines does not have a working `isset`,
+ # this additionnal attribute is used to guard the lazy initialization.
+ # TODO: to remove once isset is correctly implemented
+ var mlazypropdef: nullable MAttributeDef
+
# The associated getter (read accessor) if any
var mreadpropdef: nullable MMethodDef writable
# The associated setter (write accessor) if any
var mwritepropdef: nullable MMethodDef writable
+
redef fun build_property(modelbuilder, mclassdef)
do
var mclass = mclassdef.mclass
modelbuilder.mpropdef2npropdef[mreadpropdef] = self
mreadpropdef.mdoc = mpropdef.mdoc
+ var atlazy = self.get_single_annotation("lazy", modelbuilder)
+ if atlazy != null then
+ if n_expr == null then
+ modelbuilder.error(atlazy, "Error: a lazy attribute needs a value")
+ end
+ is_lazy = true
+ var mlazyprop = new MAttribute(mclassdef, "lazy _" + name, none_visibility)
+ var mlazypropdef = new MAttributeDef(mclassdef, mlazyprop, self.location)
+ self.mlazypropdef = mlazypropdef
+ end
+
var atreadonly = self.get_single_annotation("readonly", modelbuilder)
if atreadonly != null then
if n_expr == null then
mreadpropdef.msignature = msignature
end
- var msritepropdef = self.mwritepropdef
+ var mwritepropdef = self.mwritepropdef
if mwritepropdef != null then
var name: String
if n_id != null then
var msignature = new MSignature([mparameter], null)
mwritepropdef.msignature = msignature
end
+
+ var mlazypropdef = self.mlazypropdef
+ if mlazypropdef != null then
+ mlazypropdef.static_mtype = modelbuilder.model.get_mclasses_by_name("Bool").first.mclass_type
+ end
end
redef fun check_signature(modelbuilder)
recv.attributes[mproperty] = value
end
+ # Is the attribute `mproperty` initialized the instance `recv`?
+ fun isset_attribute(mproperty: MAttribute, recv: Instance): Bool
+ do
+ assert recv isa MutableInstance
+ return recv.attributes.has_key(mproperty)
+ end
+
# Collect attributes of a type in the order of their init
fun collect_attr_propdef(mtype: MType): Array[AAttrPropdef]
do
var recv = args.first
assert recv isa MutableInstance
var attr = self.mpropdef.mproperty
- if args.length == 1 then
- return v.read_attribute(attr, recv)
- else
+ if mpropdef == mreadpropdef then
+ assert args.length == 1
+ if not is_lazy or v.isset_attribute(attr, recv) then return v.read_attribute(attr, recv)
+ return evaluate_expr(v, recv)
+ else if mpropdef == mwritepropdef then
assert args.length == 2
v.write_attribute(attr, recv, args[1])
return null
+ else
+ abort
end
end
# Evaluate and set the default value of the attribute in `recv`
private fun init_expr(v: NaiveInterpreter, recv: Instance)
do
- assert recv isa MutableInstance
+ if is_lazy then return
var nexpr = self.n_expr
if nexpr != null then
- var f = new Frame(self, self.mpropdef.as(not null), [recv])
- v.frames.unshift(f)
- var val = v.expr(nexpr)
- assert val != null
- v.frames.shift
- assert not v.is_escaping
- v.write_attribute(self.mpropdef.mproperty, recv, val)
+ evaluate_expr(v, recv)
return
end
var mtype = self.mpropdef.static_mtype.as(not null)
v.write_attribute(self.mpropdef.mproperty, recv, v.null_instance)
end
end
+
+ private fun evaluate_expr(v: NaiveInterpreter, recv: Instance): Instance
+ do
+ assert recv isa MutableInstance
+ var nexpr = self.n_expr
+ assert nexpr != null
+ var f = new Frame(self, self.mpropdef.as(not null), [recv])
+ v.frames.unshift(f)
+ var val = v.expr(nexpr)
+ assert val != null
+ v.frames.shift
+ assert not v.is_escaping
+ v.write_attribute(self.mpropdef.mproperty, recv, val)
+ return val
+ end
end
redef class AClassdef
if recv == null then return null
if recv.mtype isa MNullType then fatal(v, "Receiver is null")
var mproperty = self.mproperty.as(not null)
- assert recv isa MutableInstance
- return v.bool_instance(recv.attributes.has_key(mproperty))
+ return v.bool_instance(v.isset_attribute(mproperty, recv))
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.
+
+# Save and load `Model` from/to Neo4j base.
+#
+# Nit models are composed by MEntities.
+# This module creates NeoNode for each MEntity found in a `Model` and save them into Neo4j database.
+#
+# see `Neo4jClient`.
+#
+# NeoNodes can also be translated back to MEntities to rebuild a Nit `Model`.
+#
+# Structure of the nit `Model` in base:
+#
+# `MProject`
+#
+# * labels: `model_name`, `MEntity`, `MProject`
+# * `(:MProject)-[:ROOT]->(:MGroup)`
+#
+# `MGroup`
+#
+# * labels: `model_name`, `MEntity`, `MGroup`
+# * `(:MGroup)-[:PROJECT]->(:MProject)`
+# * `(:MGroup)-[:PARENT]->(:MGroup)`
+#
+# `MModule`
+#
+# * labels: `model_name`, `MEntity`, `MModule`
+# * `(:MModule)-[:IMPORTS]->(:MModule)`
+# * `(:MModule)-[:INTRODUCES]->(:MClass)`
+# * `(:MModule)-[:DEFINES]->(:MClassDef)`
+#
+# `MClass`
+#
+# * labels: `model_name`, `MEntity`, `MClass`
+# * `(:MClass)-[:CLASSTYPE]->(:MClassType)`
+#
+# `MClassDef`
+#
+# * labels: `model_name`, `MEntity`, `MClassDef`
+# * `(:MClassDef)-[:BOUNDTYPE]->(:MClassType)`
+# * `(:MClassDef)-[:MCLASS]->(:MClass)`
+# * `(:MClassDef)-[:INTRODUCES]->(:MProperty)`
+# * `(:MClassDef)-[:DECLARES]->(:MPropDef)`
+#
+# `MProperty`
+#
+# * labels: `model_name`, `MEntity`, `MProperty`
+# * `(:MProperty)-[:INTRO_CLASSDEF]->(:MClassDef)`
+#
+# MProperties can also have labels `MMethod`, `MAttribute`, `MVirtualTypeProp`.
+#
+# `MPropDef`
+#
+# * labels: `model_name`, `MEntity`, `MPropDef`
+# * `(:MPropDef)-[:DEFINES]->(:MProperty)`
+#
+# MPropdefs can also have labels `MMethodDef`, `MAttributeDef`, `MVirtualTypeDef`.
+#
+# `MMethodDef` are linked to a `MSignature`:
+#
+# * `(:MMethodDef)-[:SIGNATURE]->(:MSignature)`
+#
+# `MVirtualTypeDef` are linked to a `MType` (its `bound`):
+#
+# * `(:MVirtualTypeDef)-[:BOUND]->(:MType)`
+#
+# `MType`
+#
+# * labels: `model_name`, `MEntity`, `MType`
+#
+# MTypes can also have labels `MClassType`, `MGenericType`, `MNullableType`, `MVirtualType`
+# and `MSignature`.
+#
+# `MClassType` and `MGenericType` both point to a `MClass` and have type `arguments`:
+#
+# * `(:MClassType)-[:CLASS]->(:MClass)`
+# * `(:MClassType)-[:ARGUMENT]->(:MType)`
+#
+# `MVirtualType` points to its introducing `MProperty`:
+#
+# * `(:MVirtualType)-[:PROPERTY]->(:MVirtualTypeDef)`
+#
+# `MParameterType` points to its introducing `MClass`:
+#
+# * `(:MParameterType)-[:CLASS]->(:MClass)`
+#
+# `MNullableType` points to its non-nullable `MType`:
+#
+# * `(:MNullableType)-[:TYPE]->(:MType)`
+#
+# `MSignature` can have `parameters` and a `return_mtype`:
+#
+# * `(:MSignature)-[:PARAMETER]->(:MParameter)`
+# * `(:MSignature)-[:RETURNTYPE]->(:MType)`
+#
+# `MParameter`
+#
+# * labels: `model_name`, `MEntity`, `MParameter`
+# * `(:MParameter)-[:TYPE]->(:MType)`
+module neo
+
+import model
+import neo4j
+import toolcontext
+
+# Helper class that can save and load a `Model` into a Neo4j database.
+class NeoModel
+
+ # The model name.
+ #
+ # Because we use only one Neo4j instance to store all the models,
+ # we need to mark their appartenance to a particular model and avoid loading all models.
+ #
+ # The name is used as a Neo label on each created nodes and used to load nodes from base.
+ var model_name: String
+
+ # The toolcontext used to init the `NeoModel` tool.
+ var toolcontext: ToolContext
+
+ # The Neo4j `client` used to communicate with the Neo4j instance.
+ var client: Neo4jClient
+
+ # Fill `model` using base pointed by `client`.
+ fun load(model: Model): Model do
+ toolcontext.info("Locate all mentities...", 1)
+ var nodes = client.nodes_with_label(model_name)
+
+ toolcontext.info("Preload nodes...", 1)
+ pull_all_nodes(nodes)
+ toolcontext.info("Preload edges...", 1)
+ pull_all_edges(nodes)
+
+ toolcontext.info("Build model...", 1)
+ nodes = client.nodes_with_labels([model_name, "MProject"])
+ for node in nodes do to_mproject(model, node)
+ nodes = client.nodes_with_labels([model_name, "MGroup"])
+ for node in nodes do to_mgroup(model, node)
+ nodes = client.nodes_with_labels([model_name, "MModule"])
+ for node in nodes do to_mmodule(model, node)
+ nodes = client.nodes_with_labels([model_name, "MClass"])
+ for node in nodes do to_mclass(model, node)
+ nodes = client.nodes_with_labels([model_name, "MClassDef"])
+ for node in nodes do to_mclassdef(model, node)
+ nodes = client.nodes_with_labels([model_name, "MProperty"])
+ for node in nodes do to_mproperty(model, node)
+ nodes = client.nodes_with_labels([model_name, "MPropDef"])
+ for node in nodes do to_mpropdef(model, node)
+ return model
+ end
+
+ # Save `model` in the base pointed by `client`.
+ fun save(model: Model) do
+ var nodes = collect_model_nodes(model)
+ toolcontext.info("Save {nodes.length} nodes...", 1)
+ push_all(nodes)
+ var edges = collect_model_edges(model)
+ toolcontext.info("Save {edges.length} edges...", 1)
+ push_all(edges)
+ end
+
+ # Save `neo_entities` in base using batch mode.
+ private fun push_all(neo_entities: Collection[NeoEntity]) do
+ var batch = new NeoBatch(client)
+ var len = neo_entities.length
+ var sum = 0
+ var i = 1
+ for nentity in neo_entities do
+ batch.save_entity(nentity)
+ if i == batch_max_size then
+ do_batch(batch)
+ sum += batch_max_size
+ toolcontext.info(" {sum * 100 / len}% done", 1)
+ batch = new NeoBatch(client)
+ i = 1
+ else
+ i += 1
+ end
+ end
+ do_batch(batch)
+ end
+
+ # Load content for all `nodes` from base.
+ #
+ # Content corresponds to properties and labels that are loaded in batch mode.
+ private fun pull_all_nodes(nodes: Collection[NeoNode]) do
+ var batch = new NeoBatch(client)
+ var len = nodes.length
+ var sum = 0
+ var i = 1
+ for node in nodes do
+ batch.load_node(node)
+ if i == batch_max_size then
+ do_batch(batch)
+ sum += batch_max_size
+ toolcontext.info(" {sum * 100 / len}% done", 1)
+ batch = new NeoBatch(client)
+ i = 1
+ else
+ i += 1
+ end
+ end
+ do_batch(batch)
+ end
+
+ # Load all edges from base linked to `nodes`.
+ #
+ # Edges are loaded in batch mode.
+ private fun pull_all_edges(nodes: Collection[NeoNode]) do
+ var batch = new NeoBatch(client)
+ var len = nodes.length
+ var sum = 0
+ var i = 1
+ for node in nodes do
+ batch.load_node_edges(node)
+ if i == batch_max_size then
+ do_batch(batch)
+ sum += batch_max_size
+ toolcontext.info(" {sum * 100 / len}% done", 1)
+ batch = new NeoBatch(client)
+ i = 1
+ else
+ i += 1
+ end
+ end
+ do_batch(batch)
+ end
+
+ # How many operation can be executed in one batch?
+ private var batch_max_size = 1000
+
+ # Execute `batch` and check for errors.
+ #
+ # Abort if `batch.execute` returns errors.
+ private fun do_batch(batch: NeoBatch) do
+ var errors = batch.execute
+ if not errors.is_empty then
+ print errors
+ exit(1)
+ end
+ end
+
+ # Collect all nodes from the current `model`.
+ private fun collect_model_nodes(model: Model): Collection[NeoNode] do
+ for mproject in model.mprojects do
+ to_node(mproject)
+ for mgroup in mproject.mgroups do to_node(mgroup)
+ end
+ return nodes.values
+ end
+
+ # Collect all edges from the current `model`.
+ #
+ # Actually collect all out_edges from all nodes.
+ private fun collect_model_edges(model: Model): Collection[NeoEdge] do
+ var edges = new HashSet[NeoEdge]
+ for node in nodes.values do edges.add_all(node.out_edges)
+ return edges
+ end
+
+ # Mentities associated to nodes.
+ private var mentities = new HashMap[NeoNode, MEntity]
+
+ # Nodes associated with MEntities.
+ private var nodes = new HashMap[MEntity, NeoNode]
+
+ # Get the `NeoNode` associated with `mentity`.
+ # `mentities` are stored locally to avoid duplication.
+ fun to_node(mentity: MEntity): NeoNode do
+ if nodes.has_key(mentity) then return nodes[mentity]
+ if mentity isa MProject then return mproject_node(mentity)
+ if mentity isa MGroup then return mgroup_node(mentity)
+ if mentity isa MModule then return mmodule_node(mentity)
+ if mentity isa MClass then return mclass_node(mentity)
+ if mentity isa MClassDef then return mclassdef_node(mentity)
+ if mentity isa MProperty then return mproperty_node(mentity)
+ if mentity isa MPropDef then return mpropdef_node(mentity)
+ if mentity isa MType then return mtype_node(mentity)
+ if mentity isa MParameter then return mparameter_node(mentity)
+ abort
+ end
+
+ # Make a new `NeoNode` based on `mentity`.
+ private fun make_node(mentity: MEntity): NeoNode do
+ var node = new NeoNode
+ nodes[mentity] = node
+ node.labels.add "MEntity"
+ node.labels.add model_name
+ node["name"] = mentity.name
+ if mentity.mdoc != null then node["mdoc"] = new JsonArray.from(mentity.mdoc.content)
+ return node
+ end
+
+ # Build a `NeoNode` representing `mproject`.
+ private fun mproject_node(mproject: MProject): NeoNode do
+ var node = make_node(mproject)
+ node.labels.add "MProject"
+ var root = mproject.root
+ if root != null then
+ node.out_edges.add(new NeoEdge(node, "ROOT", to_node(root)))
+ end
+ return node
+ end
+
+ # Build a new `MProject` from a `node`.
+ #
+ # REQUIRE `node.labels.has("MProject")`
+ private fun to_mproject(model: Model, node: NeoNode): MProject do
+ if mentities.has_key(node) then return mentities[node].as(MProject)
+ assert node.labels.has("MProject")
+ var mproject = new MProject(node["name"].to_s, model)
+ mentities[node] = mproject
+ set_doc(node, mproject)
+ mproject.root = to_mgroup(model, node.out_nodes("ROOT").first)
+ return mproject
+ end
+
+ # Build a `NeoNode` representing `mgroup`.
+ private fun mgroup_node(mgroup: MGroup): NeoNode do
+ var node = make_node(mgroup)
+ node.labels.add "MGroup"
+ node["full_name"] = mgroup.full_name
+ var parent = mgroup.parent
+ node.out_edges.add(new NeoEdge(node, "PROJECT", to_node(mgroup.mproject)))
+ if parent != null then
+ node.out_edges.add(new NeoEdge(node, "PARENT", to_node(parent)))
+ end
+ for mmodule in mgroup.mmodules do
+ node.out_edges.add(new NeoEdge(node, "DECLARES", to_node(mmodule)))
+ end
+ for subgroup in mgroup.in_nesting.direct_smallers do
+ node.in_edges.add(new NeoEdge(node, "NESTS", to_node(subgroup)))
+ end
+ return node
+ end
+
+ # Build a new `MGroup` from a `node`.
+ #
+ # REQUIRE `node.labels.has("MGroup")`
+ private fun to_mgroup(model: Model, node: NeoNode): MGroup do
+ if mentities.has_key(node) then return mentities[node].as(MGroup)
+ assert node.labels.has("MGroup")
+ var mproject = to_mproject(model, node.out_nodes("PROJECT").first)
+ var parent: nullable MGroup = null
+ var out = node.out_nodes("PARENT")
+ if not out.is_empty then
+ parent = to_mgroup(model, out.first)
+ end
+ var mgroup = new MGroup(node["name"].to_s, mproject, parent)
+ mentities[node] = mgroup
+ set_doc(node, mgroup)
+ return mgroup
+ end
+
+ # Build a `NeoNode` representing `mmodule`.
+ private fun mmodule_node(mmodule: MModule): NeoNode do
+ var node = make_node(mmodule)
+ node.labels.add "MModule"
+ node["full_name"] = mmodule.full_name
+ node["location"] = mmodule.location.to_s
+ var mgroup = mmodule.mgroup
+ for parent in mmodule.in_importation.direct_greaters do
+ node.out_edges.add(new NeoEdge(node, "IMPORTS", to_node(parent)))
+ end
+ for mclass in mmodule.intro_mclasses do
+ node.out_edges.add(new NeoEdge(node, "INTRODUCES", to_node(mclass)))
+ end
+ for mclassdef in mmodule.mclassdefs do
+ node.out_edges.add(new NeoEdge(node, "DEFINES", to_node(mclassdef)))
+ end
+ return node
+ end
+
+ # Build a new `MModule` from a `node`.
+ #
+ # REQUIRE `node.labels.has("MModule")`
+ private fun to_mmodule(model: Model, node: NeoNode): MModule do
+ if mentities.has_key(node) then return mentities[node].as(MModule)
+ assert node.labels.has("MModule")
+ var ins = node.in_nodes("DECLARES")
+ var mgroup: nullable MGroup = null
+ if not ins.is_empty then
+ mgroup = to_mgroup(model, ins.first)
+ end
+ var name = node["name"].to_s
+ var location = to_location(node["location"].to_s)
+ var mmodule = new MModule(model, mgroup, name, location)
+ mentities[node] = mmodule
+ set_doc(node, mmodule)
+ var imported_mmodules = new Array[MModule]
+ for smod in node.out_nodes("IMPORTS") do
+ imported_mmodules.add to_mmodule(model, smod)
+ end
+ mmodule.set_imported_mmodules(imported_mmodules)
+ return mmodule
+ end
+
+ # Build a `NeoNode` representing `mclass`.
+ private fun mclass_node(mclass: MClass): NeoNode do
+ var node = make_node(mclass)
+ node.labels.add "MClass"
+ node["arity"] = mclass.arity
+ node["full_name"] = mclass.full_name
+ node["kind"] = mclass.kind.to_s
+ node["visibility"] = mclass.visibility.to_s
+ node.out_edges.add(new NeoEdge(node, "CLASSTYPE", to_node(mclass.mclass_type)))
+ return node
+ end
+
+ # Build a new `MClass` from a `node`.
+ #
+ # REQUIRE `node.labels.has("MClass")`
+ private fun to_mclass(model: Model, node: NeoNode): MClass do
+ if mentities.has_key(node) then return mentities[node].as(MClass)
+ assert node.labels.has("MClass")
+ var mmodule = to_mmodule(model, node.in_nodes("INTRODUCES").first)
+ var name = node["name"].to_s
+ var arity = node["arity"].to_s.to_i
+ var kind = to_kind(node["kind"].to_s)
+ var visibility = to_visibility(node["visibility"].to_s)
+ var mclass = new MClass(mmodule, name, arity, kind, visibility)
+ mentities[node] = mclass
+ set_doc(node, mclass)
+ return mclass
+ end
+
+ # Build a `NeoNode` representing `mclassdef`.
+ private fun mclassdef_node(mclassdef: MClassDef): NeoNode do
+ var node = make_node(mclassdef)
+ node.labels.add "MClassDef"
+ node["is_intro"] = mclassdef.is_intro
+ node["location"] = mclassdef.location.to_s
+ if not mclassdef.parameter_names.is_empty then
+ node["parameter_names"] = new JsonArray.from(mclassdef.parameter_names)
+ end
+ node.out_edges.add(new NeoEdge(node, "BOUNDTYPE", to_node(mclassdef.bound_mtype)))
+ node.out_edges.add(new NeoEdge(node, "MCLASS", to_node(mclassdef.mclass)))
+ for mproperty in mclassdef.intro_mproperties do
+ node.out_edges.add(new NeoEdge(node, "INTRODUCES", to_node(mproperty)))
+ end
+ for mpropdef in mclassdef.mpropdefs do
+ node.out_edges.add(new NeoEdge(node, "DECLARES", to_node(mpropdef)))
+ end
+ for sup in mclassdef.supertypes do
+ node.out_edges.add(new NeoEdge(node, "INHERITS", to_node(sup)))
+ end
+ return node
+ end
+
+ # Build a new `MClassDef` from a `node`.
+ #
+ # REQUIRE `node.labels.has("MClassDef")`
+ private fun to_mclassdef(model: Model, node: NeoNode): MClassDef do
+ if mentities.has_key(node) then return mentities[node].as(MClassDef)
+ assert node.labels.has("MClassDef")
+ var mmodule = to_mmodule(model, node.in_nodes("DEFINES").first)
+ var mtype = to_mtype(model, node.out_nodes("BOUNDTYPE").first).as(MClassType)
+ var location = to_location(node["location"].to_s)
+ var parameter_names = new Array[String]
+ if node.has_key("parameter_names") then
+ for e in node["parameter_names"].as(JsonArray) do
+ parameter_names.add e.to_s
+ end
+ end
+ var mclassdef = new MClassDef(mmodule, mtype, location, parameter_names)
+ mentities[node] = mclassdef
+ set_doc(node, mclassdef)
+ var supertypes = new Array[MClassType]
+ for sup in node.out_nodes("INHERITS") do
+ supertypes.add to_mtype(model, sup).as(MClassType)
+ end
+ mclassdef.set_supertypes(supertypes)
+ mclassdef.add_in_hierarchy
+ return mclassdef
+ end
+
+ # Build a `NeoNode` representing `mproperty`.
+ private fun mproperty_node(mproperty: MProperty): NeoNode do
+ var node = make_node(mproperty)
+ node.labels.add "MProperty"
+ node["full_name"] = mproperty.full_name
+ node["visibility"] = mproperty.visibility.to_s
+ if mproperty isa MMethod then
+ node.labels.add "MMethod"
+ node["is_init"] = mproperty.is_init
+ else if mproperty isa MAttribute then
+ node.labels.add "MAttribute"
+ else if mproperty isa MVirtualTypeProp then
+ node.labels.add "MVirtualTypeProp"
+ end
+ node.out_edges.add(new NeoEdge(node, "INTRO_CLASSDEF", to_node(mproperty.intro_mclassdef)))
+ return node
+ end
+
+ # Build a new `MProperty` from a `node`.
+ #
+ # REQUIRE `node.labels.has("MProperty")`
+ private fun to_mproperty(model: Model, node: NeoNode): MProperty do
+ if mentities.has_key(node) then return mentities[node].as(MProperty)
+ assert node.labels.has("MProperty")
+ var intro_mclassdef = to_mclassdef(model, node.out_nodes("INTRO_CLASSDEF").first)
+ var name = node["name"].to_s
+ var visibility = to_visibility(node["visibility"].to_s)
+ var mprop: nullable MProperty = null
+ if node.labels.has("MMethod") then
+ mprop = new MMethod(intro_mclassdef, name, visibility)
+ mprop.is_init = node["is_init"].as(Bool)
+ else if node.labels.has("MAttribute") then
+ mprop = new MAttribute(intro_mclassdef, name, visibility)
+ else if node.labels.has("MVirtualTypeProp") then
+ mprop = new MVirtualTypeProp(intro_mclassdef, name, visibility)
+ end
+ if mprop == null then
+ print "not yet implemented to_mproperty for {node.labels.join(",")}"
+ abort
+ end
+ mentities[node] = mprop
+ set_doc(node, mprop)
+ for npropdef in node.in_nodes("DEFINES") do
+ var mpropdef = to_mpropdef(model, npropdef)
+ if npropdef["is_intro"].as(Bool) then
+ mprop.mpropdefs.unshift mpropdef
+ else
+ mprop.mpropdefs.add mpropdef
+ end
+ end
+ return mprop
+ end
+
+ # Build a `NeoNode` representing `mpropdef`.
+ private fun mpropdef_node(mpropdef: MPropDef): NeoNode do
+ var node = make_node(mpropdef)
+ node.labels.add "MPropDef"
+ node["is_intro"] = mpropdef.is_intro
+ node["location"] = mpropdef.location.to_s
+ node.out_edges.add(new NeoEdge(node, "DEFINES", to_node(mpropdef.mproperty)))
+ if mpropdef isa MMethodDef then
+ node.labels.add "MMethodDef"
+ node["is_abstract"] = mpropdef.is_abstract
+ node["is_intern"] = mpropdef.is_intern
+ node["is_extern"] = mpropdef.is_extern
+ var msignature = mpropdef.msignature
+ if msignature != null then
+ node.out_edges.add(new NeoEdge(node, "SIGNATURE", to_node(msignature)))
+ end
+ else if mpropdef isa MAttributeDef then
+ node.labels.add "MAttributeDef"
+ else if mpropdef isa MVirtualTypeDef then
+ node.labels.add "MVirtualTypeDef"
+ var bound = mpropdef.bound
+ if bound != null then
+ node.out_edges.add(new NeoEdge(node, "BOUND", to_node(bound)))
+ end
+ end
+ return node
+ end
+
+ # Build a new `MPropDef` from a `node`.
+ #
+ # REQUIRE `node.labels.has("MPropDef")`
+ private fun to_mpropdef(model: Model, node: NeoNode): MPropDef do
+ if mentities.has_key(node) then return mentities[node].as(MPropDef)
+ assert node.labels.has("MPropDef")
+ var mclassdef = to_mclassdef(model, node.in_nodes("DECLARES").first)
+ var mproperty = to_mproperty(model, node.out_nodes("DEFINES").first)
+ var location = to_location(node["location"].to_s)
+ var mpropdef: nullable MPropDef = null
+ if node.labels.has("MMethodDef") then
+ mpropdef = new MMethodDef(mclassdef, mproperty.as(MMethod), location)
+ mpropdef.is_abstract = node["is_abstract"].as(Bool)
+ mpropdef.is_intern = node["is_intern"].as(Bool)
+ mpropdef.is_extern = node["is_extern"].as(Bool)
+ mentities[node] = mpropdef
+ mpropdef.msignature = to_mtype(model, node.out_nodes("SIGNATURE").first).as(MSignature)
+ else if node.labels.has("MAttributeDef") then
+ mpropdef = new MAttributeDef(mclassdef, mproperty.as(MAttribute), location)
+ mentities[node] = mpropdef
+ else if node.labels.has("MVirtualTypeDef") then
+ mpropdef = new MVirtualTypeDef(mclassdef, mproperty.as(MVirtualTypeProp), location)
+ mentities[node] = mpropdef
+ var bound = node.out_nodes("BOUND")
+ if not bound.is_empty then mpropdef.bound = to_mtype(model, bound.first)
+ end
+ if mpropdef == null then
+ print "not yet implemented to_mpropdef for {node.labels.join(",")}"
+ abort
+ end
+ set_doc(node, mpropdef)
+ return mpropdef
+ end
+
+ # Build a `NeoNode` representing `mtype`.
+ private fun mtype_node(mtype: MType): NeoNode do
+ var node = make_node(mtype)
+ node.labels.add "MType"
+ if mtype isa MClassType then
+ node.labels.add "MClassType"
+ node.out_edges.add(new NeoEdge(node, "CLASS", to_node(mtype.mclass)))
+ for arg in mtype.arguments do
+ node.out_edges.add(new NeoEdge(node, "ARGUMENT", to_node(arg)))
+ end
+ if mtype isa MGenericType then
+ node.labels.add "MGenericType"
+ end
+ else if mtype isa MVirtualType then
+ node.labels.add "MVirtualType"
+ node.out_edges.add(new NeoEdge(node, "PROPERTY", to_node(mtype.mproperty)))
+ else if mtype isa MParameterType then
+ node.labels.add "MParameterType"
+ node["rank"] = mtype.rank
+ node.out_edges.add(new NeoEdge(node, "CLASS", to_node(mtype.mclass)))
+ else if mtype isa MNullableType then
+ node.labels.add "MNullableType"
+ node.out_edges.add(new NeoEdge(node, "TYPE", to_node(mtype.mtype)))
+ else if mtype isa MSignature then
+ node.labels.add "MSignature"
+ for mparameter in mtype.mparameters do
+ node.out_edges.add(new NeoEdge(node, "PARAMETER", to_node(mparameter)))
+ end
+ var return_mtype = mtype.return_mtype
+ if return_mtype != null then
+ node.out_edges.add(new NeoEdge(node, "RETURNTYPE", to_node(return_mtype)))
+ end
+ end
+ return node
+ end
+
+ # Build a new `MType` from a `node`.
+ #
+ # REQUIRE `node.labels.has("MType")`
+ private fun to_mtype(model: Model, node: NeoNode): MType do
+ if mentities.has_key(node) then return mentities[node].as(MType)
+ assert node.labels.has("MType")
+ if node.labels.has("MClassType") then
+ var mclass = to_mclass(model, node.out_nodes("CLASS").first)
+ var args = new Array[MType]
+ for narg in node.out_nodes("ARGUMENT") do
+ args.add to_mtype(model, narg)
+ end
+ var mtype = mclass.get_mtype(args)
+ mentities[node] = mtype
+ return mtype
+ else if node.labels.has("MParameterType") then
+ var mclass = to_mclass(model, node.out_nodes("CLASS").first)
+ var rank = node["rank"].to_s.to_i
+ var mtype = new MParameterType(mclass, rank)
+ mentities[node] = mtype
+ return mtype
+ else if node.labels.has("MNullableType") then
+ var intype = to_mtype(model, node.out_nodes("TYPE").first)
+ var mtype = new MNullableType(intype)
+ mentities[node] = mtype
+ return mtype
+ else if node.labels.has("MVirtualType") then
+ var mproperty = to_mproperty(model, node.out_nodes("PROPERTY").first)
+ var mtype = new MVirtualType(mproperty)
+ mentities[node] = mtype
+ return mtype
+ else if node.labels.has("MSignature") then
+ var mparameters = new Array[MParameter]
+ for pnode in node.out_nodes("PARAMETER") do
+ mparameters.add to_mparameter(model, pnode)
+ end
+ var return_mtype: nullable MType = null
+ var ret_nodes = node.out_nodes("RETURNTYPE")
+ if not ret_nodes.is_empty then
+ return_mtype = to_mtype(model, ret_nodes.first)
+ end
+ var mtype = new MSignature(mparameters, return_mtype)
+ mentities[node] = mtype
+ return mtype
+ end
+ print "not yet implemented to_mtype for {node.labels.join(",")}"
+ abort
+ end
+
+ # Build a `NeoNode` representing `mparameter`.
+ private fun mparameter_node(mparameter: MParameter): NeoNode do
+ var node = make_node(mparameter)
+ node.labels.add "MParameter"
+ node["name"] = mparameter.name
+ node["is_vararg"] = mparameter.is_vararg
+ node.out_edges.add(new NeoEdge(node, "TYPE", to_node(mparameter.mtype)))
+ return node
+ end
+
+ # Build a new `MParameter` from `node`.
+ #
+ # REQUIRE `node.labels.has("MParameter")`
+ private fun to_mparameter(model: Model, node: NeoNode): MParameter do
+ if mentities.has_key(node) then return mentities[node].as(MParameter)
+ assert node.labels.has("MParameter")
+ var name = node["name"].to_s
+ var mtype = to_mtype(model, node.out_nodes("TYPE").first)
+ var is_vararg = node["is_vararg"].as(Bool)
+ var mparameter = new MParameter(name, mtype, is_vararg)
+ mentities[node] = mparameter
+ return mparameter
+ end
+
+ # Get a `Location` from its string representation.
+ private fun to_location(loc: String): Location do
+ #TODO filepath
+ var parts = loc.split_with(":")
+ var file = new SourceFile.from_string(parts[0], "")
+ var pos = parts[1].split_with("--")
+ var pos1 = pos[0].split_with(",")
+ var pos2 = pos[1].split_with(",")
+ var line_s = pos1[0].to_i
+ var line_e = pos2[0].to_i
+ var column_s = pos1[1].to_i
+ var column_e = 0
+ if pos2.length == 2 then pos2[1].to_i
+ return new Location(file, line_s, line_e, column_s, column_e)
+ end
+
+ # Get a `MVisibility` from its string representation.
+ private fun to_visibility(vis: String): MVisibility do
+ if vis == intrude_visibility.to_s then
+ return intrude_visibility
+ else if vis == public_visibility.to_s then
+ return public_visibility
+ else if vis == protected_visibility.to_s then
+ return protected_visibility
+ else if vis == private_visibility.to_s then
+ return private_visibility
+ else
+ return none_visibility
+ end
+ end
+
+ # Get a `MKind` from its string representation.
+ private fun to_kind(kind: String): MClassKind do
+ if kind == abstract_kind.to_s then
+ return abstract_kind
+ else if kind == concrete_kind.to_s then
+ return concrete_kind
+ else if kind == interface_kind.to_s then
+ return interface_kind
+ else if kind == enum_kind.to_s then
+ return enum_kind
+ else if kind == extern_kind.to_s then
+ return extern_kind
+ end
+ abort
+ end
+
+ # Extract the `MDoc` from `node` and link it to `mentity`.
+ private fun set_doc(node: NeoNode, mentity: MEntity) do
+ if node.has_key("mdoc") then
+ var lines = new Array[String]
+ for e in node["mdoc"].as(JsonArray) do
+ lines.add e.to_s#.replace("\n", "\\n")
+ end
+ var mdoc = new MDoc
+ mdoc.content.add_all(lines)
+ mdoc.original_mentity = mentity
+ mentity.mdoc = mdoc
+ end
+ end
+end
# Create a tool context to handle options and paths
var toolcontext = new ToolContext
-toolcontext.tooldescription = "Usage: nitmetrics [OPTION]... <file.nit>...\mComputes various metrics on Nit programs."
+toolcontext.tooldescription = "Usage: nitmetrics [OPTION]... <file.nit>...\nComputes various metrics on Nit programs."
# We do not add other options, so process them now!
toolcontext.process_options(args)
if name == "Bool" then return "int"
if name == "Char" then return "char"
if name == "Float" then return "double"
- if name == "Int" then return "int"
+ if name == "Int" then return "long"
if name == "NativeString" then return "char*"
if mclass.kind == extern_kind then
var ctype = mclass.ctype
if name == "Bool" then return "int"
if name == "Char" then return "char"
if name == "Float" then return "double"
- if name == "Int" then return "int"
+ if name == "Int" then return "long"
if name == "NativeString" then return "char*"
if mclass.kind == extern_kind then return "void*"
return "struct nitni_instance *"
return nexpr
end
+ # Parse a super class declaration
+ # Fatal error if the `string` is not a syntactically correct super class declaration
+ fun parse_superclass(string: String): ASuperclass
+ do
+ var mod_string = "class Dummy\nsuper {string}\nend"
+ var nclassdef = parse_classdef(mod_string).as(AStdClassdef)
+ var nsuperclasses = nclassdef.n_superclasses
+ if nsuperclasses.length != 1 then
+ self.fatal_error(null, "Fatal Error: not a super class declaration")
+ abort
+ end
+ return nsuperclasses.first
+ end
+
# Try to parse the `string` as something
#
# Returns the first possible syntacticaly correct type among:
import phase
import parser_util
+import modelize_property
+intrude import modelize_class
redef class ToolContext
- var serialization_phase: Phase = new SerializationPhase(self, null)
+ var serialization_phase_pre_model: Phase = new SerializationPhasePreModel(self, null)
+ var serialization_phase_post_model: Phase = new SerializationPhasePostModel(self,
+ [modelize_class_phase, serialization_phase_pre_model])
+
+ private fun place_holder_type_name: String do return "PlaceHolderTypeWhichShouldNotExist"
end
-# TODO automaticaly add Serializable as a super class
-# TODO Sequences
# TODO add annotations on attributes (volatile, sensitive or do_not_serialize?)
-private class SerializationPhase
+private class SerializationPhasePreModel
super Phase
redef fun process_annotated_node(nclassdef, nat)
return
end
+ # Add `super Serializable`
+ var sc = toolcontext.parse_superclass("Serializable")
+ sc.location = nat.location
+ nclassdef.n_superclasses.add sc
+
generate_serialization_method(nclassdef)
generate_deserialization_init(nclassdef)
redef fun process_nmodule(nmodule)
do
+ # Clear the cache of constructors to review before adding to it
+ nmodule.inits_to_retype.clear
+
# collect all classes
var auto_serializable_nclassdefs = new Array[AStdClassdef]
for nclassdef in nmodule.n_classdefs do
code.add " v.notify_of_creation self"
for attribute in npropdefs do if attribute isa AAttrPropdef then
- if attribute.n_type == null then
- toolcontext.error(attribute.location, "NOT YET IMPLEMENTED: all attributes of an auto_serialized class definition must define a type.")
- continue
+ var n_type = attribute.n_type
+ var type_name
+ if n_type == null then
+ # Use a place holder, we will replace it with the infered type after the model phases
+ type_name = toolcontext.place_holder_type_name
+ else
+ type_name = n_type.type_name
end
var name = attribute.name
- var type_name = attribute.type_name
+
code.add ""
code.add "\tvar {name} = v.deserialize_attribute(\"{name}\")"
- code.add "\tassert {name} isa {type_name} else print \"Expected attribute '{name}' to be of type '{type_name}'\""
+ code.add "\tassert {name} isa {type_name} else print \"Unsupported type for attribute '{name}', got '\{{name}.class_name\}' (ex {type_name})\""
code.add "\tself.{name} = {name}"
end
code.add "end"
- npropdefs.add(toolcontext.parse_propdef(code.join("\n")))
+
+ var npropdef = toolcontext.parse_propdef(code.join("\n")).as(AConcreteInitPropdef)
+ npropdefs.add npropdef
+ nclassdef.parent.as(AModule).inits_to_retype.add npropdef
end
# Added to the abstract serialization service
code.add " redef fun deserialize_class(name)"
code.add " do"
else
- toolcontext.error(deserializer_npropdef.location, "Annotation error: you cannont define Deserializer::deserialize_class in a module where you use \"auto_serializable\".")
+ toolcontext.error(deserializer_npropdef.location, "Annotation error: you cannot define Deserializer::deserialize_class in a module where you use \"auto_serializable\".")
return
end
for nclassdef in nclassdefs do
var name = nclassdef.n_id.text
- if not name.chars.has('[') then # FIXME this is a temporary hack
+ if nclassdef.n_formaldefs.is_empty then
code.add " if name == \"{name}\" then return new {name}.from_deserializer(self)"
end
end
end
end
+private class SerializationPhasePostModel
+ super Phase
+
+ redef fun process_nmodule(nmodule)
+ do
+ for npropdef in nmodule.inits_to_retype do
+ var v = new PreciseTypeVisitor(npropdef, npropdef.mpropdef.mclassdef, toolcontext)
+ npropdef.accept_precise_type_visitor v
+ end
+ end
+end
+
+# Visitor on generated constructors to replace the expected type of deserialized attributes
+private class PreciseTypeVisitor
+ super Visitor
+
+ var npropdef: AConcreteInitPropdef
+ var mclassdef: MClassDef
+ var toolcontext: ToolContext
+
+ init(npropdef: AConcreteInitPropdef, mclassdef: MClassDef, toolcontext: ToolContext)
+ do
+ self.npropdef = npropdef
+ self.mclassdef = mclassdef
+ self.toolcontext = toolcontext
+ end
+
+ redef fun visit(n) do n.accept_precise_type_visitor(self)
+end
+
+redef class ANode
+ private fun accept_precise_type_visitor(v: PreciseTypeVisitor) do visit_all(v)
+end
+
+redef class AIsaExpr
+ redef fun accept_precise_type_visitor(v)
+ do
+ if n_type.collect_text != v.toolcontext.place_holder_type_name then return
+
+ var attr_name = "_" + n_expr.collect_text
+ for mattrdef in v.mclassdef.mpropdefs do
+ if mattrdef isa MAttributeDef and mattrdef.name == attr_name then
+ var new_ntype = v.toolcontext.parse_something(mattrdef.static_mtype.to_s)
+ n_type.replace_with new_ntype
+ break
+ end
+ end
+ end
+end
+
redef class AAttrPropdef
private fun name: String
do
if n_id == null then return n_id2.text
return n_id.text
end
+end
+redef class AType
private fun type_name: String
do
- var name = n_type.n_id.text
+ var name = n_id.text
- if n_type.n_kwnullable != null then name = "nullable {name}"
+ if n_kwnullable != null then name = "nullable {name}"
- var types = n_type.n_types
+ var types = n_types
if not types.is_empty then
var params = new Array[String]
- for t in types do params.add(t.n_id.text)
+ for t in types do params.add(t.type_name)
return "{name}[{params.join(", ")}]"
else return name
end
return null
end
+
+ private var inits_to_retype = new Array[AConcreteInitPropdef]
end
redef class AStdClassdef
--- /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.
+
+# Test for neo model saving and loading.
+module test_neo
+
+import neo
+import model_utils
+import frontend
+
+var test_name = "test_{get_time.to_s}"
+
+# init tool
+var toolcontext = new ToolContext
+toolcontext.tooldescription = "Usage: neo_saver host port files..."
+toolcontext.process_options(args)
+var arguments = toolcontext.option_context.rest
+
+if arguments.length < 3 then
+ toolcontext.usage
+ exit 0
+end
+
+var host = arguments.shift
+var port = arguments.shift
+var url = "http://{host}:{port}"
+
+# parse model
+toolcontext.info("Parse files...", 1)
+var org_model = new Model
+var modelbuilder = new ModelBuilder(org_model, toolcontext)
+modelbuilder.parse(arguments)
+modelbuilder.run_phases
+
+toolcontext.info("Open connection to neo4j on {url} for saving...", 1)
+var save_client = new Neo4jClient(url)
+var save_model = new NeoModel(test_name, toolcontext, save_client)
+save_model.save(org_model)
+
+toolcontext.info("Open connection to neo4j on {url} for reading...", 1)
+var read_client = new Neo4jClient(url)
+var neo_model = new Model
+var read_model = new NeoModel(test_name, toolcontext, read_client)
+read_model.load(neo_model)
+
+# Compare model
+var sorter = new MEntityNameSorter
+
+print "mprojects:"
+var org_mprojects = org_model.mprojects.to_a
+sorter.sort org_mprojects
+print org_mprojects.join(" ")
+var neo_mprojects = neo_model.mprojects.to_a
+sorter.sort neo_mprojects
+print neo_mprojects.join(" ")
+
+print "mmodules:"
+var org_mmodules = org_model.mmodules.to_a
+sorter.sort org_mmodules
+print org_mmodules.join(" ")
+var neo_mmodules = neo_model.mmodules.to_a
+sorter.sort neo_mmodules
+print neo_mmodules.join(" ")
+
+print "mclasses:"
+var org_mclasses = org_model.mclasses.to_a
+sorter.sort org_mclasses
+print org_mclasses.join(" ")
+var neo_mclasses = neo_model.mclasses.to_a
+sorter.sort neo_mclasses
+print neo_mclasses.join(" ")
+
+print "mproperties:"
+var org_mproperties = org_model.mproperties.to_a
+sorter.sort org_mproperties
+print org_mproperties.join(" ")
+var neo_mproperties = neo_model.mproperties.to_a
+sorter.sort neo_mproperties
+print neo_mproperties.join(" ")
--- /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 Foo
+ var a1: Object = fa1 is lazy
+ var a2: Object = fa2 is lazy
+ fun fa1: Object do
+ 1.output
+ return 10
+ end
+ fun fa2: Object do
+ 2.output
+ return 20
+ end
+ #alt1#var a3: Object is lazy
+end
+
+var f = new Foo
+f.a1.output
+f.a1.output
+f.a2.output
+f.a2.output
+'\n'.output
+
+var g = new Foo
+g.a2.output
+g.a1.output
+g.a2.output
+g.a1.output
+'\n'.output
+
+var h = new Foo
+h.a1 = 100
+h.a1.output
+h.a1.output
--- /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 Foo
+ var a1: Int = fa1 is lazy
+ var a2: Int = fa2 is lazy
+ fun fa1: Int do
+ 1.output
+ return 10
+ end
+ fun fa2: Int do
+ 2.output
+ return 20
+ end
+end
+
+var f = new Foo
+f.a1.output
+f.a1.output
+f.a2.output
+f.a2.output
+'\n'.output
+
+var g = new Foo
+g.a2.output
+g.a1.output
+g.a2.output
+g.a1.output
+'\n'.output
+
+var h = new Foo
+h.a1 = 100
+h.a1.output
+h.a1.output
--- /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 Foo
+ var a1: nullable Object = fa1 is lazy
+ var a2: nullable Object = fa2 is lazy
+ fun fa1: nullable Object do
+ 1.output
+ return 10
+ end
+ fun fa2: nullable Object do
+ 2.output
+ return 20
+ end
+end
+
+fun o(o: nullable Object)
+do
+ if o == null then
+ 'n'.output
+ '\n'.output
+ else
+ o.output
+ end
+end
+
+var f = new Foo
+o f.a1
+o f.a1
+o f.a2
+o f.a2
+'\n'.output
+
+var g = new Foo
+o g.a2
+o g.a1
+o g.a2
+o g.a1
+'\n'.output
+
+var h = new Foo
+h.a1 = 100
+h.a1.output
+h.a1.output
--- /dev/null
+1
+10
+10
+2
+20
+20
+
+2
+20
+1
+10
+20
+10
+
+100
+100
--- /dev/null
+alt/base_attr_lazy_alt1.nit:28,20--23: Error: a lazy attribute needs a value
--- /dev/null
+1
+10
+10
+2
+20
+20
+
+2
+20
+1
+10
+20
+10
+
+100
+100
--- /dev/null
+1
+10
+10
+2
+20
+20
+
+2
+20
+1
+10
+20
+10
+
+100
+100
--- /dev/null
+Not executable (platform?)
-Usage: nitmetrics [OPTION]... <file.nit>...mComputes various metrics on Nit programs.
+Usage: nitmetrics [OPTION]... <file.nit>...
+Computes various metrics on Nit programs.
Use --help for help
--- /dev/null
+Usage: neo_saver host port files...
+Use --help for help
--- /dev/null
+mprojects:
+test_prog
+test_prog
+mmodules:
+careers character combat game platform races rpg test_prog
+careers character combat game platform races rpg test_prog
+mclasses:
+Alcoholic Bool Career Character Combatable Dwarf Elf Float Game Human Int List Magician Object Race Starter String Sys Warrior Weapon
+Alcoholic Bool Career Character Combatable Dwarf Elf Float Game Human Int List Magician Object Race Starter String Sys Warrior Weapon
+mproperties:
+!= * * + + - - / / == > > OTHER _age _base_endurance _base_intelligence _base_strength _career _endurance_bonus _health _intelligence_bonus _name _race _sex _strength_bonus age age= attack base_endurance base_endurance= base_intelligence base_intelligence= base_strength base_strength= career career= computer_characters defend direct_attack dps endurance_bonus endurance_bonus= health health= hit_points init init init init init init init init init init intelligence_bonus intelligence_bonus= is_dead main max_health name name= pause_game player_characters quit race race= sex sex= start start_game stop_game strength_bonus strength_bonus= to_f total_endurance total_intelligence total_strengh unary -
+!= * * + + - - / / == > > OTHER _age _base_endurance _base_intelligence _base_strength _career _endurance_bonus _health _intelligence_bonus _name _race _sex _strength_bonus age age= attack base_endurance base_endurance= base_intelligence base_intelligence= base_strength base_strength= career career= computer_characters defend direct_attack dps endurance_bonus endurance_bonus= health health= hit_points init init init init init init init init init init intelligence_bonus intelligence_bonus= is_dead main max_health name name= pause_game player_characters quit race race= sex sex= start start_game stop_game strength_bonus strength_bonus= to_f total_endurance total_intelligence total_strengh unary -
# Simple class
class A
auto_serializable
- super Serializable
- var b: Bool
+ var b = false
var c: Char
var f: Float
- var i: Int
- var s: String
+ var i = 123
+ var s = "asdf"
var n: nullable Int
init(b: Bool, c: Char, f: Float, i: Int, s: String, n: nullable Int)
# Composed of an A and a B
class C
auto_serializable
- super Serializable
var a: A
- var b: B
+ var b = new B(false, 'b', 123.123, 2345, "hjkl", 12, 1111, "qwer")
var aa: A
init(a: A, b: B)
redef fun output in "Java" `{
for (Object i: recv) {
- System.out.println((int)i);
+ System.out.println((long)i);
}
`}
--- /dev/null
+localhost 7474 test_prog/test_prog.nit
--- /dev/null
+Test program for model tools.
+
+This program creates a fake model that can be used to test tools like:
+
+* `nitdoc`
+* `nitmetrics`
+* `nitx`
+* or others `modelbuilder`.
+
--- /dev/null
+Gaming group
+
--- /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 game abstraction for RPG.
+module game
+
+import rpg
+
+# This is the interface you have to implement to use ure gaming platform.
+#
+# see http://our.platform.com
+interface Game
+
+ # Characters played by human players.
+ fun player_characters: List[Character] is abstract
+
+ # Characters players by computer.
+ fun computer_characters: List[Character] is abstract
+
+ # Start the game.
+ #
+ # You have to implement that method!
+ fun start_game is abstract
+
+ # Pause the game.
+ #
+ # You have to implement that method!
+ fun pause_game is abstract
+
+ # Stop the game.
+ #
+ # You have to implement that method!
+ fun stop_game is abstract
+end
+
--- /dev/null
+Fictive Crappy Platform.
+
--- /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.
+
+# Declares base types allowed on the platform.
+module platform
+
+import end
+
+# Root of everything.
+class Object
+ # Used for comparisons.
+ type OTHER: nullable Object
+
+ # Is `other` equqls to `self`?
+ fun ==(other: OTHER): Bool is intern
+
+ # Is `other` different from `self`?
+ fun !=(other: OTHER): Bool do return not self == other
+end
+
+# Some services about Integers.
+class Int
+ fun -: Int is intern
+ fun +(i: Int): Int is intern
+ fun -(i: Int): Int is intern
+ fun *(i: Int): Int is intern
+ fun /(i: Int): Int is intern
+ fun >(i: Int): Bool is intern
+ fun to_f: Float is intern
+end
+
+# Some services about Floats.
+class Float
+ fun +(f: Float): Float is intern
+ fun -(f: Float): Float is intern
+ fun *(f: Float): Float is intern
+ fun /(f: Float): Float is intern
+ fun >(f: Float): Bool is intern
+end
+
+# Booleans, `true` or `false`.
+class Bool end
+
+# Strings (there is no chars...).
+class String end
+
+# List of things.
+class List[E] end
--- /dev/null
+Role Playing Game group
+
--- /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.
+
+# Careers of the game.
+#
+# All characters can have a `Career`.
+# A character can also quit its current career and start a new one.
+#
+# Available careers:
+#
+# * `Warrior`
+# * `Magician`
+# * `Alcoholic`
+module careers
+
+import platform
+
+# A `Career` gives a characteristic bonus or malus to the character.
+abstract class Career
+ var strength_bonus: Int
+ var endurance_bonus: Int
+ var intelligence_bonus: Int
+
+ init do end
+end
+
+# Warriors are good for fighting.
+class Warrior
+ super Career
+
+ init do
+ self.strength_bonus = 10
+ self.endurance_bonus = 10
+ self.intelligence_bonus = 0
+ end
+end
+
+# Magicians know magic and how to use it.
+class Magician
+ super Career
+
+ init do
+ self.strength_bonus = -5
+ self.endurance_bonus = 0
+ self.intelligence_bonus = 20
+ end
+end
+
+# Alcoholics are good to nothing escept taking punches.
+class Alcoholic
+ super Career
+
+ init do
+ self.strength_bonus = -20
+ self.endurance_bonus = 20
+ self.intelligence_bonus = -40
+ 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.
+
+# Characters are playable entity in the world.
+module character
+
+import races
+import careers
+
+# Characters can be played by both the human or the machine.
+class Character
+
+ # The `Race` of the character.
+ var race: Race
+
+ # The current `Career` of the character.
+ # Returns `null` if character is unemployed.
+ var career: nullable Career writable = null
+
+ fun quit do
+ career = null
+ end
+
+ var name: String
+ var age: Int
+ var sex: Bool
+
+ # The actual strength of the character.
+ #
+ # Returns `race.base_strength + career.strength_bonus` or just `race.base_strength` is unemployed.
+ fun total_strengh: Int do
+ if career != null then return race.base_strength + career.strength_bonus
+ return race.base_strength
+ end
+
+ # The actual endurance of the character.
+ fun total_endurance: Int do
+ if career != null then return race.base_endurance + career.endurance_bonus
+ return race.base_endurance
+ end
+
+ # The acutal intelligence of the character.
+ fun total_intelligence: Int do
+ if career != null then return race.base_intelligence + career.intelligence_bonus
+ return race.base_intelligence
+ end
+
+ # Maximum health of the character.
+ #
+ # Based on `total endurance * 10`.
+ fun max_health: Int do return total_endurance * 10
+
+ # The current `health` of the character.
+ #
+ # Starts at `max_health`.
+ var health: Int = max_health
+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.
+
+# COmbat interactions between characters.
+module combat
+
+import character
+
+# Something that can be used to attack someone and inflict damage.
+interface Weapon
+ # Damage per second inflicted by this weapon.
+ fun dps: Float is abstract
+end
+
+# Something that can be combatted, it can `attack` and `defend`.
+#
+# World items can also be `Combatable`.
+# `defend` method is then used to determines how the object react to an attack
+# Some magical items can even `attack`.
+interface Combatable
+ fun hit_points: Int is abstract
+
+ # A `Combatable` can attack a `target` that is also a `Combatable`.
+ #
+ # Attack the `target` using `wepaon` and returns the number of inflicted hit points.
+ fun attack(target: Combatable, weapon: Weapon): Int is abstract
+
+ # Like `attack` but cannot be defended.
+ fun direct_attack(target: Combatable, weapon: Weapon): Int is abstract
+
+ # `Combatable` can defend against attacks.
+ #
+ # Defends against a number of received hit points and return the number of pared hit points.
+ #
+ # @param hit: damage received.
+ fun defend(hit: Int): Int is abstract
+
+ # Is the character still have hit_points?
+ fun is_dead: Bool do return hit_points > 0
+end
+
+# Characters are now `Comabatable`
+redef class Character
+ super Combatable
+
+ # Use character `health` to determines hit_points.
+ redef fun hit_points do return health
+end
+
+# Dwarves can be used as weapons.
+redef class Dwarf
+ super Weapon
+
+ # Dwarf `dps` are based on the dwarf `base_endurance` (represents weight here)
+ redef fun dps do return base_endurance.to_f / 10.0
+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.
+
+# Races of the game.
+#
+# All characters belong to a `Race`.
+#
+# Available races:
+#
+# * `Human`
+# * `Dwarf`
+# * `Elf`
+module races
+
+import platform
+
+# Race determines basic characteristics and what the character will be able to do in life.
+#
+# These are base characteristics, they cannot be changed
+# but you can add new ones if needed using refinement.
+# Objects and spells cannot change those characteristics.
+abstract class Race
+
+ # Used to represents how strong the race is.
+ var base_strength: Int
+
+ # Used to represents how the race can absorb damage.
+ var base_endurance: Int
+
+ # Is this race smart?
+ var base_intelligence: Int
+
+ init do end
+end
+
+# Humans are able to do everithing.
+class Human
+ super Race
+
+ init do
+ self.base_strength = 50
+ self.base_endurance = 50
+ self.base_intelligence = 50
+ end
+end
+
+# Dwarves make strong warriors.
+class Dwarf
+ super Race
+
+ init do
+ self.base_strength = 60
+ self.base_endurance = 50
+ self.base_intelligence = 40
+ end
+end
+
+# Elves make good magicians.
+class Elf
+ super Race
+
+ init do
+ self.base_strength = 40
+ self.base_endurance = 40
+ self.base_intelligence = 70
+ 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.
+
+# A worlg RPG abstraction.
+module rpg
+
+import races
+import careers
+import character
+import combat
+
--- /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 test program with a fake model to check model tools.
+module test_prog
+
+import rpg
+import game
+
+class Starter
+ fun start do end
+end
+
+var starter = new Starter
+starter.start
+
# Simple class
class A
auto_serializable
- super Serializable
- var b: Bool
+ var b = false
var c: Char
var f: Float
- var i: Int
- var s: String
+ var i = 123
+ var s = "asdf"
var n: nullable Int
- var array: Array[nullable Object] = new Array[nullable Object].with_items(88, "hello", null)
+ var array = new Array[nullable Object].with_items(88, "hello", null)
init(b: Bool, c: Char, f: Float, i: Int, s: String, n: nullable Int)
do
# Composed of an A and a B
class C
auto_serializable
- super Serializable
var a: A
- var b: B
+ var b = new B(false, 'b', 123.123, 2345, "hjkl", 12, 1111, "qwer")
var aa: A
init(a: A, b: B)