Warning on `if a == true then` constructions.
Pull-Request: #2520
Reviewed-by: Jean-Christophe Beaupré <jcbrinfo.public@gmail.com>
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
-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/
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"
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
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
# 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
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")
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
# 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
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
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
import game_logic
import spritesheet
-import app::audio
redef class Spritesheet
# Largest meteors, organized by color
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
s += 0.05 * texture2D(tex_displace, tex_coord).r;
gl_Position = (vec4(coord.xyz * s, 1.0) * rotation + translation) * mvp;
-
}
""" @ glsl_vertex_shader
end
import gamnit::depth
-import gamnit::keys
-import app::audio
import base
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# 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
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
# 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
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
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
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
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)
# Framework for 3D games in Nit
module depth
+import flat
intrude import more_materials
import more_models
import model_dimensions
# 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
#
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)
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
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)
{
if (use_texture) {
gl_FragColor = texture2D(texture0, gl_PointCoord) * v_color;
- if (gl_FragColor.a <= 0.01) discard;
} else {
gl_FragColor = v_color;
}
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
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
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
# 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]
# ---
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),
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
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
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# 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
# 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
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
#
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
# 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
}
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
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`
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
# 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
# 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
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
# 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
# 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
end
end
-# Texture with its own pixels
+# Texture with its own pixel data
class RootTexture
super Texture
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)
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
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)
# 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
# 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)
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)
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)
# 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
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
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
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
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
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# 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
module more_collections is serialize
import serialization
+import poset
# Simple way to store an `HashMap[K, Array[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]]`
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.
#
# ~~~~
# 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
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
" 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.
# 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
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 \
# Packages needed for contrib, platforms and FFI
ant \
clang \
+ cmake \
default-jdk \
file \
inkscape \
&& 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/
<?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>(?<![\w\.])\%{float}(?![\w\.])</match>
- </context>
-
- <context id="decimal" style-ref="decimal">
- <match>(?<![\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>
+ \^=? |
+ ~ |
+ <<?=? |
+ <=> |
+ ==? |
+ >>?=? |
+ \| |
+ -=? |
+ , |
+ ; |
+ ::? |
+ !=? |
+ /=? |
+ \.{1,3} |
+ \( |
+ \) |
+ \[ |
+ \] |
+ @ |
+ \*\*?=? |
+ &=? |
+ %=? |
+ \+=?
+ </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>
" 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
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"
# 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
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
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
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Main frontend phases plus code generation phases
+module code_gen
+
+import frontend
+import actors_generation_phase
+import serialization_code_gen_phase
# 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
import modelize
import semantize
import div_by_zero
-import serialization_phase
+import serialization_model_phase
import deriving
import check_annotation
import parse_annotations
import parallelization_phase
import i18n_phase
import regex_phase
-import actors_generation_phase
import actors_injection_phase
redef class ToolContext
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# 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
# 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
# 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
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
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
module nit
import interpreter
-import frontend
+import frontend::code_gen
import parser_util
import vm
# A Nit compiler
module nitc
-import frontend
+import frontend::code_gen
import compiler
import transform
# 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
# 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
module nitvm
import vm
-import frontend
+import frontend::code_gen
# Create a tool context to handle options and paths
var toolcontext = new ToolContext
# 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.
-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::[]=`.
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`.
-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)`.
-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)`.
-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)`.
-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`.
-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`.
-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`.
-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`.
-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`.
-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`.
-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`.
-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`.
-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`.
--- /dev/null
+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.
--- /dev/null
+#! /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