Merge: Improve loader
authorJean Privat <jean@pryen.org>
Thu, 2 Apr 2015 04:10:22 +0000 (11:10 +0700)
committerJean Privat <jean@pryen.org>
Thu, 2 Apr 2015 07:55:58 +0000 (14:55 +0700)
This PR improves the loader that can now accepts

* directories of projects: to load all modules of all projects (eg `contrib`)
* root directories of groups: to load all modules of the groups (eg `contrib/benitlux`).
  Previously, this worked if there was no `src` subdirectory)

This works for tools that rely on full_parse (basically all tools except the engines).

~~~sh
$ ./test_test_phase ../lib -q
It works
I have 89 projects
I have 285 modules
I have 1038 classes
For 1366 definitions of classes
I have 7101 methods
For 9098 definitions of methods
~~~

Note that if any files has an error most tools will just stop.

Pull-Request: #1229
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>
Reviewed-by: Alexis Laferrière <alexis.laf@xymus.net>

40 files changed:
VERSION
benchmarks/markdown/bench_markdown.sh
benchmarks/markdown/engines/nitmd/Makefile
lib/geometry/points_and_lines.nit
lib/html/bootstrap.nit [new file with mode: 0644]
lib/ios/app.nit [new file with mode: 0644]
lib/ios/examples/hello_ios.nit [new file with mode: 0644]
lib/ios/ios.nit [new file with mode: 0644]
lib/ios/platform.nit [new file with mode: 0644]
lib/privileges/privileges.nit [moved from lib/privileges.nit with 100% similarity]
lib/standard/collection/abstract_collection.nit
lib/standard/collection/sorter.nit
lib/standard/collection/union_find.nit
lib/standard/exec_nit.c
lib/standard/file.nit
lib/standard/string.nit
lib/template/examples/tmpl_composer.nit
src/compiler/abstract_compiler.nit
src/compiler/coloring.nit
src/compiler/compiler.nit
src/compiler/separate_compiler.nit
src/compiler/separate_erasure_compiler.nit
src/doc/doc_base.nit
src/doc/doc_phases/doc_graphs.nit
src/doc/doc_phases/doc_hierarchies.nit
src/doc/doc_phases/doc_html.nit
src/doc/doc_phases/doc_structure.nit
src/doc/html_templates/html_components.nit
src/doc/html_templates/html_model.nit
src/doc/html_templates/html_templates.nit
src/model/model.nit
src/modelize/modelize_property.nit
src/platform/android.nit
src/platform/emscripten.nit
src/platform/ios.nit [new file with mode: 0644]
src/platform/pnacl.nit
src/platform/xcode_templates.nit [new file with mode: 0644]
tests/Linux.skip
tests/sav/test_parser_args1.res
tests/test_platform_ios.nit [new file with mode: 0644]

diff --git a/VERSION b/VERSION
index 2c0a9c7..3d105a6 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-v0.7.2
+v0.7.3
index 4cb0f15..be58d55 100755 (executable)
@@ -74,7 +74,7 @@ engdir="./engines"
 bncdir="./benches/out"
 mkdir -p $outdir
 
-s=50
+s=200
 
 function bench_nitmd()
 {
@@ -88,6 +88,18 @@ function bench_nitmd()
 }
 bench_nitmd
 
