bncdir="./benches/out"
mkdir -p $outdir
-s=50
+s=200
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"
# 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
# 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}"
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# 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\">×</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
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# 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
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Simple 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
--- /dev/null
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# iOS services for Nit app on iOS
+module ios
+
+import platform
+import app
--- /dev/null
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Triggers compilation for the iOS platform
+module platform is platform "ios"
# 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
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
# 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]
// cmd exited on SIGINT: in my opinion the user wants the main to be discontinued
kill(getpid(), SIGINT);
}
+ return status;
}
# 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
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
end
end
+ # Creates a new File stream from a file descriptor
init from_fd(fd: Int) do
self.path = ""
prepare_buffer(1)
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
#
# 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
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
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
# Short name
var name: String
- init(name: String) do self.name = name
-
redef fun rendering do add "- {name}\n"
end
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}}}
import c_tools
private import annotation
import mixin
+import counter
# Add compiling options
redef class ToolContext
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
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
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)
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
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
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
# 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)
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 = ""
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>")
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
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
# 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.
#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
#
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
import platform::android
import platform::pnacl
import platform::emscripten
+import platform::ios
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
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)
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")
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
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
# 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)
#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]
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
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 */")
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("\}")
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
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
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
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
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 */")
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("\}")
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
#
# Shortcut for `children.add`.
fun add_child(child: DocComposite) do
+ child.parent = self
children.add child
end
end
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
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
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
# 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
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.
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.
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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)
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
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
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)
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
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
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
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.
# 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
# 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
# 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
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
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
var title = new Template
title.add tpl_icon
title.add tpl_link
- title.add tpl_signature
return title
end
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 "]"
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
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
var title = new Template
title.add tpl_icon
title.add tpl_link
- title.add tpl_signature
return title
end
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
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
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
module html_templates
import html_model
+import html::bootstrap
# Renders the page as HTML.
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
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
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'>"
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
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
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
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
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)
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
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("-", "_")
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
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org )
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# 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
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
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
""".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")
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# 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
cocoa_extern_types
cocoa_message_box
hello_cocoa
+hello_ios
+test_platform_ios
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
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
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
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
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
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
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import ios