From: Jean Privat Date: Fri, 28 Nov 2014 19:50:37 +0000 (-0500) Subject: Merge: FFI with C: fix line offset in gcc error reports X-Git-Tag: v0.6.11~6 X-Git-Url: http://nitlanguage.org?hp=35218d705459d7c74ee9cf5775b5b8ae98a6659a Merge: FFI with C: fix line offset in gcc error reports Pull-Request: #944 Reviewed-by: Jean Privat --- diff --git a/contrib/jwrapper/src/code_generator.nit b/contrib/jwrapper/src/code_generator.nit index 8192855..45ce666 100644 --- a/contrib/jwrapper/src/code_generator.nit +++ b/contrib/jwrapper/src/code_generator.nit @@ -221,7 +221,7 @@ class CodeGenerator # FIXME : This huge `if` block is only necessary to copy primitive arrays as long as there's no better way to do it if comment == "#" then - temp.add(" in \"Java\" `\{\n{comment}\t\trecv.{jmethod_id}({java_params}); \n{comment}\t`\}\n") + temp.add(" in \"Java\" `\{\n{comment}\t\trecv.{jmethod_id}({java_params});\n{comment}\t`\}\n") # Methods with return type else if return_type != null then if jreturn_type.is_primitive_array then @@ -238,7 +238,7 @@ class CodeGenerator temp.add(code_warehouse.param_type_copy(param_to_copy.first, param_to_copy.second, jmethod_id, java_params, true)) # No copy else - temp.add(" in \"Java\" `\{\n{comment}\t\treturn {jreturn_type.return_cast} recv.{jmethod_id}({java_params}); \n{comment}\t`\}\n") + temp.add(" in \"Java\" `\{\n{comment}\t\treturn {jreturn_type.return_cast} recv.{jmethod_id}({java_params});\n{comment}\t`\}\n") end # Methods without return type else if jreturn_type.is_void then @@ -247,11 +247,11 @@ class CodeGenerator temp.add(code_warehouse.param_type_copy(param_to_copy.first, param_to_copy.second, jmethod_id, java_params, false)) # No copy else - temp.add(" in \"Java\" `\{\n{comment}\t\trecv.{jmethod_id}({java_params}); \n{comment}\t`\}\n") + temp.add(" in \"Java\" `\{\n{comment}\t\trecv.{jmethod_id}({java_params});\n{comment}\t`\}\n") end # No copy else - temp.add(" in \"Java\" `\{\n{comment}\t\trecv.{jmethod_id}({java_params}); \n{comment}\t`\}\n") + temp.add(" in \"Java\" `\{\n{comment}\t\trecv.{jmethod_id}({java_params});\n{comment}\t`\}\n") end return temp.join("") diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 0000000..91ae0c8 --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,2 @@ +all: + ${MAKE} docs -C .. diff --git a/doc/README b/doc/README deleted file mode 100644 index 0e23e6a..0000000 --- a/doc/README +++ /dev/null @@ -1,6 +0,0 @@ -This directory contains various documentation for Nit - -* advanced_options [TXT]: documentation for advanced options of the compiler and run-time execution. -* stdlib [HTML]: Autodocumentation for the Nit standard library. - -For more documentation, visit http://nitlanguage.org/doc/ diff --git a/doc/README.md b/doc/README.md new file mode 100644 index 0000000..406cb02 --- /dev/null +++ b/doc/README.md @@ -0,0 +1,12 @@ +This directory contains auto-documentation generated by nitdoc. + + * [stdlib](http://nitlanguage.org/doc/stdlib/): the Nit libraries (from `../lib/`). + * [nitc](http://nitlanguage.org/doc/nitc/): the Nit tools (from `../src/`). + +Run `make` to produce them. + +Specific documentation can be found elsewhere: + + * The manpages of the Nit tools are in the directory `../share/man` + * The documentation of the other tools and programs are in their subdirectories in `../examples` and `../contrib` + * For more documentation, visit diff --git a/examples/calculator/Makefile b/examples/calculator/Makefile index 9782660..acb600b 100644 --- a/examples/calculator/Makefile +++ b/examples/calculator/Makefile @@ -1,3 +1,8 @@ all: mkdir -p bin/ - ../../bin/nitg --dir bin/ src/calculator_test.nit src/calculator_gtk.nit + ../../bin/nitg --dir bin/ src/calculator_gtk.nit src/calculator_test.nit + +android: + mkdir -p bin/ res/ + ../../contrib/inkscape_tools/bin/svg_to_icons art/icon.svg --android --out res/ + ../../bin/nitg -o bin/calculator.apk src/calculator_android.nit diff --git a/examples/calculator/art/icon.svg b/examples/calculator/art/icon.svg new file mode 100644 index 0000000..ccd533c --- /dev/null +++ b/examples/calculator/art/icon.svg @@ -0,0 +1,139 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + = + + diff --git a/examples/calculator/src/calculator_android.nit b/examples/calculator/src/calculator_android.nit new file mode 100644 index 0000000..e66fea8 --- /dev/null +++ b/examples/calculator/src/calculator_android.nit @@ -0,0 +1,108 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Copyright 2014 Alexis Laferrière +# +# 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. + +# Android calculator application +module calculator_android is + app_name "app.nit Calc." + app_version(0, 1, git_revision) + java_package "org.nitlanguage.calculator" + + # Use a translucent background and lock in portrait mode + android_manifest_activity """ + android:theme="@android:style/Theme.Holo.Wallpaper" + android:screenOrientation="portrait"""" +end + +import android +import android::ui + +import calculator_logic + +redef class App + private var context = new CalculatorContext + + # The main display, at the top of the screen + private var display: EditText + + # Maps operators as `String` to their `Button` + private var op2but = new HashMap[String, Button] + + # Has this window been initialized? + private var inited = false + + redef fun init_window + do + super + + if inited then return + inited = true + + # Setup UI + var context = native_activity + var layout = new NativeLinearLayout(context) + layout.set_vertical + + # Display screen + var display = new EditText + layout.add_view_with_weight(display.native, 1.0) + display.text_size = 36.0 + self.display = display + + # Buttons; numbers and operators + var ops = [["7", "8", "9", "+"], + ["4", "5", "6", "-"], + ["1", "2", "3", "*"], + ["0", ".", "C", "/"], + ["="]] + + for line in ops do + var buts_layout = new NativeLinearLayout(context) + buts_layout.set_horizontal + layout.add_view_with_weight(buts_layout, 1.0) + + for op in line do + var but = new Button + but.text = op + but.text_size = 40 + buts_layout.add_view_with_weight(but.native, 1.0) + op2but[op] = but + end + end + + context.content_view = layout + end + + redef fun catch_event(event) + do + if event isa ClickEvent then + var sender = event.sender + var op = sender.text + + if op == "." then + sender.enabled = false + context.switch_to_decimals + else if op.is_numeric then + var n = op.to_i + context.push_digit n + else + op2but["."].enabled = true + context.push_op op.chars.first + end + + display.text = context.display_text + end + end +end diff --git a/lib/a_star.nit b/lib/a_star.nit index 4108268..97925ff 100644 --- a/lib/a_star.nit +++ b/lib/a_star.nit @@ -57,14 +57,14 @@ module a_star # General graph node class Node + # Type of the others nodes in the `graph` type N: Node # parent graph var graph: Graph[N, Link] - init(graph: Graph[N, Link]) + init do - self.graph = graph graph.add_node(self) end @@ -186,29 +186,36 @@ end # Link between two nodes and associated to a graph class Link + # Type of the nodes in `graph` type N: Node + + # Type of the other links in `graph` type L: Link + # The graph to which belongs `self` var graph: Graph[N, L] + # Origin of this link var from: N + + # Endpoint of this link var to: N - init(graph: Graph[N, L], from, to: N) + init do - self.graph = graph - self.from = from - self.to = to - graph.add_link(self) end end # General graph class Graph[N: Node, L: Link] + # Nodes in this graph var nodes: Set[N] = new HashSet[N] + + # Links in this graph var links: Set[L] = new HashSet[L] + # Add a `node` to this graph fun add_node(node: N): N do nodes.add(node) @@ -216,6 +223,7 @@ class Graph[N: Node, L: Link] return node end + # Add a `link` to this graph fun add_link(link: L): L do links.add(link) @@ -225,20 +233,22 @@ class Graph[N: Node, L: Link] return link end - # used to check if nodes have been searched in one pathfinding - var pathfinding_current_evocation: Int = 0 + # Used to check if nodes have been searched in one pathfinding + private var pathfinding_current_evocation: Int = 0 end -# Result from pathfinding, a walkable path +# Result from path finding and a walkable path class Path[N] + # The total cost of this path var total_cost: Int + # The list of nodes composing this path var nodes = new List[N] - init (cost: Int) do total_cost = cost + private var at: Int = 0 - var at: Int = 0 + # Step on the path and get the next node to travel fun step: N do assert nodes.length >= at else print "a_star::Path::step failed, is at_end_of_path" @@ -249,16 +259,22 @@ class Path[N] return s end + # Peek at the next step of the path fun peek_step: N do return nodes[at] + # Are we at the end of this path? fun at_end_of_path: Bool do return at >= nodes.length end # Context related to an evocation of pathfinding class PathContext + # Type of the nodes in `graph` type N: Node + + # Type of the links in `graph` type L: Link + # Graph to which is associated `self` var graph: Graph[N, L] # Worst cost of all the link's costs @@ -273,6 +289,7 @@ class PathContext # Heuristic fun heuristic_cost(a, b: N): Int is abstract + # The worst cost suggested by the heuristic fun worst_heuristic_cost: Int is abstract end @@ -292,12 +309,13 @@ class ConstantPathContext redef fun worst_heuristic_cost do return 0 end +# A `PathContext` for graphs with `WeightedLink` class WeightedPathContext super PathContext redef type L: WeightedLink - init(graph: Graph[N, L]) + init do super @@ -309,7 +327,7 @@ class WeightedPathContext self.worst_cost = worst_cost end - redef var worst_cost: Int + redef var worst_cost: Int is noinit redef fun cost(l) do return l.weight @@ -319,17 +337,12 @@ class WeightedPathContext redef fun worst_heuristic_cost do return 0 end +# A `Link` with a `weight` class WeightedLink super Link + # The `weight`, or cost, of this link var weight: Int - - init(graph: Graph[N, L], from, to: N, weight: Int) - do - super - - self.weight = weight - end end # Advanced path conditions with customizable accept states diff --git a/lib/android/examples/Makefile b/lib/android/examples/Makefile new file mode 100644 index 0000000..5255657 --- /dev/null +++ b/lib/android/examples/Makefile @@ -0,0 +1,11 @@ +android: + mkdir -p bin/ res/ + ../../../contrib/inkscape_tools/bin/svg_to_icons art/icon.svg --android --out res/ + ../../../bin/nitg --dir bin/ src/ui_test.nit + adb install -r bin/ui_test.apk + +install: android + adb install -r bin/ui.apk + +clean: + rm -rf bin diff --git a/lib/android/examples/art/icon.svg b/lib/android/examples/art/icon.svg new file mode 100644 index 0000000..fb46e63 --- /dev/null +++ b/lib/android/examples/art/icon.svg @@ -0,0 +1,101 @@ + + + + + + + + + + image/svg+xml + + + + + + + + App + nit + UI + + diff --git a/lib/android/examples/src/ui_test.nit b/lib/android/examples/src/ui_test.nit new file mode 100644 index 0000000..f6c2a1b --- /dev/null +++ b/lib/android/examples/src/ui_test.nit @@ -0,0 +1,91 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Copyright 2014 Alexis Laferrière +# +# 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. + +# Test for app.nit's UI services +module ui_test is + app_name("app.nit UI test") + app_version(0, 1, git_revision) + java_package("org.nitlanguage.ui_test") + android_manifest_activity """android:theme="@android:style/Theme.Light"""" +end + +import android +import android::ui +import android::toast +import android::notification + +redef class App + + var but_notif: Button + var but_toast: Button + + var notif: nullable Notification = null + + var inited = false + redef fun init_window + do + super + + if inited then return + inited = true + + # Setup UI + var context = native_activity + var layout = new NativeLinearLayout(context) + layout.set_vertical + + but_notif = new Button + but_notif.text = "Show Notification" + layout.add_view but_notif.native + + but_toast = new Button + but_toast.text = "Show Toast" + layout.add_view but_toast.native + + context.content_view = layout + end + + fun act_notif + do + var notif = self.notif + if notif == null then + notif = new Notification("From app.nit", "Some content...") + notif.ticker = "Ticker text..." + notif.show + self.notif = notif + else + notif.cancel + self.notif = null + end + end + + fun act_toast + do + toast("Sample toast from app.nit at {get_time}", false) + end + + redef fun catch_event(event) + do + if event isa ClickEvent then + var sender = event.sender + if sender == but_notif then + act_notif + else if sender == but_toast then + act_toast + end + end + end +end diff --git a/lib/android/native_app_glue.nit b/lib/android/native_app_glue.nit index 50368de..fc5a19f 100644 --- a/lib/android/native_app_glue.nit +++ b/lib/android/native_app_glue.nit @@ -114,12 +114,22 @@ in "C body" `{ } `} +# An Android activity context +extern class NativeContext in "Java" `{ android.content.Context `} + super JavaObject +end + +# A wrapper of context +extern class NativeContextWrapper in "Java" `{ android.content.ContextWrapper `} + super NativeContext +end + # Android SDK's `android.app.NativeActivity`. # # Can be used to get anything related to the `Context` of the activity in Java # and as anchor to execute Java UI code. extern class NativeActivity in "Java" `{ android.app.NativeActivity `} - super JavaObject + super NativeContextWrapper end redef class App @@ -252,11 +262,11 @@ extern class NdkNativeActivity `{ ANativeActivity * `} # The `NativeActivity`, as in the Java object, associated to `self` fun java_native_activity: NativeActivity `{ return recv->clazz; `} - # Path to this application's internal data directory. + # Path to this application's internal data directory. fun internal_data_path: NativeString `{ return (char*)recv->internalDataPath; `} # Path to this application's external (removable/mountable) data directory. - fun external_data_path: NativeString `{ return (char*)recv->externalDataPath; `} + fun external_data_path: NativeString `{ return (char*)recv->externalDataPath; `} # The platform's SDK version code. fun sdk_version: Int `{ return recv->sdkVersion; `} diff --git a/lib/android/notification/native_notification.nit b/lib/android/notification/native_notification.nit new file mode 100644 index 0000000..988727f --- /dev/null +++ b/lib/android/notification/native_notification.nit @@ -0,0 +1,71 @@ +# This file is part of NIT (http://www.nitlanguage.org). +# +# Copyright 2014 Alexis Laferrière +# +# 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. + +# Native Java classes for notifications +module native_notification is min_api_version 11 + +import android::assets_and_resources + +in "Java" `{ + import android.content.Context; + import android.app.NotificationManager; + import android.app.Notification; +`} + +redef class NativeActivity + fun notification_manager: NativeNotificationManager in "Java" `{ + return (NotificationManager)recv.getSystemService(Context.NOTIFICATION_SERVICE); + `} +end + +extern class NativeNotificationManager in "Java" `{ android.app.NotificationManager `} + + fun notify(tag: JavaString, id: Int, notif: NativeNotification) in "Java" `{ + recv.notify(tag, (int)id, notif); + `} + + fun cancel(tag: JavaString, id: Int) in "Java" `{ recv.cancel(tag, (int)id); `} + + fun cancel_all in "Java" `{ recv.cancelAll(); `} +end + +extern class NativeNotification in "Java" `{ android.app.Notification `} +end + +extern class NativeNotificationBuilder in "Java" `{ android.app.Notification$Builder `} + + new (context: NativeActivity) in "Java" `{ return new Notification.Builder(context); `} + + fun create: NativeNotification in "Java" `{ + // Deprecated since API 16, which introduces `build`, + // refinement and global compilation should prevent warnings. + return recv.getNotification(); + `} + + fun title=(value: JavaString) in "Java" `{ recv.setContentTitle(value); `} + + fun text=(value: JavaString) in "Java" `{ recv.setContentText(value); `} + + fun ticker=(value: JavaString) in "Java" `{ recv.setTicker(value); `} + + fun small_icon=(value: Int) in "Java" `{ recv.setSmallIcon((int)value); `} + + fun auto_cancel=(value: Bool) in "Java" `{ recv.setAutoCancel(value); `} + + fun number=(value: Int) in "Java" `{ recv.setNumber((int)value); `} + + fun ongoing=(value: Bool) in "Java" `{ recv.setOngoing(value); `} +end diff --git a/lib/android/notification/notification.nit b/lib/android/notification/notification.nit new file mode 100644 index 0000000..07d1c00 --- /dev/null +++ b/lib/android/notification/notification.nit @@ -0,0 +1,132 @@ +# This file is part of NIT (http://www.nitlanguage.org). +# +# Copyright 2014 Alexis Laferrière +# +# 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. + +# Services to show notification in the Android status bar +# +# ~~~~ +# # Create and show a notification +# var notif = new Notification("My Title", "Some content") +# notif.ticker = "Ticker text" +# notif.show +# +# # Update the notification +# notif.text = "New content!" +# notif.ongoing = true # Make it un-dismissable +# nofif.show +# +# # Hide the notification +# notif.cancel +# ~~~~ +# +# For more information, see: +# http://developer.android.com/guide/topics/ui/notifiers/notifications.html +module notification + +import standard +private import native_notification + +# An Android notification, shown at the top of the screen +class Notification + # Title of this notification + var title: nullable Text is writable + + # Text content of this notification + var text: nullable Text is writable + + # Text to show in the bar as the notification appears + var ticker: nullable Text = null is writable + + # Name of a resource found in the `res/drawable-*` folders to use for the small icon + # + # By default, we use the app's icon, named "icon". A valid icon must be used + # to display notifications. + var small_icon: nullable Text = null is writable + + # Number to display on the bottom right part of the notification + var number: nullable Int = null is writable + + # Is this notification ongoing? Not user dismissable. + var ongoing: Bool = false is writable + + private var id: nullable Int = null + private var tag = "app.nit notification" + + # Show the notification + fun show + do + sys.jni_env.push_local_frame(8) + + var context = app.native_activity + var builder = new NativeNotificationBuilder(context) + + # If no custom icon is specified, use app's + var small_icon = self.small_icon + if small_icon == null then small_icon = "icon" + var small_icon_id = app.resource_manager.other_id(small_icon.to_s, "drawable") + builder.small_icon = small_icon_id + + # Other options + if title != null then builder.title = title.to_java_string + if text != null then builder.text = text.to_java_string + if ticker != null then builder.ticker = ticker.to_java_string + builder.ongoing = ongoing + + var notif = builder.create + var manager = context.notification_manager + + var id = self.id + if id == null then id = sys.next_notification_id + manager.notify(tag.to_java_string, id, notif) + + self.id = id + + sys.jni_env.pop_local_frame + end + + # Was this notification shown with `show`? + # + # This does not indicates whether is has been dismissed or not. Only that + # it was shown at least once. + private fun was_shown: Bool do return id != null + + # Cancel this notification and hide it if it is currently displayed + fun cancel + do + var id = self.id + if id != null then + sys.jni_env.push_local_frame(8) + + var manager = app.native_activity.notification_manager + manager.cancel(tag.to_java_string, id) + + self.id = null + + sys.jni_env.pop_local_frame + end + end +end + +redef class Sys + private var next_notification_id_cache = 0 + + # Returns a unique ID for new notifications + private fun next_notification_id: Int + do + var id = next_notification_id_cache + next_notification_id_cache = id + 1 + return id + end +end diff --git a/lib/android/toast.nit b/lib/android/toast.nit new file mode 100644 index 0000000..dd8e149 --- /dev/null +++ b/lib/android/toast.nit @@ -0,0 +1,49 @@ +# This file is part of NIT (http://www.nitlanguage.org). +# +# Copyright 2014 Alexis Laferrière +# +# 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. + +# Services to display a _toast_, a small popup on Android +module toast + +import native_app_glue + +in "Java" `{ + import android.widget.Toast; +`} + +redef class App + # Display a _toast_ with `message`, for longer if `is_long` + fun toast(message: String, is_long: Bool) + do + var jstr = message.to_java_string + native_toast(jstr, is_long) + jstr.delete_local_ref + end + + private fun native_toast(message: JavaString, is_long: Bool) + import native_activity in "Java" `{ + final android.app.NativeActivity context = App_native_activity(recv); + final CharSequence final_message = message; + final int duration = is_long? Toast.LENGTH_LONG: Toast.LENGTH_SHORT; + + context.runOnUiThread(new Runnable() { + @Override + public void run() { + Toast toast = Toast.makeText(context, final_message, duration); + toast.show(); + } + }); + `} +end diff --git a/lib/android/ui.nit b/lib/android/ui.nit new file mode 100644 index 0000000..b4ed822 --- /dev/null +++ b/lib/android/ui.nit @@ -0,0 +1,417 @@ +# This file is part of NIT (http://www.nitlanguage.org). +# +# Copyright 2014 Alexis Laferrière +# +# 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. + +# Views and services to use the Android native user interface +# +# Events, such as a button click, come from the UI thread and are then +# passed to the main thread. It is recommended to specialize one of the +# methods of the main thread to customize the response to a given event. +# +# This graph shows the path of a button click: +# ~~~ +# UI Thread # Main thread +# +# User +# | +# V +# Button::click_ui --> Button::click +# | +# V +# App::catch_event +# ~~~ +module ui is min_api_version 14 + +import native_app_glue +import pthreads::concurrent_collections + +in "Java" `{ + import android.app.NativeActivity; + + import android.view.Gravity; + import android.view.MotionEvent; + import android.view.ViewGroup; + import android.view.ViewGroup.MarginLayoutParams; + + import android.widget.Button; + import android.widget.LinearLayout; + import android.widget.GridLayout; + import android.widget.PopupWindow; + import android.widget.TextView; + + import java.lang.*; + import java.util.*; +`} + +# An event from the `app.nit` framework +interface AppEvent + # Reaction to this event + fun react do end +end + +# A control click event +class ClickEvent + super AppEvent + + # Sender of this event + var sender: Button + + redef fun react do sender.click self +end + +# Receiver of events not handled directly by the sender +interface EventCatcher + fun catch_event(event: AppEvent) do end +end + +redef class App + super EventCatcher + + # Queue of events to be received by the main thread + var event_queue = new ConcurrentList[AppEvent] + + # Call `react` on all `AppEvent` available in `event_queue` + protected fun loop_on_ui_callbacks + do + var queue = event_queue + while not queue.is_empty do + var event = queue.pop + event.react + end + end + + redef fun run + do + loop + # Process Android events + poll_looper 100 + + # Process app.nit events + loop_on_ui_callbacks + end + end +end + +redef extern class NativeActivity + + # Fill this entire `NativeActivity` with `popup` + # + # This is a workaround for the use on `takeSurface` in `NativeActivity.java` + # + # TODO replace NativeActivity by our own NitActivity + private fun dedicate_to_popup(popup: NativePopupWindow, popup_layout: NativeViewGroup) in "Java" `{ + final LinearLayout final_main_layout = new LinearLayout(recv); + final ViewGroup final_popup_layout = popup_layout; + final PopupWindow final_popup = popup; + final NativeActivity final_recv = recv; + + recv.runOnUiThread(new Runnable() { + @Override + public void run() { + MarginLayoutParams params = new MarginLayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.MATCH_PARENT); + + final_recv.setContentView(final_main_layout, params); + + final_popup.showAtLocation(final_popup_layout, Gravity.TOP, 0, 40); + } + }); + `} + + # Set the main layout of this activity + fun content_view=(layout: NativeViewGroup) + do + var popup = new NativePopupWindow(self) + popup.content_view = layout + dedicate_to_popup(popup, layout) + end + + # Set the real content view of this activity, without hack + # + # TODO bring use this instead of the hack with `dedicate_to_pupup` + private fun real_content_view=(layout: NativeViewGroup) in "Java" `{ + final ViewGroup final_layout = layout; + final NativeActivity final_recv = recv; + + recv.runOnUiThread(new Runnable() { + @Override + public void run() { + final_recv.setContentView(final_layout); + + final_layout.requestFocus(); + } + }); + `} +end + +# An `Object` that raises events +abstract class Eventful + var event_catcher: EventCatcher = app is lazy, writable +end + +# +## Nity classes and services +# + +# An Android control with text +abstract class TextView + super Finalizable + super Eventful + + # Native Java variant to this Nity class + type NATIVE: NativeTextView + + # The native Java object encapsulated by `self` + var native: NATIVE is noinit + + # Get the text of this view + fun text: String + do + var jstr = native.text + var str = jstr.to_s + jstr.delete_local_ref + return str + end + + # Set the text of this view + fun text=(value: Text) + do + var jstr = value.to_s.to_java_string + native.text = jstr + jstr.delete_local_ref + end + + # Get whether this view is enabled or not + fun enabled: Bool do return native.enabled + + # Set if this view is enabled + fun enabled=(val: Bool) do native.enabled = val + + # Set the size of the text in this view at `dpi` + fun text_size=(dpi: Numeric) do native.text_size = dpi.to_f + + private var finalized = false + redef fun finalize + do + if not finalized then + native.delete_global_ref + finalized = true + end + end +end + +# An Android button +class Button + super TextView + + redef type NATIVE: NativeButton + + init + do + var native = new NativeButton(app.native_activity, app.event_queue, self) + self.native = native.new_global_ref + end + + # Click event on the Main thread + # + # By default, this method calls `app.catch_event`. It can be specialized + # with custom behavior or the receiver of `catch_event` can be changed + # with `event_catcher=`. + fun click(event: AppEvent) do event_catcher.catch_event(event) + + # Click event on the UI thread + # + # This method is called on the UI thread and redirects the event to `click` + # throught `App::event_queue`. In most cases, you should implement `click` + # and leave `click_ui` as is. + fun click_ui do app.event_queue.add(new ClickEvent(self)) +end + +# An Android editable text field +class EditText + super TextView + + redef type NATIVE: NativeEditText + + init + do + var native = new NativeEditText(app.native_activity) + self.native = native.new_global_ref + end +end + +# +## Native classes +# + +# A `View` for Android +extern class NativeView in "Java" `{ android.view.View `} + super JavaObject + + fun minimum_width=(val: Int) in "Java" `{ recv.setMinimumWidth((int)val); `} + fun minimum_height=(val: Int) in "Java" `{ recv.setMinimumHeight((int)val); `} +end + +# A collection of `NativeView` +extern class NativeViewGroup in "Java" `{ android.view.ViewGroup `} + super NativeView + + fun add_view(view: NativeView) in "Java" `{ recv.addView(view); `} +end + +# A `NativeViewGroup` organized in a line +extern class NativeLinearLayout in "Java" `{ android.widget.LinearLayout `} + super NativeViewGroup + + new(context: NativeActivity) in "Java" `{ return new LinearLayout(context); `} + + fun set_vertical in "Java" `{ recv.setOrientation(LinearLayout.VERTICAL); `} + fun set_horizontal in "Java" `{ recv.setOrientation(LinearLayout.HORIZONTAL); `} + + redef fun add_view(view) in "Java" + `{ + MarginLayoutParams params = new MarginLayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT); + recv.addView(view, params); + `} + + fun add_view_with_weight(view: NativeView, weight: Float) + in "Java" `{ + recv.addView(view, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT, (float)weight)); + `} +end + +# A `NativeViewGroup` organized as a grid +extern class NativeGridLayout in "Java" `{ android.widget.GridLayout `} + super NativeViewGroup + + new(context: NativeActivity) in "Java" `{ return new android.widget.GridLayout(context); `} + + fun row_count=(val: Int) in "Java" `{ recv.setRowCount((int)val); `} + + fun column_count=(val: Int) in "Java" `{ recv.setColumnCount((int)val); `} + + redef fun add_view(view) in "Java" `{ recv.addView(view); `} +end + +extern class NativePopupWindow in "Java" `{ android.widget.PopupWindow `} + super NativeView + + new (context: NativeActivity) in "Java" `{ + PopupWindow recv = new PopupWindow(context); + recv.setWindowLayoutMode(LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.MATCH_PARENT); + recv.setClippingEnabled(false); + return recv; + `} + + fun content_view=(layout: NativeViewGroup) in "Java" `{ recv.setContentView(layout); `} +end + +extern class NativeTextView in "Java" `{ android.widget.TextView `} + super NativeView + + new (context: NativeActivity) in "Java" `{ return new TextView(context); `} + + fun text: JavaString in "Java" `{ return recv.getText().toString(); `} + + fun text=(value: JavaString) in "Java" `{ + + android.util.Log.d("Nity", "1"); + final TextView final_recv = recv; + final String final_value = value; + + android.util.Log.d("Nity", "4"); + ((NativeActivity)recv.getContext()).runOnUiThread(new Runnable() { + @Override + public void run() { + android.util.Log.d("Nity", "-5"); + android.util.Log.d("Nity", final_value); + android.util.Log.d("Nity", "-5.5"); + final_recv.setText(final_value); + android.util.Log.d("Nity", "-6"); + } + }); + android.util.Log.d("Nity", "7"); + `} + + fun enabled: Bool in "Java" `{ return recv.isEnabled(); `} + fun enabled=(value: Bool) in "Java" `{ + final TextView final_recv = recv; + final boolean final_value = value; + + ((NativeActivity)recv.getContext()).runOnUiThread(new Runnable() { + @Override + public void run() { + final_recv.setEnabled(final_value); + } + }); + `} + + fun gravity_center in "Java" `{ + recv.setGravity(Gravity.CENTER); + `} + + fun text_size=(dpi: Float) in "Java" `{ + recv.setTextSize(android.util.TypedValue.COMPLEX_UNIT_DIP, (float)dpi); + `} +end + +extern class NativeEditText in "Java" `{ android.widget.EditText `} + super NativeTextView + + redef type SELF: NativeEditText + + new (context: NativeActivity) in "Java" `{ return new android.widget.EditText(context); `} + + fun width=(val: Int) in "Java" `{ recv.setWidth((int)val); `} + + fun input_type_text in "Java" `{ recv.setInputType(android.text.InputType.TYPE_CLASS_TEXT); `} + + redef fun new_global_ref: SELF import sys, Sys.jni_env `{ + Sys sys = NativeEditText_sys(recv); + JNIEnv *env = Sys_jni_env(sys); + return (*env)->NewGlobalRef(env, recv); + `} +end + +extern class NativeButton in "Java" `{ android.widget.Button `} + super NativeTextView + + redef type SELF: NativeButton + + new (context: NativeActivity, queue: ConcurrentList[AppEvent], sender_object: Object) import Button.click_ui in "Java" `{ + final int final_sender_object = sender_object; + + return new Button(context){ + @Override + public boolean onTouchEvent(MotionEvent event) { + if(event.getAction() == MotionEvent.ACTION_DOWN) { + Button_click_ui(final_sender_object); + return true; + } + return false; + } + }; + `} + + redef fun new_global_ref: SELF import sys, Sys.jni_env `{ + Sys sys = NativeButton_sys(recv); + JNIEnv *env = Sys_jni_env(sys); + return (*env)->NewGlobalRef(env, recv); + `} +end diff --git a/lib/cpp.nit b/lib/cpp.nit index 3d4daf6..6fe897a 100644 --- a/lib/cpp.nit +++ b/lib/cpp.nit @@ -23,12 +23,14 @@ end extern class CppString in "C++" `{ std::string* `} end -redef class String - fun to_cpp_string: CppString do return to_cstring.to_cpp_string +redef class Text + # Get `self` as a `CppString` + fun to_cpp_string: CppString do return to_cstring.to_cpp_string(length) end redef class NativeString - fun to_cpp_string: CppString in "C++" `{ - return new std::string(recv); + # Get `self` as a `CppString` + fun to_cpp_string(length: Int): CppString in "C++" `{ + return new std::string(recv, length); `} end diff --git a/lib/emscripten.nit b/lib/emscripten.nit index d46f4d1..3fd2fff 100644 --- a/lib/emscripten.nit +++ b/lib/emscripten.nit @@ -14,6 +14,10 @@ # See the License for the specific language governing permissions and # limitations under the License. +# Platform for the _emscripten_ framework +# +# Importing this module from your project will tell _nitg_ to compile +# to JavaScript for the _emscripten_ framework. module emscripten is platform `{ @@ -21,12 +25,16 @@ module emscripten is platform #include `} -redef class String +redef class Text + # Run `self` as JavaScript code fun run_js do run_js_native(self.escape_to_js.to_cstring) + private fun run_js_native(script: NativeString) `{ emscripten_run_script(script); `} - fun escape_to_js: String do return self.replace('\n', "\\n") + # Escape the content of `self` to pass to JavaScript code + fun escape_to_js: Text do return replace('\n', "\\n") + # Raise a JavaScript alert fun alert do "alert('{self.escape_to_js}')".run_js end diff --git a/lib/gpio.nit b/lib/gpio.nit index 820f608..cea53cb 100644 --- a/lib/gpio.nit +++ b/lib/gpio.nit @@ -17,6 +17,8 @@ # GPIO related functionnalities module gpio +# A physical binary pin interface Pin + # Set the output of this pin fun write(high: Bool) is abstract end diff --git a/lib/hash_debug.nit b/lib/hash_debug.nit index 8426097..1626437 100644 --- a/lib/hash_debug.nit +++ b/lib/hash_debug.nit @@ -136,7 +136,7 @@ redef class HashCollection[K] # Count and update length of collisions for `node_at_idx` # Note for dynamic call-graph analysis: callers of this functions are # responsible of collisions. - private fun gt_collide(i: Int, k: K) + fun gt_collide(i: Int, k: K) do var c = _array[i] sys.gt_coll += 1 @@ -159,7 +159,7 @@ redef class HashCollection[K] # Count and update length of collisions for `store` # Note for dynamic call-graph analysis: callers of this functions are # responsible of collisions. - private fun st_collide(i: Int, n: N) + fun st_collide(i: Int, n: N) do var c = _array[i] sys.st_coll += 1 diff --git a/lib/libevent.nit b/lib/libevent.nit index 525915c..9ff7ed0 100644 --- a/lib/libevent.nit +++ b/lib/libevent.nit @@ -92,8 +92,9 @@ extern class NativeEventBase `{ struct event_base * `} # Create a new event_base to use with the rest of Libevent new `{ return event_base_new(); `} + + # Has `self` been correctly initialized? fun is_valid: Bool do return not address_is_null - #fun creation_ok # Event dispatching loop # @@ -154,7 +155,7 @@ class Connection # Write a string to the connection fun write(str: String) do - var res = native_buffer_event.write(str.to_cstring, str.length) + native_buffer_event.write(str.to_cstring, str.length) end # Write a file to the connection @@ -175,6 +176,7 @@ end # A buffer event structure, strongly associated to a connection, an input buffer and an output_buffer extern class NativeBufferEvent `{ struct bufferevent * `} + # Write `length` bytes of `line` fun write(line: NativeString, length: Int): Int `{ return bufferevent_write(recv, line, length); `} @@ -205,6 +207,7 @@ extern class NativeEvBuffer `{ struct evbuffer * `} fun length: Int `{ return evbuffer_get_length(recv); `} end +# An input buffer extern class InputNativeEvBuffer super NativeEvBuffer @@ -212,6 +215,7 @@ extern class InputNativeEvBuffer fun drain(length: Int) `{ evbuffer_drain(recv, length); `} end +# An output buffer extern class OutputNativeEvBuffer super NativeEvBuffer @@ -270,6 +274,7 @@ end # Factory to listen on sockets and create new `Connection` class ConnectionFactory + # The `NativeEventBase` for the dispatch loop of this factory var event_base: NativeEventBase # On new connection, create the handler `Connection` object diff --git a/lib/more_collections.nit b/lib/more_collections.nit index bd441a1..1bcc514 100644 --- a/lib/more_collections.nit +++ b/lib/more_collections.nit @@ -48,13 +48,19 @@ class MultiHashMap[K: Object, V] self[key] = res return res end - - init do end end # Simple way to store an `HashMap[K1, HashMap[K2, V]]` +# +# ~~~~ +# var hm2 = new HashMap2[Int, String, Float] +# hm2[1, "one"] = 1.0 +# hm2[2, "two"] = 2.0 +# assert hm2[1, "one"] == 1.0 +# assert hm2[2, "not-two"] == null +# ~~~~ class HashMap2[K1: Object, K2: Object, V] - private var level1: HashMap[K1, HashMap[K2, V]] = new HashMap[K1, HashMap[K2, V]] + private var level1 = new HashMap[K1, HashMap[K2, V]] # Return the value associated to the keys `k1` and `k2`. # Return `null` if no such a value. @@ -83,8 +89,16 @@ class HashMap2[K1: Object, K2: Object, V] end # Simple way to store an `HashMap[K1, HashMap[K2, HashMap[K3, V]]]` +# +# ~~~~ +# var hm3 = new HashMap3[Int, String, Int, Float] +# hm3[1, "one", 11] = 1.0 +# hm3[2, "two", 22] = 2.0 +# assert hm3[1, "one", 11] == 1.0 +# assert hm3[2, "not-two", 22] == null +# ~~~~ class HashMap3[K1: Object, K2: Object, K3: Object, V] - private var level1: HashMap[K1, HashMap2[K2, K3, V]] = new HashMap[K1, HashMap2[K2, K3, V]] + private var level1 = new HashMap[K1, HashMap2[K2, K3, V]] # Return the value associated to the keys `k1`, `k2`, and `k3`. # Return `null` if no such a value. @@ -112,6 +126,45 @@ class HashMap3[K1: Object, K2: Object, K3: Object, V] end # A map with a default value. +# +# ~~~~ +# var dm = new DefaultMap[String, Int](10) +# assert dm["a"] == 10 +# ~~~~ +# +# The default value is used when the key is not present. +# And getting a default value does not register the key. +# +# ~~~~ +# assert dm["a"] == 10 +# assert dm.length == 0 +# assert dm.has_key("a") == false +# ~~~~ +# +# It also means that removed key retrieve the default value. +# +# ~~~~ +# dm["a"] = 2 +# assert dm["a"] == 2 +# dm.keys.remove("a") +# assert dm["a"] == 10 +# ~~~~ +# +# Warning: the default value is used as is, so using mutable object might +# cause side-effects. +# +# ~~~~ +# var dma = new DefaultMap[String, Array[Int]](new Array[Int]) +# +# dma["a"].add(65) +# assert dma["a"] == [65] +# assert dma.default == [65] +# assert dma["c"] == [65] +# +# dma["b"] += [66] +# assert dma["b"] == [65, 66] +# assert dma.default == [65] +# ~~~~ class DefaultMap[K: Object, V] super HashMap[K, V] diff --git a/lib/mpi.nit b/lib/mpi.nit index 20ff9af..1d8c406 100644 --- a/lib/mpi.nit +++ b/lib/mpi.nit @@ -123,26 +123,34 @@ class MPI return deserialized end + # Send an empty buffer, only for the `tag` fun send_empty(dest: Rank, tag: Tag, comm: Comm): SuccessOrError `{ return MPI_Send(NULL, 0, MPI_CHAR, dest, tag, comm); `} + # Receive an empty buffer, only for the `tag` fun recv_empty(dest: Rank, tag: Tag, comm: Comm): SuccessOrError `{ return MPI_Recv(NULL, 0, MPI_CHAR, dest, tag, comm, MPI_STATUS_IGNORE); `} - fun native_send(data: NativeCArray, count: Int, data_type: DataType, dest: Rank, tag: Tag, comm: Comm): SuccessOrError + # Send a `NativeCArray` `buffer` with a given `count` of `data_type` + fun native_send(buffer: NativeCArray, count: Int, data_type: DataType, dest: Rank, tag: Tag, comm: Comm): SuccessOrError `{ - return MPI_Send(data, count, data_type, dest, tag, comm); + return MPI_Send(buffer, count, data_type, dest, tag, comm); `} - fun native_recv(data: NativeCArray, count: Int, data_type: DataType, dest: Rank, tag: Tag, comm: Comm, status: Status): SuccessOrError + # Receive into a `NativeCArray` `buffer` with a given `count` of `data_type` + fun native_recv(buffer: NativeCArray, count: Int, data_type: DataType, dest: Rank, tag: Tag, comm: Comm, status: Status): SuccessOrError `{ - return MPI_Recv(data, count, data_type, dest, tag, comm, status); + return MPI_Recv(buffer, count, data_type, dest, tag, comm, status); `} + # Probe for the next data to receive, store the result in `status` + # + # Note: If you encounter an error where the next receive does not correspond + # to the last `probe`, call this method twice to ensure a correct result. fun probe(source: Rank, tag: Tag, comm: Comm, status: Status): SuccessOrError `{ return MPI_Probe(source, tag, comm, status); @@ -157,8 +165,13 @@ end # An MPI communicator extern class Comm `{ MPI_Comm `} + # The _null_ communicator, targeting no processors new null_ `{ return MPI_COMM_NULL; `} + + # The _world_ communicator, targeting all processors new world `{ return MPI_COMM_WORLD; `} + + # The _self_ communicator, targeting this processor only new self_ `{ return MPI_COMM_SELF; `} # Number of processors in this communicator @@ -278,6 +291,7 @@ end # An MPI rank within a communcator extern class Rank `{ int `} + # Special rank accepting any processor new any `{ return MPI_ANY_SOURCE; `} # This Rank as an `Int` @@ -287,6 +301,7 @@ end # An MPI tag, can be defined using `Int::tag` extern class Tag `{ int `} + # Special tag accepting any tag new any `{ return MPI_ANY_TAG; `} # This tag as an `Int` diff --git a/lib/ordered_tree.nit b/lib/ordered_tree.nit index 34ca522..5c42f46 100644 --- a/lib/ordered_tree.nit +++ b/lib/ordered_tree.nit @@ -21,24 +21,57 @@ module ordered_tree # # Ordered tree are tree where the elements of a same parent are in a specific order # -# The class can be used as it to work with generic tree. -# The class can also be specialized to provide more specific behavior. +# Elements of the trees are added with the `add` method that takes a parent and +# a sub-element. +# If the parent is `null`, then the element is considered a root. +# +# ~~~~ +# var t = new OrderedTree[String] +# t.add(null, "root") +# t.add("root", "child1") +# t.add("root", "child2") +# t.add("child1", "grand-child") +# assert t.length == 4 +# ~~~~ +# +# By default, the elements with a same parent +# are visited in the order they are added. +# +# ~~~ +# assert t.to_a == ["root", "child1", "grand-child", "child2"] +# assert t.write_to_string == """ +# root +# |--child1 +# | `--grand-child +# `--child2 +# """ +# ~~~ +# +# The `sort_with` method can be used reorder elements +# +# ~~~ +# t.add("root", "aaa") +# assert t.to_a == ["root", "child1", "grand-child", "child2", "aaa"] +# t.sort_with(alpha_comparator) +# assert t.to_a == ["root", "aaa", "child1", "grand-child", "child2"] +# ~~~ +# +# This class can be used as it to work with generic trees but can also be specialized to provide more specific +# behavior or display. It is why the internal attributes are mutable. class OrderedTree[E: Object] super Streamable super Collection[E] - # Sequence + # The roots of the tree (in sequence) var roots = new Array[E] + + # The branches of the trees. + # For each element, the ordered array of its direct sub-elements. var sub = new HashMap[E, Array[E]] - # Add a new element `e` in the tree + # Add a new element `e` in the tree. # `p` is the parent of `e`. # if `p` is null, then `e` is a root element. - # - # By defauld, the elements with a same parent - # are displayed in the order they are added. - # - # The `sort_with` method can be used reorder elements fun add(p: nullable E, e: E) do if p == null then @@ -54,7 +87,6 @@ class OrderedTree[E: Object] # Write a ASCII-style tree and use the `display` method to label elements redef fun write_to(stream: OStream) do - var last = roots.last for r in roots do stream.write display(r) stream.write "\n" diff --git a/lib/pipeline.nit b/lib/pipeline.nit index 31d007b..be553ad 100644 --- a/lib/pipeline.nit +++ b/lib/pipeline.nit @@ -14,9 +14,8 @@ # Pipelined filters and operations on iterators. # -# This module enhance `Iterator`s with some methods that enable a -# pipeline-like programing that offers the manupulation of -# collections trough connected filters with reasonable memory constraints. +# This module enhances `Iterator` with some methods that enable a pipeline-like programing. +# The processing of elements in a pipeline is done trough connected filters that are implemented with reasonable memory constraints. module pipeline redef interface Iterator[E] @@ -35,6 +34,8 @@ redef interface Iterator[E] # Filter: sort with a given `comparator`. # Important: require O(n) memory. + # + # assert ["a", "c", "b"].iterator.sort_with(alpha_comparator).to_a == ["a", "b", "c"] fun sort_with(comparator: Comparator): Iterator[E] do var a = self.to_a diff --git a/lib/poset.nit b/lib/poset.nit index 9549e48..c6fd1d2 100644 --- a/lib/poset.nit +++ b/lib/poset.nit @@ -17,11 +17,60 @@ # Pre order sets and partial order set (ie hierarchies) module poset -# Preorder set graph. -# This class modelize an incremental preorder graph where new node and edges can be added (but no removal) -# Preorder graph has two caracteristics: +# Pre-order set graph. +# This class models an incremental pre-order graph where new nodes and edges can be added (but not removed). +# Pre-order graph has two characteristics: # * reflexivity: an element is in relation with itself (ie `self.has(e) implies self.has_edge(e,e)`) # * transitivity: `(self.has_edge(e,f) and self.has_edge(f,g)) implies self.has_edge(e,g)` +# +# Nodes and edges are added to the POSet. +# +# ~~~ +# var pos = new POSet[String] +# pos.add_edge("A", "B") # add A->B +# pos.add_edge("B", "C") # add B->C +# pos.add_node("D") # add unconnected node "D" +# +# # A -> B -> C D +# +# assert pos.has_edge("A", "B") == true # direct +# ~~~ +# +# Since a poset is transitive, direct and indirect edges are considered by default. +# Direct edges (transitive-reduction) can also be considered independently. +# +# ~~~ +# assert pos.has_edge("A", "C") == true # indirect +# assert pos.has_edge("A", "D") == false # no edge +# assert pos.has_edge("B", "A") == false # edges are directed +# +# assert pos.has_direct_edge("A", "B") == true # direct +# assert pos.has_direct_edge("A", "C") == false # indirect +# ~~~ +# +# POSet are dynamic. +# It means that the transitivity is updated while new nodes and edges are added. +# The transitive-reduction (*direct edges*)) is also updated, +# so adding new edges can make some direct edge to disappear. +# +# ~~~ +# pos.add_edge("A","D") +# pos.add_edge("D","B") +# pos.add_edge("A","E") +# pos.add_edge("E","C") +# +# # A -> D -> B +# # | | +# # v v +# # E ------> C +# +# assert pos.has_edge("D", "C") == true # new indirect edge +# assert pos.has_edge("A", "B") == true # still an edge +# assert pos.has_direct_edge("A", "B") == false # but no-more a direct one +# ~~~ +# +# Thanks to the `[]` method, elements can be considered relatively to the poset. +# SEE `POSetElement` class POSet[E: Object] super Collection[E] super Comparator @@ -31,7 +80,7 @@ class POSet[E: Object] redef fun iterator do return elements.keys.iterator # All the nodes - private var elements: HashMap[E, POSetElement[E]] = new HashMap[E, POSetElement[E]] + private var elements = new HashMap[E, POSetElement[E]] redef fun has(e) do return self.elements.keys.has(e) @@ -50,14 +99,15 @@ class POSet[E: Object] end # Return a view of `e` in the poset. - # This allows to asks manipulate elements in thier relation with others elements. + # This allows to view the elements in their relation with others elements. # - # var poset: POSet[Something] # ... - # for x in poset do - # for y in poset[x].direct_greaters do - # print "{x} -> {y}" - # end - # end + # var poset = new POSet[String] + # poset.add_chain(["A", "B", "D"]) + # poset.add_chain(["A", "C", "D"]) + # var a = poset["A"] + # assert a.direct_greaters.has_exactly(["B", "C"]) + # assert a.greaters.has_exactly(["A", "B", "C", "D"]) + # assert a.direct_smallers.is_empty # # REQUIRE: has(e) fun [](e: E): POSetElement[E] @@ -69,9 +119,18 @@ class POSet[E: Object] # Add an edge from `f` to `t`. # Because a POSet is transitive, all transitive edges are also added to the graph. # If the edge already exists, the this function does nothing. + # + # ~~~ + # var pos = new POSet[String] + # pos.add_edge("A", "B") # add A->B + # assert pos.has_edge("A", "C") == false + # pos.add_edge("B", "C") # add B->C + # assert pos.has_edge("A", "C") == true + # ~~~ + # # If a reverse edge (from `t` to `f`) already exists, a loop is created. # - # FIXME: Do somethind clever to manage loops. + # FIXME: Do something clever to manage loops. fun add_edge(f, t: E) do var fe = add_node(f) @@ -108,8 +167,38 @@ class POSet[E: Object] te.dfroms.add f end + # Add an edge between all elements of `es` in order. + # + # ~~~~ + # var pos = new POSet[String] + # pos.add_chain(["A", "B", "C", "D"]) + # assert pos.has_direct_edge("A", "B") + # assert pos.has_direct_edge("B", "C") + # assert pos.has_direct_edge("C", "D") + # ~~~~ + fun add_chain(es: SequenceRead[E]) + do + if es.is_empty then return + var i = es.iterator + var e = i.item + i.next + for f in i do + add_edge(e, f) + e = f + end + end + # Is there an edge (transitive or not) from `f` to `t`? + # + # SEE: `add_edge` + # # Since the POSet is reflexive, true is returned if `f == t`. + # + # ~~~ + # var pos = new POSet[String] + # pos.add_node("A") + # assert pos.has_edge("A", "A") == true + # ~~~ fun has_edge(f,t: E): Bool do if not elements.keys.has(f) then return false @@ -118,6 +207,15 @@ class POSet[E: Object] end # Is there a direct edge from `f` to `t`? + # + # ~~~ + # var pos = new POSet[String] + # pos.add_chain(["A", "B", "C"]) # add A->B->C + # assert pos.has_direct_edge("A", "B") == true + # assert pos.has_direct_edge("A", "C") == false + # assert pos.has_edge("A", "C") == true + # ~~~ + # # Note that because of loops, the result may not be the expected one. fun has_direct_edge(f,t: E): Bool do @@ -163,12 +261,32 @@ class POSet[E: Object] end # Compare two elements in an arbitrary total order. - # Tis function is mainly used to sort elements of the set in an arbitrary linear extension. - # if ab then return 1 + # + # This function is mainly used to sort elements of the set in an coherent way. + # + # ~~~~ + # var pos = new POSet[String] + # pos.add_chain(["A", "B", "C", "D", "E"]) + # pos.add_chain(["A", "X", "C", "Y", "E"]) + # var a = ["X", "C", "E", "A", "D"] + # pos.sort(a) + # assert a == ["E", "D", "C", "X", "A"] + # ~~~~ + # + # POSet are not necessarily total orders because some distinct elements may be incomparable (neither greater or smaller). + # Therefore this method relies on arbitrary linear extension. + # This linear extension is a lawful total order (transitive, anti-symmetric, reflexive, and total), so can be used to compare the elements. + # + # The abstract behavior of the method is thus the following: + # + # ~~~~nitish # if a == b then return 0 - # else return -1 or 1 - # The total order is stable unless a new node or a new edge is added + # if has_edge(b, a) then return -1 + # if has_edge(a, b) then return 1 + # return -1 or 1 # according to the linear extension. + # ~~~~ + # + # Note that the linear extension is stable, unless a new node or a new edge is added. redef fun compare(a, b: E): Int do var ae = self.elements[a] @@ -203,6 +321,8 @@ class POSet[E: Object] return res end + # Filter elements to return only the greatest ones + # # ~~~ # var s = new POSet[String] # s.add_edge("B", "A") @@ -213,7 +333,6 @@ class POSet[E: Object] # assert s.select_greatest(["A", "B", "C"]) == ["A"] # assert s.select_greatest(["B", "C", "D"]) == ["B", "C"] # ~~~ - # Filter elements to return only the greatest ones fun select_greatest(elements: Collection[E]): Array[E] do var res = new Array[E] @@ -228,6 +347,13 @@ class POSet[E: Object] end # Sort a sorted array of poset elements using linearization order + # ~~~~ + # var pos = new POSet[String] + # pos.add_chain(["A", "B", "C", "D", "E"]) + # pos.add_chain(["A", "X", "C", "Y", "E"]) + # var a = pos.linearize(["X", "C", "E", "A", "D"]) + # assert a == ["E", "D", "C", "X", "A"] + # ~~~~ fun linearize(elements: Collection[E]): Array[E] do var lin = elements.to_a sort(lin) @@ -265,12 +391,24 @@ class POSetElement[E: Object] # Return the set of all elements `t` that have an edge from `element` to `t`. # Since the POSet is reflexive, element is included in the set. + # + # ~~~~ + # var pos = new POSet[String] + # pos.add_chain(["A", "B", "C", "D"]) + # assert pos["B"].greaters.has_exactly(["B", "C", "D"]) + # ~~~~ fun greaters: Collection[E] do return self.tos end # Return the set of all elements `t` that have a direct edge from `element` to `t`. + # + # ~~~~ + # var pos = new POSet[String] + # pos.add_chain(["A", "B", "C", "D"]) + # assert pos["B"].direct_greaters.has_exactly(["C"]) + # ~~~~ fun direct_greaters: Collection[E] do return self.dtos @@ -278,30 +416,67 @@ class POSetElement[E: Object] # Return the set of all elements `f` that have an edge from `f` to `element`. # Since the POSet is reflexive, element is included in the set. + # + # ~~~~ + # var pos = new POSet[String] + # pos.add_chain(["A", "B", "C", "D"]) + # assert pos["C"].smallers.has_exactly(["A", "B", "C"]) + # ~~~~ fun smallers: Collection[E] do return self.froms end # Return the set of all elements `f` that have an edge from `f` to `element`. + # + # ~~~~ + # var pos = new POSet[String] + # pos.add_chain(["A", "B", "C", "D"]) + # assert pos["C"].direct_smallers.has_exactly(["B"]) + # ~~~~ fun direct_smallers: Collection[E] do return self.dfroms end # Is there an edge from `element` to `t`? + # + # ~~~~ + # var pos = new POSet[String] + # pos.add_chain(["A", "B", "C", "D"]) + # assert pos["B"] <= "D" + # assert pos["B"] <= "C" + # assert pos["B"] <= "B" + # assert not pos["B"] <= "A" + # ~~~~ fun <=(t: E): Bool do return self.tos.has(t) end # Is `t != element` and is there an edge from `element` to `t`? + # + # ~~~~ + # var pos = new POSet[String] + # pos.add_chain(["A", "B", "C", "D"]) + # assert pos["B"] < "D" + # assert pos["B"] < "C" + # assert not pos["B"] < "B" + # assert not pos["B"] < "A" + # ~~~~ fun <(t: E): Bool do return t != self.element and self.tos.has(t) end # The length of the shortest path to the root of the poset hierarchy + # + # ~~~~ + # var pos = new POSet[String] + # pos.add_chain(["A", "B", "C", "D"]) + # assert pos["A"].depth == 3 + # assert pos["D"].depth == 0 + # ~~~~ fun depth: Int do if direct_greaters.is_empty then return 0 diff --git a/lib/privileges.nit b/lib/privileges.nit index 7a5503f..f17a28e 100644 --- a/lib/privileges.nit +++ b/lib/privileges.nit @@ -75,8 +75,11 @@ class OptionUserAndGroup redef type VALUE: nullable UserGroup - init for_dropping_privileges do init("Drop privileges to user:group or simply user", "-u", "--usergroup") - init(help: String, names: String...) do super(help, null, names) + # Create an `OptionUserAndGroup` for dropping privileges + init for_dropping_privileges + do + init("Drop privileges to user:group or simply user", null, ["-u", "--usergroup"]) + end redef fun convert(str) do @@ -87,8 +90,7 @@ class OptionUserAndGroup return new UserGroup(words[0], words[1]) else errors.add("Option {names.join(", ")} expected parameter in the format \"user:group\" or simply \"user\".\n") - abort # FIXME only for nitc, remove and replace with next line when FFI is working in nitg - #return null + return null end end end diff --git a/lib/sqlite3/sqlite3.nit b/lib/sqlite3/sqlite3.nit index 05cbed0..23b1ef7 100644 --- a/lib/sqlite3/sqlite3.nit +++ b/lib/sqlite3/sqlite3.nit @@ -114,8 +114,6 @@ end class Statement private var native_statement: NativeStatement - private init(ns: NativeStatement) do self.native_statement = ns - # Is this statement usable? var is_open = true @@ -134,12 +132,11 @@ class Statement end end +# A row from a `Statement` class StatementRow # Statement linked to `self` var statement: Statement - private init(s: Statement) do self.statement = s - # Number of entries in this row # # require: `self.statement.is_open` @@ -161,12 +158,6 @@ class StatementEntry private var index: Int - private init(s: Statement, i: Int) - do - self.statement = s - self.index = i - end - # Name of the column # # require: `self.statement.is_open` @@ -258,17 +249,15 @@ class StatementIterator # Statement linked to `self` var statement: Statement - private init(s: Statement) + init do - self.statement = s - self.item = new StatementRow(s) - + self.item = new StatementRow(statement) self.is_ok = statement.native_statement.step.is_row end - redef var item: StatementRow + redef var item: StatementRow is noinit - redef var is_ok: Bool + redef var is_ok: Bool is noinit # require: `self.statement.is_open` redef fun next @@ -310,12 +299,9 @@ end class Blob super Sqlite3Data - private init(pointer: Pointer, length: Int) - do - self.pointer = pointer - self.length = length - end - + # Pointer to the beginning of the blob var pointer: Pointer + + # Size of the blob var length: Int end diff --git a/lib/standard/collection/abstract_collection.nit b/lib/standard/collection/abstract_collection.nit index 56633ce..fa16295 100644 --- a/lib/standard/collection/abstract_collection.nit +++ b/lib/standard/collection/abstract_collection.nit @@ -123,17 +123,48 @@ interface Collection[E] return iterator.item end - # Is the collection contains all the elements of `other`? + # Does the collection contain at least each element of `other`? # - # assert [1,1,1].has_all([1]) == true - # assert [1,1,1].has_all([1,2]) == false # assert [1,3,4,2].has_all([1..2]) == true # assert [1,3,4,2].has_all([1..5]) == false + # + # Repeated elements in the collections are not considered. + # + # assert [1,1,1].has_all([1]) == true + # assert [1..5].has_all([1,1,1]) == true + # + # Note that the default implementation is general and correct for any lawful Collections. + # It is memory-efficient but relies on `has` so may be CPU-inefficient for some kind of collections. fun has_all(other: Collection[E]): Bool do for x in other do if not has(x) then return false return true end + + # Does the collection contain exactly all the elements of `other`? + # + # The same elements must be present in both `self` and `other`, + # but the order of the elements in the collections are not considered. + # + # assert [1..3].has_exactly([3,1,2]) == true # the same elements + # assert [1..3].has_exactly([3,1]) == false # 2 is not in the array + # assert [1..2].has_exactly([3,1,2]) == false # 3 is not in the range + # + # Repeated elements must be present in both collections in the same amount. + # So basically it is a multi-set comparison. + # + # assert [1,2,3,2].has_exactly([1,2,2,3]) == true # the same elements + # assert [1,2,3,2].has_exactly([1,2,3]) == false # more 2 in the first array + # assert [1,2,3].has_exactly([1,2,2,3]) == false # more 2 in the second array + # + # Note that the default implementation is general and correct for any lawful Collections. + # It is memory-efficient but relies on `count` so may be CPU-inefficient for some kind of collections. + fun has_exactly(other: Collection[E]): Bool + do + if length != other.length then return false + for e in self do if self.count(e) != other.count(e) then return false + return true + end end # Instances of the Iterator class generates a series of elements, one at a time.