+function bench_nitmd-o()
+{
+       name="$FUNCNAME"
+       skip_test "$name" && return
+       prepare_res $outdir/nitmd-o.dat "nitmd-o" "nitmd-o"
+       for file in $bncdir/*.md; do
+               bench=`basename $file .md`
+               bench_command "$bench" "" "$engdir/nitmd/nitmd-o" "$file" "$s"
+       done
+}
+bench_nitmd-o
+
 function bench_txtmark()
 {
        name="$FUNCNAME"
index aa79fbc..6424382 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+all: nitmd nitmd-o
+
 nitmd:
        nitc nitmd.nit
 
-test: nitmd
+nitmd-o:
+       nitc --semi-global nitmd.nit -o $@
+
+test: all
        ./nitmd ../../benches/hello.md 5
+       ./nitmd-o ../../benches/hello.md 5
 
 clean:
-       rm -rf nitmd
+       rm -rf nitmd nitmd-o
index 14a67fb..303aae1 100644 (file)
@@ -55,9 +55,13 @@ end
 
 # An abstract 2d line segment
 interface ILine[N: Numeric]
+       # The type of points that ends the segment
        type P: IPoint[N]
 
+       # The point that is the left-end of the segment
        fun point_left: P is abstract
+
+       # The point that is the right-end of the segment
        fun point_right: P is abstract
 
        redef fun to_s do return "{point_left}--{point_right}"
diff --git a/lib/html/bootstrap.nit b/lib/html/bootstrap.nit
new file mode 100644 (file)
index 0000000..66befa3
--- /dev/null
@@ -0,0 +1,466 @@
+# 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.
+
+# HTML templates for Bootstrap components.
+#
+# See http://getbootstrap.com/components/
+module bootstrap
+
+import template
+
+# Bootstrap component abstraction.
+#
+# Mainly used to factoryze CSS treatments.
+# Can be used in the future to handle generic stuff like attributes or escaping.
+#
+# TODO merge with html::HTMTag without init conflict?
+# HTMLTag requires the main init to pass a tagname,
+# this was so much verbose here.
+abstract class BSComponent
+       super Template
+
+       # CSS classes to add on this element.
+       var css_classes = new Array[String]
+
+       # Render `self` css clases as a `class` attribute.
+       fun render_css_classes: String do
+               if css_classes.is_empty then return ""
+               return " class=\"{css_classes.join(" ")}\""
+       end
+end
+
+# A `<a>` tag.
+#
+# Not really a Bootstrap component but used in other components
+# that it required its own abstraction.
+#
+# Example:
+# ~~~
+# var lnk = new Link("http://nitlanguage.org", "Nit")
+# assert lnk.write_to_string == "<a href=\"http://nitlanguage.org\">Nit</a>"
+# ~~~
+#
+# Creates a link with a title attribute:
+# ~~~
+# lnk = new Link.with_title("http://nitlanguage.org", "Nit", "Nit homepage")
+# assert lnk.write_to_string == "<a href=\"http://nitlanguage.org\" title=\"Nit homepage\">Nit</a>"
+# ~~~
+class Link
+       super BSComponent
+
+       # URL pointed by this link.
+       var href: String is writable
+
+       # Displayed text.
+       var text: Writable is writable
+
+       # Optional title.
+       var title: nullable String is noinit, writable
+
+       # Creates a link with a `title` attribute.
+       init with_title(href: String, text: Writable, title: nullable String) do
+               self.href = href
+               self.text = text
+               self.title = title
+       end
+
+       redef fun rendering do
+               add "<a{render_css_classes} href=\"{href}\""
+               if title != null then add " title=\"{title.write_to_string}\""
+               add ">{text}</a>"
+       end
+end
+
+# A `<h1>` to `<h6>` tag.
+#
+# Not really a Bootstrap component but used in other components
+# that it required its own abstraction.
+#
+# Example:
+# ~~~
+# var h1 = new Header(1, "Title")
+# assert h1.write_to_string == "<h1>Title</h1>"
+# ~~~
+#
+# With subtext:
+# ~~~
+# var h6 = new Header.with_subtext(6, "Title", "with subtext")
+# assert h6.write_to_string == "<h6>Title<small>with subtext</small></h6>"
+# ~~~
+class Header
+       super BSComponent
+
+       # Header level between 1 and 6.
+       var level: Int
+
+       # Displayed text.
+       var text: Writable
+
+       # Optional subtext.
+       var subtext: nullable Writable is noinit, writable
+
+       # Creates a link with a `title` attribute.
+       init with_subtext(level: Int, text: Writable, subtext: String) do
+               self.level = level
+               self.text = text
+               self.subtext = subtext
+       end
+
+       redef fun rendering do
+               add "<h{level}{render_css_classes}>{text.write_to_string}"
+               if subtext != null then add "<small>{subtext.write_to_string}</small>"
+               add "</h{level}>"
+       end
+end
+
+# An abstract HTML list.
+#
+# Many Bootstrap components are built around a HTML list.
+#
+# Used to factorize behavior between OrderedList and UnorderedList.
+abstract class HTMLList
+       super BSComponent
+
+       # A list contains `<li>` tags as children.
+       #
+       # See ListItem.
+       var items = new Array[ListItem]
+
+       # Adds a new ListItem to `self`.
+       fun add_li(item: ListItem) do items.add item
+
+       # Does `self` contains no items?
+       fun is_empty: Bool do return items.is_empty
+end
+
+# A `<ol>` list tag.
+#
+# Example:
+#
+# ~~~
+# var lst = new OrderedList
+# lst.add_li(new ListItem("foo"))
+# lst.add_li(new ListItem("bar"))
+# lst.add_li(new ListItem("baz"))
+#
+# assert lst.write_to_string == """
+# <ol>
+# <li>foo</li>
+# <li>bar</li>
+# <li>baz</li>
+# </ol>
+# """
+# ~~~
+class OrderedList
+       super HTMLList
+
+       redef fun rendering do
+               addn "<ol{render_css_classes}>"
+               for item in items do add item
+               addn "</ol>"
+       end
+end
+
+# A `<ul>` list tag.
+#
+# Example:
+#
+# ~~~
+# var lst = new UnorderedList
+# lst.add_li(new ListItem("foo"))
+# lst.add_li(new ListItem("bar"))
+# lst.add_li(new ListItem("baz"))
+#
+# assert lst.write_to_string == """
+# <ul>
+# <li>foo</li>
+# <li>bar</li>
+# <li>baz</li>
+# </ul>
+# """
+# ~~~
+class UnorderedList
+       super HTMLList
+
+       redef fun rendering do
+               addn "<ul{render_css_classes}>"
+               for item in items do add item
+               addn "</ul>"
+       end
+end
+
+# A `<li>` tag.
+class ListItem
+       super BSComponent
+
+       # Content to display in this list item.
+       var text: Writable is writable
+
+       redef fun rendering do addn "<li{render_css_classes}>{text.write_to_string}</li>"
+end
+
+# A Boostrap icon.
+#
+# See http://getbootstrap.com/components/#glyphicons
+#
+# Example:
+#
+# ~~~
+# var icon = new BSIcon("star")
+# assert icon.write_to_string == "<span class=\"glyphicon glyphicon-star\" aria-hidden=\"true\"></span>"
+# ~~~
+class BSIcon
+       super BSComponent
+
+       # Glyphicon name to display.
+       #
+       # See full list at http://getbootstrap.com/components/#glyphicons.
+       var icon: String
+
+       init do css_classes.add "glyphicon glyphicon-{icon}"
+
+       redef fun rendering do
+               add "<span{render_css_classes} aria-hidden=\"true\"></span>"
+       end
+end
+
+# A Bootstrap breadcrumbs component.
+#
+# See http://getbootstrap.com/components/#breadcrumbs
+#
+# Example:
+#
+# ~~~
+# var bc = new BSBreadCrumbs
+# bc.add_li(new ListItem("foo"))
+# bc.add_li(new ListItem("bar"))
+# bc.add_li(new ListItem("baz"))
+#
+# assert bc.write_to_string == """
+# <ol class=\"breadcrumbs\">
+# <li>foo</li>
+# <li>bar</li>
+# <li class=\"active\">baz</li>
+# </ol>
+# """
+# ~~~
+class BSBreadCrumbs
+       super OrderedList
+
+       init do css_classes.add "breadcrumbs"
+
+       redef fun rendering do
+               items.last.css_classes.add "active"
+               super
+       end
+end
+
+# A Bootstrap label component.
+#
+# See http://getbootstrap.com/components/#labels
+#
+# Example:
+#
+# ~~~
+# var lbl = new BSLabel("danger", "Danger!")
+# assert lbl.write_to_string == "<span class=\"label label-danger\">Danger!</span>"
+# ~~~
+class BSLabel
+       super BSComponent
+
+       # Class used to change the color of the label.
+       #
+       # Can be one of `default`, `primary`, `success`, `info`, `warning` or `danger`.
+       var color: String
+
+       # Text to display in the label.
+       var text: Writable
+
+       init do css_classes.add "label label-{color}"
+
+       redef fun rendering do
+               add "<span{render_css_classes}>{text.write_to_string}</span>"
+       end
+end
+
+# A Bootstrap badge component.
+#
+# See http://getbootstrap.com/components/#badges
+#
+# Example:
+#
+# ~~~
+# var b = new BSBadge("42 messages")
+# assert b.write_to_string == "<span class=\"badge\">42 messages</span>"
+# ~~~
+class BSBadge
+       super BSComponent
+
+       # Text to display in the label.
+       var text: Writable
+
+       init do css_classes.add "badge"
+
+       redef fun rendering do
+               add "<span{render_css_classes}>{text.write_to_string}</span>"
+       end
+end
+
+# A Bootstrap page header component.
+#
+# See http://getbootstrap.com/components/#page-header
+#
+# Example:
+#
+# ~~~
+# var h = new BSPageHeader("Welcome")
+# assert h.write_to_string == """
+# <div class=\"page-header\">
+# Welcome
+# </div>
+# """
+# ~~~
+class BSPageHeader
+       super BSComponent
+
+       # Text to display as title.
+       var text: Writable
+
+       init do css_classes.add "page-header"
+
+       redef fun rendering do
+               addn "<div{render_css_classes}>"
+               addn text.write_to_string
+               addn "</div>"
+       end
+end
+
+# A Bootstrap alert component.
+#
+# See http://getbootstrap.com/components/#alerts
+#
+# Example:
+#
+# ~~~
+# var alert = new BSAlert("danger", "Danger!")
+# assert alert.write_to_string == """
+# <div class="alert alert-danger">
+# Danger!
+# </div>
+# """
+# ~~~
+class BSAlert
+       super BSComponent
+
+       # Class used to change the color of the alert.
+       #
+       # Can be one of `primary`, `success`, `info`, `warning` or `danger`.
+       var color: String
+
+       # Text to display in the alert.
+       var text: Writable
+
+       # Can the alert be dismissed by clicking the close button?
+       #
+       # See http://getbootstrap.com/components/#alerts-dismissible
+       #
+       # Default is `false`.
+       var is_dismissible = false
+
+       init do css_classes.add "alert alert-{color}"
+
+       redef fun rendering do
+               addn "<div{render_css_classes}>"
+               if is_dismissible then
+                       add "<button type=\"button\" class=\"close\" data-dismiss=\"alert\""
+                       add "aria-label=\"Close\"><span aria-hidden=\"true\">&times;</span>"
+                       addn "</button>"
+               end
+               addn text.write_to_string
+               addn "</div>"
+       end
+end
+
+# A Bootstrap panel component.
+#
+# See http://getbootstrap.com/components/#panels
+#
+# Example:
+#
+# ~~~
+# var p = new BSPanel("default", "Panel content")
+#
+# assert p.write_to_string == """
+# <div class="panel panel-default">
+# <div class="panel-body">
+# Panel content
+# </div>
+# </div>
+# """
+# ~~~
+#
+# Panel with heading:
+#
+# ~~~
+# p = new BSPanel("danger", "Panel content")
+# p.heading = "Panel heading"
+#
+# assert p.write_to_string == """
+# <div class="panel panel-danger">
+# <div class="panel-heading">
+# Panel heading
+# </div>
+# <div class="panel-body">
+# Panel content
+# </div>
+# </div>
+# """
+# ~~~
+class BSPanel
+       super BSComponent
+
+       # Panel color.
+       #
+       # Can be one of `default`, `primary`, `success`, `info`, `warning` or `danger`.
+       var color: String
+
+       # Panel header if any.
+       var heading: nullable Writable is noinit, writable
+
+       # Body to display in the panel.
+       var body: Writable
+
+       # Panel footer is any.
+       var footer: nullable Writable is noinit, writable
+
+       init do css_classes.add "panel panel-{color}"
+
+       redef fun rendering do
+               addn "<div{render_css_classes}>"
+               if heading != null then
+                       addn "<div class=\"panel-heading\">"
+                       addn heading.write_to_string
+                       addn "</div>"
+               end
+               addn "<div class=\"panel-body\">"
+               addn body.write_to_string
+               addn "</div>"
+               if footer != null then
+                       addn "<div class=\"panel-footer\">"
+                       addn footer.write_to_string
+                       addn "</div>"
+               end
+               addn "</div>"
+       end
+end
diff --git a/lib/ios/app.nit b/lib/ios/app.nit
new file mode 100644 (file)
index 0000000..0e337bc
--- /dev/null
@@ -0,0 +1,191 @@
+# 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.
+
+# Basic structure for Nit apps on iOS
+module app
+
+import platform
+import ::app
+
+in "ObjC Header" `{
+       #import <UIKit/UIKit.h>
+
+       // Our interface to the iOS system
+       @interface AppDelegate: UIResponder <UIApplicationDelegate>
+
+               // The main window
+               @property (strong, nonatomic) UIWindow *window;
+       @end
+`}
+
+in "ObjC" `{
+
+       // Global reference to the App from app.nit
+       App app_nit_ios_app;
+
+       // Our own C argc and argv
+       int app_nit_ios_argc;
+       char **app_nit_ios_argv;
+
+       @implementation AppDelegate
+
+       - (BOOL)application:(UIApplication *)application
+               willFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+
+               // Set aside `application` to be used from Nit
+               App_ui_application__assign(app_nit_ios_app, application);
+               App_app_delegate__assign(app_nit_ios_app, self);
+
+               // Complete the callback
+               return App_will_finish_launching_with_options(app_nit_ios_app);
+       }
+
+       - (BOOL)application:(UIApplication *)application
+               didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+
+               return App_did_finish_launching_with_options(app_nit_ios_app);
+       }
+
+       - (void)applicationWillResignActive:(UIApplication *)application {
+               App_will_resign_active(app_nit_ios_app);
+       }
+
+       - (void)applicationDidEnterBackground:(UIApplication *)application {
+               App_did_enter_background(app_nit_ios_app);
+       }
+
+       - (void)applicationWillEnterForeground:(UIApplication *)application {
+               App_will_enter_foreground(app_nit_ios_app);
+       }
+
+       - (void)applicationDidBecomeActive:(UIApplication *)application {
+               App_did_become_active(app_nit_ios_app);
+       }
+
+       - (void)applicationWillTerminate:(UIApplication *)application {
+               App_will_terminate(app_nit_ios_app);
+       }
+
+       @end
+`}
+
+# Application interface to the iOS system
+extern class AppDelegate in "ObjC" `{ AppDelegate * `}
+end
+
+# Graphical application to which events are sent
+extern class UIApplication in "ObjC" `{ UIApplication * `}
+end
+
+redef class App
+
+       # Main graphical application
+       var ui_application: UIApplication
+
+       # Application interface to the iOS system
+       var app_delegate: AppDelegate
+
+       # Copy back to C the command line arguments
+       #
+       # Nit extracts the first arguments from the `args` sequence,
+       # so we need to add it back. That's why Nit's `args` is smaller than in C.
+       private fun register_args(program_name: NativeString, argc: Int,
+       argv: Sequence[String]) import Sequence[String].[], String.to_cstring in "ObjC" `{
+               app_nit_ios_argc = argc+1;
+
+               // TODO copy or pin the strings when needed
+               app_nit_ios_argv = malloc(argc * sizeof(char*));
+               app_nit_ios_argv[0] = program_name;
+               for (int i = 0; i < argc; i ++) {
+                       String arg = Sequence_of_String__index(argv, i);
+                       app_nit_ios_argv[i+1] = String_to_cstring(arg);
+               }
+       `}
+
+       # Register `self` globally in C so it can be retrieved from iOS callbacks
+       private fun register_globally in "ObjC" `{
+               App_incr_ref(recv);
+               app_nit_ios_app = recv;
+       `}
+
+       # Entry point to the iOS framework
+       private fun ui_application_main: Bool import did_finish_launching_with_options,
+       will_finish_launching_with_options,
+       will_resign_active, did_enter_background, will_enter_foreground,
+       did_become_active, will_terminate, ui_application=, app_delegate= in "ObjC" `{
+
+               @autoreleasepool {
+                       return UIApplicationMain(app_nit_ios_argc, app_nit_ios_argv,
+                               nil, NSStringFromClass([AppDelegate class]));
+               }
+       `}
+
+       # The application is about to launch
+       #
+       # Redef this method to set the very first custom code to be executed.
+       fun will_finish_launching_with_options: Bool do return true
+
+       # The application just launched but is not yet displayed to the user
+       #
+       # Redef this method to customize the behavior.
+       fun did_finish_launching_with_options: Bool do return true
+
+       # The application is about to move from active to inactive state
+       #
+       # This can occur for certain types of temporary interruptions
+       # (such as an incoming phone call or SMS message) or when the
+       # user quits the application and it begins the transition to
+       # the background state.
+       #
+       # Redef this method to pause ongoing tasks, disable timers, and
+       # throttle down OpenGL ES frame rates. Games should use this
+       # method to pause.
+       fun will_resign_active do end
+
+       # The application just left foreground it can be suspended at any time
+       #
+       # Redef this method to release shared resources, save user data,
+       # invalidate timers, and store application state to restore your
+       # application to its current state in case it is terminated later.
+       #
+       # If your application supports background execution, this method
+       # is called instead of `will_terminate` when the user quits.
+       fun did_enter_background do end
+
+       # The application will enter the foreground
+       #
+       # Called as part of the transition from the background to the
+       # inactive state.
+       #
+       # Redef to und changes made on entering the background.
+       fun will_enter_foreground do end
+
+       # The application just became active
+       #
+       # Redef to restart any tasks that were paused (or not yet started) while
+       # the application was inactive. If the application was previously
+       # in the background, optionally refresh the user interface.
+       fun did_become_active do end
+
+       # The application is about to terminate (not suspended)
+       #
+       # Redef to save data if appropriate.
+       fun will_terminate do end
+end
+
+app.register_args(program_name.to_cstring, args.length, args)
+app.register_globally
+
+var ret = app.ui_application_main
+exit if ret then 0 else 1
diff --git a/lib/ios/examples/hello_ios.nit b/lib/ios/examples/hello_ios.nit
new file mode 100644 (file)
index 0000000..d11ffcb
--- /dev/null
@@ -0,0 +1,50 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Simple iOS app with a single label
+module hello_ios
+
+import ios
+
+redef class App
+       redef fun did_finish_launching_with_options
+       do
+               return app_delegate.hello_world
+       end
+end
+
+redef class AppDelegate
+
+       # Print and show "Hello World!"
+       private fun hello_world: Bool in "ObjC" `{
+
+               // Print to the console
+               NSLog(@"Hello World!");
+
+               // Display "Hello world!" on the screen
+               recv.window = [[UIWindow alloc] initWithFrame:
+               [[UIScreen mainScreen] bounds]];
+               recv.window.backgroundColor = [UIColor whiteColor];
+
+               UILabel *label = [[UILabel alloc] init];
+               label.text = @"Hello World!";
+               label.center = CGPointMake(100, 100);
+               [label sizeToFit];
+
+               [recv.window addSubview: label];
+               [recv.window makeKeyAndVisible];
+
+               return YES;
+       `}
+end
diff --git a/lib/ios/ios.nit b/lib/ios/ios.nit
new file mode 100644 (file)
index 0000000..9d5079d
--- /dev/null
@@ -0,0 +1,19 @@
+# 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.
+
+# iOS services for Nit app on iOS
+module ios
+
+import platform
+import app
diff --git a/lib/ios/platform.nit b/lib/ios/platform.nit
new file mode 100644 (file)
index 0000000..47d1536
--- /dev/null
@@ -0,0 +1,16 @@
+# 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.
+
+# Triggers compilation for the iOS platform
+module platform is platform "ios"
index d51e710..1b1e71e 100644 (file)
@@ -66,6 +66,14 @@ interface Collection[E]
        #     assert [1..1[.is_empty   == true
        fun is_empty: Bool do return length == 0
 
+       # Alias for `not is_empty`.
+       #
+       # Some people prefer to have conditions grammatically easier to read.
+       #
+       #     assert [1,2,3].not_empty  == true
+       #     assert [1..1[.not_empty   == false
+       fun not_empty: Bool do return not self.is_empty
+
        # Number of items in the collection.
        #
        #     assert [10,20,30].length == 3
index cfcc376..00c45a3 100644 (file)
@@ -250,6 +250,81 @@ interface Comparator
 
 end
 
+redef class MapRead[K,V]
+       # Return an array of all values sorted with their keys using `comparator`.
+       #
+       # ~~~
+       # var map = new HashMap[Int, String]
+       # map[10] = "ten"
+       # map[2]  = "two"
+       # map[1]  = "one"
+       # assert map.values_sorted_by_key(default_comparator) == ["one", "two", "ten"]
+       # assert map.values_sorted_by_key(alpha_comparator) == ["one", "ten", "two"]
+       # ~~~
+       fun values_sorted_by_key(comparator: Comparator): Array[V]
+       do
+               var keys = self.keys.to_a
+               comparator.sort(keys)
+               return [for k in keys do self[k]]
+       end
+
+       # Return an array of all keys sorted with their values using `comparator`.
+       #
+       # ~~~
+       # var map = new HashMap[String, Int]
+       # map["ten"] = 10
+       # map["two"] = 2
+       # map["one"] = 1
+       # assert map.keys_sorted_by_values(default_comparator) == ["one", "two", "ten"]
+       # assert map.keys_sorted_by_values(alpha_comparator) == ["one", "ten", "two"]
+       # ~~~
+       #
+       # See: `to_map_comparator` to get the comparator used internally.
+       fun keys_sorted_by_values(comparator: Comparator): Array[K]
+       do
+               var keys = self.keys.to_a
+               var map_cmp = to_map_comparator(comparator)
+               map_cmp.sort(keys)
+               return keys
+       end
+
+       # A comparator that compares things with their values in self.
+       #
+       # See `MapComparator` for details.
+       fun to_map_comparator(comparator: Comparator): MapComparator[K, V] do return new MapComparator[K,V](self, comparator)
+end
+
+# A comparator that compares things with their values in a map.
+#
+# ~~~
+# var map = new HashMap[String, Int]
+# map["ten"] = 10
+# map["two"] = 2
+# map["one"] = 1
+#
+# var map_cmp = map.to_map_comparator(default_comparator)
+# var a = ["ten", "one", "two"]
+# map_cmp.sort(a)
+# assert a == ["one", "two", "ten"]
+# map_cmp = map.to_map_comparator(alpha_comparator)
+# map_cmp.sort(a)
+# assert a == ["one", "ten", "two"]
+# ~~~
+class MapComparator[K,V]
+       super Comparator
+
+       # What is compared are the keys of the values
+       redef type COMPARED: K
+
+       # The map that associates compared elements to the value used to compare them
+       var map: MapRead[K,V]
+
+       # The comparator used to compare values
+       var comparator: Comparator
+
+       redef fun compare(a,b) do return comparator.compare(map[a], map[b])
+end
+
 # This comparator uses the operator `<=>` to compare objects.
 # see `default_comparator` for an easy-to-use general stateless default comparator.
 class DefaultComparator
index 4df80b5..12c9c86 100644 (file)
@@ -33,10 +33,46 @@ import hash_collection
 # The methods `in_same_subset`, `to_partitions`, and their variations are offered instead.
 class DisjointSet[E]
        super SimpleCollection[E]
+       super Cloneable
 
        # The node in the hiearchical structure for each element
        private var nodes = new HashMap[E, DisjointSetNode]
 
+       # Copy constructor
+       init from(other: DisjointSet[E])
+       do
+               # Associate a root node in other to the associated root node in self
+               var map = new HashMap[DisjointSetNode, DisjointSetNode]
+               for e, v in other.nodes do
+                       # Create the associated node
+                       var n2 = new DisjointSetNode
+                       nodes[e] = n2
+
+                       # Get the root node in other and the associated one in self
+                       var p = other.find(e)
+                       var p2 = map.get_or_null(p)
+                       if p2 == null then
+                               # if no associated root node, then a new subset is created
+                               map[p] = n2.parent
+                               number_of_subsets += 1
+                       else
+                               # else attach the new node to the subset of the root node
+                               n2.parent = p2
+                       end
+               end
+       end
+
+       # Shallow copy
+       #
+       #     var s = new DisjointSet[Int]
+       #     s.add_all([1,2,3,4,5])
+       #     s.union_all([1,4,5])
+       #     var s2 = s.clone
+       #     assert s2.number_of_subsets == 3
+       #     assert s2.all_in_same_subset([1,4,5]) == true
+       #     assert s2.in_same_subset(1,2) == false
+       redef fun clone do return new DisjointSet[E].from(self)
+
        # The number of subsets in the partition
        #
        #     var s = new DisjointSet[Int]
index 5b5ffbb..93f5f9b 100644 (file)
@@ -149,4 +149,5 @@ int string_NativeString_NativeString_system_0(const char *cmd) {
                // cmd exited on SIGINT: in my opinion the user wants the main to be discontinued
                kill(getpid(), SIGINT);
        }
+       return status;
 }
index a2856ae..81341ad 100644 (file)
@@ -47,6 +47,21 @@ abstract class FileStream
        # File descriptor of this file
        fun fd: Int do return _file.fileno
 
+       redef fun close
+       do
+               if _file == null then return
+               if _file.address_is_null then
+                       if last_error != null then return
+                       last_error = new IOError("Cannot close unopened file")
+                       return
+               end
+               var i = _file.io_close
+               if i != 0 then
+                       last_error = new IOError("Close failed due to error {sys.errno.strerror}")
+               end
+               _file = null
+       end
+
        # Sets the buffering mode for the current FileStream
        #
        # If the buf_size is <= 0, its value will be 512 by default
@@ -89,11 +104,9 @@ class FileReader
 
        redef fun close
        do
-               if _file == null or _file.address_is_null then return
-               var i = _file.io_close
+               super
                _buffer.clear
                end_reached = true
-               _file = null
        end
 
        redef fun fill_buffer
@@ -122,6 +135,7 @@ class FileReader
                end
        end
 
+       # Creates a new File stream from a file descriptor
        init from_fd(fd: Int) do
                self.path = ""
                prepare_buffer(1)
@@ -154,19 +168,8 @@ class FileWriter
 
        redef fun close
        do
-               if _file == null then return
-               if _file.address_is_null then
-                       if last_error != null then return
-                       last_error = new IOError("Cannot close unopened write stream")
-                       _is_writable = false
-                       return
-               end
-               var i = _file.io_close
-               if i != 0 then
-                       last_error = new IOError("Close failed due to error {sys.errno.strerror}")
-               end
+               super
                _is_writable = false
-               _file = null
        end
        redef var is_writable = false
 
index 4892f95..e974d91 100644 (file)
@@ -531,6 +531,14 @@ abstract class Text
        #
        #     assert "abAB12<>&".escape_to_c         == "abAB12<>&"
        #     assert "\n\"'\\".escape_to_c         == "\\n\\\"\\'\\\\"
+       #
+       # Most non-printable characters (bellow ASCII 32) are escaped to an octal form `\nnn`.
+       # Three digits are always used to avoid following digits to be interpreted as an element
+       # of the octal sequence.
+       #
+       #     assert "{0.ascii}{1.ascii}{8.ascii}{31.ascii}{32.ascii}".escape_to_c == "\\000\\001\\010\\037 "
+       #
+       # The exceptions are the common `\t` and `\n`.
        fun escape_to_c: String
        do
                var b = new FlatBuffer
@@ -538,8 +546,10 @@ abstract class Text
                        var c = chars[i]
                        if c == '\n' then
                                b.append("\\n")
+                       else if c == '\t' then
+                               b.append("\\t")
                        else if c == '\0' then
-                               b.append("\\0")
+                               b.append("\\000")
                        else if c == '"' then
                                b.append("\\\"")
                        else if c == '\'' then
@@ -547,7 +557,17 @@ abstract class Text
                        else if c == '\\' then
                                b.append("\\\\")
                        else if c.ascii < 32 then
-                               b.append("\\{c.ascii.to_base(8, false)}")
+                               b.add('\\')
+                               var oct = c.ascii.to_base(8, false)
+                               # Force 3 octal digits since it is the
+                               # maximum allowed in the C specification
+                               if oct.length == 1 then
+                                       b.add('0')
+                                       b.add('0')
+                               else if oct.length == 2 then
+                                       b.add('0')
+                               end
+                               b.append(oct)
                        else
                                b.add(c)
                        end
index 6160b1a..3150c5f 100644 (file)
@@ -55,8 +55,6 @@ class TmplComposer
        # Short name
        var name: String
 
-       init(name: String) do self.name = name
-
        redef fun rendering do add "- {name}\n"
 end
 
@@ -69,13 +67,6 @@ class TmplComposerDetail
        var birth: Int
        var death: Int
 
-       init(firstname, lastname: String, birth, death: Int) do
-               self.firstname = firstname
-               self.lastname = lastname
-               self.birth = birth
-               self.death = death
-       end
-
        redef fun rendering do add """
 
 COMPOSER: {{{firstname}}} {{{lastname}}}
index 658f0e7..43fd172 100644 (file)
@@ -23,6 +23,7 @@ import platform
 import c_tools
 private import annotation
 import mixin
+import counter
 
 # Add compiling options
 redef class ToolContext
@@ -121,20 +122,30 @@ redef class ModelBuilder
        protected fun write_and_make(compiler: AbstractCompiler)
        do
                var platform = compiler.target_platform
-               var toolchain = platform.toolchain(toolcontext)
+               var toolchain = platform.toolchain(toolcontext, compiler)
                compile_dir = toolchain.compile_dir
-               toolchain.write_and_make compiler
+               toolchain.write_and_make
        end
 end
 
 redef class Platform
        # The specific tool-chain associated to the platform
-       fun toolchain(toolcontext: ToolContext): Toolchain do return new MakefileToolchain(toolcontext)
+       fun toolchain(toolcontext: ToolContext, compiler: AbstractCompiler): Toolchain
+       do
+               return new MakefileToolchain(toolcontext, compiler)
+       end
 end
 
+# Build toolchain for a specific target program, varies per `Platform`
 class Toolchain
+
+       # Toolcontext
        var toolcontext: ToolContext
 
+       # Compiler of the target program
+       var compiler: AbstractCompiler
+
+       # Directory where to generate all C files
        fun compile_dir: String
        do
                var compile_dir = toolcontext.opt_compile_dir.value
@@ -142,13 +153,15 @@ class Toolchain
                return compile_dir
        end
 
-       fun write_and_make(compiler: AbstractCompiler) is abstract
+       # Write all C files and compile them
+       fun write_and_make is abstract
 end
 
+# Default toolchain using a Makefile
 class MakefileToolchain
        super Toolchain
 
-       redef fun write_and_make(compiler)
+       redef fun write_and_make
        do
                var compile_dir = compile_dir
 
@@ -161,11 +174,11 @@ class MakefileToolchain
                compile_dir.mkdir
 
                var cfiles = new Array[String]
-               write_files(compiler, compile_dir, cfiles)
+               write_files(compile_dir, cfiles)
 
                # Generate the Makefile
 
-               write_makefile(compiler, compile_dir, cfiles)
+               write_makefile(compile_dir, cfiles)
 
                var time1 = get_time
                self.toolcontext.info("*** END WRITING C: {time1-time0} ***", 2)
@@ -177,13 +190,14 @@ class MakefileToolchain
                time0 = time1
                self.toolcontext.info("*** COMPILING C ***", 1)
 
-               compile_c_code(compiler, compile_dir)
+               compile_c_code(compile_dir)
 
                time1 = get_time
                self.toolcontext.info("*** END COMPILING C: {time1-time0} ***", 2)
        end
 
-       fun write_files(compiler: AbstractCompiler, compile_dir: String, cfiles: Array[String])
+       # Write all source files to the `compile_dir`
+       fun write_files(compile_dir: String, cfiles: Array[String])
        do
                var platform = compiler.target_platform
                if self.toolcontext.opt_stacktrace.value == "nitstack" and platform.supports_libunwind then compiler.build_c_to_nit_bindings
@@ -280,10 +294,14 @@ class MakefileToolchain
                self.toolcontext.info("Total C source files to compile: {cfiles.length}", 2)
        end
 
-       fun makefile_name(mainmodule: MModule): String do return "{mainmodule.c_name}.mk"
+       # Get the name of the Makefile to use
+       fun makefile_name: String do return "{compiler.mainmodule.c_name}.mk"
 
-       fun default_outname(mainmodule: MModule): String
+       # Get the default name of the executable to produce
+       fun default_outname: String
        do
+               var mainmodule = compiler.mainmodule
+
                # Search a non fictive module
                var res = mainmodule.name
                while mainmodule.is_fictive do
@@ -298,13 +316,14 @@ class MakefileToolchain
        do
                var res = self.toolcontext.opt_output.value
                if res != null then return res
-               res = default_outname(mainmodule)
+               res = default_outname
                var dir = self.toolcontext.opt_dir.value
                if dir != null then return dir.join_path(res)
                return res
        end
 
-       fun write_makefile(compiler: AbstractCompiler, compile_dir: String, cfiles: Array[String])
+       # Write the Makefile
+       fun write_makefile(compile_dir: String, cfiles: Array[String])
        do
                var mainmodule = compiler.mainmodule
                var platform = compiler.target_platform
@@ -319,7 +338,7 @@ class MakefileToolchain
                        # 2. copy the binary at the right place in the `all` goal.
                        outpath = mainmodule.c_name
                end
-               var makename = makefile_name(mainmodule)
+               var makename = makefile_name
                var makepath = "{compile_dir}/{makename}"
                var makefile = new FileWriter.open(makepath)
 
@@ -444,9 +463,10 @@ endif
                makepath.file_copy_to "{compile_dir}/Makefile"
        end
 
-       fun compile_c_code(compiler: AbstractCompiler, compile_dir: String)
+       # The C code is generated, compile it to an executable
+       fun compile_c_code(compile_dir: String)
        do
-               var makename = makefile_name(compiler.mainmodule)
+               var makename = makefile_name
 
                var makeflags = self.toolcontext.opt_make_flags.value
                if makeflags == null then makeflags = ""
@@ -589,6 +609,8 @@ abstract class AbstractCompiler
                self.header.add_decl("#include <stdlib.h>")
                self.header.add_decl("#include <stdio.h>")
                self.header.add_decl("#include <string.h>")
+               self.header.add_decl("#include <sys/types.h>\n")
+               self.header.add_decl("#include <unistd.h>\n")
                self.header.add_decl("#include \"gc_chooser.h\"")
                self.header.add_decl("#ifdef ANDROID")
                self.header.add_decl("  #include <android/log.h>")
@@ -1021,14 +1043,6 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref ) {
        end
 
        fun finalize_ffi_for_module(mmodule: MModule) do mmodule.finalize_ffi(self)
-
-       # Division facility
-       # Avoid division by zero by returning the string "n/a"
-       fun div(a,b:Int):String
-       do
-               if b == 0 then return "n/a"
-               return ((a*10000/b).to_f / 100.0).to_precision(2)
-       end
 end
 
 # A file unit (may be more than one file if
index b2f4837..e2afc48 100644 (file)
@@ -17,7 +17,7 @@ module coloring
 import poset
 
 # Build a conflict graph from a POSet
-class POSetConflictGraph[E: Object]
+class POSetConflictGraph[E]
 
        # Core is composed by:
        #  * elements that have mutiple direct parents
@@ -45,13 +45,18 @@ class POSetConflictGraph[E: Object]
        # REQUIRE: is_colored
        var conflicts = new HashMap[E, Set[E]]
 
+       # The associated poset
        var poset: POSet[E]
 
+       # The linearisation order to visit elements in the poset
+       var order: Array[E] is noinit
+
        init do
                extract_core
                extract_border
                extract_crown
                compute_conflicts
+               order = poset.linearize(poset)
        end
 
        # Compute the set of elements forming the core of the poset hierarchy.
@@ -116,10 +121,14 @@ class POSetConflictGraph[E: Object]
                #print "border: {border.join(" ")} ({border.length})"
                #print "crown: {crown.join(" ")} ({crown.length})"
                print "conflicts:"
-               for e, c in conflicts do print "  {e}: {c.join(" ")}"
+               for e, c in conflicts do print "  {e or else "NULL"}: {c.join(" ")}"
        end
 end
 
+redef class POSet[E]
+       fun to_conflict_graph: POSetConflictGraph[E] do return new POSetConflictGraph[E](self)
+end
+
 # Colorize elements from a POSet
 # Two elements from a POSet cannot have the same color if they share common subelements
 #
@@ -265,6 +274,166 @@ class POSetColorer[E: Object]
        end
 end
 
+# Colorize elements `E` introduced by holders `H` in a `POSet`.
+#
+# Two elements cannot have the same color if they are introduced or inherited by a same holder.
+class POSetGroupColorer[H: Object, E: Object]
+
+       # The associated conflict graph containing the poset.
+       #
+       # The conflict graph is used instead of the original poset so that the conflict graph can be reused
+       # in different coloration based on the same poset.
+       var graph: POSetConflictGraph[H]
+
+       # The elements to color.
+       #
+       # For each holder, the collection of introduced elements is given.
+       #
+       # A single element must not be introduced in more than one holder.
+       var buckets: Map[H, Collection[E]]
+
+       # The associated poset.
+       #
+       # alias for `graph.poset`
+       fun poset: POSet[H] do return graph.poset
+
+       # The resulting coloring
+       #
+       # Each element from buckets is associated to its own color
+       var colors: Map[E, Int] is lazy do
+               for h in graph.poset do
+                       used_colors[h] = new HashSet[Int]
+               end
+               compute_colors
+               return colors_cache
+       end
+
+       # Resulting colors
+       private var colors_cache = new HashMap[E, Int]
+
+       # Set of known used colors
+       private var used_colors = new HashMap[H, HashSet[Int]]
+
+       # Build table layout of elements `E` for the holder `h`.
+       #
+       # `null` is used to fill places without elements (holes).
+       fun build_layout(h: H): Array[nullable E]
+       do
+               var table = new Array[nullable E]
+               for s in poset[h].greaters do
+                       var bucket = buckets.get_or_null(s)
+                       if bucket == null then continue
+                       for e in bucket do
+                               var color = colors[e]
+                               if table.length <= color then
+                                       for i in [table.length .. color[ do
+                                               table[i] = null
+                                       end
+                               else
+                                       assert table[color] == null else print "in {h}, for {color}: {table[color] or else ""} vs {e}"
+                               end
+                               table[color] = e
+                       end
+               end
+               return table
+       end
+
+       # Colorize core, border and crown in that order
+       private fun compute_colors do
+               colors_cache.clear
+               colorize_core
+               colorize_set(graph.border)
+               colorize_set(graph.crown)
+       end
+
+       # Core elements cannot have the same color than:
+       #  * one of their parents
+       #  * one of their conflicting elements
+       private fun colorize_core do
+               for h in graph.order do
+                       if not graph.core.has(h) then continue
+
+                       var color = inherit_color(h)
+                       var mincolor = color
+                       var bucket = buckets.get_or_null(h)
+                       if bucket == null then continue
+                       var conflicts = graph.conflicts[h]
+                       var parents = poset[h].greaters
+                       for e in bucket do
+                               color = next_free_color(color, parents)
+                               color = next_free_color(color, conflicts)
+                               colors_cache[e] = color
+                               used_colors[h].add color
+                               #print "{h}: color[{color}] <- {e}"
+                               if mincolor == color then mincolor += 1
+                               color += 1
+                       end
+                       min_colors[h] = mincolor
+               end
+       end
+
+       # Other elements inherit color from their direct parents
+       private fun colorize_set(set: Set[H]) do
+               for h in graph.order do
+                       if not set.has(h) then continue
+
+                       var color = inherit_color(h)
+                       var mincolor = color
+                       var bucket = buckets.get_or_null(h)
+                       if bucket == null then continue
+                       var parents = poset[h].greaters
+                       for e in bucket do
+                               color = next_free_color(color, parents)
+                               colors_cache[e] = color
+                               used_colors[h].add color
+                               #print "{h}: color[{color}] <- {e} (set)"
+                               if mincolor == color then mincolor += 1
+                               color += 1
+                       end
+                       min_colors[h] = mincolor
+               end
+       end
+
+       # Get the first available free color.
+       private fun inherit_color(h: H): Int
+       do
+               var res = 0
+               for p in poset[h].direct_greaters do
+                       var m = min_colors[p]
+                       if m > res then res = m
+               end
+               min_colors[h] = res
+               return res
+       end
+
+       # The first available color for each holder.
+       #
+       # Is used by children to start their coloring.
+       #
+       # Is updated at the end of a coloring step.
+       private var min_colors = new HashMap[H, Int]
+
+       private fun next_free_color(color: Int, set: Collection[H]): Int do
+               loop
+                       for h in set do
+                               if used_colors[h].has(color) then
+                                       #print "\tin {h}, {color} is used"
+                                       color += 1
+                                       continue label
+                               end
+                       end
+                       break
+               end label
+               return color
+       end
+
+       # Used for debugging only
+       fun pretty_print do
+               print "colors:"
+               for e, c in colors do print "  {e}: {c}"
+       end
+end
+
 # Colorize a collection of buckets
 # Two elements cannot have the same color if they both appear in the same bucket
 # No coloring order is garantied
index ea60c0a..c013295 100644 (file)
@@ -22,3 +22,4 @@ import compiler_ffi
 import platform::android
 import platform::pnacl
 import platform::emscripten
+import platform::ios
index ecfcc8e..dab4a79 100644 (file)
@@ -59,6 +59,8 @@ redef class ToolContext
        var opt_colo_dead_methods = new OptionBool("Force colorization of dead methods", "--colo-dead-methods")
        # --tables-metrics
        var opt_tables_metrics = new OptionBool("Enable static size measuring of tables used for vft, typing and resolution", "--tables-metrics")
+       # --type-poset
+       var opt_type_poset = new OptionBool("Build a poset of types to create more condensed tables.", "--type-poset")
 
        redef init
        do
@@ -72,6 +74,7 @@ redef class ToolContext
                self.option_context.add_option(self.opt_inline_coloring_numbers, opt_inline_some_methods, opt_direct_call_monomorph, opt_skip_dead_methods, opt_semi_global)
                self.option_context.add_option(self.opt_colo_dead_methods)
                self.option_context.add_option(self.opt_tables_metrics)
+               self.option_context.add_option(self.opt_type_poset)
        end
 
        redef fun process_options(args)
@@ -146,8 +149,6 @@ class SeparateCompiler
        private var type_ids: Map[MType, Int] is noinit
        private var type_colors: Map[MType, Int] is noinit
        private var opentype_colors: Map[MType, Int] is noinit
-       protected var method_colors: Map[PropertyLayoutElement, Int] is noinit
-       protected var attr_colors: Map[MAttribute, Int] is noinit
 
        init do
                var file = new_file("nit.common")
@@ -305,170 +306,147 @@ class SeparateCompiler
 
        private var color_consts_done = new HashSet[Object]
 
+       # The conflict graph of classes used for coloration
+       var class_conflict_graph: POSetConflictGraph[MClass] is noinit
+
        # colorize classe properties
        fun do_property_coloring do
 
                var rta = runtime_type_analysis
 
-               # Layouts
-               var poset = mainmodule.flatten_mclass_hierarchy
-               var mclasses = new HashSet[MClass].from(poset)
-               var colorer = new POSetColorer[MClass]
-               colorer.colorize(poset)
-
-               # The dead methods, still need to provide a dead color symbol
-               var dead_methods = new Array[MMethod]
+               # Class graph
+               var mclasses = mainmodule.flatten_mclass_hierarchy
+               class_conflict_graph = mclasses.to_conflict_graph
 
-               # lookup properties to build layout with
+               # Prepare to collect elements to color and build layout with
                var mmethods = new HashMap[MClass, Set[PropertyLayoutElement]]
                var mattributes = new HashMap[MClass, Set[MAttribute]]
+
+               # The dead methods and super-call, still need to provide a dead color symbol
+               var dead_methods = new Array[PropertyLayoutElement]
+
                for mclass in mclasses do
                        mmethods[mclass] = new HashSet[PropertyLayoutElement]
                        mattributes[mclass] = new HashSet[MAttribute]
-                       for mprop in self.mainmodule.properties(mclass) do
-                               if mprop isa MMethod then
-                                       if not modelbuilder.toolcontext.opt_colo_dead_methods.value and rta != null and not rta.live_methods.has(mprop) then
-                                               dead_methods.add(mprop)
-                                               continue
-                                       end
-                                       mmethods[mclass].add(mprop)
-                               else if mprop isa MAttribute then
-                                       mattributes[mclass].add(mprop)
-                               end
+               end
+
+               # Pre-collect known live things
+               if rta != null then
+                       for m in rta.live_methods do
+                               mmethods[m.intro_mclassdef.mclass].add m
+                       end
+                       for m in rta.live_super_sends do
+                               var mclass = m.mclassdef.mclass
+                               mmethods[mclass].add m
                        end
                end
 
-               # Collect all super calls (dead or not)
-               var all_super_calls = new HashSet[MMethodDef]
-               for mmodule in self.mainmodule.in_importation.greaters do
-                       for mclassdef in mmodule.mclassdefs do
-                               for mpropdef in mclassdef.mpropdefs do
-                                       if not mpropdef isa MMethodDef then continue
-                                       if mpropdef.has_supercall then
-                                               all_super_calls.add(mpropdef)
+               for m in mainmodule.in_importation.greaters do for cd in m.mclassdefs do
+                       var mclass = cd.mclass
+                       # Collect methods ad attributes
+                       for p in cd.intro_mproperties do
+                               if p isa MMethod then
+                                       if rta == null then
+                                               mmethods[mclass].add p
+                                       else if not rta.live_methods.has(p) then
+                                               dead_methods.add p
                                        end
+                               else if p isa MAttribute then
+                                       mattributes[mclass].add p
                                end
                        end
-               end
 
-               # lookup super calls and add it to the list of mmethods to build layout with
-               var super_calls
-               if rta != null then
-                       super_calls = rta.live_super_sends
-               else
-                       super_calls = all_super_calls
-               end
-
-               for mmethoddef in super_calls do
-                       var mclass = mmethoddef.mclassdef.mclass
-                       mmethods[mclass].add(mmethoddef)
-                       for descendant in mclass.in_hierarchy(self.mainmodule).smallers do
-                               mmethods[descendant].add(mmethoddef)
+                       # Collect all super calls (dead or not)
+                       for mpropdef in cd.mpropdefs do
+                               if not mpropdef isa MMethodDef then continue
+                               if mpropdef.has_supercall then
+                                       if rta == null then
+                                               mmethods[mclass].add mpropdef
+                                       else if not rta.live_super_sends.has(mpropdef) then
+                                               dead_methods.add mpropdef
+                                       end
+                               end
                        end
                end
 
                # methods coloration
-               var meth_colorer = new POSetBucketsColorer[MClass, PropertyLayoutElement](poset, colorer.conflicts)
-               method_colors = meth_colorer.colorize(mmethods)
-               method_tables = build_method_tables(mclasses, super_calls)
+               var meth_colorer = new POSetGroupColorer[MClass, PropertyLayoutElement](class_conflict_graph, mmethods)
+               var method_colors = meth_colorer.colors
                compile_color_consts(method_colors)
 
-               # attribute null color to dead methods and supercalls
-               for mproperty in dead_methods do
-                       compile_color_const(new_visitor, mproperty, -1)
-               end
-               for mpropdef in all_super_calls do
-                       if super_calls.has(mpropdef) then continue
-                       compile_color_const(new_visitor, mpropdef, -1)
-               end
+               # give null color to dead methods and supercalls
+               for mproperty in dead_methods do compile_color_const(new_visitor, mproperty, -1)
 
-               # attributes coloration
-               var attr_colorer = new POSetBucketsColorer[MClass, MAttribute](poset, colorer.conflicts)
-               attr_colors = attr_colorer.colorize(mattributes)
-               attr_tables = build_attr_tables(mclasses)
+               # attribute coloration
+               var attr_colorer = new POSetGroupColorer[MClass, MAttribute](class_conflict_graph, mattributes)
+               var attr_colors = attr_colorer.colors#ize(poset, mattributes)
                compile_color_consts(attr_colors)
-       end
 
-       fun build_method_tables(mclasses: Set[MClass], super_calls: Set[MMethodDef]): Map[MClass, Array[nullable MPropDef]] do
-               var tables = new HashMap[MClass, Array[nullable MPropDef]]
+               # Build method and attribute tables
+               method_tables = new HashMap[MClass, Array[nullable MPropDef]]
+               attr_tables = new HashMap[MClass, Array[nullable MProperty]]
                for mclass in mclasses do
-                       var table = new Array[nullable MPropDef]
-                       tables[mclass] = table
+                       if not mclass.has_new_factory and (mclass.kind == abstract_kind or mclass.kind == interface_kind) then continue
+                       if rta != null and not rta.live_classes.has(mclass) then continue
 
-                       var mproperties = self.mainmodule.properties(mclass)
                        var mtype = mclass.intro.bound_mtype
 
-                       for mproperty in mproperties do
-                               if not mproperty isa MMethod then continue
-                               if not method_colors.has_key(mproperty) then continue
-                               var color = method_colors[mproperty]
-                               if table.length <= color then
-                                       for i in [table.length .. color[ do
-                                               table[i] = null
-                                       end
-                               end
-                               table[color] = mproperty.lookup_first_definition(mainmodule, mtype)
-                       end
-
-                       for supercall in super_calls do
-                               if not mtype.collect_mclassdefs(mainmodule).has(supercall.mclassdef) then continue
-
-                               var color = method_colors[supercall]
-                               if table.length <= color then
-                                       for i in [table.length .. color[ do
-                                               table[i] = null
-                                       end
+                       # Resolve elements in the layout to get the final table
+                       var meth_layout = meth_colorer.build_layout(mclass)
+                       var meth_table = new Array[nullable MPropDef].with_capacity(meth_layout.length)
+                       method_tables[mclass] = meth_table
+                       for e in meth_layout do
+                               if e == null then
+                                       meth_table.add null
+                               else if e isa MMethod then
+                                       # Standard method call of `e`
+                                       meth_table.add e.lookup_first_definition(mainmodule, mtype)
+                               else if e isa MMethodDef then
+                                       # Super-call in the methoddef `e`
+                                       meth_table.add e.lookup_next_definition(mainmodule, mtype)
+                               else
+                                       abort
                                end
-                               var mmethoddef = supercall.lookup_next_definition(mainmodule, mtype)
-                               table[color] = mmethoddef
                        end
 
+                       # Do not need to resolve attributes as only the position is used
+                       attr_tables[mclass] = attr_colorer.build_layout(mclass)
                end
-               return tables
-       end
-
-       fun build_attr_tables(mclasses: Set[MClass]): Map[MClass, Array[nullable MPropDef]] do
-               var tables = new HashMap[MClass, Array[nullable MPropDef]]
-               for mclass in mclasses do
-                       var table = new Array[nullable MPropDef]
-                       tables[mclass] = table
 
-                       var mproperties = self.mainmodule.properties(mclass)
-                       var mtype = mclass.intro.bound_mtype
 
-                       for mproperty in mproperties do
-                               if not mproperty isa MAttribute then continue
-                               if not attr_colors.has_key(mproperty) then continue
-                               var color = attr_colors[mproperty]
-                               if table.length <= color then
-                                       for i in [table.length .. color[ do
-                                               table[i] = null
-                                       end
-                               end
-                               table[color] = mproperty.lookup_first_definition(mainmodule, mtype)
-                       end
-               end
-               return tables
        end
 
        # colorize live types of the program
-       private fun do_type_coloring: POSet[MType] do
+       private fun do_type_coloring: Collection[MType] do
                # Collect types to colorize
                var live_types = runtime_type_analysis.live_types
                var live_cast_types = runtime_type_analysis.live_cast_types
 
-               # Compute colors
-               var poset = poset_from_mtypes(live_types, live_cast_types)
-               var colorer = new POSetColorer[MType]
-               colorer.colorize(poset)
-               type_ids = colorer.ids
-               type_colors = colorer.colors
-               type_tables = build_type_tables(poset)
+               var res = new HashSet[MType]
+               res.add_all live_types
+               res.add_all live_cast_types
+
+               if modelbuilder.toolcontext.opt_type_poset.value then
+                       # Compute colors with a type poset
+                       var poset = poset_from_mtypes(live_types, live_cast_types)
+                       var colorer = new POSetColorer[MType]
+                       colorer.colorize(poset)
+                       type_ids = colorer.ids
+                       type_colors = colorer.colors
+                       type_tables = build_type_tables(poset)
+               else
+                       # Compute colors using the class poset
+                       # Faster to compute but the number of holes can degenerate
+                       compute_type_test_layouts(live_types, live_cast_types)
+
+                       type_ids = new HashMap[MType, Int]
+                       for x in res do type_ids[x] = type_ids.length + 1
+               end
 
                # VT and FT are stored with other unresolved types in the big resolution_tables
                self.compute_resolution_tables(live_types)
 
-               return poset
+               return res
        end
 
        private fun poset_from_mtypes(mtypes, cast_types: Set[MType]): POSet[MType] do
@@ -527,6 +505,48 @@ class SeparateCompiler
                return tables
        end
 
+
+       private fun compute_type_test_layouts(mtypes: Set[MClassType], cast_types: Set[MType]) do
+               # Group cast_type by their classes
+               var bucklets = new HashMap[MClass, Set[MType]]
+               for e in cast_types do
+                       var c = e.as_notnullable.as(MClassType).mclass
+                       if not bucklets.has_key(c) then
+                               bucklets[c] = new HashSet[MType]
+                       end
+                       bucklets[c].add(e)
+               end
+
+               # Colorize cast_types from the class hierarchy
+               var colorer = new POSetGroupColorer[MClass, MType](class_conflict_graph, bucklets)
+               type_colors = colorer.colors
+
+               var layouts = new HashMap[MClass, Array[nullable MType]]
+               for c in runtime_type_analysis.live_classes do
+                       layouts[c] = colorer.build_layout(c)
+               end
+
+               # Build the table for each live type
+               for t in mtypes do
+                       # A live type use the layout of its class
+                       var c = t.mclass
+                       var layout = layouts[c]
+                       var table = new Array[nullable MType].with_capacity(layout.length)
+                       type_tables[t] = table
+
+                       # For each potential super-type in the layout
+                       for sup in layout do
+                               if sup == null then
+                                       table.add null
+                               else if t.is_subtype(mainmodule, null, sup) then
+                                       table.add sup
+                               else
+                                       table.add null
+                               end
+                       end
+               end
+       end
+
        # resolution_tables is used to perform a type resolution at runtime in O(1)
        private fun compute_resolution_tables(mtypes: Set[MType]) do
                # During the visit of the body of classes, live_unresolved_types are collected
@@ -534,21 +554,26 @@ class SeparateCompiler
                # Collect all live_unresolved_types (visited in the body of classes)
 
                # Determinate fo each livetype what are its possible requested anchored types
-               var mtype2unresolved = new HashMap[MClassType, Set[MType]]
+               var mtype2unresolved = new HashMap[MClass, Set[MType]]
                for mtype in self.runtime_type_analysis.live_types do
-                       var set = new HashSet[MType]
+                       var mclass = mtype.mclass
+                       var set = mtype2unresolved.get_or_null(mclass)
+                       if set == null then
+                               set = new HashSet[MType]
+                               mtype2unresolved[mclass] = set
+                       end
                        for cd in mtype.collect_mclassdefs(self.mainmodule) do
                                if self.live_unresolved_types.has_key(cd) then
                                        set.add_all(self.live_unresolved_types[cd])
                                end
                        end
-                       mtype2unresolved[mtype] = set
                end
 
                # Compute the table layout with the prefered method
-               var colorer = new BucketsColorer[MType, MType]
+               var colorer = new BucketsColorer[MClass, MType]
+
                opentype_colors = colorer.colorize(mtype2unresolved)
-               resolution_tables = self.build_resolution_tables(mtype2unresolved)
+               resolution_tables = self.build_resolution_tables(self.runtime_type_analysis.live_types, mtype2unresolved)
 
                # Compile a C constant for each collected unresolved type.
                # Either to a color, or to -1 if the unresolved type is dead (no live receiver can require it)
@@ -573,9 +598,10 @@ class SeparateCompiler
                #print ""
        end
 
-       fun build_resolution_tables(elements: Map[MClassType, Set[MType]]): Map[MClassType, Array[nullable MType]] do
+       fun build_resolution_tables(elements: Set[MClassType], map: Map[MClass, Set[MType]]): Map[MClassType, Array[nullable MType]] do
                var tables = new HashMap[MClassType, Array[nullable MType]]
-               for mclasstype, mtypes in elements do
+               for mclasstype in elements do
+                       var mtypes = map[mclasstype.mclass]
                        var table = new Array[nullable MType]
                        for mtype in mtypes do
                                var color = opentype_colors[mtype]
@@ -788,8 +814,6 @@ class SeparateCompiler
                var mtype = mclass.intro.bound_mtype
                var c_name = mclass.c_name
 
-               var vft = self.method_tables[mclass]
-               var attrs = self.attr_tables[mclass]
                var v = new_visitor
 
                var rta = runtime_type_analysis
@@ -803,7 +827,8 @@ class SeparateCompiler
                        v.add_decl("const struct class class_{c_name} = \{")
                        v.add_decl("{self.box_kind_of(mclass)}, /* box_kind */")
                        v.add_decl("\{")
-                       for i in [0 .. vft.length[ do
+                       var vft = self.method_tables.get_or_null(mclass)
+                       if vft != null then for i in [0 .. vft.length[ do
                                var mpropdef = vft[i]
                                if mpropdef == null then
                                        v.add_decl("NULL, /* empty */")
@@ -932,13 +957,20 @@ class SeparateCompiler
                else
                        var res = v.new_named_var(mtype, "self")
                        res.is_exact = true
-                       v.add("{res} = nit_alloc(sizeof(struct instance) + {attrs.length}*sizeof(nitattribute_t));")
+                       var attrs = self.attr_tables.get_or_null(mclass)
+                       if attrs == null then
+                               v.add("{res} = nit_alloc(sizeof(struct instance));")
+                       else
+                               v.add("{res} = nit_alloc(sizeof(struct instance) + {attrs.length}*sizeof(nitattribute_t));")
+                       end
                        v.add("{res}->type = type;")
                        hardening_live_type(v, "type")
                        v.require_declaration("class_{c_name}")
                        v.add("{res}->class = &class_{c_name};")
-                       self.generate_init_attr(v, res, mtype)
-                       v.set_finalizer res
+                       if attrs != null then
+                               self.generate_init_attr(v, res, mtype)
+                               v.set_finalizer res
+                       end
                        v.add("return {res};")
                end
                v.add("\}")
@@ -1017,7 +1049,7 @@ class SeparateCompiler
        private var type_tables: Map[MType, Array[nullable MType]] = new HashMap[MType, Array[nullable MType]]
        private var resolution_tables: Map[MClassType, Array[nullable MType]] = new HashMap[MClassType, Array[nullable MType]]
        protected var method_tables: Map[MClass, Array[nullable MPropDef]] = new HashMap[MClass, Array[nullable MPropDef]]
-       protected var attr_tables: Map[MClass, Array[nullable MPropDef]] = new HashMap[MClass, Array[nullable MPropDef]]
+       protected var attr_tables: Map[MClass, Array[nullable MProperty]] = new HashMap[MClass, Array[nullable MProperty]]
 
        redef fun display_stats
        do
@@ -2266,7 +2298,7 @@ class SeparateRuntimeFunction
                        var v2 = compiler.new_visitor
                        v2.add "{c_ret} {n2}{c_sig} \{"
                        v2.require_declaration(m.const_color)
-                       var call = "(({c_funptrtype})({selfvar}->class->vft[{m.const_color}]))({arguments.join(", ")});"
+                       var call = "(({c_funptrtype})({v2.class_info(selfvar)}->vft[{m.const_color}]))({arguments.join(", ")});"
                        if ret != null then
                                v2.add "return {call}"
                        else
@@ -2283,7 +2315,7 @@ class SeparateRuntimeFunction
                        var v2 = compiler.new_visitor
                        v2.add "{c_ret} {n2}{c_sig} \{"
                        v2.require_declaration(m.const_color)
-                       var call = "(({c_funptrtype})({selfvar}->class->vft[{m.const_color}]))({arguments.join(", ")});"
+                       var call = "(({c_funptrtype})({v2.class_info(selfvar)}->vft[{m.const_color}]))({arguments.join(", ")});"
                        if ret != null then
                                v2.add "return {call}"
                        else
index 2a7f0fa..b8b2c0a 100644 (file)
@@ -199,8 +199,6 @@ class SeparateErasureCompiler
                var mtype = mclass.intro.bound_mtype
                var c_name = mclass.c_name
 
-               var vft = self.method_tables[mclass]
-               var attrs = self.attr_tables[mclass]
                var class_table = self.class_tables[mclass]
                var v = self.new_visitor
 
@@ -230,7 +228,8 @@ class SeparateErasureCompiler
                        end
                        v.add_decl("&type_table_{c_name},")
                        v.add_decl("\{")
-                       for i in [0 .. vft.length[ do
+                       var vft = self.method_tables.get_or_null(mclass)
+                       if vft != null then for i in [0 .. vft.length[ do
                                var mpropdef = vft[i]
                                if mpropdef == null then
                                        v.add_decl("NULL, /* empty */")
@@ -355,11 +354,18 @@ class SeparateErasureCompiler
 
                        var res = v.new_named_var(mtype, "self")
                        res.is_exact = true
-                       v.add("{res} = nit_alloc(sizeof(struct instance) + {attrs.length}*sizeof(nitattribute_t));")
+                       var attrs = self.attr_tables.get_or_null(mclass)
+                       if attrs == null then
+                               v.add("{res} = nit_alloc(sizeof(struct instance));")
+                       else
+                               v.add("{res} = nit_alloc(sizeof(struct instance) + {attrs.length}*sizeof(nitattribute_t));")
+                       end
                        v.require_declaration("class_{c_name}")
                        v.add("{res}->class = &class_{c_name};")
-                       self.generate_init_attr(v, res, mtype)
-                       v.set_finalizer res
+                       if attrs != null then
+                               self.generate_init_attr(v, res, mtype)
+                               v.set_finalizer res
+                       end
                        v.add("return {res};")
                end
                v.add("\}")
index e947ee2..64b2022 100644 (file)
@@ -68,7 +68,7 @@ end
 abstract class DocComposite
 
        # Parent element.
-       var parent: nullable DocComposite = null
+       var parent: nullable DocComposite = null is writable
 
        # Does `self` have a `parent`?
        fun is_root: Bool do return parent == null
@@ -85,6 +85,7 @@ abstract class DocComposite
        #
        # Shortcut for `children.add`.
        fun add_child(child: DocComposite) do
+               child.parent = self
                children.add child
        end
 end
index aff25d4..66ef564 100644 (file)
@@ -41,7 +41,8 @@ class GraphPhase
                        if article == null then continue
                        # FIXME avoid diff
                        # page.root.add article
-                       page.root.children[1].children.insert(article, 0)
+                       article.parent = page.root.children.first.children[1]
+                       page.root.children.first.children[1].children.insert(article, 0)
                end
        end
 end
index 39ad273..23da906 100644 (file)
@@ -47,7 +47,8 @@ redef class MModulePage
                var clients = self.clients.to_a
                v.name_sorter.sort(clients)
                section.add_child new HierarchyListArticle(mentity, "Clients", clients)
-               root.children.insert(section, 1)
+               section.parent = root.children.first
+               root.children.first.children.insert(section, 1)
        end
 end
 
@@ -66,7 +67,8 @@ redef class MClassPage
                var descendants = self.descendants.to_a
                v.name_sorter.sort(descendants)
                section.add_child new HierarchyListArticle(mentity, "Descendants", descendants)
-               root.children.insert(section, 1)
+               section.parent = root.children.first
+               root.children.first.children.insert(section, 1)
        end
 end
 
index a11e187..7d38bc0 100644 (file)
@@ -191,7 +191,7 @@ redef class DocPage
 
        # Build top menu template if any.
        fun init_topmenu(v: RenderHTMLPhase, doc: DocModel) do
-               topmenu = new TplTopMenu(html_url)
+               topmenu = new DocTopMenu
                var brand = v.ctx.opt_custom_brand.value
                if brand != null then
                        var tpl = new Template
@@ -200,8 +200,13 @@ redef class DocPage
                        tpl.add "</span>"
                        topmenu.brand = tpl
                end
-               topmenu.add_link new TplLink("index.html", "Overview")
-               topmenu.add_link new TplLink("search.html", "Index")
+               var title = "Overview"
+               if v.ctx.opt_custom_title.value != null then
+                       title = v.ctx.opt_custom_title.value.to_s
+               end
+               topmenu.add_li new ListItem(new Link("index.html", title))
+               topmenu.add_li new ListItem(new Link("search.html", "Index"))
+               topmenu.active_item = topmenu.items.first
        end
 
        # Build page sidebar if any.
@@ -257,6 +262,12 @@ end
 redef class SearchPage
        redef var html_url = "search.html"
        redef fun init_title(v, doc) do title = "Index"
+
+       redef fun init_topmenu(v, doc) do
+               super
+               topmenu.active_item = topmenu.items.last
+       end
+
        redef fun init_sidebar(v, doc) do end
 
        # TODO this should be done in StructurePhase.
@@ -314,7 +325,7 @@ end
 
 redef class MEntityPage
        redef var html_url is lazy do return mentity.nitdoc_url
-       redef fun init_title(v, doc) do title = mentity.nitdoc_name
+       redef fun init_title(v, doc) do title = mentity.html_name
        redef fun init_content(v, doc) do add_section root.start_rendering(v, doc, self)
 end
 
@@ -327,9 +338,10 @@ redef class MGroupPage
                super
                var mproject = mentity.mproject
                if not mentity.is_root then
-                       topmenu.add_link new TplLink(mproject.nitdoc_url, mproject.nitdoc_name)
+                       topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
                end
-               topmenu.add_link new TplLink(html_url, mproject.nitdoc_name)
+               topmenu.add_li new ListItem(new Link(html_url, mproject.html_name))
+               topmenu.active_item = topmenu.items.last
        end
 
        redef fun init_sidebar(v, doc) do
@@ -366,8 +378,9 @@ redef class MModulePage
        redef fun init_topmenu(v, doc) do
                super
                var mproject = mentity.mproject
-               topmenu.add_link new TplLink(mproject.nitdoc_url, mproject.nitdoc_name)
-               topmenu.add_link new TplLink(mentity.nitdoc_url, mentity.nitdoc_name)
+               topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
+               topmenu.add_li new ListItem(new Link(mentity.nitdoc_url, mentity.html_name))
+               topmenu.active_item = topmenu.items.last
        end
 
        # Class list to display in sidebar
@@ -404,15 +417,12 @@ end
 
 redef class MClassPage
 
-       redef fun init_title(v, doc) do
-               title = "{mentity.nitdoc_name}{mentity.tpl_signature.write_to_string}"
-       end
-
        redef fun init_topmenu(v, doc) do
                super
                var mproject = mentity.intro_mmodule.mgroup.mproject
-               topmenu.add_link new TplLink("{mproject.nitdoc_url}", "{mproject.nitdoc_name}")
-               topmenu.add_link new TplLink(html_url, mentity.nitdoc_name)
+               topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
+               topmenu.add_li new ListItem(new Link(html_url, mentity.html_name))
+               topmenu.active_item = topmenu.items.last
        end
 
        redef fun init_sidebar(v, doc) do
@@ -442,7 +452,7 @@ redef class MClassPage
                        classes.add "inherit"
                        var cls_url = mprop.intro.mclassdef.mclass.nitdoc_url
                        var def_url = "{cls_url}#{mprop.nitdoc_id}"
-                       var lnk = new TplLink(def_url, mprop.nitdoc_name)
+                       var lnk = new TplLink(def_url, mprop.html_name)
                        var mdoc = mprop.intro.mdoc_or_fallback
                        if mdoc != null then lnk.title = mdoc.short_comment
                        var item = new Template
@@ -486,7 +496,7 @@ end
 
 redef class MPropertyPage
        redef fun init_title(v, doc) do
-               title = "{mentity.nitdoc_name}{mentity.tpl_signature.write_to_string}"
+               title = "{mentity.html_name}{mentity.tpl_signature.write_to_string}"
        end
 
        redef fun init_topmenu(v, doc) do
@@ -494,9 +504,10 @@ redef class MPropertyPage
                var mmodule = mentity.intro_mclassdef.mmodule
                var mproject = mmodule.mgroup.mproject
                var mclass = mentity.intro_mclassdef.mclass
-               topmenu.add_link new TplLink("{mproject.nitdoc_url}", "{mproject.nitdoc_name}")
-               topmenu.add_link new TplLink("{mclass.nitdoc_url}", "{mclass.nitdoc_name}")
-               topmenu.add_link new TplLink(html_url, mentity.nitdoc_name)
+               topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
+               topmenu.add_li new ListItem(new Link(mclass.nitdoc_url, mclass.html_name))
+               topmenu.add_li new ListItem(new Link(html_url, mentity.html_name))
+               topmenu.active_item = topmenu.items.last
        end
 end
 
@@ -515,18 +526,16 @@ redef class DocRoot
        fun start_rendering(v: RenderHTMLPhase, doc: DocModel, page: MEntityPage): TplSection do
                var section = new TplSection("top")
                var mentity = page.mentity
-               section.title = mentity.nitdoc_name
+               section.title = mentity.html_name
                section.subtitle = mentity.tpl_declaration
                # FIXME ugly hack to avoid diff
                if mentity isa MGroup and mentity.is_root then
-                       section.title = mentity.mproject.nitdoc_name
+                       section.title = mentity.mproject.html_name
                        section.subtitle = mentity.mproject.tpl_declaration
-               else if mentity isa MClass then
-                       section.title = "{mentity.nitdoc_name}{mentity.tpl_signature.write_to_string}"
                else if mentity isa MProperty then
-                       section.title = "{mentity.nitdoc_name}{mentity.intro.tpl_signature.write_to_string}"
+                       section.title = "{mentity.html_name}{mentity.intro.tpl_signature.write_to_string}"
                        section.subtitle = mentity.tpl_namespace
-                       section.summary_title = mentity.nitdoc_name
+                       section.summary_title = mentity.html_name
                end
                render(v, doc, page, section)
                return section
@@ -561,10 +570,10 @@ redef class ConcernSection
                var title = new Template
                if mmodule == page.mentity then
                        title.add "in "
-                       section.summary_title = "in {mmodule.nitdoc_name}"
+                       section.summary_title = "in {mmodule.html_name}"
                else
                        title.add "from "
-                       section.summary_title = "from {mmodule.nitdoc_name}"
+                       section.summary_title = "from {mmodule.html_name}"
                end
                title.add mmodule.tpl_namespace
                section.title = title
@@ -575,7 +584,13 @@ redef class ConcernSection
                title.add "in "
                title.add mmodule.tpl_namespace
                section.title = title
-               section.summary_title = "in {mmodule.nitdoc_name}"
+               section.summary_title = "in {mmodule.html_name}"
+       end
+end
+
+redef class MEntitySection
+       redef fun render(v, doc, page, parent) do
+               for child in children do child.render(v, doc, page, parent)
        end
 end
 
@@ -690,14 +705,14 @@ redef class DefinitionArticle
                else
                        var cls_url = mprop.intro.mclassdef.mclass.nitdoc_url
                        var def_url = "{cls_url}#{mprop.nitdoc_id}"
-                       var lnk = new TplLink.with_title(def_url, mprop.nitdoc_name,
+                       var lnk = new TplLink.with_title(def_url, mprop.html_name,
                                        "Go to introduction")
                        title.add "redef "
                        title.add lnk
                end
                article.title = title
                article.title_classes.add "signature"
-               article.summary_title = "{mprop.nitdoc_name}"
+               article.summary_title = "{mprop.html_name}"
                article.subtitle = mpropdef.tpl_namespace
                if mpropdef.mdoc_or_fallback != null then
                        article.content = mpropdef.mdoc_or_fallback.tpl_comment
index 1e0d773..9c32c8c 100644 (file)
@@ -50,10 +50,12 @@ end
 
 redef class MGroupPage
        redef fun apply_structure(v, doc) do
+               var section = new MEntitySection(mentity)
+               root.add_child section
                if mentity.is_root then
-                       root.add_child new IntroArticle(mentity.mproject)
+                       section.add_child new IntroArticle(mentity.mproject)
                else
-                       root.add_child new IntroArticle(mentity)
+                       section.add_child new IntroArticle(mentity)
                end
                var concerns = self.concerns
                if concerns == null or concerns.is_empty then return
@@ -63,12 +65,12 @@ redef class MGroupPage
                concerns.sort_with(v.concerns_sorter)
                mentity.mproject.booster_rank = 0
                mentity.booster_rank = 0
-               root.add_child new ConcernsArticle(mentity, concerns)
+               section.add_child new ConcernsArticle(mentity, concerns)
                for mentity in concerns do
                        if mentity isa MModule then
-                               root.add_child new DefinitionArticle(mentity)
+                               section.add_child new DefinitionArticle(mentity)
                        else
-                               root.add_child new ConcernSection(mentity)
+                               section.add_child new ConcernSection(mentity)
                        end
                end
        end
@@ -76,7 +78,9 @@ end
 
 redef class MModulePage
        redef fun apply_structure(v, doc) do
-               root.add_child new IntroArticle(mentity)
+               var section = new MEntitySection(mentity)
+               root.add_child section
+               section.add_child new IntroArticle(mentity)
                var concerns = self.concerns
                if concerns == null or concerns.is_empty then return
                # FIXME avoid diff
@@ -87,10 +91,10 @@ redef class MModulePage
                mentity.mgroup.mproject.booster_rank = 0
                mentity.mgroup.booster_rank = 0
                mentity.booster_rank = 0
-               root.add_child new ConcernsArticle(mentity, concerns)
+               section.add_child new ConcernsArticle(mentity, concerns)
                # reference list
                for mentity in concerns do
-                       var section = new ConcernSection(mentity)
+                       var ssection = new ConcernSection(mentity)
                        if mentity isa MModule then
                                var mclasses = mclasses_for_mmodule(mentity).to_a
                                v.name_sorter.sort(mclasses)
@@ -104,10 +108,10 @@ redef class MModulePage
                                        for mclassdef in mclassdefs do
                                                article.add_child(new DefinitionArticle(mclassdef))
                                        end
-                                       section.add_child article
+                                       ssection.add_child article
                                end
                        end
-                       root.add_child section
+                       section.add_child ssection
                end
        end
 
@@ -136,7 +140,9 @@ end
 
 redef class MClassPage
        redef fun apply_structure(v, doc) do
-               root.add_child new IntroArticle(mentity)
+               var section = new MEntitySection(mentity)
+               root.add_child section
+               section.add_child new IntroArticle(mentity)
                var concerns = self.concerns
                if concerns == null or concerns.is_empty then return
                # FIXME diff hack
@@ -147,9 +153,9 @@ redef class MClassPage
                mentity.intro_mmodule.mgroup.mproject.booster_rank = 0
                mentity.intro_mmodule.mgroup.booster_rank = 0
                mentity.intro_mmodule.booster_rank = 0
-               root.add_child new ConcernsArticle(mentity, concerns)
+               section.add_child new ConcernsArticle(mentity, concerns)
                for mentity in concerns do
-                       var section = new ConcernSection(mentity)
+                       var ssection = new ConcernSection(mentity)
                        if mentity isa MModule then
                                var mprops = mproperties_for(mentity)
                                var by_kind = new PropertiesByKind.with_elements(mprops)
@@ -157,12 +163,12 @@ redef class MClassPage
                                        v.name_sorter.sort(group)
                                        for mprop in group do
                                                for mpropdef in mpropdefs_for(mprop, mentity) do
-                                                       section.add_child new DefinitionArticle(mpropdef)
+                                                       ssection.add_child new DefinitionArticle(mpropdef)
                                                end
                                        end
                                end
                        end
-                       root.add_child section
+                       section.add_child ssection
                end
        end
 
@@ -196,7 +202,9 @@ end
 
 redef class MPropertyPage
        redef fun apply_structure(v, doc) do
-               root.add_child new IntroArticle(mentity)
+               var section = new MEntitySection(mentity)
+               root.add_child section
+               section.add_child new IntroArticle(mentity)
                var concerns = self.concerns
                if concerns == null or concerns.is_empty then return
                # FIXME diff hack
@@ -207,18 +215,18 @@ redef class MPropertyPage
                mentity.intro.mclassdef.mmodule.mgroup.mproject.booster_rank = 0
                mentity.intro.mclassdef.mmodule.mgroup.booster_rank = 0
                mentity.intro.mclassdef.mmodule.booster_rank = 0
-               root.add_child new ConcernsArticle(mentity, concerns)
+               section.add_child new ConcernsArticle(mentity, concerns)
                for mentity in concerns do
-                       var section = new ConcernSection(mentity)
+                       var ssection = new ConcernSection(mentity)
                        if mentity isa MModule then
                                # Add mproperties
                                var mpropdefs = mpropdefs_for(mentity).to_a
                                v.name_sorter.sort(mpropdefs)
                                for mpropdef in mpropdefs do
-                                       section.add_child new DefinitionArticle(mpropdef)
+                                       ssection.add_child new DefinitionArticle(mpropdef)
                                end
                        end
-                       root.add_child section
+                       section.add_child ssection
                end
        end
 
@@ -258,6 +266,14 @@ abstract class MEntityArticle
        super DocArticle
 end
 
+# A section about a Mentity.
+#
+# Used to regroup content about a MEntity.
+class MEntitySection
+       super MEntityComposite
+       super DocSection
+end
+
 # An introduction article about a MEntity.
 #
 # Used at the top of a documentation page to introduce the documented MEntity.
index c3126f7..e65059b 100644 (file)
@@ -24,70 +24,6 @@ import json::static
 # general layout elements
 #########################
 
-# Top menu bar template
-class TplTopMenu
-       super Template
-
-       # Brand link to display in first position of the top menu
-       private var brand: nullable Writable = null is writable
-       # Elements of the topmenu
-       private var elts = new Array[Writable]
-
-       # The page url where the top menu is displayed.
-       #
-       # Used to select the active link.
-       private var current_url: String
-
-       # Add a new link to the menu.
-       fun add_link(content: TplLink) do
-               var is_active = content.href == current_url
-               add_item(content, is_active)
-       end
-
-       # Add a content between `<li>` tags
-       fun add_item(content: Writable, is_active: Bool) do
-               var tpl = new Template
-               tpl.add "<li"
-               if is_active then
-                       tpl.add " class=\"active\""
-               end
-               tpl.add ">"
-               tpl.add content
-               tpl.addn "</li>"
-               add_raw(tpl)
-       end
-
-       # Add a raw content to the menu
-       fun add_raw(content: Writable) do
-               elts.add content
-       end
-
-       redef fun rendering do
-               if brand == null and elts.is_empty then return
-               addn "<nav id='topmenu' class='navbar navbar-default navbar-fixed-top' role='navigation'>"
-               addn " <div class='container-fluid'>"
-               addn "  <div class='navbar-header'>"
-               add "   <button type='button' class='navbar-toggle' "
-               addn "       data-toggle='collapse' data-target='#topmenu-collapse'>"
-               addn "    <span class='sr-only'>Toggle menu</span>"
-               addn "    <span class='icon-bar'></span>"
-               addn "    <span class='icon-bar'></span>"
-               addn "    <span class='icon-bar'></span>"
-               addn "   </button>"
-               if brand != null then add brand.as(not null)
-               addn "  </div>"
-               addn "  <div class='collapse navbar-collapse' id='topmenu-collapse'>"
-               if not elts.is_empty then
-                       addn "<ul class='nav navbar-nav'>"
-                       for elt in elts do add elt
-                       addn "</ul>"
-               end
-               addn "  </div>"
-               addn " </div>"
-               addn "</nav>"
-       end
-end
-
 # A sidebar template
 class TplSidebar
        super Template
index 15b2963..2908fad 100644 (file)
@@ -45,9 +45,20 @@ redef class MEntity
        # URL of this entity’s Nitdoc page.
        fun nitdoc_url: String is abstract
 
+       # Returns the mentity name without short signature.
+       #
+       # * MProject: `foo`
+       # * MGroup: `foo`
+       # * MModule: `foo`
+       # * MClass: `Foo[E]`
+       # * MClassDef: `Foo[E]`
+       # * MProperty: `foo(e)`
+       # * MPropdef: `foo(e)`
+       var html_name: String is lazy do return name.html_escape
+
        # A template link to the mentity `nitdoc_id`
        fun tpl_anchor: TplLink do
-               var tpl = new TplLink("#{nitdoc_id}", nitdoc_name)
+               var tpl = new TplLink("#{nitdoc_id}", html_name)
                var mdoc = mdoc_or_fallback
                if mdoc != null then
                        tpl.title = mdoc.short_comment
@@ -57,7 +68,7 @@ redef class MEntity
 
        # A template link to the mentity `nitdoc_url`
        fun tpl_link: TplLink do
-               var tpl = new TplLink(nitdoc_url, nitdoc_name)
+               var tpl = new TplLink(nitdoc_url, html_name)
                var mdoc = mdoc_or_fallback
                if mdoc != null then
                        tpl.title = mdoc.short_comment
@@ -80,7 +91,7 @@ redef class MEntity
                var tpl = new TplArticle.with_title(nitdoc_id, tpl_title)
                tpl.title_classes.add "signature"
                tpl.subtitle = tpl_namespace
-               tpl.summary_title = nitdoc_name
+               tpl.summary_title = html_name
                return tpl
        end
 
@@ -252,6 +263,22 @@ redef class MClass
        redef fun nitdoc_url do return "class_{nitdoc_id}.html"
        redef fun mdoc_or_fallback do return intro.mdoc
 
+       # Format: `Foo[E]`
+       redef var html_name is lazy do
+               var tpl = new Template
+               tpl.add name.html_escape
+               if arity > 0 then
+                       tpl.add "["
+                       var parameter_names = new Array[String]
+                       for p in mparameters do
+                               parameter_names.add(p.html_name)
+                       end
+                       tpl.add parameter_names.join(", ")
+                       tpl.add "]"
+               end
+               return tpl.write_to_string
+       end
+
        redef fun tpl_declaration do return intro.tpl_declaration
        redef fun tpl_definition do return intro.tpl_definition
 
@@ -268,7 +295,6 @@ redef class MClass
                var title = new Template
                title.add tpl_icon
                title.add tpl_link
-               title.add tpl_signature
                return title
        end
 
@@ -280,7 +306,7 @@ redef class MClass
                        tpl.add "["
                        var parameter_names = new Array[String]
                        for p in mparameters do
-                               parameter_names.add(p.nitdoc_name)
+                               parameter_names.add(p.html_name)
                        end
                        tpl.add parameter_names.join(", ")
                        tpl.add "]"
@@ -288,12 +314,6 @@ redef class MClass
                return tpl
        end
 
-       redef fun tpl_article do
-               var tpl = super
-               tpl.summary_title = "{nitdoc_name}{tpl_signature.write_to_string}"
-               return tpl
-       end
-
        redef fun tpl_css_classes do return intro.tpl_css_classes
 end
 
@@ -314,7 +334,7 @@ redef class MClassDef
 
        redef fun tpl_article do
                var tpl = new TplArticle(nitdoc_id)
-               tpl.summary_title = "in {mmodule.nitdoc_name}"
+               tpl.summary_title = "in {mmodule.html_name}"
                tpl.title = tpl_declaration
                tpl.title_classes.add "signature"
                var title = new Template
@@ -332,7 +352,6 @@ redef class MClassDef
                var title = new Template
                title.add tpl_icon
                title.add tpl_link
-               title.add tpl_signature
                return title
        end
 
@@ -350,7 +369,7 @@ redef class MClassDef
                if not mparameters.is_empty then
                        tpl.add "["
                        for i in [0..mparameters.length[ do
-                               tpl.add "{mparameters[i].nitdoc_name}: "
+                               tpl.add "{mparameters[i].html_name}: "
                                tpl.add bound_mtype.arguments[i].tpl_signature
                                if i < mparameters.length - 1 then tpl.add ", "
                        end
@@ -428,7 +447,7 @@ redef class MPropDef
 
        redef fun tpl_article do
                var tpl = new TplArticle(nitdoc_id)
-               tpl.summary_title = "in {mclassdef.nitdoc_name}"
+               tpl.summary_title = "in {mclassdef.html_name}"
                var title = new Template
                title.add "in "
                title.add mclassdef.tpl_link
@@ -577,7 +596,9 @@ end
 redef class MGenericType
        redef fun tpl_signature do
                var tpl = new Template
-               tpl.add tpl_link
+               var lnk = tpl_link
+               lnk.text = mclass.name.html_escape
+               tpl.add lnk
                tpl.add "["
                for i in [0..arguments.length[ do
                        tpl.add arguments[i].tpl_signature
index 83c1842..53fc0cf 100644 (file)
@@ -16,6 +16,7 @@
 module html_templates
 
 import html_model
+import html::bootstrap
 
 # Renders the page as HTML.
 redef class DocPage
@@ -31,7 +32,7 @@ redef class DocPage
        var body_attrs = new Array[TagAttribute]
 
        # Top menu template if any.
-       var topmenu: TplTopMenu is writable, noinit
+       var topmenu: DocTopMenu is writable, noinit
 
        # Sidebar template if any.
        var sidebar: nullable TplSidebar = null is writable
@@ -74,13 +75,6 @@ redef class DocPage
                addn ">"
        end
 
-       # Renders the topmenu template.
-       private fun render_topmenu do
-               addn " <div class='row'>"
-               add topmenu
-               addn " </div>"
-       end
-
        # Renders the sidebar template.
        #
        # Sidebar is automatically populated with a summary of all sections
@@ -129,7 +123,9 @@ redef class DocPage
        redef fun rendering do
                render_head
                addn "<div class='container-fluid'>"
-               render_topmenu
+               addn " <div class='row'>"
+               add topmenu
+               addn " </div>"
                addn " <div class='row' id='content'>"
                if sidebar != null then
                        addn "<div class='col col-xs-3 col-lg-2'>"
@@ -148,3 +144,55 @@ redef class DocPage
                render_footer
        end
 end
+
+# Top menu bar template.
+#
+# FIXME should be a Bootstrap component template
+# At this moment, the topmenu structure stills to specific to Nitdoc to use the
+# generic component.
+class DocTopMenu
+       super UnorderedList
+
+       # Brand link to display in first position of the top menu.
+       #
+       # This is where you want to put your logo.
+       var brand: nullable Writable is noinit, writable
+
+       # Active menu item.
+       #
+       # Depends on the current page, this allows to hilighted the current item.
+       #
+       # FIXME should be using Boostrap breadcrumbs component.
+       # This will still like this to avoid diff and be changed in further fixes
+       # when we will modify the output.
+       var active_item: nullable ListItem is noinit, writable
+
+       redef fun rendering do
+               addn "<nav id='topmenu' class='navbar navbar-default navbar-fixed-top' role='navigation'>"
+               addn " <div class='container-fluid'>"
+               addn "  <div class='navbar-header'>"
+               add "   <button type='button' class='navbar-toggle' "
+               addn "       data-toggle='collapse' data-target='#topmenu-collapse'>"
+               addn "    <span class='sr-only'>Toggle menu</span>"
+               addn "    <span class='icon-bar'></span>"
+               addn "    <span class='icon-bar'></span>"
+               addn "    <span class='icon-bar'></span>"
+               addn "   </button>"
+               if brand != null then
+                       add "<span class='navbar-brand'>"
+                       add brand.write_to_string
+                       add "</span>"
+               end
+               addn "  </div>"
+               addn "  <div class='collapse navbar-collapse' id='topmenu-collapse'>"
+               addn "   <ul class='nav navbar-nav'>"
+               for item in items do
+                       if item == active_item then item.css_classes.add "active"
+                       add item.write_to_string
+               end
+               addn "   </ul>"
+               addn "  </div>"
+               addn " </div>"
+               addn "</nav>"
+       end
+end
index 3a64638..76a3839 100644 (file)
@@ -477,6 +477,9 @@ class MClass
        end
 
        private var get_mtype_cache = new HashMap[Array[MType], MGenericType]
+
+       # Is there a `new` factory to allow the pseudo instantiation?
+       var has_new_factory = false is writable
 end
 
 
index a4d1141..bb0184f 100644 (file)
@@ -735,6 +735,7 @@ redef class AMethPropdef
                        end
                        mprop.is_init = is_init
                        mprop.is_new = n_kwnew != null
+                       if mprop.is_new then mclassdef.mclass.has_new_factory = true
                        if parent isa ATopClassdef then mprop.is_toplevel = true
                        self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, mprop)
                else
index e2db002..2c9e706 100644 (file)
@@ -42,7 +42,7 @@ class AndroidPlatform
 
        redef fun supports_linker_script do return false
 
-       redef fun toolchain(toolcontext) do return new AndroidToolchain(toolcontext)
+       redef fun toolchain(toolcontext, compiler) do return new AndroidToolchain(toolcontext, compiler)
 end
 
 class AndroidToolchain
@@ -57,9 +57,9 @@ class AndroidToolchain
                return "{android_project_root}/jni/nit_compile/"
        end
 
-       redef fun default_outname(mainmodule) do return "{mainmodule.name}.apk"
+       redef fun default_outname do return "{super}.apk"
 
-       redef fun write_files(compiler, compile_dir, cfiles)
+       redef fun write_files(compile_dir, cfiles)
        do
                var android_project_root = android_project_root.as(not null)
                var project = toolcontext.modelbuilder.android_project_for(compiler.mainmodule)
@@ -107,7 +107,7 @@ class AndroidToolchain
                if not dir.file_exists then dir.mkdir
 
                # compile normal C files
-               super(compiler, compile_dir, cfiles)
+               super
 
                # Gather extra C files generated elsewhere than in super
                for f in compiler.extern_bodies do
@@ -311,12 +311,12 @@ $(call import-module,android/native_app_glue)
                end
        end
 
-       redef fun write_makefile(compiler, compile_dir, cfiles)
+       redef fun write_makefile(compile_dir, cfiles)
        do
                # Do nothing, already done in `write_files`
        end
 
-       redef fun compile_c_code(compiler, compile_dir)
+       redef fun compile_c_code(compile_dir)
        do
                var android_project_root = android_project_root.as(not null)
                var short_project_name = compiler.mainmodule.name.replace("-", "_")
index 3e9199a..90e361e 100644 (file)
@@ -35,17 +35,17 @@ class EmscriptenPlatform
        redef fun supports_libunwind do return false
        redef fun supports_libgc do return false
        redef fun supports_linker_script do return false
-       redef fun toolchain(toolcontext) do return new EnscriptenToolchain(toolcontext)
+       redef fun toolchain(toolcontext, compiler) do return new EnscriptenToolchain(toolcontext, compiler)
 end
 
 class EnscriptenToolchain
        super MakefileToolchain
 
-       redef fun makefile_name(mainmodule) do return "{mainmodule.name}.js.mk"
+       redef fun makefile_name do return "{super}.js.mk"
 
-       redef fun default_outname(mainmodule) do return "{super}.js"
+       redef fun default_outname do return "{super}.js"
 
-       redef fun write_makefile(compiler, compile_dir, cfiles)
+       redef fun write_makefile(compile_dir, cfiles)
        do
                super
 
diff --git a/src/platform/ios.nit b/src/platform/ios.nit
new file mode 100644 (file)
index 0000000..94d0c5f
--- /dev/null
@@ -0,0 +1,122 @@
+# 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.
+
+# Compile programs for the iOS platform
+module ios
+
+import platform
+import compiler::abstract_compiler
+import xcode_templates
+private import annotation
+
+redef class ToolContext
+       redef fun platform_from_name(name)
+       do
+               if name == "ios" then return new IOSPlatform
+               return super
+       end
+end
+
+private class IOSPlatform
+       super Platform
+
+       redef fun supports_libunwind do return false
+       redef fun supports_libgc do return false
+       redef fun toolchain(toolcontext, compiler) do return new IOSToolchain(toolcontext, compiler)
+end
+
+private class IOSToolchain
+       super MakefileToolchain
+
+       # Root of the iOS project, usually `.nit_compile/ios/`
+       var ios_project_root: String is noinit
+
+       redef fun default_outname do return "{super}.app"
+
+       # Name of the current project of `compiler`
+       fun project_name: String
+       do
+               var project_name = null
+               # TODO unite the app_name annotation from Android with iOS
+               var annot = compiler.modelbuilder.lookup_annotation_on_modules("app_name", compiler.mainmodule)
+               if annot != null then project_name = annot.arg_as_string(compiler.modelbuilder)
+               if project_name == null then project_name = compiler.mainmodule.name
+               return project_name
+       end
+
+       # Compile C files in `ios_project_root/project_name`
+       redef fun compile_dir
+       do
+               ios_project_root = super/"ios"
+               return ios_project_root/project_name
+       end
+
+       redef fun write_files(compile_dir, cfiles)
+       do
+               # Clear the project directory before writing anything
+               if ios_project_root.file_exists then ios_project_root.rmdir
+               compile_dir.mkdir
+
+               super
+       end
+
+       redef fun write_makefile(compile_dir, cfiles)
+       do
+               var project_name = project_name
+
+               # Create an XCode project directory
+               var dir = ios_project_root/project_name+".xcodeproj"
+               if not dir.file_exists then dir.mkdir
+
+               # Create a PBX project file
+               var pbx = new PbxprojectTemplate(project_name)
+
+               ## Register all source files
+               for file in cfiles do pbx.add_file new PbxFile(file)
+               for file in compiler.extern_bodies do
+                       pbx.add_file new PbxFile(file.filename.basename(""))
+               end
+
+               ## TODO Register asset files
+
+               pbx.write_to_file dir/"project.pbxproj"
+
+               # Create the plist in the same directory as the generated C code
+               if not compile_dir.file_exists then compile_dir.mkdir
+               var plist = new PlistTemplate("org.nitlanguage") # TODO customize using an annotation
+               plist.write_to_file compile_dir/"Info.plist"
+       end
+
+       redef fun compile_c_code(compile_dir)
+       do
+               var project_name = project_name
+               var release = toolcontext.opt_release.value
+               var outfile = outfile(compiler.mainmodule)
+
+               # Compile with `xcodebuild`
+               #
+               # TODO support more than the iPhone and the simulator.
+               var args = ["sh", "-c", "cd {ios_project_root}; " +
+                       "xcodebuild -target '{project_name}' " +
+                       "-destination 'platform=iOS Simulator,name=iPhone' " +
+                       "-configuration {if release then "Release" else "Debug"} " +
+                       "-sdk iphonesimulator build"]
+               toolcontext.exec_and_check(args, "iOS project error")
+
+               # Move compiled app to destination
+               if outfile.file_exists then outfile.rmdir
+               args = ["mv", "{ios_project_root}/build/Debug-iphonesimulator/{project_name}.app", outfile]
+               toolcontext.exec_and_check(args, "iOS project error")
+       end
+end
index d7103db..8136187 100644 (file)
@@ -37,13 +37,13 @@ class PnaclPlatform
 
        redef fun no_main do return true
 
-       redef fun toolchain(toolcontext) do return new PnaclToolchain(toolcontext)
+       redef fun toolchain(toolcontext, compiler) do return new PnaclToolchain(toolcontext, compiler)
 end
 
 class PnaclToolchain
        super MakefileToolchain
 
-       redef fun write_files(compiler, compile_dir, cfiles)
+       redef fun write_files(compile_dir, cfiles)
        do
                var app_name = compiler.mainmodule.name
 
@@ -52,7 +52,7 @@ class PnaclToolchain
                if not dir.file_exists then dir.mkdir
 
                # compile normal C files
-               super(compiler, compile_dir, cfiles)
+               super
 
                # Gather extra C files generated elsewhere than in super
                for f in compiler.extern_bodies do
@@ -238,12 +238,12 @@ function updateStatus(opt_message) {
                """.write_to_file(file)
        end
 
-       redef fun write_makefile(compiler, compile_dir, cfiles)
+       redef fun write_makefile(compile_dir, cfiles)
        do
                # Do nothing, already done in `write_files`
        end
 
-       redef fun compile_c_code(compiler, compile_dir)
+       redef fun compile_c_code(compile_dir)
        do
                # Generate the pexe
                toolcontext.exec_and_check(["make", "-C", compile_dir, "-j", "4"], "PNaCl project error")
diff --git a/src/platform/xcode_templates.nit b/src/platform/xcode_templates.nit
new file mode 100644 (file)
index 0000000..de9d500
--- /dev/null
@@ -0,0 +1,681 @@
+# 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.
+
+# Templates and other services to create XCode projects
+module xcode_templates
+
+import template
+
+import platform
+import compiler::abstract_compiler
+
+redef class Sys
+       # Map to identify the PBX file type for a given file extension
+       private var pbx_file_types: Map[String, String] is lazy do
+               var map = new HashMap[String, String]
+
+               # Source code
+               map["m"] =                      "sourcecode.c.objc"
+               map["c"] =                      "sourcecode.c.c"
+               map["h"] =                      "sourcecode.c.h"
+               map["cpp"] =            "sourcecode.cpp.cpp"
+               map["hpp"] =            "sourcecode.cpp.h"
+               map["vsh"] =            "sourcecode.glsl"
+               map["fsh"] =            "sourcecode.glsl"
+
+               # Images
+               map["png"] =            "image.png"
+               map["gif"] =            "image.gif"
+               map["jpg"] =            "image.jpeg"
+               map["jpeg"] =           "image.jpeg"
+               map["pdf"] =            "image.pdf"
+               map["ico"] =            "image.ico"
+
+               # Others
+               map["app"] =            "wrapper.application"
+               map["plist"] =          "text.plist.xml"
+               map["storyboard"] =     "file.storyboard"
+               map["xib"] =            "file.xib"
+               map["xcassets"] =       "folder.assetcatalog"
+               map["xctest"] =         "wrapper.cfbundle"
+
+               return map
+       end
+
+       # Generator of PBX UUIDs quique to an execution of the compiler
+       private var pbx_uuid_generator = new PbxUUIDGenerator is lazy
+end
+
+# Generator of PBX UUIDs
+#
+# PBX UUID are composed of 24 hex characters.
+# They only need to be unique within the same project.
+#
+# This implementation simply counts upward from 0.
+class PbxUUIDGenerator
+       private var seed = 0
+
+       # Generate a new UUID
+       fun next_uuid: String
+       do
+               seed += 1
+
+               var hex_val = seed.to_hex.to_upper
+               return "0"*(24-hex_val.length) + hex_val
+       end
+end
+
+# Reference to a file for the PBX format of a project file
+#
+# TODO create subclasses for different file types, this is currently for
+# compilable source files only.
+class PbxFile
+
+       # Path to `self`
+       var path: String
+
+       # UUID for build elements
+       private var build_uuid: String = sys.pbx_uuid_generator.next_uuid is lazy
+
+       # File reference UUID
+       private var ref_uuid: String = sys.pbx_uuid_generator.next_uuid is lazy
+
+       # Documentation to add besides this file in the template
+       private fun doc: String do return path
+
+       # PBX file type for `self`
+       fun file_type: String
+       do
+               var map = sys.pbx_file_types
+               var ext = path.file_extension
+               if ext != null and map.keys.has(ext) then return map[ext]
+               return "unknown"
+       end
+
+       # PBX description of this file
+       private fun description: Writable do return """
+               {{{ref_uuid}}} /* {{{doc}}} */ = {
+                       isa = PBXFileReference;
+                       fileEncoding = 4;
+                       lastKnownFileType = {{{file_type}}};
+                       path = {{{path}}};
+                       sourceTree = "<group>";
+                       };
+"""
+
+       private fun add_to_project(project: PbxprojectTemplate)
+       do
+               project.source_files.add self
+               project.files.add self
+       end
+end
+
+# Template for a PBX project file, usually a `project.pbcproj`
+#
+# This file list all information required to build an XCode project.
+# It would usually be written and read by XCode.
+# From the command line, xcodebuild can read this file but not write it.
+#
+# Information in the file (simplified list):
+#
+# * Compilable source files
+# * Asset files
+# * Build configurations (Release and debug modes, cflags, etc.)
+# * List of files composing the project
+class PbxprojectTemplate
+       super Template
+
+       # Name of the project
+       var name: String
+
+       # All body/implementation source files to be compiled
+       private var source_files = new Array[PbxFile]
+
+       # All asset files added to the app package
+       private var asset_files = new Array[PbxFile]
+
+       # All files used by this project
+       private var files = new Array[PbxFile]
+
+       # Add `file` to this project
+       fun add_file(file: PbxFile) do file.add_to_project(self)
+
+       redef fun rendering
+       do
+               add """
+// !$*UTF8*$!
+{
+       archiveVersion = 1;
+       classes = {
+       };
+       objectVersion = 46;
+       objects = {
+
+/* Begin PBXBuildFile section */
+"""
+
+               # List build files (compilable sources and assets) with their reference UUID
+               for array in [source_files, asset_files] do for file in array do add """
+               {{{file.build_uuid}}} /* {{{file.doc}}} */ = {
+                       isa = PBXBuildFile;
+                       fileRef = {{{file.ref_uuid}}} /* {{{file.doc}}} */;
+                       };
+"""
+
+               add """
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+               AF9F83EA1A5F0D21004B62C0 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = AF9F83C41A5F0D21004B62C0 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = AF9F83CB1A5F0D21004B62C0;
+                       remoteInfo = {{{name}}};
+               };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+       /* Static generated files */
+               AF9F83CC1A5F0D21004B62C0 /* {{{name}}}.app */ = {
+                       isa = PBXFileReference;
+                       explicitFileType = wrapper.application;
+                       includeInIndex = 0;
+                       path = {{{name}}}.app;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+                       };
+               AF9F83D01A5F0D21004B62C0 /* Info.plist */ = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.plist.xml;
+                       path = Info.plist;
+                       sourceTree = "<group>";
+                       };
+               AF9F83DE1A5F0D21004B62C0 /* Base */ = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = file.storyboard;
+                       name = Base;
+                       path = Base.lproj/Main.storyboard;
+                       sourceTree = "<group>";
+                       };
+               AF9F83E01A5F0D21004B62C0 /* Images.xcassets */ = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = folder.assetcatalog;
+                       path = Images.xcassets;
+                       sourceTree = "<group>";
+                       };
+               AF9F83E31A5F0D21004B62C0 /* Base */ = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = file.xib;
+                       name = Base;
+                       path = Base.lproj/LaunchScreen.xib;
+                       sourceTree = "<group>";
+                       };
+               AF9F83E91A5F0D21004B62C0 /* {{{name}}}Tests.xctest */ = {
+                       isa = PBXFileReference;
+                       explicitFileType = wrapper.cfbundle;
+                       includeInIndex = 0;
+                       path = {{{name}}}Tests.xctest;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+                       };
+               AF9F83EE1A5F0D21004B62C0 /* Info.plist */ = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.plist.xml;
+                       path = Info.plist;
+                       sourceTree = "<group>";
+                       };
+               AF9F83EF1A5F0D21004B62C0 /* {{{name}}}Tests.m */ = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = {{{name}}}Tests.m;
+                       sourceTree = "<group>";
+                       };
+
+       /* Changing generated files */
+"""
+               # Describe all known files
+               for file in files do add file.description
+
+               add """
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+               AF9F83C91A5F0D21004B62C0 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               AF9F83E61A5F0D21004B62C0 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+               AF9F83C31A5F0D21004B62C0 = {
+                       isa = PBXGroup;
+                       children = (
+                               AF9F83CE1A5F0D21004B62C0 /* {{{name}}} */,
+                               AF9F83EC1A5F0D21004B62C0 /* {{{name}}}Tests */,
+                               AF9F83CD1A5F0D21004B62C0 /* Products */,
+                       );
+                       sourceTree = "<group>";
+               };
+               AF9F83CD1A5F0D21004B62C0 /* Products */ = {
+                       isa = PBXGroup;
+                       children = (
+                               AF9F83CC1A5F0D21004B62C0 /* {{{name}}}.app */,
+                               AF9F83E91A5F0D21004B62C0 /* {{{name}}}Tests.xctest */,
+                       );
+                       name = Products;
+                       sourceTree = "<group>";
+               };
+               AF9F83CE1A5F0D21004B62C0 /* {{{name}}} */ = {
+                       isa = PBXGroup;
+                       children = (
+"""
+                       # Reference all known files
+                       for file in files do add """
+                               {{{file.ref_uuid}}} /* {{{file.doc}}} */,
+"""
+
+               add """
+                       );
+                       path = {{{name}}};
+                       sourceTree = "<group>";
+               };
+               AF9F83CF1A5F0D21004B62C0 /* Supporting Files */ = {
+                       isa = PBXGroup;
+                       children = (
+                               AF9F83D01A5F0D21004B62C0 /* Info.plist */,
+                               AF9F83D11A5F0D21004B62C0 /* main.m */,
+                       );
+                       name = "Supporting Files";
+                       sourceTree = "<group>";
+               };
+               AF9F83EC1A5F0D21004B62C0 /* {{{name}}}Tests */ = {
+                       isa = PBXGroup;
+                       children = (
+                               AF9F83EF1A5F0D21004B62C0 /* {{{name}}}Tests.m */,
+                               AF9F83ED1A5F0D21004B62C0 /* Supporting Files */,
+                       );
+                       path = {{{name}}}Tests;
+                       sourceTree = "<group>";
+               };
+               AF9F83ED1A5F0D21004B62C0 /* Supporting Files */ = {
+                       isa = PBXGroup;
+                       children = (
+                               AF9F83EE1A5F0D21004B62C0 /* Info.plist */,
+                       );
+                       name = "Supporting Files";
+                       sourceTree = "<group>";
+               };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+               AF9F83CB1A5F0D21004B62C0 /* {{{name}}} */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = AF9F83F31A5F0D21004B62C0 /* Build configuration list for PBXNativeTarget "{{{name}}}" */;
+                       buildPhases = (
+                               AF9F83C81A5F0D21004B62C0 /* Sources */,
+                               AF9F83C91A5F0D21004B62C0 /* Frameworks */,
+                               AF9F83CA1A5F0D21004B62C0 /* Resources */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = {{{name}}};
+                       productName = {{{name}}};
+                       productReference = AF9F83CC1A5F0D21004B62C0 /* {{{name}}}.app */;
+                       productType = "com.apple.product-type.application";
+               };
+               AF9F83E81A5F0D21004B62C0 /* {{{name}}}Tests */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = AF9F83F61A5F0D21004B62C0 /* Build configuration list for PBXNativeTarget "{{{name}}}Tests" */;
+                       buildPhases = (
+                               AF9F83E51A5F0D21004B62C0 /* Sources */,
+                               AF9F83E61A5F0D21004B62C0 /* Frameworks */,
+                               AF9F83E71A5F0D21004B62C0 /* Resources */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                               AF9F83EB1A5F0D21004B62C0 /* PBXTargetDependency */,
+                       );
+                       name = {{{name}}}Tests;
+                       productName = {{{name}}}Tests;
+                       productReference = AF9F83E91A5F0D21004B62C0 /* {{{name}}}Tests.xctest */;
+                       productType = "com.apple.product-type.bundle.unit-test";
+               };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+               AF9F83C41A5F0D21004B62C0 /* Project object */ = {
+                       isa = PBXProject;
+                       attributes = {
+                               LastUpgradeCheck = 0610;
+                               TargetAttributes = {
+                                       AF9F83CB1A5F0D21004B62C0 = {
+                                               CreatedOnToolsVersion = 6.1.1;
+                                       };
+                                       AF9F83E81A5F0D21004B62C0 = {
+                                               CreatedOnToolsVersion = 6.1.1;
+                                               TestTargetID = AF9F83CB1A5F0D21004B62C0;
+                                       };
+                               };
+                       };
+                       buildConfigurationList = AF9F83C71A5F0D21004B62C0 /* Build configuration list for PBXProject "{{{name}}}" */;
+                       compatibilityVersion = "Xcode 3.2";
+                       developmentRegion = English;
+                       hasScannedForEncodings = 0;
+                       knownRegions = (
+                               en,
+                               Base,
+                       );
+                       mainGroup = AF9F83C31A5F0D21004B62C0;
+                       productRefGroup = AF9F83CD1A5F0D21004B62C0 /* Products */;
+                       projectDirPath = "";
+                       projectRoot = "";
+                       targets = (
+                               AF9F83CB1A5F0D21004B62C0 /* {{{name}}} */,
+                               AF9F83E81A5F0D21004B62C0 /* {{{name}}}Tests */,
+                       );
+               };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+               AF9F83CA1A5F0D21004B62C0 /* Resources */ = {
+                       isa = PBXResourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+"""
+               # Reference all asset files by their build UUID
+               for file in asset_files do add """
+                               {{{file.build_uuid}}} /* {{{file.doc}}} */,
+"""
+
+               add """
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               AF9F83E71A5F0D21004B62C0 /* Resources */ = {
+                       isa = PBXResourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+               AF9F83C81A5F0D21004B62C0 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+"""
+               # Reference all compilable source files by their build UUID
+               for file in source_files do add """
+                               {{{file.build_uuid}}} /* {{{file.doc}}} */,
+"""
+               add """
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               AF9F83E51A5F0D21004B62C0 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               AF9F83F01A5F0D21004B62C0 /* {{{name}}}Tests.m in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+               AF9F83EB1A5F0D21004B62C0 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = AF9F83CB1A5F0D21004B62C0 /* {{{name}}} */;
+                       targetProxy = AF9F83EA1A5F0D21004B62C0 /* PBXContainerItemProxy */;
+               };
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+               AF9F83DD1A5F0D21004B62C0 /* Main.storyboard */ = {
+                       isa = PBXVariantGroup;
+                       children = (
+                               AF9F83DE1A5F0D21004B62C0 /* Base */,
+                       );
+                       name = Main.storyboard;
+                       sourceTree = "<group>";
+               };
+               AF9F83E21A5F0D21004B62C0 /* LaunchScreen.xib */ = {
+                       isa = PBXVariantGroup;
+                       children = (
+                               AF9F83E31A5F0D21004B62C0 /* Base */,
+                       );
+                       name = LaunchScreen.xib;
+                       sourceTree = "<group>";
+               };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+               AF9F83F11A5F0D21004B62C0 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+                               CLANG_CXX_LIBRARY = "libc++";
+                               CLANG_ENABLE_MODULES = YES;
+                               CLANG_ENABLE_OBJC_ARC = YES;
+                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+                               "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+                               COPY_PHASE_STRIP = NO;
+                               ENABLE_STRICT_OBJC_MSGSEND = YES;
+                               GCC_C_LANGUAGE_STANDARD = gnu99;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "DEBUG=1",
+                                       "$(inherited)",
+                               );
+                               GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+                               GCC_WARN_UNDECLARED_SELECTOR = YES;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+                               IPHONEOS_DEPLOYMENT_TARGET = 8.1;
+                               MTL_ENABLE_DEBUG_INFO = YES;
+                               ONLY_ACTIVE_ARCH = YES;
+                               SDKROOT = iphoneos;
+                               TARGETED_DEVICE_FAMILY = "1,2";
+                       };
+                       name = Debug;
+               };
+               AF9F83F21A5F0D21004B62C0 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+                               CLANG_CXX_LIBRARY = "libc++";
+                               CLANG_ENABLE_MODULES = YES;
+                               CLANG_ENABLE_OBJC_ARC = YES;
+                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+                               "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+                               COPY_PHASE_STRIP = YES;
+                               ENABLE_NS_ASSERTIONS = NO;
+                               ENABLE_STRICT_OBJC_MSGSEND = YES;
+                               GCC_C_LANGUAGE_STANDARD = gnu99;
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+                               GCC_WARN_UNDECLARED_SELECTOR = YES;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+                               IPHONEOS_DEPLOYMENT_TARGET = 8.1;
+                               MTL_ENABLE_DEBUG_INFO = NO;
+                               SDKROOT = iphoneos;
+                               TARGETED_DEVICE_FAMILY = "1,2";
+                               VALIDATE_PRODUCT = YES;
+                       };
+                       name = Release;
+               };
+               AF9F83F41A5F0D21004B62C0 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+                               INFOPLIST_FILE = {{{name}}}/Info.plist;
+                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                       };
+                       name = Debug;
+               };
+               AF9F83F51A5F0D21004B62C0 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+                               INFOPLIST_FILE = {{{name}}}/Info.plist;
+                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                       };
+                       name = Release;
+               };
+               AF9F83F71A5F0D21004B62C0 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               BUNDLE_LOADER = "$(TEST_HOST)";
+                               FRAMEWORK_SEARCH_PATHS = (
+                                       "$(SDKROOT)/Developer/Library/Frameworks",
+                                       "$(inherited)",
+                               );
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "DEBUG=1",
+                                       "$(inherited)",
+                               );
+                               INFOPLIST_FILE = {{{name}}}Tests/Info.plist;
+                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                               TEST_HOST = "$(BUILT_PRODUCTS_DIR)/{{{name}}}.app/{{{name}}}";
+                       };
+                       name = Debug;
+               };
+               AF9F83F81A5F0D21004B62C0 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               BUNDLE_LOADER = "$(TEST_HOST)";
+                               FRAMEWORK_SEARCH_PATHS = (
+                                       "$(SDKROOT)/Developer/Library/Frameworks",
+                                       "$(inherited)",
+                               );
+                               INFOPLIST_FILE = {{{name}}}Tests/Info.plist;
+                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                               TEST_HOST = "$(BUILT_PRODUCTS_DIR)/{{{name}}}.app/{{{name}}}";
+                       };
+                       name = Release;
+               };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+               AF9F83C71A5F0D21004B62C0 /* Build configuration list for PBXProject "{{{name}}}" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               AF9F83F11A5F0D21004B62C0 /* Debug */,
+                               AF9F83F21A5F0D21004B62C0 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+               AF9F83F31A5F0D21004B62C0 /* Build configuration list for PBXNativeTarget "{{{name}}}" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               AF9F83F41A5F0D21004B62C0 /* Debug */,
+                               AF9F83F51A5F0D21004B62C0 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+               };
+               AF9F83F61A5F0D21004B62C0 /* Build configuration list for PBXNativeTarget "{{{name}}}Tests" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               AF9F83F71A5F0D21004B62C0 /* Debug */,
+                               AF9F83F81A5F0D21004B62C0 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+               };
+/* End XCConfigurationList section */
+       };
+       rootObject = AF9F83C41A5F0D21004B62C0 /* Project object */;
+}
+"""
+       end
+end
+
+# Template for a property list used by XCode for iOS projects
+class PlistTemplate
+       super Template
+
+       # Package of the app
+       var package_name: String
+
+       redef fun rendering
+       do
+               add """
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>en</string>
+       <key>CFBundleExecutable</key>
+       <string>$(EXECUTABLE_NAME)</string>
+       <key>CFBundleIdentifier</key>
+       <string>{{{package_name}}}.$(PRODUCT_NAME:rfc1034identifier)</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>$(PRODUCT_NAME)</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string>1.0</string>
+       <key>CFBundleSignature</key>
+       <string>\\?\\?\\?\\?</string>
+       <key>CFBundleVersion</key>
+       <string>1</string>
+       <key>LSRequiresIPhoneOS</key>
+       <true/>
+       <key>UIRequiredDeviceCapabilities</key>
+       <array>
+               <string>armv7</string>
+       </array>
+       <key>UISupportedInterfaceOrientations</key>
+       <array>
+               <string>UIInterfaceOrientationPortrait</string>
+               <string>UIInterfaceOrientationLandscapeLeft</string>
+               <string>UIInterfaceOrientationLandscapeRight</string>
+       </array>
+       <key>UISupportedInterfaceOrientations~ipad</key>
+       <array>
+               <string>UIInterfaceOrientationPortrait</string>
+               <string>UIInterfaceOrientationPortraitUpsideDown</string>
+               <string>UIInterfaceOrientationLandscapeLeft</string>
+               <string>UIInterfaceOrientationLandscapeRight</string>
+       </array>
+</dict>
+</plist>
+"""
+       end
+end
index 609105e..8a90f1d 100644 (file)
@@ -1,3 +1,5 @@
 cocoa_extern_types
 cocoa_message_box
 hello_cocoa
+hello_ios
+test_platform_ios
index 36503ed..3e3247e 100644 (file)
@@ -475,7 +475,7 @@ Start ../src/test_parser.nit:17,1--147,1
                 AParExprs ../src/test_parser.nit:71,7--36
                   TOpar "(" ../src/test_parser.nit:71,7
                   AStringExpr ../src/test_parser.nit:71,8--35
-                    TString "\"  -n\11do not print anything\"" ../src/test_parser.nit:71,8--35
+                    TString "\"  -n\tdo not print anything\"" ../src/test_parser.nit:71,8--35
                   TCpar ")" ../src/test_parser.nit:71,36
               ACallExpr ../src/test_parser.nit:72,2--25
                 AImplicitSelfExpr ../src/test_parser.nit:72,2
@@ -483,7 +483,7 @@ Start ../src/test_parser.nit:17,1--147,1
                 AParExprs ../src/test_parser.nit:72,7--25
                   TOpar "(" ../src/test_parser.nit:72,7
                   AStringExpr ../src/test_parser.nit:72,8--24
-                    TString "\"  -l\11only lexer\"" ../src/test_parser.nit:72,8--24
+                    TString "\"  -l\tonly lexer\"" ../src/test_parser.nit:72,8--24
                   TCpar ")" ../src/test_parser.nit:72,25
               ACallExpr ../src/test_parser.nit:73,2--41
                 AImplicitSelfExpr ../src/test_parser.nit:73,2
@@ -491,7 +491,7 @@ Start ../src/test_parser.nit:17,1--147,1
                 AParExprs ../src/test_parser.nit:73,7--41
                   TOpar "(" ../src/test_parser.nit:73,7
                   AStringExpr ../src/test_parser.nit:73,8--40
-                    TString "\"  -p\11lexer and parser (default)\"" ../src/test_parser.nit:73,8--40
+                    TString "\"  -p\tlexer and parser (default)\"" ../src/test_parser.nit:73,8--40
                   TCpar ")" ../src/test_parser.nit:73,41
               ACallExpr ../src/test_parser.nit:74,2--68
                 AImplicitSelfExpr ../src/test_parser.nit:74,2
@@ -499,7 +499,7 @@ Start ../src/test_parser.nit:17,1--147,1
                 AParExprs ../src/test_parser.nit:74,7--68
                   TOpar "(" ../src/test_parser.nit:74,7
                   AStringExpr ../src/test_parser.nit:74,8--67
-                    TString "\"  -e\11instead on files, each argument is a content to parse\"" ../src/test_parser.nit:74,8--67
+                    TString "\"  -e\tinstead on files, each argument is a content to parse\"" ../src/test_parser.nit:74,8--67
                   TCpar ")" ../src/test_parser.nit:74,68
               ACallExpr ../src/test_parser.nit:75,2--51
                 AImplicitSelfExpr ../src/test_parser.nit:75,2
@@ -507,7 +507,7 @@ Start ../src/test_parser.nit:17,1--147,1
                 AParExprs ../src/test_parser.nit:75,7--51
                   TOpar "(" ../src/test_parser.nit:75,7
                   AStringExpr ../src/test_parser.nit:75,8--50
-                    TString "\"  -i\11tree to parse are read interactively\"" ../src/test_parser.nit:75,8--50
+                    TString "\"  -i\ttree to parse are read interactively\"" ../src/test_parser.nit:75,8--50
                   TCpar ")" ../src/test_parser.nit:75,51
               ACallExpr ../src/test_parser.nit:76,2--30
                 AImplicitSelfExpr ../src/test_parser.nit:76,2
@@ -515,7 +515,7 @@ Start ../src/test_parser.nit:17,1--147,1
                 AParExprs ../src/test_parser.nit:76,7--30
                   TOpar "(" ../src/test_parser.nit:76,7
                   AStringExpr ../src/test_parser.nit:76,8--29
-                    TString "\"  -h\11print this help\"" ../src/test_parser.nit:76,8--29
+                    TString "\"  -h\tprint this help\"" ../src/test_parser.nit:76,8--29
                   TCpar ")" ../src/test_parser.nit:76,30
             AIfExpr ../src/test_parser.nit:77,6--146,3
               TKwif "if" ../src/test_parser.nit:77,6--7
diff --git a/tests/test_platform_ios.nit b/tests/test_platform_ios.nit
new file mode 100644 (file)
index 0000000..b49f379
--- /dev/null
@@ -0,0 +1,15 @@
+# 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 ios