This introduce a new colorer, `POSetGroupColorer` that colors elements introduced by the classes in a class-hierarchy.
The advantage of this new colorer is that it uses conflict graphs of classes to colorize elements.
By comparison, the previously used colorers work with conflict graphs of elements; that are therefore much larger.
An other advantage is that only the introductions of elements are needed by the colorer, so filling the information from the model is far more easier.
The construction of the poset of types is also removed.
Instead, subtyping tables are computed with a more standard way:
* target cast types are grouped by classes: a map class->types is created
* the map is colored: a table layout by class is computed
* for each live type, the table layout of the associated class is used to build the type table
Results are so good that most of the time of the coloring is removed.
For nitc/nitc/nit
Before:
user: 0m6.044s
total: 15096 MIr
do_property_coloring: 1420 MIr
do_type_coloring: 2600 MIr
After:
user: 0m5.608s (-7%)
total: 12800 MIr (-15%)
do_property_coloring: 452 MIr (-68%)
do_type_coloring: 895 MIr (-65%)
note that in the previous numbers, most of the time is done in the model to inherit or resolve things.
Pure coloring algorithm is now negligible:
conflict_graph: 34 MIr (<1% of the total Ir)
coloring: 60 MIr (<1% of the total Ir)
Unfortunately, with types the coloring can degenerate and produce big tables. If this is an issue, the options `--type-poset` use the previous coloring method for types
Pull-Request: #1215
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>
Reviewed-by: Lucas Bajolet <r4pass@hotmail.com>
Reviewed-by: Romain Chanoir <chanoir.romain@courrier.uqam.ca>
Reviewed-by: Alexis Laferrière <alexis.laf@xymus.net>
{
local title=$1
shift
- if test -n "$fast"; then
+ if test "$fast" = truetrue; then
+ run_command "$@" ../examples/hello_world.nit -o "hello.$title.bin"
+ bench_command "hello" "hello_world" "./hello.$title.bin"
+ elif test -n "$fast"; then
run_command "$@" ../src/nitc.nit -o "nitc.$title.bin"
bench_command "nitc-g" "nitc --global ../src/test_parser.nit" "./nitc.$title.bin" -v --global --no-cc ../src/test_parser.nit
run_command "$@" ../src/nit.nit -o "nit.$title.bin"
bench_command "nitmd" "markdown" "./nitmd.$title.bin" markdown/benches/out/mixed.md 80
fi
- rm -r *.bin .nit_compile out
+ rm -r *.bin .nit_compile out 2> /dev/null
}
## HANDLE OPTIONS ##
-h) usage; exit;;
-n) count="$2"; shift; shift;;
--dry) dry_run=true; shift;;
- --fast) fast=true; shift;;
+ --fast) fast=true$fast; shift;;
--html) html="index.html"; echo >"$html" "<html><head></head><body>"; shift;;
*) stop=true
esac
}
bench_steps
-# $#: options to compare
-function bench_nitc-g_options()
+# Simple script to compare various options on nitc
+#
+# usage: *name* *common* [NOALL] *options*...
+#
+# * *name*, the name of the bench
+# * *common*, options to use on each case
+# * NOALL, optional flag to avoid a last case including all additional options
+# * *options*, sequences of options, one for each case
+#
+# Example: `bench_nitc_options "foo" "-a -b" -c "-d -e"` generates 4 cases:
+#
+# * only *common*: `nitc -a -b`
+# * *common* and first *options*: `nitc -a -b -c`
+# * *common* and second *options*: `nitc -a -b -d -e`
+# * all: *common* and all *options*: `nitc -a -b -c -d -e`
+function bench_nitc_options()
{
tag=$1
shift
- name="$FUNCNAME-$tag"
+ common=$1
+ shift
+ name="$FUNCNAME-$tag$common"
+ name=${name// /}
skip_test "$name" && return
- prepare_res "$name.dat" "no options" "nitc-g without options"
- run_compiler "nitc-g" ./nitc --global
+ prepare_res "$name.dat" "no options" "nitc $common without more options"
+ run_compiler "nitc-$name" ./nitc $common
if test "$1" = NOALL; then
+ withall=
shift
- elif test -n "$2"; then
- prepare_res "$name-all.dat" "all" "nitc-g with all options $@"
- run_compiler "nitc-g-$tag" ./nitc --global $@
+ else
+ withall=true
fi
for opt in "$@"; do
- ot=${opt// /+}
+ ot=${opt// /}
prepare_res "$name$ot.dat" "$opt" "nitc-g with option $opt"
- run_compiler "nitc-g$ot" ./nitc --global $opt
+ run_compiler "nitc-$name" ./nitc $common $opt
done
- plot "$name.gnu"
-}
-bench_nitc-g_options "slower" --hardening --no-shortcut-range
-bench_nitc-g_options "nocheck" --no-check-null --no-check-autocast --no-check-attr-isset --no-check-covariance --no-check-assert
-
-function bench_nitc-s_options()
-{
- tag=$1
- shift
- name="$FUNCNAME-$tag"
- skip_test "$name" && return
- prepare_res "$name.dat" "no options" "nitc-s without options"
- run_compiler "nitc-s" ./nitc --separate
-
- if test "$1" = NOALL; then
- shift
- elif test -n "$2"; then
- prepare_res "$name-all.dat" "all" "nitc-s with all options $@"
- run_compiler "nitc-s-$tag" ./nitc --separate $@
+ if test -n "$2" -a -n "$withall"; then
+ prepare_res "$name-all.dat" "all" "nitc-g with all options $@"
+ run_compiler "nitc-$name" ./nitc $common $@
fi
- for opt in "$@"; do
- ot=${opt// /+}
- prepare_res "$name-$ot.dat" "$opt" "nitc-s with option $opt"
- run_compiler "nitc-s$ot" ./nitc --separate $opt
- done
-
plot "$name.gnu"
}
-bench_nitc-s_options "slower" --hardening --no-shortcut-equal --no-union-attribute --no-shortcut-range --no-inline-intern "--no-gcc-directive likely --no-gcc-directive noreturn" "--no-tag-primitives"
-bench_nitc-s_options "nocheck" --no-check-null --no-check-autocast --no-check-attr-isset --no-check-covariance --no-check-assert
-bench_nitc-s_options "faster" --skip-dead-methods --inline-coloring-numbers --inline-some-methods --direct-call-monomorph "--inline-some-methods --direct-call-monomorph" ""
-function bench_nitc-e_options()
-{
- tag=$1
- shift
- name="$FUNCNAME-$tag"
- skip_test "$name" && return
- prepare_res "$name.dat" "no options" "nitc-e without options"
- run_compiler "nitc-e" ./nitc --erasure
+bench_nitc_options "slower" --global --hardening --no-shortcut-range
+bench_nitc_options "nocheck" --global --no-check-null --no-check-autocast --no-check-attr-isset --no-check-covariance --no-check-assert
- if test "$1" = NOALL; then
- shift
- elif test -n "$2"; then
- prepare_res "$name-all.dat" "all" "nitc-e with all options $@"
- run_compiler "nitc-e-$tag" ./nitc --erasure $@
- fi
+bench_nitc_options "slower" --separate --hardening --no-shortcut-equal --no-union-attribute --no-shortcut-range --no-inline-intern "--no-gcc-directive likely --no-gcc-directive noreturn" "--no-tag-primitives"
+bench_nitc_options "nocheck" --separate --no-check-null --no-check-autocast --no-check-attr-isset --no-check-covariance --no-check-assert
+bench_nitc_options "faster" --separate --skip-dead-methods --inline-coloring-numbers --inline-some-methods --direct-call-monomorph "--inline-some-methods --direct-call-monomorph"
- for opt in "$@"; do
- ot=${opt// /+}
- prepare_res "$name$ot.dat" "$opt" "nitc-e with option $opt"
- run_compiler "nitc-e$ot" ./nitc --erasure $opt
- done
+bench_nitc_options "slower" --erasure --hardening --no-shortcut-equal --no-union-attribute --no-shortcut-range --no-inline-intern
+bench_nitc_options "nocheck" --erasure --no-check-null --no-check-autocast --no-check-attr-isset --no-check-covariance --no-check-assert --no-check-erasure-cast
+bench_nitc_options "faster" --erasure --skip-dead-methods --inline-coloring-numbers --inline-some-methods --direct-call-monomorph --rta
- plot "$name.gnu"
-}
-bench_nitc-e_options "slower" --hardening --no-shortcut-equal --no-union-attribute --no-shortcut-range --no-inline-intern
-bench_nitc-e_options "nocheck" --no-check-null --no-check-autocast --no-check-attr-isset --no-check-covariance --no-check-assert --no-check-erasure-cast
-bench_nitc-e_options "faster" --skip-dead-methods --inline-coloring-numbers --inline-some-methods --direct-call-monomorph --rta
-
-function bench_engines()
-{
- name="$FUNCNAME"
- skip_test "$name" && return
- prepare_res "$name-nitc-s.dat" "nitc-s" "nitc with --separate"
- run_compiler "nitc-s" ./nitc --separate
- prepare_res "$name-nitc-e.dat" "nitc-e" "nitc with --erasure"
- run_compiler "nitc-e" ./nitc --erasure
- prepare_res "$name-nitc-sg.dat" "nitc-sg" "nitc with --separate --semi-global"
- run_compiler "nitc-sg" ./nitc --separate --semi-global
- prepare_res "$name-nitc-eg.dat" "nitc-eg" "nitc with --erasure --semi-global"
- run_compiler "nitc-eg" ./nitc --erasure --semi-global
- prepare_res "$name-nitc-egt.dat" "nitc-egt" "nitc with --erasure --semi-global --rta"
- run_compiler "nitc-egt" ./nitc --erasure --semi-global --rta
- prepare_res "$name-nitc-g.dat" "nitc-g" "nitc with --global"
- run_compiler "nitc-g" ./nitc --global
- plot "$name.gnu"
-}
-bench_engines
+bench_nitc_options "engine" "" NOALL "--separate" "--erasure" "--separate --semi-global" "--erasure --semi-global" "--erasure --semi-global --rta" "--global"
+bench_nitc_options "policy" "" NOALL "--separate" "--erasure" "--separate --no-check-covariance" "--erasure --no-check-covariance --no-check-erasure-cast"
+bench_nitc_options "nullables" "" "--no-check-attr-isset" "--no-union-attribute"
+bench_nitc_options "linkboost" "" NOALL --trampoline-call --colors-are-symbols "--colors-are-symbols --trampoline-call" "--separate --link-boost" "--separate --colors-are-symbols --guard-call" "--separate --colors-are-symbols --direct-call-monomorph0"
+bench_nitc_options "monomorph" "" --direct-call-monomorph0 --direct-call-monomorph
function bench_nitc-e_gc()
{
}
bench_cc_nitc-e
-function bench_policy()
-{
- name="$FUNCNAME"
- skip_test "$name" && return
- prepare_res "$name-nitc-s.dat" "nitc-s" "nitc with --separate"
- run_compiler "nitc-s" ./nitc --separate
- prepare_res "$name-nitc-e.dat" "nitc-e" "nitc with --erasure"
- run_compiler "nitc-e" ./nitc --erasure
- prepare_res "$name-nitc-su.dat" "nitc-su" "nitc with --separate --no-check-covariance"
- run_compiler "nitc-su" ./nitc --separate --no-check-covariance
- prepare_res "$name-nitc-eu.dat" "nitc-eu" "nitc with --erasure --no-check-covariance --no-check-erasure-cast"
- run_compiler "nitc-eu" ./nitc --erasure --no-check-covariance --no-check-erasure-cast
- plot "$name.gnu"
-}
-bench_policy
-
-function bench_nullables()
-{
- name="$FUNCNAME"
- skip_test "$name" && return
- prepare_res "$name-nitc.dat" "nitc" "nitc no options"
- run_compiler "nitc" ./nitc --separate
- prepare_res "$name-nitc-ni.dat" "nitc-ni" "nitc --no-check-attr-isset"
- run_compiler "nitc" ./nitc --separate --no-check-attr-isset
- prepare_res "$name-nitc-nu.dat" "nitc-nu" "nitc --no-union-attribute"
- run_compiler "nitc" ./nitc --separate --no-union-attribute
- prepare_res "$name-nitc-nu-ni.dat" "nitc-nu-ni" "nitc --no-union-attribute --no-check-attr-isset"
- run_compiler "nitc" ./nitc --separate --no-union-attribute --no-check-attr-isset
- plot "$name.gnu"
-}
-bench_nullables
-
function bench_compilation_time
{
name="$FUNCNAME"
}
bench_compilation_time
-function bench_linkboost()
-{
- name="$FUNCNAME"
- skip_test "$name" && return
- prepare_res "$name-nitc-st.dat" "nitc-st" "nitc with --separate --trampoline-call"
- run_compiler "nitc-st" ./nitc --separate --trampoline-call
- prepare_res "$name-nitc-s.dat" "nitc-s" "nitc with --separate"
- run_compiler "nitc-s" ./nitc --separate
- prepare_res "$name-nitc-sc.dat" "nitc-sc" "nitc with --separate --colors-are-symbols"
- run_compiler "nitc-sc" ./nitc --separate --colors-are-symbols
- prepare_res "$name-nitc-sct.dat" "nitc-sct" "nitc with --separate --colors-are-symbols --trampoline-call"
- run_compiler "nitc-sct" ./nitc --separate --colors-are-symbols --trampoline-call
- prepare_res "$name-nitc-sl.dat" "nitc-sl" "nitc with --separate --link-boost"
- run_compiler "nitc-scts" ./nitc --separate --link-boost
- prepare_res "$name-nitc-scgc.dat" "nitc-scgc" "nitc with --separate --colors-are-symbols --guard-call"
- run_compiler "nitc-scgc" ./nitc --separate --colors-are-symbols --guard-call
- prepare_res "$name-nitc-scd.dat" "nitc-scd" "nitc with --separate --colors-are-symbols --direct-call-monomorph0"
- run_compiler "nitc-scd" ./nitc --separate --colors-are-symbols --direct-call-monomorph0
- plot "$name.gnu"
-}
-bench_linkboost
-
-function bench_call_monomorph()
-{
- name="$FUNCNAME"
- skip_test "$name" && return
- prepare_res "$name-nitc.dat" "nitc" "nitc with --separate"
- run_compiler "nitc" ./nitc
- prepare_res "$name-nitc-d0.dat" "nitc-d0" "nitc with --separate --direct-call-monomorph0"
- run_compiler "nitc-d0" ./nitc --direct-call-monomorph0
- prepare_res "$name-nitc-d1.dat" "nitc-d" "nitc with --separate --direct-call-monomorph"
- run_compiler "nitc-d1" ./nitc --direct-call-monomorph
- prepare_res "$name-nitc-d2.dat" "nitc-d2" "nitc with --separate --direct-call-monomorph2"
- run_compiler "nitc-d2" ./nitc --direct-call-monomorph --direct-call-monomorph0
- plot "$name.gnu"
-}
-bench_call_monomorph
-
if test -n "$html"; then
echo >>"$html" "</body></html>"
fi
# An abstract 2d line segment
interface ILine[N: Numeric]
+ # The type of points that ends the segment
type P: IPoint[N]
+ # The point that is the left-end of the segment
fun point_left: P is abstract
+
+ # The point that is the right-end of the segment
fun point_right: P is abstract
redef fun to_s do return "{point_left}--{point_right}"
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Basic structure for Nit apps on iOS
+module app
+
+import platform
+import ::app
+
+in "ObjC Header" `{
+ #import <UIKit/UIKit.h>
+
+ // Our interface to the iOS system
+ @interface AppDelegate: UIResponder <UIApplicationDelegate>
+
+ // The main window
+ @property (strong, nonatomic) UIWindow *window;
+ @end
+`}
+
+in "ObjC" `{
+
+ // Global reference to the App from app.nit
+ App app_nit_ios_app;
+
+ // Our own C argc and argv
+ int app_nit_ios_argc;
+ char **app_nit_ios_argv;
+
+ @implementation AppDelegate
+
+ - (BOOL)application:(UIApplication *)application
+ willFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+
+ // Set aside `application` to be used from Nit
+ App_ui_application__assign(app_nit_ios_app, application);
+ App_app_delegate__assign(app_nit_ios_app, self);
+
+ // Complete the callback
+ return App_will_finish_launching_with_options(app_nit_ios_app);
+ }
+
+ - (BOOL)application:(UIApplication *)application
+ didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+
+ return App_did_finish_launching_with_options(app_nit_ios_app);
+ }
+
+ - (void)applicationWillResignActive:(UIApplication *)application {
+ App_will_resign_active(app_nit_ios_app);
+ }
+
+ - (void)applicationDidEnterBackground:(UIApplication *)application {
+ App_did_enter_background(app_nit_ios_app);
+ }
+
+ - (void)applicationWillEnterForeground:(UIApplication *)application {
+ App_will_enter_foreground(app_nit_ios_app);
+ }
+
+ - (void)applicationDidBecomeActive:(UIApplication *)application {
+ App_did_become_active(app_nit_ios_app);
+ }
+
+ - (void)applicationWillTerminate:(UIApplication *)application {
+ App_will_terminate(app_nit_ios_app);
+ }
+
+ @end
+`}
+
+# Application interface to the iOS system
+extern class AppDelegate in "ObjC" `{ AppDelegate * `}
+end
+
+# Graphical application to which events are sent
+extern class UIApplication in "ObjC" `{ UIApplication * `}
+end
+
+redef class App
+
+ # Main graphical application
+ var ui_application: UIApplication
+
+ # Application interface to the iOS system
+ var app_delegate: AppDelegate
+
+ # Copy back to C the command line arguments
+ #
+ # Nit extracts the first arguments from the `args` sequence,
+ # so we need to add it back. That's why Nit's `args` is smaller than in C.
+ private fun register_args(program_name: NativeString, argc: Int,
+ argv: Sequence[String]) import Sequence[String].[], String.to_cstring in "ObjC" `{
+ app_nit_ios_argc = argc+1;
+
+ // TODO copy or pin the strings when needed
+ app_nit_ios_argv = malloc(argc * sizeof(char*));
+ app_nit_ios_argv[0] = program_name;
+ for (int i = 0; i < argc; i ++) {
+ String arg = Sequence_of_String__index(argv, i);
+ app_nit_ios_argv[i+1] = String_to_cstring(arg);
+ }
+ `}
+
+ # Register `self` globally in C so it can be retrieved from iOS callbacks
+ private fun register_globally in "ObjC" `{
+ App_incr_ref(recv);
+ app_nit_ios_app = recv;
+ `}
+
+ # Entry point to the iOS framework
+ private fun ui_application_main: Bool import did_finish_launching_with_options,
+ will_finish_launching_with_options,
+ will_resign_active, did_enter_background, will_enter_foreground,
+ did_become_active, will_terminate, ui_application=, app_delegate= in "ObjC" `{
+
+ @autoreleasepool {
+ return UIApplicationMain(app_nit_ios_argc, app_nit_ios_argv,
+ nil, NSStringFromClass([AppDelegate class]));
+ }
+ `}
+
+ # The application is about to launch
+ #
+ # Redef this method to set the very first custom code to be executed.
+ fun will_finish_launching_with_options: Bool do return true
+
+ # The application just launched but is not yet displayed to the user
+ #
+ # Redef this method to customize the behavior.
+ fun did_finish_launching_with_options: Bool do return true
+
+ # The application is about to move from active to inactive state
+ #
+ # This can occur for certain types of temporary interruptions
+ # (such as an incoming phone call or SMS message) or when the
+ # user quits the application and it begins the transition to
+ # the background state.
+ #
+ # Redef this method to pause ongoing tasks, disable timers, and
+ # throttle down OpenGL ES frame rates. Games should use this
+ # method to pause.
+ fun will_resign_active do end
+
+ # The application just left foreground it can be suspended at any time
+ #
+ # Redef this method to release shared resources, save user data,
+ # invalidate timers, and store application state to restore your
+ # application to its current state in case it is terminated later.
+ #
+ # If your application supports background execution, this method
+ # is called instead of `will_terminate` when the user quits.
+ fun did_enter_background do end
+
+ # The application will enter the foreground
+ #
+ # Called as part of the transition from the background to the
+ # inactive state.
+ #
+ # Redef to und changes made on entering the background.
+ fun will_enter_foreground do end
+
+ # The application just became active
+ #
+ # Redef to restart any tasks that were paused (or not yet started) while
+ # the application was inactive. If the application was previously
+ # in the background, optionally refresh the user interface.
+ fun did_become_active do end
+
+ # The application is about to terminate (not suspended)
+ #
+ # Redef to save data if appropriate.
+ fun will_terminate do end
+end
+
+app.register_args(program_name.to_cstring, args.length, args)
+app.register_globally
+
+var ret = app.ui_application_main
+exit if ret then 0 else 1
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Simple iOS app with a single label
+module hello_ios
+
+import ios
+
+redef class App
+ redef fun did_finish_launching_with_options
+ do
+ return app_delegate.hello_world
+ end
+end
+
+redef class AppDelegate
+
+ # Print and show "Hello World!"
+ private fun hello_world: Bool in "ObjC" `{
+
+ // Print to the console
+ NSLog(@"Hello World!");
+
+ // Display "Hello world!" on the screen
+ recv.window = [[UIWindow alloc] initWithFrame:
+ [[UIScreen mainScreen] bounds]];
+ recv.window.backgroundColor = [UIColor whiteColor];
+
+ UILabel *label = [[UILabel alloc] init];
+ label.text = @"Hello World!";
+ label.center = CGPointMake(100, 100);
+ [label sizeToFit];
+
+ [recv.window addSubview: label];
+ [recv.window makeKeyAndVisible];
+
+ return YES;
+ `}
+end
--- /dev/null
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# iOS services for Nit app on iOS
+module ios
+
+import platform
+import app
--- /dev/null
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Triggers compilation for the iOS platform
+module platform is platform "ios"
# assert [1..1[.is_empty == true
fun is_empty: Bool do return length == 0
+ # Alias for `not is_empty`.
+ #
+ # Some people prefer to have conditions grammatically easier to read.
+ #
+ # assert [1,2,3].not_empty == true
+ # assert [1..1[.not_empty == false
+ fun not_empty: Bool do return not self.is_empty
+
# Number of items in the collection.
#
# assert [10,20,30].length == 3
end
+redef class MapRead[K,V]
+ # Return an array of all values sorted with their keys using `comparator`.
+ #
+ # ~~~
+ # var map = new HashMap[Int, String]
+ # map[10] = "ten"
+ # map[2] = "two"
+ # map[1] = "one"
+ # assert map.values_sorted_by_key(default_comparator) == ["one", "two", "ten"]
+ # assert map.values_sorted_by_key(alpha_comparator) == ["one", "ten", "two"]
+ # ~~~
+ fun values_sorted_by_key(comparator: Comparator): Array[V]
+ do
+ var keys = self.keys.to_a
+ comparator.sort(keys)
+ return [for k in keys do self[k]]
+ end
+
+ # Return an array of all keys sorted with their values using `comparator`.
+ #
+ # ~~~
+ # var map = new HashMap[String, Int]
+ # map["ten"] = 10
+ # map["two"] = 2
+ # map["one"] = 1
+ # assert map.keys_sorted_by_values(default_comparator) == ["one", "two", "ten"]
+ # assert map.keys_sorted_by_values(alpha_comparator) == ["one", "ten", "two"]
+ # ~~~
+ #
+ # See: `to_map_comparator` to get the comparator used internally.
+ fun keys_sorted_by_values(comparator: Comparator): Array[K]
+ do
+ var keys = self.keys.to_a
+ var map_cmp = to_map_comparator(comparator)
+ map_cmp.sort(keys)
+ return keys
+ end
+
+ # A comparator that compares things with their values in self.
+ #
+ # See `MapComparator` for details.
+ fun to_map_comparator(comparator: Comparator): MapComparator[K, V] do return new MapComparator[K,V](self, comparator)
+end
+
+# A comparator that compares things with their values in a map.
+#
+# ~~~
+# var map = new HashMap[String, Int]
+# map["ten"] = 10
+# map["two"] = 2
+# map["one"] = 1
+#
+# var map_cmp = map.to_map_comparator(default_comparator)
+# var a = ["ten", "one", "two"]
+# map_cmp.sort(a)
+# assert a == ["one", "two", "ten"]
+# map_cmp = map.to_map_comparator(alpha_comparator)
+# map_cmp.sort(a)
+# assert a == ["one", "ten", "two"]
+# ~~~
+class MapComparator[K,V]
+ super Comparator
+
+ # What is compared are the keys of the values
+ redef type COMPARED: K
+
+ # The map that associates compared elements to the value used to compare them
+ var map: MapRead[K,V]
+
+ # The comparator used to compare values
+ var comparator: Comparator
+
+ redef fun compare(a,b) do return comparator.compare(map[a], map[b])
+end
+
# This comparator uses the operator `<=>` to compare objects.
# see `default_comparator` for an easy-to-use general stateless default comparator.
class DefaultComparator
redef fun execute
do
super
- stream_out = new FileWriter.from_fd(data.in_fd)
+ var out = new FileWriter.from_fd(data.in_fd)
+ out.set_buffering_mode(0, sys.buffer_mode_none)
+ stream_out = out
end
end
// cmd exited on SIGINT: in my opinion the user wants the main to be discontinued
kill(getpid(), SIGINT);
}
+ return status;
}
# File descriptor of this file
fun fd: Int do return _file.fileno
+ redef fun close
+ do
+ if _file == null then return
+ if _file.address_is_null then
+ if last_error != null then return
+ last_error = new IOError("Cannot close unopened file")
+ return
+ end
+ var i = _file.io_close
+ if i != 0 then
+ last_error = new IOError("Close failed due to error {sys.errno.strerror}")
+ end
+ _file = null
+ end
+
# Sets the buffering mode for the current FileStream
#
# If the buf_size is <= 0, its value will be 512 by default
redef fun close
do
- if _file == null or _file.address_is_null then return
- var i = _file.io_close
+ super
_buffer.clear
end_reached = true
- _file = null
end
redef fun fill_buffer
end
end
+ # Creates a new File stream from a file descriptor
init from_fd(fd: Int) do
self.path = ""
prepare_buffer(1)
else
for i in s.substrings do write_native(i.to_cstring, i.length)
end
- _file.flush
end
redef fun close
do
- if _file == null then return
- if _file.address_is_null then
- if last_error != null then return
- last_error = new IOError("Cannot close unopened write stream")
- _is_writable = false
- return
- end
- var i = _file.io_close
- if i != 0 then
- last_error = new IOError("Close failed due to error {sys.errno.strerror}")
- end
+ super
_is_writable = false
- _file = null
end
redef var is_writable = false
#
# assert "abAB12<>&".escape_to_c == "abAB12<>&"
# assert "\n\"'\\".escape_to_c == "\\n\\\"\\'\\\\"
+ #
+ # Most non-printable characters (bellow ASCII 32) are escaped to an octal form `\nnn`.
+ # Three digits are always used to avoid following digits to be interpreted as an element
+ # of the octal sequence.
+ #
+ # assert "{0.ascii}{1.ascii}{8.ascii}{31.ascii}{32.ascii}".escape_to_c == "\\000\\001\\010\\037 "
+ #
+ # The exceptions are the common `\t` and `\n`.
fun escape_to_c: String
do
var b = new FlatBuffer
var c = chars[i]
if c == '\n' then
b.append("\\n")
+ else if c == '\t' then
+ b.append("\\t")
else if c == '\0' then
- b.append("\\0")
+ b.append("\\000")
else if c == '"' then
b.append("\\\"")
else if c == '\'' then
else if c == '\\' then
b.append("\\\\")
else if c.ascii < 32 then
- b.append("\\{c.ascii.to_base(8, false)}")
+ b.add('\\')
+ var oct = c.ascii.to_base(8, false)
+ # Force 3 octal digits since it is the
+ # maximum allowed in the C specification
+ if oct.length == 1 then
+ b.add('0')
+ b.add('0')
+ else if oct.length == 2 then
+ b.add('0')
+ end
+ b.append(oct)
else
b.add(c)
end
end
end
+redef class NativeArray[E]
+ # Join all the elements using `to_s`
+ #
+ # REQUIRE: `self isa NativeArray[String]`
+ # REQUIRE: all elements are initialized
+ fun native_to_s: String
+ do
+ assert self isa NativeArray[String]
+ var l = length
+ var na = self
+ var i = 0
+ var sl = 0
+ var mypos = 0
+ while i < l do
+ sl += na[i].length
+ i += 1
+ mypos += 1
+ end
+ var ns = new NativeString(sl + 1)
+ ns[sl] = '\0'
+ i = 0
+ var off = 0
+ while i < mypos do
+ var tmp = na[i]
+ var tpl = tmp.length
+ if tmp isa FlatString then
+ tmp.items.copy_to(ns, tpl, tmp.index_from, off)
+ off += tpl
+ else
+ for j in tmp.substrings do
+ var s = j.as(FlatString)
+ var slen = s.length
+ s.items.copy_to(ns, slen, s.index_from, off)
+ off += slen
+ end
+ end
+ i += 1
+ end
+ return ns.to_s_with_length(sl)
+ end
+end
+
redef class Map[K,V]
# Concatenate couple of 'key value'.
# key and value are separated by `couple_sep`.
private var it: UnicodeChar
- private var is_created: Bool
+ private var is_created = false
init(s: FlatString) do from(s, 0)
# Short name
var name: String
- init(name: String) do self.name = name
-
redef fun rendering do add "- {name}\n"
end
var birth: Int
var death: Int
- init(firstname, lastname: String, birth, death: Int) do
- self.firstname = firstname
- self.lastname = lastname
- self.birth = birth
- self.death = death
- end
-
redef fun rendering do add """
COMPOSER: {{{firstname}}} {{{lastname}}}
# Make a new Int literal
fun make_int(value: Int): AIntExpr
do
- return new ADecIntExpr.make(value, mmodule.get_primitive_class("Int").mclass_type)
+ return new ADecIntExpr.make(value, mmodule.int_type)
end
# Make a new instatiation
protected fun write_and_make(compiler: AbstractCompiler)
do
var platform = compiler.target_platform
- var toolchain = platform.toolchain(toolcontext)
+ var toolchain = platform.toolchain(toolcontext, compiler)
compile_dir = toolchain.compile_dir
- toolchain.write_and_make compiler
+ toolchain.write_and_make
end
end
redef class Platform
# The specific tool-chain associated to the platform
- fun toolchain(toolcontext: ToolContext): Toolchain do return new MakefileToolchain(toolcontext)
+ fun toolchain(toolcontext: ToolContext, compiler: AbstractCompiler): Toolchain
+ do
+ return new MakefileToolchain(toolcontext, compiler)
+ end
end
+# Build toolchain for a specific target program, varies per `Platform`
class Toolchain
+
+ # Toolcontext
var toolcontext: ToolContext
+ # Compiler of the target program
+ var compiler: AbstractCompiler
+
+ # Directory where to generate all C files
fun compile_dir: String
do
var compile_dir = toolcontext.opt_compile_dir.value
return compile_dir
end
- fun write_and_make(compiler: AbstractCompiler) is abstract
+ # Write all C files and compile them
+ fun write_and_make is abstract
end
+# Default toolchain using a Makefile
class MakefileToolchain
super Toolchain
- redef fun write_and_make(compiler)
+ redef fun write_and_make
do
var compile_dir = compile_dir
compile_dir.mkdir
var cfiles = new Array[String]
- write_files(compiler, compile_dir, cfiles)
+ write_files(compile_dir, cfiles)
# Generate the Makefile
- write_makefile(compiler, compile_dir, cfiles)
+ write_makefile(compile_dir, cfiles)
var time1 = get_time
self.toolcontext.info("*** END WRITING C: {time1-time0} ***", 2)
time0 = time1
self.toolcontext.info("*** COMPILING C ***", 1)
- compile_c_code(compiler, compile_dir)
+ compile_c_code(compile_dir)
time1 = get_time
self.toolcontext.info("*** END COMPILING C: {time1-time0} ***", 2)
end
- fun write_files(compiler: AbstractCompiler, compile_dir: String, cfiles: Array[String])
+ # Write all source files to the `compile_dir`
+ fun write_files(compile_dir: String, cfiles: Array[String])
do
var platform = compiler.target_platform
if self.toolcontext.opt_stacktrace.value == "nitstack" and platform.supports_libunwind then compiler.build_c_to_nit_bindings
self.toolcontext.info("Total C source files to compile: {cfiles.length}", 2)
end
- fun makefile_name(mainmodule: MModule): String do return "{mainmodule.c_name}.mk"
+ # Get the name of the Makefile to use
+ fun makefile_name: String do return "{compiler.mainmodule.c_name}.mk"
- fun default_outname(mainmodule: MModule): String
+ # Get the default name of the executable to produce
+ fun default_outname: String
do
+ var mainmodule = compiler.mainmodule
+
# Search a non fictive module
var res = mainmodule.name
while mainmodule.is_fictive do
do
var res = self.toolcontext.opt_output.value
if res != null then return res
- res = default_outname(mainmodule)
+ res = default_outname
var dir = self.toolcontext.opt_dir.value
if dir != null then return dir.join_path(res)
return res
end
- fun write_makefile(compiler: AbstractCompiler, compile_dir: String, cfiles: Array[String])
+ # Write the Makefile
+ fun write_makefile(compile_dir: String, cfiles: Array[String])
do
var mainmodule = compiler.mainmodule
var platform = compiler.target_platform
# 2. copy the binary at the right place in the `all` goal.
outpath = mainmodule.c_name
end
- var makename = makefile_name(mainmodule)
+ var makename = makefile_name
var makepath = "{compile_dir}/{makename}"
var makefile = new FileWriter.open(makepath)
makepath.file_copy_to "{compile_dir}/Makefile"
end
- fun compile_c_code(compiler: AbstractCompiler, compile_dir: String)
+ # The C code is generated, compile it to an executable
+ fun compile_c_code(compile_dir: String)
do
- var makename = makefile_name(compiler.mainmodule)
+ var makename = makefile_name
var makeflags = self.toolcontext.opt_make_flags.value
if makeflags == null then makeflags = ""
self.header.add_decl("#include <stdlib.h>")
self.header.add_decl("#include <stdio.h>")
self.header.add_decl("#include <string.h>")
+ self.header.add_decl("#include <sys/types.h>\n")
+ self.header.add_decl("#include <unistd.h>\n")
self.header.add_decl("#include \"gc_chooser.h\"")
self.header.add_decl("#ifdef ANDROID")
self.header.add_decl(" #include <android/log.h>")
self.writer = new CodeWriter(compiler.files.last)
end
- # Force to get the primitive class named `name` or abort
- fun get_class(name: String): MClass do return self.compiler.mainmodule.get_primitive_class(name)
-
# Force to get the primitive property named `name` in the instance `recv` or abort
fun get_property(name: String, recv: MType): MMethod
do
fun native_array_def(pname: String, ret_type: nullable MType, arguments: Array[RuntimeVariable]) is abstract
+ # Return an element of a native array.
+ # The method is unsafe and is just a direct wrapper for the specific implementation of native arrays
+ fun native_array_get(native_array: RuntimeVariable, index: Int): RuntimeVariable is abstract
+
+ # Store an element in a native array.
+ # The method is unsafe and is just a direct wrapper for the specific implementation of native arrays
+ fun native_array_set(native_array: RuntimeVariable, index: Int, value: RuntimeVariable) is abstract
+
# Evaluate `args` as expressions in the call of `mpropdef` on `recv`.
# This method is used to manage varargs in signatures and returns the real array
# of runtime variables to use in the call.
var recv
var ctype = mtype.ctype
assert mtype.mclass.name != "NativeArray"
- if ctype == "val*" then
+ if not mtype.is_c_primitive then
recv = init_instance(mtype)
else if ctype == "char*" then
recv = new_expr("NULL/*special!*/", mtype)
end
end
+ # The currently processed module
+ #
+ # alias for `compiler.mainmodule`
+ fun mmodule: MModule do return compiler.mainmodule
+
# Generate an integer value
fun int_instance(value: Int): RuntimeVariable
do
- var res = self.new_var(self.get_class("Int").mclass_type)
- self.add("{res} = {value};")
+ var t = mmodule.int_type
+ var res = new RuntimeVariable("{value.to_s}l", t, t)
+ return res
+ end
+
+ # Generate a char value
+ fun char_instance(value: Char): RuntimeVariable
+ do
+ var t = mmodule.char_type
+ var res = new RuntimeVariable("'{value.to_s.escape_to_c}'", t, t)
+ return res
+ end
+
+ # Generate a float value
+ #
+ # FIXME pass a Float, not a string
+ fun float_instance(value: String): RuntimeVariable
+ do
+ var t = mmodule.float_type
+ var res = new RuntimeVariable("{value}", t, t)
return res
end
# Generate an integer value
fun bool_instance(value: Bool): RuntimeVariable
do
- var res = self.new_var(self.get_class("Bool").mclass_type)
- if value then
- self.add("{res} = 1;")
- else
- self.add("{res} = 0;")
- end
+ var s = if value then "1" else "0"
+ var res = new RuntimeVariable(s, bool_type, bool_type)
+ return res
+ end
+
+ # Generate the `null` value
+ fun null_instance: RuntimeVariable
+ do
+ var t = compiler.mainmodule.model.null_type
+ var res = new RuntimeVariable("((val*)NULL)", t, t)
return res
end
# Generate a string value
fun string_instance(string: String): RuntimeVariable
do
- var mtype = self.get_class("String").mclass_type
+ var mtype = mmodule.string_type
var name = self.get_name("varonce")
self.add_decl("static {mtype.ctype} {name};")
var res = self.new_var(mtype)
self.add("if (likely({name}!=NULL)) \{")
self.add("{res} = {name};")
self.add("\} else \{")
- var native_mtype = self.get_class("NativeString").mclass_type
+ var native_mtype = mmodule.native_string_type
var nat = self.new_var(native_mtype)
self.add("{nat} = \"{string.escape_to_c}\";")
var length = self.int_instance(string.length)
# Short name of the `ctype` to use in unions
fun ctypename: String do return "val"
+
+ # Is the associated C type a primitive one?
+ #
+ # ENSURE `result == (ctype != "val*")`
+ fun is_c_primitive: Bool do return false
end
redef class MClassType
- redef fun ctype: String
- do
+ redef var ctype is lazy do
if mclass.name == "Int" then
return "long"
else if mclass.name == "Bool" then
end
end
+ redef var is_c_primitive is lazy do return ctype != "val*"
+
redef fun ctype_extern: String
do
if mclass.kind == extern_kind then
if is_lazy then
var set
var ret = self.mpropdef.static_mtype
- var useiset = ret.ctype == "val*" and not ret isa MNullableType
+ var useiset = not ret.is_c_primitive and not ret isa MNullableType
var guard = self.mlazypropdef.mproperty
if useiset then
set = v.isset_attribute(self.mpropdef.mproperty, recv)
v.assign(res, value)
if not useiset then
- var true_v = v.new_expr("1", v.bool_type)
+ var true_v = v.bool_instance(true)
v.write_attribute(guard, arguments.first, true_v)
end
v.add("\}")
v.write_attribute(self.mpropdef.mproperty, arguments.first, arguments[1])
if is_lazy then
var ret = self.mpropdef.static_mtype
- var useiset = ret.ctype == "val*" and not ret isa MNullableType
+ var useiset = not ret.is_c_primitive and not ret isa MNullableType
if not useiset then
- v.write_attribute(self.mlazypropdef.mproperty, arguments.first, v.new_expr("1", v.bool_type))
+ v.write_attribute(self.mlazypropdef.mproperty, arguments.first, v.bool_instance(true))
end
end
else
end
redef class AIntExpr
- redef fun expr(v) do return v.new_expr("{self.value.to_s}", self.mtype.as(not null))
+ redef fun expr(v) do return v.int_instance(self.value.as(not null))
end
redef class AFloatExpr
- redef fun expr(v) do return v.new_expr("{self.n_float.text}", self.mtype.as(not null)) # FIXME use value, not n_float
+ redef fun expr(v) do return v.float_instance("{self.n_float.text}") # FIXME use value, not n_float
end
redef class ACharExpr
- redef fun expr(v) do return v.new_expr("'{self.value.to_s.escape_to_c}'", self.mtype.as(not null))
+ redef fun expr(v) do return v.char_instance(self.value.as(not null))
end
redef class AArrayExpr
redef class ASuperstringExpr
redef fun expr(v)
do
- var array = new Array[RuntimeVariable]
+ var type_string = mtype.as(not null)
+
+ # Collect elements of the superstring
+ var array = new Array[AExpr]
for ne in self.n_exprs do
+ # Drop literal empty string.
+ # They appears in things like "{a}" that is ["", a, ""]
if ne isa AStringFormExpr and ne.value == "" then continue # skip empty sub-strings
- var i = v.expr(ne, null)
- array.add(i)
+ array.add(ne)
+ end
+
+ # Store the allocated native array in a static variable
+ # For reusing later
+ var varonce = v.get_name("varonce")
+ v.add("if (unlikely({varonce}==NULL)) \{")
+
+ # The native array that will contains the elements to_s-ized.
+ # For fast concatenation.
+ var a = v.native_array_instance(type_string, v.int_instance(array.length))
+
+ v.add_decl("static {a.mtype.ctype} {varonce};")
+
+ # Pre-fill the array with the literal string parts.
+ # So they do not need to be filled again when reused
+ for i in [0..array.length[ do
+ var ne = array[i]
+ if not ne isa AStringFormExpr then continue
+ var e = v.expr(ne, null)
+ v.native_array_set(a, i, e)
end
- var a = v.array_instance(array, v.object_type)
- var res = v.send(v.get_property("to_s", a.mtype), [a])
+
+ v.add("\} else \{")
+ # Take the native-array from the store.
+ # The point is to prevent that some recursive execution use (and corrupt) the same native array
+ # WARNING: not thread safe! (FIXME?)
+ v.add("{a} = {varonce};")
+ v.add("{varonce} = NULL;")
+ v.add("\}")
+
+ # Stringify the elements and put them in the native array
+ var to_s_method = v.get_property("to_s", v.object_type)
+ for i in [0..array.length[ do
+ var ne = array[i]
+ if ne isa AStringFormExpr then continue
+ var e = v.expr(ne, null)
+ # Skip the `to_s` if the element is already a String
+ if not e.mcasttype.is_subtype(v.compiler.mainmodule, null, type_string) then
+ e = v.send(to_s_method, [e]).as(not null)
+ end
+ v.native_array_set(a, i, e)
+ end
+
+ # Fast join the native string to get the result
+ var res = v.send(v.get_property("native_to_s", a.mtype), [a])
+
+ # We finish to work with the native array,
+ # so store it so that it can be reused
+ v.add("{varonce} = {a};")
return res
end
end
end
redef class ATrueExpr
- redef fun expr(v) do return v.new_expr("1", self.mtype.as(not null))
+ redef fun expr(v) do return v.bool_instance(true)
end
redef class AFalseExpr
- redef fun expr(v) do return v.new_expr("0", self.mtype.as(not null))
+ redef fun expr(v) do return v.bool_instance(false)
end
redef class ANullExpr
- redef fun expr(v) do return v.new_expr("NULL", self.mtype.as(not null))
+ redef fun expr(v) do return v.null_instance
end
redef class AIsaExpr
var i = v.expr(self.n_expr, null)
if v.compiler.modelbuilder.toolcontext.opt_no_check_assert.value then return i
- if i.mtype.ctype != "val*" then return i
+ if i.mtype.is_c_primitive then return i
v.add("if (unlikely({i} == NULL)) \{")
v.add_abort("Cast failed")
import platform::android
import platform::pnacl
import platform::emscripten
+import platform::ios
self.header = new CodeWriter(file)
self.live_primitive_types = new Array[MClassType]
for t in runtime_type_analysis.live_types do
- if t.ctype != "val*" or t.mclass.name == "Pointer" then
+ if t.is_c_primitive or t.mclass.name == "Pointer" then
self.live_primitive_types.add(t)
end
end
# Init instance code (allocate and init-arguments)
for t in runtime_type_analysis.live_types do
- if t.ctype == "val*" then
+ if not t.is_c_primitive then
compiler.generate_init_instance(t)
if t.mclass.kind == extern_kind then
compiler.generate_box_instance(t)
fun generate_init_instance(mtype: MClassType)
do
assert self.runtime_type_analysis.live_types.has(mtype)
- assert mtype.ctype == "val*"
+ assert not mtype.is_c_primitive
var v = self.new_visitor
var is_native_array = mtype.mclass.name == "NativeArray"
do
if value.mtype == mtype then
return value
- else if value.mtype.ctype == "val*" and mtype.ctype == "val*" then
+ else if not value.mtype.is_c_primitive and not mtype.is_c_primitive then
return value
- else if value.mtype.ctype == "val*" then
+ else if not value.mtype.is_c_primitive then
return self.new_expr("((struct {mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype)
- else if mtype.ctype == "val*" then
+ else if not mtype.is_c_primitive then
var valtype = value.mtype.as(MClassType)
var res = self.new_var(mtype)
if not compiler.runtime_type_analysis.live_types.has(valtype) then
redef fun native_array_instance(elttype: MType, length: RuntimeVariable): RuntimeVariable
do
- var ret_type = self.get_class("NativeArray").get_mtype([elttype])
+ var ret_type = mmodule.native_array_type(elttype)
ret_type = anchor(ret_type).as(MClassType)
return self.new_expr("NEW_{ret_type.c_name}({length})", ret_type)
end
+ redef fun native_array_get(nat, i)
+ do
+ var recv = "((struct {nat.mcasttype.c_name}*){nat})->values"
+ var ret_type = nat.mcasttype.as(MClassType).arguments.first
+ return self.new_expr("{recv}[{i}]", ret_type)
+ end
+
+ redef fun native_array_set(nat, i, val)
+ do
+ var recv = "((struct {nat.mcasttype.c_name}*){nat})->values"
+ self.add("{recv}[{i}]={val};")
+ end
+
redef fun calloc_array(ret_type, arguments)
do
self.ret(self.new_expr("NEW_{ret_type.c_name}({arguments[1]})", ret_type))
end
self.add("/* send {m} on {args.first.inspect} */")
- if args.first.mtype.ctype != "val*" then
+ if args.first.mtype.is_c_primitive then
var mclasstype = args.first.mtype.as(MClassType)
if not self.compiler.runtime_type_analysis.live_types.has(mclasstype) then
self.add("/* skip, no method {m} */")
var defaultpropdef: nullable MMethodDef = null
for t in types do
var propdef = m.lookup_first_definition(self.compiler.mainmodule, t)
- if propdef.mclassdef.mclass.name == "Object" and t.ctype == "val*" then
+ if propdef.mclassdef.mclass.name == "Object" and not t.is_c_primitive then
defaultpropdef = propdef
continue
end
end
self.add("/* super {m} on {args.first.inspect} */")
- if args.first.mtype.ctype != "val*" then
+ if args.first.mtype.is_c_primitive then
var mclasstype = args.first.mtype.as(MClassType)
if not self.compiler.runtime_type_analysis.live_types.has(mclasstype) then
self.add("/* skip, no method {m} */")
fun bugtype(recv: RuntimeVariable)
do
- if recv.mtype.ctype != "val*" then return
+ if recv.mtype.is_c_primitive then return
self.add("PRINT_ERROR(\"BTD BUG: Dynamic type is %s, static type is %s\\n\", class_names[{recv}->classid], \"{recv.mcasttype}\");")
self.add("fatal_exit(1);")
end
ta = self.resolve_for(ta, recv2)
var attr = self.new_expr("((struct {t.c_name}*){recv})->{a.intro.c_name}", ta)
if not ta isa MNullableType then
- if ta.ctype == "val*" then
+ if not ta.is_c_primitive then
self.add("{res} = ({attr} != NULL);")
else
self.add("{res} = 1; /*NOTYET isset on primitive attributes*/")
ta = self.resolve_for(ta, recv2)
var res2 = self.new_expr("((struct {t.c_name}*){recv})->{a.intro.c_name}", ta)
if not ta isa MNullableType and not self.compiler.modelbuilder.toolcontext.opt_no_check_attr_isset.value then
- if ta.ctype == "val*" then
+ if not ta.is_c_primitive then
self.add("if ({res2} == NULL) \{")
self.add_abort("Uninitialized attribute {a.name}")
self.add("\}")
var res = self.new_var(bool_type)
self.add("/* isa {mtype} on {value.inspect} */")
- if value.mtype.ctype != "val*" then
+ if value.mtype.is_c_primitive then
if value.mtype.is_subtype(self.compiler.mainmodule, null, mtype) then
self.add("{res} = 1;")
else
redef fun is_same_type_test(value1, value2)
do
var res = self.new_var(bool_type)
- if value2.mtype.ctype == "val*" then
- if value1.mtype.ctype == "val*" then
+ if not value2.mtype.is_c_primitive then
+ if not value1.mtype.is_c_primitive then
self.add "{res} = {value1}->classid == {value2}->classid;"
else
self.add "{res} = {self.compiler.classid(value1.mtype.as(MClassType))} == {value2}->classid;"
end
else
- if value1.mtype.ctype == "val*" then
+ if not value1.mtype.is_c_primitive then
self.add "{res} = {value1}->classid == {self.compiler.classid(value2.mtype.as(MClassType))};"
else if value1.mcasttype == value2.mcasttype then
self.add "{res} = 1;"
do
var res = self.get_name("var_class_name")
self.add_decl("const char* {res};")
- if value.mtype.ctype == "val*" then
+ if not value.mtype.is_c_primitive then
self.add "{res} = class_names[{value}->classid];"
else
self.add "{res} = class_names[{self.compiler.classid(value.mtype.as(MClassType))}];"
redef fun equal_test(value1, value2)
do
var res = self.new_var(bool_type)
- if value2.mtype.ctype != "val*" and value1.mtype.ctype == "val*" then
+ if value2.mtype.is_c_primitive and not value1.mtype.is_c_primitive then
var tmp = value1
value1 = value2
value2 = tmp
end
- if value1.mtype.ctype != "val*" then
+ if value1.mtype.is_c_primitive then
if value2.mtype == value1.mtype then
self.add("{res} = {value1} == {value2};")
- else if value2.mtype.ctype != "val*" then
+ else if value2.mtype.is_c_primitive then
self.add("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/")
else
var mtype1 = value1.mtype.as(MClassType)
redef fun array_instance(array, elttype)
do
elttype = self.anchor(elttype)
- var arraytype = self.get_class("Array").get_mtype([elttype])
+ var arraytype = mmodule.array_type(elttype)
var res = self.init_instance(arraytype)
self.add("\{ /* {res} = array_instance Array[{elttype}] */")
- var nat = self.new_var(self.get_class("NativeArray").get_mtype([elttype]))
+ var nat = self.new_var(mmodule.native_array_type(elttype))
nat.is_exact = true
self.add("{nat} = NEW_{nat.mtype.c_name}({array.length});")
for i in [0..array.length[ do
for i in [0..mmethoddef.msignature.arity[ do
var mtype = mmethoddef.msignature.mparameters[i].mtype
if i == mmethoddef.msignature.vararg_rank then
- mtype = v.get_class("Array").get_mtype([mtype])
+ mtype = v.mmodule.array_type(mtype)
end
mtype = v.resolve_for(mtype, selfvar)
comment.append(", {mtype}")
if mclass.mclass_type.ctype_extern == "val*" then
return 0
else if mclass.kind == extern_kind and mclass.name != "NativeString" then
- return self.box_kinds[self.mainmodule.get_primitive_class("Pointer")]
+ return self.box_kinds[self.mainmodule.pointer_type.mclass]
else
return self.box_kinds[mclass]
end
var v = new_visitor
var rta = runtime_type_analysis
- var is_dead = rta != null and not rta.live_classes.has(mclass) and mtype.ctype == "val*" and mclass.name != "NativeArray" and mclass.name != "Pointer"
+ var is_dead = rta != null and not rta.live_classes.has(mclass) and not mtype.is_c_primitive and mclass.name != "NativeArray" and mclass.name != "Pointer"
v.add_decl("/* runtime class {c_name} */")
v.add_decl("\};")
end
- if mtype.ctype != "val*" or mtype.mclass.name == "Pointer" then
+ if mtype.is_c_primitive or mtype.mclass.name == "Pointer" then
# Is a primitive type or the Pointer class, not any other extern class
if mtype.is_tagged then return
do
if value.mtype == mtype then
return value
- else if value.mtype.ctype == "val*" and mtype.ctype == "val*" then
+ else if not value.mtype.is_c_primitive and not mtype.is_c_primitive then
return value
- else if value.mtype.ctype == "val*" then
+ else if not value.mtype.is_c_primitive then
if mtype.is_tagged then
if mtype.name == "Int" then
return self.new_expr("(long)({value})>>2", mtype)
end
end
return self.new_expr("((struct instance_{mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype)
- else if mtype.ctype == "val*" then
+ else if not mtype.is_c_primitive then
if value.mtype.is_tagged then
if value.mtype.name == "Int" then
return self.new_expr("(val*)({value}<<2|1)", mtype)
# Thus the expression can be used as a condition.
fun extract_tag(value: RuntimeVariable): String
do
- assert value.mtype.ctype == "val*"
+ assert not value.mtype.is_c_primitive
return "((long){value}&3)" # Get the two low bits
end
# The point of the method is to work also with primitive types.
fun class_info(value: RuntimeVariable): String
do
- if value.mtype.ctype == "val*" then
+ if not value.mtype.is_c_primitive then
if can_be_primitive(value) and not compiler.modelbuilder.toolcontext.opt_no_tag_primitives.value then
var tag = extract_tag(value)
return "({tag}?class_info[{tag}]:{value}->class)"
# The point of the method is to work also with primitive types.
fun type_info(value: RuntimeVariable): String
do
- if value.mtype.ctype == "val*" then
+ if not value.mtype.is_c_primitive then
if can_be_primitive(value) and not compiler.modelbuilder.toolcontext.opt_no_tag_primitives.value then
var tag = extract_tag(value)
return "({tag}?type_info[{tag}]:{value}->type)"
end
redef fun send(mmethod, arguments)
do
- if arguments.first.mcasttype.ctype != "val*" then
+ if arguments.first.mcasttype.is_c_primitive then
# In order to shortcut the primitive, we need to find the most specific method
# Howverr, because of performance (no flattening), we always work on the realmainmodule
var m = self.compiler.mainmodule
redef fun supercall(m: MMethodDef, recvtype: MClassType, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
do
- if arguments.first.mcasttype.ctype != "val*" then
+ if arguments.first.mcasttype.is_c_primitive then
# In order to shortcut the primitive, we need to find the most specific method
# However, because of performance (no flattening), we always work on the realmainmodule
var main = self.compiler.mainmodule
self.add("{res} = {recv}->attrs[{a.const_color}] != NULL; /* {a} on {recv.inspect}*/")
else
- if mtype.ctype == "val*" then
+ if not mtype.is_c_primitive and not mtype.is_tagged then
self.add("{res} = {recv}->attrs[{a.const_color}].val != NULL; /* {a} on {recv.inspect} */")
else
self.add("{res} = 1; /* NOT YET IMPLEMENTED: isset of primitives: {a} on {recv.inspect} */")
self.add("{res} = {recv}->attrs[{a.const_color}].{ret.ctypename}; /* {a} on {recv.inspect} */")
# Check for Uninitialized attribute
- if ret.ctype == "val*" and not ret isa MNullableType and not self.compiler.modelbuilder.toolcontext.opt_no_check_attr_isset.value then
+ if not ret.is_c_primitive and not ret isa MNullableType and not self.compiler.modelbuilder.toolcontext.opt_no_check_attr_isset.value then
self.add("if (unlikely({res} == NULL)) \{")
self.add_abort("Uninitialized attribute {a.name}")
self.add("\}")
self.require_declaration(a.const_color)
if self.compiler.modelbuilder.toolcontext.opt_no_union_attribute.value then
var attr = "{recv}->attrs[{a.const_color}]"
- if mtype.ctype != "val*" then
+ if mtype.is_tagged then
+ # The attribute is not primitive, thus store it as tagged
+ var tv = autobox(value, compiler.mainmodule.object_type)
+ self.add("{attr} = {tv}; /* {a} on {recv.inspect} */")
+ else if mtype.is_c_primitive then
assert mtype isa MClassType
# The attribute is primitive, thus we store it in a box
# The trick is to create the box the first time then resuse the box
do
var res = self.new_var(bool_type)
# Swap values to be symetric
- if value2.mtype.ctype != "val*" and value1.mtype.ctype == "val*" then
+ if value2.mtype.is_c_primitive and not value1.mtype.is_c_primitive then
var tmp = value1
value1 = value2
value2 = tmp
end
- if value1.mtype.ctype != "val*" then
+ if value1.mtype.is_c_primitive then
if value2.mtype == value1.mtype then
self.add("{res} = 1; /* is_same_type_test: compatible types {value1.mtype} vs. {value2.mtype} */")
- else if value2.mtype.ctype != "val*" then
+ else if value2.mtype.is_c_primitive then
self.add("{res} = 0; /* is_same_type_test: incompatible types {value1.mtype} vs. {value2.mtype}*/")
else
var mtype1 = value1.mtype.as(MClassType)
do
var res = self.get_name("var_class_name")
self.add_decl("const char* {res};")
- if value.mtype.ctype == "val*" then
+ if not value.mtype.is_c_primitive then
self.add "{res} = {value} == NULL ? \"null\" : {type_info(value)}->name;"
else if value.mtype isa MClassType and value.mtype.as(MClassType).mclass.kind == extern_kind and
value.mtype.as(MClassType).name != "NativeString" then
redef fun equal_test(value1, value2)
do
var res = self.new_var(bool_type)
- if value2.mtype.ctype != "val*" and value1.mtype.ctype == "val*" then
+ if value2.mtype.is_c_primitive and not value1.mtype.is_c_primitive then
var tmp = value1
value1 = value2
value2 = tmp
end
- if value1.mtype.ctype != "val*" then
+ if value1.mtype.is_c_primitive then
if value2.mtype == value1.mtype then
self.add("{res} = {value1} == {value2};")
- else if value2.mtype.ctype != "val*" then
+ else if value2.mtype.is_c_primitive then
self.add("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/")
else if value1.mtype.is_tagged then
self.add("{res} = ({value2} != NULL) && ({self.autobox(value2, value1.mtype)} == {value1});")
var incompatible = false
var primitive
- if t1.ctype != "val*" then
+ if t1.is_c_primitive then
primitive = t1
if t1 == t2 then
# No need to compare class
- else if t2.ctype != "val*" then
+ else if t2.is_c_primitive then
incompatible = true
else if can_be_primitive(value2) then
if t1.is_tagged then
else
incompatible = true
end
- else if t2.ctype != "val*" then
+ else if t2.is_c_primitive then
primitive = t2
if can_be_primitive(value1) then
if t2.is_tagged then
var t = value.mcasttype.as_notnullable
if not t isa MClassType then return false
var k = t.mclass.kind
- return k == interface_kind or t.ctype != "val*"
+ return k == interface_kind or t.is_c_primitive
end
fun maybe_null(value: RuntimeVariable): Bool
redef fun array_instance(array, elttype)
do
- var nclass = self.get_class("NativeArray")
- var arrayclass = self.get_class("Array")
+ var nclass = mmodule.native_array_class
+ var arrayclass = mmodule.array_class
var arraytype = arrayclass.get_mtype([elttype])
var res = self.init_instance(arraytype)
self.add("\{ /* {res} = array_instance Array[{elttype}] */")
redef fun native_array_instance(elttype: MType, length: RuntimeVariable): RuntimeVariable
do
- var mtype = self.get_class("NativeArray").get_mtype([elttype])
+ var mtype = mmodule.native_array_type(elttype)
self.require_declaration("NEW_{mtype.mclass.c_name}")
assert mtype isa MGenericType
var compiler = self.compiler
redef fun native_array_def(pname, ret_type, arguments)
do
var elttype = arguments.first.mtype
- var nclass = self.get_class("NativeArray")
+ var nclass = mmodule.native_array_class
var recv = "((struct instance_{nclass.c_name}*){arguments[0]})->values"
if pname == "[]" then
# Because the objects are boxed, return the box to avoid unnecessary (or broken) unboxing/reboxing
end
end
- redef fun calloc_array(ret_type, arguments)
+ redef fun native_array_get(nat, i)
+ do
+ var nclass = mmodule.native_array_class
+ var recv = "((struct instance_{nclass.c_name}*){nat})->values"
+ # Because the objects are boxed, return the box to avoid unnecessary (or broken) unboxing/reboxing
+ var res = self.new_expr("{recv}[{i}]", compiler.mainmodule.object_type)
+ return res
+ end
+
+ redef fun native_array_set(nat, i, val)
do
- var mclass = self.get_class("ArrayCapable")
- var ft = mclass.mparameters.first
- var res = self.native_array_instance(ft, arguments[1])
- self.ret(res)
+ var nclass = mmodule.native_array_class
+ var recv = "((struct instance_{nclass.c_name}*){nat})->values"
+ self.add("{recv}[{i}]={val};")
end
fun link_unresolved_type(mclassdef: MClassDef, mtype: MType) do
for i in [0..called_signature.arity[ do
var mtype = called_signature.mparameters[i].mtype
if i == called_signature.vararg_rank then
- mtype = mmethoddef.mclassdef.mmodule.get_primitive_class("Array").get_mtype([mtype])
+ mtype = mmethoddef.mclassdef.mmodule.array_type(mtype)
end
sig.append(", {mtype.ctype} p{i}")
end
for i in [0..msignature.arity[ do
var mtype = msignature.mparameters[i].mtype
if i == msignature.vararg_rank then
- mtype = v.get_class("Array").get_mtype([mtype])
+ mtype = v.mmodule.array_type(mtype)
end
comment.append(", {mtype}")
var argvar = new RuntimeVariable("p{i}", mtype, mtype)
var selfvar = arguments.first
var ret = called_signature.return_mtype
- if mmethoddef.is_intro and recv.ctype == "val*" then
+ if mmethoddef.is_intro and not recv.is_c_primitive then
var m = mmethoddef.mproperty
var n2 = "CALL_" + m.const_color
compiler.provide_declaration(n2, "{c_ret} {n2}{c_sig};")
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
v2.add "\}"
end
- if mmethoddef.has_supercall and recv.ctype == "val*" then
+ if mmethoddef.has_supercall and not recv.is_c_primitive then
var m = mmethoddef
var n2 = "CALL_" + m.const_color
compiler.provide_declaration(n2, "{c_ret} {n2}{c_sig};")
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
return super
end
end
+
+redef class AAttrPropdef
+ redef fun init_expr(v, recv)
+ do
+ super
+ if is_lazy and v.compiler.modelbuilder.toolcontext.opt_no_union_attribute.value then
+ var guard = self.mlazypropdef.mproperty
+ v.write_attribute(guard, recv, v.bool_instance(false))
+ end
+ end
+end
var rta = runtime_type_analysis
var is_dead = false # mclass.kind == abstract_kind or mclass.kind == interface_kind
- if not is_dead and rta != null and not rta.live_classes.has(mclass) and mtype.ctype == "val*" and mclass.name != "NativeArray" then
+ if not is_dead and rta != null and not rta.live_classes.has(mclass) and not mtype.is_c_primitive and mclass.name != "NativeArray" then
is_dead = true
end
v.add_decl("\}")
v.add_decl("\};")
- if mtype.ctype != "val*" or mtype.mclass.name == "Pointer" then
+ if mtype.is_c_primitive or mtype.mclass.name == "Pointer" then
#Build instance struct
self.header.add_decl("struct instance_{c_name} \{")
self.header.add_decl("const struct class *class;")
end
var class_ptr
- if value.mtype.ctype == "val*" then
+ if not value.mtype.is_c_primitive then
class_ptr = "{value}->class->"
else
var mclass = value.mtype.as(MClassType).mclass
else if mtype isa MVirtualType then
var recv = self.frame.arguments.first
var recv_ptr
- if recv.mtype.ctype == "val*" then
+ if not recv.mtype.is_c_primitive then
recv_ptr = "{recv}->class->"
else
var mclass = recv.mtype.as(MClassType).mclass
do
var res = self.get_name("var_class_name")
self.add_decl("const char* {res};")
- if value.mtype.ctype == "val*" then
+ if not value.mtype.is_c_primitive then
self.add "{res} = {value} == NULL ? \"null\" : {value}->class->name;"
else
self.require_declaration("class_{value.mtype.c_name}")
redef fun native_array_instance(elttype, length)
do
- var nclass = self.get_class("NativeArray")
+ var nclass = mmodule.native_array_class
var mtype = nclass.get_mtype([elttype])
var res = self.new_var(mtype)
res.is_exact = true
# Return the integer instance associated with `val`.
fun int_instance(val: Int): Instance
do
- var ic = get_primitive_class("Int")
- var instance = new PrimitiveInstance[Int](ic.mclass_type, val)
+ var t = mainmodule.int_type
+ var instance = new PrimitiveInstance[Int](t, val)
init_instance_primitive(instance)
return instance
end
# Return the char instance associated with `val`.
fun char_instance(val: Char): Instance
do
- var ic = get_primitive_class("Char")
- var instance = new PrimitiveInstance[Char](ic.mclass_type, val)
+ var t = mainmodule.char_type
+ var instance = new PrimitiveInstance[Char](t, val)
init_instance_primitive(instance)
return instance
end
# Return the float instance associated with `val`.
fun float_instance(val: Float): Instance
do
- var ic = get_primitive_class("Float")
- var instance = new PrimitiveInstance[Float](ic.mclass_type, val)
+ var t = mainmodule.float_type
+ var instance = new PrimitiveInstance[Float](t, val)
init_instance_primitive(instance)
return instance
end
fun array_instance(values: Array[Instance], elttype: MType): Instance
do
assert not elttype.need_anchor
- var nat = new PrimitiveInstance[Array[Instance]](get_primitive_class("NativeArray").get_mtype([elttype]), values)
+ var nat = new PrimitiveInstance[Array[Instance]](mainmodule.native_array_type(elttype), values)
init_instance_primitive(nat)
- var mtype = get_primitive_class("Array").get_mtype([elttype])
+ var mtype = mainmodule.array_type(elttype)
var res = new MutableInstance(mtype)
self.init_instance(res)
self.send(self.force_get_primitive_method("with_native", mtype), [res, nat, self.int_instance(values.length)])
do
var val = new FlatBuffer.from(txt)
val.add('\0')
- var ic = get_primitive_class("NativeString")
- var instance = new PrimitiveInstance[Buffer](ic.mclass_type, val)
+ var t = mainmodule.native_string_type
+ var instance = new PrimitiveInstance[Buffer](t, val)
init_instance_primitive(instance)
return instance
end
# A hook to initialize a `PrimitiveInstance`
fun init_instance_primitive(recv: Instance) do end
- # Return the primitive `MClass` corresponding to the `name` given in parameter
- # `name` : name of the primitive class
- fun get_primitive_class(name: String): MClass
- do
- return mainmodule.get_primitive_class(name)
- end
-
# This function determines the correct type according to the receiver of the current propdef (self).
fun unanchor_type(mtype: MType): MType
do
if pname == "files" then
var res = new Array[Instance]
for f in str.files do res.add v.string_instance(f)
- return v.array_instance(res, v.get_primitive_class("String").mclass_type)
+ return v.array_instance(res, v.mainmodule.string_type)
end
else if pname == "calloc_string" then
return v.native_string_instance("!" * args[1].to_i)
else if pname == "set_buffering_type" then
return v.int_instance(recvval.as(PrimitiveNativeFile).set_buffering_type(args[1].to_i, args[2].to_i))
end
- else if pname == "calloc_array" then
- var recvtype = args.first.mtype.as(MClassType)
- var mtype: MType
- mtype = recvtype.supertype_to(v.mainmodule, recvtype, v.get_primitive_class("ArrayCapable"))
- mtype = mtype.arguments.first
- var val = new Array[Instance].filled_with(v.null_instance, args[1].to_i)
- var instance = new PrimitiveInstance[Array[Instance]](v.get_primitive_class("NativeArray").get_mtype([mtype]), val)
- v.init_instance_primitive(instance)
- return instance
else if pname == "native_argc" then
return v.int_instance(v.arguments.length)
else if pname == "native_argv" then
if i == null then return null
array.add(i)
end
- var i = v.array_instance(array, v.get_primitive_class("Object").mclass_type)
+ var i = v.array_instance(array, v.mainmodule.object_type)
var res = v.send(v.force_get_primitive_method("to_s", i.mtype), [i])
assert res != null
return res
private var flatten_mclass_hierarchy_cache: nullable POSet[MClass] = null
# The primitive type `Object`, the root of the class hierarchy
- fun object_type: MClassType
- do
- var res = self.object_type_cache
- if res != null then return res
- res = self.get_primitive_class("Object").mclass_type
- self.object_type_cache = res
- return res
- end
-
- private var object_type_cache: nullable MClassType
+ var object_type: MClassType = self.get_primitive_class("Object").mclass_type is lazy
# The type `Pointer`, super class to all extern classes
var pointer_type: MClassType = self.get_primitive_class("Pointer").mclass_type is lazy
# The primitive type `Bool`
- fun bool_type: MClassType
- do
- var res = self.bool_type_cache
- if res != null then return res
- res = self.get_primitive_class("Bool").mclass_type
- self.bool_type_cache = res
- return res
- end
+ var bool_type: MClassType = self.get_primitive_class("Bool").mclass_type is lazy
+
+ # The primitive type `Int`
+ var int_type: MClassType = self.get_primitive_class("Int").mclass_type is lazy
+
+ # The primitive type `Char`
+ var char_type: MClassType = self.get_primitive_class("Char").mclass_type is lazy
+
+ # The primitive type `Float`
+ var float_type: MClassType = self.get_primitive_class("Float").mclass_type is lazy
+
+ # The primitive type `String`
+ var string_type: MClassType = self.get_primitive_class("String").mclass_type is lazy
+
+ # The primitive type `NativeString`
+ var native_string_type: MClassType = self.get_primitive_class("NativeString").mclass_type is lazy
+
+ # A primitive type of `Array`
+ fun array_type(elt_type: MType): MClassType do return array_class.get_mtype([elt_type])
+
+ # The primitive class `Array`
+ var array_class: MClass = self.get_primitive_class("Array") is lazy
+
+ # A primitive type of `NativeArray`
+ fun native_array_type(elt_type: MType): MClassType do return native_array_class.get_mtype([elt_type])
- private var bool_type_cache: nullable MClassType
+ # The primitive class `NativeArray`
+ var native_array_class: MClass = self.get_primitive_class("NativeArray") is lazy
# The primitive type `Sys`, the main type of the program, if any
fun sys_type: nullable MClassType
import frontend
import parser_util
import vm
-import vm_optimizations
-import variables_numbering
# Create a tool context to handle options and paths
var toolcontext = new ToolContext
module nitvm
import vm
-import vm_optimizations
-import variables_numbering
import frontend
# Create a tool context to handle options and paths
redef fun supports_linker_script do return false
- redef fun toolchain(toolcontext) do return new AndroidToolchain(toolcontext)
+ redef fun toolchain(toolcontext, compiler) do return new AndroidToolchain(toolcontext, compiler)
end
class AndroidToolchain
return "{android_project_root}/jni/nit_compile/"
end
- redef fun default_outname(mainmodule) do return "{mainmodule.name}.apk"
+ redef fun default_outname do return "{super}.apk"
- redef fun write_files(compiler, compile_dir, cfiles)
+ redef fun write_files(compile_dir, cfiles)
do
var android_project_root = android_project_root.as(not null)
var project = toolcontext.modelbuilder.android_project_for(compiler.mainmodule)
if not dir.file_exists then dir.mkdir
# compile normal C files
- super(compiler, compile_dir, cfiles)
+ super
# Gather extra C files generated elsewhere than in super
for f in compiler.extern_bodies do
</manifest>
<!-- END_INCLUDE(manifest) -->
"""
+ manifest_file.close
### Link to png sources
# libpng is not available on Android NDK
end
end
- redef fun write_makefile(compiler, compile_dir, cfiles)
+ redef fun write_makefile(compile_dir, cfiles)
do
# Do nothing, already done in `write_files`
end
- redef fun compile_c_code(compiler, compile_dir)
+ redef fun compile_c_code(compile_dir)
do
var android_project_root = android_project_root.as(not null)
var short_project_name = compiler.mainmodule.name.replace("-", "_")
redef fun supports_libunwind do return false
redef fun supports_libgc do return false
redef fun supports_linker_script do return false
- redef fun toolchain(toolcontext) do return new EnscriptenToolchain(toolcontext)
+ redef fun toolchain(toolcontext, compiler) do return new EnscriptenToolchain(toolcontext, compiler)
end
class EnscriptenToolchain
super MakefileToolchain
- redef fun makefile_name(mainmodule) do return "{mainmodule.name}.js.mk"
+ redef fun makefile_name do return "{super}.js.mk"
- redef fun default_outname(mainmodule) do return "{super}.js"
+ redef fun default_outname do return "{super}.js"
- redef fun write_makefile(compiler, compile_dir, cfiles)
+ redef fun write_makefile(compile_dir, cfiles)
do
super
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org )
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Compile programs for the iOS platform
+module ios
+
+import platform
+import compiler::abstract_compiler
+import xcode_templates
+private import annotation
+
+redef class ToolContext
+ redef fun platform_from_name(name)
+ do
+ if name == "ios" then return new IOSPlatform
+ return super
+ end
+end
+
+private class IOSPlatform
+ super Platform
+
+ redef fun supports_libunwind do return false
+ redef fun supports_libgc do return false
+ redef fun toolchain(toolcontext, compiler) do return new IOSToolchain(toolcontext, compiler)
+end
+
+private class IOSToolchain
+ super MakefileToolchain
+
+ # Root of the iOS project, usually `.nit_compile/ios/`
+ var ios_project_root: String is noinit
+
+ redef fun default_outname do return "{super}.app"
+
+ # Name of the current project of `compiler`
+ fun project_name: String
+ do
+ var project_name = null
+ # TODO unite the app_name annotation from Android with iOS
+ var annot = compiler.modelbuilder.lookup_annotation_on_modules("app_name", compiler.mainmodule)
+ if annot != null then project_name = annot.arg_as_string(compiler.modelbuilder)
+ if project_name == null then project_name = compiler.mainmodule.name
+ return project_name
+ end
+
+ # Compile C files in `ios_project_root/project_name`
+ redef fun compile_dir
+ do
+ ios_project_root = super/"ios"
+ return ios_project_root/project_name
+ end
+
+ redef fun write_files(compile_dir, cfiles)
+ do
+ # Clear the project directory before writing anything
+ if ios_project_root.file_exists then ios_project_root.rmdir
+ compile_dir.mkdir
+
+ super
+ end
+
+ redef fun write_makefile(compile_dir, cfiles)
+ do
+ var project_name = project_name
+
+ # Create an XCode project directory
+ var dir = ios_project_root/project_name+".xcodeproj"
+ if not dir.file_exists then dir.mkdir
+
+ # Create a PBX project file
+ var pbx = new PbxprojectTemplate(project_name)
+
+ ## Register all source files
+ for file in cfiles do pbx.add_file new PbxFile(file)
+ for file in compiler.extern_bodies do
+ pbx.add_file new PbxFile(file.filename.basename(""))
+ end
+
+ ## TODO Register asset files
+
+ pbx.write_to_file dir/"project.pbxproj"
+
+ # Create the plist in the same directory as the generated C code
+ if not compile_dir.file_exists then compile_dir.mkdir
+ var plist = new PlistTemplate("org.nitlanguage") # TODO customize using an annotation
+ plist.write_to_file compile_dir/"Info.plist"
+ end
+
+ redef fun compile_c_code(compile_dir)
+ do
+ var project_name = project_name
+ var release = toolcontext.opt_release.value
+ var outfile = outfile(compiler.mainmodule)
+
+ # Compile with `xcodebuild`
+ #
+ # TODO support more than the iPhone and the simulator.
+ var args = ["sh", "-c", "cd {ios_project_root}; " +
+ "xcodebuild -target '{project_name}' " +
+ "-destination 'platform=iOS Simulator,name=iPhone' " +
+ "-configuration {if release then "Release" else "Debug"} " +
+ "-sdk iphonesimulator build"]
+ toolcontext.exec_and_check(args, "iOS project error")
+
+ # Move compiled app to destination
+ if outfile.file_exists then outfile.rmdir
+ args = ["mv", "{ios_project_root}/build/Debug-iphonesimulator/{project_name}.app", outfile]
+ toolcontext.exec_and_check(args, "iOS project error")
+ end
+end
redef fun no_main do return true
- redef fun toolchain(toolcontext) do return new PnaclToolchain(toolcontext)
+ redef fun toolchain(toolcontext, compiler) do return new PnaclToolchain(toolcontext, compiler)
end
class PnaclToolchain
super MakefileToolchain
- redef fun write_files(compiler, compile_dir, cfiles)
+ redef fun write_files(compile_dir, cfiles)
do
var app_name = compiler.mainmodule.name
if not dir.file_exists then dir.mkdir
# compile normal C files
- super(compiler, compile_dir, cfiles)
+ super
# Gather extra C files generated elsewhere than in super
for f in compiler.extern_bodies do
""".write_to_file(file)
end
- redef fun write_makefile(compiler, compile_dir, cfiles)
+ redef fun write_makefile(compile_dir, cfiles)
do
# Do nothing, already done in `write_files`
end
- redef fun compile_c_code(compiler, compile_dir)
+ redef fun compile_c_code(compile_dir)
do
# Generate the pexe
toolcontext.exec_and_check(["make", "-C", compile_dir, "-j", "4"], "PNaCl project error")
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Templates and other services to create XCode projects
+module xcode_templates
+
+import template
+
+import platform
+import compiler::abstract_compiler
+
+redef class Sys
+ # Map to identify the PBX file type for a given file extension
+ private var pbx_file_types: Map[String, String] is lazy do
+ var map = new HashMap[String, String]
+
+ # Source code
+ map["m"] = "sourcecode.c.objc"
+ map["c"] = "sourcecode.c.c"
+ map["h"] = "sourcecode.c.h"
+ map["cpp"] = "sourcecode.cpp.cpp"
+ map["hpp"] = "sourcecode.cpp.h"
+ map["vsh"] = "sourcecode.glsl"
+ map["fsh"] = "sourcecode.glsl"
+
+ # Images
+ map["png"] = "image.png"
+ map["gif"] = "image.gif"
+ map["jpg"] = "image.jpeg"
+ map["jpeg"] = "image.jpeg"
+ map["pdf"] = "image.pdf"
+ map["ico"] = "image.ico"
+
+ # Others
+ map["app"] = "wrapper.application"
+ map["plist"] = "text.plist.xml"
+ map["storyboard"] = "file.storyboard"
+ map["xib"] = "file.xib"
+ map["xcassets"] = "folder.assetcatalog"
+ map["xctest"] = "wrapper.cfbundle"
+
+ return map
+ end
+
+ # Generator of PBX UUIDs quique to an execution of the compiler
+ private var pbx_uuid_generator = new PbxUUIDGenerator is lazy
+end
+
+# Generator of PBX UUIDs
+#
+# PBX UUID are composed of 24 hex characters.
+# They only need to be unique within the same project.
+#
+# This implementation simply counts upward from 0.
+class PbxUUIDGenerator
+ private var seed = 0
+
+ # Generate a new UUID
+ fun next_uuid: String
+ do
+ seed += 1
+
+ var hex_val = seed.to_hex.to_upper
+ return "0"*(24-hex_val.length) + hex_val
+ end
+end
+
+# Reference to a file for the PBX format of a project file
+#
+# TODO create subclasses for different file types, this is currently for
+# compilable source files only.
+class PbxFile
+
+ # Path to `self`
+ var path: String
+
+ # UUID for build elements
+ private var build_uuid: String = sys.pbx_uuid_generator.next_uuid is lazy
+
+ # File reference UUID
+ private var ref_uuid: String = sys.pbx_uuid_generator.next_uuid is lazy
+
+ # Documentation to add besides this file in the template
+ private fun doc: String do return path
+
+ # PBX file type for `self`
+ fun file_type: String
+ do
+ var map = sys.pbx_file_types
+ var ext = path.file_extension
+ if ext != null and map.keys.has(ext) then return map[ext]
+ return "unknown"
+ end
+
+ # PBX description of this file
+ private fun description: Writable do return """
+ {{{ref_uuid}}} /* {{{doc}}} */ = {
+ isa = PBXFileReference;
+ fileEncoding = 4;
+ lastKnownFileType = {{{file_type}}};
+ path = {{{path}}};
+ sourceTree = "<group>";
+ };
+"""
+
+ private fun add_to_project(project: PbxprojectTemplate)
+ do
+ project.source_files.add self
+ project.files.add self
+ end
+end
+
+# Template for a PBX project file, usually a `project.pbcproj`
+#
+# This file list all information required to build an XCode project.
+# It would usually be written and read by XCode.
+# From the command line, xcodebuild can read this file but not write it.
+#
+# Information in the file (simplified list):
+#
+# * Compilable source files
+# * Asset files
+# * Build configurations (Release and debug modes, cflags, etc.)
+# * List of files composing the project
+class PbxprojectTemplate
+ super Template
+
+ # Name of the project
+ var name: String
+
+ # All body/implementation source files to be compiled
+ private var source_files = new Array[PbxFile]
+
+ # All asset files added to the app package
+ private var asset_files = new Array[PbxFile]
+
+ # All files used by this project
+ private var files = new Array[PbxFile]
+
+ # Add `file` to this project
+ fun add_file(file: PbxFile) do file.add_to_project(self)
+
+ redef fun rendering
+ do
+ add """
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+"""
+
+ # List build files (compilable sources and assets) with their reference UUID
+ for array in [source_files, asset_files] do for file in array do add """
+ {{{file.build_uuid}}} /* {{{file.doc}}} */ = {
+ isa = PBXBuildFile;
+ fileRef = {{{file.ref_uuid}}} /* {{{file.doc}}} */;
+ };
+"""
+
+ add """
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ AF9F83EA1A5F0D21004B62C0 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = AF9F83C41A5F0D21004B62C0 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = AF9F83CB1A5F0D21004B62C0;
+ remoteInfo = {{{name}}};
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ /* Static generated files */
+ AF9F83CC1A5F0D21004B62C0 /* {{{name}}}.app */ = {
+ isa = PBXFileReference;
+ explicitFileType = wrapper.application;
+ includeInIndex = 0;
+ path = {{{name}}}.app;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ AF9F83D01A5F0D21004B62C0 /* Info.plist */ = {
+ isa = PBXFileReference;
+ lastKnownFileType = text.plist.xml;
+ path = Info.plist;
+ sourceTree = "<group>";
+ };
+ AF9F83DE1A5F0D21004B62C0 /* Base */ = {
+ isa = PBXFileReference;
+ lastKnownFileType = file.storyboard;
+ name = Base;
+ path = Base.lproj/Main.storyboard;
+ sourceTree = "<group>";
+ };
+ AF9F83E01A5F0D21004B62C0 /* Images.xcassets */ = {
+ isa = PBXFileReference;
+ lastKnownFileType = folder.assetcatalog;
+ path = Images.xcassets;
+ sourceTree = "<group>";
+ };
+ AF9F83E31A5F0D21004B62C0 /* Base */ = {
+ isa = PBXFileReference;
+ lastKnownFileType = file.xib;
+ name = Base;
+ path = Base.lproj/LaunchScreen.xib;
+ sourceTree = "<group>";
+ };
+ AF9F83E91A5F0D21004B62C0 /* {{{name}}}Tests.xctest */ = {
+ isa = PBXFileReference;
+ explicitFileType = wrapper.cfbundle;
+ includeInIndex = 0;
+ path = {{{name}}}Tests.xctest;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ AF9F83EE1A5F0D21004B62C0 /* Info.plist */ = {
+ isa = PBXFileReference;
+ lastKnownFileType = text.plist.xml;
+ path = Info.plist;
+ sourceTree = "<group>";
+ };
+ AF9F83EF1A5F0D21004B62C0 /* {{{name}}}Tests.m */ = {
+ isa = PBXFileReference;
+ lastKnownFileType = sourcecode.c.objc;
+ path = {{{name}}}Tests.m;
+ sourceTree = "<group>";
+ };
+
+ /* Changing generated files */
+"""
+ # Describe all known files
+ for file in files do add file.description
+
+ add """
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ AF9F83C91A5F0D21004B62C0 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ AF9F83E61A5F0D21004B62C0 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ AF9F83C31A5F0D21004B62C0 = {
+ isa = PBXGroup;
+ children = (
+ AF9F83CE1A5F0D21004B62C0 /* {{{name}}} */,
+ AF9F83EC1A5F0D21004B62C0 /* {{{name}}}Tests */,
+ AF9F83CD1A5F0D21004B62C0 /* Products */,
+ );
+ sourceTree = "<group>";
+ };
+ AF9F83CD1A5F0D21004B62C0 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ AF9F83CC1A5F0D21004B62C0 /* {{{name}}}.app */,
+ AF9F83E91A5F0D21004B62C0 /* {{{name}}}Tests.xctest */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ AF9F83CE1A5F0D21004B62C0 /* {{{name}}} */ = {
+ isa = PBXGroup;
+ children = (
+"""
+ # Reference all known files
+ for file in files do add """
+ {{{file.ref_uuid}}} /* {{{file.doc}}} */,
+"""
+
+ add """
+ );
+ path = {{{name}}};
+ sourceTree = "<group>";
+ };
+ AF9F83CF1A5F0D21004B62C0 /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ AF9F83D01A5F0D21004B62C0 /* Info.plist */,
+ AF9F83D11A5F0D21004B62C0 /* main.m */,
+ );
+ name = "Supporting Files";
+ sourceTree = "<group>";
+ };
+ AF9F83EC1A5F0D21004B62C0 /* {{{name}}}Tests */ = {
+ isa = PBXGroup;
+ children = (
+ AF9F83EF1A5F0D21004B62C0 /* {{{name}}}Tests.m */,
+ AF9F83ED1A5F0D21004B62C0 /* Supporting Files */,
+ );
+ path = {{{name}}}Tests;
+ sourceTree = "<group>";
+ };
+ AF9F83ED1A5F0D21004B62C0 /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ AF9F83EE1A5F0D21004B62C0 /* Info.plist */,
+ );
+ name = "Supporting Files";
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ AF9F83CB1A5F0D21004B62C0 /* {{{name}}} */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = AF9F83F31A5F0D21004B62C0 /* Build configuration list for PBXNativeTarget "{{{name}}}" */;
+ buildPhases = (
+ AF9F83C81A5F0D21004B62C0 /* Sources */,
+ AF9F83C91A5F0D21004B62C0 /* Frameworks */,
+ AF9F83CA1A5F0D21004B62C0 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = {{{name}}};
+ productName = {{{name}}};
+ productReference = AF9F83CC1A5F0D21004B62C0 /* {{{name}}}.app */;
+ productType = "com.apple.product-type.application";
+ };
+ AF9F83E81A5F0D21004B62C0 /* {{{name}}}Tests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = AF9F83F61A5F0D21004B62C0 /* Build configuration list for PBXNativeTarget "{{{name}}}Tests" */;
+ buildPhases = (
+ AF9F83E51A5F0D21004B62C0 /* Sources */,
+ AF9F83E61A5F0D21004B62C0 /* Frameworks */,
+ AF9F83E71A5F0D21004B62C0 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ AF9F83EB1A5F0D21004B62C0 /* PBXTargetDependency */,
+ );
+ name = {{{name}}}Tests;
+ productName = {{{name}}}Tests;
+ productReference = AF9F83E91A5F0D21004B62C0 /* {{{name}}}Tests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ AF9F83C41A5F0D21004B62C0 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0610;
+ TargetAttributes = {
+ AF9F83CB1A5F0D21004B62C0 = {
+ CreatedOnToolsVersion = 6.1.1;
+ };
+ AF9F83E81A5F0D21004B62C0 = {
+ CreatedOnToolsVersion = 6.1.1;
+ TestTargetID = AF9F83CB1A5F0D21004B62C0;
+ };
+ };
+ };
+ buildConfigurationList = AF9F83C71A5F0D21004B62C0 /* Build configuration list for PBXProject "{{{name}}}" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = AF9F83C31A5F0D21004B62C0;
+ productRefGroup = AF9F83CD1A5F0D21004B62C0 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ AF9F83CB1A5F0D21004B62C0 /* {{{name}}} */,
+ AF9F83E81A5F0D21004B62C0 /* {{{name}}}Tests */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ AF9F83CA1A5F0D21004B62C0 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+"""
+ # Reference all asset files by their build UUID
+ for file in asset_files do add """
+ {{{file.build_uuid}}} /* {{{file.doc}}} */,
+"""
+
+ add """
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ AF9F83E71A5F0D21004B62C0 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ AF9F83C81A5F0D21004B62C0 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+"""
+ # Reference all compilable source files by their build UUID
+ for file in source_files do add """
+ {{{file.build_uuid}}} /* {{{file.doc}}} */,
+"""
+ add """
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ AF9F83E51A5F0D21004B62C0 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ AF9F83F01A5F0D21004B62C0 /* {{{name}}}Tests.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ AF9F83EB1A5F0D21004B62C0 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = AF9F83CB1A5F0D21004B62C0 /* {{{name}}} */;
+ targetProxy = AF9F83EA1A5F0D21004B62C0 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+ AF9F83DD1A5F0D21004B62C0 /* Main.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ AF9F83DE1A5F0D21004B62C0 /* Base */,
+ );
+ name = Main.storyboard;
+ sourceTree = "<group>";
+ };
+ AF9F83E21A5F0D21004B62C0 /* LaunchScreen.xib */ = {
+ isa = PBXVariantGroup;
+ children = (
+ AF9F83E31A5F0D21004B62C0 /* Base */,
+ );
+ name = LaunchScreen.xib;
+ sourceTree = "<group>";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ AF9F83F11A5F0D21004B62C0 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ IPHONEOS_DEPLOYMENT_TARGET = 8.1;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ AF9F83F21A5F0D21004B62C0 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = YES;
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ IPHONEOS_DEPLOYMENT_TARGET = 8.1;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ AF9F83F41A5F0D21004B62C0 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ INFOPLIST_FILE = {{{name}}}/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ AF9F83F51A5F0D21004B62C0 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ INFOPLIST_FILE = {{{name}}}/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ AF9F83F71A5F0D21004B62C0 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(SDKROOT)/Developer/Library/Frameworks",
+ "$(inherited)",
+ );
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ INFOPLIST_FILE = {{{name}}}Tests/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/{{{name}}}.app/{{{name}}}";
+ };
+ name = Debug;
+ };
+ AF9F83F81A5F0D21004B62C0 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(SDKROOT)/Developer/Library/Frameworks",
+ "$(inherited)",
+ );
+ INFOPLIST_FILE = {{{name}}}Tests/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/{{{name}}}.app/{{{name}}}";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ AF9F83C71A5F0D21004B62C0 /* Build configuration list for PBXProject "{{{name}}}" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ AF9F83F11A5F0D21004B62C0 /* Debug */,
+ AF9F83F21A5F0D21004B62C0 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ AF9F83F31A5F0D21004B62C0 /* Build configuration list for PBXNativeTarget "{{{name}}}" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ AF9F83F41A5F0D21004B62C0 /* Debug */,
+ AF9F83F51A5F0D21004B62C0 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ };
+ AF9F83F61A5F0D21004B62C0 /* Build configuration list for PBXNativeTarget "{{{name}}}Tests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ AF9F83F71A5F0D21004B62C0 /* Debug */,
+ AF9F83F81A5F0D21004B62C0 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = AF9F83C41A5F0D21004B62C0 /* Project object */;
+}
+"""
+ end
+end
+
+# Template for a property list used by XCode for iOS projects
+class PlistTemplate
+ super Template
+
+ # Package of the app
+ var package_name: String
+
+ redef fun rendering
+ do
+ add """
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIdentifier</key>
+ <string>{{{package_name}}}.$(PRODUCT_NAME:rfc1034identifier)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>\\?\\?\\?\\?</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+ <key>UIRequiredDeviceCapabilities</key>
+ <array>
+ <string>armv7</string>
+ </array>
+ <key>UISupportedInterfaceOrientations</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ </array>
+ <key>UISupportedInterfaceOrientations~ipad</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationPortraitUpsideDown</string>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ </array>
+</dict>
+</plist>
+"""
+ end
+end
var node = self.modelbuilder.mpropdef2node(mmethoddef)
var elttype = mmethoddef.msignature.mparameters[vararg_rank].mtype
#elttype = elttype.anchor_to(self.mainmodule, v.receiver)
- var vararg = self.mainmodule.get_primitive_class("Array").get_mtype([elttype])
+ var vararg = self.mainmodule.array_type(elttype)
v.add_type(vararg)
- var native = self.mainmodule.get_primitive_class("NativeArray").get_mtype([elttype])
+ var native = self.mainmodule.native_array_type(elttype)
v.add_type(native)
v.add_monomorphic_send(vararg, self.modelbuilder.force_get_primitive_method(node, "with_native", vararg.mclass, self.mainmodule))
end
return mtype
end
- fun get_class(name: String): MClass
- do
- return analysis.mainmodule.get_primitive_class(name)
- end
-
fun get_method(recv: MType, name: String): MMethod
do
var mtype = cleanup_type(recv)
do
var mtype = self.mtype.as(MClassType)
v.add_type(mtype)
- var native = v.analysis.mainmodule.get_primitive_class("NativeArray").get_mtype([mtype.arguments.first])
+ var native = v.analysis.mainmodule.native_array_type(mtype.arguments.first)
v.add_type(native)
mtype = v.cleanup_type(mtype).as(not null)
var prop = v.get_method(mtype, "with_native")
redef class AStringFormExpr
redef fun accept_rapid_type_visitor(v)
do
- var native = v.get_class("NativeString").mclass_type
+ var native = v.analysis.mainmodule.native_string_type
v.add_type(native)
var prop = v.get_method(native, "to_s_with_length")
v.add_monomorphic_send(native, prop)
redef class ASuperstringExpr
redef fun accept_rapid_type_visitor(v)
do
- var arraytype = v.get_class("Array").get_mtype([v.get_class("Object").mclass_type])
+ var mmodule = v.analysis.mainmodule
+ var object_type = mmodule.object_type
+ var arraytype = mmodule.array_type(object_type)
v.add_type(arraytype)
- v.add_type(v.get_class("NativeArray").get_mtype([v.get_class("Object").mclass_type]))
+ var nattype = mmodule.native_array_type(object_type)
+ v.add_type(nattype)
var prop = v.get_method(arraytype, "join")
v.add_monomorphic_send(arraytype, prop)
var prop2 = v.get_method(arraytype, "with_native")
v.add_monomorphic_send(arraytype, prop2)
+ v.add_monomorphic_send(nattype, v.get_method(nattype, "native_to_s"))
end
end
node.full_transform_visitor(self)
end
- # Get a primitive class or display a fatal error on `location`.
- fun get_class(location: AExpr, name: String): MClass
- do
- return mmodule.get_primitive_class(name)
- end
-
# Get a primitive method or display a fatal error on `location`.
fun get_method(location: AExpr, name: String, recv: MClass): MMethod
do
# Handle all numbering operations related to local variables in the Nit virtual machine
module variables_numbering
-import vm
+import virtual_machine
redef class VirtualMachine
# limitations under the License.
# Implementation of the Nit virtual machine
-module vm
+module virtual_machine
import interpreter::naive_interpreter
import perfect_hashing
recv.vtable = recv.mtype.as(MClassType).mclass.vtable
end
- # Create a virtual table for this `MClass` if not already done
- redef fun get_primitive_class(name: String): MClass
- do
- var mclass = super
-
- if not mclass.loaded then create_class(mclass)
-
- return mclass
- end
-
# Initialize the internal representation of an object (its attribute values)
# `init_instance` is the initial value of attributes
private fun init_internal_attributes(init_instance: Instance, size: Int): Pointer
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2015 Julien Pagès <julien.pages@lirmm.fr>
+#
+# 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.
+
+# Entry point of all vm components
+module vm
+
+import virtual_machine
+import vm_optimizations
+import variables_numbering
# Optimization of the nitvm
module vm_optimizations
-import vm
+import virtual_machine
redef class VirtualMachine
cocoa_extern_types
cocoa_message_box
hello_cocoa
+hello_ios
+test_platform_ios
+++ /dev/null
-alt/error_needed_method_alt4.nit:49,10--14: Fatal Error: NativeString must have a property named to_s_with_length.
AParExprs ../src/test_parser.nit:71,7--36
TOpar "(" ../src/test_parser.nit:71,7
AStringExpr ../src/test_parser.nit:71,8--35
- TString "\" -n\11do not print anything\"" ../src/test_parser.nit:71,8--35
+ TString "\" -n\tdo not print anything\"" ../src/test_parser.nit:71,8--35
TCpar ")" ../src/test_parser.nit:71,36
ACallExpr ../src/test_parser.nit:72,2--25
AImplicitSelfExpr ../src/test_parser.nit:72,2
AParExprs ../src/test_parser.nit:72,7--25
TOpar "(" ../src/test_parser.nit:72,7
AStringExpr ../src/test_parser.nit:72,8--24
- TString "\" -l\11only lexer\"" ../src/test_parser.nit:72,8--24
+ TString "\" -l\tonly lexer\"" ../src/test_parser.nit:72,8--24
TCpar ")" ../src/test_parser.nit:72,25
ACallExpr ../src/test_parser.nit:73,2--41
AImplicitSelfExpr ../src/test_parser.nit:73,2
AParExprs ../src/test_parser.nit:73,7--41
TOpar "(" ../src/test_parser.nit:73,7
AStringExpr ../src/test_parser.nit:73,8--40
- TString "\" -p\11lexer and parser (default)\"" ../src/test_parser.nit:73,8--40
+ TString "\" -p\tlexer and parser (default)\"" ../src/test_parser.nit:73,8--40
TCpar ")" ../src/test_parser.nit:73,41
ACallExpr ../src/test_parser.nit:74,2--68
AImplicitSelfExpr ../src/test_parser.nit:74,2
AParExprs ../src/test_parser.nit:74,7--68
TOpar "(" ../src/test_parser.nit:74,7
AStringExpr ../src/test_parser.nit:74,8--67
- TString "\" -e\11instead on files, each argument is a content to parse\"" ../src/test_parser.nit:74,8--67
+ TString "\" -e\tinstead on files, each argument is a content to parse\"" ../src/test_parser.nit:74,8--67
TCpar ")" ../src/test_parser.nit:74,68
ACallExpr ../src/test_parser.nit:75,2--51
AImplicitSelfExpr ../src/test_parser.nit:75,2
AParExprs ../src/test_parser.nit:75,7--51
TOpar "(" ../src/test_parser.nit:75,7
AStringExpr ../src/test_parser.nit:75,8--50
- TString "\" -i\11tree to parse are read interactively\"" ../src/test_parser.nit:75,8--50
+ TString "\" -i\ttree to parse are read interactively\"" ../src/test_parser.nit:75,8--50
TCpar ")" ../src/test_parser.nit:75,51
ACallExpr ../src/test_parser.nit:76,2--30
AImplicitSelfExpr ../src/test_parser.nit:76,2
AParExprs ../src/test_parser.nit:76,7--30
TOpar "(" ../src/test_parser.nit:76,7
AStringExpr ../src/test_parser.nit:76,8--29
- TString "\" -h\11print this help\"" ../src/test_parser.nit:76,8--29
+ TString "\" -h\tprint this help\"" ../src/test_parser.nit:76,8--29
TCpar ")" ../src/test_parser.nit:76,30
AIfExpr ../src/test_parser.nit:77,6--146,3
TKwif "if" ../src/test_parser.nit:77,6--7
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import ios