Merge: nitdoc: Do not overwrite search results.
authorJean Privat <jean@pryen.org>
Wed, 19 Nov 2014 15:37:21 +0000 (10:37 -0500)
committerJean Privat <jean@pryen.org>
Wed, 19 Nov 2014 15:37:21 +0000 (10:37 -0500)
Fix the main problem of #882 by avoiding the overwriting of a search
entry when 2 entities has the same name.

TODO: Make the presentation of duplicates less ambiguous.

Note: This PR concerns only the last commit. Others come from PR #907.

Signed-off-by: Jean-Christophe Beaupré <jcbrinfo@users.noreply.github.com>

Pull-Request: #911
Reviewed-by: Jean Privat <jean@pryen.org>
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>

25 files changed:
contrib/friendz/src/friendz.nit
examples/shoot/src/shoot_logic.nit
lib/a_star.nit
lib/bucketed_game.nit
lib/counter.nit
lib/jvm.nit
lib/markdown/markdown.nit
lib/mnit/mnit_injected_input.nit
lib/mnit/tileset.nit
lib/mnit_android/android_assets.nit
lib/standard/collection/union_find.nit
lib/standard/math.nit
lib/standard/string_nit.c
src/interpreter/naive_interpreter.nit
src/markdown.nit
src/modelbuilder.nit
src/testing/testing_doc.nit
tests/base_import_standard.nit [new file with mode: 0644]
tests/base_import_standard2.nit [new file with mode: 0644]
tests/nitunit.args
tests/sav/base_import_standard.res [new file with mode: 0644]
tests/sav/base_import_standard2.res [new file with mode: 0644]
tests/sav/nitunit_args1.res
tests/sav/nitunit_args4.res [new file with mode: 0644]
tests/test_nitunit2.nit [new file with mode: 0644]

index b8187ff..3877fe2 100644 (file)
@@ -834,7 +834,7 @@ redef class Display
        fun measureText(str: String, height: Int): Int
        do
                var font = app.game.font
-               return str.length * (app.game.font.width + app.game.font.hspace)
+               return str.length * (font.width + font.hspace.to_i)
        end
 
        # displays a debug rectangle
index 838c78b..824af57 100644 (file)
@@ -1052,6 +1052,7 @@ end
 
 fun headless_run
 do
+       srand_from 0
        print "Headless run"
        # Only run the playscene
        var scene = new PlayScene(80000,60000)
index 125b053..4108268 100644 (file)
 # ~~~
 module a_star
 
-redef class Object
-       protected fun debug_a_star: Bool do return false
-       private fun debug(msg: String) do if debug_a_star then
-               sys.stderr.write "a_star debug: {msg}\n"
-       end
-end
-
 # General graph node
 class Node
        type N: Node
@@ -130,14 +123,12 @@ class Node
                                var current_bucket = buckets[cost % nbr_buckets]
 
                                if current_bucket.is_empty then # move to next bucket
-                                       debug "b {cost} {cost % nbr_buckets} {buckets[cost % nbr_buckets].hash}"
                                        cost += 1
                                        if cost > max_cost then return null
                                        bucket_searched += 1
 
                                        if bucket_searched > nbr_buckets then break
                                else # found a node
-                                       debug "c {cost}"
                                        frontier_node = current_bucket.pop
 
                                        if frontier_node.open then break
@@ -151,7 +142,6 @@ class Node
                        # at destination
                        else if frontier_node == destination or
                             (alt_targets != null and alt_targets.accept(frontier_node)) then
-                               debug "picked {frontier_node}, is destination"
 
                                var path = new Path[N](cost)
 
@@ -166,11 +156,8 @@ class Node
                        else
                                frontier_node.open = false
 
-                               debug "w exploring adjacents of {frontier_node}"
-
                                for link in frontier_node.links do
                                        var peek_node = link.to
