Merge: Tnitter: read the latest tnits on the go with the new Tnitter portable app!
authorJean Privat <jean@pryen.org>
Fri, 13 Nov 2015 13:29:29 +0000 (08:29 -0500)
committerJean Privat <jean@pryen.org>
Fri, 13 Nov 2015 13:29:29 +0000 (08:29 -0500)
Intro a portable client for Tnitter listing the more recent 16 tnits. It is more of a test and example on using `AsyncHttpRequest` to do both simple request to a REST server and implement push notifications using an open request. By design, this client does not support posting Tnits, this feature would require much more code and it may be simplified by future services in the lib.

To support the client the server has a few new REST interfaces. One to list the tnits and the other for push notifications.

This PR also fixes a few bugs on the Tnitter server: losing the session on posting and empty post being accepted by the server.

-----

Note for the reviewers: You may be better to read commits individually. There are 2 bigs commits, one extracts the database logic from the model module and the other introduces code generated by Jwrapper for the native layer of that Android ui implementation.

Pull-Request: #1834
Reviewed-by: Jean Privat <jean@pryen.org>
Reviewed-by: Romain Chanoir <romain.chanoir@viacesi.fr>

25 files changed:
contrib/nitiwiki/README.md
contrib/nitiwiki/examples/default/templates/template.html
contrib/nitiwiki/examples/nitiwiki/assets/css/main.css
contrib/nitiwiki/examples/nitiwiki/pages/section/a_last_page.md [new file with mode: 0644]
contrib/nitiwiki/examples/nitiwiki/pages/section/a_page.md [new file with mode: 0644]
contrib/nitiwiki/examples/nitiwiki/pages/section/another_page.md [new file with mode: 0644]
contrib/nitiwiki/examples/nitiwiki/pages/section/index.md [new file with mode: 0644]
contrib/nitiwiki/examples/nitiwiki/pages/section/sub_section/bar.md [new file with mode: 0644]
contrib/nitiwiki/examples/nitiwiki/pages/section/sub_section/foo.md [new file with mode: 0644]
contrib/nitiwiki/examples/nitiwiki/pages/section/sub_section/index.md [new file with mode: 0644]
contrib/nitiwiki/examples/nitiwiki/templates/template.html
contrib/nitiwiki/src/wiki_html.nit
contrib/nitiwiki/src/wiki_links.nit
contrib/nitiwiki/tests/res/wiki2_nitiwiki_render.res
contrib/nitiwiki/tests/res/wiki3_nitiwiki_render.res
lib/core/text/string_search.nit
src/compiler/abstract_compiler.nit
src/compiler/java_compiler.nit
src/interpreter/naive_interpreter.nit
src/model/model.nit
src/modelize/modelize_property.nit
src/semantize/typing.nit
tests/base_vararg_mult.nit [new file with mode: 0644]
tests/sav/base_vararg_mult.res [new file with mode: 0644]
tests/sav/base_vararg_mult_alt1.res [new file with mode: 0644]

index 77e0b56..f9c7c45 100644 (file)
@@ -174,6 +174,29 @@ will appear like this: `Contact me!`.
 
 You can link to an anchor inside a page, using something like `[[WikiLink#foo]]`.
 
+#### Trails of Pages
+
+Wikilinks, with the directive `trail`, will register the target page as an element of a trail.
+Each `trail` are chained together and will display navigational link `prev` for the previous page of the trail, `next` for the next page of the trail and `up` to go to the pages that has used the `trail` wikilink.
+
+For instance, if the page `doc.md` has the following content:
+
+~~~md
+To use nitiwiki, first [[trail: install|install it]],
+then [[trail: simple_wiki|create a first wiki]].
+
+You can also do advanced things like:
+
+* [[trail: github|editing pages with github]]
+* [[trail: templating| adapting the templates]]
+~~~
+
+A trail will be made and will consist of the sequence of pages `install`, `simple_wiki`, `github` and `templating`.
+On each one of these pages, there will be links for the previous page, the next page and the `doc.md` page.
+
+If a page includes trail wikilinks and is also the target for trail wikilinks, then the two trails are merged and pages will be visitable in a depth-first order.
+This nesting of trails can be used to have sections and sub-sections.
+
 #### Render the wiki in HTML
 
 Once you have done your changes, use:
@@ -243,7 +266,9 @@ The template file `template.html` represents the overall structure of your wiki
                        %HEADER%
                        %TOP_MENU%
                        <div>
