Merge: typing: new warning `useless-truism` to catch trainees.
authorJean Privat <jean@pryen.org>
Tue, 18 Jul 2017 12:38:12 +0000 (08:38 -0400)
committerJean Privat <jean@pryen.org>
Tue, 18 Jul 2017 12:38:12 +0000 (08:38 -0400)
Warning on `if a == true then` constructions.

Pull-Request: #2520
Reviewed-by: Jean-Christophe Beaupré <jcbrinfo.public@gmail.com>

61 files changed:
NOTICE
contrib/action_nitro/Makefile
contrib/action_nitro/art/icon.svg
contrib/action_nitro/art/icon_background.png [new file with mode: 0644]
contrib/action_nitro/assets/particles/blood07.png
contrib/action_nitro/assets/particles/explosion00.png
contrib/action_nitro/package.ini
contrib/action_nitro/src/action_nitro.nit
contrib/asteronits/src/asteronits.nit
contrib/model_viewer/src/globe.nit
contrib/tinks/src/client/client3d.nit
lib/gamnit/android19.nit [new file with mode: 0644]
lib/gamnit/bmfont.nit
lib/gamnit/depth/depth.nit
lib/gamnit/depth/depth_core.nit
lib/gamnit/depth/more_materials.nit
lib/gamnit/depth/particles.nit
lib/gamnit/display_android.nit
lib/gamnit/examples/fonts_showcase/src/fonts_showcase.nit
lib/gamnit/examples/template/src/template.nit
lib/gamnit/flat/flat.nit [new file with mode: 0644]
lib/gamnit/flat/flat_core.nit [moved from lib/gamnit/flat.nit with 94% similarity]
lib/gamnit/font.nit
lib/gamnit/textures.nit
lib/geometry/quadtree.nit
lib/gmp/gmp.nit [new file with mode: 0644]
lib/more_collections.nit
lib/neo4j/neo4j.nit
lib/poset.nit
misc/README.md
misc/docker/Dockerfile
misc/docker/full/Dockerfile
misc/gtksourceview/nit.lang
misc/vim/plugin/nit.vim
src/doc/vim_autocomplete.nit
src/frontend/code_gen.nit [new file with mode: 0644]
src/frontend/frontend.nit
src/frontend/serialization_code_gen_phase.nit [new file with mode: 0644]
src/frontend/serialization_model_phase.nit [moved from src/frontend/serialization_phase.nit with 62% similarity]
src/model/model.nit
src/nit.nit
src/nitc.nit
src/nitmetrics.nit
src/nitvm.nit
src/test_test_phase.nit
tests/sav/base_arg_default_alt1.res
tests/sav/base_arg_default_autoinit_alt1.res
tests/sav/base_arg_named_alt1.res
tests/sav/base_arg_named_inherit_alt1.res
tests/sav/base_arg_named_inherit_alt2.res
tests/sav/base_arg_named_inherit_alt3.res
tests/sav/base_init_basic_alt5.res
tests/sav/base_init_combine_alt1.res
tests/sav/base_vararg_alt2.res
tests/sav/base_vararg_alt3.res
tests/sav/base_vararg_alt6.res
tests/sav/base_vararg_alt7.res
tests/sav/base_vararg_alt8.res
tests/sav/error_init_auto_alt2.res
tests/sav/test_syntax.res [new file with mode: 0644]
tests/test_syntax.nit [new file with mode: 0644]

diff --git a/NOTICE b/NOTICE
index 5a96547..32b5754 100644 (file)
--- a/NOTICE
+++ b/NOTICE
@@ -72,16 +72,6 @@ Files: share/nitdoc/scripts/jquery-1.7.1.min.js
 Copyright: 2011 John Resig, http://jquery.com/
 Licence: BSD 2 (see LICENSE-BSD)
 
