From: Jean Privat Date: Thu, 2 Apr 2015 04:10:22 +0000 (+0700) Subject: Merge: Improve loader X-Git-Tag: v0.7.4~47 X-Git-Url: http://nitlanguage.org?hp=4d8c87e3218b35f353992ad6e25da36ab724040c Merge: Improve loader This PR improves the loader that can now accepts * directories of projects: to load all modules of all projects (eg `contrib`) * root directories of groups: to load all modules of the groups (eg `contrib/benitlux`). Previously, this worked if there was no `src` subdirectory) This works for tools that rely on full_parse (basically all tools except the engines). ~~~sh $ ./test_test_phase ../lib -q It works I have 89 projects I have 285 modules I have 1038 classes For 1366 definitions of classes I have 7101 methods For 9098 definitions of methods ~~~ Note that if any files has an error most tools will just stop. Pull-Request: #1229 Reviewed-by: Alexandre Terrasa Reviewed-by: Alexis Laferrière --- diff --git a/VERSION b/VERSION index 2c0a9c7..3d105a6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v0.7.2 +v0.7.3 diff --git a/benchmarks/markdown/bench_markdown.sh b/benchmarks/markdown/bench_markdown.sh index 4cb0f15..be58d55 100755 --- a/benchmarks/markdown/bench_markdown.sh +++ b/benchmarks/markdown/bench_markdown.sh @@ -74,7 +74,7 @@ engdir="./engines" bncdir="./benches/out" mkdir -p $outdir -s=50 +s=200 function bench_nitmd() { @@ -88,6 +88,18 @@ function bench_nitmd() } bench_nitmd +function bench_nitmd-o() +{ + name="$FUNCNAME" + skip_test "$name" && return + prepare_res $outdir/nitmd-o.dat "nitmd-o" "nitmd-o" + for file in $bncdir/*.md; do + bench=`basename $file .md` + bench_command "$bench" "" "$engdir/nitmd/nitmd-o" "$file" "$s" + done +} +bench_nitmd-o + function bench_txtmark() { name="$FUNCNAME" diff --git a/benchmarks/markdown/engines/nitmd/Makefile b/benchmarks/markdown/engines/nitmd/Makefile index aa79fbc..6424382 100644 --- a/benchmarks/markdown/engines/nitmd/Makefile +++ b/benchmarks/markdown/engines/nitmd/Makefile @@ -14,11 +14,17 @@ # 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 diff --git a/lib/geometry/points_and_lines.nit b/lib/geometry/points_and_lines.nit index 14a67fb..303aae1 100644 --- a/lib/geometry/points_and_lines.nit +++ b/lib/geometry/points_and_lines.nit @@ -55,9 +55,13 @@ end # An abstract 2d line segment interface ILine[N: Numeric] + # The type of points that ends the segment type P: IPoint[N] + # The point that is the left-end of the segment fun point_left: P is abstract + + # The point that is the right-end of the segment fun point_right: P is abstract redef fun to_s do return "{point_left}--{point_right}" diff --git a/lib/html/bootstrap.nit b/lib/html/bootstrap.nit new file mode 100644 index 0000000..66befa3 --- /dev/null +++ b/lib/html/bootstrap.nit @@ -0,0 +1,466 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# HTML templates for Bootstrap components. +# +# See http://getbootstrap.com/components/ +module bootstrap + +import template + +# Bootstrap component abstraction. +# +# Mainly used to factoryze CSS treatments. +# Can be used in the future to handle generic stuff like attributes or escaping. +# +# TODO merge with html::HTMTag without init conflict? +# HTMLTag requires the main init to pass a tagname, +# this was so much verbose here. +abstract class BSComponent + super Template + + # CSS classes to add on this element. + var css_classes = new Array[String] + + # Render `self` css clases as a `class` attribute. + fun render_css_classes: String do + if css_classes.is_empty then return "" + return " class=\"{css_classes.join(" ")}\"" + end +end + +# A `` 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 == "Nit" +# ~~~ +# +# Creates a link with a title attribute: +# ~~~ +# lnk = new Link.with_title("http://nitlanguage.org", "Nit", "Nit homepage") +# assert lnk.write_to_string == "Nit" +# ~~~ +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 "{text}" + end +end + +# A `

` to `

` 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 == "

Title

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