+                               %TRAIL%
                                %BODY%
+                               %TRAIL%
                                %FOOTER%
                        </div>
                </body>
@@ -256,6 +281,7 @@ Additionnal macros:
 * `TOP_MENU`: Wiki top menu (see [Topmenu template](#Topmenu_template))
 * `HEADER`: Wiki header (see [Header template](#Header_template))
 * `BODY`: Wiki body content
+* `TRAIL`: content of the trail navigational links, if any (see [Trails of Pages](#Trails_of_Pages))
 
 ### Header template
 
index 692a999..f7061a0 100644 (file)
@@ -8,7 +8,9 @@
         %HEADER%
         %TOP_MENU%
         <div>
+            %TRAIL%
             %BODY%
+            %TRAIL%
             %FOOTER%
         </div>
     </body>
index c00394a..63dda7c 100644 (file)
@@ -28,3 +28,17 @@ footer {
 .summary li li li { font-size: 12px; font-weight: normal }
 
 .breadcrumb { margin-top: 20px; }
+
+.trail {
+       list-style-type: none;
+       color: #838183;
+       text-align: center;
+}
+
+.trail li{
+       display: inline;
+}
+
+.trail li+li:before{
+       content: " | ";
+}
diff --git a/contrib/nitiwiki/examples/nitiwiki/pages/section/a_last_page.md b/contrib/nitiwiki/examples/nitiwiki/pages/section/a_last_page.md
new file mode 100644 (file)
index 0000000..885663d
--- /dev/null
@@ -0,0 +1 @@
+# a last page
diff --git a/contrib/nitiwiki/examples/nitiwiki/pages/section/a_page.md b/contrib/nitiwiki/examples/nitiwiki/pages/section/a_page.md
new file mode 100644 (file)
index 0000000..bf5a54f
--- /dev/null
@@ -0,0 +1 @@
+# a page
diff --git a/contrib/nitiwiki/examples/nitiwiki/pages/section/another_page.md b/contrib/nitiwiki/examples/nitiwiki/pages/section/another_page.md
new file mode 100644 (file)
index 0000000..ec67b83
--- /dev/null
@@ -0,0 +1 @@
+# another page
diff --git a/contrib/nitiwiki/examples/nitiwiki/pages/section/index.md b/contrib/nitiwiki/examples/nitiwiki/pages/section/index.md
new file mode 100644 (file)
index 0000000..229d1f0
--- /dev/null
@@ -0,0 +1,7 @@
+
+# Example of trail
+
+* [[trail: a_page]]
+* [[trail: another_page]]
+* [[trail: sub_section]]
+* [[trail: a_last_page]]
diff --git a/contrib/nitiwiki/examples/nitiwiki/pages/section/sub_section/bar.md b/contrib/nitiwiki/examples/nitiwiki/pages/section/sub_section/bar.md
new file mode 100644 (file)
index 0000000..d93e603
--- /dev/null
@@ -0,0 +1 @@
+# bar
diff --git a/contrib/nitiwiki/examples/nitiwiki/pages/section/sub_section/foo.md b/contrib/nitiwiki/examples/nitiwiki/pages/section/sub_section/foo.md
new file mode 100644 (file)
index 0000000..c2a8392
--- /dev/null
@@ -0,0 +1 @@
+# foo
diff --git a/contrib/nitiwiki/examples/nitiwiki/pages/section/sub_section/index.md b/contrib/nitiwiki/examples/nitiwiki/pages/section/sub_section/index.md
new file mode 100644 (file)
index 0000000..040e564
--- /dev/null
@@ -0,0 +1,4 @@
+# A sub-section
+
+* [[trail: foo]]
+* [[trail: bar]]
index 7c43833..57196fa 100644 (file)
@@ -21,7 +21,9 @@
                %TOP_MENU%
                <div class="container">
                        <div class="row">
+                               %TRAIL%
                                %BODY%
+                               %TRAIL%
                        </div>
                        %FOOTER%
                </div>
index 2e96567..05c06f9 100644 (file)
@@ -95,6 +95,9 @@ redef class WikiSection
                        index.is_dirty = true
                        add_child index
                end
+               # Hack: Force the rendering of `index` first so that trails are collected
+               # TODO: Add first-pass analysis to collect global information before doing the rendering
+               index.render
                super
        end
 
@@ -209,6 +212,9 @@ redef class WikiArticle
                if tpl.has_macro("FOOTER") then
                        tpl.replace("FOOTER", tpl_footer)
                end
+               if tpl.has_macro("TRAIL") then
+                       tpl.replace("TRAIL", tpl_trail)
+               end
                return tpl
        end
 
@@ -293,6 +299,37 @@ redef class WikiArticle
                return tpl
        end
 
+       # Generate navigation links for the trail of this article, if any.
+       #
+       # A trail is generated if the article include or is included in a trail.
+       # See `wiki.trails` for details.
+       fun tpl_trail: Writable do
+               if not wiki.trails.has(self) then return ""
+
+               # Get the position of `self` in the trail
+               var flat = wiki.trails.to_a
+               var pos = flat.index_of(self)
+               assert pos >= 0
+
+               var res = new Template
+               res.add "<ul class=\"trail\">"
+               if pos > 0 then
+                       var target = flat[pos-1]
+                       res.add "<li>{target.a_from(self, "prev")}</li>"
+               end
+               var parent = wiki.trails.parent(self)
+               if parent != null then
+                       res.add "<li>{parent.a_from(self, "up")}</li>"
+               end
+               if pos < flat.length - 1 then
+                       var target = flat[pos+1]
+                       res.add "<li>{target.a_from(self, "next")}</li>"
+               end
+               res.add "</ul>"
+
+               return res
+       end
+
        # Generate the HTML footer for this article.
        fun tpl_footer: Writable do
                var file = footer_file
index efb9f78..03f21ca 100644 (file)
@@ -17,6 +17,7 @@ module wiki_links
 
 import wiki_base
 import markdown::wikilinks
+import ordered_tree
 
 redef class Nitiwiki
        # Looks up a WikiEntry by its `name`.
@@ -86,6 +87,12 @@ redef class Nitiwiki
                end
                return entry
        end
+
+       # Trails between pages
+       #
+       # Trails are represented as a forest of entries.
+       # This way it is possible to represent a flat-trail as a visit of a tree.
+       var trails = new OrderedTree[WikiEntry]
 end
 
 redef class WikiEntry
@@ -102,6 +109,17 @@ redef class WikiEntry
                return res
        end
 
+       # A relative hyperlink <a> to `self` from the page `context`.
+       #
+       # If `text` is not given, `title` will be used instead.
+       fun a_from(context: WikiEntry, text: nullable Text): Writable
+       do
+               var title = title.html_escape
+               if text == null then text = title else text = text.html_escape
+               var href = href_from(context)
+               return """<a href="{{{href}}}" title="{{{title}}}">{{{text}}}</a>"""
+       end
+
        redef fun render do
                super
                if not is_dirty and not wiki.force_render then return
@@ -233,6 +251,14 @@ class NitiwikiDecorator
                var name = token.name
                v.add "<a "
                if not link.has_prefix("http://") and not link.has_prefix("https://") then
+                       # Extract commands from the link.
+                       var command = null
+                       var command_split = link.split_once_on(":")
+                       if command_split.length > 1 then
+                               command = command_split[0].trim
+                               link = command_split[1].trim
+                       end
+
                        if link.has("#") then
                                var parts = link.split_with("#")
                                link = parts.first
@@ -249,6 +275,11 @@ class NitiwikiDecorator
                        if target != null then
                                if name == null then name = target.title
                                link = target.href_from(context)
+
+                               if command == "trail" then
+                                       if target isa WikiSection then target = target.index
+                                       wiki.trails.add(context, target)
+                               end
                        else
                                wiki.message("Warning: unknown wikilink `{link}` (in {context.src_path.as(not null)})", 0)
                                v.add "class=\"broken\" "
index 1bf4497..cdba310 100644 (file)
@@ -1,5 +1,4 @@
 Render section pages -> out
-Render article contact -> wiki2/out/contact.html
 Warning: unknown wikilink `not found` (in pages/index.md)
 Warning: unknown wikilink `Not Found` (in pages/index.md)
 Warning: unknown wikilink `/not/found` (in pages/index.md)
@@ -8,6 +7,7 @@ Warning: unknown wikilink `not found` (in pages/index.md)
 Warning: unknown wikilink `not found` (in pages/index.md)
 Warning: unknown wikilink `not found` (in pages/index.md)
 Render article index -> wiki2/out/index.html
+Render article contact -> wiki2/out/contact.html
 Render article other_page -> wiki2/out/other_page.html
 Render section sec1 -> out/sec1
 Render article index -> wiki2/out/sec1/index.html
index 2199343..65466e3 100644 (file)
@@ -1,5 +1,5 @@
 Render section pages -> out
-Render article contact -> wiki3/out/contact.html
 Render article index -> wiki3/out/index.html
+Render article contact -> wiki3/out/contact.html
 Render article other_page -> wiki3/out/other_page.html
 Render article sitemap -> wiki3/out/sitemap.html
index deb4478..62f3b5e 100644 (file)
@@ -237,21 +237,62 @@ end
 # Matches are a part of a `Text` found by a `Pattern`.
 class Match
        # The base string matched
+       #
+       # ~~~
+       # var m = "hello world".search("lo")
+       # assert m.string == "hello world"
+       # ~~~
        var string: String
 
        # The starting position in the string
+       #
+       # ~~~
+       # var m = "hello world".search("lo")
+       # assert m.from == 3
+       # ~~~
        var from: Int
 
        # The length of the matching part
+       #
+       # ~~~
+       # var m = "hello world".search("lo")
+       # assert m.length == 2
+       # ~~~
        var length: Int
 
        # The position of the first character just after the matching part.
        # May be out of the base string
+       #
+       # ~~~
+       # var m = "hello world".search("lo")
+       # assert m.after == 5
+       # ~~~
        fun after: Int do return from + length
 
        # The contents of the matching part
+       #
+       # ~~~
+       # var m = "hello world".search("lo")
+       # assert m.to_s == "lo"
+       # ~~~
        redef fun to_s do return string.substring(from,length)
 
+       # The content of `string` before the match
+       #
+       # ~~~
+       # var m = "hello world".search("lo")
+       # assert m.text_before == "hel"
+       # ~~~
+       fun text_before: String do return string.substring(0, from)
+
+       # The content of `string` after the match
+       #
+       # ~~~
+       # var m = "hello world".search("lo")
+       # assert m.text_after == " world"
+       # ~~~
+       fun text_after: String do return string.substring_from(after)
+
        init
        do
                assert positive_length: length >= 0
@@ -358,6 +399,37 @@ redef class Text
                return null
        end
 
+       # Extract a given prefix, if any.
+       #
+       # ~~~
+       # var p = "hello world".prefix("hello")
+       # assert p != null
+       # assert p.text_after == " world"
+       # ~~~
+       fun prefix(t: Text): nullable Match do
+               var len = t.length
+               if substring(0, len) == t then
+                       return new Match(self.to_s, 0, len)
+               end
+               return null
+       end
+
+       # Extract a given suffix, if any.
+       #
+       # ~~~
+       # var p = "hello world".suffix("world")
+       # assert p != null
+       # assert p.text_before == "hello "
+       # ~~~
+       fun suffix(t: Text): nullable Match do
+               var len = t.length
+               var from = length - len
+               if substring(from, len) == t then
+                       return new Match(self.to_s, from, len)
+               end
+               return null
+       end
+
        # Search all occurrences of `pattern` into self.
        #
        #     var a = new Array[Int]
index 821ad31..1308e29 100644 (file)
@@ -1224,8 +1224,8 @@ abstract class AbstractCompilerVisitor
                                res.add(null_instance)
                                continue
                        end
-                       if param.is_vararg and map.vararg_decl > 0 then
-                               var vararg = exprs.sub(j, map.vararg_decl)
+                       if param.is_vararg and args[i].vararg_decl > 0 then
+                               var vararg = exprs.sub(j, args[i].vararg_decl)
                                var elttype = param.mtype
                                var arg = self.vararg_instance(mpropdef, recv, vararg, elttype)
                                res.add(arg)
index 84b5a47..7468d28 100644 (file)
@@ -526,8 +526,8 @@ class JavaCompilerVisitor
                                res.add(null_instance)
                                continue
                        end
-                       if param.is_vararg and map.vararg_decl > 0 then
-                               var vararg = exprs.sub(j, map.vararg_decl)
+                       if param.is_vararg and args[i].vararg_decl > 0 then
+                               var vararg = exprs.sub(j, args[i].vararg_decl)
                                var elttype = param.mtype
                                var arg = self.vararg_instance(mpropdef, recv, vararg, elttype)
                                res.add(arg)
index dc911fd..299445d 100644 (file)
@@ -471,8 +471,8 @@ class NaiveInterpreter
                                res.add(null_instance)
                                continue
                        end
-                       if param.is_vararg and map.vararg_decl > 0 then
-                               var vararg = exprs.sub(j, map.vararg_decl)
+                       if param.is_vararg and args[i].vararg_decl > 0 then
+                               var vararg = exprs.sub(j, args[i].vararg_decl)
                                var elttype = param.mtype.anchor_to(self.mainmodule, recv.mtype.as(MClassType))
                                var arg = self.array_instance(vararg, elttype)
                                res.add(arg)
index ccb7522..49ababd 100644 (file)
@@ -1818,16 +1818,26 @@ class MSignature
                for i in [0..mparameters.length[ do
                        var parameter = mparameters[i]
                        if parameter.is_vararg then
-                               assert vararg_rank == -1
+                               if vararg_rank >= 0 then
+                                       # If there is more than one vararg,
+                                       # consider that additional arguments cannot be mapped.
+                                       vararg_rank = -1
+                                       break
+                               end
                                vararg_rank = i
                        end
                end
                self.vararg_rank = vararg_rank
        end
 
-       # The rank of the ellipsis (`...`) for vararg (starting from 0).
+       # The rank of the main ellipsis (`...`) for vararg (starting from 0).
        # value is -1 if there is no vararg.
        # Example: for "(a: Int, b: Bool..., c: Char)" #-> vararg_rank=1
+       #
+       # From a model POV, a signature can contain more than one vararg parameter,
+       # the `vararg_rank` just indicates the one that will receive the additional arguments.
+       # However, currently, if there is more that one vararg parameter, no one will be the main one,
+       # and additional arguments will be refused.
        var vararg_rank: Int is noinit
 
        # The number of parameters
index 23feb87..cd50d4a 100644 (file)
@@ -186,11 +186,7 @@ redef class ModelBuilder
                                var sig = mpropdef.msignature
                                if sig == null then continue # Skip broken method
 
-                               for param in sig.mparameters do
-                                       var ret_type = param.mtype
-                                       var mparameter = new MParameter(param.name, ret_type, false)
-                                       mparameters.add(mparameter)
-                               end
+                               mparameters.add_all sig.mparameters
                                initializers.add(mpropdef.mproperty)
                                mpropdef.mproperty.is_autoinit = true
                        end
index b4599d0..aeb3b7e 100644 (file)
@@ -490,8 +490,12 @@ private class TypeVisitor
                                continue # skip the vararg
                        end
 
-                       var paramtype = param.mtype
-                       self.visit_expr_subtype(arg, paramtype)
+                       if not param.is_vararg then
+                               var paramtype = param.mtype
+                               self.visit_expr_subtype(arg, paramtype)
+                       else
+                               check_one_vararg(arg, param)
+                       end
                end
 
                if min_arity > 0 then
@@ -509,27 +513,9 @@ private class TypeVisitor
                        var paramtype = msignature.mparameters[vararg_rank].mtype
                        var first = args[vararg_rank]
                        if vararg_decl == 0 then
-                               var mclass = get_mclass(node, "Array")
-                               if mclass == null then return null # Forward error
-                               var array_mtype = mclass.get_mtype([paramtype])
-                               if first isa AVarargExpr then
-                                       self.visit_expr_subtype(first.n_expr, array_mtype)
-                                       first.mtype  = first.n_expr.mtype
-                               else
-                                       # only one vararg, maybe `...` was forgot, so be gentle!
-                                       var t = visit_expr(first)
-                                       if t == null then return null # Forward error
-                                       if not is_subtype(t, paramtype) and is_subtype(t, array_mtype) then
-                                               # Not acceptable but could be a `...`
-                                               error(first, "Type Error: expected `{paramtype}`, got `{t}`. Is an ellipsis `...` missing on the argument?")
-                                               return null
-                                       end
-                                       # Standard valid vararg, finish the job
-                                       map.vararg_decl = 1
-                                       self.visit_expr_subtype(first, paramtype)
-                               end
+                               if not check_one_vararg(first, msignature.mparameters[vararg_rank]) then return null
                        else
-                               map.vararg_decl = vararg_decl + 1
+                               first.vararg_decl = vararg_decl + 1
                                for i in [vararg_rank..vararg_rank+vararg_decl] do
                                        self.visit_expr_subtype(args[i], paramtype)
                                end
@@ -539,6 +525,33 @@ private class TypeVisitor
                return map
        end
 
+       # Check an expression as a single vararg.
+       # The main point of the method if to handle the case of reversed vararg (see `AVarargExpr`)
+       fun check_one_vararg(arg: AExpr, param: MParameter): Bool
+       do
+               var paramtype = param.mtype
+               var mclass = get_mclass(arg, "Array")
+               if mclass == null then return false # Forward error
+               var array_mtype = mclass.get_mtype([paramtype])
+               if arg isa AVarargExpr then
+                       self.visit_expr_subtype(arg.n_expr, array_mtype)
+                       arg.mtype  = arg.n_expr.mtype
+               else
+                       # only one vararg, maybe `...` was forgot, so be gentle!
+                       var t = visit_expr(arg)
+                       if t == null then return false # Forward error
+                       if not is_subtype(t, paramtype) and is_subtype(t, array_mtype) then
+                               # Not acceptable but could be a `...`
+                               error(arg, "Type Error: expected `{paramtype}`, got `{t}`. Is an ellipsis `...` missing on the argument?")
+                               return false
+                       end
+                       # Standard valid vararg, finish the job
+                       arg.vararg_decl = 1
+                       self.visit_expr_subtype(arg, paramtype)
+               end
+               return true
+       end
+
        fun error(node: ANode, message: String)
        do
                self.modelbuilder.error(node, message)
@@ -614,10 +627,6 @@ end
 class SignatureMap
        # Associate a parameter to an argument
        var map = new ArrayMap[Int, Int]
-
-       # The length of the vararg sequence
-       # 0 if no vararg or if reverse vararg (cf `AVarargExpr`)
-       var vararg_decl: Int = 0
 end
 
 # A specific method call site with its associated informations.
@@ -853,6 +862,15 @@ redef class AExpr
        # The result of the evaluation of `self` must be
        # stored inside the designated array (there is an implicit `push`)
        var comprehension: nullable AArrayExpr = null
+
+       # It indicates the number of arguments collected as a vararg.
+       #
+       # When 0, the argument is used as is, without transformation.
+       # When 1, the argument is transformed into an singleton array.
+       # Above 1, the arguments and the next ones are transformed into a common array.
+       #
+       # This attribute is meaning less on expressions not used as attributes.
+       var vararg_decl: Int = 0
 end
 
 redef class ABlockExpr
diff --git a/tests/base_vararg_mult.nit b/tests/base_vararg_mult.nit
new file mode 100644 (file)
index 0000000..9f9bd0a
--- /dev/null
@@ -0,0 +1,51 @@
+# 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 array
+
+class A
+       fun x(ints: Int...) is autoinit do
+               for i in ints do
+                       'X'.output
+                       i.output
+               end
+               '\n'.output
+       end
+end
+
+class B
+       super A
+       fun y(objs: Object...) is autoinit do
+               for i in objs do
+                       'Y'.output
+                       i.output
+               end
+               '\n'.output
+       end
+end
+
+var x
+
+#alt1#x = new A
+x = new A(1)
+x = new A(10, 20)
+x = new A([100, 200, 300]...)
+
+#aly1#x = new B(1)
+x = new B(1, 2)
+#alt1#x = new B(1, 2, 3)
+#alt1#x = new B([10, 20], 33)
+x = new B([10, 11]..., 20)
+x = new B(10, [20, 21]...)
+x = new B([10, 11]..., [20, 21, 23]...)
diff --git a/tests/sav/base_vararg_mult.res b/tests/sav/base_vararg_mult.res
new file mode 100644 (file)
index 0000000..2776784
--- /dev/null
@@ -0,0 +1,30 @@
+X1
+
+X10
+X20
+
+X100
+X200
+X300
+
+X1
+
+Y2
+
+X10
+X11
+
+Y20
+
+X10
+
+Y20
+Y21
+
+X10
+X11
+
+Y20
+Y21
+Y23
+
diff --git a/tests/sav/base_vararg_mult_alt1.res b/tests/sav/base_vararg_mult_alt1.res
new file mode 100644 (file)
index 0000000..8189994
--- /dev/null
@@ -0,0 +1,3 @@
+alt/base_vararg_mult_alt1.nit:40,5--7: Error: expected at least 1 argument(s) for `init(ints: Int...)`; got 0. See introduction at `core::Object::init`.
+alt/base_vararg_mult_alt1.nit:47,5--7: Error: expected 2 argument(s) for `init(ints: Int..., objs: Object...)`; got 3. See introduction at `core::Object::init`.
+alt/base_vararg_mult_alt1.nit:48,11--18: Type Error: expected `Int`, got `Array[Int]`. Is an ellipsis `...` missing on the argument?