-Files: /misc/gtksourceview/nit.lang
-Copyright: 2009-2011 Alexis Laferrière <alexis.laf@xymus.net>
-           2011-2017 Jean Privat <jean@pryen.org>
-           Based on ruby.lang from
-           2004      Archit Baweja <bighead@users.sourceforge.net>
-           2005      Michael Witrant <mike@lepton.fr>
-           2006      Gabriel Bauman <gbauman@gmail.com>
-License: GPL 2.0 (see LICENSE-GPL-2)
-Comment: GPL because the original work is GPL
-
 Files: /share/png/*
 Copyright: 1998-2014 Glenn Randers-Pehrson
            1996-1997 Andreas Dilger
index b3fcebc..81db63b 100644 (file)
@@ -1,14 +1,14 @@
-NITC=nitc
-NITLS=nitls
-
 all: bin/action_nitro
 
-bin/action_nitro: $(shell ${NITLS} -M src/action_nitro.nit -m linux) pre-build
-       ${NITC} src/action_nitro.nit -m linux -o $@
+bin/action_nitro: $(shell nitls -M src/action_nitro.nit -m linux) pre-build
+       nitc src/action_nitro.nit -m linux -o $@
+
+android: bin/action_nitro.apk
+bin/action_nitro.apk: $(shell nitls -M src/action_nitro.nit -m gamnit::android19 -m src/touch_ui.nit) pre-build android/res/
+       nitc src/action_nitro.nit -m gamnit::android19 -m src/touch_ui.nit -o $@
 
-android:
-bin/action_nitro.apk: $(shell ${NITLS} -M src/action_nitro.nit -m android -m src/touch_ui.nit) pre-build android/res/
-       ${NITC} src/action_nitro.nit -m android -m src/touch_ui.nit -o $@
+android-release: $(shell nitls -M src/action_nitro.nit -m gamnit::android19 -m src/touch_ui.nit) pre-build android/res/
+       nitc src/action_nitro.nit -m gamnit::android19 -m src/touch_ui.nit -o bin/action_nitro.apk --release
 
 src/gen/texts.nit: art/texts.svg
        make -C ../inkscape_tools/
index 7383208..a0701e1 100644 (file)
@@ -60,8 +60,8 @@
      id="layer1"
      transform="translate(-286.05811,81.477047)">
     <image
-       sodipodi:absref="/home/xymus/projects/nit/contrib/action_nitro/art/../assets/particles/explosion00.png"
-       xlink:href="../assets/particles/explosion00.png"
+       sodipodi:absref="icon_background.png"
+       xlink:href="icon_background.png"
        width="479.1073"
        height="439.72864"
        id="image3062"
diff --git a/contrib/action_nitro/art/icon_background.png b/contrib/action_nitro/art/icon_background.png
new file mode 100644 (file)
index 0000000..22529ca
Binary files /dev/null and b/contrib/action_nitro/art/icon_background.png differ
index 584e6d1..4c590d5 100644 (file)
Binary files a/contrib/action_nitro/assets/particles/blood07.png and b/contrib/action_nitro/assets/particles/blood07.png differ
index 22529ca..16a484f 100644 (file)
Binary files a/contrib/action_nitro/assets/particles/explosion00.png and b/contrib/action_nitro/assets/particles/explosion00.png differ
index b9ae919..bcd9ef0 100644 (file)
@@ -9,3 +9,4 @@ git=https://github.com/nitlang/nit.git
 git.directory=contrib/action_nitro/
 homepage=http://nitlanguage.org
 issues=https://github.com/nitlang/nit/issues
+apk=http://nitlanguage.org/fdroid/apk/action_nitro.apk
index 4fdf39e..5ddeea6 100644 (file)
@@ -18,12 +18,9 @@ module action_nitro is
        app_version(1, 0, git_revision)
 
        android_manifest_activity """android:screenOrientation="sensorLandscape""""
-       android_api_target 10
 end
 
 import gamnit::depth
-import gamnit::keys
-import gamnit::limit_fps
 
 import game
 
@@ -80,11 +77,11 @@ redef class App
        # Particle effects
 
        # Explosion particles
-       var explosions = new ParticleSystem(20, explosion_program,
+       var explosions = new ParticleSystem(100, explosion_program,
                new Texture("particles/explosion00.png"))
 
        # Blood explosion particles
-       var blood = new ParticleSystem(20, explosion_program,
+       var blood = new ParticleSystem(100, explosion_program,
                new Texture("particles/blood07.png"))
 
        # Smoke for the background
@@ -137,6 +134,9 @@ redef class App
 
        redef fun on_create
        do
+               blood.texture.as(RootTexture).premultiply_alpha = false
+               explosions.texture.as(RootTexture).premultiply_alpha = false
+
                super
 
                show_splash_screen new Texture("textures/splash.jpg")
@@ -150,10 +150,10 @@ redef class App
                ui_camera.reset_height 1080.0
 
                # Register particle systems
-               particle_systems.add explosions
-               particle_systems.add blood
                particle_systems.add smoke
                particle_systems.add clouds
+               particle_systems.add blood
+               particle_systems.add explosions
 
                # Stars background
                sprites.add stars
@@ -468,12 +468,12 @@ redef class Human
        # Show death animation (explosion)
        fun death_animation
        do
-               var force = 4.0
+               var force = 2.0
                health = 0.0
-               for i in 32.times do
+               for i in 16.times do
                        app.blood.add(
                                new Point3d[Float](center.x & force, center.y & force, center.z & force),
-                               (2048.0 & 4096.0) * force, 0.3 & 0.1)
+                               (4096.0 & 2048.0) * force, 0.3 & 0.1)
                end
        end
 end
@@ -622,26 +622,16 @@ redef class World
                super
 
                # Particles
-               app.explosions.add(center, 8192.0 * force, 0.3)
-               for i in (4.0*force).to_i.times do
+               var range = 0.5 * force
+               app.explosions.add(center, 4096.0 * force, 0.3)
+               for i in (2.0*force).to_i.times do
                        app.explosions.add(
-                               new Point3d[Float](center.x & force, center.y & force/2.0, center.z & force),
-                               (4096.0 & 2048.0) * force, 0.3 & 0.3, 0.5.rand)
+                               new Point3d[Float](center.x & range, center.y & range, center.z & range),
+                               (2048.0 & 1024.0) * force, 0.3 & 0.3, 0.5.rand)
                end
        end
 end
 
-redef class Int
-       # Pad a number with `0`s on the left side to reach `size` digits
-       private fun pad(size: Int): String
-       do
-               var s = to_s
-               var d = size - s.length
-               if d > 0 then s = "0"*d + s
-               return s
-       end
-end
-
 # Manager to display numbers in sprite
 class CounterSprites
 
@@ -694,8 +684,8 @@ redef class SmokeProgram
                gl_PointSize = scale / gl_Position.z * (pt+0.1);
 
                if (pt < 0.1)
-                       v_color.a = pt / 0.1;
+                       v_color *= pt / 0.1;
                else
-                       v_color.a = 1.0 - pt*0.9;
+                       v_color *= 1.0 - pt*0.9;
        """
 end
index 02cb3f4..1c148db 100644 (file)
@@ -26,7 +26,6 @@ import gamnit::flat
 
 import game_logic
 import spritesheet
-import app::audio
 
 redef class Spritesheet
        # Largest meteors, organized by color
index a5a9a62..12c6ffc 100644 (file)
@@ -91,10 +91,12 @@ class GlobeMaterial
        init surface do init(0, true, [1.0, 1.0, 1.0, 1.0])
 
        # Create and configure a material for the cloud layer
-       init clouds do init(4, false, [1.0, 1.0, 1.0, 0.5])
+       init clouds do init(4, false, [1.0*clouds_a, 1.0*clouds_a, 1.0*clouds_a, clouds_a])
+       private var clouds_a = 0.5
 
        # Create and configure a material for the visible atmosphere
-       init atmo do init(null, false, [0.0, 0.8, 1.0, 0.05])
+       init atmo do init(null, false, [0.0, 0.8*atmo_a, 1.0*atmo_a, atmo_a])
+       private var atmo_a = 0.05
 
        redef fun draw(actor, model)
        do
@@ -228,7 +230,6 @@ class GlobeProgram
                                s += 0.05 * texture2D(tex_displace, tex_coord).r;
 
                        gl_Position = (vec4(coord.xyz * s, 1.0) * rotation + translation) * mvp;
-
                }
                """ @ glsl_vertex_shader
 
index b37fc69..3b272d6 100644 (file)
@@ -23,8 +23,6 @@ module client3d is
 end
 
 import gamnit::depth
-import gamnit::keys
-import app::audio
 
 import base
 
diff --git a/lib/gamnit/android19.nit b/lib/gamnit/android19.nit
new file mode 100644 (file)
index 0000000..3325ece
--- /dev/null
@@ -0,0 +1,55 @@
+# 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.
+
+# Variation using features from Android API 19
+#
+# Add support for `TextureAsset::premultiply_alpha = false` on Android.
+module android19 is
+       android_api_min 19
+       android_api_target 22
+end
+
+import android
+intrude import display_android
+intrude import android::load_image
+
+in "Java" `{
+       import android.graphics.Bitmap;
+       import android.graphics.BitmapFactory;
+`}
+
+redef class TextureAsset
+
+       redef fun load_bitmap(asset_manager, path)
+       do
+               var stream = asset_manager.native_assets_manager.open(path.to_java_string)
+               return new NativeBitmap.from_stream_ex(stream, premultiply_alpha)
+       end
+end
+
+redef class NativeCByteArray
+
+       # The data was not premultiplied, don't unmultiply it
+       redef fun unmultiply(w, h) do end
+end
+
+redef class NativeBitmap
+
+       # Load from `input_stream` with optional `premultiply_alpha`
+       new from_stream_ex(input_stream: NativeInputStream, premultiply_alpha: Bool) in "Java" `{
+               BitmapFactory.Options opts = new BitmapFactory.Options();
+               opts.inPremultiplied = premultiply_alpha; // API 19
+               return BitmapFactory.decodeStream(input_stream, null, opts);
+       `}
+end
index fa3a197..c2c8be5 100644 (file)
@@ -139,13 +139,16 @@ class BMFontChar
        var xadvance: Float
 
        # Full texture contaning this character and others
-       var page: TextureAsset
+       var page: RootTexture
 
        # TODO Channel where the image is found
        #var chnl: Int
 
        # Subtexture with this character image only
-       var subtexture: Texture = page.subtexture(x, y, width, height) is lazy
+       var subtexture: Texture = page.subtexture(x, y, width, height) is lazy, writable
+
+       # Scale to apply to this char only
+       var scale = 1.0 is writable
 end
 
 redef class Text
@@ -184,7 +187,7 @@ redef class Text
        # assert fnt.to_s == "<BMFont arial at 72.0 pt, 1 pages, 3 chars>"
        # assert fnt.line_height == 80.0
        # assert fnt.kernings['A', 'C'] == -1.0
-       # assert fnt.chars['A'].page.path == "dir_in_assets/arial.png"
+       # assert fnt.chars['A'].page.as(TextureAsset).path == "dir_in_assets/arial.png"
        # ~~~
        fun parse_bmfont(dir: String): MaybeError[BMFont, Error]
        do
@@ -363,14 +366,24 @@ class BMFontAsset
                var dx = 0.0
                var dy = 0.0
                var text_width = 0.0
+               var line_sprites = new Array[Sprite]
 
+               # TextSprite customization
                var max_width = text_sprites.max_width
                var max_height = text_sprites.max_height
+               var scale = text_sprites.scale
 
-               var line_height = desc.line_height
+               # Font customization
+               var line_height = desc.line_height * scale
                var partial_line_skip = line_height * partial_line_mod.to_f
-               var line_sprites = new Array[Sprite]
 
+               # Links data
+               text_sprites.links.clear
+               var in_link = false
+               var link_sprites = new Array[Sprite]
+               var link_name = ""
+
+               # Loop over all characters
                var prev_char = null
                var i = -1
                while i < text.length - 1 do
@@ -400,10 +413,59 @@ class BMFontAsset
                                        else if desc.chars.keys.has('f') then
                                                desc.chars['f'].xadvance
                                        else 16.0
-                               dx += space_advance
+                               dx += space_advance * scale
                                word_break = true
+                       else if c == '[' then
+                               # Open link?
+                               if i + 1 < text.length and text[i+1] == '[' then
+                                       # Escape if duplicated
+                                       i += 1
+                               else
+                                       in_link = true
+                                       continue
+                               end
+                       else if c == ']' then
+                               # Close link?
+                               if i + 1 < text.length and text[i+1] == ']' then
+                                       # Escape if duplicated
+                                       i += 1
+                               else
+                                       # If there's a () use it as link_name
+                                       var j = i + 1
+                                       if j < text.length and text[j] == '(' then
+                                               var new_name
+                                               new_name = ""
+                                               loop
+                                                       j += 1
+                                                       if j > text.length then
+                                                               # No closing ), abort
+                                                               new_name = null
+                                                               break
+                                                       end
+
+                                                       var l = text[j]
+                                                       if l == ')' then break
+                                                       new_name += l.to_s
+                                               end
+                                               if new_name != null then
+                                                       link_name = new_name
+                                                       i = j
+                                               end
+                                       end
+
+                                       # Register the link for the clients
+                                       text_sprites.links[link_name] = link_sprites
+
+                                       # Prepare next link
+                                       in_link = false
+                                       link_sprites = new Array[Sprite]
+                                       link_name = ""
+                                       continue
+                               end
                        end
 
+                       if in_link then link_name += c.to_s
+
                        # End of a word?
                        if word_break then
                                # If we care about line width, check for overflow
@@ -414,8 +476,8 @@ class BMFontAsset
                                        for wi in [i+1..text.length[ do
                                                var w = text[wi]
 
-                                               if w == '\n' or w == pld or w == plu or w.is_whitespace then break
-                                               word_len += advance(prev_w, w)
+                                               if w == '\n' or w == pld or w == plu or w.is_whitespace or (in_link and w == ']') then break
+                                               word_len += advance(prev_w, w) * scale
                                                prev_w = w
                                        end
 
@@ -456,14 +518,16 @@ class BMFontAsset
                        var advance = char_info.xadvance
                        var kerning = desc.kerning(prev_char, c)
 
-                       var x = dx + char_info.width/2.0  + char_info.xoffset + kerning
-                       var y = dy - char_info.height/2.0 - char_info.yoffset
+                       var x = dx + (char_info.width/2.0  + char_info.xoffset + kerning) * scale
+                       var y = dy - (char_info.height/2.0 + char_info.yoffset) * scale
                        var pos = text_sprites.anchor.offset(x, y, 0.0)
                        var s = new Sprite(char_info.subtexture, pos)
+                       s.scale = scale * char_info.scale
                        text_sprites.sprites.add s
                        line_sprites.add s
+                       if in_link then link_sprites.add s
 
-                       dx += advance + kerning
+                       dx += (advance + kerning) * scale
                        prev_char = c
 
                        text_width = text_width.max(dx)
index 9b4be47..4139949 100644 (file)
@@ -15,6 +15,7 @@
 # Framework for 3D games in Nit
 module depth
 
+import flat
 intrude import more_materials
 import more_models
 import model_dimensions
index 890395a..c1c1619 100644 (file)
@@ -15,7 +15,7 @@
 # Base entities of the depth 3D game framework
 module depth_core
 
-intrude import gamnit::flat
+import gamnit::flat_core
 
 # Visible 3D entity in the game world
 #
index 746a952..3b320f9 100644 (file)
@@ -31,12 +31,18 @@ class SmoothMaterial
        super Material
 
        # Ambient color, always visible
+       #
+       # The RGB values should be premultiplied by the alpha value.
        var ambient_color: Array[Float] is writable
 
        # Diffuse color when covered by a light source
+       #
+       # The RGB values should be premultiplied by the alpha value.
        var diffuse_color: Array[Float] is writable
 
        # Specular color affecting reflections
+       #
+       # The RGB values should be premultiplied by the alpha value.
        var specular_color: Array[Float] is writable
 
        redef fun draw(actor, model)
@@ -71,9 +77,13 @@ class SmoothMaterial
                program.camera.uniform(app.world_camera.position.x, app.world_camera.position.y, app.world_camera.position.z)
 
                # Colors from the material
-               program.ambient_color.uniform(ambient_color[0], ambient_color[1], ambient_color[2], ambient_color[3]*actor.alpha)
-               program.diffuse_color.uniform(diffuse_color[0], diffuse_color[1], diffuse_color[2], diffuse_color[3]*actor.alpha)
-               program.specular_color.uniform(specular_color[0], specular_color[1], specular_color[2], specular_color[3]*actor.alpha)
+               var a = actor.alpha
+               program.ambient_color.uniform(ambient_color[0]*a, ambient_color[1]*a,
+                                             ambient_color[2]*a, ambient_color[3]*a)
+               program.diffuse_color.uniform(diffuse_color[0]*a, diffuse_color[1]*a,
+                                             diffuse_color[2]*a, diffuse_color[3]*a)
+               program.specular_color.uniform(specular_color[0]*a, specular_color[1]*a,
+                                              specular_color[2]*a, specular_color[3]*a)
 
                # Execute draw
                if mesh.indices.is_empty then
@@ -188,9 +198,13 @@ class TexturedMaterial
 
                program.rotation.uniform new Matrix.gamnit_euler_rotation(actor.pitch, actor.yaw, actor.roll)
 
-               program.ambient_color.uniform(ambient_color[0], ambient_color[1], ambient_color[2], ambient_color[3]*actor.alpha)
-               program.diffuse_color.uniform(diffuse_color[0], diffuse_color[1], diffuse_color[2], diffuse_color[3]*actor.alpha)
-               program.specular_color.uniform(specular_color[0], specular_color[1], specular_color[2], specular_color[3]*actor.alpha)
+               var a = actor.alpha
+               program.ambient_color.uniform(ambient_color[0]*a, ambient_color[1]*a,
+                                             ambient_color[2]*a, ambient_color[3]*a)
+               program.diffuse_color.uniform(diffuse_color[0]*a, diffuse_color[1]*a,
+                                             diffuse_color[2]*a, diffuse_color[3]*a)
+               program.specular_color.uniform(specular_color[0]*a, specular_color[1]*a,
+                                              specular_color[2]*a, specular_color[3]*a)
 
                program.normal.array_enabled = true
                program.normal.array(mesh.normals, 3)
index 3c40ac1..bfe3392 100644 (file)
@@ -258,7 +258,6 @@ class ParticleProgram
                {
                        if (use_texture) {
                                gl_FragColor = texture2D(texture0, gl_PointCoord) * v_color;
-                               if (gl_FragColor.a <= 0.01) discard;
                        } else {
                                gl_FragColor = v_color;
                        }
@@ -301,7 +300,7 @@ class ExplosionProgram
                gl_Position = center * mvp;
                gl_PointSize = scale / gl_Position.z * pt;
 
-               if (pt > 0.8) v_color.a = (1.0-pt)/0.2;
+               if (pt > 0.8) v_color *= (1.0-pt)/0.2;
        """
 end
 
@@ -318,8 +317,8 @@ class SmokeProgram
                gl_PointSize = scale / gl_Position.z * (pt+0.1);
 
                if (pt < 0.1)
-                       v_color.a = pt / 0.1;
+                       v_color *= pt / 0.1;
                else
-                       v_color.a = 1.0 - pt*0.9;
+                       v_color *= 1.0 - pt*0.9;
        """
 end
index e9d1b4a..8e5566c 100644 (file)
@@ -50,19 +50,24 @@ end
 
 redef class TextureAsset
 
+       private fun load_bitmap(asset_manager: AssetManager, path: String): NativeBitmap
+       do
+               return asset_manager.bitmap(path)
+       end
+
        redef fun load_from_platform
        do
                jni_env.push_local_frame 4
 
                var asset_manager = app.asset_manager
-               var bmp = asset_manager.bitmap(path)
+               var bmp = load_bitmap(asset_manager, path)
                if bmp.is_java_null then
                        error = new Error("Failed to load texture at '{path}'")
                        jni_env.pop_local_frame
                        return
                end
 
-               var buf = bmp.copy_pixels
+               var buf = bmp.copy_pixels(unmultiply=not premultiply_alpha)
                loaded = true
                width = bmp.width.to_f
                height = bmp.height.to_f
index 0fae76d..d64c304 100644 (file)
@@ -46,7 +46,7 @@ redef class App
 
                # Shared content
                var description = "The anchor icon identifies the coordinate of TextSprites::anchor."
-               var lorem_ipsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
+               var lorem_ipsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et [dolore magna](my_link asdf) aliqua."
                var color = [0.0, 0.25, 0.5]
 
                # ---
@@ -77,8 +77,8 @@ redef class App
 
                texts.add new TextSprites(font,
                        ui_camera.top_left.offset(1000.0, -400.0, 0.0),
-                       "Right, max_width=400.0:\n"+lorem_ipsum,
-                       align=1.0, max_width=400.0)
+                       "Right, max_width=400.0, scale=0.66:\n"+lorem_ipsum,
+                       align=1.0, max_width=400.0, scale=0.66)
 
                texts.add new TextSprites(font,
                        ui_camera.top_left.offset(300.0, -700.0, 0.0),
@@ -121,6 +121,16 @@ redef class App
                        max_width=400.0, align=0.5, valign=0.5)
 
                # ---
+               # Links
+
+               for ts in texts do
+                       for link_name, sprites in ts.links do
+                               print "Link: {link_name}"
+                               for s in sprites do s.green = 0.0
+                       end
+               end
+
+               # ---
                # Anchors and background boxes
 
                # Gradient background for the max_width texts
index 9c2c220..a0f37a0 100644 (file)
@@ -13,9 +13,7 @@ module template is
        android_api_target 10
 end
 
-import gamnit::flat # For `Texture, Sprite`, etc.
-import gamnit::keys # For `pressed_keys`
-import app::audio # For `Sound`
+import gamnit::flat # The 2D API, use `gamnit::depth` for 3D
 
 redef class App
 
diff --git a/lib/gamnit/flat/flat.nit b/lib/gamnit/flat/flat.nit
new file mode 100644 (file)
index 0000000..4094333
--- /dev/null
@@ -0,0 +1,44 @@
+# 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.
+
+# Simple API for 2D games, built around `Sprite` and `App::update`
+#
+# Client programs should implement `App::update` to execute game logic and
+# add instances of `Sprite` to `App::sprites` and `App::ui_sprites`.
+# At each frame, all sprites are drawn to the screen.
+#
+# This system relies on two cameras `App::world_camera` and `App::ui_camera`.
+#
+# * `App::world_camera` applies a perspective effect to draw the game world.
+#   This camera is designed to be moved around to see the world as well as to
+#   zoom in and out. It is used to position the sprites in `App::sprites`.
+#
+# * `App::ui_camera` is a simple orthogonal camera to display UI objects.
+#   This camera should mostly be still, it can still move for chock effects
+#   and the like. It can be used to standardize the size of the UI across
+#   devices. It is used to position the sprites in `App::ui_sprites`.
+#
+# See the sample game at `contrib/asteronits/` and the basic project template
+# at `lib/gamnit/examples/template/`.
+module flat
+
+import gamnit::flat_core
+
+# Extra optional features
+import gamnit::limit_fps
+import gamnit::keys
+import gamnit::camera_control
+import gamnit::tileset
+import gamnit::bmfont
+import app::audio
similarity index 94%
rename from lib/gamnit/flat.nit
rename to lib/gamnit/flat/flat_core.nit
index 56fd402..c8ffed4 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Simple API for 2D games, built around `Sprite` and `App::update`
-#
-# Client programs should implement `App::update` to execute game logic and
-# add instances of `Sprite` to `App::sprites` and `App::ui_sprites`.
-# At each frame, all sprites are drawn to the screen.
-#
-# This system relies on two cameras `App::world_camera` and `App::ui_camera`.
-#
-# * `App::world_camera` applies a perspective effect to draw the game world.
-#   This camera is designed to be moved around to see the world as well as to
-#   zoom in and out. It is used to position the sprites in `App::sprites`.
-#
-# * `App::ui_camera` is a simple orthogonal camera to display UI objects.
-#   This camera should mostly be still, it can still move for chock effects
-#   and the like. It can be used to standardize the size of the UI across
-#   devices. It is used to position the sprites in `App::ui_sprites`.
-#
-# See the sample game at `contrib/asteronits/` and the basic project template
-# at `lib/gamnit/examples/template/`.
-module flat
+# Core services for the `flat` API for 2D games
+module flat_core
 
 import glesv2
 intrude import geometry::points_and_lines # For _x, _y and _z
@@ -44,8 +26,6 @@ import gamnit
 intrude import gamnit::cameras
 intrude import gamnit::cameras_cache
 import gamnit::dynamic_resolution
-import gamnit::limit_fps
-import gamnit::camera_control
 
 # Visible 2D entity in the game world or UI
 #
@@ -261,6 +241,32 @@ class Sprite
                tint_direct = value
        end
 
+       # Draw order, higher values cause this sprite to be drawn latter
+       #
+       # Change this value to avoid artifacts when drawing non-opaque sprites.
+       # In general, sprites with a non-opaque `texture` and sprites closer to
+       # the camera should have a higher value to be drawn last.
+       #
+       # Sprites sharing a `draw_order` are drawn in the same pass.
+       # The sprite to sprite draw order is undefined and may change when adding
+       # and removing sprites, or changing their attributes.
+       #
+       # ### Warning
+       #
+       # Changing this value may have a negative performance impact if there are
+       # many different `draw_order` values across many sprites.
+       # Sprites sharing some attributes are drawn as group to reduce
+       # the communication overhead between the CPU and GPU,
+       # and changing `draw_order` may break up large groups into smaller groups.
+       var draw_order = 0 is writable(draw_order_direct=)
+
+       # Set draw order,  see `draw_order`
+       fun draw_order=(value: Int)
+       do
+               if isset _draw_order and value != draw_order then needs_remap
+               draw_order_direct = value
+       end
+
        # Is this sprite static and added in bulk?
        #
        # Set to `true` to give a hint to the framework that this sprite won't
@@ -430,7 +436,7 @@ redef class App
 
                # Enable blending
                gl.capabilities.blend.enable
-               glBlendFunc(gl_SRC_ALPHA, gl_ONE_MINUS_SRC_ALPHA)
+               glBlendFunc(gl_ONE, gl_ONE_MINUS_SRC_ALPHA)
 
                # Enable depth test
                gl.capabilities.depth_test.enable
@@ -695,7 +701,7 @@ private class Simple2dProgram
                        }
 
                        gl_Position = (vec4(c * scale, 1.0) * rotation() + translation)* mvp;
-                       v_color = color;
+                       v_color = vec4(color.rgb*color.a, color.a);
                }
                """ @ glsl_vertex_shader
 
@@ -873,9 +879,9 @@ private class SpriteSet
        super HashSet[Sprite]
 
        # Map texture then static vs dynamic to a `SpriteContext`
-       var contexts_map = new HashMap3[RootTexture, nullable RootTexture, Bool, SpriteContext]
+       var contexts_map = new HashMap4[RootTexture, nullable RootTexture, Bool, Int, Array[SpriteContext]]
 
-       # Contexts in `contexts_map`
+       # Contexts in `contexts_map`, sorted by draw order
        var contexts_items = new Array[SpriteContext]
 
        # Sprites needing resorting in `contexts_map`
@@ -897,14 +903,33 @@ private class SpriteSet
                var animation = sprite.animation
                var animation_texture = if animation != null then
                        animation.frames.first.root else null
-               var context = contexts_map[texture, animation_texture, sprite.static]
+               var draw_order = sprite.draw_order
+               var contexts = contexts_map[texture, animation_texture, sprite.static, draw_order]
+
+               var context = null
+               if contexts != null then
+                       for c in contexts.reverse_iterator do
+                               var size = c.sprites.length + 1
+                               if size * 4 <= 0xffff then
+                                       context = c
+                                       break
+                               end
+                       end
+               end
 
                if context == null then
                        var usage = if sprite.static then gl_STATIC_DRAW else gl_DYNAMIC_DRAW
-                       context = new SpriteContext(texture, animation_texture, usage)
+                       context = new SpriteContext(texture, animation_texture, usage, draw_order)
+
+                       if contexts == null then
+                               contexts = new Array[SpriteContext]
+                               contexts_map[texture, animation_texture, sprite.static, draw_order] = contexts
+                       end
+
+                       contexts.add context
 
-                       contexts_map[texture, animation_texture, sprite.static] = context
                        contexts_items.add context
+                       sprite_draw_order_sorter.sort(contexts_items)
                end
 
                context.sprites.add sprite
@@ -934,12 +959,14 @@ private class SpriteSet
        # Draw all sprites by all contexts
        fun draw
        do
+               # Remap sprites that may need to change context
                for sprite in sprites_to_remap do
                        unmap_sprite sprite
                        map_sprite sprite
                end
                sprites_to_remap.clear
 
+               # Sort by draw order
                for context in contexts_items do context.draw
        end
 
@@ -992,6 +1019,9 @@ private class SpriteContext
        # OpenGL ES usage of `buffer_array` and `buffer_element`
        var usage: GLBufferUsage
 
+       # Draw order shared by all `sprites`
+       var draw_order: Int
+
        # Sprites drawn by this context
        var sprites = new GroupedSprites
 
@@ -1700,3 +1730,20 @@ redef class NativeGLfloatArray
                        self[i+dst_offset] = (GLfloat)matrix[i];
        `}
 end
+
+redef class Sys
+       private var sprite_draw_order_sorter = new DrawOrderComparator is lazy
+end
+
+# Sort `SpriteContext` by their `draw_order`
+private class DrawOrderComparator
+       super Comparator
+
+       # This class can't set COMPARED because
+       # `the public property cannot contain the private type...`
+       #redef type COMPARED: SpriteContext
+
+       # Require: `a isa SpriteContext and b isa SpriteContext`
+       redef fun compare(a, b)
+       do return a.as(SpriteContext).draw_order <=> b.as(SpriteContext).draw_order
+end
index df46590..c6f48df 100644 (file)
@@ -15,7 +15,7 @@
 # Abstract font drawing services, implemented by `bmfont` and `tileset`
 module font
 
-import flat
+import gamnit::flat_core
 
 # Abstract font, drawn by a `TextSprites`
 abstract class Font
@@ -124,6 +124,24 @@ class TextSprites
        # Otherwise, lines are cut before overflowing.
        var wrap = true is optional, writable
 
+       # Scale applied to all sprites and spacing
+       #
+       # Defaults to 1.0.
+       var scale = 1.0 is optional, writable
+
+       # Links in the currently displayed text
+       #
+       # Links are declared in a Markdown-like format:
+       #
+       # * `[my link]` creates a link with the name `my link`.
+       # * `[pretty name](internal name)` creates a link with the
+       #   name `internal_name` while showing the text `pretty name`.
+       #
+       # This `Map` lists the sprites composing each link.
+       # These sprites can be modified as desired by the clients,
+       # by changing their tints or anything else.
+       var links = new Map[String, Array[Sprite]] is lazy
+
        # Width of the currently displayed text
        var width = 0.0
 
index 65f654b..4fb98ac 100644 (file)
@@ -208,7 +208,7 @@ class CustomTexture
        end
 end
 
-# Texture with its own pixels
+# Texture with its own pixel data
 class RootTexture
        super Texture
 
@@ -221,6 +221,18 @@ class RootTexture
 
        init do all_root_textures.add self
 
+       # Should the pixels RGB values be premultiplied by their alpha value at loading?
+       #
+       # All gamnit textures must have premultiplied alpha, it provides a better
+       # alpha blending, avoids artifacts and allows for additive blending.
+       #
+       # When at `true`, the default, pixels RGB values are premultiplied
+       # at loading. Set to `false` if pixels RGB values are already
+       # premultiplied in the source data.
+       #
+       # This value must be set before calling `load`.
+       var premultiply_alpha = true is writable
+
        private fun load_from_pixels(pixels: Pointer, width, height: Int, format: GLPixelFormat)
        do
                var max_texture_size = glGetIntegerv(gl_MAX_TEXTURE_SIZE, 0)
@@ -229,6 +241,11 @@ class RootTexture
                        return
                end
 
+               # Premultiply alpha?
+               if premultiply_alpha and format == gl_RGBA then
+                       pixels.premultiply_alpha(width, height)
+               end
+
                glPixelStorei(gl_UNPACK_ALIGNEMENT, 1)
                var tex = glGenTextures(1)[0]
                gl_texture = tex
@@ -238,6 +255,9 @@ class RootTexture
 
                glHint(gl_GENERATE_MIPMAP_HINT, gl_NICEST)
                glGenerateMipmap(gl_TEXTURE_2D)
+               glTexParameteri(gl_TEXTURE_2D, gl_TEXTURE_MIN_FILTER, gl_LINEAR_MIPMAP_LINEAR)
+
+               glBindTexture(gl_TEXTURE_2D, 0)
        end
 
        private fun load_checker(size: Int)
@@ -365,3 +385,20 @@ class TextureSet
        # Load all texture of this set
        fun load_all do for t in self do t.load
 end
+
+redef class Pointer
+       # Multiply RBG values by their alpha value
+       private fun premultiply_alpha(width, height: Int) `{
+               uint8_t *bytes = (uint8_t *)self;
+               int x, y, i = 0;
+               for(y = 0; y < height; y ++) {
+                       for(x = 0; x < width; x ++) {
+                               int a = bytes[i+3];
+                               bytes[i  ] = bytes[i  ] * a / 255;
+                               bytes[i+1] = bytes[i+1] * a / 255;
+                               bytes[i+2] = bytes[i+2] * a / 255;
+                               i += 4;
+                       }
+               }
+       `}
+end
index 7c3f2d4..b3ed46f 100644 (file)
 # limitations under the License.
 
 # QuadTree API mostly used for 2 dimensional collision detection
+#
 # The QuadTree data structure partition a 2D space by recursively
-# subdividing it into 4 regions when it's capacity is reached
-# This module introduce 2 principal implementation of the structure,
-# the static and the dynamic QuadTree
+# subdividing it into 4 regions when its capacity is reached.
+# This module introduces 2 main implementation of the structure,
+# a static and a dynamic QuadTree.
 module quadtree
 
 import boxes
 import pipeline
 
-# Abstract QuadTree implementing most of the basic functions
-# and introducing specific QuadTree data
+# Abstract QuadTree implementing the basic functions and data
 abstract class QuadTree[E: Boxed[Numeric]]
        super BoxedCollection[E]
 
+       # Center coordinate of the children
        protected var center: nullable Point[Numeric] = null
-       var data: Array[E] = new Array[E]
 
-       #  ________________
-       #  |       |       |
-       #  |   1   |   2   |
-       #  |-------|-------|
-       #  |   0   |   3   |
-       #  |_______|_______|
+       # Items in this node
+       protected var data = new Array[E]
 
-       protected var child0: nullable QuadTree[E] = null
-       protected var child1: nullable QuadTree[E] = null
-       protected var child2: nullable QuadTree[E] = null
-       protected var child3: nullable QuadTree[E] = null
+       # Children nodes, if not `is_leaf`
+       #
+       # ~~~raw
+       # ________________
+       # |       |       |
+       # |   1   |   2   |
+       # |-------|-------|
+       # |   0   |   3   |
+       # |_______|_______|
+       # ~~~
+       protected var children = new Array[QuadTree[E]]
 
-       # represent the threshold before subdividing the node
+       # Maximum number of items in this node before subdividing
        protected var item_limit: Int
+
+       # Parent node in the tree
        protected var parent_node: nullable QuadTree[E] = null
 
-       # create a node, giving him self as a parent. Used to create children nodes
+       # Create a child node to `parent`
        init with_parent(limit: Int, parent: QuadTree[E])
        do
                init(limit)
@@ -61,31 +66,33 @@ abstract class QuadTree[E: Boxed[Numeric]]
                return res
        end
 
-       # add the item to the tree, create children if the limit is reached
+       # Add `item` to the tree, create children if `item_limit` is reached
        redef fun add(item) do if self.is_leaf then self.data.add(item) else add_to_children(item)
 
        private fun add_to_children(item: Boxed[Numeric])
        do
-               if self.child0 != null then
-                       if self.center.x > item.right then
-                               if self.center.y > item.top then
-                                       child0.add(item)
-                               else if self.center.y < item.bottom then
-                                       child1.add(item)
+               if children.not_empty then
+                       var center = center
+                       assert center != null
+                       if center.x > item.right then
+                               if center.y > item.top then
+                                       children[0].add(item)
+                               else if center.y < item.bottom then
+                                       children[1].add(item)
                                else
                                        self.data.add(item)
                                end
-                       else if self.center.x < item.left then
-                               if self.center.y > item.top then
-                                       child3.add(item)
-                               else if self.center.y < item.bottom then
-                                       child2.add(item)
+                       else if center.x < item.left then
+                               if center.y > item.top then
+                                       children[3].add(item)
+                               else if center.y < item.bottom then
+                                       children[2].add(item)
                                else
                                        self.data.add(item)
                                end
-                       else if self.center.y > item.top then
+                       else if center.y > item.top then
                                self.data.add(item)
-                       else if self.center.y < item.bottom then
+                       else if center.y < item.bottom then
                                self.data.add(item)
                        else
                                self.data.add(item)
@@ -93,10 +100,16 @@ abstract class QuadTree[E: Boxed[Numeric]]
                end
        end
 
-       redef fun is_empty do return data.is_empty and (self.is_leaf or (child0.is_empty and child1.is_empty and child2.is_empty and child3.is_empty))
+       redef fun is_empty
+       do
+               if is_leaf then return data.is_empty
+
+               assert children.length >= 4
+               return data.is_empty and children[0].is_empty and children[1].is_empty and children[2].is_empty and children[3].is_empty
+       end
 
        # Return whether or not the Node is a leaf of the tree
-       fun is_leaf: Bool do return child0 == null
+       fun is_leaf: Bool do return children.is_empty
 
        #     var dquadtree = new DQuadTree[Point[Int]](2)
        #     var p1 = new Point[Int](0,0)
@@ -113,7 +126,7 @@ abstract class QuadTree[E: Boxed[Numeric]]
        #     assert result.length == 0
        #     result = dquadtree.items_overlapping(p4.padded(10))
        #     assert result.length == 3
-       fun items_overlapping_in(region: Boxed[Numeric], mdata: SimpleCollection[E])
+       private fun items_overlapping_in(region: Boxed[Numeric], mdata: SimpleCollection[E])
        do
                if self.is_leaf and data.length >= item_limit then
                        subdivide
@@ -125,63 +138,72 @@ abstract class QuadTree[E: Boxed[Numeric]]
                        end
                end
                for i in data do if i.intersects(region) then mdata.add(i)
-               if self.child0 != null then
-                       if self.center.x > region.right then
-                               if self.center.y > region.top then
-                                       child0.items_overlapping_in(region, mdata)
-                               else if self.center.y < region.bottom then
-                                       child1.items_overlapping_in(region, mdata)
+
+               if children.not_empty then
+                       var center = center
+                       assert center != null
+                       if center.x > region.right then
+                               if center.y > region.top then
+                                       children[0].items_overlapping_in(region, mdata)
+                               else if center.y < region.bottom then
+                                       children[1].items_overlapping_in(region, mdata)
                                else
-                                       child0.items_overlapping_in(region,mdata)
-                                       child1.items_overlapping_in(region, mdata)
+                                       children[0].items_overlapping_in(region,mdata)
+                                       children[1].items_overlapping_in(region, mdata)
                                end
-                       else if self.center.x < region.left then
-                               if self.center.y > region.top then
-                                       child3.items_overlapping_in(region, mdata)
-                               else if self.center.y < region.bottom then
-                                       child2.items_overlapping_in(region, mdata)
+                       else if center.x < region.left then
+                               if center.y > region.top then
+                                       children[3].items_overlapping_in(region, mdata)
+                               else if center.y < region.bottom then
+                                       children[2].items_overlapping_in(region, mdata)
                                else
-                                       child3.items_overlapping_in(region, mdata)
-                                       child2.items_overlapping_in(region, mdata)
+                                       children[3].items_overlapping_in(region, mdata)
+                                       children[2].items_overlapping_in(region, mdata)
                                end
-                       else if self.center.y > region.top then
-                               child0.items_overlapping_in(region, mdata)
-                               child3.items_overlapping_in(region, mdata)
-                       else if self.center.y < region.bottom then
-                               child1.items_overlapping_in(region, mdata)
-                               child2.items_overlapping_in(region, mdata)
+                       else if center.y > region.top then
+                               children[0].items_overlapping_in(region, mdata)
+                               children[3].items_overlapping_in(region, mdata)
+                       else if center.y < region.bottom then
+                               children[1].items_overlapping_in(region, mdata)
+                               children[2].items_overlapping_in(region, mdata)
                        else
-                               child0.items_overlapping_in(region, mdata)
-                               child1.items_overlapping_in(region, mdata)
-                               child2.items_overlapping_in(region, mdata)
-                               child3.items_overlapping_in(region, mdata)
+                               children[0].items_overlapping_in(region, mdata)
+                               children[1].items_overlapping_in(region, mdata)
+                               children[2].items_overlapping_in(region, mdata)
+                               children[3].items_overlapping_in(region, mdata)
                        end
                end
        end
 
-       # this function is responsible of the creation of the children,
-       # depending on your needs
+       # Create children nodes, depends on the concrete implementation
        protected fun subdivide is abstract
 
-       redef fun iterator do if self.is_leaf then return data.iterator else return data.iterator + child0.iterator + child1.iterator + child2.iterator + child3.iterator
+       redef fun iterator
+       do
+               if is_leaf then return data.iterator
+
+               assert children.length >= 4
+               return data.iterator + children[0].iterator + children[1].iterator + children[2].iterator + children[3].iterator
+       end
 end
 
 # A dynamic implementation of the quadtree data structure
-# the center of the parent node is determined by the average
-# values of the data it contains when the item limit is reached
+#
+# The center of the parent node is determined by the average
+# values of the data it contains when `item_limit` is reached.
 class DQuadTree[E: Boxed[Numeric]]
        super QuadTree[E]
 
        redef fun subdivide
        do
                self.center = new Point[Numeric](average_x, average_y)
-               child0 = new DQuadTree[E].with_parent(self.item_limit, self)
-               child1 = new DQuadTree[E].with_parent(self.item_limit, self)
-               child2 = new DQuadTree[E].with_parent(self.item_limit, self)
-               child3 = new DQuadTree[E].with_parent(self.item_limit, self)
+               children[0] = new DQuadTree[E].with_parent(self.item_limit, self)
+               children[1] = new DQuadTree[E].with_parent(self.item_limit, self)
+               children[2] = new DQuadTree[E].with_parent(self.item_limit, self)
+               children[3] = new DQuadTree[E].with_parent(self.item_limit, self)
        end
 
-       # average x of data in this node
+       # Average X coordinate of the items in this node
        fun average_x: Numeric
        do
                var x_total = data.first.left.zero
@@ -191,7 +213,7 @@ class DQuadTree[E: Boxed[Numeric]]
                return x_total/x_total.value_of(self.data.length)
        end
 
-       # average y of data in this node
+       # Average Y coordinate of the items in this node
        fun average_y: Numeric
        do
                var y_total = data.first.left.zero
@@ -202,17 +224,19 @@ class DQuadTree[E: Boxed[Numeric]]
        end
 end
 
-# Static implementation of the quadtree structure.
+# Static implementation of the quadtree structure
+#
 # You need to specify a zone when creating the quadtree,
 # which will be the zone corresponding to the root node.
-# each subdivision cut the space in 4 equal regions from
-# the center of the parent node
+# Each subdivision cut the space in 4 equal regions from
+# the center of the parent node.
 class SQuadTree[E: Boxed[Numeric]]
        super QuadTree[E]
 
-       # the width of the current node of the QuadTree
+       # Width of this node of the QuadTree
        var width: Numeric
-       # the height of the current node of the QuadTree
+
+       # Height of this node of the QuadTree
        var height: Numeric
 
        init
@@ -220,30 +244,35 @@ class SQuadTree[E: Boxed[Numeric]]
                center = new Point[Numeric](width.div(2), height.div(2))
        end
 
-       init with_parent(l: Int, c: Point[Numeric], w: Numeric, h: Numeric, p: QuadTree[E])
+       # Create a child node to `parent`
+       init with_parent(l: Int, c: Point[Numeric], w, h: Numeric, parent: QuadTree[E])
        do
                init(l, w, h)
                center = c
-               self.parent_node = p
+               self.parent_node = parent
        end
 
        redef fun subdivide
        do
-               child0 = new SQuadTree[E].with_parent(self.item_limit, new Point[Numeric](self.center.x.div(2), self.center.y.div(2)), self.width.div(2), self.height.div(2), self)
-               child1 = new SQuadTree[E].with_parent(self.item_limit, new Point[Numeric](self.center.x.div(2), (self.center.y.mul(3)).div(2)), self.width.div(2), self.height.div(2), self)
-               child2 = new SQuadTree[E].with_parent(self.item_limit, new Point[Numeric]((self.center.x.mul(3)).div(2), (self.center.y.mul(3)).div(2)), self.width.div(2), self.height.div(2), self)
-               child3 = new SQuadTree[E].with_parent(self.item_limit, new Point[Numeric]((self.center.x.mul(3)).div(2), self.center.y.div(2)), self.width.div(2), self.height.div(2), self)
+               var center = center
+               assert center != null
+
+               children[0] = new SQuadTree[E].with_parent(self.item_limit, new Point[Numeric](center.x.div(2), center.y.div(2)), self.width.div(2), self.height.div(2), self)
+               children[1] = new SQuadTree[E].with_parent(self.item_limit, new Point[Numeric](center.x.div(2), (center.y.mul(3)).div(2)), self.width.div(2), self.height.div(2), self)
+               children[2] = new SQuadTree[E].with_parent(self.item_limit, new Point[Numeric]((center.x.mul(3)).div(2), (center.y.mul(3)).div(2)), self.width.div(2), self.height.div(2), self)
+               children[3] = new SQuadTree[E].with_parent(self.item_limit, new Point[Numeric]((center.x.mul(3)).div(2), center.y.div(2)), self.width.div(2), self.height.div(2), self)
        end
 
        redef fun to_s
        do
-               var s = "center : {center.to_s}\n"
+               var s = "center : {center or else "null"}\n"
                for d in data do s += d.to_s
-               if child0 != null then
-                       s += "\nchild0: {child0.to_s}\n"
-                       s += "   child1: {child1.to_s}\n"
-                       s += "   child2: {child2.to_s}\n"
-                       s += "   child3: {child3.to_s}\n"
+
+               if children.not_empty then
+                       s += "\n   children[0]: {children[0]}\n"
+                       s += "   children[1]: {children[1]}\n"
+                       s += "   children[2]: {children[2]}\n"
+                       s += "   children[3]: {children[3]}\n"
                end
                return s
        end
diff --git a/lib/gmp/gmp.nit b/lib/gmp/gmp.nit
new file mode 100644 (file)
index 0000000..66bd703
--- /dev/null
@@ -0,0 +1,399 @@
+# 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.
+
+# Multi precision integer and rational number using gmp lib
+module gmp
+
+private import native_gmp
+
+redef class Numeric
+
+    # The BigInt equivalent of `self`
+    fun to_bi: BigInt do return self.to_i.to_bi
+
+    # The Ratio equivalent of `self`
+    fun to_r: Ratio do return self.to_f.to_r
+
+end
+
+redef class Text
+
+    # Is `self` a well-formed BigInt (i.e. parsable via `to_bi`)
+    #
+    #     assert "123".is_bi
+    #     assert "-123".is_bi
+    #     assert not "0b1011".is_bi
+    #     assert not "123u8".is_bi
+    #     assert not "Not a BigInt".is_bi
+    fun is_bi: Bool do
+        var pre = prefix("-")
+        if pre != null then
+            return pre.text_after.is_dec
+        else
+            return is_dec
+        end
+    end
+
+    # Is `self` a well-formed Ratio (i.e. parsable via `to_r`)
+    #
+    #     assert "123".is_r
+    #     assert "-123".is_r
+    #     assert "1/2".is_r
+    #     assert "-1/2".is_r
+    #     assert not "-1/-2".is_r
+    #     assert not "0b1011".is_r
+    #     assert not "123u8".is_r
+    #     assert not "Not an Ratio".is_r
+    fun is_r: Bool do
+        var frac = split_once_on('/')
+        if frac.length == 2 then
+            return frac[0].is_bi and frac[1].is_dec
+        else
+            return is_bi
+        end
+    end
+
+    # If `self` contains a BigInt, return the corresponding BigInt
+    #
+    #     assert("123".to_bi == 123.to_bi)
+    #     assert("-123".to_bi == -123.to_bi)
+    fun to_bi: BigInt do
+        assert is_bi
+        var tmp = new NativeMPZ
+        tmp.set_str(self.to_cstring, 10i32)
+        return new BigInt(tmp)
+    end
+
+    # If `self` contains a Ratio, return the corresponding Ratio
+    #
+    #     assert("123".to_r == 123.to_r)
+    #     assert("-123".to_r == -123.to_r)
+    #     assert("1/2".to_r == 0.5.to_r)
+    #     assert("-1/2".to_r == -0.5.to_r)
+    fun to_r: Ratio do
+        assert is_r
+        var tmp = new NativeMPQ
+        tmp.set_str self.to_cstring
+        return new Ratio(tmp)
+    end
+end
+
+redef class Float
+    redef fun to_bi do
+        var tmp = new NativeMPZ
+        tmp.set_d self
+        return new BigInt(tmp)
+    end
+
+    redef fun to_r do
+        var tmp = new NativeMPQ
+        tmp.set_d self
+        return new Ratio(tmp)
+    end
+end
+
+redef class Int
+    redef fun to_bi do
+        var tmp = new NativeMPZ
+        tmp.set_si self
+        return new BigInt(tmp)
+    end
+
+    redef fun to_r do
+        var tmp = new NativeMPQ
+        tmp.set_si(self, 1)
+        return new Ratio(tmp)
+    end
+end
+
+# Multi precision Integer numbers.
+class BigInt
+    super Discrete
+    super Numeric
+    super FinalizableOnce
+
+    redef type OTHER: BigInt
+
+    private var val: NativeMPZ
+
+    redef fun successor(i) do return self + i.to_bi
+    redef fun predecessor(i) do return self - i.to_bi
+
+    redef fun hash do return self.to_i
+
+    redef fun <=>(i) do
+        var res = val.cmp(i.val)
+        if (res) < 0 then
+            return -1
+        else if (res) > 0 then
+            return 1
+        else
+            return 0
+        end
+    end
+
+    redef fun ==(i) do return i isa BigInt and (self <=> i) == 0
+    redef fun <=(i) do return (self <=> i) <= 0
+    redef fun <(i) do return (self <=> i) < 0
+    redef fun >=(i) do return (self <=> i) >= 0
+    redef fun >(i) do return (self <=> i) > 0
+
+
+    #     assert(2.to_bi + 2.to_bi == 4.to_bi)
+    redef fun +(i) do
+        var res = new NativeMPZ
+        val.add(res, i.val)
+        return new BigInt(res)
+    end
+
+    #     assert(-(2.to_bi) == (-2).to_bi)
+    redef fun - do
+        var res = new NativeMPZ
+        val.neg res
+        return new BigInt(res)
+    end
+
+    #     assert(2.to_bi - 2.to_bi == 0.to_bi)
+    redef fun -(i) do
+        var res = new NativeMPZ
+        val.sub(res, i.val)
+        return new BigInt(res)
+    end
+
+    #     assert(2.to_bi * 2.to_bi == 4.to_bi)
+    redef fun *(i) do
+        var res = new NativeMPZ
+        val.mul(res, i.val)
+        return new BigInt(res)
+    end
+
+    #     assert(3.to_bi / 2.to_bi == 1.to_bi)
+    redef fun /(i) do
+        var res = new NativeMPZ
+        val.tdiv_q(res, i.val)
+        return new BigInt(res)
+    end
+
+    # Modulo of `self` with `i`.
+    #
+    # Finds the remainder of the division of `self` by `i`.
+    #
+    #     assert(5.to_bi % 2.to_bi == 1.to_bi)
+    fun %(i: BigInt): BigInt do
+        var res = new NativeMPZ
+        val.mod(res, i.val)
+        return new BigInt(res)
+    end
+
+    # Returns `self` raised to the power of `e`.
+    #
+    #     assert(3.to_bi ** 2 == 9.to_bi)
+    fun **(e: Int): BigInt do
+        var res = new NativeMPZ
+        var pow = new UInt64
+        pow.set_si e
+        val.pow_ui(res, pow)
+        pow.free
+        return new BigInt(res)
+    end
+
+    # The absolute value of `self`.
+    #
+    #     assert((-3).to_bi.abs == 3.to_bi)
+    fun abs: BigInt do
+        var res = new NativeMPZ
+        val.abs res
+        return new BigInt(res)
+    end
+
+    # Returns the greatest common divisor of `self` and `i`
+    #
+    #     assert(15.to_bi.gcd(10.to_bi) == 5.to_bi)
+    fun gcd(i: BigInt): BigInt do
+        var res = new NativeMPZ
+        val.gcd(res, i.val)
+        return new BigInt(res)
+    end
+
+    # Determine if `self` is a prime number.
+    # Return 2 if `self` is prime, return 1 if `self` is probably prime and
+    # return 0 if `self` is definitely not a prime number.
+    #
+    # This function begins by trying some divisions with small number to find if
+    # there is other factors then `self` and one. After that, it uses the
+    # Miller-Rabin probabilistic primality tests. The probability of a non-prime
+    # being identified as probably prime with that test is less than
+    # `4^(-reps)`. It is recommended to use a `reps` value between 15 and 50.
+    #
+    #     assert((0x10001).to_bi.probab_prime(15) == 2)
+    fun probab_prime(reps: Int): Int do
+        return val.probab_prime_p(reps.to_i32)
+    end
+
+    # Return the next prime number greater than `self`.
+    # This fonction uses a probabilistic algorithm.
+    #
+    #     assert(11.to_bi.next_prime == 13.to_bi)
+    fun next_prime: BigInt do
+        var res = new NativeMPZ
+        val.nextprime res
+        return new BigInt(res)
+    end
+
+    #     assert(11.to_bi.zero == 0.to_bi)
+    redef fun zero do return new BigInt(new NativeMPZ)
+
+    #     assert(11.to_bi.value_of(4) == 4.to_bi)
+    redef fun value_of(i) do return i.to_bi
+
+    #     assert(11.to_bi.to_i == 11)
+    redef fun to_i do return val.get_si
+
+    #     assert(11.to_bi.to_f == 11.0)
+    redef fun to_f do return val.get_d
+
+    #     assert(11.to_bi.to_s == "11")
+    redef fun to_s do
+        var cstr = val.get_str(10.to_i32)
+        var str = cstr.to_s
+        cstr.free
+        return str
+    end
+
+    redef fun to_bi do return self
+
+    #     assert(123.to_bi.to_r == 123.to_r)
+    redef fun to_r do
+        var tmp = new NativeMPQ
+        tmp.set_z val
+        return new Ratio(tmp)
+    end
+
+    #     assert(3.to_bi.distance(6.to_bi) == -3)
+    redef fun distance(i) do return (self - i).to_i
+
+    redef fun finalize_once do val.finalize
+end
+
+# Multi precision Rational numbers.
+#
+#     assert((0.2 + 0.1) == 0.30000000000000004)
+#     assert(("1/5".to_r + "1/10".to_r) == "3/10".to_r)
+class Ratio
+    super Numeric
+    super FinalizableOnce
+
+    redef type OTHER: Ratio
+
+    private var val: NativeMPQ
+
+    redef fun hash do return self.to_i
+
+    redef fun <=>(r) do
+        var res = val.cmp(r.val)
+        if (res) < 0 then
+            return -1
+        else if (res) > 0 then
+            return 1
+        else
+            return 0
+        end
+    end
+
+    redef fun ==(r) do return r isa Ratio and (self <=> r) == 0
+    redef fun <=(r) do return (self <=> r) <= 0
+    redef fun <(r) do return (self <=> r) < 0
+    redef fun >=(r) do return (self <=> r) >= 0
+    redef fun >(r) do return (self <=> r) > 0
+
+    #     assert("3/2".to_r + "5/2".to_r == 4.to_r)
+    redef fun +(r) do
+        var res = new NativeMPQ
+        val.add(res, r.val)
+        return new Ratio(res)
+    end
+
+    #     assert( -("1/2".to_r) == ("-1/2").to_r)
+    redef fun - do
+        var res = new NativeMPQ
+        val.neg res
+        return new Ratio(res)
+    end
+
+    #     assert("5/2".to_r - "3/2".to_r == 1.to_r)
+    redef fun -(r) do
+        var res = new NativeMPQ
+        val.sub(res, r.val)
+        return new Ratio(res)
+    end
+
+    #     assert("3/2".to_r * 2.to_r == 3.to_r)
+    redef fun *(r) do
+        var res = new NativeMPQ
+        val.mul(res, r.val)
+        return new Ratio(res)
+    end
+
+    #     assert(3.to_r / 2.to_r == "3/2".to_r)
+    redef fun /(r) do
+        var res = new NativeMPQ
+        val.div(res, r.val)
+        return new Ratio(res)
+    end
+
+    # The absolute value of `self`.
+    #
+    #     assert((-3.to_r).abs == 3.to_r)
+    #     assert(3.to_r.abs == 3.to_r)
+    fun abs: Ratio do
+        var res = new NativeMPQ
+        val.abs res
+        return new Ratio(res)
+    end
+
+    #     assert((3.to_r).zero == 0.to_r)
+    redef fun zero do return new Ratio(new NativeMPQ)
+
+    #     assert((3.to_r).value_of(2) == 2.to_r)
+    redef fun value_of(n) do return n.to_r
+
+    #     assert("7/2".to_r.to_i == 3)
+    redef fun to_i do
+        var res = new NativeMPZ
+        val.numref.tdiv_q(res, val.denref)
+        return res.get_si
+    end
+
+    #     assert(3.to_r.to_f == 3.0)
+    redef fun to_f do return val.get_d
+
+    #     assert(3.to_r.to_s == "3")
+    redef fun to_s do
+        var cstr = val.get_str(10i32)
+        var str = cstr.to_s
+        cstr.free
+        return str
+    end
+
+    #     assert("7/2".to_r.to_bi == 3.to_bi)
+    redef fun to_bi do
+        var res = new NativeMPZ
+        val.numref.tdiv_q(res, val.denref)
+        return new BigInt(res)
+    end
+
+    redef fun to_r do return self
+
+    redef fun finalize_once do val.finalize
+end
index 81688d9..dd68f12 100644 (file)
@@ -16,6 +16,7 @@
 module more_collections is serialize
 
 import serialization
+import poset
 
 # Simple way to store an `HashMap[K, Array[V]]`
 #
@@ -102,6 +103,35 @@ class MultiHashMap[K, V]
                        if x.is_empty then keys.remove(k)
                end
        end
+
+       # Search the values in `pe.greaters` from the most smaller elements that have a value.
+       #
+       # Elements without values are ignored.
+       #
+       # Basically, values defined in nearest greater elements of `pe` are inherited.
+       #
+       # ~~~
+       # var pos = new POSet[String]
+       # pos.add_chain(["E", "D", "C", "B", "A"])
+       # pos.add_chain(["D", "X", "B"])
+       #
+       # var map = new MultiHashMap[String, String]
+       # map["A"].append(["a", "1"])
+       # map["C"].append(["c", "2"])
+       # map["X"].append(["x", "2"])
+       # map["E"].add "e"
+       #
+       # assert map.lookup_joined_values(pos["B"]).has_exactly(["a", "1"])
+       # assert map.lookup_joined_values(pos["C"]).has_exactly(["c", "2"])
+       # assert map.lookup_joined_values(pos["D"]).has_exactly(["c", "x", "2"])
+       # ~~~
+       fun lookup_joined_values(pe: POSetElement[K]): Set[V]
+       do
+               var res = new Set[V]
+               for k in pe.poset.select_smallest(filter_keys(pe.greaters)) do res.add_all self[k]
+               return res
+
+       end
 end
 
 # Simple way to store an `HashMap[K1, HashMap[K2, V]]`
@@ -214,6 +244,61 @@ class HashMap3[K1, K2, K3, V]
        fun clear do level1.clear
 end
 
+# Simple way to store an `HashMap[K1, HashMap[K2, HashMap[K3, HashMap[K4, V]]]]`
+#
+# ~~~~
+# var hm4 = new HashMap4[Int, String, Int, String, Float]
+# hm4[1, "one", 11, "un"] = 1.0
+# hm4[2, "two", 22, "deux"] = 2.0
+# assert hm4[1, "one", 11, "un"] == 1.0
+# assert hm4[2, "not-two", 22, "deux"] == null
+# ~~~~
+class HashMap4[K1, K2, K3, K4, V]
+
+       private var level1 = new HashMap[K1, HashMap3[K2, K3, K4, V]]
+
+       # Return the value associated to the keys `k1`, `k2`, `k3` and `k4`.
+       # Return `null` if no such a value.
+       fun [](k1: K1, k2: K2, k3: K3, k4: K4): nullable V
+       do
+               var level1 = self.level1
+               var level2 = level1.get_or_null(k1)
+               if level2 == null then return null
+               return level2[k2, k3, k4]
+       end
+
+       # Set `v` the value associated to the keys `k1`, `k2`, `k3` and `k4`.
+       fun []=(k1: K1, k2: K2, k3: K3, k4: K4, v: V)
+       do
+               var level1 = self.level1
+               var level2 = level1.get_or_null(k1)
+               if level2 == null then
+                       level2 = new HashMap3[K2, K3, K4, V]
+                       level1[k1] = level2
+               end
+               level2[k2, k3, k4] = v
+       end
+
+       # Remove the item at `k1`, `k2`, `k3` and `k4`
+       fun remove_at(k1: K1, k2: K2, k3: K3, k4: K4)
+       do
+               var level1 = self.level1
+               var level2 = level1.get_or_null(k1)
+               if level2 == null then return
+               level2.remove_at(k2, k3, k4)
+       end
+
+       # Is there a value at `k1, k2, k3, k4`?
+       fun has(k1: K1, k2: K2, k3: K3, k4: K4): Bool
+       do
+               if not level1.keys.has(k1) then return false
+               return level1[k1].has(k2, k3, k4)
+       end
+
+       # Remove all items
+       fun clear do level1.clear
+end
+
 # A map with a default value.
 #
 # ~~~~
index d512462..665ecdb 100644 (file)
@@ -290,7 +290,7 @@ class Neo4jClient
 
                # Build the query.
                var buffer = new Buffer
-               buffer.append "match n where \{label_0\} in labels(n)"
+               buffer.append "match (n) where \{label_0\} in labels(n)"
                for i in [1..labels.length[ do
                        buffer.append " and \{label_{i}\} in labels(n)"
                end
index 98205ac..767b27d 100644 (file)
@@ -729,3 +729,84 @@ class POSetElement[E]
                end
        end
 end
+
+redef class MapRead[K, V]
+       # Return all elements of `keys` that have a value.
+       #
+       # ~~~
+       # var map = new Map[String, String]
+       # map["A"] = "a"
+       # map["B"] = "b"
+       # map["C"] = "c"
+       #
+       # assert map.filter_keys(["B"]) == ["B"]
+       # assert map.filter_keys(["A", "Z", "C"]) == ["A", "C"]
+       # assert map.filter_keys(["X", "Y", "Z"]).is_empty
+       # ~~~
+       #
+       # `has_key` is used to filter.
+       fun filter_keys(keys: Collection[nullable Object]): Array[K]
+       do
+               var res = new Array[K]
+               for e in keys do
+                       if has_key(e) then res.add e
+               end
+               return res
+       end
+
+       # Search all the values in `pe.greaters`.
+       #
+       # Elements without values are ignored.
+       #
+       # Basically, values defined in all greater elements of `pe` are inherited.
+       #
+       # ~~~
+       # var pos = new POSet[String]
+       # pos.add_chain(["E", "D", "C", "B", "A"])
+       # pos.add_chain(["D", "X", "B"])
+       #
+       # var map = new HashMap[String, String]
+       # map["A"] = "a"
+       # map["C"] = "c"
+       # map["X"] = "x"
+       # map["E"] = "e"
+       #
+       # assert map.lookup_all_values(pos["B"]).has_exactly(["a"])
+       # assert map.lookup_all_values(pos["C"]).has_exactly(["a", "c"])
+       # assert map.lookup_all_values(pos["D"]).has_exactly(["a", "c", "x"])
+       # ~~~
+       fun lookup_all_values(pe: POSetElement[K]): Set[V]
+       do
+               var res = new Set[V]
+               for k in filter_keys(pe.greaters) do res.add self[k]
+               return res
+       end
+
+       # Combine the values in `pe.greaters` from the most smaller elements that have a value.
+       #
+       # Elements without values are ignored.
+       #
+       # Basically, values defined in nearest greater elements of `pe` are inherited.
+       #
+       # ~~~
+       # var pos = new POSet[String]
+       # pos.add_chain(["E", "D", "C", "B", "A"])
+       # pos.add_chain(["D", "X", "B"])
+       #
+       # var map = new HashMap[String, String]
+       # map["A"] = "a"
+       # map["C"] = "c"
+       # map["X"] = "x"
+       # map["E"] = "e"
+       #
+       # assert map.lookup_values(pos["B"]).has_exactly(["a"])
+       # assert map.lookup_values(pos["C"]).has_exactly(["c"])
+       # assert map.lookup_values(pos["D"]).has_exactly(["c", "x"])
+       # ~~~
+       fun lookup_values(pe: POSetElement[K]): Set[V]
+       do
+               var res = new Set[V]
+               for k in pe.poset.select_smallest(filter_keys(pe.greaters)) do res.add self[k]
+               return res
+       end
+end
index 8d09d74..be3e41e 100644 (file)
@@ -134,3 +134,7 @@ You may want to map the command to a shortcut by adding the following code to `~
 " Map the NitExecute function to Ctrl-F
 map <C-f> :NitExecute<enter>
 ~~~
+
+# Test case for syntax highlighting
+To check the accuracy of language definition files, the module
+`../tests/test_syntax.nit` can be used as a demo.
index ee34149..3d795c2 100644 (file)
@@ -1,6 +1,6 @@
 # This is a basic install of Nit on a debian base.
 
-FROM debian:jessie
+FROM debian:stretch
 MAINTAINER Jean Privat <jean@pryen.org>
 
 # Install dependencies
index e6bfe66..eb7f26d 100644 (file)
@@ -14,8 +14,10 @@ RUN dpkg --add-architecture i386 \
                libgles1-mesa-dev \
                libgles2-mesa-dev \
                libgtk-3-dev \
+               libgmp-dev \
                libncurses5-dev \
                libpq-dev \
+               libreadline-dev \
                libsdl-image1.2-dev \
                libsdl-ttf2.0-dev \
                libsdl1.2-dev \
@@ -29,6 +31,7 @@ RUN dpkg --add-architecture i386 \
                # Packages needed for contrib, platforms and FFI
                ant \
                clang \
+               cmake \
                default-jdk \
                file \
                inkscape \
@@ -50,15 +53,27 @@ RUN mkdir -p /opt \
        && rm android-sdk-linux.tgz \
        && echo y | android-sdk-linux/tools/android update sdk -a --no-ui --filter \
                # Hardcode minimal known working things
-               platform-tools,build-tools-22.0.1,android-22,android-10 \
+               platform-tools,build-tools-22.0.1,android-22,android-21,android-19,android-16,android-15,android-10 \
        # Android NDK
        && curl http://dl.google.com/android/repository/android-ndk-r11c-linux-x86_64.zip -o android-ndk.zip \
        && unzip -q android-ndk.zip \
+       && chmod -R a+X /opt \
        && ln -s android-ndk-r11c android-ndk \
        && rm android-ndk.zip \
        && printf "PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools:$ANDROID_NDK\nexport PATH\n" >> "/etc/profile.d/android.sh"
 
+# Install OpenGL validator
+RUN git clone https://github.com/KhronosGroup/glslang.git \
+       && mkdir -p glslang/build \
+       && cd glslang/build \
+       && cmake .. \
+       && make \
+       && make
+
 # Setup environment variables
 ENV ANDROID_HOME /opt/android-sdk-linux
 ENV ANDROID_NDK /opt/android-ndk
 ENV PATH $PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools:$ANDROID_NDK
+ENV JAVA_HOME=/usr/lib/jvm/default-java/
+ENV JNI_LIB_PATH=$JAVA_HOME/jre/lib/amd64/server/
+ENV LD_LIBRARY_PATH=$JAVA_HOME/jre/lib/amd64/server/
index 2e7a08e..68889e3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
+       This file is part of NIT ( http://www.nitlanguage.org ).
 
- Author: Alexis Laferrière <alexis.laf@xymus.net>
- Copyright (C) 2009 Alexis Laferrière <alexis.laf@xymus.net>
+       Licensed under the Apache License, Version 2.0 (the "License");
+       you may not use this file except in compliance with the License.
+       You may obtain a copy of the License at
 
- Based on ruby.lang
- Copyright (C) 2004 Archit Baweja <bighead@users.sourceforge.net>
- Copyright (C) 2005 Michael Witrant <mike@lepton.fr>
- Copyright (C) 2006 Gabriel Bauman <gbauman@gmail.com>
+               http://www.apache.org/licenses/LICENSE-2.0
 
- This library is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
+       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.
+-->
+<language id="nit" _name="Nit" version="2.0" _section="Source">
+       <metadata>
+               <!-- TODO: Register the media type -->
+               <property name="mimetypes">text/x-nit</property>
+               <property name="globs">*.nit</property>
+               <property name="line-comment-start">#</property>
+       </metadata>
 
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
+       <styles>
+               <style id="attribute"          _name="Attribute"             map-to="def:builtin"/>
+               <style id="boolean"            _name="Boolean value"         map-to="def:boolean"/>
+               <style id="binary"             _name="Binary number"         map-to="def:base-n-integer"/>
+               <style id="builtin-annotation" _name="Built-in Annotation"   map-to="def:keyword"/>
+               <style id="character"          _name="Character"             map-to="def:character"/>
+               <style id="decimal"            _name="Decimal number"        map-to="def:decimal"/>
+               <style id="escaped-character"  _name="Escaped Character"     map-to="def:special-char"/>
+               <style id="extern-code"        _name="Extern Code"           map-to="def:preprocessor"/>
+               <style id="floating-point"     _name="Floating point number" map-to="def:floating-point"/>
+               <style id="hexadecimal"        _name="Hexadecimal number"    map-to="def:base-n-integer"/>
+               <style id="keyword"            _name="Keyword"               map-to="def:keyword"/>
+               <style id="octal"              _name="Octal number"          map-to="def:base-n-integer"/>
+               <style id="module-handler"     _name="Module Handler"        map-to="def:preprocessor"/>
+               <style id="null-value"         _name="Null Value"            map-to="def:special-constant"/>
+               <style id="reserved"           _name="Reserved keyword"      map-to="def:reserved"/>
+               <style id="special-variable"   _name="Special Variable"      map-to="def:builtin"/>
+               <style id="string"             _name="String"                map-to="def:string"/>
+               <style id="type"               _name="Data Type"             map-to="def:type"/>
 
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+               <!--
+                       The following styles do not inherit from `def` because most style
+                       schemes highlight them too much.
+               -->
+               <style id="operator"           _name="Operator"/>              <!-- "def:operator" -->
+               <style id="variable"           _name="Variable or Method"/>    <!-- "def:identifier" -->
 
--->
-<language id="nit" _name="Nit" version="2.0" _section="Sources">
-  <metadata>
-    <property name="mimetypes">text/x-nit</property>
-    <property name="globs">*.nit</property>
-    <property name="line-comment-start">#</property>
-  </metadata>
-
-  <styles>
-    <style id="escape"               _name="Escaped Character"     map-to="def:special-char"/>
-    <style id="comment"              _name="Comment"               map-to="def:comment"/>
-    <style id="attribute-definition" _name="Attribute Definition"  map-to="def:statement"/>
-    <style id="module-handler"       _name="Module handler"        map-to="def:preprocessor"/>
-    <style id="keyword"              _name="Keyword"               map-to="def:keyword"/>
-    <style id="null-value"           _name="Nil Constant"          map-to="def:special-constant"/>
-    <style id="boolean"              _name="Boolean value"         map-to="def:boolean"/>
-    <style id="floating-point"       _name="Floating point number" map-to="def:floating-point"/>
-    <style id="decimal"              _name="Decimal number"        map-to="def:decimal"/>
-    <style id="base-n-integer"       _name="Base-N number"         map-to="def:base-n-integer"/>
-    <style id="string"               _name="String"                map-to="def:string"/>
-    <style id="builtin"              _name="Builtin"               map-to="def:type"/>
-    <style id="class-name"           _name="Constant"              map-to="def:type"/>
-    <style id="symbol"               _name="Symbol"                map-to="def:string"/>
-    <style id="special-variable"     _name="Special Variable"      map-to="def:identifier"/>
-    <style id="predefined-variable"  _name="Predefined Variable"   map-to="def:identifier"/>
-    <style id="variable"             _name="Variable"              map-to="def:identifier"/>
-    <style id="extern-code"          _name="Extern code"           map-to="def:comment"/>
-  </styles>
-
-  <definitions>
-
-    <context id="escape" style-ref="escape">
-      <match>\\((0-7){3}|(x[a-fA-F0-9]{2})|(c\S)|([CM]-\S)|(M-C-\S)|.)</match>
-    </context>
-
-    <context id="extern-code" style-ref="extern-code">
-        <start>`\{</start>
-        <end>`\}</end>
-        <include>
-            <context ref="def:in-comment"/>
-        </include>
-    </context>
-
-    <context id="definitions" style-ref="keyword">
-      <keyword>class</keyword>
-      <keyword>fun</keyword>
-      <keyword>redef</keyword>
-      <keyword>var</keyword>
-      <keyword>module</keyword>
-      <keyword>type</keyword>
-      <keyword>universal</keyword>
-      <keyword>enum</keyword>
-    </context>
-
-    <context id="module-handlers" style-ref="module-handler">
-      <keyword>import</keyword>
-    </context>
-
-    <context id="keywords" style-ref="keyword">
-      <keyword>do</keyword>
-      <keyword>end</keyword>
-      <keyword>catch</keyword>
-      <keyword>intrude</keyword>
-      <keyword>private</keyword>
-      <keyword>if</keyword>
-      <keyword>then</keyword>
-      <keyword>else</keyword>
-      <keyword>while</keyword>
-      <keyword>for</keyword>
-      <keyword>assert</keyword>
-      <keyword>is</keyword>
-      <keyword>abstract</keyword>
-      <keyword>intern</keyword>
-      <keyword>extern</keyword>
-      <keyword>public</keyword>
-      <keyword>protected</keyword>
-      <keyword>or</keyword>
-      <keyword>as</keyword>
-      <keyword>isa</keyword>
-      <keyword>break</keyword>
-      <keyword>continue</keyword>
-      <keyword>return</keyword>
-      <keyword>label</keyword>
-      <keyword>abort</keyword>
-      <keyword>nullable</keyword>
-      <keyword>new</keyword>
-      <keyword>special</keyword>
-      <keyword>super</keyword>
-      <keyword>init</keyword>
-      <keyword>in</keyword>
-      <keyword>or</keyword>
-      <keyword>and</keyword>
-      <keyword>not</keyword>
-      <keyword>writable</keyword>
-      <keyword>readable</keyword>
-    </context>
-
-    <context id="special-variables" style-ref="special-variable">
-      <keyword>self</keyword>
-    </context>
-
-    <context id="instance-variables" style-ref="variable">
-      <match>(::)?\b_[a-zA-Z_][a-zA-Z0-9_]*</match>
-    </context>
-
-    <context id="class-name" style-ref="class-name">
-      <match>(::)?\b[A-Z][A-Za-z0-9_]*\b</match>
-    </context>
-
-    <context id="null-value" style-ref="null-value">
-      <keyword>null</keyword>
-    </context>
-
-    <context id="boolean" style-ref="boolean">
-      <keyword>false</keyword>
-      <keyword>true</keyword>
-    </context>
-    
-    <define-regex id="underscore_num">\d(_?\d)*</define-regex>
-
-    <define-regex id="float" extended="true">
-      ( (\%{underscore_num})?\.\%{underscore_num} | \%{underscore_num}\. ) |
-      ( (\%{underscore_num}|(\%{underscore_num})?\.\%{underscore_num}|\%{underscore_num}\.)[eE][+-]?\%{underscore_num} )
-    </define-regex>
-
-    <context id="float" style-ref="floating-point">
-      <match>(?&lt;![\w\.])\%{float}(?![\w\.])</match>
-    </context>
-
-    <context id="decimal" style-ref="decimal">
-      <match>(?&lt;![\w\.])([1-9](_?[0-9])*|0)(?![\w\.])</match>
-    </context>
-
-    <!-- in double quotes and backticks -->
-    <!-- FIXME: really would like for the syntax highlight to go back
-         to none here, as any ruby code could go here -->
-    <context id="complex-interpolation" style-ref="escape">
-      <start>{</start>
-      <end>}</end>
-      <include>
-        <context ref="nit:*"/>
-      </include>
-    </context>
-
-    <!-- ruby strings do not end at line end,
-         so we cannot use def:string
-         (parts lifted from perl.lang) -->
-    <context id="double-quoted-string" style-ref="string">
-      <start>"</start>
-      <end>"</end>
-      <include>
-        <context ref="escape"/>
-        <context ref="def:line-continue"/>
-        <context ref="complex-interpolation"/>
-      </include>
-    </context>
-
-    <context id="single-quoted-string" style-ref="string">
-      <start>'</start>
-      <end>'</end>
-      <include>
-        <context style-ref="escape">
-          <match>\\['\\]</match>
-        </context>
-      </include>
-    </context>
-
-    <context id="nit">
-      <include>
-        <context ref="def:shebang"/>
-        <context ref="def:shell-like-comment"/>
-        <context ref="double-quoted-string"/>
-        <context ref="single-quoted-string"/>
-        <context ref="definitions"/>
-        <context ref="module-handlers"/>
-        <context ref="keywords"/>
-        <context ref="special-variables"/>
-        <context ref="instance-variables"/>
-        <context ref="class-name"/>
-        <context ref="null-value"/>
-        <context ref="boolean"/>
-        <context ref="float"/>
-        <context ref="decimal"/>
-        <context ref="extern-code"/>
-      </include>
-    </context>
-
-  </definitions>
+               <!-- TODO: Implement `bad_string` and `bad_char`?
+               <style id="error"              _name="Error"                 map-to="def:error"/>
+               -->
+       </styles>
+
+       <default-regex-options extended="true"/>
+       <keyword-char-class>[A-Za-z0-9_]</keyword-char-class>
+
+       <definitions>
+               <define-regex id="space" extended="false">[ \n\r\t]</define-regex>
+
+               <!-- Keywords and operators -->
+
+               <context id="reserved" style-ref="reserved">
+                       <keyword>package</keyword>
+                       <keyword>yield</keyword>
+               </context>
+
+               <context id="kwimport" style-ref="module-handler">
+                       <keyword>import</keyword>
+               </context>
+
+               <context id="kwnull" style-ref="null-value">
+                       <keyword>null</keyword>
+               </context>
+
+               <context id="keyword" style-ref="keyword">
+                       <keyword>abort</keyword>
+                       <keyword>abstract</keyword>
+                       <keyword>as</keyword>
+                       <keyword>assert</keyword>
+                       <keyword>break</keyword>
+                       <keyword>catch</keyword>
+                       <keyword>class</keyword>
+                       <keyword>continue</keyword>
+                       <keyword>__debug__</keyword>
+                       <keyword>do</keyword>
+                       <keyword>else</keyword>
+                       <keyword>end</keyword>
+                       <keyword>enum</keyword>
+                       <keyword>extern</keyword>
+                       <keyword>for</keyword>
+                       <keyword>fun</keyword>
+                       <keyword>if</keyword>
+                       <keyword>init</keyword>
+                       <keyword>in</keyword>
+                       <keyword>interface</keyword>
+                       <keyword>intrude</keyword>
+                       <keyword>isa</keyword>
+                       <keyword>is</keyword>
+                       <keyword>isset</keyword>
+                       <keyword>label</keyword>
+                       <keyword>loop</keyword>
+                       <keyword>module</keyword>
+                       <keyword>new</keyword>
+                       <keyword>nullable</keyword>
+                       <keyword>once</keyword>
+                       <keyword>private</keyword>
+                       <keyword>protected</keyword>
+                       <keyword>public</keyword>
+                       <keyword>redef</keyword>
+                       <keyword>return</keyword>
+                       <keyword>subset</keyword>
+                       <keyword>super</keyword>
+                       <keyword>then</keyword>
+                       <keyword>type</keyword>
+                       <keyword>universal</keyword>
+                       <keyword>var</keyword>
+                       <keyword>while</keyword>
+                       <keyword>with</keyword>
+               </context>
+
+               <context id="builtin-annotation" style-ref="builtin-annotation">
+                       <keyword>autoinit</keyword>
+                       <keyword>auto_inspect</keyword>
+                       <keyword>cflags</keyword>
+                       <keyword>conditional</keyword>
+                       <keyword>deprecated</keyword>
+                       <keyword>fixed</keyword>
+                       <keyword>generated</keyword>
+                       <keyword>intern</keyword>
+                       <keyword>lateinit</keyword>
+                       <keyword>lazy</keyword>
+                       <keyword>ldflags</keyword>
+                       <keyword>light_ffi</keyword>
+                       <keyword>new_annotation</keyword>
+                       <keyword>noautoinit</keyword>
+                       <keyword>noinit</keyword>
+                       <keyword>nosuper</keyword>
+                       <keyword>no_warning</keyword>
+                       <keyword>old_style_init</keyword>
+                       <keyword>optional</keyword>
+                       <keyword>pkgconfig</keyword>
+                       <keyword>platform</keyword>
+                       <keyword>readonly</keyword>
+                       <keyword>writable</keyword>
+               </context>
+
+               <context id="boolean" style-ref="boolean">
+                       <keyword>true</keyword>
+                       <keyword>false</keyword>
+               </context>
+
+               <context id="special-variable" style-ref="special-variable">
+                       <keyword>self</keyword>
+               </context>
+
+               <context id="operator-keyword" style-ref="keyword">
+                       <keyword>and</keyword>
+                       <keyword>implies</keyword>
+                       <keyword>not</keyword>
+                       <keyword>or</keyword>
+               </context>
+
+               <context id="operator-punctuation" style-ref="operator">
+                       <match>
+                               \^=? |
+                               ~ |
+                               &lt;&lt;?=? |
+                               &lt;=&gt; |
+                               ==? |
+                               &gt;&gt;?=? |
+                               \| |
+                               -=? |
+                               , |
+                               ; |
+                               ::? |
+                               !=? |
+                               /=? |
+                               \.{1,3} |
+                               \( |
+                               \) |
+                               \[ |
+                               \] |
+                               @ |
+                               \*\*?=? |
+                               &amp;=? |
+                               %=? |
+                               \+=?
+                       </match>
+               </context>
+
+               <!-- Identifiers -->
+
+               <context id="attribute" style-ref="attribute">
+                       <match>\%[ _[a-z][A-Za-z0-9_]* \%]</match>
+               </context>
+
+               <context id="type" style-ref="type">
+                       <match>\%[ [A-Z][A-Za-z0-9_]* \%]</match>
+               </context>
+
+               <context id="variable" style-ref="variable">
+                       <match>\%[ [a-z][A-Za-z0-9_]* \%]</match>
+               </context>
+
+               <!-- Numbers -->
+
+               <define-regex id="integer-suffix">
+                       (?:[iu](?:8|16|32))?
+               </define-regex>
+
+               <context id="binary" style-ref="binary">
+                       <match>[+-]?0[Bb][01_]+\%{integer-suffix}</match>
+               </context>
+
+               <context id="octal" style-ref="octal">
+                       <match>[+-]?0[Oo][0-7_]+\%{integer-suffix}</match>
+               </context>
+
+               <context id="hexadecimal" style-ref="hexadecimal">
+                       <match>[+-]?0[Xx][0-9A-Fa-f_]+\%{integer-suffix}</match>
+               </context>
+
+               <context id="decimal" style-ref="decimal">
+                       <match>[+-]?[0-9][0-9_]*\%{integer-suffix}</match>
+               </context>
+
+               <context id="floating-point" style-ref="floating-point">
+                       <match>[+-]?(?:[0-9]+|[0-9]*\.[0-9]+)(?:[Ee][+-]?[0-9]+)?</match>
+               </context>
+
+               <!-- Strings and characters -->
+
+               <context id="escaped-apostrophe" style-ref="escaped-character">
+                       <match>\\'</match>
+               </context>
+
+               <context id="escaped-character" style-ref="escaped-character">
+                       <match>\\.</match>
+               </context>
+
+               <context id="interpolation" style-ref="escaped-character">
+                       <start>\{</start>
+                       <end>\}</end>
+                       <include>
+                               <!-- FIXME: Reset style -->
+                               <context ref="nit" />
+                       </include>
+               </context>
+
+               <context id="long-interpolation" style-ref="escaped-character">
+                       <start>\{\{\{</start>
+                       <end>\}\}\}</end>
+                       <include>
+                               <!-- FIXME: Reset style -->
+                               <context ref="nit" />
+                       </include>
+               </context>
+
+               <context id="long-string" style-ref="string" class="string">
+                       <start>"""|'''</start>
+                       <end>\%{0@start}</end>
+                       <include>
+                               <context ref="escaped-character"/>
+                               <context ref="long-interpolation"/>
+                       </include>
+               </context>
+
+               <context id="character" style-ref="character" class="string">
+                       <start>'</start>
+                       <end>'</end>
+                       <include>
+                               <context ref="escaped-apostrophe"/>
+                       </include>
+               </context>
+
+               <context id="string" style-ref="string" class="string">
+                       <start>"</start>
+                       <end>"</end>
+                       <include>
+                               <context ref="escaped-character"/>
+                               <context ref="interpolation"/>
+                       </include>
+               </context>
+
+               <!-- Extern code -->
+
+               <context id="extern-code-cpp" style-ref="extern-code">
+                       <start case-sensitive="false">
+                               (?'cpp_kwin' in) \%{space}*
+                               (?'cpp_language_name' "c\+\+(?: [^"]*)?") \%{space}*
+                               `\{
+                       </start>
+                       <end>`\}</end>
+                       <include>
+                               <context sub-pattern="cpp_kwin" where="start" style-ref="keyword"/>
+                               <context sub-pattern="cpp_language_name" where="start"
+                                               style-ref="string" class="string" />
+                               <!-- FIXME: Reset style -->
+                               <context ref="cpp:cpp"/>
+                       </include>
+               </context>
+
+               <context id="extern-code-java" style-ref="extern-code">
+                       <start case-sensitive="false">
+                               (?'java_kwin' in) \%{space}*
+                               (?'java_language_name' "java(?: [^"]*)?") \%{space}*
+                               `\{
+                       </start>
+                       <end>`\}</end>
+                       <include>
+                               <context sub-pattern="java_kwin" where="start" style-ref="keyword"/>
+                               <context sub-pattern="java_language_name" where="start"
+                                               style-ref="string" class="string" />
+                               <!-- FIXME: Reset style -->
+                               <context ref="java:java"/>
+                       </include>
+               </context>
+
+               <context id="extern-code-objc" style-ref="extern-code">
+                       <start case-sensitive="false">
+                               (?'objc_kwin' in) \%{space}*
+                               (?'objc_language_name' "objc(?: [^"]*)?") \%{space}*
+                               `\{
+                       </start>
+                       <end>`\}</end>
+                       <include>
+                               <context sub-pattern="objc_kwin" where="start" style-ref="keyword"/>
+                               <context sub-pattern="objc_language_name" where="start"
+                                               style-ref="string" class="string" />
+                               <!-- FIXME: Reset style -->
+                               <context ref="objc:objc"/>
+                       </include>
+               </context>
+
+               <context id="extern-code-default" style-ref="extern-code">
+                       <!-- By default, the embedded language is C. -->
+                       <start>`\{</start>
+                       <end>`\}</end>
+                       <include>
+                               <!-- FIXME: Reset style -->
+                               <context ref="c:c"/>
+                       </include>
+               </context>
+
+               <!-- Main context -->
+               <context id="nit" class="no-spell-check">
+                       <include>
+                               <context ref="def:shebang"/>
+                               <context ref="def:shell-like-comment"/>
+                               <context ref="extern-code-cpp"/>
+                               <context ref="extern-code-java"/>
+                               <context ref="extern-code-objc"/>
+                               <context ref="extern-code-default"/>
+                               <context ref="long-string"/>
+                               <context ref="character"/>
+                               <context ref="string"/>
+                               <context ref="reserved"/>
+                               <context ref="kwimport"/>
+                               <context ref="kwnull"/>
+                               <context ref="keyword"/>
+                               <context ref="builtin-annotation"/>
+                               <context ref="boolean"/>
+                               <context ref="special-variable"/>
+                               <context ref="operator-keyword"/>
+                               <context ref="attribute"/>
+                               <context ref="type"/>
+                               <context ref="variable"/>
+                               <context ref="binary"/>
+                               <context ref="octal"/>
+                               <context ref="hexadecimal"/>
+                               <context ref="decimal"/>
+                               <context ref="floating-point"/>
+                               <context ref="operator-punctuation"/>
+                       </include>
+               </context>
+       </definitions>
 </language>
index 582e5fb..c810664 100644 (file)
@@ -358,12 +358,13 @@ endfun
 
 " Call `git grep` on the word under the cursor
 "
-" Shows declarations first, then all matches, in the preview window.
+" In the preview window, list introductions, declarations and then all matches.
 fun NitGitGrep()
        let word = expand("<cword>")
        let out = tempname()
-       execute 'silent !(git grep "\\(module\\|class\\|universal\\|interface\\|var\\|fun\\) '.word.'";'.
-               \'echo; git grep '.word.') > '.out
+       execute 'silent !(git grep -n -e "\<\\(module\\|class\\|universal\\|interface\\|subset\\|var\\|fun\\)\> \<'.word.'\>" --and --not -e redef -- ''*.nit'';'.
+               \'git grep -n "redef \<\\(class\\|universal\\|interface\\|subset\\|var\\|fun\\)\> \<'.word.'\>" -- ''*.nit'';'.
+               \'echo; git grep -n -e "\<'.word.'\>" --and --not -e "\<\\(module\\|class\\|universal\\|interface\\|subset\\|var\\|fun\\)\> \<'.word.'\>" -- ''*.nit'') > '.out
 
        " Open the preview window on a temp file
        execute "silent pedit " . out
index 3d632c6..0846e85 100644 (file)
@@ -89,6 +89,9 @@ redef class MEntity
                        for i in 2.times do stream.write line_separator
                        stream.write mdoc.content.join(line_separator)
                end
+
+               write_location(mainmodule, stream)
+
                write_extra_doc(mainmodule, stream)
 
                stream.write "\n"
@@ -104,6 +107,15 @@ redef class MEntity
 
        # Extra auto documentation to append to the `stream`
        private fun write_extra_doc(mainmodule: MModule, stream: Writer) do end
+
+       # Location (file and line when available) of related declarations
+       private fun write_location(mainmodule: MModule, stream: Writer)
+       do
+               for i in 2.times do stream.write line_separator
+               stream.write "## Location"
+               stream.write line_separator
+               stream.write "* {location}"
+       end
 end
 
 redef class MMethodDef
@@ -114,6 +126,26 @@ redef class MMethodDef
                        stream.write msignature.to_s
                end
        end
+
+       redef fun write_location(mainmodule, stream)
+       do
+               for i in 2.times do stream.write line_separator
+               stream.write "## Location of introduction and refinements"
+
+               # Group locations in the same file
+               var file_to_location = new MultiHashMap[nullable SourceFile, Location]
+               for c in mproperty.mpropdefs do
+                       file_to_location[c.location.file].add c.location
+               end
+
+               # Write one file per location
+               for file, locations in file_to_location do
+                       var l = locations.first
+                       stream.write line_separator
+                       stream.write "* {l}"
+                       if locations.length > 1 then stream.write " ({locations.length-1} more)"
+               end
+       end
 end
 
 redef class MAttributeDef
@@ -218,6 +250,16 @@ redef class MClassType
        end
 
        redef fun complete_mdoc do return mclass.intro.mdoc
+
+       redef fun write_location(mainmodule, stream)
+       do
+               for i in 2.times do stream.write line_separator
+               stream.write "## Location of introduction and refinements"
+               for c in mclass.mclassdefs do
+                       stream.write line_separator
+                       stream.write "* {c.location}"
+               end
+       end
 end
 
 private class AutocompletePhase
diff --git a/src/frontend/code_gen.nit b/src/frontend/code_gen.nit
new file mode 100644 (file)
index 0000000..ccbddde
--- /dev/null
@@ -0,0 +1,20 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Main frontend phases plus code generation phases
+module code_gen
+
+import frontend
+import actors_generation_phase
+import serialization_code_gen_phase
index 042cfc1..d18285c 100644 (file)
@@ -13,6 +13,8 @@
 # limitations under the License.
 
 # Collect and orchestration of main frontend phases
+#
+# Import `frontend::code_gen` to also include code generation modules.
 module frontend
 
 import no_warning
@@ -21,7 +23,7 @@ import literal
 import modelize
 import semantize
 import div_by_zero
-import serialization_phase
+import serialization_model_phase
 import deriving
 import check_annotation
 import parse_annotations
@@ -29,7 +31,6 @@ import glsl_validation
 import parallelization_phase
 import i18n_phase
 import regex_phase
-import actors_generation_phase
 import actors_injection_phase
 
 redef class ToolContext
diff --git a/src/frontend/serialization_code_gen_phase.nit b/src/frontend/serialization_code_gen_phase.nit
new file mode 100644 (file)
index 0000000..57f46c5
--- /dev/null
@@ -0,0 +1,208 @@
+# 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.
+
+# Phase generating methods (code) to serialize Nit objects
+module serialization_code_gen_phase
+
+intrude import serialization_model_phase
+
+redef class ToolContext
+
+       # The second phase of the serialization
+       var serialization_phase_post_model: Phase = new SerializationPhasePostModel(self,
+               [modelize_property_phase, serialization_phase_pre_model])
+end
+
+private class SerializationPhasePostModel
+       super Phase
+
+       # Fill the deserialization init `from_deserializer` and `Deserializer.deserialize_class_intern`
+       redef fun process_nmodule(nmodule)
+       do
+               for npropdef in nmodule.inits_to_retype do
+                       var nclassdef = npropdef.parent
+                       assert nclassdef isa AStdClassdef
+
+                       var serialize_by_default = nclassdef.how_serialize
+                       assert serialize_by_default != null
+
+                       var per_attribute = not serialize_by_default
+                       fill_deserialization_init(nclassdef, npropdef, per_attribute)
+               end
+
+               # collect all classes
+               var auto_serializable_nclassdefs = nmodule.auto_serializable_nclassdefs
+               if not auto_serializable_nclassdefs.is_empty then
+                       fill_deserialization_method(nmodule, auto_serializable_nclassdefs)
+               end
+       end
+
+       # Fill the constructor to the generated `init_npropdef` of `nclassdef`
+       fun fill_deserialization_init(nclassdef: AClassdef, init_npropdef: AMethPropdef, per_attribute: Bool)
+       do
+               var code = new Array[String]
+               code.add """
+redef init from_deserializer(v: Deserializer)
+do
+       super
+       v.notify_of_creation self
+"""
+
+               for attribute in nclassdef.n_propdefs do
+                       if not attribute isa AAttrPropdef then continue
+
+                       # Is `attribute` to be skipped?
+                       if (per_attribute and not attribute.is_serialize) or
+                               attribute.is_noserialize then continue
+
+                       var mtype = attribute.mtype
+                       if mtype == null then continue
+                       var type_name = mtype.to_s
+                       var name = attribute.name
+
+                       var resolved_type_name = type_name
+                       var mclassdef = nclassdef.mclassdef
+                       if mclassdef != null then
+                               var bound_mtype = mclassdef.bound_mtype
+                               var resolved_mtype = mtype.resolve_for(bound_mtype, bound_mtype, mclassdef.mmodule, true)
+                               resolved_type_name = resolved_mtype.name
+
+                               # TODO Use something like `V.class_name` to get the precise runtime type of virtual types.
+                               # We currently use the upper bound of virtual types as static type in generated code
+                               # for type suggestion and to prevent loading unexected types.
+                               # This leaves a security issue when, for example, `DefaultMap::default_value`
+                               # is bound to `nullable Object` and would allow any object to be loaded.
+                       end
+
+                       if type_name == "nullable Object" then
+                               # Don't type check
+                               code.add """
+       self.{{{name}}} = v.deserialize_attribute("{{{attribute.serialize_name}}}", "{{{resolved_type_name}}}")
+"""
+                       else
+                               code.add """
+       var {{{name}}} = v.deserialize_attribute("{{{attribute.serialize_name}}}", "{{{resolved_type_name}}}")
+       if v.deserialize_attribute_missing then
+"""
+                               # What to do when an attribute is missing?
+                               if attribute.has_value then
+                                       # Leave it to the default value
+                               else if mtype isa MNullableType then
+                                       code.add """
+               self.{{{name}}} = null"""
+                               else code.add """
+               v.errors.add new Error("Deserialization Error: attribute `{class_name}::{{{name}}}` missing from JSON object")"""
+
+                               code.add """
+       else if not {{{name}}} isa {{{type_name}}} then
+               v.errors.add new AttributeTypeError(self, "{{{attribute.serialize_name}}}", {{{name}}}, "{{{resolved_type_name}}}")
+               if v.keep_going == false then return
+       else
+               self.{{{name}}} = {{{name}}}
+       end
+"""
+                       end
+               end
+
+               code.add "end"
+
+               # Replace the body of the constructor
+               var npropdef = toolcontext.parse_propdef(code.join("\n")).as(AMethPropdef)
+               init_npropdef.n_block = npropdef.n_block
+
+               # Run the literal phase on the generated code
+               var v = new LiteralVisitor(toolcontext)
+               v.enter_visit(npropdef.n_block)
+       end
+
+       # Fill the abstract serialization service
+       fun fill_deserialization_method(nmodule: AModule, nclassdefs: Array[AStdClassdef])
+       do
+               var deserializer_nclassdef = nmodule.deserializer_nclassdef
+               if deserializer_nclassdef == null then return
+               var deserializer_npropdef = deserializer_nclassdef.deserializer_npropdef
+               if deserializer_npropdef == null then return
+
+               # Collect local types expected to be deserialized
+               var types_to_deserialize = new Set[String]
+
+               ## Local serializable standard class without parameters
+               for nclassdef in nclassdefs do
+                       var mclass = nclassdef.mclass
+                       if mclass == null then continue
+
+                       if mclass.arity == 0 and mclass.kind == concrete_kind then
+                               types_to_deserialize.add mclass.name
+                       end
+               end
+
+               ## Static parametized types on serializable attributes
+               for nclassdef in nmodule.n_classdefs do
+                       if not nclassdef isa AStdClassdef then continue
+
+                       for attribute in nclassdef.n_propdefs do
+                               if not attribute isa AAttrPropdef then continue
+
+                               var serialize_by_default = nclassdef.how_serialize
+                               if serialize_by_default == null then continue
+                               var per_attribute = not serialize_by_default
+
+                               # Is `attribute` to be skipped?
+                               if (per_attribute and not attribute.is_serialize) or
+                                       attribute.is_noserialize then continue
+
+                               var mtype = attribute.mtype
+                               if mtype == null then continue
+                               if mtype isa MNullableType then mtype = mtype.mtype
+
+                               if mtype isa MClassType and mtype.mclass.arity > 0 and
+                                  mtype.mclass.kind == concrete_kind and not mtype.need_anchor then
+
+                                       # Check is a `Serializable`
+                                       var mmodule = nmodule.mmodule
+                                       if mmodule == null then continue
+
+                                       var greaters = mtype.mclass.in_hierarchy(mmodule).greaters
+                                       var is_serializable = false
+                                       for sup in greaters do if sup.name == "Serializable" then
+                                               is_serializable = true
+                                               break
+                                       end
+
+                                       if is_serializable then types_to_deserialize.add mtype.to_s
+                               end
+                       end
+               end
+
+               # Build implementation code
+               var code = new Array[String]
+               code.add "redef fun deserialize_class_intern(name)"
+               code.add "do"
+
+               for name in types_to_deserialize do
+                       code.add "      if name == \"{name}\" then return new {name}.from_deserializer(self)"
+               end
+
+               code.add "      return super"
+               code.add "end"
+
+               # Replace the body of the constructor
+               var npropdef = toolcontext.parse_propdef(code.join("\n")).as(AMethPropdef)
+               deserializer_npropdef.n_block = npropdef.n_block
+
+               # Run the literal phase on the generated code
+               var v = new LiteralVisitor(toolcontext)
+               v.enter_visit(npropdef.n_block)
+       end
+end
similarity index 62%
rename from src/frontend/serialization_phase.nit
rename to src/frontend/serialization_model_phase.nit
index 1091c47..a269ee4 100644 (file)
@@ -16,8 +16,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Phase generating methods to serialize Nit objects to different formats
-module serialization_phase
+# Phase generating methods (model-only) to serialize Nit objects
+module serialization_model_phase
 
 private import parser_util
 import modelize
@@ -32,10 +32,6 @@ redef class ToolContext
        # Generate serialization and deserialization methods on `auto_serializable` annotated classes.
        var serialization_phase_pre_model: Phase = new SerializationPhasePreModel(self,
                [serialization_phase_rename])
-
-       # The second phase of the serialization
-       var serialization_phase_post_model: Phase = new SerializationPhasePostModel(self,
-               [modelize_property_phase, serialization_phase_pre_model])
 end
 
 redef class ANode
@@ -270,189 +266,6 @@ redef init from_deserializer(v: Deserializer) do abort"""
        end
 end
 
-private class SerializationPhasePostModel
-       super Phase
-
-       # Fill the deserialization init `from_deserializer` and `Deserializer.deserialize_class_intern`
-       redef fun process_nmodule(nmodule)
-       do
-               for npropdef in nmodule.inits_to_retype do
-                       var nclassdef = npropdef.parent
-                       assert nclassdef isa AStdClassdef
-
-                       var serialize_by_default = nclassdef.how_serialize
-                       assert serialize_by_default != null
-
-                       var per_attribute = not serialize_by_default
-                       fill_deserialization_init(nclassdef, npropdef, per_attribute)
-               end
-
-               # collect all classes
-               var auto_serializable_nclassdefs = nmodule.auto_serializable_nclassdefs
-               if not auto_serializable_nclassdefs.is_empty then
-                       fill_deserialization_method(nmodule, auto_serializable_nclassdefs)
-               end
-       end
-
-       # Fill the constructor to the generated `init_npropdef` of `nclassdef`
-       fun fill_deserialization_init(nclassdef: AClassdef, init_npropdef: AMethPropdef, per_attribute: Bool)
-       do
-               var code = new Array[String]
-               code.add """
-redef init from_deserializer(v: Deserializer)
-do
-       super
-       v.notify_of_creation self
-"""
-
-               for attribute in nclassdef.n_propdefs do
-                       if not attribute isa AAttrPropdef then continue
-
-                       # Is `attribute` to be skipped?
-                       if (per_attribute and not attribute.is_serialize) or
-                               attribute.is_noserialize then continue
-
-                       var mtype = attribute.mtype
-                       if mtype == null then continue
-                       var type_name = mtype.to_s
-                       var name = attribute.name
-
-                       var resolved_type_name = type_name
-                       var mclassdef = nclassdef.mclassdef
-                       if mclassdef != null then
-                               var bound_mtype = mclassdef.bound_mtype
-                               var resolved_mtype = mtype.resolve_for(bound_mtype, bound_mtype, mclassdef.mmodule, true)
-                               resolved_type_name = resolved_mtype.name
-
-                               # TODO Use something like `V.class_name` to get the precise runtime type of virtual types.
-                               # We currently use the upper bound of virtual types as static type in generated code
-                               # for type suggestion and to prevent loading unexected types.
-                               # This leaves a security issue when, for example, `DefaultMap::default_value`
-                               # is bound to `nullable Object` and would allow any object to be loaded.
-                       end
-
-                       if type_name == "nullable Object" then
-                               # Don't type check
-                               code.add """
-       self.{{{name}}} = v.deserialize_attribute("{{{attribute.serialize_name}}}", "{{{resolved_type_name}}}")
-"""
-                       else
-                               code.add """
-       var {{{name}}} = v.deserialize_attribute("{{{attribute.serialize_name}}}", "{{{resolved_type_name}}}")
-       if v.deserialize_attribute_missing then
-"""
-                               # What to do when an attribute is missing?
-                               if attribute.has_value then
-                                       # Leave it to the default value
-                               else if mtype isa MNullableType then
-                                       code.add """
-               self.{{{name}}} = null"""
-                               else code.add """
-               v.errors.add new Error("Deserialization Error: attribute `{class_name}::{{{name}}}` missing from JSON object")"""
-
-                               code.add """
-       else if not {{{name}}} isa {{{type_name}}} then
-               v.errors.add new AttributeTypeError(self, "{{{attribute.serialize_name}}}", {{{name}}}, "{{{resolved_type_name}}}")
-               if v.keep_going == false then return
-       else
-               self.{{{name}}} = {{{name}}}
-       end
-"""
-                       end
-               end
-
-               code.add "end"
-
-               # Replace the body of the constructor
-               var npropdef = toolcontext.parse_propdef(code.join("\n")).as(AMethPropdef)
-               init_npropdef.n_block = npropdef.n_block
-
-               # Run the literal phase on the generated code
-               var v = new LiteralVisitor(toolcontext)
-               v.enter_visit(npropdef.n_block)
-       end
-
-       # Fill the abstract serialization service
-       fun fill_deserialization_method(nmodule: AModule, nclassdefs: Array[AStdClassdef])
-       do
-               var deserializer_nclassdef = nmodule.deserializer_nclassdef
-               if deserializer_nclassdef == null then return
-               var deserializer_npropdef = deserializer_nclassdef.deserializer_npropdef
-               if deserializer_npropdef == null then return
-
-               # Collect local types expected to be deserialized
-               var types_to_deserialize = new Set[String]
-
-               ## Local serializable standard class without parameters
-               for nclassdef in nclassdefs do
-                       var mclass = nclassdef.mclass
-                       if mclass == null then continue
-
-                       if mclass.arity == 0 and mclass.kind == concrete_kind then
-                               types_to_deserialize.add mclass.name
-                       end
-               end
-
-               ## Static parametized types on serializable attributes
-               for nclassdef in nmodule.n_classdefs do
-                       if not nclassdef isa AStdClassdef then continue
-
-                       for attribute in nclassdef.n_propdefs do
-                               if not attribute isa AAttrPropdef then continue
-
-                               var serialize_by_default = nclassdef.how_serialize
-                               if serialize_by_default == null then continue
-                               var per_attribute = not serialize_by_default
-
-                               # Is `attribute` to be skipped?
-                               if (per_attribute and not attribute.is_serialize) or
-                                       attribute.is_noserialize then continue
-
-                               var mtype = attribute.mtype
-                               if mtype == null then continue
-                               if mtype isa MNullableType then mtype = mtype.mtype
-
-                               if mtype isa MClassType and mtype.mclass.arity > 0 and
-                                  mtype.mclass.kind == concrete_kind and not mtype.need_anchor then
-
-                                       # Check is a `Serializable`
-                                       var mmodule = nmodule.mmodule
-                                       if mmodule == null then continue
-
-                                       var greaters = mtype.mclass.in_hierarchy(mmodule).greaters
-                                       var is_serializable = false
-                                       for sup in greaters do if sup.name == "Serializable" then
-                                               is_serializable = true
-                                               break
-                                       end
-
-                                       if is_serializable then types_to_deserialize.add mtype.to_s
-                               end
-                       end
-               end
-
-               # Build implementation code
-               var code = new Array[String]
-               code.add "redef fun deserialize_class_intern(name)"
-               code.add "do"
-
-               for name in types_to_deserialize do
-                       code.add "      if name == \"{name}\" then return new {name}.from_deserializer(self)"
-               end
-
-               code.add "      return super"
-               code.add "end"
-
-               # Replace the body of the constructor
-               var npropdef = toolcontext.parse_propdef(code.join("\n")).as(AMethPropdef)
-               deserializer_npropdef.n_block = npropdef.n_block
-
-               # Run the literal phase on the generated code
-               var v = new LiteralVisitor(toolcontext)
-               v.enter_visit(npropdef.n_block)
-       end
-end
-
 redef class AAttrPropdef
        private fun name: String do return n_id2.text
 
index 70edaec..935b201 100644 (file)
@@ -1975,16 +1975,34 @@ class MSignature
                var b = new FlatBuffer
                if not mparameters.is_empty then
                        b.append("(")
+                       var last_mtype = null
                        for i in [0..mparameters.length[ do
                                var mparameter = mparameters[i]
+
+                               # Group types that are common to contiguous parameters
+                               if mparameter.mtype != last_mtype and last_mtype != null then
+                                       b.append(": ")
+                                       b.append(last_mtype.to_s)
+                               end
+
                                if i > 0 then b.append(", ")
                                b.append(mparameter.name)
-                               b.append(": ")
-                               b.append(mparameter.mtype.to_s)
+
                                if mparameter.is_vararg then
+                                       b.append(": ")
+                                       b.append(mparameter.mtype.to_s)
                                        b.append("...")
+                                       last_mtype = null
+                               else
+                                       last_mtype = mparameter.mtype
                                end
                        end
+
+                       if last_mtype != null then
+                               b.append(": ")
+                               b.append(last_mtype.to_s)
+                       end
+
                        b.append(")")
                end
                var ret = self.return_mtype
index d38f1bf..be6c665 100644 (file)
@@ -18,7 +18,7 @@
 module nit
 
 import interpreter
-import frontend
+import frontend::code_gen
 import parser_util
 import vm
 
index cab5638..83f9de3 100644 (file)
@@ -17,7 +17,7 @@
 # A Nit compiler
 module nitc
 
-import frontend
+import frontend::code_gen
 import compiler
 import transform
 
index 3925360..032ce7f 100644 (file)
@@ -17,7 +17,7 @@
 # A program that collects various metrics on nit programs and libraries
 module nitmetrics
 
-import frontend
+import frontend::code_gen
 import metrics
 
 # Create a tool context to handle options and paths
@@ -30,9 +30,9 @@ toolcontext.process_options(args)
 # Get arguments
 var arguments = toolcontext.option_context.rest
 
-# We need a model to collect stufs
+# We need a model to collect stuff
 var model = new Model
-# An a model builder to parse files
+# And a model builder to parse files
 var modelbuilder = new ModelBuilder(model, toolcontext)
 
 # Here we load an process all modules passed on the command line
index e81b20d..dae856b 100644 (file)
@@ -18,7 +18,7 @@
 module nitvm
 
 import vm
-import frontend
+import frontend::code_gen
 
 # Create a tool context to handle options and paths
 var toolcontext = new ToolContext
index 22fc750..cd300d4 100644 (file)
 
 # Example of simple module that aims to do some specific work on nit programs.
 #
-# Fast prototypes can just start with this skeletton.
+# Fast prototypes can just start with this skeleton.
 module test_test_phase
 
-# We need the framework that perfoms standard code for the main-program
+# We need the framework that performs standard code for the main-program
 import test_phase
 
 # We usualy need specific phases
-# NOTE: `frontend` is sufficent in most case (it is often too much)
+# NOTE: `frontend` is sufficient in most case (it is often too much)
 import frontend
 
 # The body of the specific work.
index 40dd13d..6157963 100644 (file)
@@ -1,8 +1,8 @@
-alt/base_arg_default_alt1.nit:81,3--5: Error: expected at least 4 argument(s) for `foo(a: nullable Int, b: nullable Int, c: Int, d: Int, e: nullable Int, f: nullable Int)`; got 0. See introduction at `base_arg_default_alt1::A::foo`.
-alt/base_arg_default_alt1.nit:82,3--5: Error: expected at least 4 argument(s) for `foo(a: nullable Int, b: nullable Int, c: Int, d: Int, e: nullable Int, f: nullable Int)`; got 1. See introduction at `base_arg_default_alt1::A::foo`.
-alt/base_arg_default_alt1.nit:83,3--5: Error: expected at least 4 argument(s) for `foo(a: nullable Int, b: nullable Int, c: Int, d: Int, e: nullable Int, f: nullable Int)`; got 2. See introduction at `base_arg_default_alt1::A::foo`.
-alt/base_arg_default_alt1.nit:84,3--5: Error: expected at least 4 argument(s) for `foo(a: nullable Int, b: nullable Int, c: Int, d: Int, e: nullable Int, f: nullable Int)`; got 3. See introduction at `base_arg_default_alt1::A::foo`.
-alt/base_arg_default_alt1.nit:88,3--5: Error: expected 6 argument(s) for `foo(a: nullable Int, b: nullable Int, c: Int, d: Int, e: nullable Int, f: nullable Int)`; got 7. See introduction at `base_arg_default_alt1::A::foo`.
-alt/base_arg_default_alt1.nit:94,3--5: Error: expected 3 argument(s) for `bar(a: nullable Int, b: nullable Int, c: nullable Int)`; got 4. See introduction at `base_arg_default_alt1::A::bar`.
-alt/base_arg_default_alt1.nit:99,3--5: Error: expected 3 argument(s) for `bar=(a: nullable Int, b: nullable Int, c: nullable Int)`; got 4. See introduction at `base_arg_default_alt1::A::bar=`.
-alt/base_arg_default_alt1.nit:110,1--13: Error: expected 3 argument(s) for `[]=(a: nullable Int, b: nullable Int, c: nullable Int): Int`; got 4. See introduction at `base_arg_default_alt1::A::[]=`.
+alt/base_arg_default_alt1.nit:81,3--5: Error: expected at least 4 argument(s) for `foo(a, b: nullable Int, c, d: Int, e, f: nullable Int)`; got 0. See introduction at `base_arg_default_alt1::A::foo`.
+alt/base_arg_default_alt1.nit:82,3--5: Error: expected at least 4 argument(s) for `foo(a, b: nullable Int, c, d: Int, e, f: nullable Int)`; got 1. See introduction at `base_arg_default_alt1::A::foo`.
+alt/base_arg_default_alt1.nit:83,3--5: Error: expected at least 4 argument(s) for `foo(a, b: nullable Int, c, d: Int, e, f: nullable Int)`; got 2. See introduction at `base_arg_default_alt1::A::foo`.
+alt/base_arg_default_alt1.nit:84,3--5: Error: expected at least 4 argument(s) for `foo(a, b: nullable Int, c, d: Int, e, f: nullable Int)`; got 3. See introduction at `base_arg_default_alt1::A::foo`.
+alt/base_arg_default_alt1.nit:88,3--5: Error: expected 6 argument(s) for `foo(a, b: nullable Int, c, d: Int, e, f: nullable Int)`; got 7. See introduction at `base_arg_default_alt1::A::foo`.
+alt/base_arg_default_alt1.nit:94,3--5: Error: expected 3 argument(s) for `bar(a, b, c: nullable Int)`; got 4. See introduction at `base_arg_default_alt1::A::bar`.
+alt/base_arg_default_alt1.nit:99,3--5: Error: expected 3 argument(s) for `bar=(a, b, c: nullable Int)`; got 4. See introduction at `base_arg_default_alt1::A::bar=`.
+alt/base_arg_default_alt1.nit:110,1--13: Error: expected 3 argument(s) for `[]=(a, b, c: nullable Int): Int`; got 4. See introduction at `base_arg_default_alt1::A::[]=`.
index b865616..d6c4929 100644 (file)
@@ -1,9 +1,9 @@
 alt/base_arg_default_autoinit_alt1.nit:59,5--7: Error: expected at least 1 argument(s) for `init(mandatory: Int, optional: nullable Int)`; got 0. See introduction at `core::Object::init`.
 alt/base_arg_default_autoinit_alt1.nit:68,5--7: Error: expected 2 argument(s) for `init(mandatory: Int, optional: nullable Int)`; got 3. See introduction at `core::Object::init`.
-alt/base_arg_default_autoinit_alt1.nit:71,5--7: Error: expected 4 argument(s) for `init(mandatory: Int, optional: nullable Int, optional_b: nullable Int, mandatory_b: Int)`; got 1. See introduction at `core::Object::init`.
-alt/base_arg_default_autoinit_alt1.nit:74,5--7: Error: expected 4 argument(s) for `init(mandatory: Int, optional: nullable Int, optional_b: nullable Int, mandatory_b: Int)`; got 2. See introduction at `core::Object::init`.
-alt/base_arg_default_autoinit_alt1.nit:77,5--7: Error: expected 4 argument(s) for `init(mandatory: Int, optional: nullable Int, optional_b: nullable Int, mandatory_b: Int)`; got 3. See introduction at `core::Object::init`.
-alt/base_arg_default_autoinit_alt1.nit:83,5--7: Error: expected 4 argument(s) for `init(mandatory: Int, optional: nullable Int, optional_b: nullable Int, mandatory_b: Int)`; got 5. See introduction at `core::Object::init`.
-alt/base_arg_default_autoinit_alt1.nit:86,5--7: Error: expected 3 argument(s) for `init(optional_b: nullable Int, mandatory_b: Int, mandatory: Int)`; got 1. See introduction at `core::Object::init`.
-alt/base_arg_default_autoinit_alt1.nit:89,5--7: Error: expected 3 argument(s) for `init(optional_b: nullable Int, mandatory_b: Int, mandatory: Int)`; got 2. See introduction at `core::Object::init`.
-alt/base_arg_default_autoinit_alt1.nit:95,5--7: Error: expected 3 argument(s) for `init(optional_b: nullable Int, mandatory_b: Int, mandatory: Int)`; got 4. See introduction at `core::Object::init`.
+alt/base_arg_default_autoinit_alt1.nit:71,5--7: Error: expected 4 argument(s) for `init(mandatory: Int, optional, optional_b: nullable Int, mandatory_b: Int)`; got 1. See introduction at `core::Object::init`.
+alt/base_arg_default_autoinit_alt1.nit:74,5--7: Error: expected 4 argument(s) for `init(mandatory: Int, optional, optional_b: nullable Int, mandatory_b: Int)`; got 2. See introduction at `core::Object::init`.
+alt/base_arg_default_autoinit_alt1.nit:77,5--7: Error: expected 4 argument(s) for `init(mandatory: Int, optional, optional_b: nullable Int, mandatory_b: Int)`; got 3. See introduction at `core::Object::init`.
+alt/base_arg_default_autoinit_alt1.nit:83,5--7: Error: expected 4 argument(s) for `init(mandatory: Int, optional, optional_b: nullable Int, mandatory_b: Int)`; got 5. See introduction at `core::Object::init`.
+alt/base_arg_default_autoinit_alt1.nit:86,5--7: Error: expected 3 argument(s) for `init(optional_b: nullable Int, mandatory_b, mandatory: Int)`; got 1. See introduction at `core::Object::init`.
+alt/base_arg_default_autoinit_alt1.nit:89,5--7: Error: expected 3 argument(s) for `init(optional_b: nullable Int, mandatory_b, mandatory: Int)`; got 2. See introduction at `core::Object::init`.
+alt/base_arg_default_autoinit_alt1.nit:95,5--7: Error: expected 3 argument(s) for `init(optional_b: nullable Int, mandatory_b, mandatory: Int)`; got 4. See introduction at `core::Object::init`.
index 39b6ba4..74a9faf 100644 (file)
@@ -1,4 +1,4 @@
-alt/base_arg_named_alt1.nit:22,3--5: Error: expected at least 5 argument(s) for `foo(a: nullable Int, b: nullable Int, c: Int, d: Int, e: nullable Int, f: nullable Int)`; got 4. See introduction at `base_arg_default::A::foo`.
-alt/base_arg_named_alt1.nit:45,3--5: Error: expected 3 argument(s) for `bar(a: nullable Int, b: nullable Int, c: nullable Int)`; got 4. See introduction at `base_arg_default::A::bar`.
-alt/base_arg_named_alt1.nit:46,7--10: Error: no parameter `fail` for `bar(a: nullable Int, b: nullable Int, c: nullable Int)`.
-alt/base_arg_named_alt1.nit:47,11--13: Error: parameter `a` already associated with argument #0 for `bar(a: nullable Int, b: nullable Int, c: nullable Int)`.
+alt/base_arg_named_alt1.nit:22,3--5: Error: expected at least 5 argument(s) for `foo(a, b: nullable Int, c, d: Int, e, f: nullable Int)`; got 4. See introduction at `base_arg_default::A::foo`.
+alt/base_arg_named_alt1.nit:45,3--5: Error: expected 3 argument(s) for `bar(a, b, c: nullable Int)`; got 4. See introduction at `base_arg_default::A::bar`.
+alt/base_arg_named_alt1.nit:46,7--10: Error: no parameter `fail` for `bar(a, b, c: nullable Int)`.
+alt/base_arg_named_alt1.nit:47,11--13: Error: parameter `a` already associated with argument #0 for `bar(a, b, c: nullable Int)`.
index 20528d9..e89c7dd 100644 (file)
@@ -1,4 +1,4 @@
-alt/base_arg_named_inherit_alt1.nit:27,7: Error: no parameter `a` for `foo(x: nullable Int, y: nullable Int, z: Int, t: Int, u: nullable Int, v: nullable Int)`.
-alt/base_arg_named_inherit_alt1.nit:28,7: Error: no parameter `f` for `foo(x: nullable Int, y: nullable Int, z: Int, t: Int, u: nullable Int, v: nullable Int)`.
-alt/base_arg_named_inherit_alt1.nit:32,7: Error: no parameter `x` for `foo(a: nullable Int, b: nullable Int, c: Int, d: Int, e: nullable Int, f: nullable Int)`.
-alt/base_arg_named_inherit_alt1.nit:33,7: Error: no parameter `v` for `foo(a: nullable Int, b: nullable Int, c: Int, d: Int, e: nullable Int, f: nullable Int)`.
+alt/base_arg_named_inherit_alt1.nit:27,7: Error: no parameter `a` for `foo(x, y: nullable Int, z, t: Int, u, v: nullable Int)`.
+alt/base_arg_named_inherit_alt1.nit:28,7: Error: no parameter `f` for `foo(x, y: nullable Int, z, t: Int, u, v: nullable Int)`.
+alt/base_arg_named_inherit_alt1.nit:32,7: Error: no parameter `x` for `foo(a, b: nullable Int, c, d: Int, e, f: nullable Int)`.
+alt/base_arg_named_inherit_alt1.nit:33,7: Error: no parameter `v` for `foo(a, b: nullable Int, c, d: Int, e, f: nullable Int)`.
index 29bba0d..6a04fdb 100644 (file)
@@ -1,2 +1,2 @@
-alt/base_arg_named_inherit_alt2.nit:27,7: Error: no parameter `a` for `foo(x: nullable Int, y: nullable Int, z: Int, t: Int, u: nullable Int, v: nullable Int)`.
-alt/base_arg_named_inherit_alt2.nit:28,7: Error: no parameter `f` for `foo(x: nullable Int, y: nullable Int, z: Int, t: Int, u: nullable Int, v: nullable Int)`.
+alt/base_arg_named_inherit_alt2.nit:27,7: Error: no parameter `a` for `foo(x, y: nullable Int, z, t: Int, u, v: nullable Int)`.
+alt/base_arg_named_inherit_alt2.nit:28,7: Error: no parameter `f` for `foo(x, y: nullable Int, z, t: Int, u, v: nullable Int)`.
index 46dfc27..cea82f9 100644 (file)
@@ -1,2 +1,2 @@
-alt/base_arg_named_inherit_alt3.nit:29,3--5: Error: expected at least 5 argument(s) for `foo(a: nullable Int, b: nullable Int, c: Int, d: Int, e: nullable Int, f: nullable Int)`; got 4. See introduction at `base_arg_default::A::foo`.
-alt/base_arg_named_inherit_alt3.nit:34,3--5: Error: expected at least 5 argument(s) for `foo(x: nullable Int, y: nullable Int, z: Int, t: Int, u: nullable Int, v: nullable Int)`; got 4. See introduction at `base_arg_default::A::foo`.
+alt/base_arg_named_inherit_alt3.nit:29,3--5: Error: expected at least 5 argument(s) for `foo(a, b: nullable Int, c, d: Int, e, f: nullable Int)`; got 4. See introduction at `base_arg_default::A::foo`.
+alt/base_arg_named_inherit_alt3.nit:34,3--5: Error: expected at least 5 argument(s) for `foo(x, y: nullable Int, z, t: Int, u, v: nullable Int)`; got 4. See introduction at `base_arg_default::A::foo`.
index e73cdca..82ddfc6 100644 (file)
@@ -1 +1 @@
-alt/base_init_basic_alt5.nit:79,9--11: Error: expected 2 argument(s) for `init(c: Int, b: Int)`; got 1. See introduction at `core::Object::init`.
+alt/base_init_basic_alt5.nit:79,9--11: Error: expected 2 argument(s) for `init(c, b: Int)`; got 1. See introduction at `core::Object::init`.
index 23bd9f9..b079cab 100644 (file)
@@ -1 +1 @@
-alt/base_init_combine_alt1.nit:59,9--11: Error: expected 2 argument(s) for `init(i: Int, z: Int)`; got 1. See introduction at `core::Object::init`.
+alt/base_init_combine_alt1.nit:59,9--11: Error: expected 2 argument(s) for `init(i, z: Int)`; got 1. See introduction at `core::Object::init`.
index 2550be0..174ba96 100644 (file)
@@ -1 +1 @@
-alt/base_vararg_alt2.nit:54,1--3: Error: expected at least 2 argument(s) for `bar(b: Char, a: Char...)`; got 0. See introduction at `base_vararg_alt2::base_vararg_alt2::Sys::bar`.
+alt/base_vararg_alt2.nit:54,1--3: Error: expected at least 2 argument(s) for `bar(b, a: Char...)`; got 0. See introduction at `base_vararg_alt2::base_vararg_alt2::Sys::bar`.
index e7bc17f..697571a 100644 (file)
@@ -1 +1 @@
-alt/base_vararg_alt3.nit:55,1--3: Error: expected at least 2 argument(s) for `bar(b: Char, a: Char...)`; got 1. See introduction at `base_vararg_alt3::base_vararg_alt3::Sys::bar`.
+alt/base_vararg_alt3.nit:55,1--3: Error: expected at least 2 argument(s) for `bar(b, a: Char...)`; got 1. See introduction at `base_vararg_alt3::base_vararg_alt3::Sys::bar`.
index ece6a22..b894ebf 100644 (file)
@@ -1 +1 @@
-alt/base_vararg_alt6.nit:62,1--6: Error: expected at least 3 argument(s) for `foobar(b: Char, a: Char..., c: Char)`; got 0. See introduction at `base_vararg_alt6::base_vararg_alt6::Sys::foobar`.
+alt/base_vararg_alt6.nit:62,1--6: Error: expected at least 3 argument(s) for `foobar(b, a: Char..., c: Char)`; got 0. See introduction at `base_vararg_alt6::base_vararg_alt6::Sys::foobar`.
index f2baff5..ff7f718 100644 (file)
@@ -1 +1 @@
-alt/base_vararg_alt7.nit:63,1--6: Error: expected at least 3 argument(s) for `foobar(b: Char, a: Char..., c: Char)`; got 1. See introduction at `base_vararg_alt7::base_vararg_alt7::Sys::foobar`.
+alt/base_vararg_alt7.nit:63,1--6: Error: expected at least 3 argument(s) for `foobar(b, a: Char..., c: Char)`; got 1. See introduction at `base_vararg_alt7::base_vararg_alt7::Sys::foobar`.
index d3d6f38..f6e3b39 100644 (file)
@@ -1 +1 @@
-alt/base_vararg_alt8.nit:64,1--6: Error: expected at least 3 argument(s) for `foobar(b: Char, a: Char..., c: Char)`; got 2. See introduction at `base_vararg_alt8::base_vararg_alt8::Sys::foobar`.
+alt/base_vararg_alt8.nit:64,1--6: Error: expected at least 3 argument(s) for `foobar(b, a: Char..., c: Char)`; got 2. See introduction at `base_vararg_alt8::base_vararg_alt8::Sys::foobar`.
index af18d0c..16c9ed4 100644 (file)
@@ -1,4 +1,4 @@
-alt/error_init_auto_alt2.nit:34,5--7: Error: expected 2 argument(s) for `init(x: Int, y: Int)`; got 0. See introduction at `core::Object::init`.
-alt/error_init_auto_alt2.nit:35,5--7: Error: expected 2 argument(s) for `init(x: Int, y: Int)`; got 1. See introduction at `core::Object::init`.
-alt/error_init_auto_alt2.nit:37,5--7: Error: expected 2 argument(s) for `init(x: Int, y: Int)`; got 3. See introduction at `core::Object::init`.
+alt/error_init_auto_alt2.nit:34,5--7: Error: expected 2 argument(s) for `init(x, y: Int)`; got 0. See introduction at `core::Object::init`.
+alt/error_init_auto_alt2.nit:35,5--7: Error: expected 2 argument(s) for `init(x, y: Int)`; got 1. See introduction at `core::Object::init`.
+alt/error_init_auto_alt2.nit:37,5--7: Error: expected 2 argument(s) for `init(x, y: Int)`; got 3. See introduction at `core::Object::init`.
 alt/error_init_auto_alt2.nit:38,11--13: Error: method `foo` does not exists in `A`.
diff --git a/tests/sav/test_syntax.res b/tests/sav/test_syntax.res
new file mode 100644 (file)
index 0000000..98bfc04
--- /dev/null
@@ -0,0 +1 @@
+test_syntax.nit:48,2--39: Error: dev package for `a libray from outer space` unknown by `pkg-config`, install it with `apt-get`, `brew` or similar.
diff --git a/tests/test_syntax.nit b/tests/test_syntax.nit
new file mode 100644 (file)
index 0000000..42b88d0
--- /dev/null
@@ -0,0 +1,184 @@
+#! /usr/bin/env nitc
+
+# 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 case for syntax highlighters.
+#
+# Also test spell-checking and comment recognition.
+#
+# TODO: Fix the annotations so the module actually compiles.
+#
+# SEE: [Nit](http://nitlanguage.org)
+# XXX: Dummy task
+module test_syntax is
+       new_annotation new_annotation
+
+       conditional
+
+       deprecated
+       fixed
+       lazy
+       noinit
+       readonly
+       writable
+       optional
+       autoinit
+       noautoinit
+       lateinit
+       nosuper
+       old_style_init
+       abstract
+       intern
+       extern
+       no_warning("fictive-module")
+       generated
+
+       pkgconfig("a libray from outer space")
+       cflags ""
+       ldflags "-framework Foundation"
+       light_ffi
+
+       platform "space-time"
+end
+
+import core::kernel
+intrude import core::abstract_collection
+
+in "C" `{
+       #include <stdio.h>
+`}
+
+in "ObjC Header" `{
+       #import <Foundation/Foundation.h>
+`}
+
+abstract class Blurry[ELEM_ENT: nullable Object]
+       super core::kernel::Object
+
+       type KIND: Char
+
+       init do
+               foo = 21
+       end
+
+       new do return new Concrete[Bool]
+
+       # Stromgol says "Dou, dou, dou…"
+       var stromgol: String = "Dou, dou, dou…"
+
+       fun isset_stromgol: Bool do return isset _stromgol
+
+       var foo: Int is writable, noinit
+
+       fun noop do end
+
+       protected fun shield(x, y: Int) do return 42 * x - y
+
+       private fun secret
+       do
+       end
+
+       public fun redundant(hello: Float) do
+               if hello.to_i.to_c == 'z' then
+                       do
+                               var z = "hello = {hello}"
+                               abort
+                       catch
+                               output_value hello
+                       end
+               else if true and not false or hello <= hello implies true then
+                       assert (123.digit_count(10) <=> 3) == 0
+                       var decimal = -2442.42e24
+                       var hexadecimal = 0xCAFE_BABE
+                       var octal = 0o007
+                       var binary = 0B1010
+                       var byte = (0XBEEFu8).as(not null)
+                       var long_string = """
+                       \{
+                               print "Hello {{{"#" + (octal * hexadecimal).to_s}}}"
+                       \}}}
+                       """
+                       var long_string2 = '''
+                       """print "Hello {{{"#" + (octal * hexadecimal).to_s}}}"
+                       '''
+               else
+                       while false do end
+                       for i in [0..1[ do
+                               hello += 0
+                               continue
+                       end
+                       loop
+                               break
+                       end label sticker
+                       with y = self.stromgol do
+                       end
+               end
+       end
+
+       fun is_ghost: Bool is abstract
+end
+
+class Concrete
+       super Blurry
+
+       auto_inspect
+
+       fun answer do return once 42
+
+       redef fun is_ghost do return false
+
+       var camelCase: nullable Char = null
+end
+
+extern class CString `{ char * `}
+
+       fun c_foo is extern import CString.to_s, Object.output `{
+               if (0) {
+                       Object_output(CString_to_s(self));
+               }
+       `}
+
+       fun cpp_foo import Object.output in "C++" `{
+               if (true) {
+                       char *s = dynamic_cast<char *>(self);
+               }
+       `}
+
+       fun java_foo in "Java" `{
+               if (!System.out instanceof java.io.PrintStream) {
+                       throw new ClassCastException();
+               }
+       `}
+
+       fun ojbc_foo in "ObjC" `{
+               @autoreleasepool {
+                       NSLog(@"Hello World!");
+               }
+       `}
+end
+
+interface Protocol end
+enum Integral end
+universal Galaxy end
+
+subset Limited
+       isa do return false
+end
+
+fun output_value(value: Object) do value.output
+
+var x = 42
+assert x isa Int
+__debug__ type Int: x