Fix a wrong `useless-type` warning for attributes.
Extends the `useless-type` warning to local variables.
Pull-Request: #945
# #
# C L A S S H E A D E R #
# #
+
redef class Nclass_header
redef fun accept_visitor(v)
do
#
# The generated tree will be something like this:
#
- # <ul>
- # <li>section 1</li>
- # <li>section 2
- # <ul>
- # <li>section 2.1</li>
- # <li>section 2.2</li>
- # </ul>
- # </li>
- # </ul>
+ # ~~~html
+ # <ul>
+ # <li>section 1</li>
+ # <li>section 2
+ # <ul>
+ # <li>section 2.1</li>
+ # <li>section 2.2</li>
+ # </ul>
+ # </li>
+ # </ul>
+ # ~~~
fun tpl_tree(limit: Int): Template do
return tpl_tree_intern(limit, 1)
end
--- /dev/null
+all:
+ ${MAKE} docs -C ..
+++ /dev/null
-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/
--- /dev/null
+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 <http://nitlanguage.org/doc/>
# 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
# 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)
return node
end
+ # Add a `link` to this graph
fun add_link(link: L): L
do
links.add(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"
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
# 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
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
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
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
# 2. Apply the method `run`, that will search and return a solution.
# 3. Retrieve information from the solution.
#
-# ~~~~
+# ~~~~nitish
# var p: BacktrackProblem = new MyProblem
# var solver = p.solve
# var res = solver.run
# The constraint is that two queens cannot be on the same row, column or diagonal.
#
# Eg. a solution to the 8-queens problem is
-# ~~~
+# ~~~raw
# +--------+
# |Q.......|
# |....Q...|
# 2. Apply the method `run`, that will search and return a solution.
# 3. Retrieve information from the solution.
#
-# ~~~~
+# ~~~~nitish
# var p: SearchProblem = new MyProblem
# var res = p.astar.run
# if res != null then print "Found plan with {res.depth} actions, that cost {res.cost}: {res.plan.join(", ")}"
# The general action to be performed
#
- # Example :
- # ~~~
+ # ~~~nitish
+ # # TODO better example
# intent.action = intent_action.view.to_s
# ~~~
fun action=(action: String)
# Add category to the intent
# Only activities providing all of the requested categories will be used
#
- # Example :
- # ~~~
+ # ~~~nitish
+ # # TODO better example
# intent.add_category(intent_category.home.to_s)
# ~~~
# Returns `self` allowing fluent programming
# Add a flag to be used by the intent
#
- # Example :
- # ~~~
+ # ~~~nitish
+ # # TODO better example
# intent.add_flags(intent_flag.activity_new_task)
# ~~~
# Returns `self` allowing fluent programming
# Services to show notification in the Android status bar
#
-# ~~~~
+# ~~~~nitish
# # Create and show a notification
# var notif = new Notification("My Title", "Some content")
# notif.ticker = "Ticker text"
# # Update the notification
# notif.text = "New content!"
# notif.ongoing = true # Make it un-dismissable
-# nofif.show
+# notif.show
#
# # Hide the notification
# notif.cancel
# The sensor support is implemented in android_app module, so the user can enable the type of sensor he wants to use.
# There is an example of how you can use the android sensors in nit/examples/mnit_ballz :
#
-# ~~~~
+# ~~~~nitish
+# #FIXME rewrite the example
# var app = new MyApp
# app.sensors_support_enabled = true
# app.accelerometer.enabled = true
#
# User has to manage local stack deallocation himself
#
- # Example :
- # ~~~
+ # ~~~nitish
# var foo = new HashMap[JavaString, JavaObject]
# # ...
# for key, value in foo do
# key.delete_local_ref
# value.delete_local_ref
# end
- #Â ~~~
+ # ~~~
# *You should use Nit getters instead and get each value one by one*
fun all: nullable HashMap[JavaString, JavaObject]
do
#
# User has to manage local stack deallocation himself
#
- # Example :
- # ~~~
- # var a_hash_set = shared_preferences.string_set("A key")
- # ...
+ # ~~~nitish
+ # var a_hash_set = app.shared_preferences.string_set("A key")
+ # # ...
# for element in a_hash_set do element.delete_local_ref
# ~~~
fun string_set(key: String): HashSet[JavaString]
#
# User has to manage local stack deallocation himself
#
- # Example :
- # ~~~
+ # ~~~nitish
# var foo = new HashSet[JavaString]
- # shared_preferences.add_string_set("A key", foo)
+ # app.shared_preferences.add_string_set("A key", foo)
# for element in foo do element.delete_local_ref
# ~~~
fun add_string_set(key: String, value: HashSet[JavaString]): SharedPreferences
# methods of the main thread to customize the response to a given event.
#
# This graph shows the path of a button click:
-# ~~~
+# ~~~raw
# UI Thread # Main thread
#
# User
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
# 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
`{
#include <gc.h>
`}
-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
self.top >= other.bottom and other.top >= self.bottom
end
- # Create a bounding box that englobes the actual bounding box.
+ # Create a bounding box that encloses the actual bounding box.
# `dist` is the distance between the inner boundaries and the outer boundaries.
# ~~~
# var p = new Point[Int](5,10)
# var b = p.padded(3)
- # assert b.top == 2 and b.bot = 8 and b.left == 7 and b.right == 13
+ # assert b.left == 2 and b.right == 8 and b.top == 13 and b.bottom == 7
# ~~~
fun padded(dist: N): Box[N] do return new Box[N].lrtb(left - dist, right + dist, top + dist, bottom - dist)
end
# GPIO related functionnalities
module gpio
+# A physical binary pin
interface Pin
+ # Set the output of this pin
fun write(high: Bool) is abstract
end
# 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
# 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
#
# require: `self.is_numeric`
#
- # assert "1.234".to_json_value.to_numeric = 1.234
- # assert "1234".to_json_value.to_numeric = 1234
+ # assert "1.234".to_json_value.to_numeric == 1.234
+ # assert "1234".to_json_value.to_numeric == 1234
fun to_numeric: Numeric
do
if is_int then return to_i
# Utility to select options to create the VM using `create_jvm`
#
# Usage example:
-# ~~~~
+#
+# ~~~~nitish
# var builder = new JavaVMBuilder
# builder.options.add "-Djava.class.path=."
# var jvm = builder.create_jvm
# 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
#
# 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
# 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);
`}
fun length: Int `{ return evbuffer_get_length(recv); `}
end
+# An input buffer
extern class InputNativeEvBuffer
super NativeEvBuffer
fun drain(length: Int) `{ evbuffer_drain(recv, length); `}
end
+# An output buffer
extern class OutputNativeEvBuffer
super NativeEvBuffer
# 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
# A Link Reference.
# Links that are specified somewhere in the mardown document to be reused as shortcuts.
#
-# Example:
-#
-# [1]: http://example.com/ "Optional title"
+# ~~~raw
+# [1]: http://example.com/ "Optional title"
+# ~~~
class LinkRef
# Link href
#
# The input event file is made of event descriptions, one event by line.
#
-# ~~~
+# ~~~raw
# 10 click 10.0 20.0
# 20 quit
# ~~~
# Draw image by specifying the positon of each image corners
# Corners are in counter-clockwise order stating top left
# a is top left, b is bottom left, c is bottom right and d is top right
- # ~~~
+ # ~~~raw
# a-d
# | |
# b-c
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.
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.
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]
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);
# 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
# 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`
# 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`
#
# 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
# 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"
# 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]
# 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
# 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.
-#
-# Targets the PNaCl platform
+
+# Provides PNaCl support for Nit.
#
# To use this module and compile for PNaCl, you must install the
# NaCl SDK (This file is based on Pepper 33).
# If NACL_SDK_ROOT is not set in your PATH, you have to work in
# 'nacl_sdk/pepper_your_pepper_version/getting_started/your_project_folder'.
-#
-# Provides PNaCl support for Nit.
module pnacl is platform
import standard
# 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
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)
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]
# 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)
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
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
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 a<b then return -1
- # if a>b 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]
return res
end
+ # Filter elements to return only the greatest ones
+ #
# ~~~
# var s = new POSet[String]
# s.add_edge("B", "A")
# 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]
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)
#
# For instance, one common usage is to add a specific attribute for each poset a class belong.
#
-# class Thing
-# var in_some_relation: POSetElement[Thing]
-# var in_other_relation: POSetElement[Thing]
-# end
-# var t: Thing # ...
-# t.in_some_relation.greaters
-#
+# ~~~nitish
+# class Thing
+# var in_some_relation: POSetElement[Thing]
+# var in_other_relation: POSetElement[Thing]
+# end
+# var t: Thing
+# # ...
+# t.in_some_relation.greaters
+# ~~~
class POSetElement[E: Object]
# The poset self belong to
var poset: POSet[E]
# 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
# 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
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
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
# can use it to make a persistent snapshot of a locator at any
# point during a document parse:
#
-# module example
-# #
-# import sax::helpers::SAXLocatorImpl
-# import sax::ContentHandler
-# #
+# import sax::helpers::sax_locator_impl
+# import sax::content_handler
+#
# class Example super ContentHandler
-# private var _locator: nullable SAXLocator = null
+# private var locator: SAXLocator
# private var start_loc: nullable SAXLocator = null
-# #
-# fun locator=(Locator locator) do
-# # note the locator
-# _locator = locator
-# end
-# #
-# fun start_document do
+#
+# redef fun start_document do
# # save the location of the start of the document
# # for future use.
-# start_loc = new SAXLocatorImpl.from(locator)
+# start_loc = new SAXLocatorImpl.with(locator)
# end
# end
#
# document from a system identifier. It is the exact
# equivalent of the following:
#
- # var source = new InputSouce
- # source.system_id = system_id
- # parse(source)
+ # ~~~nitish
+ # var source = new InputSouce
+ # source.system_id = system_id
+ # parse(source)
+ # ~~~
#
# If the system identifier is a URL, it must be fully resolved
# by the application before it is passed to the parser.
# This method must be implemented for each specific view.
# A traditional way of implementation is to use a double-dispatch mechanism
#
- # Exemple:
# class MyView
+ # super View
# redef fun draw_sprite(s) do s.draw_on_myview(self)
# end
# redef class Sprite
# r.handle_signal(sigint, true)
# r.handle_signal(sigalarm, true)
#
-# Ask system to receive a `sigalarm` signal in 1 second
+# # Ask system to receive a `sigalarm` signal in 1 second
# set_alarm(1)
#
# loop
class Statement
private var native_statement: NativeStatement
- private init(ns: NativeStatement) do self.native_statement = ns
-
# Is this statement usable?
var is_open = true
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`
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`
# 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
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
# Subclasses often provide a more efficient implementation.
#
# Because of the `iterator` method, Collections instances can use
-# the `for` control structure:
+# the `for` control structure.
#
-# var x: Collection[U]
-# # ...
-# for u in x do
-# # u is a U
-# # ...
-# end
+# ~~~nitish
+# var x: Collection[U]
+# # ...
+# for u in x do
+# # u is a U
+# # ...
+# end
+# ~~~
#
-# that is equivalent with
+# that is equivalent with the following:
#
-# var x: Collection[U]
-# # ...
-# var i = x.iterator
-# while i.is_ok do
-# var u = i.item # u is a U
-# # ...
-# i.next
-# end
+# ~~~nitish
+# var x: Collection[U]
+# # ...
+# var i = x.iterator
+# while i.is_ok do
+# var u = i.item # u is a U
+# # ...
+# i.next
+# end
+# ~~~
interface Collection[E]
# Get a new iterator on the collection.
fun iterator: Iterator[E] is abstract
#
# SEE: `Char::is_letter` for the definition of a letter.
#
- # var b = new FlatBuffer.from("jAVAsCriPt")"
+ # var b = new FlatBuffer.from("jAVAsCriPt")
# b.capitalize
# assert b == "Javascript"
# b = new FlatBuffer.from("i am root")
#
# As per the specification :
#
+ # ~~~raw
# Length | UTF-8 octet sequence
# | (binary)
# ---------+-------------------------------------------------
# 2 | 110xxxxx 10xxxxxx
# 3 | 1110xxxx 10xxxxxx 10xxxxxx
# 4 | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ # ~~~
private fun len: Int `{
char* ns = recv->ns;
int pos = recv->pos;
#
# As per the specification :
#
+ # ~~~raw
# Length | UTF-8 octet sequence
# | (binary)
# ---------+-------------------------------------------------
# 2 | 110xxxxx 10xxxxxx
# 3 | 1110xxxx 10xxxxxx 10xxxxxx
# 4 | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ # ~~~
fun len: Int `{
uint32_t s = *recv;
if(s <= 127) {return 1;}
#
# In external file `example.tpl`:
#
-# <!DOCTYPE html>
-# <html lang="en">
-# <head>
-# <title>%TITLE%</title>
-# </head>
-# <body>
-# <h1>%TITLE%</h1>
-# <p>%ARTICLE%</p>
-# </body>
-# </html>
+# ~~~html
+# <!DOCTYPE html>
+# <html lang="en">
+# <head>
+# <title>%TITLE%</title>
+# </head>
+# <body>
+# <h1>%TITLE%</h1>
+# <p>%ARTICLE%</p>
+# </body>
+# </html>
+# ~~~
#
# Loading the template file using `TemplateString`:
#
# Perform left rotation on `node`
#
+ # ~~~raw
# N Y
# / \ > / \
# a Y N c
# / \ < / \
# b c a b
+ # ~~~
#
protected fun rotate_left(node: N) do
var y = node.right
# Perform right rotation on `node`
#
+ # ~~~raw
# N Y
# / \ > / \
# a Y N c
# / \ < / \
# b c a b
+ # ~~~
#
protected fun rotate_right(node: N) do
var y = node.left
# Red-Black Tree Map
# Properties of a Red-Black tree map:
-# * every node is either red or black
-# * root is black
-# * every leaf (null) is black
-# * if a node is red, then both its children are black
-# * for each node, all simple path from the node to descendant
-# leaves contain the same number of black nodes
+# * every node is either red or black
+# * root is black
+# * every leaf (null) is black
+# * if a node is red, then both its children are black
+# * for each node, all simple path from the node to descendant
+# leaves contain the same number of black nodes
#
# Operations:
-# * search average O(lg n) worst O(lg n)
-# * insert average O(lg n) worst O(lg n)
-# * delete average O(lg n) worst O(lg n)
+# * search average O(lg n) worst O(lg n)
+# * insert average O(lg n) worst O(lg n)
+# * delete average O(lg n) worst O(lg n)
class RBTreeMap[K: Comparable, E]
super BinTreeMap[K, E]
## Working with `DocUnits`
-With DocUnits, executable code can be placed in comments of modules, classes and properties.
-The execution can be verified using `assert`
+DocUnits are blocks of executable code placed in comments of modules, classes and properties.
+The execution can be verified using `assert`.
Example with a class:
fun baz(a, b: Int) do return a + b
end
+In a single piece of documentation, each docunit is considered a part of a single module, thus regrouped when
+tested.
+Therefore, it is possible (and recommended) to split docunits in small parts if it make the explanation easier.
+
+~~~~
+# Some example of grouped docunits
+#
+# Declare and initialize a variable `a`.
+#
+# var a = 1
+#
+# So the value of `a` can be used
+#
+# assert a == 1
+#
+# even in complex operations
+#
+# assert a + 1 == 2
+fun foo do end
+~~~~
+
+Sometime, some blocks of code has to be included in documentation but not considered by `nitunit`.
+Those blocks are distinguished by their tagged fences (untagged fences or fences tagged `nit` are considered to be docunits).
+
+~~~~
+# Some ASCII drawing
+#
+# ~~~~raw
+# @<
+# <__)
+# ~~~~
+fun foo do end
+~~~~
+
+The special fence-tag `nitish` could also be used to indicate pseudo-nit that will be ignored by nitunit but highlighted by nitdoc.
+Such `nitish` piece of code can be used to enclose examples that cannot compile or that one do not want to be automatically executed.
+
+~~~~
+# Some pseudo-nit
+#
+# ~~~~nitish
+# var a: Int = someting
+# # ...
+# if a == 1 then something else something-else
+# ~~~~
+#
+# Some code to not try to execute automatically
+#
+# ~~~~nitish
+# system("rm -rf /")
+# ~~~~
+~~~~
+
The `nitunit` command is used to test Nit files:
$ nitunit foo.nit
# To create the new node `n`, we need to attach the child to it.
# But, to put `n` where `c` was in `p`, the place has to be remembered.
#
- # var p: AExpr
- # var c = p.c
- # var h = c.detach_with_placeholder
- # var n = astbuilder.make_XXX(c)
- # h.replace_with(n)
+ # ~~~nitish
+ # var p: AExpr
+ # var c = p.c
+ # var h = c.detach_with_placeholder
+ # var n = astbuilder.make_XXX(c)
+ # h.replace_with(n)
+ # ~~~
fun detach_with_placeholder: AExpr
do
var h = new APlaceholderExpr.make
# Two elements from a POSet cannot have the same color if they share common subelements
#
# Example:
+#
+# ~~~raw
# A
# / | \
# / | \
# E F G
# |
# H
+# ~~~
+#
# Conflicts:
-# A: {B, C, D, E, F, G, H}
-# B: {A, C, E, H}
-# C: {A, E, H, F}
-# D: {A, G}
-# E: {A, B, C, H}
-# F: {A, C}
-# G: {A, D}
-# H: {A, B, C, E}
+#
+# * A: {B, C, D, E, F, G, H}
+# * B: {A, C, E, H}
+# * C: {A, E, H, F}
+# * D: {A, G}
+# * E: {A, B, C, H}
+# * F: {A, C}
+# * G: {A, D}
+# * H: {A, B, C, E}
+#
# Possible colors:
-# A:0, B:1, C: 2, D: 1, E: 3, F:3, G:2, H:4
#
-# see:
-# Ducournau, R. (2011).
-# Coloring, a versatile technique for implementing object-oriented languages.
-# Software: Practice and Experience, 41(6), 627–659.
+# * A:0, B:1, C: 2, D: 1, E: 3, F:3, G:2, H:4
+#
+# see: Ducournau, R. (2011).
+# Coloring, a versatile technique for implementing object-oriented languages.
+# Software: Practice and Experience, 41(6), 627–659.
class POSetColorer[E: Object]
# Is the poset already colored?
# Count empty lines between code blocks
var empty_lines = 0
+ # Optional tag for a fence
+ var fence_tag = ""
+
fun work(mdoc: MDoc): HTMLTag
do
var root = new HTMLTag("div")
empty_lines = 0
# to allows 4 spaces including the one that follows the #
curblock.add(text)
+ fence_tag = ""
continue
end
var l = 3
while l < text.length and text.chars[l] == '~' do l += 1
in_fence = text.substring(0, l)
+ while l < text.length and (text.chars[l] == '.' or text.chars[l] == ' ') do l += 1
+ fence_tag = text.substring_from(l)
continue
end
# Code part
var n2 = new HTMLTag("code")
n.add(n2)
- process_code(n2, part)
+ process_code(n2, part, null)
end
is_text = not is_text
end
# add the node
var n = new HTMLTag("pre")
root.add(n)
- process_code(n, btext.to_s)
+ process_code(n, btext.to_s, fence_tag)
curblock.clear
end
end
- fun process_code(n: HTMLTag, text: String)
+ fun process_code(n: HTMLTag, text: String, tag: nullable String)
do
+ # Do not try to highlight non-nit code.
+ if tag != null and tag != "" and tag != "nit" and tag != "nitish" then
+ n.append text
+ n.add_class("rawcode")
+ return
+ end
+
# Try to parse it
var ast = toolcontext.parse_something(text)
end
redef class Location
- fun as_line_pragma: String do return "#line {line_start} \"{file.filename}\"\n"
+ fun as_line_pragma: String do return "#line {line_start-1} \"{file.filename}\"\n"
end
redef class MModule
# types to their bounds.
#
# Example
+ #
# class A end
# class B super A end
# class X end
# super G[B]
# redef type U: Y
# end
+ #
# Map[T,U] anchor_to H #-> Map[B,Y]
#
# Explanation of the example:
# In Nit, for each super-class of a type, there is a equivalent super-type.
#
# Example:
+ #
+ # ~~~nitish
# class G[T, U] end
# class H[V] super G[V, Bool] end
+ #
# H[Int] supertype_to G #-> G[Int, Bool]
+ # ~~~
#
# REQUIRE: `super_mclass` is a super-class of `self`
# REQUIRE: `self.need_anchor implies anchor != null and self.can_resolve_for(anchor, null, mmodule)`
#
# ## Example 1
#
- # class G[E] end
- # class H[F] super G[F] end
- # class X[Z] end
+ # ~~~
+ # class G[E] end
+ # class H[F] super G[F] end
+ # class X[Z] end
+ # ~~~
#
# * Array[E].resolve_for(H[Int]) #-> Array[Int]
# * Array[E].resolve_for(G[Z], X[Int]) #-> Array[Z]
#
# ## Example 2
#
- # class A[E]
- # fun foo(e:E):E is abstract
- # end
- # class B super A[Int] end
+ # ~~~
+ # class A[E]
+ # fun foo(e:E):E is abstract
+ # end
+ # class B super A[Int] end
+ # ~~~
#
# The signature on foo is (e: E): E
# If we resolve the signature for B, we get (e:Int):Int
#
# ## Example 3
#
- # class A[E]
- # fun foo(e:E) is abstract
- # end
- # class B[F]
- # var a: A[Array[F]]
- # fun bar do a.foo(x) # <- x is here
- # end
+ # ~~~nitish
+ # class A[E]
+ # fun foo(e:E):E is abstract
+ # end
+ # class C[F]
+ # var a: A[Array[F]]
+ # fun bar do a.foo(x) # <- x is here
+ # end
+ # ~~~
#
# The first question is: is foo available on `a`?
#
# The static type of a is `A[Array[F]]`, that is an open type.
# in order to find a method `foo`, whe must look at a resolved type.
#
- # A[Array[F]].anchor_to(B[nullable Object]) #-> A[Array[nullable Object]]
+ # A[Array[F]].anchor_to(C[nullable Object]) #-> A[Array[nullable Object]]
#
# the method `foo` exists in `A[Array[nullable Object]]`, therefore `foo` exists for `a`.
#
#
# the signature of `foo` is `foo(e:E)`, thus we must resolve the type E
#
- # E.resolve_for(A[Array[F]],B[nullable Object]) #-> Array[F]
+ # E.resolve_for(A[Array[F]],C[nullable Object]) #-> Array[F]
#
# The resolution can be done because `E` make sense for the class A (see `can_resolve_for`)
#
# class B[F]
# end
#
- # * E.can_resolve_for(A[Int]) #-> true, E make sense in A
- # * E.can_resolve_for(B[Int]) #-> false, E does not make sense in B
- # * B[E].can_resolve_for(A[F], B[Object]) #-> true,
- # B[E] is a red hearing only the E is important,
- # E make sense in A
+ # ~~~nitish
+ # E.can_resolve_for(A[Int]) #-> true, E make sense in A
+ #
+ # E.can_resolve_for(B[Int]) #-> false, E does not make sense in B
+ #
+ # B[E].can_resolve_for(A[F], B[Object]) #-> true,
+ # # B[E] is a red hearing only the E is important,
+ # # E make sense in A
+ # ~~~
#
# REQUIRE: `anchor != null implies not anchor.need_anchor`
# REQUIRE: `mtype.need_anchor implies anchor != null and mtype.can_resolve_for(anchor, null, mmodule)`
# directly to the parameter types of the super-classes.
#
# Example:
+#
# class A[E]
# fun e: E is abstract
# end
# class B[F]
# super A[Array[F]]
# end
+#
# In the class definition B[F], `F` is a valid type but `E` is not.
# However, `self.e` is a valid method call, and the signature of `e` is
# declared `e: E`.
#
# Comparison is made with the formula:
#
-# a.concern_rank + a.booster_rank <=> b.concern_rank + b.booster_ran
+# ~~~nitish
+# a.concern_rank + a.booster_rank <=> b.concern_rank + b.booster_ran
+# ~~~
#
# If both `a` and `b` have the same ranking,
# ordering is based on lexicographic comparison of `a.name` and `b.name`
#
# For example, if the source code contains:
#
+# ~~~nitish
# fun foo(a: A, b: B, c: C)
+# ~~~
#
# The `MSignature` node will contain a property
# `parameter_names = ["a", "b", "c"]` so the MSignature can be reconstructed
# `Licence comments` are attached to the top of the file
# no blank line before, one after.
#
-# # This is a licence comment
+# ~~~nitish
+# # This is a licence comment
#
-# # Documentation for module `foo`
-# module foo
+# # Documentation for module `foo`
+# module foo
+# ~~~
#
# `ADoc` are documentation comments attached to a `AModule`, `AClassdef`, `APropdef`.
#
# They are printed before the definition with a blank line before and no after
# at the same indentation level than the definition.
#
-# # Documentation for module `foo`
-# module foo
+# ~~~nitish
+# # Documentation for module `foo`
+# module foo
#
-# # Documentation for class `Bar`
-# class Bar
-# # Documentation for method `baz`
-# fun baz do end
-# end
+# # Documentation for class `Bar`
+# class Bar
+# # Documentation for method `baz`
+# fun baz do end
+# end
+# ~~~
#
# `Block comments` are comments composed of one or more line rattached to nothing.
# They are displayed with one blank line before and after at current indent level.
#
-# <blank>
-# # block
-# # comment
-# <blank>
+# ~~~nitish
+# <blank>
+# # block
+# # comment
+# <blank>
+# ~~~
#
# `Attached comments` are comments attached to a production.
# They are printed as this.
#
-# fun foo do # attached comment
-# end
+# ~~~nitish
+# fun foo do # attached comment
+# end
+# ~~~
#
# `nitpretty` automatically remove multiple blanks between comments:
#
-# # Licence
-# # ...
-# <blank>
-# # Block comment
+# ~~~nitish
+# # Licence
+# # ...
+# <blank>
+# # Block comment
+# ~~~
#
# ### Inlining
#
# * There is a blank between each class definition
# * There is no blank line at the end of the module
#
-# # Documentation for module `foo`
-# module foo
+# ~~~nitish
+# # Documentation for module `foo`
+# module foo
#
-# import a
-# # import b
-# import c
+# import a
+# # import b
+# import c
#
-# # Documentation for class `Bar`
-# class Bar end
+# # Documentation for class `Bar`
+# class Bar end
#
-# class Baz end # not a `ADoc` comment
+# class Baz end # not a `ADoc` comment
+# ~~~
#
#
# ### Classes
# * There is a blank between each block definition
# * There no blank line at the end of the class definition
#
-# # Documentation for class `Bar`
-# class Bar end
+# ~~~nitish
+# # Documentation for class `Bar`
+# class Bar end
#
-# class Baz
-# super Bar
+# class Baz
+# super Bar
#
-# fun a is abstract
-# private fun b do end
+# fun a is abstract
+# private fun b do end
#
-# fun c do
-# # ...
-# end
-# end
+# fun c do
+# # ...
+# end
+# end
+# ~~~
#
-# Generic types have no espace after or before brackets and are separated by a comma and a space:
+# Generic types have no space after or before brackets and are separated by a comma and a space:
#
-# class A[E: Type1, F: Type1] do end
+# ~~~nitish
+# class A[E: Type1, F: Type1] end
+# ~~~
#
# ### Blocks
#
# * Inlined productions have no blank lines between them
# * Block productions have a blank before and after
#
-# var a = 10
-# var b = 0
+# ~~~nitish
+# var a = 10
+# var b = 0
#
-# if a > b then
-# # is positive
-# print "positive"
-# end
+# if a > b then
+# # is positive
+# print "positive"
+# end
#
-# print "end"
+# print "end"
+# ~~~
#
# ### Calls and Binary Ops
#
# Arguments are always printed separated with a comma and a space:
#
-# foo(a, b, c)
+# ~~~nitish
+# foo(a, b, c)
+# ~~~
#
# Binary ops are always printed wrapped with spaces:
#
-# var c = 1 + 2
+# ~~~nitish
+# var c = 1 + 2
+# ~~~
#
# Calls and binary ops can be splitted to fit the `max-size` constraint.
# Breaking priority is given to arguments declaration after the comma.
#
-# return foo("aaaaaaaaaaaaaaaaaaaaaaaaaa", "bbbbbbbbbbbbbbbbbbbbbbbbbbb",
-# "cccccccccccccccccccccccccc")
+# ~~~nitish
+# return foo("aaaaaaaaaaaaaaaaaaaaaaaaaa", "bbbbbbbbbbbbbbbbbbbbbbbbbbb",
+# "cccccccccccccccccccccccccc")
+# ~~~
#
# Binary ops can also be broken to fit the `max-size` limit:
#
-# return "aaaaaaaaaaaaaaaaaaaaaaaaaa" + "bbbbbbbbbbbbbbbbbbbbbbbbbbb" +
-# "cccccccccccccccccccccccccc"
-#
+# ~~~nitish
+# return "aaaaaaaaaaaaaaaaaaaaaaaaaa" + "bbbbbbbbbbbbbbbbbbbbbbbbbbb" +
+# "cccccccccccccccccccccccccc"
+# ~~~
module nitpretty
import template
# All blocks of code from a same `ADoc`
var blocks = new Array[Array[String]]
- redef fun process_code(n: HTMLTag, text: String)
+ # All failures from a same `ADoc`
+ var failures = new Array[String]
+
+ redef fun process_code(n: HTMLTag, text: String, tag: nullable String)
do
# Skip non-blocks
if n.tag != "pre" then return
+ # Skip strict non-nit
+ if tag != null and tag != "nit" and tag != "" then
+ return
+ end
+
# Try to parse it
var ast = toolcontext.parse_something(text)
+ # Skip pure comments
+ if ast isa TComment then return
+
# We want executable code
if not (ast isa AModule or ast isa ABlockExpr or ast isa AExpr) then
- if ndoc != null and n.tag == "pre" and toolcontext.opt_warn.value > 1 then
- toolcontext.warning(ndoc.location, "invalid-block", "Warning: There is a block of code that is not valid Nit, thus not considered a nitunit")
- if ast isa AError then toolcontext.warning(ast.location, "syntax-error", ast.message)
- ndoc = null # To avoid multiple warning in the same node
- end
- return
- end
-
- # Search `assert` in the AST
- var v = new SearchAssertVisitor
- v.enter_visit(ast)
- if not v.foundit then
- if ndoc != null and n.tag == "pre" and toolcontext.opt_warn.value > 1 then
- toolcontext.warning(ndoc.location, "invalid-block", "Warning: There is a block of Nit code without `assert`, thus not considered a nitunit")
- ndoc = null # To avoid multiple warning in the same node
- end
+ var message = ""
+ if ast isa AError then message = " At {ast.location}: {ast.message}."
+ toolcontext.warning(ndoc.location, "invalid-block", "Error: There is a block of code that is not valid Nit, thus not considered a nitunit. To suppress this warning, enclose the block with a fence tagged `nitish` or `raw` (see `man nitdoc`).{message}")
+ failures.add("{ndoc.location}: Invalid block of code.{message}")
return
end
fun extract(ndoc: ADoc, tc: HTMLTag)
do
blocks.clear
+ failures.clear
self.ndoc = ndoc
work(ndoc.to_mdoc)
+
toolcontext.check_errors
+ if not failures.is_empty then
+ for msg in failures do
+ var ne = new HTMLTag("failure")
+ ne.attr("message", msg)
+ tc.add ne
+ toolcontext.modelbuilder.failed_entities += 1
+ end
+ if blocks.is_empty then testsuite.add(tc)
+ end
+
if blocks.is_empty then return
for block in blocks do test_block(ndoc, tc, block)
test_file = "{include_dir}/{test_file}"
end
if not test_file.file_exists then
- toolcontext.info("Skip test for {mmodule}, no file {test_file} found", 1)
+ toolcontext.info("Skip test for {mmodule}, no file {test_file} found", 2)
return ts
end
var tester = new NitUnitTester(self)
var res = tester.test_module_unit(test_file)
if res == null then
- toolcontext.info("Skip test for {mmodule}, no test suite found", 1)
+ toolcontext.info("Skip test for {mmodule}, no test suite found", 2)
return ts
end
return res.to_xml
redef class AArrayExpr
# `[x,y]` is replaced with
#
- # var t = new Array[X].with_capacity(2)
- # t.add(x)
- # t.add(y)
- # t
+ # ~~~nitish
+ # var t = new Array[X].with_capacity(2)
+ # t.add(x)
+ # t.add(y)
+ # t
+ # ~~~
redef fun accept_transform_visitor(v)
do
var nblock = v.builder.make_block
redef class ASendReassignFormExpr
# `x.foo(y)+=z` is replaced with
#
- # x.foo(y) = x.foo(y) + z
+ # ~~~nitish
+ # x.foo(y) = x.foo(y) + z
+ # ~~~
#
# witch is, in reality:
#
- # x."foo="(y, x.foo(y)."+"(z))
+ # ~~~nitish
+ # x."foo="(y, x.foo(y)."+"(z))
+ # ~~~
redef fun accept_transform_visitor(v)
do
var nblock = v.builder.make_block
end
# Return the attribute value in `instance` with a sequence of perfect_hashing
- # `instance` is the attributes array of the receiver
- # `vtable` is the pointer to the virtual table of the class (of the receiver)
- # `mask` is the perfect hashing mask of the class
- # `id` is the identifier of the class
- # `offset` is the relative offset of this attribute
+ # * `instance` is the attributes array of the receiver
+ # * `vtable` is the pointer to the virtual table of the class (of the receiver)
+ # * `mask` is the perfect hashing mask of the class
+ # * `id` is the identifier of the class
+ # * `offset` is the relative offset of this attribute
private fun read_attribute_ph(instance: Pointer, vtable: Pointer, mask: Int, id: Int, offset: Int): Instance `{
// Perfect hashing position
int hv = mask & id;
end
# Replace the value of an attribute in an instance
- # `instance` is the attributes array of the receiver
- # `vtable` is the pointer to the virtual table of the class (of the receiver)
- # `mask` is the perfect hashing mask of the class
- # `id` is the identifier of the class
- # `offset` is the relative offset of this attribute
- # `value` is the new value for this attribute
+ # * `instance` is the attributes array of the receiver
+ # * `vtable` is the pointer to the virtual table of the class (of the receiver)
+ # * `mask` is the perfect hashing mask of the class
+ # * `id` is the identifier of the class
+ # * `offset` is the relative offset of this attribute
+ # * `value` is the new value for this attribute
private fun write_attribute_ph(instance: Pointer, vtable: Pointer, mask: Int, id: Int, offset: Int, value: Instance) `{
// Perfect hashing position
int hv = mask & id;
end
# Allocate a single vtable
- # `ids : Array of superclasses identifiers
- # `nb_methods : Array which contain the number of introduced methods for each class in ids
- # `nb_attributes : Array which contain the number of introduced attributes for each class in ids
- # `offset_attributes : Offset from the beginning of the table of the group of attributes
- # `offset_methods : Offset from the beginning of the table of the group of methods
+ # * `ids : Array of superclasses identifiers
+ # * `nb_methods : Array which contain the number of introduced methods for each class in ids
+ # * `nb_attributes : Array which contain the number of introduced attributes for each class in ids
+ # * `offset_attributes : Offset from the beginning of the table of the group of attributes
+ # * `offset_methods : Offset from the beginning of the table of the group of methods
private fun allocate_vtable(v: VirtualMachine, ids: Array[Int], nb_methods: Array[Int], nb_attributes: Array[Int],
offset_attributes: Int, offset_methods: Int)
do
end
# Fill the vtable with methods of `self` class
- # `v` : Current instance of the VirtualMachine
- # `table` : the table of self class, will be filled with its methods
+ # * `v` : Current instance of the VirtualMachine
+ # * `table` : the table of self class, will be filled with its methods
private fun fill_vtable(v:VirtualMachine, table: VTable, cl: MClass)
do
var methods = new Array[MMethodDef]
# Computes delta for each class
# A delta represents the offset for this group of attributes in the object
- # `nb_attributes` : number of attributes for each class (classes are linearized from Object to current)
- # return deltas for each class
+ # *`nb_attributes` : number of attributes for each class (classes are linearized from Object to current)
+ # * return deltas for each class
private fun calculate_delta(nb_attributes: Array[Int]): Array[Int]
do
var deltas = new Array[Int]
end
# A kind of Depth-First-Search for superclasses ordering
- # `v` : the current executed instance of VirtualMachine
- # `res` : Result Array, ie current superclasses ordering
+ # *`v` : the current executed instance of VirtualMachine
+ # * `res` : Result Array, ie current superclasses ordering
private fun dfs(v: VirtualMachine, res: Array[MClass]): Array[MClass]
do
# Add this class at the beginning
end
# Update positions of self class in `parent`
- # `attributes_offset`: absolute offset of introduced attributes
- # `methods_offset`: absolute offset of introduced methods
+ # * `attributes_offset`: absolute offset of introduced attributes
+ # * `methods_offset`: absolute offset of introduced methods
private fun update_positions(attributes_offsets: Int, methods_offset:Int, parent: MClass)
do
parent.positions_attributes[self] = attributes_offsets
`}
# Put implementation of methods of a class in `vtable`
- # `vtable` : Pointer to the C-virtual table
- # `mask` : perfect-hashing mask of the class corresponding to the vtable
- # `id` : id of the target class
- # `methods` : array of MMethodDef of the target class
+ # * `vtable` : Pointer to the C-virtual table
+ # * `mask` : perfect-hashing mask of the class corresponding to the vtable
+ # * `id` : id of the target class
+ # * `methods` : array of MMethodDef of the target class
fun put_methods(vtable: Pointer, mask: Int, id: Int, methods: Array[MMethodDef])
import Array[MMethodDef].length, Array[MMethodDef].[] `{
nitg_args5
nitg_args6
nitg_args8
-test_markdown_args1
+nitunit_args
+test_docdown_args
pep8analysis
emscripten
nitserial_args
test_nitunit.nit --gen-suite --only-show
test_nitunit.nit --gen-suite --only-show --private
test_nitunit2.nit -o $WRITE
+test_doc2.nit --no-color -o $WRITE
--- /dev/null
+DocUnits:
+DocUnits Success
+Entities: 6; Documented ones: 5; With nitunits: 3; Failures: 0
+
+TestSuites:
+No test cases found
+Class suites: 0; Test Cases: 0; Failures: 0
+<testsuites><testsuite package="test_doc2"><testcase classname="nitunit.test_doc2.standard::kernel::Object" name="test_doc2::Object::foo1"><system-err></system-err><system-out>assert true # tested
+</system-out></testcase><testcase classname="nitunit.test_doc2.standard::kernel::Object" name="test_doc2::Object::foo2"><system-err></system-err><system-out>assert true # tested
+</system-out></testcase><testcase classname="nitunit.test_doc2.standard::kernel::Object" name="test_doc2::Object::foo3"><system-err></system-err><system-out>assert true # tested
+</system-out></testcase></testsuite><testsuite></testsuite></testsuites>
\ No newline at end of file
h5 {font-weight:bold;}
.nitcode a { color: inherit; cursor:pointer; }
.nitcode .popupable:hover { text-decoration: underline; cursor:help; } /* underline titles */
-pre.nitcode .foldable { display: block } /* for block productions*/
-pre.nitcode .line{ display: block } /* for lines */
-pre.nitcode .line:hover{ background-color: #FFFFE0; } /* current line */
+.nitcode .foldable { display: block } /* for block productions*/
+.nitcode .line{ display: block } /* for lines */
+.nitcode .line:hover{ background-color: #FFFFE0; } /* current line */
.nitcode :target { background-color: #FFF3C2 } /* target highlight*/
/* lexical raw tokens. independent of usage or semantic: */
.nitcode .nc_c { color: gray; font-style: italic; } /* comment */
--- /dev/null
+<html><head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
+<style type="text/css">
+code {margin: 0 2px;
+padding: 0px 5px;
+border: 1px solid #ddd;
+background-color: #f8f8f8;
+border-radius: 3px;}
+pre {
+background-color: #f8f8f8;
+border: 1px solid #ddd;
+font-size: 13px;
+line-height: 19px;
+overflow: auto;
+padding: 6px 6px;
+border-radius: 3px;
+}
+.rawcode[title] {
+border-color: red;
+}
+h5 {font-weight:bold;}
+.nitcode a { color: inherit; cursor:pointer; }
+.nitcode .popupable:hover { text-decoration: underline; cursor:help; } /* underline titles */
+.nitcode .foldable { display: block } /* for block productions*/
+.nitcode .line{ display: block } /* for lines */
+.nitcode .line:hover{ background-color: #FFFFE0; } /* current line */
+.nitcode :target { background-color: #FFF3C2 } /* target highlight*/
+/* lexical raw tokens. independent of usage or semantic: */
+.nitcode .nc_c { color: gray; font-style: italic; } /* comment */
+.nitcode .nc_d { color: #3D8127; font-style: italic; } /* documentation comments */
+.nitcode .nc_k { font-weight: bold; } /* keyword */
+.nitcode .nc_o {} /* operator */
+.nitcode .nc_i {} /* standard identifier */
+.nitcode .nc_t { color: #445588; font-weight: bold; } /* type/class identifier */
+.nitcode .nc_a { color: #445588; font-style: italic; } /* old style attribute identifier */
+.nitcode .nc_l { color: #009999; } /* char and number literal */
+.nitcode .nc_s { color: #8F1546; } /* string literal */
+/* syntactic token usage. added because of their position in the AST */
+.nitcode .nc_ast { color: blue; } /* assert label */
+.nitcode .nc_la { color: blue; } /* break/continue label */
+.nitcode .nc_m { color: #445588; } /* module name */
+/* syntactic groups */
+.nitcode .nc_def { font-weight: bold; color: blue; } /* name used in a definition */
+ .nitcode .nc_def.nc_a { color: blue; } /* name used in a attribute definition */
+ .nitcode .nc_def.nc_t { color: blue; } /* name used in a class or vt definition */
+.nitcode .nc_ss { color: #9E6BEB; } /* superstrings */
+.nitcode .nc_cdef {} /* A whole class definition */
+.nitcode .nc_pdef {} /* A whole property definition */
+/* semantic token usage */
+.nitcode .nc_v { font-style: italic; } /* local variable or parameter */
+.nitcode .nc_vt { font-style: italic; } /* virtual type or formal type */
+
+.nitcode .nc_error { border: 1px red solid;} /* not used */
+.popover { max-width: 800px !important; }
+
+</style>
+</head><body><h3 id='test_doc2'>module test_doc2</h1><h5 id='test_doc2#Object#foo1'>prop test_doc2#Object#foo1</h3><div class="nitdoc"><p class="synopsys">Test code</p><pre class="nitcode"><span class="nitcode"><span class="line" id="L1"><span class="nc_k">assert</span> <span class="nc_k">true</span> <span># tested
+</span></span><span class="line" id="L2"><span></span></span></span></pre></div><h5 id='test_doc2#Object#foo2'>prop test_doc2#Object#foo2</h3><div class="nitdoc"><p class="synopsys">Test code</p><pre class="nitcode"><span class="nitcode"><span class="line" id="L1"><span class="nc_k">assert</span> <span class="nc_k">true</span> <span># tested
+</span></span><span class="line" id="L2"><span></span></span></span></pre></div><h5 id='test_doc2#Object#foo3'>prop test_doc2#Object#foo3</h3><div class="nitdoc"><p class="synopsys">Test code</p><pre class="nitcode"><span class="nitcode"><span class="line" id="L1"><span class="nc_k">assert</span> <span class="nc_k">true</span> <span># tested
+</span></span><span class="line" id="L2"><span></span></span></span></pre></div><h5 id='test_doc2#Object#foo4'>prop test_doc2#Object#foo4</h3><div class="nitdoc"><p class="synopsys">Test code</p><pre class="rawcode">assert false # not tested (and not highlighted)
+</pre></div><h5 id='test_doc2#Object#foo5'>prop test_doc2#Object#foo5</h3><div class="nitdoc"><p class="synopsys">Test code</p><pre class="nitcode"><span class="nitcode"><span class="line" id="L1"><span class="nc_k">assert</span> <span class="nc_k">false</span> <span># not tested (but highlighted)
+</span></span><span class="line" id="L2"><span></span></span></span></pre></div><script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
+<script src="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
+<script>$(".popupable").popover({html:true, placement:'top'})/*initialize bootstrap popover*/</script></body></html>
\ No newline at end of file
--- /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.
+
+# Test code
+#
+# assert true # tested
+fun foo1 do end
+
+# Test code
+#
+# ~~~~
+# assert true # tested
+# ~~~~
+fun foo2 do end
+
+# Test code
+#
+# ~~~~nit
+# assert true # tested
+# ~~~~
+fun foo3 do end
+
+# Test code
+#
+# ~~~~raw
+# assert false # not tested (and not highlighted)
+# ~~~~
+fun foo4 do end
+
+# Test code
+#
+# ~~~~nitish
+# assert false # not tested (but highlighted)
+# ~~~~
+fun foo5 do end
--- /dev/null
+test_doc.nit
+test_doc2.nit
+++ /dev/null
-test_doc.nit