Calling Nitdoc() or Ctrl-D on the word `Container` will now display the following in the preview window.
~~~
# standard::Container[standard::Container::E]
A collection that contains only one item.
Used to pass arguments by reference.
Also used when one want to give a single element when a full
collection is expected
## Class hierarchy
* Direct super classes: Collection
* All super classes: Collection, Object
* Direct sub classes: ListNode
* All sub classes: ListNode
## Properties
+ count(item: E): Int # How many occurrences of `item` are in the collection?
+ first: E # Return the first item of the collection
+ has(item: E): Bool # Is `item` in the collection ?
+ has_all(other: Collection[E]): Bool # Does the collection contain at least each element of `other`?
+ has_exactly(other: Collection[E]): Bool # Does the collection contain exactly all the elements of `other`?
+ has_only(item: E): Bool # Is the collection contain only `item`?
+ is_empty: Bool # Is there no item in the collection?
+ item: E # The stored item
+ item=(item: E) # The stored item
+ iterator: Iterator[E] # Get a new iterator on the collection.
+ join(sep: Text): String # Concatenate and separate each elements with `sep`.
+ length: Int # Number of items in the collection.
+ rand: E # Return a random element form the collection
+ to_a: Array[E] # Build a new array from a collection
~~~
Pull-Request: #1197
Reviewed-by: Jean Privat <jean@pryen.org>
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>
--- /dev/null
+#!/usr/bin/env nit
+#
+# This file is part of NIT ( http://www.nitlanguage.org ).
+# This program is public domain
+
+# Task: Perlin noise
+#
+# See: <http://rosettacode.org/wiki/Perlin_noise>
+module perlin_noise
+
+redef universal Float
+ # Smoothened `self`
+ fun fade: Float do return self*self*self*(self*(self*6.0-15.0)+10.0)
+end
+
+# Improved noise
+class ImprovedNoise
+ # Permutations
+ var p: Array[Int] = [151,160,137,91,90,15,
+ 131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
+ 190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
+ 88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
+ 77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
+ 102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
+ 135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
+ 5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
+ 223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
+ 129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
+ 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
+ 49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
+ 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180]
+
+ # Noise value in [-1..1] at 3d coordinates `x, y, z`
+ fun noise(x, y, z: Float): Float
+ do
+ var xx = x.to_i.bin_and(255)
+ var yy = y.to_i.bin_and(255)
+ var zz = z.to_i.bin_and(255)
+
+ x -= x.floor
+ y -= y.floor
+ z -= z.floor
+
+ var u = x.fade
+ var v = y.fade
+ var w = z.fade
+
+ var a = p[xx ] + yy
+ var aa = p[a ] + zz
+ var ab = p[a+1 ] + zz
+ var b = p[xx+1] + yy
+ var ba = p[b ] + zz
+ var bb = p[b+1 ] + zz
+
+ return w.lerp(v.lerp(u.lerp(grad(p[aa ], x, y, z ),
+ grad(p[ba ], x-1.0, y, z )),
+ u.lerp(grad(p[ab ], x, y-1.0, z ),
+ grad(p[bb ], x-1.0, y-1.0, z ))),
+ v.lerp(u.lerp(grad(p[aa+1], x, y, z-1.0),
+ grad(p[ba+1], x-1.0, y, z-1.0)),
+ u.lerp(grad(p[ab+1], x, y-1.0, z-1.0),
+ grad(p[bb+1], x-1.0, y-1.0, z-1.0))))
+ end
+
+ # Value at a corner of the grid
+ fun grad(hash: Int, x, y, z: Float): Float
+ do
+ var h = hash.bin_and(15)
+ var u = if h < 8 then x else y
+ var v = if h < 4 then y else if h == 12 or h == 14 then x else z
+ return (if h.is_even then u else -u) + (if h.bin_and(2) == 0 then v else -v)
+ end
+end
+
+var map = new ImprovedNoise
+print map.noise(3.14, 42.0, 7.0).to_precision(17)
# Images from 0 to 9
var imgs: Array[Image]
-
- private init(imgs: Array[Image]) do self.imgs = imgs
end
redef class App
import mnit_display
-# Efficienly retrieve tiles in a big image
+# Efficiently retrieve tiles in a big image
class TileSet
# The image containing the tileset
var image: Image
class TileSetFont
super TileSet
- # Each caracter in the image
+ # Each character in the image
# in left->right, then top->bottom order
# Use space (' ') for holes in the tileset
var chars: String
# Additional space to insert horizontally between characters
- # A negave value will display tile overlaped
+ # A negative value will display tile overlapped
var hspace: Numeric = 0.0 is writable
# Additional space to insert vertically between characters
- # A negave value will display tile overlaped
+ # A negative value will display tile overlapped
var vspace: Numeric = 0.0 is writable
- # The glyph (tile) associated to the caracter `c` according to `chars`
+ # The glyph (tile) associated to the character `c` according to `chars`
# Returns null if `c` is not in `chars`
fun char(c: Char): nullable Image
do
if i == -1 then return null
return subimages[i]
end
+
+ # Distance between the beginning of a letter tile and the beginning of the next letter tile
+ fun advance: Numeric do return width.add(hspace)
+
+ # Distance between the beginning and the end of the longest line of `text`
+ fun text_width(text: String): Numeric
+ do
+ var lines = text.split('\n')
+ if lines.is_empty then return 0
+
+ var longest = 0
+ for line in lines do longest = longest.max(line.length)
+
+ return longest.mul(advance)
+ end
+
+ # Distance between the top of the first line to the bottom of the last line in `text`
+ fun text_height(text: Text): Numeric
+ do
+ if text.is_empty then return 0
+
+ var n_lines = text.chars.count('\n')
+ return (n_lines+1).mul(height.add(vspace)).sub(vspace)
+ end
end
redef class Display
--- /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.
+
+# Provides the noise generators `PerlinNoise` and `InterpolatedNoise`
+module noise
+
+# 2D noise generator
+abstract class Noise
+
+ # Get the noise value at `x`, `y`
+ #
+ # The coordinates `x`, `y` can be floats of any size.
+ #
+ # Returns a value between or equal to `min` and `max`.
+ fun [](x, y: Float): Float is abstract
+
+ # Lowest possible value returned by `[]`
+ #
+ # Default at `0.0`.
+ #
+ # Require: `min < max`
+ var min = 0.0 is writable
+
+ # Highest possible value returned by `[]`
+ #
+ # Default at `1.0`.
+ #
+ # Require: `min < max`
+ var max = 1.0 is writable
+
+ # Distance between reference points of the noise
+ #
+ # Higher values will result in smoother noise and
+ # lower values will result in steeper curves.
+ #
+ # Default at `1.0`.
+ var period = 1.0 is writable
+
+ # Amplitude of the values returned by `[]`
+ fun amplitude: Float do return max - min
+
+ # Set the desired amplitude of the values returned by `[]`
+ #
+ # Will only modify `max`, `min` stays the same.
+ fun amplitude=(value: Float) do max = min + value
+
+ # Frequency of this noise
+ fun frequency: Float do return 1.0/period
+
+ # Set the frequency if this noise
+ fun frequency=(value: Float) do period = 1.0/value
+
+ # Seed to the random number generator `gradient_vector`
+ #
+ # By default, `seed` has a random value created with `Int::rand`.
+ var seed: Int = 19559.rand is lazy, writable
+end
+
+# 2D Perlin noise generator using layered `InterpolatedNoise`
+#
+# Get values at any coordinates with `[]`.
+# The behavior of this generator can be customized using its attributes `min`,
+# `max`, `period` and `seed`.
+#
+# This noise is more realistic and less smooth than the `InterpolatedNoise`.
+#
+# Due to implementation logic, the full amplitude cannot be reached.
+# In practice, only `amplitude * (1.0 - 1.0 / n_levels)` is covered.
+#
+# This implementation uses a custom deterministic pseudo random number
+# generator to set `InterpolatedNoise::seed` of the `layers`.
+# It is seeded with the local `seed` and can be further customized by
+# redefining `pseudo_random`.
+# This process do not require any state, so this class only holds the
+# attributes of the generator and does not keep any generated data.
+#
+# ## Usage example
+#
+# ~~~
+# var map = new PerlinNoise
+# map.min = 0.0
+# map.max = 16.0
+# map.period = 20.0
+# map.seed = 0
+#
+# var max = 0.0
+# var min = 100.0
+# for y in 30.times do
+# for x in 70.times do
+# # Get a value at x, y
+# var val = map[x.to_f, y.to_f]
+# printn val.to_i.to_hex
+#
+# max = max.max(val)
+# min = min.min(val)
+# end
+# print ""
+# end
+# assert max <= map.max
+# assert min >= map.min
+# ~~~
+#
+# ## Result at seed == 0
+#
+# ~~~raw
+# 76666555444322234567789abbcbbaabbaa98777766665665566667888987655444444
+# 776665554443322234567789abbbbbbbbba98777766666665556666788998654444444
+# 777766544443322234566789abbbbbbbbaa99877777776665556666788888655444444
+# 777776444443322244556679abbbccbbbaa99877777776655556666688888655444444
+# 777766444444332244555678abbbccbbbaa99887787877655556666678888654444444
+# 8887654344443333444456789abcccbbaa999877888886555555666688777654444455
+# 8887654344443333444456789abbcdcbaa999887889887655555566677777654444456
+# 7876654434444444444456778abbcccaaa999888899888655555566677777654444556
+# 78765544344445544444567789bbccca99999888899988765555566666667654445566
+# 77765444344455554445567889bbccba99999998999988765555566555666654445667
+# 7765444334555665445556788abbbba988998999999988765555566545556554456677
+# 87654444334556655455567899bbbba998888899999887766555566544556555456777
+# 87655444334566665555567899bbbbba98888899988888776555566544556555556777
+# 97655544334566665555567899abbbba98888899988888776555655544456555667777
+# 97655544444566665556667899aaaaba98888999877777776555555444456666667777
+# 866555444456666666566789999aaaaa98889998877777766556544443456667777777
+# 976555445556776666666789aa99aaaa98889998876777666555544444456677887777
+# 9765554556667777776667899999aaaa98889988876676666555443444446678888888
+# 87655555666777788766678999899aaa99889988776666666554433344446789998888
+# 876555566777788888766889998899a999889987776666666543333334456899a99899
+# 766556677877889998877888888889a99998888777666666653222233345799aaa999a
+# 6665556777777899998878988888899999999887777656666543222233446899aa999a
+# 6655456777777899999888988888889999a988887776566666532222233457899a999a
+# 665555677777789999998998888878899aa9888887765666655322222234578899aa9a
+# 665555677777789999a98888888877899aa9888887766666655322222234467899aa9a
+# 65666677667778999aaa988878877789aaa9888887776676654322222344467889aa9a
+# 55566677767788899aaa987777777789aaa9888887776666654322222344567889aaa9
+# 5566767777788889aaaa987777777789aaaa988887777666555432122344556899aaa9
+# 5567777777788889aaaa977777777789aaaa99888777766555543212234555689aaaaa
+# 5667877777889989aaa9876677777889aaaa99888777765554443212334555689aaaaa
+# ~~~
+class PerlinNoise
+ super Noise
+
+ # Desired number of `layers`
+ #
+ # This attribute must be assigned before any call to `layers` or `[]`.
+ #
+ # By default, it is the highest integer under the logarithm base 2
+ # of `amplitude`, or 4, whichever is the highest.
+ var n_layers: Int = 4.max(amplitude.abs.log_base(2.0).to_i) is lazy, writable
+
+ # Layers of `InterpolatedNoise` composing `self`
+ var layers: Array[InterpolatedNoise] is lazy do
+ var layers = new Array[InterpolatedNoise]
+
+ var max = max
+ var min = min
+ var period = period
+ var seed = seed
+ for l in n_layers.times do
+ min = min / 2.0
+ max = max / 2.0
+ seed = pseudo_random(seed)
+
+ var layer = new InterpolatedNoise
+ layer.min = min
+ layer.max = max
+ layer.period = period
+ layer.seed = seed
+ layers.add layer
+
+ period = period / 2.0
+ end
+ return layers
+ end
+
+ redef fun [](x, y)
+ do
+ var val = 0.0
+ for layer in layers do
+ val += layer[x, y]
+ end
+ return val
+ end
+
+ # Deterministic pseudo random number generator
+ #
+ # Used to get seeds for layers from the previous layers or `seed`.
+ protected fun pseudo_random(value: Int): Int
+ do
+ return value + 2935391 % 954847
+ end
+end
+
+# Simple interpolated noise
+#
+# Generates smoother noise than `PerlinNoise`.
+#
+# Each coordinates at a multiple of `period` defines a random vector and
+# values in between are interpolated from these vectors.
+#
+# This implementation uses a custom deterministic pseudo random number
+# generator seeded with `seed`.
+# It can be further customized by redefining `gradient_vector`.
+# This process do not require any state, so this class only holds the
+# attributes of the generator and does not keep any generated data.
+#
+# ## Usage example
+#
+# ~~~
+# var map = new InterpolatedNoise
+# map.min = 0.0
+# map.max = 16.0
+# map.period = 20.0
+# map.seed = 0
+#
+# var max = 0.0
+# var min = 100.0
+# for y in 30.times do
+# for x in 70.times do
+# # Get a value at x, y
+# var val = map[x.to_f, y.to_f]
+# printn val.to_i.to_hex
+#
+# max = max.max(val)
+# min = min.min(val)
+# end
+# print ""
+# end
+# assert max <= map.max
+# assert min >= map.min
+# ~~~
+#
+# ## Result at seed == 0
+#
+# ~~~raw
+# 89abcddeeeeeeeddcba9877666555555555666778766555544444555566789abcddeee
+# 789abcddeeeeeeddccba887766655555555566677766555544444555566779abcddeee
+# 689abcddeeeeeeeddcba988776655555555555667666555554455555566778abccdeee
+# 678abccdeeeeeeeedccba988766655555555555666655555555555556666789abcddee
+# 5789abcddeeeeeeeddcba998776655544444555666655555555555556666789abcddee
+# 5689abcddeeeeeeeedccba98776655544444455566555555555555566666789abccdde
+# 4679abccdeeeffeeeddcba98776655444444445565555555555555666666789abbcddd
+# 4678abccdeeeffeeeedcba98876555444444444555555555566666666666689aabccdd
+# 46789abcdeeeeffeeedccb988765544443344445555566666666666666666789abccdd
+# 45789abcddeeeffeeeddcb987765544433334445555666666666666666666789abbccd
+# 45789abcddeeeeeeeeddcb987665444333333445556666666777777777766789aabccc
+# 45789abcddeeeeeeeeddca987655443333333445566666777777777777776789aabbcc
+# 45789abcddeeeeeeeedcca9876544333333333455666777777788877777767899aabbc
+# 46789abcddeeeeeeeddcba9876544333222333455667777888888888877767899aabbb
+# 46789abcdddeeeeedddcba87655433222223334566777888889998888877778899aabb
+# 5678aabcdddeeeedddccb987654332222222334566778889999999998887778899aaab
+# 5689abbcddddeedddccba9865443222222223345677889999aaaa99998877788999aaa
+# 6789abbcddddddddccbba8765432221111223345678899aaaaaaaaaa9988778889999a
+# 6789abccdddddddccbba9865433221111122344577899aabbbbbbbaaa9987788889999
+# 789abbccddddddccbba9876543211111111234567899aabbbccccbbbaa987788888899
+# 889abbccdddddccbba9886543211000001123456889abbcccccccccbba988888888888
+# 899abbcccddddcccbaa9875432211000011223457899abbcccccccccbba98888888888
+# 899abbccccddccccbba9876533211000001123456789aabccccddcccbbaa9998888888
+# 899abbccccccccccbbaa9765432111000011223456899abbcccdddcccbba9999988888
+# 899abbbcccccccccbbaa9865432211000011123456789abbccdddddcccbba999988888
+# 899aabbcccccccccbbaa9875433211100001122346789abbccddddddcccbaa99988888
+# 899aabbbcccccccbbbbaa876543211100001122345689aabccdddddddccbaaa9988887
+# 899aabbbbbbccbbbbbbaa876543221110001112335679aabccddddddddcbbaa9988877
+# 899aaabbbbbbbbbbbbbaa9765433211111111123356789abccddddddddccbaa9988777
+# 8999aaaabbbbbbbbbbaaa9765433221111111122356789abccdddeedddccbaa9988777
+# ~~~
+class InterpolatedNoise
+ super Noise
+
+ redef fun [](x, y)
+ do
+ x = x/period
+ y = y/period
+
+ # Get grid coordinates
+ var x0 = if x > 0.0 then x.to_i else x.to_i - 1
+ var x1 = x0 + 1
+ var y0 = if y > 0.0 then y.to_i else y.to_i - 1
+ var y1 = y0 + 1
+
+ # Position in grid
+ var sx = x - x0.to_f
+ var sy = y - y0.to_f
+
+ # Interpolate
+ var n0 = gradient_dot_product(x0, y0, x, y)
+ var n1 = gradient_dot_product(x1, y0, x, y)
+ var ix0 = sx.lerp(n0, n1)
+ n0 = gradient_dot_product(x0, y1, x, y)
+ n1 = gradient_dot_product(x1, y1, x, y)
+ var ix1 = sx.lerp(n0, n1)
+ var val = sy.lerp(ix0, ix1)
+
+ # Return value in [min...max] from val in [-0.5...0.5]
+ val += 0.5
+ return val.lerp(min, max)
+ end
+
+ # Get the component `w` of the gradient unit vector at `x`, `y`
+ #
+ # `w` at 0 targets the X axis, at 1 the Y axis.
+ #
+ # Returns a value between -1.0 and 1.0.
+ #
+ # Require: `w == 0 or w == 1`
+ protected fun gradient_vector(x, y, w: Int): Float
+ do
+ assert w == 0 or w == 1
+
+ # Use our own deterministic pseudo random number generator
+ #
+ # These magic prime numbers were determined good enough by
+ # non-emperical experimentation. They may need to be changed/improved.
+ var i = 17957*seed + 45127*x + 22613*y
+ var mod = 19031
+
+ var angle = (i%mod).to_f*2.0*pi/mod.to_f
+ if w == 0 then return angle.cos
+ return angle.sin
+ end
+
+ private fun gradient_dot_product(ix, iy: Int, x, y: Float): Float
+ do
+ var dx = x - ix.to_f
+ var dy = y - iy.to_f
+
+ return dx*gradient_vector(ix, iy, 0) + dy*gradient_vector(ix, iy, 1)
+ end
+end
# #assert 0.0.pow(9.0) == 0.0
fun pow(e: Float): Float is extern "kernel_Float_Float_pow_1"
- # Returns the logarithm of `self`.
+ # Natural logarithm of `self`.
#
# assert 0.0.log.is_inf == -1
# #assert 1.0.log == 0.0
fun log: Float is extern "kernel_Float_Float_log_0"
+ # Logarithm of `self` to base `base`.
+ #
+ # assert 100.0.log_base(10.0) == 2.0
+ # assert 256.0.log_base(2.0) == 8.0
+ fun log_base(base: Float): Float do return log/base.log
+
# Returns *e* raised to `self`.
fun exp: Float is extern "kernel_Float_Float_exp_0"
# assert -1.34.round == -1.0
# assert -1.67.round == -2.0
fun round: Float is extern "round"
-
+
# Returns a random `Float` in `[0.0 .. self[`.
fun rand: Float is extern "kernel_Float_Float_rand_0"
end
private fun is_inf_extern: Bool is extern "isinf"
+
+ # Linear interpolation between `a` and `b` using `self` as weight
+ #
+ # ~~~
+ # assert 0.0.lerp(0.0, 128.0) == 0.0
+ # assert 0.5.lerp(0.0, 128.0) == 64.0
+ # assert 1.0.lerp(0.0, 128.0) == 128.0
+ # assert -0.5.lerp(0.0, 128.0) == -64.0
+ # ~~~
+ fun lerp(a, b: Float): Float do return (1.0 - self) * a + self * b
end
redef class Collection[ E ]
end
end
+redef class SequenceRead[E]
+ # Optimized for large collections using `[]`
+ redef fun rand
+ do
+ assert not is_empty
+ return self[length.rand]
+ end
+end
+
redef class Sys
init
do
if _buffer_pos + i >= _buffer.length then
var from = _buffer_pos
_buffer_pos = _buffer.length
+ if from == 0 then return _buffer.to_s
return _buffer.substring_from(from).to_s
end
_buffer_pos += i
# String Specific Methods #
##################################################
- private init with_infos(items: NativeString, len: Int, from: Int, to: Int)
+ # Low-level creation of a new string with given data.
+ #
+ # `items` will be used as is, without copy, to retrieve the characters of the string.
+ # Aliasing issues is the responsibility of the caller.
+ private init with_infos(items: NativeString, length: Int, from: Int, to: Int)
do
self.items = items
- length = len
+ self.length = length
index_from = from
index_to = to
end
# Create a new empty string.
init do end
+ # Low-level creation a new buffer with given data.
+ #
+ # `items` will be used as is, without copy, to store the characters of the buffer.
+ # Aliasing issues is the responsibility of the caller.
+ #
+ # If `items` is shared, `written` should be set to true after the creation
+ # so that a modification will do a copy-on-write.
+ private init with_infos(items: NativeString, capacity, length: Int)
+ do
+ self.items = items
+ self.length = length
+ self.capacity = capacity
+ end
+
# Create a new string copied from `s`.
init from(s: Text)
do
init with_capacity(cap: Int)
do
assert cap >= 0
- # _items = new NativeString.calloc(cap)
items = new NativeString(cap+1)
capacity = cap
length = 0
if from < 0 then from = 0
if count > length then count = length
if from < count then
- var r = new FlatBuffer.with_capacity(count - from)
- while from < count do
- r.chars.push(items[from])
- from += 1
- end
+ var len = count - from
+ var r_items = new NativeString(len)
+ items.copy_to(r_items, len, from, 0)
+ var r = new FlatBuffer.with_infos(r_items, len, len)
return r
else
return new FlatBuffer
var modelbuilder = v.compiler.modelbuilder
var val = constant_value
var node = modelbuilder.mpropdef2node(self)
+
+ if is_abstract then
+ var cn = v.class_name_string(arguments.first)
+ v.current_node = node
+ v.add("PRINT_ERROR(\"Runtime error: Abstract method `%s` called on `%s`\", \"{mproperty.name.escape_to_c}\", {cn});")
+ v.add_raw_abort
+ return null
+ end
+
if node isa APropdef then
var oldnode = v.current_node
v.current_node = node
redef class AMethPropdef
redef fun compile_to_c(v, mpropdef, arguments)
do
- if mpropdef.is_abstract then
- var cn = v.class_name_string(arguments.first)
- v.add("PRINT_ERROR(\"Runtime error: Abstract method `%s` called on `%s`\", \"{mpropdef.mproperty.name.escape_to_c}\", {cn});")
- v.add_raw_abort
- return
- end
-
# Call the implicit super-init
var auto_super_inits = self.auto_super_inits
if auto_super_inits != null then
var val = mpropdef.constant_value
var node = modelbuilder.mpropdef2node(mpropdef)
+ if mpropdef.is_abstract then
+ if node != null then
+ self.frames.unshift new Frame(node, mpropdef, args)
+ end
+ fatal("Abstract method `{mpropdef.mproperty.name}` called on `{args.first.mtype}`")
+ abort
+ end
+
if node isa APropdef then
self.parameter_check(node, mpropdef, args)
return node.call(self, mpropdef, args)
v.write_variable(variable, arguments[i+1])
end
- if mpropdef.is_abstract then
- v.fatal("Abstract method `{mpropdef.mproperty.name}` called on `{arguments.first.mtype}`")
- abort
- end
-
# Call the implicit super-init
var auto_super_inits = self.auto_super_inits
if auto_super_inits != null then
evaluate_expr(v, recv)
return
end
- var mtype = self.mpropdef.static_mtype.as(not null)
+ var mpropdef = self.mpropdef
+ if mpropdef == null then return
+ var mtype = mpropdef.static_mtype.as(not null)
mtype = mtype.anchor_to(v.mainmodule, recv.mtype.as(MClassType))
if mtype isa MNullableType then
v.write_attribute(self.mpropdef.mproperty, recv, v.null_instance)
redef fun build_property(modelbuilder, mclassdef)
do
var mclass = mclassdef.mclass
+ var nid2 = n_id2
+ var name = nid2.text
+
+ var atabstract = self.get_single_annotation("abstract", modelbuilder)
+ if atabstract == null then
+ if mclass.kind == interface_kind then
+ modelbuilder.error(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
+ else if mclass.kind == enum_kind then
+ modelbuilder.error(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
+ else if mclass.kind == extern_kind then
+ modelbuilder.error(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.")
+ end
- var name: String
- name = self.n_id2.text
-
- if mclass.kind == interface_kind or mclassdef.mclass.kind == enum_kind then
- modelbuilder.error(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
- else if mclass.kind == enum_kind then
- modelbuilder.error(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
- else if mclass.kind == extern_kind then
- modelbuilder.error(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.")
+ var mprop = new MAttribute(mclassdef, "_" + name, private_visibility)
+ var mpropdef = new MAttributeDef(mclassdef, mprop, self.location)
+ self.mpropdef = mpropdef
+ modelbuilder.mpropdef2npropdef[mpropdef] = self
end
- # New attribute style
- var nid2 = self.n_id2
- var mprop = new MAttribute(mclassdef, "_" + name, private_visibility)
- var mpropdef = new MAttributeDef(mclassdef, mprop, self.location)
- self.mpropdef = mpropdef
- modelbuilder.mpropdef2npropdef[mpropdef] = self
-
var readname = name
var mreadprop = modelbuilder.try_get_mproperty_by_name(nid2, mclassdef, readname).as(nullable MMethod)
if mreadprop == null then
var mvisibility = new_property_visibility(modelbuilder, mclassdef, self.n_visibility)
mreadprop = new MMethod(mclassdef, readname, mvisibility)
if not self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, mreadprop) then return
- mreadprop.deprecation = mprop.deprecation
else
if not self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, true, mreadprop) then return
check_redef_property_visibility(modelbuilder, self.n_visibility, mreadprop)
self.mreadpropdef = mreadpropdef
modelbuilder.mpropdef2npropdef[mreadpropdef] = self
set_doc(mreadpropdef, modelbuilder)
- mpropdef.mdoc = mreadpropdef.mdoc
+ if mpropdef != null then mpropdef.mdoc = mreadpropdef.mdoc
+ if atabstract != null then mreadpropdef.is_abstract = true
has_value = n_expr != null or n_block != null
+ if atabstract != null and has_value then
+ modelbuilder.error(atabstract, "Error: `abstract` attributes cannot have an initial value")
+ return
+ end
+
var atnoinit = self.get_single_annotation("noinit", modelbuilder)
if atnoinit == null then atnoinit = self.get_single_annotation("noautoinit", modelbuilder)
if atnoinit != null then
modelbuilder.error(atnoinit, "Error: `noautoinit` attributes cannot have an initial value")
return
end
+ if atabstract != null then
+ modelbuilder.error(atnoinit, "Error: `noautoinit` attributes cannot be abstract")
+ return
+ end
end
var atlazy = self.get_single_annotation("lazy", modelbuilder)
end
mwriteprop = new MMethod(mclassdef, writename, mvisibility)
if not self.check_redef_keyword(modelbuilder, mclassdef, nwkwredef, false, mwriteprop) then return
- mwriteprop.deprecation = mprop.deprecation
+ mwriteprop.deprecation = mreadprop.deprecation
else
if not self.check_redef_keyword(modelbuilder, mclassdef, nwkwredef or else n_kwredef, true, mwriteprop) then return
if atwritable != null then
var mwritepropdef = new MMethodDef(mclassdef, mwriteprop, self.location)
self.mwritepropdef = mwritepropdef
modelbuilder.mpropdef2npropdef[mwritepropdef] = self
- mwritepropdef.mdoc = mpropdef.mdoc
+ mwritepropdef.mdoc = mreadpropdef.mdoc
+ if atabstract != null then mwritepropdef.is_abstract = true
end
redef fun build_signature(modelbuilder)
do
+ var mreadpropdef = self.mreadpropdef
var mpropdef = self.mpropdef
- if mpropdef == null then return # Error thus skipped
- var mclassdef = mpropdef.mclassdef
+ if mreadpropdef == null then return # Error thus skipped
+ var mclassdef = mreadpropdef.mclassdef
var mmodule = mclassdef.mmodule
var mtype: nullable MType = null
- var mreadpropdef = self.mreadpropdef
var ntype = self.n_type
if ntype != null then
var inherited_type: nullable MType = null
# Inherit the type from the getter (usually an abstract getter)
- if mreadpropdef != null and not mreadpropdef.is_intro then
+ if not mreadpropdef.is_intro then
var msignature = mreadpropdef.mproperty.intro.msignature
if msignature == null then return # Error, thus skipped
inherited_type = msignature.return_mtype
var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "String")
if cla != null then mtype = cla.mclass_type
else
- modelbuilder.error(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
+ modelbuilder.error(self, "Error: Untyped attribute {mreadpropdef}. Implicit typing allowed only for literals and new.")
end
if mtype == null then return
end
if mtype == null then
- modelbuilder.error(self, "Error: Untyped attribute {mpropdef}")
+ modelbuilder.error(self, "Error: Untyped attribute {mreadpropdef}")
return
end
- mpropdef.static_mtype = mtype
+ if mpropdef != null then
+ mpropdef.static_mtype = mtype
+ end
- if mreadpropdef != null then
+ do
var msignature = new MSignature(new Array[MParameter], mtype)
mreadpropdef.msignature = msignature
end
if mproperty.mpropdefs.length <= 1 then return
# If all definitions of a method are live, we can remove the definition of the totry set
for d in mproperty.mpropdefs do
- if d.is_abstract then continue
if not live_methoddefs.has(d) then return
end
#print "full property: {mpropdef.mproperty} for {mpropdef.mproperty.mpropdefs.length} definitions"
redef class AAttrPropdef
redef fun do_typing(modelbuilder: ModelBuilder)
do
+ if not has_value then return
+
var mpropdef = self.mpropdef.as(not null)
var v = new TypeVisitor(modelbuilder, mpropdef.mclassdef.mmodule, mpropdef)
self.selfvariable = v.selfvariable
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import kernel
+
+interface Foo
+ var a: Object is abstract
+ #alt1#var b = 1 is abstract
+ #alt2#var b is abstract, noautoinit
+end
+
+class Bar
+ super Foo
+ redef var a
+end
+
+class Baz
+ super Foo
+ redef fun a do return 100
+ redef fun a=(x) do (101).output
+end
+
+class FooBar
+ super Foo
+end
+
+var f: Foo = new Bar(1)
+f.a.output
+f.a = 2
+f.a.output
+
+f = new Baz
+f.a.output
+f.a = 3
+f.a.output
+
+f = new FooBar
+#alt3#f.a.output
+#alt4#f.a = 4
--- /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.
+
+# Function that recursively allocate and concatenate strings.
+#
+# It is related to the Fibonacci sequence since:
+#
+# * `strfib(0).length == 0`
+# * `strfib(1).length == 2`
+# * `strfib(n).length = strfib(n-1).length + strfib(n-2).length + 2`
+fun strfib(i: Int): String
+do
+ if i == 0 then return ""
+ if i == 1 then return "()"
+ return "({strfib(i-2)}{strfib(i-1)})"
+end
+
+var quiet = false
+if args.has("-q") then
+ quiet = true
+ args.remove("-q")
+end
+
+var n = 5
+if args.length > 0 then n = args.first.to_i
+var res = strfib(n)
+
+if quiet then
+ print res.length
+else
+ print res
+end
alt/base_attr5_alt17.nit:47,12--14: Error: No property B::bar is inherited. Remove the redef keyword to define a new property.
-alt/base_attr5_alt17.nit:47,12--14: Error: Untyped attribute base_attr5_alt17#B#_bar
--- /dev/null
+1
+2
+100
+101
+100
--- /dev/null
+alt/base_attr_abstract_alt1.nit:19,15--22: Error: `abstract` attributes cannot have an initial value
--- /dev/null
+alt/base_attr_abstract_alt2.nit:20,6: Error: Untyped attribute base_attr_abstract_alt2#Foo#b
+alt/base_attr_abstract_alt2.nit:20,21--30: Error: `noautoinit` attributes cannot be abstract
--- /dev/null
+Runtime error: Abstract method `a` called on `FooBar` (alt/base_attr_abstract_alt3.nit:18)
+1
+2
+100
+101
+100
--- /dev/null
+Runtime error: Abstract method `a=` called on `FooBar` (alt/base_attr_abstract_alt4.nit:18)
+1
+2
+100
+101
+100
--- /dev/null
+((()(()))((())(()(()))))
-error_kern_attr_int.nit:18,6--9: Error: Attempt to define attribute toto in the interface Int.
+error_kern_attr_int.nit:18,6--9: Error: Attempt to define attribute toto in the enum class Int.
--- /dev/null
+0.13691995878400010