-                                       debug "v {context.is_blocked(link)} {peek_node.last_pathfinding_evocation != graph.pathfinding_current_evocation} {peek_node.best_cost_up_to > frontier_node.best_cost_up_to + context.cost(link)}, {peek_node.best_cost_up_to} > {frontier_node.best_cost_up_to} + {context.cost(link)}"
                                        if not context.is_blocked(link) and
                                         (peek_node.last_pathfinding_evocation != graph.pathfinding_current_evocation or
                                           (peek_node.open and
@@ -190,8 +177,6 @@ class Node
 
                                                var at_bucket = buckets[est_cost % nbr_buckets]
                                                at_bucket.add(peek_node)
-
-                                               debug "u putting {peek_node} at {est_cost} -> {est_cost % nbr_buckets} {at_bucket.hash}, {cost}+{context.cost(link)}"
                                        end
                                end
                        end
index 45a439c..09a4ee8 100644 (file)
@@ -83,6 +83,8 @@ class Buckets[G: Game]
                var current_bucket = buckets[current_bucket_key]
 
                var next_bucket = new HashSet[Bucketable[G]]
+               buckets[current_bucket_key] = next_bucket
+               self.next_bucket = next_bucket
 
                for e in current_bucket do
                        var act_at = e.act_at
@@ -96,9 +98,6 @@ class Buckets[G: Game]
                                end
                        end
                end
-
-               self.next_bucket = next_bucket
-               buckets[current_bucket_key] = next_bucket
        end
 end
 
index 670fc59..3d1555b 100644 (file)
@@ -19,10 +19,33 @@ import poset
 
 # A counter counts occurrences of things
 # Use this instead of a `HashMap[E, Int]`
+#
+# ~~~
+# var c = new Counter[String].from(["a", "a", "b", "b", "b", "c"])
+# assert c["a"]   == 2
+# assert c["b"]   == 3
+# assert c["c"]   == 1
+# assert c["d"]   == 0
+# ~~~
+#
+# The counter class can also be used to gather statistical informations.
+#
+# ~~~~
+# assert c.length == 3   # because 3 distinct values
+# assert c.max    == "b" # because "b" has the most count (3)
+# assert c.avg    == 2.0 # because it is the mean of the counts
+# ~~~~
 class Counter[E: Object]
        super Map[E, Int]
 
        # Total number of counted occurrences
+       #
+       # ~~~
+       # var c = new Counter[String]
+       # assert c.sum == 0
+       # c.inc_all(["a", "a", "b", "b", "b", "c"])
+       # assert c.sum == 6
+       # ~~~
        var sum: Int = 0
 
        private var map = new HashMap[E, Int]
@@ -64,7 +87,24 @@ class Counter[E: Object]
                sum += 1
        end
 
+       # Count one more for each element of `es`
+       fun inc_all(es: Collection[E])
+       do
+               for e in es do inc(e)
+       end
+
+       # A new Counter initialized with `inc_all`.
+       init from(es: Collection[E])
+       do
+               inc_all(es)
+       end
+
        # Return an array of elements sorted by occurrences
+       #
+       # ~~~
+       # var c = new Counter[String].from(["a", "a", "b", "b", "b", "c"])
+       # assert c.sort == ["c", "a", "b"]
+       # ~~~
        fun sort: Array[E]
        do
                var res = map.keys.to_a
@@ -77,7 +117,7 @@ class Counter[E: Object]
        # @toimplement by default just call `to_s` on the element
        protected fun element_to_s(e: E): String
        do
-               do return e.to_s
+               return e.to_s
        end
 
        # Display statistical information
@@ -130,7 +170,14 @@ class Counter[E: Object]
                end
        end
 
-       # Return the element with the highest value
+       # Return the element with the highest value (aka. the mode)
+       #
+       # ~~~
+       # var c = new Counter[String].from(["a", "a", "b", "b", "b", "c"])
+       # assert c.max == "b"
+       # ~~~
+       #
+       # If more than one max exists, the first one is returned.
        fun max: nullable E do
                var max: nullable Int = null
                var elem: nullable E = null
@@ -144,6 +191,13 @@ class Counter[E: Object]
        end
 
        # Return the couple with the lowest value
+       #
+       # ~~~
+       # var c = new Counter[String].from(["a", "a", "b", "b", "b", "c"])
+       # assert c.min == "c"
+       # ~~~
+       #
+       # If more than one min exists, the first one is returned.
        fun min: nullable E do
                var min: nullable Int = null
                var elem: nullable E = null
@@ -156,13 +210,24 @@ class Counter[E: Object]
                return elem
        end
 
-       # Values average
+       # Values average (aka. arithmetic mean)
+       #
+       # ~~~
+       # var c = new Counter[String].from(["a", "a", "b", "b", "b", "c"])
+       # assert c.avg == 2.0
+       # ~~~
        fun avg: Float do
                if values.is_empty then return 0.0
                return (sum / values.length).to_f
        end
 
        # The standard derivation of the counter values
+       #
+       # ~~~
+       # var c = new Counter[String].from(["a", "a", "b", "b", "b", "c"])
+       # assert c.std_dev > 0.81
+       # assert c.std_dev < 0.82
+       # ~~~
        fun std_dev: Float do
                var avg = self.avg
                var sum = 0.0
index 56080a5..8012746 100644 (file)
@@ -173,6 +173,7 @@ extern class JavaVM `{JavaVM *`}
                        JavaVM_jni_error(NULL, "Could not attach current thread to Java VM", res);
                        return NULL;
                }
+               return env;
        `}
 end
 
@@ -216,36 +217,41 @@ extern class JniEnv `{JNIEnv *`}
        # Call a method on `obj` designed by `method_id` with an array `args` of argument returning a JavaObject
        fun call_object_method(obj: JavaObject, method_id: JMethodID, args: nullable Array[nullable Object]): JavaObject import convert_args_to_jni `{
                jvalue * args_tab = JniEnv_convert_args_to_jni(recv, args);
-               (*recv)->CallObjectMethod(recv, obj, method_id, args_tab);
+               jobject res = (*recv)->CallObjectMethod(recv, obj, method_id, args_tab);
                free(args_tab);
+               return res;
        `}
        
        # Call a method on `obj` designed by `method_id` with an array `args` of arguments returning a Bool
        fun call_boolean_method(obj: JavaObject, method_id: JMethodID, args: nullable Array[nullable Object]): Bool import convert_args_to_jni `{
                jvalue * args_tab = JniEnv_convert_args_to_jni(recv, args);
-               return (*recv)->CallBooleanMethod(recv, obj, method_id, args_tab);
+               jboolean res = (*recv)->CallBooleanMethod(recv, obj, method_id, args_tab);
                free(args_tab);
+               return res;
        `}
 
        # Call a method on `obj` designed by `method_id` with an array `args` of arguments returning a Char
        fun call_char_method(obj: JavaObject, method_id: JMethodID, args: nullable Array[nullable Object]): Char import convert_args_to_jni `{
                jvalue * args_tab = JniEnv_convert_args_to_jni(recv, args);
-               return (*recv)->CallCharMethod(recv, obj, method_id, args_tab);
+               jchar res = (*recv)->CallCharMethod(recv, obj, method_id, args_tab);
                free(args_tab);
+               return res;
        `}
 
        # Call a method on `obj` designed by `method_id` with an array `args` of arguments returning an Int
        fun call_int_method(obj: JavaObject, method_id: JMethodID, args: nullable Array[nullable Object]): Int import convert_args_to_jni `{
                jvalue * args_tab = JniEnv_convert_args_to_jni(recv, args);
-               return (*recv)->CallIntMethod(recv, obj, method_id, args_tab);
+               jint res = (*recv)->CallIntMethod(recv, obj, method_id, args_tab);
                free(args_tab);
+               return res;
        `}
        
        # Call a method on `obj` designed by `method_id` with an array `args` of arguments returning a Float
        fun call_float_method(obj: JavaObject, method_id: JMethodID, args: nullable Array[nullable Object]): Float import convert_args_to_jni `{
                jvalue * args_tab = JniEnv_convert_args_to_jni(recv, args);
-               return (*recv)->CallFloatMethod(recv, obj, method_id, args_tab);
+               jfloat res = (*recv)->CallFloatMethod(recv, obj, method_id, args_tab);
                free(args_tab);
+               return res;
        `}
 
        # Call a method on `obj` designed by `method_id` with an array `args` of arguments returning a NativeString
index 5b73d3b..add43e1 100644 (file)
@@ -30,6 +30,7 @@ import template
 # SEE: `String::md_to_html` for a shortcut.
 class MarkdownProcessor
 
+       # `MarkdownEmitter` used for ouput.
        var emitter: MarkdownEmitter is noinit
 
        init do self.emitter = new MarkdownEmitter(self)
@@ -261,6 +262,101 @@ class MarkdownProcessor
                return new LineOther
        end
 
+       # Get the token kind at `pos`.
+       fun token_at(text: Text, pos: Int): Token do
+               var c0: Char
+               var c1: Char
+               var c2: Char
+
+               if pos > 0 then
+                       c0 = text[pos - 1]
+               else
+                       c0 = ' '
+               end
+               var c = text[pos]
+
+               if pos + 1 < text.length then
+                       c1 = text[pos + 1]
+               else
+                       c1 = ' '
+               end
+               if pos + 2 < text.length then
+                       c2 = text[pos + 2]
+               else
+                       c2 = ' '
+               end
+
+               if c == '*' then
+                       if c1 == '*' then
+                               if c0 != ' ' or c2 != ' ' then
+                                       return new TokenStrongStar(pos, c)
+                               else
+                                       return new TokenEmStar(pos, c)
+                               end
+                       end
+                       if c0 != ' ' or c1 != ' ' then
+                               return new TokenEmStar(pos, c)
+                       else
+                               return new TokenNone(pos, c)
+                       end
+               else if c == '_' then
+                       if c1 == '_' then
+                               if c0 != ' ' or c2 != ' 'then
+                                       return new TokenStrongUnderscore(pos, c)
+                               else
+                                       return new TokenEmUnderscore(pos, c)
+                               end
+                       end
+                       if c0 != ' ' or c1 != ' ' then
+                               return new TokenEmUnderscore(pos, c)
+                       else
+                               return new TokenNone(pos, c)
+                       end
+               else if c == '!' then
+                       if c1 == '[' then return new TokenImage(pos, c)
+                       return new TokenNone(pos, c)
+               else if c == '[' then
+                       return new TokenLink(pos, c)
+               else if c == ']' then
+                       return new TokenNone(pos, c)
+               else if c == '`' then
+                       if c1 == '`' then
+                               return new TokenCodeDouble(pos, c)
+                       else
+                               return new TokenCodeSingle(pos, c)
+                       end
+               else if c == '\\' then
+                       if c1 == '\\' or c1 == '[' or c1 == ']' or c1 == '(' or c1 == ')' or c1 == '{' or c1 == '}' or c1 == '#' or c1 == '"' or c1 == '\'' or c1 == '.' or c1 == '<' or c1 == '>' or c1 == '*' or c1 == '+' or c1 == '-' or c1 == '_' or c1 == '!' or c1 == '`' or c1 == '~' or c1 == '^' then
+                               return new TokenEscape(pos, c)
+                       else
+                               return new TokenNone(pos, c)
+                       end
+               else if c == '<' then
+                       return new TokenHTML(pos, c)
+               else if c == '&' then
+                       return new TokenEntity(pos, c)
+               else if c == '^' then
+                       if c0 == '^' or c1 == '^' then
+                               return new TokenNone(pos, c)
+                       else
+                               return new TokenSuper(pos, c)
+                       end
+               else
+                       return new TokenNone(pos, c)
+               end
+       end
+
+       # Find the position of a `token` in `self`.
+       fun find_token(text: Text, start: Int, token: Token): Int do
+               var pos = start
+               while pos < text.length do
+                       if token_at(text, pos).is_same_type(token) then
+                               return pos
+                       end
+                       pos += 1
+               end
+               return -1
+       end
 end
 
 # Emit output corresponding to blocks content.
@@ -276,11 +372,6 @@ class MarkdownEmitter
        # Default is `HTMLDecorator`
        var decorator: Decorator = new HTMLDecorator is writable
 
-       # Create a new `MardownEmitter` using the default `HTMLDecorator`
-       init(processor: MarkdownProcessor) do
-               self.processor = processor
-       end
-
        # Create a new `MarkdownEmitter` using a custom `decorator`.
        init with_decorator(processor: MarkdownProcessor, decorator: Decorator) do
                init processor
@@ -312,7 +403,7 @@ class MarkdownEmitter
                current_text = text
                current_pos = start
                while current_pos < text.length do
-                       var mt = text.token_at(current_pos)
+                       var mt = processor.token_at(text, current_pos)
                        if (token != null and not token isa TokenNone) and
                        (mt.is_same_type(token) or
                        (token isa TokenEmStar and mt isa TokenStrongStar) or
@@ -1112,8 +1203,7 @@ class MDLine
        var next_empty: Bool = false is writable
 
        # Initialize a new MDLine from its string value
-       init(value: String) do
-               self.value = value
+       init do
                self.leading = process_leading
                if leading != value.length then
                        self.is_empty = false
@@ -1675,7 +1765,7 @@ abstract class TokenCode
 
        redef fun emit(v) do
                var a = pos + next_pos + 1
-               var b = v.current_text.find_token(a, self)
+               var b = v.processor.find_token(v.current_text.as(not null), a, self)
                if b > 0 then
                        v.current_pos = b + next_pos
                        while a < b and v.current_text[a] == ' ' do a += 1
@@ -1967,102 +2057,6 @@ end
 
 redef class Text
 
-       # Get the token kind at `pos`.
-       private fun token_at(pos: Int): Token do
-               var c0: Char
-               var c1: Char
-               var c2: Char
-
-               if pos > 0 then
-                       c0 = self[pos - 1]
-               else
-                       c0 = ' '
-               end
-               var c = self[pos]
-
-               if pos + 1 < length then
-                       c1 = self[pos + 1]
-               else
-                       c1 = ' '
-               end
-               if pos + 2 < length then
-                       c2 = self[pos + 2]
-               else
-                       c2 = ' '
-               end
-
-               if c == '*' then
-                       if c1 == '*' then
-                               if c0 != ' ' or c2 != ' ' then
-                                       return new TokenStrongStar(pos, c)
-                               else
-                                       return new TokenEmStar(pos, c)
-                               end
-                       end
-                       if c0 != ' ' or c1 != ' ' then
-                               return new TokenEmStar(pos, c)
-                       else
-                               return new TokenNone(pos, c)
-                       end
-               else if c == '_' then
-                       if c1 == '_' then
-                               if c0 != ' ' or c2 != ' 'then
-                                       return new TokenStrongUnderscore(pos, c)
-                               else
-                                       return new TokenEmUnderscore(pos, c)
-                               end
-                       end
-                       if c0 != ' ' or c1 != ' ' then
-                               return new TokenEmUnderscore(pos, c)
-                       else
-                               return new TokenNone(pos, c)
-                       end
-               else if c == '!' then
-                       if c1 == '[' then return new TokenImage(pos, c)
-                       return new TokenNone(pos, c)
-               else if c == '[' then
-                       return new TokenLink(pos, c)
-               else if c == ']' then
-                       return new TokenNone(pos, c)
-               else if c == '`' then
-                       if c1 == '`' then
-                               return new TokenCodeDouble(pos, c)
-                       else
-                               return new TokenCodeSingle(pos, c)
-                       end
-               else if c == '\\' then
-                       if c1 == '\\' or c1 == '[' or c1 == ']' or c1 == '(' or c1 == ')' or c1 == '{' or c1 == '}' or c1 == '#' or c1 == '"' or c1 == '\'' or c1 == '.' or c1 == '<' or c1 == '>' or c1 == '*' or c1 == '+' or c1 == '-' or c1 == '_' or c1 == '!' or c1 == '`' or c1 == '~' or c1 == '^' then
-                               return new TokenEscape(pos, c)
-                       else
-                               return new TokenNone(pos, c)
-                       end
-               else if c == '<' then
-                       return new TokenHTML(pos, c)
-               else if c == '&' then
-                       return new TokenEntity(pos, c)
-               else if c == '^' then
-                       if c0 == '^' or c1 == '^' then
-                               return new TokenNone(pos, c)
-                       else
-                               return new TokenSuper(pos, c)
-                       end
-               else
-                       return new TokenNone(pos, c)
-               end
-       end
-
-       # Find the position of a `token` in `self`.
-       private fun find_token(start: Int, token: Token): Int do
-               var pos = start
-               while pos < length do
-                       if token_at(pos).is_same_type(token) then
-                               return pos
-                       end
-                       pos += 1
-               end
-               return -1
-       end
-
        # Get the position of the next non-space character.
        private fun skip_spaces(start: Int): Int do
                var pos = start
index 4ed9664..a72b34d 100644 (file)
@@ -78,6 +78,8 @@ redef class App
                var env = "MNIT_SRAND".environ
                if env != "" then
                        srand_from(env.to_i)
+               else
+                       srand_from(0)
                end
 
                var input = "MNIT_READ_INPUT".environ
index 568fad5..5bd5d4d 100644 (file)
@@ -70,11 +70,11 @@ class TileSetFont
 
        # Additional space to insert horizontally between characters
        # A negave value will display tile overlaped
-       var hspace: Int = 0 is writable
+       var hspace: Numeric = 0.0 is writable
 
        # Additional space to insert vertically between characters
        # A negave value will display tile overlaped
-       var vspace: Int = 0 is writable
+       var vspace: Numeric = 0.0 is writable
 
        # The glyph (tile) associated to the caracter `c` according to `chars`
        # Returns null if `c` is not in `chars`
@@ -91,10 +91,11 @@ redef class Display
        # '\n' are rendered as carriage return
        fun text(text: String, font: TileSetFont, x, y: Numeric)
        do
+               x = x.to_f
                var cx = x
-               var cy = y
-               var sw = font.width + font.hspace
-               var sh = font.height + font.vspace
+               var cy = y.to_f
+               var sw = font.width.to_f + font.hspace.to_f
+               var sh = font.height.to_f + font.vspace.to_f
                for c in text.chars do
                        if c == '\n' then
                                cx = x
index 20704b6..2c703bb 100644 (file)
@@ -129,8 +129,8 @@ redef class Opengles1Image
                int has_alpha;
 
                unsigned int row_bytes;
-               png_bytepp row_pointers;
-               unsigned char *pixels;
+               png_bytepp row_pointers = NULL;
+               unsigned char *pixels = NULL;
                unsigned int i;
 
                unsigned char sig[8];
@@ -166,23 +166,24 @@ redef class Opengles1Image
 
                png_get_IHDR(   png_ptr, info_ptr, &width, &height,
                                                &depth, &color_type, NULL, NULL, NULL);
-               if (color_type == PNG_COLOR_TYPE_RGBA)
-                       has_alpha = 1;
-               else if (color_type == PNG_COLOR_TYPE_RGB)
-                       has_alpha = 0;
-               else {
-                       LOGW("unknown color_type");
-                       goto close_png_ptr;
+               has_alpha = color_type & PNG_COLOR_MASK_ALPHA;
+
+               // If we get gray and alpha only, standardize the format of the pixels.
+               // GA is not supported by OpenGL ES 1.
+               if (!(color_type & PNG_COLOR_MASK_COLOR)) {
+                       png_set_gray_to_rgb(png_ptr);
+                       png_set_palette_to_rgb(png_ptr);
+                       png_read_update_info(png_ptr, info_ptr);
                }
 
                LOGW("w: %i, h: %i", width, height);
 
                row_bytes = png_get_rowbytes(png_ptr, info_ptr);
                pixels = malloc(row_bytes * height);
-        row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
+               row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
 
-        for (i=0; i<height; i++)
-            row_pointers[i] = (png_byte*) malloc(row_bytes);
+               for (i=0; i<height; i++)
+                       row_pointers[i] = (png_byte*) malloc(row_bytes);
 
                png_read_image(png_ptr, row_pointers);
 
@@ -199,6 +200,15 @@ redef class Opengles1Image
                else
                        png_destroy_read_struct(&png_ptr, NULL, NULL);
 
+               if (pixels != NULL)
+                       free(pixels);
+
+               if (row_pointers != NULL) {
+                       for (i=0; i<height; i++)
+                               free(row_pointers[i]);
+                       free(row_pointers);
+               }
+
        close_stream:
                return recv;
        `}
index e865703..f9ac76f 100644 (file)
@@ -37,6 +37,17 @@ class DisjointSet[E: Object]
        # The node in the hiearchical structure for each element
        private var nodes = new HashMap[E, DisjointSetNode]
 
+       # The number of subsets in the partition
+       #
+       #     var s = new DisjointSet[Int]
+       #     s.add_all([1,2,3,4,5])
+       #     assert s.number_of_subsets == 5
+       #     s.union_all([1,4,5])
+       #     assert s.number_of_subsets == 3
+       #     s.union(4,5)
+       #     assert s.number_of_subsets == 3
+       var number_of_subsets: Int = 0
+
        # Get the root node of an element
        # require: `has(e)`
        private fun find(e:E): DisjointSetNode
@@ -84,6 +95,7 @@ class DisjointSet[E: Object]
                if nodes.has_key(e) then return
                var ne = new DisjointSetNode
                nodes[e] = ne
+               number_of_subsets += 1
        end
 
        # Are two elements in the same subset?
@@ -171,6 +183,7 @@ class DisjointSet[E: Object]
                                ne.rank = er+1
                        end
                end
+               number_of_subsets -= 1
        end
 
        # Combine the subsets of all elements of `es`
index 5a980aa..2bbb6aa 100644 (file)
@@ -178,7 +178,31 @@ redef class Collection[ E ]
        end
 end
 
+redef class Sys
+       init
+       do
+               srand
+       end
+end
+
 fun atan2(x: Float, y: Float): Float is extern "kernel_Any_Any_atan2_2"
 fun pi: Float is extern "kernel_Any_Any_pi_0"
+
+# Initialize the pseudo-random generator with the given seed.
+# The pseudo-random generator is used by the method `rand` and other to generate sequence of numbers.
+# These sequences are repeatable by calling `srand_from` with a same seed value.
+#
+# ~~~~
+# srand_from(0)
+# var a = 10.rand
+# var b = 100.rand
+# srand_from(0)
+# assert 10.rand == a
+# assert 100.rand == b
+# ~~~~
 fun srand_from(x: Int) is extern "kernel_Any_Any_srand_from_1"
+
+# Reinitialize the pseudo-random generator used by the method `rand` and other.
+# This method is automatically invoked at the begin of the program, so usually, there is no need to manually invoke it.
+# The only exception is in conjunction with `srand_from` to reset the pseudo-random generator.
 fun srand is extern "kernel_Any_Any_srand_0"
index 0159249..1a11e99 100644 (file)
@@ -14,7 +14,7 @@
 // Integer to NativeString method
 char* native_int_to_s(long recv){
        int len = snprintf(NULL, 0, "%ld", recv);
-       char* str = malloc(len);
+       char* str = malloc(len+1);
        sprintf(str, "%ld", recv);
        return str;
 }
index 86bba5f..2879ac9 100644 (file)
@@ -1046,6 +1046,9 @@ redef class AMethPropdef
                        return v.native_string_instance(txt)
                else if pname == "get_time" then
                        return v.int_instance(get_time)
+               else if pname == "srand" then
+                       srand
+                       return null
                else if pname == "srand_from" then
                        srand_from(args[1].to_i)
                        return null
index 01a054c..e254480 100644 (file)
@@ -27,6 +27,9 @@ private class Doc2Mdwn
        # The lines of the current code block, empty is no current code block
        var curblock = new Array[String]
 
+       # Count empty lines between code blocks
+       var empty_lines = 0
+
        fun work(mdoc: MDoc): HTMLTag
        do
                var root = new HTMLTag("div")
@@ -70,16 +73,18 @@ private class Doc2Mdwn
 
                        # Is codeblock? Then just collect them
                        if indent >= 3 then
+                               for i in [0..empty_lines[ do curblock.add("")
+                               empty_lines = 0
                                # to allows 4 spaces including the one that follows the #
                                curblock.add(text)
                                continue
                        end
 
-                       # Was a codblock just before the current line ?
-                       close_codeblock(n or else root)
-
                        # fence opening
                        if text.substring(0,3) == "~~~" then
+                               # Was a codblock just before the current line ?
+                               close_codeblock(n or else root)
+
                                var l = 3
                                while l < text.length and text.chars[l] == '~' do l += 1
                                in_fence = text.substring(0, l)
@@ -96,9 +101,15 @@ private class Doc2Mdwn
                        if text.is_empty or indent < lastindent then
                                n = null
                                ul = null
-                               if text.is_empty then continue
+                               if text.is_empty then
+                                       if not curblock.is_empty then empty_lines += 1
+                                       continue
+                               end
                        end
 
+                       # Was a codblock just before the current line ?
+                       close_codeblock(n or else root)
+
                        # Special first word: new paragraph
                        if text.has_prefix("TODO") or text.has_prefix("FIXME") then
                                n = new HTMLTag("p")
@@ -186,15 +197,20 @@ private class Doc2Mdwn
        do
                # Is there a codeblock to manage?
                if not curblock.is_empty then
+                       empty_lines = 0
+
                        # determine the smalest indent
                        var minindent = -1
                        for text in curblock do
                                var indent = 0
                                while indent < text.length and text.chars[indent] == ' ' do indent += 1
+                               # skip white lines
+                               if indent >= text.length then continue
                                if minindent == -1 or indent < minindent then
                                        minindent = indent
                                end
                        end
+                       if minindent < 0 then minindent = 0
 
                        # Generate the text
                        var btext = new FlatBuffer
index 83f5e0e..1ae7e45 100644 (file)
@@ -705,6 +705,13 @@ class ModelBuilder
                self.toolcontext.info("{mmodule} imports {imported_modules.join(", ")}", 3)
                mmodule.set_imported_mmodules(imported_modules)
 
+               # Force standard to be public if imported
+               for sup in mmodule.in_importation.greaters do
+                       if sup.name == "standard" then
+                               mmodule.set_visibility_for(sup, public_visibility)
+                       end
+               end
+
                # TODO: Correctly check for useless importation
                # It is even doable?
                var directs = mmodule.in_importation.direct_greaters
index f393950..7bb39ca 100644 (file)
@@ -36,6 +36,9 @@ class NitUnitExecutor
 
        redef fun process_code(n: HTMLTag, text: String)
        do
+               # Skip non-blocks
+               if n.tag != "pre" then return
+
                # Try to parse it
                var ast = toolcontext.parse_something(text)
 
@@ -98,7 +101,7 @@ class NitUnitExecutor
                toolcontext.modelbuilder.unit_entities += 1
 
                cpt += 1
-               var file = "{prefix}{cpt}.nit"
+               var file = "{prefix}-{cpt}.nit"
 
                toolcontext.info("Execute doc-unit {tc.attrs["name"]} in {file}", 1)
 
diff --git a/tests/base_import_standard.nit b/tests/base_import_standard.nit
new file mode 100644 (file)
index 0000000..2e76488
--- /dev/null
@@ -0,0 +1,17 @@
+# 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.
+
+private import template
+
+print 1
diff --git a/tests/base_import_standard2.nit b/tests/base_import_standard2.nit
new file mode 100644 (file)
index 0000000..da5111e
--- /dev/null
@@ -0,0 +1,17 @@
+# 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 base_import_standard
+
+print 2
index cc7239d..70d5027 100644 (file)
@@ -1,3 +1,4 @@
 test_nitunit.nit --no-color -o $WRITE
 test_nitunit.nit --gen-suite --only-show
 test_nitunit.nit --gen-suite --only-show --private
+test_nitunit2.nit -o $WRITE
diff --git a/tests/sav/base_import_standard.res b/tests/sav/base_import_standard.res
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/tests/sav/base_import_standard2.res b/tests/sav/base_import_standard2.res
new file mode 100644 (file)
index 0000000..0cfbf08
--- /dev/null
@@ -0,0 +1 @@
+2
index 3a07d20..12b7181 100644 (file)
@@ -1,6 +1,6 @@
-test_nitunit.nit:20,1--22,0: ERROR: nitunit.test_nitunit.test_nitunit::X.<class> (in .nitunit/test_nitunit2.nit): Runtime error: Assert failed (.nitunit/test_nitunit2.nit:5)
+test_nitunit.nit:20,1--22,0: ERROR: nitunit.test_nitunit.test_nitunit::X.<class> (in .nitunit/test_nitunit-2.nit): Runtime error: Assert failed (.nitunit/test_nitunit-2.nit:5)
 
-test_nitunit.nit:23,2--25,0: FAILURE: nitunit.test_nitunit.test_nitunit::X.test_nitunit::X::foo (in .nitunit/test_nitunit3.nit): .nitunit/test_nitunit3.nit:5,8--27: Error: Method or variable 'undefined_identifier' unknown in Sys.
+test_nitunit.nit:23,2--25,0: FAILURE: nitunit.test_nitunit.test_nitunit::X.test_nitunit::X::foo (in .nitunit/test_nitunit-3.nit): .nitunit/test_nitunit-3.nit:5,8--27: Error: Method or variable 'undefined_identifier' unknown in Sys.
 
 test_test_nitunit.nit:36,2--40,4: ERROR: test_foo1 (in file .nitunit/test_test_nitunit_TestX_test_foo1.nit): Runtime error: Assert failed (test_test_nitunit.nit:39)
 
@@ -11,8 +11,8 @@ TestSuites:
 Class suites: 1; Test Cases: 3; Failures: 1
 <testsuites><testsuite package="test_nitunit"><testcase classname="nitunit.test_nitunit.&lt;module&gt;" name="&lt;module&gt;"><system-err></system-err><system-out>assert true
 </system-out></testcase><testcase classname="nitunit.test_nitunit.test_nitunit::X" name="&lt;class&gt;"><system-err></system-err><system-out>assert false
-</system-out><error message="Runtime error: Assert failed (.nitunit/test_nitunit2.nit:5)
+</system-out><error message="Runtime error: Assert failed (.nitunit/test_nitunit-2.nit:5)
 "></error></testcase><testcase classname="nitunit.test_nitunit.test_nitunit::X" name="test_nitunit::X::foo"><system-err></system-err><system-out>assert undefined_identifier
-</system-out><failure message=".nitunit/test_nitunit3.nit:5,8--27: Error: Method or variable 'undefined_identifier' unknown in Sys.
+</system-out><failure message=".nitunit/test_nitunit-3.nit:5,8--27: Error: Method or variable 'undefined_identifier' unknown in Sys.
 "></failure></testcase></testsuite><testsuite package="test_test_nitunit"><testcase classname="nitunit.test_test_nitunit.test_test_nitunit::TestX" name="test_test_nitunit::TestX::test_foo"><system-err></system-err><system-out>out</system-out></testcase><testcase classname="nitunit.test_test_nitunit.test_test_nitunit::TestX" name="test_test_nitunit::TestX::test_foo1"><system-err></system-err><system-out>out</system-out><error message="Runtime error: Assert failed (test_test_nitunit.nit:39)
 "></error></testcase><testcase classname="nitunit.test_test_nitunit.test_test_nitunit::TestX" name="test_test_nitunit::TestX::test_foo2"><system-err></system-err><system-out>out</system-out></testcase></testsuite></testsuites>
\ No newline at end of file
diff --git a/tests/sav/nitunit_args4.res b/tests/sav/nitunit_args4.res
new file mode 100644 (file)
index 0000000..faaa0c9
--- /dev/null
@@ -0,0 +1,21 @@
+DocUnits:
+DocUnits Success
+Entities: 4; Documented ones: 3; With nitunits: 3; Failures: 0
+
+TestSuites:
+No test cases found
+Class suites: 0; Test Cases: 0; Failures: 0
+<testsuites><testsuite package="test_nitunit2"><testcase classname="nitunit.test_nitunit2.standard::kernel::Object" name="test_nitunit2::Object::foo1"><system-err></system-err><system-out>if true then
+
+   assert true
+
+end
+</system-out></testcase><testcase classname="nitunit.test_nitunit2.standard::kernel::Object" name="test_nitunit2::Object::bar2"><system-err></system-err><system-out>if true then
+
+    assert true
+
+end
+</system-out></testcase><testcase classname="nitunit.test_nitunit2.standard::kernel::Object" name="test_nitunit2::Object::foo3"><system-err></system-err><system-out>var a = 1
+assert a == 1
+assert a == 1
+</system-out></testcase></testsuite><testsuite></testsuite></testsuites>
\ No newline at end of file
diff --git a/tests/test_nitunit2.nit b/tests/test_nitunit2.nit
new file mode 100644 (file)
index 0000000..899ff94
--- /dev/null
@@ -0,0 +1,43 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# a fence unit
+#
+# ~~~~
+# if true then
+#
+#    assert true
+#
+# end
+# ~~~~
+fun foo1 do end
+
+# a block unit
+#
+#    if true then
+#
+#        assert true
+#
+#    end
+fun bar2 do end
+
+# a context continuation
+#
+#    var a = 1
+#    assert a == 1
+#
+# bla bla
+#
+#    assert a == 1
+fun foo3 do end