From: Jean Privat Date: Fri, 21 Aug 2015 19:48:25 +0000 (-0400) Subject: Merge: objcwrapper: wrapper generator to access Objective-C services from Nit X-Git-Tag: v0.7.8~76 X-Git-Url: http://nitlanguage.org?hp=031983f6b64dc3759938d6dd0a1c528dd5bdd794 Merge: objcwrapper: wrapper generator to access Objective-C services from Nit This PR introduces *objcwrapper*, a wrapper generator to access Objective-C services from Nit. At this point, *objcwrapper* can parse large Objective-C header files from Apple, and generate valid Nit code to wrap simple classes. This PR contains the work of @Tagachi (as the first commit), some of my refactoring and new features. Because of this, there is some rewrite between commits. I chose to keep them as-is because it may be useful to debug regressions in the future. Actually, some of the refactoring remove a few features (such as super class declaration parsing), they will be brought back in future PRs. This is a good base for future work but also a work in progress. Please restrain comments to structural and algorithmic problems, the doc and manual will be completed with the missing features. Working features: - [x] Generate a Nit extern class for each Objective-C `@interface` block. - [x] Generate Nit extern methods to wrap Objective-C methods (`- `). - [x] Generate getters for attributes `@property`. - [x] Basic type conversion from Objective-C to Nit. - [x] Partial detection of supported and unsupported types. Todo features: - [ ] Static functions (`+`) as top-level methods. - [ ] Attribute setter (when not `readonly`). - [ ] Intro and use an `ObjcType` instead of a `String`. - [ ] Reproduce class hierarchy. - [ ] Reuse wrapped classes (serialize the model alongside the wrapper). - [ ] Deal with incompatible types: function pointers and others. - [ ] Print a report on unsupported services. - [ ] Support parsing GNUstep classes. - [ ] Generate valid Nit code with Apple classes. - [ ] Merge with *jwrapper*? Pull-Request: #1647 Reviewed-by: Jean Privat Reviewed-by: Lucas Bajolet --- diff --git a/contrib/benitlux/.gitignore b/contrib/benitlux/.gitignore index e4e2a7d..2ccbe7b 100644 --- a/contrib/benitlux/.gitignore +++ b/contrib/benitlux/.gitignore @@ -1,3 +1,4 @@ src/benitlux_serial.nit *.db *.email +benitlux_corrections.txt diff --git a/contrib/benitlux/src/benitlux_daily.nit b/contrib/benitlux/src/benitlux_daily.nit index 1c1f4d6..f4a3f25 100644 --- a/contrib/benitlux/src/benitlux_daily.nit +++ b/contrib/benitlux/src/benitlux_daily.nit @@ -75,21 +75,13 @@ class Benitlux var street: String # The url of this precise Benelux - var url: String + var url = "www.brasseriebenelux.com/{street}" is lazy # Path to the database - var db_path: String + var db_path = "benitlux_{street}.db" is lazy # Where to save the sample email - var sample_email_path: String - - init(street: String) - do - self.street = street - self.url = "www.brasseriebenelux.com/{street}" - self.db_path = "benitlux_{street}.db" - self.sample_email_path = "benitlux_{street}.email" - end + var sample_email_path = "benitlux_{street}.email" is lazy # Execute the main program logic fun run(send_emails: Bool) @@ -171,10 +163,10 @@ class Benitlux end # Content lines of the email - var email_content: Array[String] + var email_content: Array[String] is noautoinit # Title of the email - var email_title: String + var email_title: String is noautoinit # Generate email and fill the attributes `email_content` and `email_title` fun generate_email(beer_events: BeerEvents) @@ -229,7 +221,7 @@ end var ben = new Benitlux("sherbrooke") ben.run(opts.send_emails.value) -# The parsing logic for the wellington locaiton is active (to gather data) +# The parsing logic for the wellington location is active (to gather data) # but the web interface do not allow to subscribe to its mailing list. # # TODO revamp mailing list Web interface diff --git a/contrib/benitlux/src/benitlux_model.nit b/contrib/benitlux/src/benitlux_model.nit index f4aeae8..d3e440d 100644 --- a/contrib/benitlux/src/benitlux_model.nit +++ b/contrib/benitlux/src/benitlux_model.nit @@ -23,12 +23,6 @@ import serialization class Beer auto_serializable - init(name, desc: String) - do - self.name = name - self.desc = desc - end - # Name of the beer var name: String diff --git a/contrib/benitlux/src/correct.nit b/contrib/benitlux/src/correct.nit new file mode 100644 index 0000000..3c2384c --- /dev/null +++ b/contrib/benitlux/src/correct.nit @@ -0,0 +1,78 @@ +# 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. + +# Correct errors in beer names before using data from the DB +# +# Reads corrections from the file at `DB::corrections_path` which must be formatted like so: +# +# ~~~raw +# Wrong name -> Correct name +# Name with typo -> Clean name +# ~~~ +module correct + +import benitlux_db + +redef class DB + # Path to file with the corrections + private var corrections_path = "benitlux_corrections.txt" + + # Corrections of beer name: wrong name to corrected name + private var corrections: Map[String, String] is lazy do + var map = new HashMap[String, String] + + # Read from file + if corrections_path.file_exists then + var lines = corrections_path.to_path.read_lines + for line in lines do + var parts = line.split("->") + assert parts.length == 2 else print_error "Error: wrong format in '{corrections_path}'" + map[parts[0].trim] = parts[1].trim + end + end + + return map + end + + redef fun beers + do + var beers = super + if beers == null then return null + + # Skip corrected beers + for beer in beers.reverse_iterator do + if corrections.keys.has(beer.name) then + beers.remove beer + end + end + + return beers + end + + redef fun days(beer) + do + var days = super(beer) + if beer == null or days == null then return days + + # Merge days of `corrections` to `beer` + for from, to in corrections do + if to == beer.name then + var missing_days = super(new Beer(from, "")) + if missing_days != null then days.add_all missing_days + end + end + + return days + end +end diff --git a/contrib/benitlux/src/report.nit b/contrib/benitlux/src/report.nit index 54f22ad..084e935 100644 --- a/contrib/benitlux/src/report.nit +++ b/contrib/benitlux/src/report.nit @@ -14,6 +14,7 @@ import benitlux_model import benitlux_db +import correct # Sort beers by their availability class BeerComparator @@ -31,6 +32,20 @@ class BeerComparator else map1[a] <=> map1[b] end +redef class Text + + # Get the background for the date `self` of format `yyyy-mm-dd` + private fun date_to_back: String + do + assert length == 10 + + var m = substring(5, 2) + var month = m.to_i + if [4..9].has(month) then return " " + return "-" + end +end + # Use the local DB var db_path = "benitlux_sherbrooke.db" var db = new DB.open(db_path) @@ -94,20 +109,53 @@ sorter = new BeerComparator(appearances, availability) sorter.sort beers # Display the batch graph -print "\nBatches:" +print "\nAvailability graph:" # Compute `column_width` days from all the known days var column_width = 70 var days_sample = [for i in column_width.times do all_days[i*all_days.length/column_width]] +# Gather columns headers for each month +var headers = new Array[nullable String] +var pre = "" +for day in days_sample do + var new_pre = day.substring(0, 7) + + if not day.has_prefix(pre) then + headers.add new_pre + else headers.add null + + pre = new_pre +end + +# Draw the headers from top to bottom so they look like: +# +# ~~~ +# 2 +# 0 +# 1 +# 5 +# - +# 0 +# 1 +# ~~~ +for l in 7.times do + for header in headers do + if header != null then + printn header[l] + else printn " " + end + print "" +end + for beer in beers do var days = beer2days[beer] # Skip never-available beers, usually name errors if days.is_empty then continue - # Print a line looking like: " ############ ###### ######## : Beer" - for s in days_sample do printn if days.has(s) then "#" else " " + # Print a line looking like: " ############ ###### -----########-: Beer" + for s in days_sample do printn if days.has(s) then "#" else s.date_to_back print ": {beer.name}" end diff --git a/contrib/crazy_moles/.gitignore b/contrib/crazy_moles/.gitignore new file mode 100644 index 0000000..f4dac05 --- /dev/null +++ b/contrib/crazy_moles/.gitignore @@ -0,0 +1,3 @@ +icon.png +src/drawing.nit +assets/images/ diff --git a/contrib/crazy_moles/Makefile b/contrib/crazy_moles/Makefile new file mode 100644 index 0000000..06751d0 --- /dev/null +++ b/contrib/crazy_moles/Makefile @@ -0,0 +1,29 @@ +default: bin/moles + +bin/moles: $(shell ../../bin/nitls -M src/moles_linux.nit) assets/images/drawing.png + mkdir -p bin + ../../bin/nitc -o bin/moles src/moles_linux.nit + +android: android-icons $(shell ../../bin/nitls -M src/moles_android.nit) assets/images/drawing.png + mkdir -p bin + ../../bin/nitc -o bin/moles.apk src/moles_android.nit + +../inkscape_tools/bin/svg_to_icons: + $(MAKE) -C ../inkscape_tools + +android-icons: ../../contrib/inkscape_tools/bin/svg_to_icons art/icon.svg + mkdir -p res + ../inkscape_tools/bin/svg_to_icons art/icon.svg --android --out res/ + +android-install: android + adb install -rf bin/moles.apk + +assets/images/drawing.png: art/drawing.svg ../../contrib/inkscape_tools/bin/svg_to_icons + mkdir -p assets/images + ../inkscape_tools/bin/svg_to_png_and_nit --src src/ --scale 2.0 art/drawing.svg + +check-android: + ./check-android.sh + +clean: + rm -rf bin res diff --git a/contrib/crazy_moles/art/drawing.svg b/contrib/crazy_moles/art/drawing.svg new file mode 100644 index 0000000..76546a7 --- /dev/null +++ b/contrib/crazy_moles/art/drawing.svg @@ -0,0 +1,3383 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Warning! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Cute GroundhogInfestation!!! + + + + + + + + + + + + + + + + + + Hits: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 + - + + + + + + + + + + + + + + + + + + + HAHA! + + + + + + + + + + + + + + + + + + Points + + + + + + + + + + + + + + + + + + + diff --git a/examples/mnit_moles/art/icon.svg b/contrib/crazy_moles/art/icon.svg similarity index 100% rename from examples/mnit_moles/art/icon.svg rename to contrib/crazy_moles/art/icon.svg diff --git a/contrib/crazy_moles/check-android.sh b/contrib/crazy_moles/check-android.sh new file mode 100755 index 0000000..8596eef --- /dev/null +++ b/contrib/crazy_moles/check-android.sh @@ -0,0 +1,43 @@ +#!/bin/bash +# 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. + +set -x + +avd=android4.0 +sleep=20 + +android list avd | grep $avd + +if [ $? -eq 1 ]; then + echo no | android create avd -n $avd --snapshot -t android-15 --abi x86 || true + sleep=120 +fi + +#-no-window +emulator -avd android4.0 -no-window -qemu -m 512 -enable-kvm & + +sleep $sleep + +dev=`adb devices | grep emulator | sed "s/\(.*\)\s*device/\1/"` + +adb -s $dev install -r bin/moles.apk + +# Unlock screen +adb -s $dev shell input keyevent 82 + +adb -s $dev shell monkey -p org.nitlanguage.moles_android_debug \ + --monitor-native-crashes --throttle 5 --pct-touch 50 --pct-motion 50 1000 + +adb -s $dev emu kill diff --git a/examples/mnit_moles/org.nitlanguage.moles_android.txt b/contrib/crazy_moles/org.nitlanguage.moles_android.txt similarity index 100% rename from examples/mnit_moles/org.nitlanguage.moles_android.txt rename to contrib/crazy_moles/org.nitlanguage.moles_android.txt diff --git a/contrib/crazy_moles/src/effects.nit b/contrib/crazy_moles/src/effects.nit new file mode 100644 index 0000000..a34a864 --- /dev/null +++ b/contrib/crazy_moles/src/effects.nit @@ -0,0 +1,339 @@ +# 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. + +# Graphical effects +module effects + +intrude import geometry::points_and_lines +import mnit::opengles1 + +import moles + +# Position, or vector +class Pos + super Point[Float] + + # Addition of `self` and `other` + fun +(other: Pos): Pos do return new Pos(other.x + x, other.y + y) +end + +redef class PointerEvent + # Convert to `Pos` + fun to_pos: Pos do return new Pos(x, y) +end + +redef class Float + # Pretty alias to `pow` + private fun ^(other: Float): Float do return self.pow(other) +end + +# Graphical effect +abstract class Effect + # Time of creation since (appropriate) app lauch + var created_at: Float = app.clock.total.to_f + + # Is this effect dead? + var dead = false + + # Time to live of this effect, in seconds + var ttl: Float = ttl_base + ttl_rand.rand is lazy + + # Time to live base value + private var ttl_base: Float + + # Variation range to add to `ttl_base` + private var ttl_rand: Float + + private fun update_and_draw(display: Display, t: Float) do end +end + +# Full screen flash +class Flash + super Effect + + # Red value + var r: Float + + # Green value + var g: Float + + # Blue value + var b: Float + + # Start alpha value + var a: Float + + # Reduction in alpha value per seconds + var da: Float + + redef fun update_and_draw(display, t) + do + var dt = t - created_at + var a = a - da * dt + if a <= 0.0 then + dead = true + return + end + + native_flash(r, g, b, a, display.width.to_f, display.height.to_f) + end + + private fun native_flash(r, g, b, a, w, h: Float) `{ + GLfloat colors[] = + { + r, g, b, a, + r, g, b, a, + r, g, b, a, + r, g, b, a, + }; + GLfloat coords[] = + { + 0.0, 0.0, 0.0, + 0.0, h, 0.0, + w, 0.0, 0.0, + w, h, 0.0, + }; + + glLoadIdentity(); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glDisable(GL_DEPTH_TEST); + glDisable(GL_TEXTURE_2D); + + glVertexPointer(3, GL_FLOAT, 0, coords); + glColorPointer(4, GL_FLOAT, 0, colors); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + glDisable(GL_BLEND); + + if ((mnit_opengles_error_code = glGetError()) != GL_NO_ERROR) { + fprintf(stderr, "Error drawing: %i\n", mnit_opengles_error_code); + } + `} +end + +# Visible particle +abstract class Particle + super Effect + + # Effect image + var img: Image +end + +# Particle moving along a cubic Bézier curve +class CubicBezierParticle + super Particle + + # Points on this curve, from the start to the end with the handles in the middle + # + # Require: `points.length == 4` + var points: Array[Pos] + + redef fun update_and_draw(display, t) + do + assert points.length == 4 + + var dt = t - created_at + var p = dt / ttl + + var i = 1.0-p + var bx = i*i*i * points[0].x + 3.0*i*i*p * points[1].x + + 3.0*i*p*p * points[2].x + p*p*p*points[3].x + var by = i*i*i * points[0].y + 3.0*i*i*p * points[1].y + + 3.0*i*p*p * points[2].y + p*p*p*points[3].y + + img.scale = display_scale + if display isa Opengles1Display then display.color(1.0, 1.0, 1.0, p) + display.blit_centered(img, bx, by) + if display isa Opengles1Display then display.reset_color + + if dt > ttl then dead = true + end +end + +# Particle falling like a feather +class FeatheryParticle + super Particle + + # Origin of effect + var from: Pos + + # Randomized variation so this particle is unique + var ddt: Float = pi.rand + + # Direction: `-1.0` for left, `1.0` for right + var dir: Float = if 2.rand == 0 then -1.0 else 1.0 + + # Randomized variation on X + var ddx: Float = (4.0 - 8.0.rand)^2.0 + + # Randomized variation on Y + var ddy: Float = (12.0 - 24.0.rand)^2.0 + + redef fun update_and_draw(display, t) + do + var dt = t - created_at + + var dx = ddx + 30.0*(dt+ddt).sin + dx *= dir + var dy = ddy + 20.0*dt + 16.0*(dt*2.0+ddt*2.0).cos + var pos = from + new Pos(dx, dy) + + if display isa Opengles1Display then display.color(1.0, 1.0, 1.0, 5.0-5.0*dt/ttl) + display.blit_centered(img, pos.x, pos.y) + if display isa Opengles1Display then display.reset_color + + if dt > ttl then dead = true + end +end + +# Particles that start small then grow bigger and fade out +private class BlowUpParticle + super Particle + + # Origin/center of effect + var from: Pos + + redef fun update_and_draw(display, t) + do + var dt = t - created_at + var p = dt/ttl + + if display isa Opengles1Display then display.color(1.0, 1.0, 1.0, 2.0-p*2.0) + + img.scale = p*4.0*display_scale + display.blit_centered(img, from.x, from.y) + + if display isa Opengles1Display then display.reset_color + + if dt > ttl then dead = true + end +end + +redef class Screen + private var particles = new Array[Particle] + private var flashes = new Array[Flash] + + redef fun draw_hud(display) + do + var t = app.clock.total.to_f + + # Particles + for particle in particles do particle.update_and_draw(display, t) + for particle in particles.reverse_iterator do if particle.dead then + particles.remove particle + end + + # Flashes + for flash in flashes do flash.update_and_draw(display, t) + for flash in flashes.reverse_iterator do if flash.dead then + flashes.remove flash + end + + super + end + + private var score_center = new Pos(48.0*display_scale, 32.0*display_scale) is lazy + private var score_entry = new Pos(48.0*display_scale, 256.0*display_scale) is lazy + + private var score_history = new List[Int] + private var score_history_max_length = 60 + + redef fun draw_score(display, score) + do + # Use an history to smooth the score + score_history.add game.points + if score_history.length > score_history_max_length then score_history.shift + var sum = 0 + for h in score_history do sum += h + var avg = sum.to_f/score_history.length.to_f + var d = game.points.to_f - avg + + # Color the score according to positive or negative changes + var r = 1.0 + var g = 1.0 + var b = 1.0 + if d > 0.0 then + r = 1.0-d.to_f/2.0 + b = r + g = 1.0-d.to_f/10.0 + else if d < 0.0 then + g = 1.0+d.to_f/5.0 + b = g + end + + if display isa Opengles1Display then display.color(r, g, b, 1.0) + + # Draw the score itself + super(display, avg.to_i) + + if display isa Opengles1Display then display.reset_color + end +end + +redef class HoleContent + # Add a `CubicBezierParticle` from `event` to the score box with `img` + private fun bezier_to_score(img: Image, event: PointerEvent) + do + app.screen.particles.add new CubicBezierParticle(2.0, 0.0, img, + [event.to_pos, event.to_pos + new Pos(0.0, -128.0), + app.screen.score_entry, app.screen.score_center]) + end +end + +redef class Mole + + # Number of hair particles + private var n_hair_on_hit = 20 + + redef fun hit(game, hole, event) + do + super + + app.assets.hair.scale = display_scale + for i in n_hair_on_hit.times do + app.screen.particles.add new FeatheryParticle(2.0, 2.0, app.assets.hair, event.to_pos) + end + + bezier_to_score(app.assets.point, event) + app.screen.particles.add new BlowUpParticle(0.5, 0.0, app.assets.point, event.to_pos) + end +end + +redef class Trap + # Image for `CubicBezierParticle` effect towards the score board + protected fun penalty_img: Image do return app.assets.penalty_ten + + # `Flash` effects on hit + protected fun flashes: Array[Flash] do + return [new Flash(0.5, 0.0, 1.0, 0.0, 0.0, 0.5, 2.0)] + end + + redef fun hit(game, hole, event) + do + super + + bezier_to_score(penalty_img, event) + app.screen.particles.add new BlowUpParticle(0.5, 0.0, penalty_img, event.to_pos) + + app.screen.flashes.add_all flashes + end +end diff --git a/contrib/crazy_moles/src/moles.nit b/contrib/crazy_moles/src/moles.nit new file mode 100644 index 0000000..27ca3ad --- /dev/null +++ b/contrib/crazy_moles/src/moles.nit @@ -0,0 +1,349 @@ +# This file is part of NIT (http://www.nitlanguage.org). +# +# Copyright 2012-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. + +# Classic moles game +# +# This is a minimal practical example of the mnit framework. +module moles is + app_version(1, 0, git_revision) + app_name("Crazy Groundhogs") +end + +import mnit +import realtime + +import drawing + +# A hole with a possible mole, or a trap in it +class Hole + var game: Game + + # Horizontal center of the hole + var x: Int + + # Vertical center of the hole + var y: Int + + # Half width of the hit box + var dx = 200.0 + + # Height of the hit box + var dy = 800.0 + + # Content (and state) of this hole + var content: nullable HoleContent = null + + # Time at witch this hole can act again + var timeout_until: Float = app.clock.total.to_f is lazy + + # Timeout for 1/2 sec or less with a higher score + private fun reset_timeout do + timeout_until = app.clock.total.to_f + + 0.5 - 0.4 * (game.points.to_f / 1000.0).min(1.0) + end + + fun do_turn + do + if timeout_until > app.clock.total.to_f then return + + var content = content + if content != null then + if content == game.down then + if (20.0*game.speed_modifier).to_i.rand == 0 then + # dead / hide + self.content = null + reset_timeout + end + else if (80.0*game.speed_modifier).to_i.rand == 0 then + # hide + self.content = null + reset_timeout + end + else if (100.0*game.speed_modifier).to_i.rand == 0 then + self.content = to_pop + reset_timeout + end + end + + # Get next `HoleContent` to pop + fun to_pop: HoleContent + do + # show traps only at 10 points and up + if game.points > 10 then + + # After 50 points we have more and more traps until point 1000 + var d = 1250-(game.points - 50) + if d < 200 then d = 200 + + if d.rand < 100 then return game.trap + end + + return game.up + end + + # Does this hole intercepts `event`? + fun intercepts(event: PointerEvent): Bool + do + if content == null then return false + + var dx = (dx*display_scale).to_i + var dy = (dy*display_scale).to_i + var ex = event.x.to_i - display_offset_x + var ey = event.y.to_i - display_offset_y + return ex > x - dx and ex < x + dx and + ey > y - dy and ey < y + end + + # Draw this hole and content to `display` + fun draw(display: Display) + do + # The hole itself + var img = app.assets.empty + var dx = 300.0*display_scale + var dy = 256.0*display_scale + img.scale = display_scale + display.blit(img, x-dx.to_i+display_offset_x, y-dy.to_i+display_offset_y) + + # The mole in the hole, or other content + var content = self.content + if content != null then + content.draw(display, x, y) + end + end +end + +# Content of a `Hole` +class HoleContent + # Image + var img: Image + + # Offset of the horizontal center of the hole + var dx: Float + + # Offset of the vertical center of the hole + var dy: Float + + # Hit this hole content + fun hit(game: Game, hole: Hole, event: PointerEvent) do end + + # Draw this content to `display` + fun draw(display: Display, x, y: Int) + do + img.scale = display_scale + display.blit(img, + x-dx.to_i+display_offset_x, + y-dy.to_i+display_offset_y) + end +end + +# A mole in a hole +class Mole + super HoleContent + + # Points value when hit + var value: Int + + redef fun hit(game, hole, event) + do + game.points += value + hole.content = game.down + end +end + +# A trap held out of a hole +class Trap + super HoleContent + + # Points penalty when hit + var penalty: Int + + redef fun hit(game, hole, event) + do + game.points -= penalty + if game.points < 0 then game.points = 0 + hole.content = null + end +end + +class Game + # All holes, filled or not + var holes = new Array[Hole] + + # rule / const + var modifier_half_life = 1000.0 + + # Row count + fun rows: Int do return 4 + + # Columns count + fun columns: Int do return 5 + + # Score + var points = 0 + + # Acceleration + var speed_modifier = 1.0 + + # Vertical offset between rows + var dist_between_rows = 448 + + # Horizontal offset between columns + var dist_between_columns = 600 + + # Global accumulation control, applied to `speed_modifier` + fun global_speed_modifier: Float do return 2.0 + + # A mole, in a hole + var up = new Mole(app.assets.up, 212.0*display_scale, 820.0*display_scale, 1) is lazy + + # A mole that was hit + var down = new HoleContent(app.assets.hit, 250.0*display_scale, 512.0*display_scale) is lazy + + # A trap out of the hole + var trap = new Trap(app.assets.trap, 212.0*display_scale, 830.0*display_scale, 10) is lazy + + init + do + var dx = (dist_between_columns.to_f*display_scale).to_i + var dy = (dist_between_rows.to_f*display_scale).to_i + for x in [0 .. columns[ do + for y in [0 .. rows[ do + holes.add(new Hole(self, x*dx, y*dy)) + end + end + end + + fun do_turn + do + for hole in holes do hole.do_turn + + speed_modifier = modifier_half_life / (modifier_half_life+points.to_f) * global_speed_modifier + end +end + +# Where all the UI stuff is done +class Screen + # The running game + var game = new Game is lazy + + fun do_frame(display: Display) + do + display.clear(0.0, 0.45, 0.0) + + app.assets.sign_warning.scale = display_scale + display.blit(app.assets.sign_warning, (380.0*display_scale).to_i, (256.0*display_scale).to_i) + + app.assets.sign_cute.scale = display_scale + display.blit(app.assets.sign_cute, (1024.0*display_scale).to_i, (64.0*display_scale).to_i) + + for hole in game.holes do + hole.draw display + end + + draw_hud display + end + + fun input(event: InputEvent): Bool + do + if event isa PointerEvent then + for hole in game.holes.reverse_iterator do + if hole.intercepts(event) then + var hole_content = hole.content + if hole_content != null then hole_content.hit(game, hole, event) + return true + end + end + end + + return false + end + + # Draw the HUD as the topmost layer of the screen + fun draw_hud(display: Display) + do + var board = app.assets.points_board + board.scale = display_scale + display.blit(board, (32.0*display_scale).to_i, -10) + + draw_score(display) + end + + # Draw the score + fun draw_score(display: Display, score: nullable Int) + do + if score == null then score = game.points + + # Draw the score itself + for img in app.numbers.imgs do img.scale = display_scale + display.blit_number(app.numbers, score, + (92.0*display_scale).to_i, + (172.0*display_scale).to_i) + end +end + +redef class App + + # Main play screen + var screen = new Screen + + # Image set generate by inkscape_tools + var assets = new DrawingImages + + # Numbers to display the score + var numbers = new NumberImages(assets.n) + + # Elapsed time since program launch + var clock = new Clock + + redef fun on_start + do + super + assets.load_all self + end + + redef fun on_create + do + super + + maximum_fps = 50 + end + + redef fun frame_core(display) + do + screen.game.do_turn + screen.do_frame(display) + end + + redef fun input(ie) + do + if ie isa QuitEvent or + (ie isa KeyEvent and ie.to_c == 'q') then + quit = true + return true + end + + return screen.input(ie) + end +end + +# Main zoom +fun display_scale: Float do return 1.0 + +# Depends on the hole center in the uo image +fun display_offset_x: Int do return (512.0*display_scale).to_i + +# Depends on the width of the holes +fun display_offset_y: Int do return (1000.0*display_scale).to_i diff --git a/examples/mnit_moles/src/moles_android.nit b/contrib/crazy_moles/src/moles_android.nit similarity index 83% rename from examples/mnit_moles/src/moles_android.nit rename to contrib/crazy_moles/src/moles_android.nit index 677cb5b..1da39be 100644 --- a/examples/mnit_moles/src/moles_android.nit +++ b/contrib/crazy_moles/src/moles_android.nit @@ -20,6 +20,8 @@ import mnit_android import android::portrait import moles +import effects +import more_traps redef class Game redef fun columns do return 3 @@ -27,7 +29,7 @@ redef class Game end redef class App - redef fun init_screen_and_game + redef fun on_start do # We use as a reference the Moto X var tw = 720 @@ -38,10 +40,7 @@ redef class App var ys = display.height.to_f/th.to_f*0.4 # Use the smaller scale so everything fits - # FIXME replace these conditions with xs.min(ys) when Float isa Comparable - if xs < ys then - display_scale_container.item = xs - else display_scale_container.item = ys + display_scale_container.item = xs.min(ys) super end @@ -50,4 +49,3 @@ end fun display_scale_container: Ref[Float] do return once new Ref[Float](0.1) redef fun display_scale do return display_scale_container.item redef fun display_offset_x: Int do return (300.0*display_scale).to_i -redef fun display_offset_y: Int do return (800.0*display_scale).to_i diff --git a/examples/mnit_moles/src/moles_linux.nit b/contrib/crazy_moles/src/moles_linux.nit similarity index 95% rename from examples/mnit_moles/src/moles_linux.nit rename to contrib/crazy_moles/src/moles_linux.nit index f7ddd91..66a645a 100644 --- a/examples/mnit_moles/src/moles_linux.nit +++ b/contrib/crazy_moles/src/moles_linux.nit @@ -16,7 +16,10 @@ module moles_linux -import moles import mnit_linux +import moles +import effects +import more_traps + redef fun display_scale do return 0.25 diff --git a/contrib/crazy_moles/src/more_traps.nit b/contrib/crazy_moles/src/more_traps.nit new file mode 100644 index 0000000..cf64cc5 --- /dev/null +++ b/contrib/crazy_moles/src/more_traps.nit @@ -0,0 +1,58 @@ +# 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. + +# Add more traps +module more_traps + +import moles +import effects + +# Nuclear trap +class Nuke + super Trap + + redef fun penalty_img do return app.assets.penalty_hundred + + redef fun flashes do return [ + new Flash(5.0, 0.0, 1.0, 0.0, 0.0, 1.25, 2.0), + new Flash(0.2, 0.0, 1.0, 1.0, 1.0, 1.0, 2.0)] +end + +# Large cactus trap +class BigTrap + super Trap + + redef fun penalty_img do return app.assets.penalty_twenty +end + +redef class Game + + # Nuclear trap + var nuke = new Nuke(app.assets.nuke, 180.0*display_scale, 780.0*display_scale, 100) is lazy + + # Large cactus trap + var big_cactus = new BigTrap(app.assets.big_cactus, 242.0*display_scale, 820.0*display_scale, 20) is lazy +end + +redef class Hole + redef fun to_pop + do + if game.points > 25 then + if 25.rand == 0 then return game.big_cactus + if game.points > 50 and 100.rand == 0 then return game.nuke + end + + return super + end +end diff --git a/contrib/tinks/src/client/client.nit b/contrib/tinks/src/client/client.nit index 32a9852..8dad5eb 100644 --- a/contrib/tinks/src/client/client.nit +++ b/contrib/tinks/src/client/client.nit @@ -276,26 +276,7 @@ redef class App end # Events - for event in turn.events do - event.client_react(display, turn) - - if event isa ExplosionEvent then - var pos = event.pos.to_screen(camera) - display.blit_centered(assets.drawing.explosion, pos.x, pos.y) - else if event isa OpenFireEvent then - var tank = event.tank - var screen_pos = tank.pos.to_screen(camera) - display.blit_rotated(assets.drawing.turret_firing, screen_pos.x, screen_pos.y, tank.turret.heading) - - if tank.pos.dist2(camera.center(display)) < far_dist2 then - assets.turret_fire.play - end - else if event isa TurretReadyEvent then - if event.tank.pos.dist2(camera.center(display)) < far_dist2 then - assets.turret_ready.play - end - end - end + for event in turn.events do event.client_react(display, turn) # Gather and show some performance stats! sys.perfs["draw"].add clock.lapse diff --git a/examples/mnit_moles/.gitignore b/examples/mnit_moles/.gitignore deleted file mode 100644 index 18c4e15..0000000 --- a/examples/mnit_moles/.gitignore +++ /dev/null @@ -1 +0,0 @@ -icon.png diff --git a/examples/mnit_moles/Makefile b/examples/mnit_moles/Makefile deleted file mode 100644 index 1c4c732..0000000 --- a/examples/mnit_moles/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -default: linux - -linux: - mkdir -p bin - ../../bin/nitc -o bin/moles src/moles_linux.nit - -android: android-icons - mkdir -p bin - ../../bin/nitc -o bin/moles.apk src/moles_android.nit - -../../contrib/inkscape_tools/bin/svg_to_icons: - $(MAKE) -C ../../contrib/inkscape_tools - -android-icons: ../../contrib/inkscape_tools/bin/svg_to_icons - mkdir -p res - ../../contrib/inkscape_tools/bin/svg_to_icons art/icon.svg --android --out res/ - -android-install: android - adb install -rf bin/moles.apk - -pngs: - mkdir -p assets/images - ../mnit_dino/tools/svg-to-pngs art/drawing.svg assets/images - -clean: - rm -rf bin res diff --git a/examples/mnit_moles/art/drawing.svg b/examples/mnit_moles/art/drawing.svg deleted file mode 100644 index f63fd06..0000000 --- a/examples/mnit_moles/art/drawing.svg +++ /dev/null @@ -1,1942 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Warning! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cute GroundhogInfestation!!! - - - - - - - - - - - - - - - - - - Hits: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/examples/mnit_moles/assets/images/0.png b/examples/mnit_moles/assets/images/0.png deleted file mode 100644 index b471835..0000000 Binary files a/examples/mnit_moles/assets/images/0.png and /dev/null differ diff --git a/examples/mnit_moles/assets/images/1.png b/examples/mnit_moles/assets/images/1.png deleted file mode 100644 index 2a5ae86..0000000 Binary files a/examples/mnit_moles/assets/images/1.png and /dev/null differ diff --git a/examples/mnit_moles/assets/images/2.png b/examples/mnit_moles/assets/images/2.png deleted file mode 100644 index 113e0eb..0000000 Binary files a/examples/mnit_moles/assets/images/2.png and /dev/null differ diff --git a/examples/mnit_moles/assets/images/3.png b/examples/mnit_moles/assets/images/3.png deleted file mode 100644 index f94c43d..0000000 Binary files a/examples/mnit_moles/assets/images/3.png and /dev/null differ diff --git a/examples/mnit_moles/assets/images/4.png b/examples/mnit_moles/assets/images/4.png deleted file mode 100644 index 2e05015..0000000 Binary files a/examples/mnit_moles/assets/images/4.png and /dev/null differ diff --git a/examples/mnit_moles/assets/images/5.png b/examples/mnit_moles/assets/images/5.png deleted file mode 100644 index ac17174..0000000 Binary files a/examples/mnit_moles/assets/images/5.png and /dev/null differ diff --git a/examples/mnit_moles/assets/images/6.png b/examples/mnit_moles/assets/images/6.png deleted file mode 100644 index 122f412..0000000 Binary files a/examples/mnit_moles/assets/images/6.png and /dev/null differ diff --git a/examples/mnit_moles/assets/images/7.png b/examples/mnit_moles/assets/images/7.png deleted file mode 100644 index a341702..0000000 Binary files a/examples/mnit_moles/assets/images/7.png and /dev/null differ diff --git a/examples/mnit_moles/assets/images/8.png b/examples/mnit_moles/assets/images/8.png deleted file mode 100644 index 40c1c17..0000000 Binary files a/examples/mnit_moles/assets/images/8.png and /dev/null differ diff --git a/examples/mnit_moles/assets/images/9.png b/examples/mnit_moles/assets/images/9.png deleted file mode 100644 index 8263229..0000000 Binary files a/examples/mnit_moles/assets/images/9.png and /dev/null differ diff --git a/examples/mnit_moles/assets/images/empty.png b/examples/mnit_moles/assets/images/empty.png deleted file mode 100644 index 032d075..0000000 Binary files a/examples/mnit_moles/assets/images/empty.png and /dev/null differ diff --git a/examples/mnit_moles/assets/images/hit.png b/examples/mnit_moles/assets/images/hit.png deleted file mode 100644 index 1488e6a..0000000 Binary files a/examples/mnit_moles/assets/images/hit.png and /dev/null differ diff --git a/examples/mnit_moles/assets/images/sign-cute.png b/examples/mnit_moles/assets/images/sign-cute.png deleted file mode 100644 index bf1ab24..0000000 Binary files a/examples/mnit_moles/assets/images/sign-cute.png and /dev/null differ diff --git a/examples/mnit_moles/assets/images/sign-hits.png b/examples/mnit_moles/assets/images/sign-hits.png deleted file mode 100644 index a8a9992..0000000 Binary files a/examples/mnit_moles/assets/images/sign-hits.png and /dev/null differ diff --git a/examples/mnit_moles/assets/images/sign-warning.png b/examples/mnit_moles/assets/images/sign-warning.png deleted file mode 100644 index 62b7688..0000000 Binary files a/examples/mnit_moles/assets/images/sign-warning.png and /dev/null differ diff --git a/examples/mnit_moles/assets/images/trap.png b/examples/mnit_moles/assets/images/trap.png deleted file mode 100644 index c795661..0000000 Binary files a/examples/mnit_moles/assets/images/trap.png and /dev/null differ diff --git a/examples/mnit_moles/assets/images/up.png b/examples/mnit_moles/assets/images/up.png deleted file mode 100644 index 84cb8d0..0000000 Binary files a/examples/mnit_moles/assets/images/up.png and /dev/null differ diff --git a/examples/mnit_moles/src/moles.nit b/examples/mnit_moles/src/moles.nit deleted file mode 100644 index c3824a4..0000000 --- a/examples/mnit_moles/src/moles.nit +++ /dev/null @@ -1,277 +0,0 @@ -# This file is part of NIT (http://www.nitlanguage.org). -# -# Copyright 2012-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. - -# Classic moles game -# -# This is a minimal practical example of the mnit framework. -module moles is - app_version(1, 0, git_revision) - app_name("Crazy Groundhogs") -end - -import mnit - -class Hole - var game: Game - - # Center of the hole - var x: Int - var y: Int - - # Half width of the hit box - var dx = 200.0 - # Heigth of the hit box - var dy = 800.0 - - # state - var up = false - var hitted = false - var trap = false - - init (g: Game, x, y: Int) - do - game = g - self.x = x - self.y = y - end - - fun do_turn - do - if up then - if hitted then - if (20.0*game.speed_modifier).to_i.rand == 0 then - # dead / hide - hitted = false - up = false - end - else if (80.0*game.speed_modifier).to_i.rand == 0 then - # hide - up = false - end - else if (100.0*game.speed_modifier).to_i.rand == 0 then - # show up - up = true - - # shot traps only at 50 points and up - trap = false - if game.points > 50 then - - # After 50 points we have more and more traps until point 1000 - var d = 1250-(game.points - 50) - if d < 200 then d = 200 - - if d.rand < 100 then trap = true - end - end - end - - fun intercepts(event: PointerEvent): Bool - do - if not up or hitted then return false - - var dx = (dx*display_scale).to_i - var dy = (dy*display_scale).to_i - var ex = event.x.to_i - display_offset_x - var ey = event.y.to_i - display_offset_y - return ex > x - dx and ex < x + dx and - ey > y - dy and ey < y - end - - fun hit - do - if hitted then return - - if trap then - up = false - game.points -= 5 - if game.points < 0 then game.points = 0 - else - hitted = true - game.points += 1 - end - end -end - -class Game - var holes = new Array[Hole].with_capacity(4) - - # rule / const - var modifier_half_life = 1000.0 - fun rows: Int do return 4 - fun columns: Int do return 5 - - # state - var points = 0 - var speed_modifier = 1.0 - - # configs - var dist_between_rows = 512 - var dist_between_columns = 600 - fun global_speed_modifier: Float do return 2.0 - - init - do - var dx = (dist_between_columns.to_f*display_scale).to_i - var dy = (dist_between_rows.to_f*display_scale).to_i - for x in [0 .. columns[ do - for y in [0 .. rows[ do - holes.add(new Hole(self, x*dx, y*dy)) - end - end - end - - fun do_turn do - for hole in holes do hole.do_turn - - speed_modifier = modifier_half_life / (modifier_half_life+points.to_f) * global_speed_modifier - end -end - -# Where all the UI stuff is done -class Screen - var empty_img: Image - var up_img: Image - var hit_img: Image - var trap_img: Image - var numbers: NumberImages - - var sign_warning: Image - var sign_cute: Image - var sign_hits: Image - - var game = new Game - - init (app: App) - do - empty_img = app.load_image("images/empty.png") - up_img = app.load_image("images/up.png") - hit_img = app.load_image("images/hit.png") - trap_img = app.load_image("images/trap.png") - numbers = app.load_numbers("images/#.png") - - sign_warning = app.load_image("images/sign-warning.png") - sign_cute = app.load_image("images/sign-cute.png") - sign_hits = app.load_image("images/sign-hits.png") - end - - fun do_frame(display: Display) - do - display.clear(0.1, 0.65, 0.2) - - sign_warning.scale = display_scale - sign_cute.scale = display_scale - sign_hits.scale = display_scale - for img in numbers.imgs do img.scale = display_scale - - display.blit(sign_warning, (-120.0*display_scale).to_i, (-235.0*display_scale).to_i) - display.blit(sign_cute, (540.0*display_scale).to_i, (-180.0*display_scale).to_i) - display.blit(sign_hits, (1340.0*display_scale).to_i, (55.0*display_scale).to_i) - display.blit_number(numbers, game.points, (1460.0*display_scale).to_i, (270.0*display_scale).to_i) - - for hole in game.holes do - # Hole - var img = empty_img - var dx = 512.0*display_scale - var dy = 512.0*display_scale - img.scale = display_scale - display.blit(img, hole.x-dx.to_i+display_offset_x, hole.y-dy.to_i+display_offset_y) - - # Mole - var empty = false - if hole.hitted then - img = hit_img - dx = 256.0*display_scale - dy = 417.0*display_scale - else if hole.up then - if hole.trap then - img = trap_img - dx = 512.0*display_scale - dy = 830.0*display_scale - else - img = up_img - dx = 512.0*display_scale - dy = 830.0*display_scale - end - else empty = true - - if not empty then - img.scale = display_scale - display.blit(img, hole.x-dx.to_i+display_offset_x, hole.y-dy.to_i+display_offset_y) - end - end - end - - fun input(event: InputEvent): Bool - do - if event isa PointerEvent then - for hole in game.holes do - if hole.intercepts(event) then - if hole.up then hole.hit - return true - end - end - end - - return false - end -end - -redef class App - - var screen: nullable Screen = null - - redef fun on_create - do - super - - maximum_fps = 50 - init_screen_and_game - end - - fun init_screen_and_game do screen = new Screen(self) - - redef fun frame_core(display) - do - var screen = self.screen - if screen != null then - screen.game.do_turn - screen.do_frame(display) - end - end - - redef fun input(ie) - do - var screen = screen - if ie isa QuitEvent or - (ie isa KeyEvent and ie.to_c == 'q') then - quit = true - return true - else if screen != null then - return screen.input(ie) - else - print "unknown input: {ie}" - return false - end - end -end - -fun display_scale: Float do return 1.0 - -# Depends on the hole center in the uo image -fun display_offset_x: Int do return (512.0*display_scale).to_i - -# Depends on the width of the holes -fun display_offset_y: Int do return (800.0*display_scale).to_i diff --git a/lib/binary/binary.nit b/lib/binary/binary.nit index 263ad95..7e5c180 100644 --- a/lib/binary/binary.nit +++ b/lib/binary/binary.nit @@ -178,11 +178,13 @@ redef abstract class Reader # Returns a truncated string when an error is pending (`last_error != null`). fun read_string: String do - var buf = new FlatBuffer + var buf = new Bytes.empty loop var byte = read_byte - if byte == null or byte == 0x00u8 then return buf.to_s - buf.bytes.add byte + if byte == null or byte == 0u8 then + return buf.to_s + end + buf.add byte end end diff --git a/lib/graphs/digraph.nit b/lib/graphs/digraph.nit new file mode 100644 index 0000000..00807d3 --- /dev/null +++ b/lib/graphs/digraph.nit @@ -0,0 +1,907 @@ +# This file is part of NIT (http://www.nitlanguage.org). +# +# Copyright 2015 Alexandre Blondin Massé +# +# 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. + +# Implementation of directed graphs, also called digraphs. +# +# Overview +# ======== +# +# This module provides a simple interface together with a concrete +# implementation of directed graphs (or digraphs). +# +# The upper level interface is `Digraph` and contains all methods for digraphs +# that do not depend on the underlying data structure. More precisely, if basic +# operations such as `predecessors`, `successors`, `num_vertices`, etc. are +# implemented, then high level operations (such as computing the connected +# components or a shortest path between two vertices) can be easily derived. +# Also, all methods found in `Digraph` do no modify the graph. For mutable +# methods, one needs to check the `MutableDigraph` child class. Vertices can be +# any `Object`, but there is no information stored in the arcs, which are +# simple arrays of the form `[u,v]`, where `u` is the source of the arc and `v` +# is the target. +# +# There is currently only one concrete implementation named `HashDigraph` that +# makes use of the HashMap class for storing the predecessors and successors. +# It is therefore simple to provide another implementation: One only has to +# create a concrete specialization of either `Digraph` or `MutableDigraph`. +# +# Basic methods +# ============= +# +# To create an (empty) new graph whose keys are integers, one simply type +# ~~~ +# import digraph +# var g = new HashDigraph[Int] +# ~~~ +# +# Then we can add vertices and arcs. Note that if an arc is added whose source +# and target are not already in the digraph, the vertices are added beforehand. +# ~~~ +# import digraph +# var g = new HashDigraph[Int] +# g.add_vertex(0) +# g.add_vertex(1) +# g.add_arc(0,1) +# g.add_arc(1,2) +# assert g.to_s == "Digraph of 3 vertices and 2 arcs" +# ~~~ +# +# One might also create digraphs with strings in vertices, for instance to +# represent some directed relation. However, it is currently not possible to +# store values in the arcs. +# ~~~ +# import digraph +# var g = new HashDigraph[String] +# g.add_vertex("Amy") +# g.add_vertex("Bill") +# g.add_vertex("Chris") +# g.add_vertex("Diane") +# g.add_arc("Amy", "Bill") # Amy likes Bill +# g.add_arc("Bill", "Amy") # Bill likes Amy +# g.add_arc("Chris", "Diane") # and so on +# g.add_arc("Diane", "Amy") # and so on +# ~~~ +# +# `HashDigraph`s are mutable, i.e. one might remove arcs and/or vertices: +# ~~~ +# import digraph +# var g = new HashDigraph[Int] +# g.add_arc(0,1) +# g.add_arc(0,2) +# g.add_arc(1,2) +# g.add_arc(2,3) +# g.add_arc(2,4) +# g.remove_vertex(1) +# g.remove_arc(2, 4) +# assert g.to_s == "Digraph of 4 vertices and 2 arcs" +# ~~~ +# +# If one has installed [Graphviz](http://graphviz.org), it is easy to produce a +# *dot* file which Graphviz process into a picture: +# ~~~ +# import digraph +# var g = new HashDigraph[Int] +# g.add_arcs([[0,1],[0,2],[1,2],[2,3],[2,4]]) +# print g.to_dot +# # Then call "dot -Tpng -o graph.png" +# ~~~ +# +# ![A graph drawing produced by Graphviz](https://github.com/privat/nit/blob/master/lib/graph.png) +# +# Other methods +# ============= +# +# There exist other methods available for digraphs and many other will be +# implemented in the future. For more details, one should look at the methods +# directly. For instance, the [strongly connected components] +# (https://en.wikipedia.org/wiki/Strongly_connected_component) of a digraph are +# returned as a [disjoint set data structure] +# (https://en.wikipedia.org/wiki/Disjoint-set_data_structure) (i.e. a set of +# sets): +# ~~~ +# import digraph +# var g = new HashDigraph[Int] +# g.add_arcs([[1,2],[2,1],[2,3],[3,4],[4,5],[5,3]]) +# for component in g.strongly_connected_components.to_partitions +# do +# print component +# end +# # Prints [1,2] and [3,4,5] +# ~~~ +# +# It is also possible to compute a shortest (directed) path between two +# vertices: +# ~~~ +# import digraph +# var g = new HashDigraph[Int] +# g.add_arcs([[1,2],[2,1],[2,3],[3,4],[4,5],[5,3]]) +# var path = g.a_shortest_path(2, 4) +# if path != null then print path else print "No path" +# # Prints [2,3,4] +# path = g.a_shortest_path(4, 2) +# if path != null then print path else print "No path" +# # Prints "No path" +# ~~~ +# +# Extending the library +# ===================== +# +# There are at least two ways of providing new methods on digraphs. If the +# method is standard and could be useful to other users, you should consider +# including your implementation directly in this library. +# +# Otherwise, for personal use, you should simply define a new class inheriting +# from `HashDigraph` and add the new services. +module digraph + +# Interface for digraphs +interface Digraph[V: Object] + + ## ---------------- ## + ## Abstract methods ## + ## ---------------- ## + + # The number of vertices in this graph. + # + # ~~~ + # import digraph + # var g = new HashDigraph[Int] + # g.add_vertex(0) + # g.add_vertex(1) + # assert g.num_vertices == 2 + # g.add_vertex(0) + # assert g.num_vertices == 2 + # ~~~ + fun num_vertices: Int is abstract + + # The number of arcs in this graph. + # + # ~~~ + # import digraph + # var g = new HashDigraph[Int] + # g.add_arc(0, 1) + # assert g.num_arcs == 1 + # g.add_arc(0, 1) + # assert g.num_arcs == 1 + # g.add_arc(2, 3) + # assert g.num_arcs == 2 + # ~~~ + fun num_arcs: Int is abstract + + # Returns true if and only if `u` exists in this graph. + # + # ~~~ + # import digraph + # var g = new HashDigraph[Int] + # g.add_vertex(1) + # assert g.has_vertex(1) + # assert not g.has_vertex(0) + # g.add_vertex(1) + # assert g.has_vertex(1) + # assert not g.has_vertex(0) + # ~~~ + fun has_vertex(u: V): Bool is abstract + + # Returns true if and only if `(u,v)` is an arc in this graph. + # + # ~~~ + # import digraph + # var g = new HashDigraph[Int] + # g.add_arc(0, 1) + # g.add_arc(1, 2) + # assert g.has_arc(0, 1) + # assert g.has_arc(1, 2) + # assert not g.has_arc(0, 2) + # ~~~ + fun has_arc(u, v: V): Bool is abstract + + # Returns the predecessors of `u`. + # + # If `u` does not exist, then it returns null. + # + # ~~~ + # import digraph + # var g = new HashDigraph[Int] + # g.add_arc(0, 1) + # g.add_arc(1, 2) + # g.add_arc(0, 2) + # assert g.predecessors(2).has(0) + # assert g.predecessors(2).has(1) + # assert not g.predecessors(2).has(2) + # ~~~ + fun predecessors(u: V): Collection[V] is abstract + + # Returns the successors of `u`. + # + # If `u` does not exist, then an empty collection is returned. + # + # ~~~ + # import digraph + # var g = new HashDigraph[Int] + # g.add_arc(0, 1) + # g.add_arc(1, 2) + # g.add_arc(0, 2) + # assert not g.successors(0).has(0) + # assert g.successors(0).has(1) + # assert g.successors(0).has(2) + # ~~~ + fun successors(u: V): Collection[V] is abstract + + # Returns an iterator over the vertices of this graph. + # + # ~~~ + # import digraph + # var g = new HashDigraph[Int] + # g.add_arc(0, 1) + # g.add_arc(0, 2) + # g.add_arc(1, 2) + # var vs = new HashSet[Int] + # for v in g.vertices_iterator do vs.add(v) + # assert vs == new HashSet[Int].from([0,1,2]) + # ~~~ + fun vertices_iterator: Iterator[V] is abstract + + ## -------------------- ## + ## Non abstract methods ## + ## -------------------- ## + + ## ------------- ## + ## Basic methods ## + ## ------------- ## + + # Returns true if and only if this graph is empty. + # + # An empty graph is a graph without vertex and arc. + # + # ~~~ + # import digraph + # assert (new HashDigraph[Int]).is_empty + # ~~~ + fun is_empty: Bool do return num_vertices == 0 and num_arcs == 0 + + # Returns an array containing the vertices of this graph. + # + # ~~~ + # import digraph + # var g = new HashDigraph[Int] + # g.add_vertices([0,2,4,5]) + # assert g.vertices.length == 4 + # ~~~ + fun vertices: Array[V] do return [for u in vertices_iterator do u] + + # Returns an iterator over the arcs of this graph + # + # ~~~ + # import digraph + # var g = new HashDigraph[Int] + # g.add_arc(0, 1) + # g.add_arc(0, 2) + # g.add_arc(1, 2) + # for arc in g.arcs_iterator do + # assert g.has_arc(arc[0], arc[1]) + # end + # ~~~ + fun arcs_iterator: Iterator[Array[V]] do return new ArcsIterator[V](self) + + # Returns the arcs of this graph. + # + # ~~~ + # import digraph + # var g = new HashDigraph[Int] + # g.add_arc(1, 3) + # g.add_arc(2, 3) + # assert g.arcs.length == 2 + # ~~~ + fun arcs: Array[Array[V]] do return [for arc in arcs_iterator do arc] + + # Returns the incoming arcs of vertex `u`. + # + # If `u` is not in this graph, an empty array is returned. + # + # ~~~ + # import digraph + # var g = new HashDigraph[Int] + # g.add_arc(1, 3) + # g.add_arc(2, 3) + # for arc in g.incoming_arcs(3) do + # assert g.is_predecessor(arc[0], arc[1]) + # end + # ~~~ + fun incoming_arcs(u: V): Collection[Array[V]] + do + if has_vertex(u) then + return [for v in predecessors(u) do [v, u]] + else + return new Array[Array[V]] + end + end + + # Returns the outgoing arcs of vertex `u`. + # + # If `u` is not in this graph, an empty array is returned. + # + # ~~~ + # import digraph + # var g = new HashDigraph[Int] + # g.add_arc(1, 3) + # g.add_arc(2, 3) + # g.add_arc(1, 2) + # for arc in g.outgoing_arcs(1) do + # assert g.is_successor(arc[1], arc[0]) + # end + # ~~~ + fun outgoing_arcs(u: V): Collection[Array[V]] + do + if has_vertex(u) then + return [for v in successors(u) do [u, v]] + else + return new Array[Array[V]] + end + end + + ## ---------------------- ## + ## String representations ## + ## ---------------------- ## + + redef fun to_s + do + var vertex_word = "vertices" + var arc_word = "arcs" + if num_vertices <= 1 then vertex_word = "vertex" + if num_arcs <= 1 then arc_word = "arc" + return "Digraph of {num_vertices} {vertex_word} and {num_arcs} {arc_word}" + end + + # Returns a GraphViz string representing this digraph. + fun to_dot: String + do + var s = "digraph \{\n" + # Writing the vertices + for u in vertices_iterator do + s += " \"{u.to_s.escape_to_dot}\" " + s += "[label=\"{u.to_s.escape_to_dot}\"];\n" + end + # Writing the arcs + for arc in arcs do + s += " {arc[0].to_s.escape_to_dot} " + s += "-> {arc[1].to_s.escape_to_dot};" + end + s += "\}" + return s + end + + ## ------------ ## + ## Neighborhood ## + ## ------------ ## + + # Returns true if and only if `u` is a predecessor of `v`. + # + # ~~~ + # import digraph + # var g = new HashDigraph[Int] + # g.add_arc(1, 3) + # assert g.is_predecessor(1, 3) + # assert not g.is_predecessor(3, 1) + # ~~~ + fun is_predecessor(u, v: V): Bool do return has_arc(u, v) + + # Returns true if and only if `u` is a successor of `v`. + # + # ~~~ + # import digraph + # var g = new HashDigraph[Int] + # g.add_arc(1, 3) + # assert not g.is_successor(1, 3) + # assert g.is_successor(3, 1) + # ~~~ + fun is_successor(u, v: V): Bool do return has_arc(v, u) + + # Returns the number of arcs whose target is `u`. + # + # ~~~ + # import digraph + # var g = new HashDigraph[Int] + # g.add_arc(1, 3) + # g.add_arc(2, 3) + # assert g.in_degree(3) == 2 + # assert g.in_degree(1) == 0 + # ~~~ + fun in_degree(u: V): Int do return predecessors(u).length + + # Returns the number of arcs whose source is `u`. + # + # ~~~ + # import digraph + # var g = new HashDigraph[Int] + # g.add_arc(1, 2) + # g.add_arc(1, 3) + # g.add_arc(2, 3) + # assert g.out_degree(3) == 0 + # assert g.out_degree(1) == 2 + # ~~~ + fun out_degree(u: V): Int do return successors(u).length + + # ------------------ # + # Paths and circuits # + # ------------------ # + + # Returns true if and only if `vertices` is a path of this digraph. + # + # ~~~ + # import digraph + # var g = new HashDigraph[Int] + # g.add_arc(1, 2) + # g.add_arc(2, 3) + # g.add_arc(3, 4) + # assert g.has_path([1,2,3]) + # assert not g.has_path([1,3,3]) + # ~~~ + fun has_path(vertices: SequenceRead[V]): Bool + do + for i in [0..vertices.length - 1[ do + if not has_arc(vertices[i], vertices[i + 1]) then return false + end + return true + end + + # Returns true if and only if `vertices` is a circuit of this digraph. + # + # ~~~ + # import digraph + # var g = new HashDigraph[Int] + # g.add_arc(1, 2) + # g.add_arc(2, 3) + # g.add_arc(3, 1) + # assert g.has_circuit([1,2,3,1]) + # assert not g.has_circuit([1,3,2,1]) + # ~~~ + fun has_circuit(vertices: SequenceRead[V]): Bool + do + return vertices.is_empty or (has_path(vertices) and vertices.first == vertices.last) + end + + # Returns a shortest path from vertex `u` to `v`. + # + # If no path exists between `u` and `v`, it returns `null`. + # + # ~~~ + # import digraph + # var g = new HashDigraph[Int] + # g.add_arc(1, 2) + # g.add_arc(2, 3) + # g.add_arc(3, 4) + # assert g.a_shortest_path(1, 4).length == 4 + # g.add_arc(1, 3) + # assert g.a_shortest_path(1, 4).length == 3 + # assert g.a_shortest_path(4, 1) == null + # ~~~ + fun a_shortest_path(u, v: V): nullable Sequence[V] + do + var queue = new List[V].from([u]).as_fifo + var pred = new HashMap[V, nullable V] + var visited = new HashSet[V] + var w: nullable V = null + pred[u] = null + while not queue.is_empty do + w = queue.take + if not visited.has(w) then + visited.add(w) + if w == v then break + for wp in successors(w) do + if not pred.keys.has(wp) then + queue.add(wp) + pred[wp] = w + end + end + end + end + if w != v then + return null + else + var path = new List[V] + path.add(v) + w = v + while pred[w] != null do + path.unshift(pred[w].as(not null)) + w = pred[w] + end + return path + end + end + + # Returns the distance between `u` and `v` + # + # If no path exists between `u` and `v`, it returns null. It is not + # symmetric, i.e. we may have `dist(u, v) != dist(v, u)`. + # + # ~~~ + # import digraph + # var g = new HashDigraph[Int] + # g.add_arc(1, 2) + # g.add_arc(2, 3) + # g.add_arc(3, 4) + # assert g.distance(1, 4) == 3 + # g.add_arc(1, 3) + # assert g.distance(1, 4) == 2 + # assert g.distance(4, 1) == null + # ~~~ + fun distance(u, v: V): nullable Int + do + var queue = new List[V].from([u]).as_fifo + var dist = new HashMap[V, Int] + var visited = new HashSet[V] + var w: nullable V + dist[u] = 0 + while not queue.is_empty do + w = queue.take + if not visited.has(w) then + visited.add(w) + if w == v then break + for wp in successors(w) do + if not dist.keys.has(wp) then + queue.add(wp) + dist[wp] = dist[w] + 1 + end + end + end + end + return dist.get_or_null(v) + end + + # -------------------- # + # Connected components # + # -------------------- # + + # Returns the weak connected components of this digraph. + # + # The weak connected components of a digraph are the usual + # connected components of its associated undirected graph, + # i.e. the graph obtained by replacing each arc by an edge. + # + # ~~~ + # import digraph + # var g = new HashDigraph[Int] + # g.add_arc(1, 2) + # g.add_arc(2, 3) + # g.add_arc(4, 5) + # assert g.weakly_connected_components.number_of_subsets == 2 + # ~~~ + fun weakly_connected_components: DisjointSet[V] + do + var components = new DisjointSet[V] + components.add_all(vertices) + for arc in arcs_iterator do + components.union(arc[0], arc[1]) + end + return components + end + + # Returns the strongly connected components of this digraph. + # + # Two vertices `u` and `v` belong to the same strongly connected + # component if and only if there exists a path from `u` to `v` + # and there exists a path from `v` to `u`. + # + # This is computed in linear time (Tarjan's algorithm). + # + # ~~~ + # import digraph + # var g = new HashDigraph[Int] + # g.add_arc(1, 2) + # g.add_arc(2, 3) + # g.add_arc(3, 1) + # g.add_arc(3, 4) + # g.add_arc(4, 5) + # g.add_arc(5, 6) + # g.add_arc(6, 5) + # assert g.strongly_connected_components.number_of_subsets == 3 + # ~~~ + fun strongly_connected_components: DisjointSet[V] + do + var tarjanAlgorithm = new TarjanAlgorithm[V](self) + return tarjanAlgorithm.strongly_connected_components + end +end + +# Computing the strongly connected components using Tarjan's algorithm +private class TarjanAlgorithm[V: Object] + # The graph whose strongly connected components will be computed + var graph: Digraph[V] + # The strongly connected components computed in Tarjan's algorithm + var sccs = new DisjointSet[V] + # An index used for Tarjan's algorithm + var index = 0 + # A stack used for Tarjan's algorithm + var stack: Queue[V] = (new Array[V]).as_lifo + # A map associating with each vertex its index + var vertex_to_index = new HashMap[V, Int] + # A map associating with each vertex its ancestor in Tarjan's algorithm + var ancestor = new HashMap[V, Int] + # True if and only if the vertex is in the stack + var in_stack = new HashSet[V] + + # Returns the strongly connected components of a graph + fun strongly_connected_components: DisjointSet[V] + do + for u in graph.vertices_iterator do sccs.add(u) + for v in graph.vertices_iterator do + visit(v) + end + return sccs + end + + # The recursive part of Tarjan's algorithm + fun visit(u: V) + do + vertex_to_index[u] = index + ancestor[u] = index + index += 1 + stack.add(u) + in_stack.add(u) + for v in graph.successors(u) do + if not vertex_to_index.keys.has(v) then + visit(v) + ancestor[u] = ancestor[u].min(ancestor[v]) + else if in_stack.has(v) then + ancestor[u] = ancestor[u].min(vertex_to_index[v]) + end + end + if vertex_to_index[u] == ancestor[u] then + var v + loop + v = stack.take + in_stack.remove(v) + sccs.union(u, v) + if u == v then break + end + end + end +end + +# Arcs iterator +class ArcsIterator[V: Object] + super Iterator[Array[V]] + + # The graph whose arcs are iterated over + var graph: Digraph[V] + # Attributes + # + private var sources_iterator: Iterator[V] is noinit + private var targets_iterator: Iterator[V] is noinit + init + do + sources_iterator = graph.vertices_iterator + if sources_iterator.is_ok then + targets_iterator = graph.successors(sources_iterator.item).iterator + if not targets_iterator.is_ok then update_iterators + end + end + + redef fun is_ok do return sources_iterator.is_ok and targets_iterator.is_ok + + redef fun item do return [sources_iterator.item, targets_iterator.item] + + redef fun next + do + targets_iterator.next + update_iterators + end + + private fun update_iterators + do + while not targets_iterator.is_ok and sources_iterator.is_ok + do + sources_iterator.next + if sources_iterator.is_ok then + targets_iterator = graph.successors(sources_iterator.item).iterator + end + end + end +end + +# Mutable digraph +abstract class MutableDigraph[V: Object] + super Digraph[V] + + ## ---------------- ## + ## Abstract methods ## + ## ---------------- ## + + # Adds the vertex `u` to this graph. + # + # If `u` already belongs to the graph, then nothing happens. + # + # ~~~ + # import digraph + # var g = new HashDigraph[Int] + # g.add_vertex(0) + # assert g.has_vertex(0) + # assert not g.has_vertex(1) + # g.add_vertex(1) + # assert g.num_vertices == 2 + # ~~~ + fun add_vertex(u: V) is abstract + + # Removes the vertex `u` from this graph and all its incident arcs. + # + # If the vertex does not exist in the graph, then nothing happens. + # + # ~~~ + # import digraph + # var g = new HashDigraph[Int] + # g.add_vertex(0) + # g.add_vertex(1) + # assert g.has_vertex(0) + # g.remove_vertex(0) + # assert not g.has_vertex(0) + # ~~~ + fun remove_vertex(u: V) is abstract + + # Adds the arc `(u,v)` to this graph. + # + # If there is already an arc from `u` to `v` in this graph, then + # nothing happens. If vertex `u` or vertex `v` do not exist in the + # graph, they are added. + # + # ~~~ + # import digraph + # var g = new HashDigraph[Int] + # g.add_arc(0, 1) + # g.add_arc(1, 2) + # assert g.has_arc(0, 1) + # assert g.has_arc(1, 2) + # assert not g.has_arc(1, 0) + # g.add_arc(1, 2) + # assert g.num_arcs == 2 + # ~~~ + fun add_arc(u, v: V) is abstract + + # Removes the arc `(u,v)` from this graph. + # + # If the arc does not exist in the graph, then nothing happens. + # + # ~~~ + # import digraph + # var g = new HashDigraph[Int] + # g.add_arc(0, 1) + # assert g.num_arcs == 1 + # g.remove_arc(0, 1) + # assert g.num_arcs == 0 + # g.remove_arc(0, 1) + # assert g.num_arcs == 0 + # ~~~ + fun remove_arc(u, v: V) is abstract + + ## -------------------- ## + ## Non abstract methods ## + ## -------------------- ## + + # Adds all vertices of `vertices` to this digraph. + # + # If vertices appear more than once, they are only added once. + # + # ~~~ + # import digraph + # var g = new HashDigraph[Int] + # g.add_vertices([0,1,2,3]) + # assert g.num_vertices == 4 + # g.add_vertices([2,3,4,5]) + # assert g.num_vertices == 6 + # ~~~ + fun add_vertices(vertices: Collection[V]) + do + for u in vertices do add_vertex(u) + end + + # Adds all arcs of `arcs` to this digraph. + # + # If arcs appear more than once, they are only added once. + # + # ~~~ + # import digraph + # var g = new HashDigraph[Int] + # var arcs = [[0,1], [1,2], [1,2]] + # g.add_arcs(arcs) + # assert g.num_arcs == 2 + # ~~~ + fun add_arcs(arcs: Collection[Array[V]]) + do + for a in arcs do add_arc(a[0], a[1]) + end +end +# A directed graph represented by hash maps +class HashDigraph[V: Object] + super MutableDigraph[V] + + # Attributes + # + private var incoming_vertices_map = new HashMap[V, Array[V]] + private var outgoing_vertices_map = new HashMap[V, Array[V]] + private var number_of_arcs = 0 + + redef fun num_vertices do return outgoing_vertices_map.keys.length end + + redef fun num_arcs do return number_of_arcs end + + redef fun add_vertex(u) + do + if not has_vertex(u) then + incoming_vertices_map[u] = new Array[V] + outgoing_vertices_map[u] = new Array[V] + end + end + + redef fun has_vertex(u) do return outgoing_vertices_map.keys.has(u) + + redef fun remove_vertex(u) + do + if has_vertex(u) then + for v in successors(u) do + remove_arc(u, v) + end + for v in predecessors(u) do + remove_arc(v, u) + end + incoming_vertices_map.keys.remove(u) + outgoing_vertices_map.keys.remove(u) + end + end + + redef fun add_arc(u, v) + do + if not has_vertex(u) then add_vertex(u) + if not has_vertex(v) then add_vertex(v) + if not has_arc(u, v) then + incoming_vertices_map[v].add(u) + outgoing_vertices_map[u].add(v) + number_of_arcs += 1 + end + end + + redef fun has_arc(u, v) + do + return outgoing_vertices_map[u].has(v) + end + + redef fun remove_arc(u, v) + do + if has_arc(u, v) then + outgoing_vertices_map[u].remove(v) + incoming_vertices_map[v].remove(u) + number_of_arcs -= 1 + end + end + + redef fun predecessors(u): Array[V] + do + if incoming_vertices_map.keys.has(u) then + return incoming_vertices_map[u].clone + else + return new Array[V] + end + end + + redef fun successors(u): Array[V] + do + if outgoing_vertices_map.keys.has(u) then + return outgoing_vertices_map[u].clone + else + return new Array[V] + end + end + + redef fun vertices_iterator: Iterator[V] do return outgoing_vertices_map.keys.iterator +end diff --git a/lib/markdown/Makefile b/lib/markdown/Makefile new file mode 100644 index 0000000..24ea4bb --- /dev/null +++ b/lib/markdown/Makefile @@ -0,0 +1,6 @@ +NITC=../../bin/nitc + +all: nitmd + +nitmd: nitmd.nit + ${NITC} $< diff --git a/lib/markdown/decorators.nit b/lib/markdown/decorators.nit index f33302f..9f0843c 100644 --- a/lib/markdown/decorators.nit +++ b/lib/markdown/decorators.nit @@ -70,7 +70,7 @@ class MdDecorator in_orderedlist = true current_li = 0 v.emit_in block - in_unorderedlist = false + in_orderedlist = false end private var in_orderedlist = false private var current_li = 0 diff --git a/lib/markdown/man.nit b/lib/markdown/man.nit new file mode 100644 index 0000000..8128642 --- /dev/null +++ b/lib/markdown/man.nit @@ -0,0 +1,173 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Simple *groff* decorator restricted for manpages. +module man + +import markdown + +# `Decorator` that outputs markdown. +class ManDecorator + super Decorator + + redef fun add_ruler(v, block) do v.add "***\n" + + redef fun add_headline(v, block) do + var lvl = block.depth + if lvl == 1 then + v.add ".SH " + else if lvl == 2 then + v.add ".SS " + else if lvl >= 3 then + # We use dictionary (titled paragraph) to simulate a 3rd level (or more) + v.add ".TP\n" + end + v.emit_in block + v.addn + end + + redef fun add_paragraph(v, block) do + if not in_unorderedlist and not in_orderedlist then + v.addn + v.emit_in block + v.addn + else + v.emit_in block + end + end + + redef fun add_code(v, block) do + v.add ".RS\n.nf\n\\f[C]\n" + v.emit_in block + v.addn + v.add "\\f[]\n.fi\n.RE\n" + end + + redef fun add_blockquote(v, block) do + v.add ".RS\n" + v.emit_in block + v.add ".RE\n" + end + + redef fun add_unorderedlist(v, block) do + v.add ".RS\n" + in_unorderedlist = true + v.emit_in block + in_unorderedlist = false + v.add ".RE\n" + end + private var in_unorderedlist = false + + redef fun add_orderedlist(v, block) do + v.add ".RS\n" + in_orderedlist = true + current_li = 0 + v.emit_in block + in_orderedlist = false + v.add ".RE\n" + end + private var in_orderedlist = false + private var current_li = 0 + + redef fun add_listitem(v, block) do + if in_unorderedlist then + v.add ".IP \\[bu] 3\n" + else if in_orderedlist then + current_li += 1 + v.add ".IP \"{current_li}.\" 3\n" + end + v.emit_in block + v.addn + end + + redef fun add_em(v, text) do + v.add "\\f[I]" + v.add text + v.add "\\f[]" + end + + redef fun add_strong(v, text) do + v.add "\\f[B]" + v.add text + v.add "\\f[]" + end + + redef fun add_strike(v, text) do + v.add "[STRIKEOUT:" + v.add text + v.add "]" + end + + redef fun add_image(v, link, name, comment) do + v.add name + v.add " (" + append_value(v, link) + if comment != null and not comment.is_empty then + v.add " " + append_value(v, comment) + end + v.add ")" + end + + redef fun add_link(v, link, name, comment) do + v.add name + v.add " (" + append_value(v, link) + if comment != null and not comment.is_empty then + v.add " " + append_value(v, comment) + end + v.add ")" + end + + redef fun add_abbr(v, name, comment) do + v.add "\">" + v.emit_text(name) + v.add " (" + append_value(v, comment) + v.add ")" + end + + redef fun add_span_code(v, text, from, to) do + v.add "\\f[C]" + append_code(v, text, from, to) + v.add "\\f[]" + end + + redef fun add_line_break(v) do + v.addn + end + + redef fun append_value(v, text) do for c in text do escape_char(v, c) + + redef fun add_char(v, c) do + # Escape - because manpages + if c == '-' then + v.addc '\\' + end + v.addc(c) + end + + redef fun escape_char(v, c) do add_char(v, c) + + redef fun append_code(v, buffer, from, to) do + for i in [from..to[ do + var c = buffer[i] + if c == '-' or c == ' ' then + v.addc '\\' + end + v.addc c + end + end +end diff --git a/lib/markdown/markdown.nit b/lib/markdown/markdown.nit index 251f784..1bb8815 100644 --- a/lib/markdown/markdown.nit +++ b/lib/markdown/markdown.nit @@ -646,6 +646,11 @@ interface Decorator # Kind of emitter used for decoration. type EMITTER: MarkdownEmitter + # Render a single plain char. + # + # Redefine this method to add special escaping for plain text. + fun add_char(v: EMITTER, c: Char) do v.addc c + # Render a ruler block. fun add_ruler(v: EMITTER, block: BlockRuler) is abstract @@ -1918,7 +1923,7 @@ abstract class Token var char: Char # Output that token using `MarkdownEmitter::decorator`. - fun emit(v: MarkdownEmitter) do v.addc char + fun emit(v: MarkdownEmitter) do v.decorator.add_char(v, char) end # A token without a specific meaning. @@ -2102,6 +2107,7 @@ abstract class TokenLinkOrImage if pos == -1 then return -1 end end + if pos < start then return -1 if md[pos] != ')' then return -1 else if md[pos] == '[' then pos += 1 diff --git a/lib/markdown/nitmd.nit b/lib/markdown/nitmd.nit index 3570513..41d28c1 100644 --- a/lib/markdown/nitmd.nit +++ b/lib/markdown/nitmd.nit @@ -16,16 +16,28 @@ module nitmd import markdown +import decorators +import man -if args.length != 1 then - print "usage: nitmd " - exit 0 +import opts + +var options = new OptionContext +var opt_help = new OptionBool("Show this help.", "-h", "-?", "--help") +options.add_option(opt_help) +var opt_to = new OptionString("Specify output format (html, md, man)", "-t", "--to") +options.add_option(opt_to) + +options.parse(args) +if options.rest.length != 1 then + print "usage: nitmd [-t format] " + options.usage + exit 1 end -var file = args.first +var file = options.rest.first if not file.file_exists then print "'{file}' not found" - exit 0 + exit 1 end var ifs = new FileReader.open(file) @@ -33,4 +45,15 @@ var md = ifs.read_all ifs.close var processor = new MarkdownProcessor +var to = opt_to.value +if to == null or to == "html" then + # Noop +else if to == "md" then + processor.emitter.decorator = new MdDecorator +else if to == "man" then + processor.emitter.decorator = new ManDecorator +else + print "Unknown output format: {to}" + exit 1 +end print processor.process(md) diff --git a/lib/md5.nit b/lib/md5.nit index 41de768..6495145 100644 --- a/lib/md5.nit +++ b/lib/md5.nit @@ -490,25 +490,31 @@ in "C Header" `{ `} redef class String - # returns the md5 digest of the receiver string - # algorithm implemented by L. Peter Deutsch - fun md5: String import String.to_cstring, NativeString.to_s `{ + # MD5 digest of `self` + # + # ~~~ + # assert "".md5 == "d41d8cd98f00b204e9800998ecf8427e" + # assert "a".md5 == "0cc175b9c0f1b6a831c399e269772661" + # assert "abc".md5 == "900150983cd24fb0d6963f7d28e17f72" + # ~~~ + fun md5: String do return to_cstring.native_md5.to_s +end + +redef class NativeString + private fun native_md5: NativeString `{ md5_state_t state; md5_byte_t digest[16]; /* result */ char *hex_output = malloc(33*sizeof(char)); int di; - char *in_text; - - in_text = String_to_cstring(self); md5_init(&state); - md5_append(&state, (const md5_byte_t *)in_text, strlen(in_text)); + md5_append(&state, (const md5_byte_t *)self, strlen(self)); md5_finish(&state, digest); for (di = 0; di < 16; ++di) sprintf(hex_output + di * 2, "%02x", digest[di]); hex_output[32] = '\0'; - return NativeString_to_s(hex_output); + return hex_output; `} end diff --git a/lib/mongodb/mongodb.nit b/lib/mongodb/mongodb.nit index 2372179..1e9b9bd 100644 --- a/lib/mongodb/mongodb.nit +++ b/lib/mongodb/mongodb.nit @@ -601,6 +601,7 @@ class MongoCollection fun find(query: JsonObject): nullable JsonObject do assert is_alive var c = native.find(query.to_bson.native) + assert is_alive # FIXME used to avoid segfault (so `self` isn't garbage collected to soon) if c == null then return null var cursor = new MongoCursor(c) if cursor.is_ok then diff --git a/lib/mongodb/native_mongodb.nit b/lib/mongodb/native_mongodb.nit index 6d6f2fe..d25a9ac 100644 --- a/lib/mongodb/native_mongodb.nit +++ b/lib/mongodb/native_mongodb.nit @@ -51,7 +51,7 @@ extern class NativeBSON `{ bson_t * `} new from_json_string(data: NativeString) import set_mongoc_error `{ bson_error_t error; bson_t *bson; - bson = bson_new_from_json(data, -1, &error); + bson = bson_new_from_json((uint8_t *)data, -1, &error); if(!bson) { NativeBSON_set_mongoc_error(bson, &error); return NULL; @@ -183,7 +183,7 @@ extern class NativeMongoClient `{ mongoc_client_t * `} import set_mongoc_error, NativeCStringArray, NativeCStringArray.as nullable `{ bson_error_t error; char **strv; - if(strv = mongoc_client_get_database_names(self, &error)) { + if((strv = mongoc_client_get_database_names(self, &error))) { return NativeCStringArray_as_nullable(strv); } NativeMongoClient_set_mongoc_error(self, &error); @@ -230,7 +230,7 @@ extern class NativeMongoDb `{ mongoc_database_t * `} import set_mongoc_error, NativeCStringArray, NativeCStringArray.as nullable `{ bson_error_t error; char **strv; - if(strv = mongoc_database_get_collection_names(self, &error)) { + if((strv = mongoc_database_get_collection_names(self, &error))) { return NativeCStringArray_as_nullable(strv); } NativeMongoDb_set_mongoc_error(self, &error); @@ -426,12 +426,10 @@ extern class NativeMongoCollection `{ mongoc_collection_t * `} bson_error_t error; mongoc_cursor_t *cursor; cursor = mongoc_collection_find(self, MONGOC_QUERY_NONE, 0, 0, 0, query, NULL, NULL); - if (mongoc_cursor_error(cursor, &error)) { NativeMongoCollection_set_mongoc_error(self, &error); return null_NativeMongoCursor(); } - return NativeMongoCursor_as_nullable(cursor); `} diff --git a/lib/standard/bytes.nit b/lib/standard/bytes.nit index b8cc1fb..59c4c5f 100644 --- a/lib/standard/bytes.nit +++ b/lib/standard/bytes.nit @@ -145,10 +145,81 @@ class Bytes redef fun to_s do persisted = true - return new FlatString.with_infos(items, length, 0, length -1) + var b = self + if not is_utf8 then + b = clean_utf8 + persisted = false + end + return new FlatString.with_infos(b.items, b.length, 0, b.length -1) end redef fun iterator do return new BytesIterator.with_buffer(self) + + # Is the byte collection valid UTF-8 ? + fun is_utf8: Bool do + var charst = once [0x80u8, 0u8, 0xE0u8, 0xC0u8, 0xF0u8, 0xE0u8, 0xF8u8, 0xF0u8] + var lobounds = once [0, 0x80, 0x800, 0x10000] + var hibounds = once [0x7F, 0x7FF, 0xFFFF, 0x10FFFF] + var pos = 0 + var len = length + var mits = items + while pos < len do + var nxst = mits.length_of_char_at(pos) + var charst_index = (nxst - 1) * 2 + if mits[pos] & charst[charst_index] == charst[charst_index + 1] then + var c = mits.char_at(pos) + var cp = c.ascii + if cp <= hibounds[nxst - 1] and cp >= lobounds[nxst - 1] then + if cp >= 0xD800 and cp <= 0xDFFF or + cp == 0xFFFE or cp == 0xFFFF then return false + else + return false + end + else + return false + end + pos += nxst + end + return true + end + + # Cleans the bytes of `self` to be UTF-8 compliant + private fun clean_utf8: Bytes do + var charst = once [0x80u8, 0u8, 0xE0u8, 0xC0u8, 0xF0u8, 0xE0u8, 0xF8u8, 0xF0u8] + var badchar = once [0xEFu8, 0xBFu8, 0xBDu8] + var lobounds = once [0, 0x80, 0x800, 0x10000] + var hibounds = once [0x7F, 0x7FF, 0xFFFF, 0x10FFFF] + var pos = 0 + var len = length + var ret = new Bytes.with_capacity(len) + var mits = items + while pos < len do + var nxst = mits.length_of_char_at(pos) + var charst_index = (nxst - 1) * 2 + if mits[pos] & charst[charst_index] == charst[charst_index + 1] then + var c = mits.char_at(pos) + var cp = c.ascii + if cp <= hibounds[nxst - 1] and cp >= lobounds[nxst - 1] then + if cp >= 0xD800 and cp <= 0xDFFF or + cp == 0xFFFE or cp == 0xFFFF then + ret.append badchar + pos += 1 + else + var pend = pos + nxst + for i in [pos .. pend[ do ret.add mits[i] + pos += nxst + end + else + ret.append badchar + pos += 1 + end + else + ret.append badchar + pos += 1 + end + end + return ret + end end private class BytesIterator @@ -178,21 +249,23 @@ redef class Text # ~~~ fun to_bytes: Bytes do var b = new Bytes.with_capacity(bytelen) + append_to_bytes b + return b + end + + # Appends `self.bytes` to `b` + fun append_to_bytes(b: Bytes) do for s in substrings do var from = if s isa FlatString then s.first_byte else 0 b.append_ns_from(s.items, s.bytelen, from) end - return b end end redef class FlatText - redef fun to_bytes do - var len = bytelen - var b = new Bytes.with_capacity(len) + redef fun append_to_bytes(b) do var from = if self isa FlatString then first_byte else 0 - b.append_ns_from(items, len, from) - return b + b.append_ns_from(items, bytelen, from) end end diff --git a/lib/standard/codecs/codec_base.nit b/lib/standard/codecs/codec_base.nit new file mode 100644 index 0000000..b4a9523 --- /dev/null +++ b/lib/standard/codecs/codec_base.nit @@ -0,0 +1,51 @@ +# 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. + +# Base for codecs to use with streams +# +# A Codec (Coder/Decoder) is a tranformer from a byte-format to another +# +# As Nit Strings are UTF-8, a codec works as : +# - Coder: From a UTF-8 string to a specified format (writing) +# - Decoder: From a specified format to a UTF-8 string (reading) +module codec_base + +import text +import bytes + +# Codes UTF-8 entities to an external format +abstract class Coder + + # Transforms `c` to its representation in the format of `self` + fun code_char(c: Char): Bytes is abstract + + # Adds a char `c` to bytes `s` + fun add_char_to(c: Char, s: Bytes) is abstract + + # Transforms `s` to the format of `self` + fun code_string(s: Text): Bytes is abstract + + # Adds a string `s` to bytes `b` + fun add_string_to(s: Text, b: Bytes) is abstract +end + +# Decodes entities in an external format to UTF-8 +abstract class Decoder + + # Decodes a char from `b` to a Unicode code-point + fun decode_char(b: Bytes): Char is abstract + + # Decodes a string `b` to UTF-8 + fun decode_string(b: Bytes): String is abstract +end diff --git a/lib/standard/codecs/codecs.nit b/lib/standard/codecs/codecs.nit new file mode 100644 index 0000000..25e9931 --- /dev/null +++ b/lib/standard/codecs/codecs.nit @@ -0,0 +1,19 @@ +# This file is part of NIT (http://www.nitlanguage.org). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Group module for all codec-related manipulations +module codecs + +import codec_base +import utf8 diff --git a/lib/standard/codecs/utf8.nit b/lib/standard/codecs/utf8.nit new file mode 100644 index 0000000..65f2fc9 --- /dev/null +++ b/lib/standard/codecs/utf8.nit @@ -0,0 +1,50 @@ +# This file is part of NIT (http://www.nitlanguage.org). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Codec for UTF-8 I/O +module utf8 + +import codec_base + +# Returns UTF-8 entities as-is +private class UTF8Coder + super Coder + + redef fun code_char(c) do return c.to_s.to_bytes + + redef fun add_char_to(c, stream) do c.to_s.append_to_bytes(stream) + + redef fun code_string(s) do return s.to_bytes + + redef fun add_string_to(s, b) do s.append_to_bytes(b) +end + +# Decodes entities in an external format to UTF-8 +private class UTF8Decoder + super Decoder + + redef fun decode_char(b) do + var s = b.to_s + return s[0] + end + + redef fun decode_string(b) do + return b.to_s + end +end + +# Returns the instance of a UTF-8 Coder +fun utf8_coder: Coder do return once new UTF8Coder +# Returns the instance of a UTF-8 Decoder +fun utf8_decoder: Decoder do return once new UTF8Decoder diff --git a/lib/standard/file.nit b/lib/standard/file.nit index e5fc85b..aba34e8 100644 --- a/lib/standard/file.nit +++ b/lib/standard/file.nit @@ -156,7 +156,7 @@ class FileReader init open(path: String) do self.path = path - prepare_buffer(10) + prepare_buffer(100) _file = new NativeFile.io_open_read(path.to_cstring) if _file.address_is_null then last_error = new IOError("Cannot open `{path}`: {sys.errno.strerror}") diff --git a/lib/standard/fixed_ints.nit b/lib/standard/fixed_ints.nit new file mode 100644 index 0000000..6dc6550 --- /dev/null +++ b/lib/standard/fixed_ints.nit @@ -0,0 +1,979 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# This file is free software, which comes along with NIT. This software is +# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. You can modify it is you want, provided this header +# is kept unaltered, and a notification of the changes is added. +# You are allowed to redistribute it and sell it, alone or is a part of +# another product. + +# Basic integers of fixed-precision +# +# All classes defined here have C-equivalents and the semantics of their +# operations are the same as C's +# +# * Int8 => int8_t +# * Int16 => int16_t +# * UInt16 => uint16_t +# * Int32 => int32_t +# * UInt32 => uint32_t +# +# NOTE: No UInt8 is provided as Byte is the same +# SEE: kernel::Byte +# +# HOW TO USE: +# All classes can be instanciated via a literal rule. +# Namely, a suffix to append after the literal integer. +# +# * Int8 => i8 +# * Byte => u8 +# * Int16 => i16 +# * UInt16 => u16 +# * Int32 => i32 +# * UInt32 => u32 +module fixed_ints + +import text + +in "C" `{ +#include +`} + +redef class Numeric + + # The Int8 equivalent of `self` + # + # assert (-1).to_i8 == 0xFFFFi8 + # assert (1.9).to_i8 == 1i8 + fun to_i8: Int8 do return self.to_i.to_i8 + + # The Int16 equivalent of `self` + # + # assert (-1).to_i16 == 0xFFFFi16 + # assert (1.9).to_i16 == 1i16 + fun to_i16: Int16 do return self.to_i.to_i16 + + # The UInt16 equivalent of `self` + # + # assert (-1).to_u16 == 0xFFFFu16 + # assert (1.9).to_u16 == 1u16 + fun to_u16: UInt16 do return self.to_i.to_u16 + + # The Int32 equivalent of `self` + # + # assert (-1).to_i32 == 0xFFFFFFFFi32 + # assert (1.9).to_i32 == 1i32 + fun to_i32: Int32 do return self.to_i.to_i32 + + # The UInt32 equivalent of `self` + # + # assert (-1).to_u32 == 0xFFFFFFFFu32 + # assert (1.9).to_u32 == 1u32 + fun to_u32: UInt32 do return self.to_i.to_u32 + +end + +redef class Float + redef fun to_i8 is intern + redef fun to_i16 is intern + redef fun to_u16 is intern + redef fun to_i32 is intern + redef fun to_u32 is intern +end + +redef class Byte + redef fun to_i8 is intern + redef fun to_i16 is intern + redef fun to_u16 is intern + redef fun to_i32 is intern + redef fun to_u32 is intern +end + +redef class Int + redef fun to_i8 is intern + redef fun to_i16 is intern + redef fun to_u16 is intern + redef fun to_i32 is intern + redef fun to_u32 is intern +end + +# Native 8-bit signed integer. +# Same as a C `int8_t` +universal Int8 + super Discrete + super Numeric + + redef type OTHER: Int8 + + redef fun successor(i) do return self + i.to_i8 + redef fun predecessor(i) do return self - i.to_i8 + + redef fun object_id is intern + redef fun hash do return self.to_i + redef fun ==(i) is intern + redef fun !=(i) is intern + redef fun output is intern + + redef fun <=(i) is intern + redef fun <(i) is intern + redef fun >=(i) is intern + redef fun >(i) is intern + redef fun +(i) is intern + + # assert -1i8 == 0xFFi8 + # assert -0i8 == 0x00i8 + redef fun - is intern + redef fun -(i) is intern + redef fun *(i) is intern + redef fun /(i) is intern + + # Modulo of `self` with `i`. + # + # Returns the remainder of division of `self` by `i`. + # + # assert 5i8 % 2i8 == 1i8 + # assert 10i8 % 2i8 == 0i8 + fun %(i: Int8): Int8 is intern + + redef fun zero do return 0.to_i8 + redef fun value_of(val) do return val.to_i8 + + # `i` bits shift to the left + # + # assert 5i8 << 1 == 10i8 + fun <<(i: Int): Int8 is intern + + # `i` bits shift to the right + # + # assert 5i8 >> 1 == 2i8 + fun >>(i: Int): Int8 is intern + + redef fun to_i is intern + redef fun to_f is intern + redef fun to_b is intern + redef fun to_i8 do return self + redef fun to_i16 is intern + redef fun to_u16 is intern + redef fun to_i32 is intern + redef fun to_u32 is intern + + redef fun distance(i) do return (self - i).to_i + + redef fun <=>(other) + do + if self < other then + return -1 + else if other < self then + return 1 + else + return 0 + end + end + + redef fun is_between(c, d) + do + if self < c or d < self then + return false + else + return true + end + end + + redef fun max(other) + do + if self < other then + return other + else + return self + end + end + + redef fun min(c) + do + if c < self then + return c + else + return self + end + end + + # Returns the result of a binary AND operation on `self` and `i` + # + # assert 0x10i8 & 0x01i8 == 0i8 + fun &(i: Int8): Int8 is intern + + # Returns the result of a binary OR operation on `self` and `i` + # + # assert 0x10i8 | 0x01i8 == 0x11i8 + fun |(i: Int8): Int8 is intern + + # Returns the result of a binary XOR operation on `self` and `i` + # + # assert 0x101i8 ^ 0x110i8 == 0x11i8 + fun ^(i: Int8): Int8 is intern + + # Returns the 1's complement of `self` + # + # assert ~0x2Fi8 == 0xD0i8 + fun ~: Int8 is intern + + # C function to calculate the length of the `NativeString` to receive `self` + private fun to_s_len: Int `{ + return snprintf(NULL, 0, "%"PRIi8, self); + `} + + # C function to convert a nit Int to a NativeString (char*) + private fun native_to_s(nstr: NativeString, strlen: Int) `{ + snprintf(nstr, strlen, "%"PRIi8, self); + `} + + # Displayable Int8 + # + # assert 1i8.to_s == "1" + # assert (-123i8).to_s == "-123" + redef fun to_s do + var nslen = to_s_len + var ns = new NativeString(nslen + 1) + ns[nslen] = 0u8 + native_to_s(ns, nslen + 1) + return ns.to_s_with_length(nslen) + end +end + +# Native 16-bit signed integer. +# Same as a C `int16_t` +universal Int16 + super Discrete + super Numeric + + redef type OTHER: Int16 + + redef fun successor(i) do return self + i.to_i16 + redef fun predecessor(i) do return self - i.to_i16 + + redef fun object_id is intern + redef fun hash do return self.to_i + redef fun ==(i) is intern + redef fun !=(i) is intern + redef fun output is intern + + redef fun <=(i) is intern + redef fun <(i) is intern + redef fun >=(i) is intern + redef fun >(i) is intern + redef fun +(i) is intern + + # assert -1i16 == 0xFFFFi16 + # assert -0i16 == 0i16 + redef fun - is intern + redef fun -(i) is intern + redef fun *(i) is intern + redef fun /(i) is intern + + # Modulo of `self` with `i`. + # + # Returns the remainder of division of `self` by `i`. + # + # assert 5i16 % 2i16 == 1i16 + # assert 10i16 % 2i16 == 0i16 + fun %(i: Int16): Int16 is intern + + redef fun zero do return 0.to_i16 + redef fun value_of(val) do return val.to_i16 + + # `i` bits shift to the left + # + # assert 5i16 << 1 == 10i16 + fun <<(i: Int): Int16 is intern + + # `i` bits shift to the right + # + # assert 5i16 >> 1 == 2i16 + fun >>(i: Int): Int16 is intern + + redef fun to_i is intern + redef fun to_f is intern + redef fun to_b is intern + redef fun to_i8 is intern + redef fun to_i16 do return self + redef fun to_u16 is intern + redef fun to_i32 is intern + redef fun to_u32 is intern + + redef fun distance(i) do return (self - i).to_i + + redef fun <=>(other) + do + if self < other then + return -1 + else if other < self then + return 1 + else + return 0 + end + end + + redef fun is_between(c, d) + do + if self < c or d < self then + return false + else + return true + end + end + + redef fun max(other) + do + if self < other then + return other + else + return self + end + end + + redef fun min(c) + do + if c < self then + return c + else + return self + end + end + + # Returns the result of a binary AND operation on `self` and `i` + # + # assert 0x10i16 & 0x01i16 == 0i16 + fun &(i: Int16): Int16 is intern + + # Returns the result of a binary OR operation on `self` and `i` + # + # assert 0x10i16 | 0x01i16 == 0x11i16 + fun |(i: Int16): Int16 is intern + + # Returns the result of a binary XOR operation on `self` and `i` + # + # assert 0x101i16 ^ 0x110i16 == 0x11i16 + fun ^(i: Int16): Int16 is intern + + # Returns the 1's complement of `self` + # + # assert ~0x2Fi16 == 0xFFD0i16 + fun ~: Int16 is intern + + # C function to calculate the length of the `NativeString` to receive `self` + private fun to_s_len: Int `{ + return snprintf(NULL, 0, "%"PRIi16, self); + `} + + # C function to convert a nit Int to a NativeString (char*) + private fun native_to_s(nstr: NativeString, strlen: Int) `{ + snprintf(nstr, strlen, "%"PRIi16, self); + `} + + # Displayable Int16 + # + # assert 1i16.to_s == "1" + # assert (-123i16).to_s == "-123" + redef fun to_s do + var nslen = to_s_len + var ns = new NativeString(nslen + 1) + ns[nslen] = 0u8 + native_to_s(ns, nslen + 1) + return ns.to_s_with_length(nslen) + end +end + +# Native 16-bit unsigned integer. +# Same as a C `uint16_t` +universal UInt16 + super Discrete + super Numeric + + redef type OTHER: UInt16 + + redef fun successor(i) do return self + i.to_u16 + redef fun predecessor(i) do return self - i.to_u16 + + redef fun object_id is intern + redef fun hash do return self.to_i + redef fun ==(i) is intern + redef fun !=(i) is intern + redef fun output is intern + + redef fun <=(i) is intern + redef fun <(i) is intern + redef fun >=(i) is intern + redef fun >(i) is intern + redef fun +(i) is intern + + # assert -1u16 == 0xFFFFu16 + # assert -0u16 == 0u16 + redef fun - is intern + redef fun -(i) is intern + redef fun *(i) is intern + redef fun /(i) is intern + + # Modulo of `self` with `i`. + # + # Returns the remainder of division of `self` by `i`. + # + # assert 5u16 % 2u16 == 1u16 + # assert 10u16 % 2u16 == 0u16 + fun %(i: UInt16): UInt16 is intern + + redef fun zero do return 0.to_u16 + redef fun value_of(val) do return val.to_u16 + + # `i` bits shift to the left + # + # assert 5u16 << 1 == 10u16 + fun <<(i: Int): UInt16 is intern + + # `i` bits shift to the right + # + # assert 5u16 >> 1 == 2u16 + fun >>(i: Int): UInt16 is intern + + redef fun to_i is intern + redef fun to_f is intern + redef fun to_b is intern + redef fun to_i8 is intern + redef fun to_i16 is intern + redef fun to_u16 do return self + redef fun to_i32 is intern + redef fun to_u32 is intern + + redef fun distance(i) do return (self - i).to_i + + redef fun <=>(other) + do + if self < other then + return -1 + else if other < self then + return 1 + else + return 0 + end + end + + redef fun is_between(c, d) + do + if self < c or d < self then + return false + else + return true + end + end + + redef fun max(other) + do + if self < other then + return other + else + return self + end + end + + redef fun min(c) + do + if c < self then + return c + else + return self + end + end + + # Returns the result of a binary AND operation on `self` and `i` + # + # assert 0x10u16 & 0x01u16 == 0u16 + fun &(i: UInt16): UInt16 is intern + + # Returns the result of a binary OR operation on `self` and `i` + # + # assert 0x10u16 | 0x01u16 == 0x11u16 + fun |(i: UInt16): UInt16 is intern + + # Returns the result of a binary XOR operation on `self` and `i` + # + # assert 0x101u16 ^ 0x110u16 == 0x11u16 + fun ^(i: UInt16): UInt16 is intern + + # Returns the 1's complement of `self` + # + # assert ~0x2Fu16 == 0xFFD0u16 + fun ~: UInt16 is intern + + # C function to calculate the length of the `NativeString` to receive `self` + private fun to_s_len: Int `{ + return snprintf(NULL, 0, "%"PRIu16, self); + `} + + # C function to convert a nit Int to a NativeString (char*) + private fun native_to_s(nstr: NativeString, strlen: Int) `{ + snprintf(nstr, strlen, "%"PRIu16, self); + `} + + # Displayable UInt16 + # + # assert 1u16.to_s == "1" + # assert (-123u16).to_s == "65413" + redef fun to_s do + var nslen = to_s_len + var ns = new NativeString(nslen + 1) + ns[nslen] = 0u8 + native_to_s(ns, nslen + 1) + return ns.to_s_with_length(nslen) + end +end + + +# Native 32-bit signed integer. +# Same as a C `int32_t` +universal Int32 + super Discrete + super Numeric + + redef type OTHER: Int32 + + redef fun successor(i) do return self + i.to_i32 + redef fun predecessor(i) do return self - i.to_i32 + + redef fun object_id is intern + redef fun hash do return self.to_i + redef fun ==(i) is intern + redef fun !=(i) is intern + redef fun output is intern + + redef fun <=(i) is intern + redef fun <(i) is intern + redef fun >=(i) is intern + redef fun >(i) is intern + redef fun +(i) is intern + + # assert -1i32 == 0xFFFFFFFFi32 + # assert -0i32 == 0x00i32 + redef fun - is intern + redef fun -(i) is intern + redef fun *(i) is intern + redef fun /(i) is intern + + # Modulo of `self` with `i`. + # + # Returns the remainder of division of `self` by `i`. + # + # assert 5i32 % 2i32 == 1i32 + # assert 10i32 % 2i32 == 0i32 + fun %(i: Int32): Int32 is intern + + redef fun zero do return 0.to_i32 + redef fun value_of(val) do return val.to_i32 + + # `i` bits shift to the left + # + # assert 5i32 << 1 == 10i32 + fun <<(i: Int): Int32 is intern + + # `i` bits shift to the right + # + # assert 5i32 >> 1 == 2i32 + fun >>(i: Int): Int32 is intern + + redef fun to_i is intern + redef fun to_f is intern + redef fun to_b is intern + redef fun to_i8 is intern + redef fun to_i16 is intern + redef fun to_u16 is intern + redef fun to_i32 do return self + redef fun to_u32 is intern + + redef fun distance(i) do return (self - i).to_i + + redef fun <=>(other) + do + if self < other then + return -1 + else if other < self then + return 1 + else + return 0 + end + end + + redef fun is_between(c, d) + do + if self < c or d < self then + return false + else + return true + end + end + + redef fun max(other) + do + if self < other then + return other + else + return self + end + end + + redef fun min(c) + do + if c < self then + return c + else + return self + end + end + + # Returns the result of a binary AND operation on `self` and `i` + # + # assert 0x10i32 & 0x01i32 == 0i32 + fun &(i: Int32): Int32 is intern + + # Returns the result of a binary OR operation on `self` and `i` + # + # assert 0x10i32 | 0x01i32 == 0x11i32 + fun |(i: Int32): Int32 is intern + + # Returns the result of a binary XOR operation on `self` and `i` + # + # assert 0x101i32 ^ 0x110i32 == 0x11i32 + fun ^(i: Int32): Int32 is intern + + # Returns the 1's complement of `self` + # + # assert ~0x2Fi32 == 0xFFFFFFD0i32 + fun ~: Int32 is intern + + # C function to calculate the length of the `NativeString` to receive `self` + private fun to_s_len: Int `{ + return snprintf(NULL, 0, "%"PRIi32, self); + `} + + # C function to convert a nit Int to a NativeString (char*) + private fun native_to_s(nstr: NativeString, strlen: Int) `{ + snprintf(nstr, strlen, "%"PRIi32, self); + `} + + # Displayable Int32 + # + # assert 1i32.to_s == "1" + # assert (-123i32).to_s == "-123" + redef fun to_s do + var nslen = to_s_len + var ns = new NativeString(nslen + 1) + ns[nslen] = 0u8 + native_to_s(ns, nslen + 1) + return ns.to_s_with_length(nslen) + end +end + +# Native 32-bit unsigned integer. +# Same as a C `uint32_t` +universal UInt32 + super Discrete + super Numeric + + redef type OTHER: UInt32 + + redef fun successor(i) do return self + i.to_u32 + redef fun predecessor(i) do return self - i.to_u32 + + redef fun object_id is intern + redef fun hash do return self.to_i + redef fun ==(i) is intern + redef fun !=(i) is intern + redef fun output is intern + + redef fun <=(i) is intern + redef fun <(i) is intern + redef fun >=(i) is intern + redef fun >(i) is intern + redef fun +(i) is intern + + # assert -1u32 == 0xFFFFFFFFu32 + # assert -0u32 == 0x00u32 + redef fun - is intern + redef fun -(i) is intern + redef fun *(i) is intern + redef fun /(i) is intern + + # Modulo of `self` with `i`. + # + # Returns the remainder of division of `self` by `i`. + # + # assert 5u32 % 2u32 == 1u32 + # assert 10u32 % 2u32 == 0u32 + fun %(i: UInt32): UInt32 is intern + + redef fun zero do return 0.to_u32 + redef fun value_of(val) do return val.to_u32 + + # `i` bits shift to the left + # + # assert 5u32 << 1 == 10u32 + fun <<(i: Int): UInt32 is intern + + # `i` bits shift to the right + # + # assert 5u32 >> 1 == 2u32 + fun >>(i: Int): UInt32 is intern + + redef fun to_i is intern + redef fun to_f is intern + redef fun to_b is intern + redef fun to_i8 is intern + redef fun to_i16 is intern + redef fun to_u16 is intern + redef fun to_i32 is intern + redef fun to_u32 do return self + + redef fun distance(i) do return (self - i).to_i + + redef fun <=>(other) + do + if self < other then + return -1 + else if other < self then + return 1 + else + return 0 + end + end + + redef fun is_between(c, d) + do + if self < c or d < self then + return false + else + return true + end + end + + redef fun max(other) + do + if self < other then + return other + else + return self + end + end + + redef fun min(c) + do + if c < self then + return c + else + return self + end + end + + # Returns the result of a binary AND operation on `self` and `i` + # + # assert 0x10u32 & 0x01u32 == 0u32 + fun &(i: UInt32): UInt32 is intern + + # Returns the result of a binary OR operation on `self` and `i` + # + # assert 0x10u32 | 0x01u32 == 0x11u32 + fun |(i: UInt32): UInt32 is intern + + # Returns the result of a binary XOR operation on `self` and `i` + # + # assert 0x101u32 ^ 0x110u32 == 0x11u32 + fun ^(i: UInt32): UInt32 is intern + + # Returns the 1's complement of `self` + # + # assert ~0x2Fu32 == 0xFFFFFFD0u32 + fun ~: UInt32 is intern + + # C function to calculate the length of the `NativeString` to receive `self` + private fun to_s_len: Int `{ + return snprintf(NULL, 0, "%"PRIu32, self); + `} + + # C function to convert a nit Int to a NativeString (char*) + private fun native_to_s(nstr: NativeString, strlen: Int) `{ + snprintf(nstr, strlen, "%"PRIu32, self); + `} + + # Displayable UInt32 + # + # assert 1u32.to_s == "1" + # assert (-123u32).to_s == "4294967173" + redef fun to_s do + var nslen = to_s_len + var ns = new NativeString(nslen + 1) + ns[nslen] = 0u8 + native_to_s(ns, nslen + 1) + return ns.to_s_with_length(nslen) + end +end + +redef class Text + + # Removes the numeric head of `self` if present + # + # intrude import standard::fixed_ints + # assert "0xFFEF".strip_numhead == "FFEF" + # assert "0o7364".strip_numhead == "7364" + # assert "0b01001".strip_numhead == "01001" + # assert "98".strip_numhead == "98" + private fun strip_numhead: Text do + if get_numhead != "" then return substring_from(2) + return self + end + + # Gets the numeric head of `self` if present + # Returns "" otherwise + # + # intrude import standard::fixed_ints + # assert "0xFEFF".get_numhead == "0x" + # assert "0b01001".get_numhead == "0b" + # assert "0o872".get_numhead == "0o" + # assert "98".get_numhead == "" + private fun get_numhead: Text do + if self.length < 2 then return "" + var c = self[0] + if c != '0' then return "" + c = self[1] + if c == 'x' or c == 'b' or c == 'o' or + c == 'X' or c == 'B' or c == 'O' then return substring(0, 2) + return "" + end + + # Removes the numeric extension if present + # + # intrude import standard::fixed_ints + # assert "0xFEFFu8".strip_numext == "0xFEFF" + # assert "0b01001u8".strip_numext == "0b01001" + # assert "0o872u8".strip_numext == "0o872" + # assert "98".strip_numext == "98" + private fun strip_numext: Text do + var ext = get_numext + if ext != "" then return substring(0, length - ext.length) + return self + end + + # Gets the numeric extension (i/u 8/16/32) in `self` is present + # Returns "" otherwise + # + # intrude import standard::fixed_ints + # assert "0xFEFFu8".get_numext == "u8" + # assert "0b01001u8".get_numext == "u8" + # assert "0o872u8".get_numext == "u8" + # assert "98".get_numext == "" + private fun get_numext: Text do + var len = self.length + var max = if self.length < 3 then self.length else 3 + for i in [1 .. max] do + var c = self[len - i] + if c == 'i' or c == 'u' then return substring_from(len - i) + end + return "" + end + + # Is `self` a well-formed Integer (i.e. parsable via `to_i`) + # + # assert "123".is_int + # assert "0b1011".is_int + # assert not "0x_".is_int + # assert not "0xGE".is_int + fun is_int: Bool do + var s = remove_all('_') + var pos = 0 + while s[pos] == '-' do + pos += 1 + end + s = s.substring_from(pos) + var rets = s.strip_numhead + if rets == "" then return false + var hd = get_numhead + if hd == "0x" or hd == "0X" then return rets.is_hex + if hd == "0b" or hd == "0B" then return rets.is_bin + if hd == "0o" or hd == "0O" then return rets.is_oct + return hd.is_dec + end + + redef fun to_i + do + assert self.is_int + var s = remove_all('_') + var val = 0 + var neg = false + var pos = 0 + while s[pos] == '-' do + neg = not neg + pos += 1 + end + s = s.substring_from(pos) + if s.length >= 2 then + var s1 = s[1] + if s1 == 'x' or s1 == 'X' then + val = s.substring_from(2).to_hex + else if s1 == 'o' or s1 == 'O' then + val = s.substring_from(2).to_oct + else if s1 == 'b' or s1 == 'B' then + val = s.substring_from(2).to_bin + else if s1.is_numeric then + val = s.to_dec + end + else + val = s.to_dec + end + return if neg then -val else val + end + + # Is `self` a valid integer ? + # + # assert "0xFE46u8".is_num + # assert "0b0100".is_num + # assert "0o645".is_num + # assert "897u8".is_num + fun is_num: Bool do + var prefix = get_numhead + var s = strip_numhead.strip_numext.remove_all('_') + if prefix != "" then + var c = prefix[1] + if c == 'x' or c == 'X' then return s.is_hex + if c == 'o' or c == 'O' then return s.is_oct + if c == 'b' or c == 'B' then return s.is_bin + end + return s.is_dec + end + + # If `self` is a properly formatted integer, returns the corresponding value + # Returns `null` otherwise + # + # assert "0xFEu8".to_num == 254u8 + # assert "0b10_10".to_num != 10u8 + fun to_num: nullable Numeric do + if not is_num then return null + var s = remove_all('_') + var ext = s.get_numext + var trunk = s.strip_numext + if trunk.strip_numhead == "" then return null + var trval = trunk.to_i + if ext == "u8" then + return trval.to_b + else if ext == "i8" then + return trval.to_i8 + else if ext == "i16" then + return trval.to_i16 + else if ext == "u16" then + return trval.to_u16 + else if ext == "i32" then + return trval.to_i32 + else if ext == "u32" then + return trval.to_u32 + else if ext == "" then + return trval + else + return null + end + end +end diff --git a/lib/standard/kernel.nit b/lib/standard/kernel.nit index 686334d..b2ac524 100644 --- a/lib/standard/kernel.nit +++ b/lib/standard/kernel.nit @@ -221,7 +221,7 @@ interface Object # and a cause of bugs. # # Without redefinition, `hash` is based on the `object_id` of the instance. - fun hash: Int do return object_id / 8 + fun hash: Int do return object_id end # The main class of the program. diff --git a/lib/standard/standard.nit b/lib/standard/standard.nit index e675600..2251bc3 100644 --- a/lib/standard/standard.nit +++ b/lib/standard/standard.nit @@ -32,3 +32,4 @@ import numeric import error import re import bytes +import fixed_ints diff --git a/lib/standard/stream.nit b/lib/standard/stream.nit index ce6e9b3..2db319a 100644 --- a/lib/standard/stream.nit +++ b/lib/standard/stream.nit @@ -14,6 +14,7 @@ module stream intrude import text::ropes import error intrude import bytes +import codecs in "C" `{ #include @@ -43,6 +44,10 @@ end # A `Stream` that can be read from abstract class Reader super Stream + + # Decoder used to transform input bytes to UTF-8 + var decoder: Decoder = utf8_decoder is writable + # Reads a character. Returns `null` on EOF or timeout fun read_char: nullable Char is abstract @@ -168,6 +173,7 @@ abstract class Reader # ~~~ fun read_all: String do var s = read_all_bytes + if not s.is_utf8 then s = s.clean_utf8 var slen = s.length if slen == 0 then return "" var rets = "" @@ -378,6 +384,9 @@ end abstract class Writer super Stream + # The coder from a nit UTF-8 String to the output file + var coder: Coder = utf8_coder is writable + # Writes bytes from `s` fun write_bytes(s: Bytes) is abstract @@ -448,6 +457,7 @@ abstract class BufferedReader return c end + # Resets the internal buffer fun buffer_reset do _buffer_length = 0 _buffer_pos = 0 @@ -518,14 +528,13 @@ abstract class BufferedReader do if last_error != null then return new Bytes.empty var s = new Bytes.with_capacity(10) + var b = _buffer while not eof do var j = _buffer_pos var k = _buffer_length - while j < k do - s.add(_buffer[j]) - j += 1 - end - _buffer_pos = j + var rd_sz = k - j + s.append_ns_from(b, rd_sz, j) + _buffer_pos = k fill_buffer end return s @@ -533,6 +542,7 @@ abstract class BufferedReader redef fun append_line_to(s) do + var lb = new Bytes.with_capacity(10) loop # First phase: look for a '\n' var i = _buffer_pos @@ -551,27 +561,29 @@ abstract class BufferedReader # if there is something to append if i > _buffer_pos then - # Enlarge the string (if needed) - s.enlarge(s.bytelen + i - _buffer_pos) - # Copy from the buffer to the string var j = _buffer_pos while j < i do - s.bytes.add(_buffer[j]) + lb.add(_buffer[j]) j += 1 end _buffer_pos = i else assert end_reached + s.append lb.to_s return end if eol then # so \n is found + s.append lb.to_s return else # so \n is not found - if end_reached then return + if end_reached then + s.append lb.to_s + return + end fill_buffer end end diff --git a/lib/standard/text/abstract_text.nit b/lib/standard/text/abstract_text.nit index d7b915c..1faaad3 100644 --- a/lib/standard/text/abstract_text.nit +++ b/lib/standard/text/abstract_text.nit @@ -240,89 +240,6 @@ abstract class Text return b.to_s end - # Is `self` a well-formed Integer (i.e. parsable via `to_i`) - # - # assert "123".is_int - # assert "0b1011".is_int - # assert not "0x_".is_int - # assert not "0xGE".is_int - fun is_int: Bool do - var s = remove_all('_') - var pos = 0 - while s[pos] == '-' do - pos += 1 - end - s = s.substring_from(pos) - var rets = s.strip_numhead - if rets == "" then return false - var hd = get_numhead - if hd == "0x" or hd == "0X" then return rets.is_hex - if hd == "0b" or hd == "0B" then return rets.is_bin - if hd == "0o" or hd == "0O" then return rets.is_oct - return hd.is_dec - end - - # Removes the numeric head of `self` if present - # - # intrude import standard::text::abstract_text - # assert "0xFFEF".strip_numhead == "FFEF" - # assert "0o7364".strip_numhead == "7364" - # assert "0b01001".strip_numhead == "01001" - # assert "98".strip_numhead == "98" - private fun strip_numhead: Text do - if get_numhead != "" then return substring_from(2) - return self - end - - # Gets the numeric head of `self` if present - # Returns "" otherwise - # - # intrude import standard::text::abstract_text - # assert "0xFEFF".get_numhead == "0x" - # assert "0b01001".get_numhead == "0b" - # assert "0o872".get_numhead == "0o" - # assert "98".get_numhead == "" - private fun get_numhead: Text do - if self.length < 2 then return "" - var c = self[0] - if c != '0' then return "" - c = self[1] - if c == 'x' or c == 'b' or c == 'o' or - c == 'X' or c == 'B' or c == 'O' then return substring(0, 2) - return "" - end - - # Removes the numeric extension if present - # - # intrude import standard::text::abstract_text - # assert "0xFEFFu8".strip_numext == "0xFEFF" - # assert "0b01001u8".strip_numext == "0b01001" - # assert "0o872u8".strip_numext == "0o872" - # assert "98".strip_numext == "98" - private fun strip_numext: Text do - var ext = get_numext - if ext != "" then return substring(0, length - ext.length) - return self - end - - # Gets the numeric extension (i/u 8/16/32) in `self` is present - # Returns "" otherwise - # - # intrude import standard::text::abstract_text - # assert "0xFEFFu8".get_numext == "u8" - # assert "0b01001u8".get_numext == "u8" - # assert "0o872u8".get_numext == "u8" - # assert "98".get_numext == "" - private fun get_numext: Text do - var len = self.length - var max = if self.length < 3 then self.length else 3 - for i in [1 .. max] do - var c = self[len - i] - if c == 'i' or c == 'u' then return substring_from(len - i) - end - return "" - end - # Returns `self` as the corresponding integer # # assert "123".to_i == 123 @@ -332,72 +249,7 @@ abstract class Text # assert "--12".to_i == 12 # # REQUIRE: `self`.`is_int` - fun to_i: Int - do - assert self.is_int - var s = remove_all('_') - var val = 0 - var neg = false - var pos = 0 - while s[pos] == '-' do - neg = not neg - pos += 1 - end - s = s.substring_from(pos) - if s.length >= 2 then - var s1 = s[1] - if s1 == 'x' or s1 == 'X' then - val = s.substring_from(2).to_hex - else if s1 == 'o' or s1 == 'O' then - val = s.substring_from(2).to_oct - else if s1 == 'b' or s1 == 'B' then - val = s.substring_from(2).to_bin - else if s1.is_numeric then - val = s.to_dec - end - else - val = s.to_dec - end - return if neg then -val else val - end - - # Is `self` a valid integer ? - # - # assert "0xFE46u8".is_num - # assert "0b0100".is_num - # assert "0o645".is_num - # assert "897u8".is_num - fun is_num: Bool do - var prefix = get_numhead - var s = strip_numhead.strip_numext.remove_all('_') - if prefix != "" then - var c = prefix[1] - if c == 'x' or c == 'X' then return s.is_hex - if c == 'o' or c == 'O' then return s.is_oct - if c == 'b' or c == 'B' then return s.is_bin - end - return s.is_dec - end - - # Is `self` is a properly formatted integer, returns the corresponding value - # - # assert "0xFEu8".to_num == 254u8 - # assert "0b10_10".to_num != 10u8 - fun to_num: nullable Numeric do - if not is_num then return null - var s = remove_all('_') - var ext = s.get_numext - var trunk = s.strip_numext - if trunk.strip_numhead == "" then return null - var trval = trunk.to_i - if ext == "u8" then - return trval.to_b - else if ext == "" then - return trval - else - return null - end - end + fun to_i: Int is abstract # If `self` contains a float, return the corresponding float # @@ -1501,10 +1353,6 @@ abstract class Buffer # In Buffers, the internal sequence of character is mutable # Thus, `chars` can be used to modify the buffer. redef fun chars: Sequence[Char] is abstract - - # In Buffers, the internal sequence of bytes is mutable - # Thus, `bytes` can be used to modify the buffer. - redef fun bytes: Sequence[Byte] is abstract end # View for chars on Buffer objects, extends Sequence @@ -1521,7 +1369,6 @@ end # for mutation operations private abstract class BufferByteView super StringByteView - super Sequence[Byte] redef type SELFTYPE: Buffer end diff --git a/lib/standard/text/flat.nit b/lib/standard/text/flat.nit index 87381e6..917b0e5 100644 --- a/lib/standard/text/flat.nit +++ b/lib/standard/text/flat.nit @@ -34,41 +34,18 @@ private class FlatSubstringsIter redef fun next do tgt = null end -# Immutable strings of characters. -class FlatString - super FlatText - super String - - # Index at which `self` begins in `items`, inclusively - private var first_byte: Int is noinit +redef class FlatText - # Index at which `self` ends in `items`, inclusively - private var last_byte: Int is noinit - - redef var chars = new FlatStringCharView(self) is lazy + private fun first_byte: Int do return 0 - redef var bytes = new FlatStringByteView(self) is lazy + private fun last_byte: Int do return bytelen - 1 # Cache of the latest position (char) explored in the string var position: Int = 0 + # Cached position (bytes) in the NativeString underlying the String var bytepos: Int = first_byte is lateinit - redef var length is lazy do - if bytelen == 0 then return 0 - var st = first_byte - var its = items - var ln = 0 - var lst = last_byte - while st <= lst do - st += its.length_of_char_at(st) - ln += 1 - end - return ln - end - - redef fun [](index) do return items.char_at(char_to_byte_index(index)) - # Index of the character `index` in `items` private fun char_to_byte_index(index: Int): Int do var ln = length @@ -107,6 +84,37 @@ class FlatString return ns_i end + redef fun [](index) do return items.char_at(char_to_byte_index(index)) +end + +# Immutable strings of characters. +class FlatString + super FlatText + super String + + # Index at which `self` begins in `items`, inclusively + redef var first_byte is noinit + + # Index at which `self` ends in `items`, inclusively + redef var last_byte is noinit + + redef var chars = new FlatStringCharView(self) is lazy + + redef var bytes = new FlatStringByteView(self) is lazy + + redef var length is lazy do + if bytelen == 0 then return 0 + var st = first_byte + var its = items + var ln = 0 + var lst = last_byte + while st <= lst do + st += its.length_of_char_at(st) + ln += 1 + end + return ln + end + redef fun reversed do var b = new FlatBuffer.with_capacity(bytelen + 1) @@ -280,7 +288,7 @@ class FlatString var mifrom = first_byte if s isa FlatText then var sits = s.items - var sifrom = s.as(FlatString).first_byte + var sifrom = s.first_byte var ns = new NativeString(nlen + 1) mits.copy_to(ns, mlen, mifrom, 0) sits.copy_to(ns, slen, sifrom, mlen) @@ -471,23 +479,15 @@ class FlatBuffer redef var chars: Sequence[Char] = new FlatBufferCharView(self) is lazy - redef var bytes: Sequence[Byte] = new FlatBufferByteView(self) is lazy + redef var bytes = new FlatBufferByteView(self) is lazy redef var bytelen = 0 - # O(n) - redef fun length do - var max = bytelen - if max == 0 then return 0 - var pos = 0 - var ln = 0 - var its = items - while pos < max do - pos += its.length_of_char_at(pos) - ln += 1 - end - return ln - end + redef var length = 0 + + private var char_cache: Int = -1 + + private var byte_cache: Int = -1 private var capacity = 0 @@ -527,12 +527,6 @@ class FlatBuffer items.copy_to(items, bytelen - from, from, from - len) end - redef fun [](i) - do - assert i < length and i >= 0 - return items.char_at(items.char_to_byte_index(i)) - end - redef fun []=(index, item) do assert index >= 0 and index <= length @@ -553,6 +547,7 @@ class FlatBuffer lshift_bytes(ip + clen, -size_diff) end bytelen += size_diff + bytepos += size_diff items.set_char_at(ip, item) end @@ -564,21 +559,14 @@ class FlatBuffer enlarge(bytelen + clen) items.set_char_at(bytelen, c) bytelen += clen - end - - private fun add_byte(b: Byte) do - if written then reset - is_dirty = true - enlarge(bytelen + 1) - items[bytelen] = b - # FIXME: Might trigger errors - bytelen += 1 + length += 1 end redef fun clear do is_dirty = true if written then reset bytelen = 0 + length = 0 end redef fun empty do return new Buffer @@ -626,11 +614,12 @@ class FlatBuffer # # If `items` is shared, `written` should be set to true after the creation # so that a modification will do a copy-on-write. - private init with_infos(items: NativeString, capacity, bytelen: Int) + private init with_infos(items: NativeString, capacity, bytelen, length: Int) do self.items = items self.capacity = capacity self.bytelen = bytelen + self.length = length end # Create a new string copied from `s`. @@ -643,6 +632,7 @@ class FlatBuffer for i in substrings do i.as(FlatString).items.copy_to(items, i.bytelen, 0, 0) end bytelen = s.bytelen + length = s.length capacity = s.bytelen written = true end @@ -662,15 +652,14 @@ class FlatBuffer is_dirty = true var sl = s.bytelen enlarge(bytelen + sl) - if s isa FlatString then + if s isa FlatText then s.items.copy_to(items, sl, s.first_byte, bytelen) - else if s isa FlatBuffer then - s.items.copy_to(items, sl, 0, bytelen) else for i in s.substrings do append i return end bytelen += sl + length += s.length end # Copies the content of self in `dest` @@ -695,7 +684,7 @@ class FlatBuffer var byte_length = byteto - bytefrom + 1 var r_items = new NativeString(byte_length) items.copy_to(r_items, byte_length, bytefrom, 0) - return new FlatBuffer.with_infos(r_items, byte_length, byte_length) + return new FlatBuffer.with_infos(r_items, byte_length, byte_length, count) else return new Buffer end @@ -761,39 +750,6 @@ private class FlatBufferByteView redef fun [](index) do return target.items[index] - redef fun []=(index, item) - do - assert index >= 0 and index <= target.bytelen - if index == target.bytelen then - add(item) - return - end - target.items[index] = item - end - - redef fun push(c) - do - target.add_byte(c) - end - - fun enlarge(cap: Int) - do - target.enlarge(cap) - end - - redef fun append(s) - do - var s_length = s.length - if target.capacity < (target.length + s_length) then enlarge(s_length + target.length) - var pos = target.length - var its = target.items - for i in s do - its[pos] = i - pos += 1 - end - target.length += s.length - end - redef fun iterator_from(pos) do return new FlatBufferByteIterator.with_pos(target, pos) redef fun reverse_iterator_from(pos) do return new FlatBufferByteReverseIterator.with_pos(target, pos) diff --git a/lib/standard/text/ropes.nit b/lib/standard/text/ropes.nit index 08611b7..2b3ff28 100644 --- a/lib/standard/text/ropes.nit +++ b/lib/standard/text/ropes.nit @@ -270,7 +270,7 @@ class RopeBuffer redef var chars: Sequence[Char] is lazy do return new RopeBufferChars(self) - redef var bytes: Sequence[Byte] is lazy do return new RopeBufferBytes(self) + redef var bytes is lazy do return new RopeBufferBytes(self) # The final string being built on the fly private var str: String = "" @@ -281,6 +281,9 @@ class RopeBuffer # Next available (e.g. unset) character in the `Buffer` private var rpos = 0 + # Length (in chars) of the buffered part + private var nslen = 0 + # Keeps track of the buffer's currently dumped part # # This might happen if for instance, a String was being @@ -436,7 +439,7 @@ class RopeBuffer end if s isa FlatText then var oits = s.items - var from = if s isa FlatString then s.first_byte else 0 + var from = s.first_byte var remsp = buf_size - rpos if slen <= remsp then oits.copy_to(ns, slen, from, rpos) @@ -467,18 +470,6 @@ class RopeBuffer rpos = rp end - private fun add_byte(b: Byte) do - var rp = rpos - if rp >= buf_size then - dump_buffer - rp = 0 - end - ns[rp] = b - rp += 1 - bytelen += 1 - rpos = rp - end - # Converts the Buffer to a FlatString, appends it to # the final String and re-allocates a new larger Buffer. private fun dump_buffer do @@ -1237,23 +1228,6 @@ class RopeBufferBytes end end - redef fun []=(i,c) do - if i == target.length then target.add_byte c - if i < target.str.length then - # FIXME: Will need to be optimized and rewritten with Unicode - var s = target.str - var l = s.substring(0, i) - var r = s.substring_from(i + 1) - target.str = l + c.to_i.ascii.to_s + r - else - target.ns[i - target.str.length] = c - end - end - - redef fun add(c) do target.add_byte c - - redef fun push(c) do target.add_byte c - redef fun iterator_from(i) do return new RopeBufferByteIterator.from(target, i) redef fun reverse_iterator_from(i) do return new RopeBufferByteReverseIterator.from(target, i) diff --git a/misc/jenkins/check_contrib.sh b/misc/jenkins/check_contrib.sh index d43f7f5..320dac8 100755 --- a/misc/jenkins/check_contrib.sh +++ b/misc/jenkins/check_contrib.sh @@ -25,11 +25,11 @@ for p in $projects; do dir=`dirname "$p"` name=`basename "$dir"` echo "*** make $dir ***" - if misc/jenkins/unitrun.sh "run-$name-make" make -C "$dir"; then + if misc/jenkins/unitrun.sh "cmd-$name-make" make -C "$dir"; then # Make OK, is there a `check` rule? make -C "$dir" check -n 2>/dev/null || continue echo "*** makecheck $dir ***" - if misc/jenkins/unitrun.sh "run-$name-makecheck" make -C "$dir" check; then + if misc/jenkins/unitrun.sh "cmd-$name-makecheck" make -C "$dir" check; then : else failed="$failed $name-check" diff --git a/misc/jenkins/checklicense.sh b/misc/jenkins/checklicense.sh index 3fcd8af..16f5260 100755 --- a/misc/jenkins/checklicense.sh +++ b/misc/jenkins/checklicense.sh @@ -14,19 +14,33 @@ # limitations under the License. # Check missing "This file is part of NIT…" comment in committed scripts. +# +# Usage: checklicense.sh from to -if test "$#" -lt 2; then - echo "Usage: checklicense from to" - echo "" - exit -fi +set -e -from=$1 -to=$2 +from=${1:-origin/master} +to=${2:-HEAD} err=0 +cd `git rev-parse --show-toplevel` + +echo "checklicense $from (`git rev-parse "$from"`) .. $to (`git rev-parse "$to"`)" git diff --name-status $from..$to -- "*.nit" "*.sh" | sed -n 's/^A\s*//p' > checklicense_new_files.out -test -s checklicense_new_files.out || exit 0 -grep -L '\(^\|\b\)# [Tt]his file is part of NIT ' `cat checklicense_new_files.out` 2>/dev/null | tee checklicense_missing.out -test \! -s checklicense_missing.out +if test \! -s checklicense_new_files.out; then + echo "No new files" + exit 0 +fi +grep -L '\(^\|\b\)# [Tt]his file is part of NIT ' `cat checklicense_new_files.out` 2>/dev/null > checklicense_missing.out || true +if test -s checklicense_missing.out; then + echo "These files are missing their licence:" + echo "" + cat checklicense_missing.out + echo "" + echo "Please double check that the licence text (i.e. \`This file is part of NIT...\`) is included at the begin of these files." + exit 1 +else + echo "All `cat checklicense_new_files.out | wc -l` checked new files have a correct license." + exit 0 +fi diff --git a/misc/jenkins/checksignedoffby.sh b/misc/jenkins/checksignedoffby.sh index bebd200..9a5c27f 100755 --- a/misc/jenkins/checksignedoffby.sh +++ b/misc/jenkins/checksignedoffby.sh @@ -14,36 +14,47 @@ # limitations under the License. # Check missing signed-off-by in commits +# Usage: checksignedoffby from to -if test "$#" -lt 2; then - echo "Usage: checksignedoffby from to" - echo "" - exit -fi +set -e -from=$1 -to=$2 +from=${1:-origin/master} +to=${2:-HEAD} err=0 +cd `git rev-parse --show-toplevel` + +echo "checksignedoffby $from (`git rev-parse "$from"`) .. $to (`git rev-parse "$to"`)" for ref in `git rev-list --no-merges "$from".."$to"`; do # What is the expected? sig=`git --no-pager show -s --format='Signed-off-by: %an <%ae>' $ref` # Do we found some signed-off-by? git --no-pager show -s --format="%b" $ref | grep "^Signed-off-by:" > check_signedoff_list.out || { + echo "" + echo "Missing $sig for commit" git --no-pager show -s --oneline $ref - echo "Missing $sig" err=1 continue } # Do we found the expected thing? cat check_signedoff_list.out | grep -q "^$sig\$" && continue + echo "" + echo "Bad or missing Signed-off-by for commit" git --no-pager show -s --oneline $ref - echo "Bad or missing $sig; got:" + echo "Expected (from local git config):" + echo "$sig" + echo "Got:" cat check_signedoff_list.out err=1 done rm check_signedoff_list.out 2> /dev/null +if test "$err" = 1; then + echo "" + echo "Please check that each commit contains a \`Signed-off-by:\` statement that matches the author's name and email." + echo "Note that existing commits should be amended; pushing new commit is not sufficient." +fi + exit $err diff --git a/misc/jenkins/checkwhitespaces.sh b/misc/jenkins/checkwhitespaces.sh new file mode 100755 index 0000000..32a9aab --- /dev/null +++ b/misc/jenkins/checkwhitespaces.sh @@ -0,0 +1,51 @@ +#!/bin/bash +# 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. + +# Check whitespace errors in commits +# Usage: checkwhitespaces from to +# +# This script is in fact a more friendly version of `git log --check` + +set -e + +from=${1:-origin/master} +to=${2:-HEAD} + +err=0 + +cd `git rev-parse --show-toplevel` + +echo "checkwhitespaces $from (`git rev-parse "$from"`) .. $to (`git rev-parse "$to"`)" +for ref in `git rev-list --no-merges "$from".."$to"`; do + # Show nothing if no error + if git --no-pager show --check --oneline $ref > /dev/null; then + continue + fi + + # Run the command again to display things + echo "" + echo "Found whitespace errors in commit" + git --no-pager show --check --oneline $ref || true + err=1 +done + +if test "$err" = 1; then + echo "" + echo "Please check that each file in each commit does not contain whitespace errors." + echo "Note that existing commits should be amended; pushing new commit is not sufficient." + echo "Hint: use \"git log --check\" to see whitespace errors." +fi + +exit $err diff --git a/misc/jenkins/nitester-wrapper.sh b/misc/jenkins/nitester-wrapper.sh index 902cd4a..70f086b 100755 --- a/misc/jenkins/nitester-wrapper.sh +++ b/misc/jenkins/nitester-wrapper.sh @@ -35,14 +35,14 @@ if ! git checkout $hash; then fi # Make basic bootstrap -$tools_dir/unitrun.sh "run-make-csrc" make -C c_src -$tools_dir/unitrun.sh "run-make-version" src/git-gen-version.sh -$tools_dir/unitrun.sh "run-make-nitc_0" c_src/nitc -o bin/nitc_0 src/nitc.nit -$tools_dir/unitrun.sh "run-make-nitc" bin/nitc_0 --dir bin/ src/nitc.nit -$tools_dir/unitrun.sh "run-make-nit-and-nitvm" bin/nitc --dir bin/ src/nit.nit src/nitvm.nit +$tools_dir/unitrun.sh "cmd-make-csrc" make -C c_src +$tools_dir/unitrun.sh "cmd-make-version" src/git-gen-version.sh +$tools_dir/unitrun.sh "cmd-make-nitc_0" c_src/nitc -o bin/nitc_0 src/nitc.nit +$tools_dir/unitrun.sh "cmd-make-nitc" bin/nitc_0 --dir bin/ src/nitc.nit +$tools_dir/unitrun.sh "cmd-make-nit-and-nitvm" bin/nitc --dir bin/ src/nit.nit src/nitvm.nit # Make nitester -$tools_dir/unitrun.sh "run-make-nitester" make -C contrib/nitester/ +$tools_dir/unitrun.sh "cmd-make-nitester" make -C contrib/nitester/ # Run tests cd tests diff --git a/misc/jenkins/unitrun.sh b/misc/jenkins/unitrun.sh index 6b1c7f5..1c3d39f 100755 --- a/misc/jenkins/unitrun.sh +++ b/misc/jenkins/unitrun.sh @@ -63,13 +63,21 @@ if test "$res" != "0"; then echo >> "${name}.xml" "" echo "+ Command returned $res" >&2 fi +if test -s "${name}.out"; then cat >> "${name}.xml"< +END +fi +if test -s "${name}.2.out"; then +cat >> "${name}.xml"< +END +fi +cat >> "${name}.xml"< END diff --git a/share/man/Makefile b/share/man/Makefile index 4aa0754..b42d869 100644 --- a/share/man/Makefile +++ b/share/man/Makefile @@ -15,11 +15,20 @@ IN=$(wildcard nit*.md) OUT=$(patsubst %.md,man1/%.1,$(IN)) +MARKDOWN=../../lib/markdown +NITMD=$(MARKDOWN)/nitmd + all: $(OUT) -man1/%.1: %.md + +man1/%.1: %.md $(NITMD) mkdir -p man1 - pandoc $< -t man -s -o $@ + echo ".TH $* 1" > $@ + $(NITMD) $< -t man >> $@ + + +$(NITMD): + $(MAKE) -C $(MARKDOWN) # Rule to produce mdwn files for ikiwiki that will be used at http://nitlanguage.org/tools/ web: @@ -27,7 +36,7 @@ web: mkdir -p www cp nit*.md www rename '$$_ = "$${_}wn"' www/*.md - sed -i -e '1d;/SEE ALSO/,$$d' www/*.mdwn + sed -i -e '/SEE ALSO/,$$d' www/*.mdwn publish: web rsync www/* asimov:wiki/nitlanguage/doc/tools/ diff --git a/share/man/nit.md b/share/man/nit.md index 697f2bb..6fb1202 100644 --- a/share/man/nit.md +++ b/share/man/nit.md @@ -1,5 +1,3 @@ -% NIT(1) - # NAME nit - interprets and debugs Nit programs. @@ -55,60 +53,60 @@ Whatever follows it is used as arguments of the interpreted program. ## COMMAND -`-e` -: Specifies the program from command-line. +### `-e` +Specifies the program from command-line. - The `-e` option runs a program written on the command line. - Like with ruby, perl, bash and other script language. +The `-e` option runs a program written on the command line. +Like with ruby, perl, bash and other script language. - $ nit -e 'print 5+5' - 10 + $ nit -e 'print 5+5' + 10 -`-n` -: Repeatedly run the program for each line in file-name arguments. +### `-n` +Repeatedly run the program for each line in file-name arguments. - If no arguments are given, then `nit` iterates over the lines of the standard input (stdin). +If no arguments are given, then `nit` iterates over the lines of the standard input (stdin). - $ echo "hello world" | nit -n -e 'print sys.line.capitalized' - Hello World + $ echo "hello world" | nit -n -e 'print sys.line.capitalized' + Hello World - If some arguments are given, then `nit` considers that each argument is a filepath then it iterates on their lines. +If some arguments are given, then `nit` considers that each argument is a filepath then it iterates on their lines. ## INTERPRETATION OPTIONS -`--discover-call-trace` -: Trace calls of the first invocation of methods. +### `--discover-call-trace` +Trace calls of the first invocation of methods. - Each time a method is invoked for the first time, its information is printed on the standard output for error (`stderr`). +Each time a method is invoked for the first time, its information is printed on the standard output for error (`stderr`). - This option helps the user to have a simplified but humanly readable overview of the behavior of a particular program execution. +This option helps the user to have a simplified but humanly readable overview of the behavior of a particular program execution. ## DEBUGGER OPTIONS -`-d` -: Launches the target program with the debugger attached to it +### `-d` +Launches the target program with the debugger attached to it -`-c` -: Launches the target program with the interpreter, such as when the program fails, the debugging prompt is summoned +### `-c` +Launches the target program with the interpreter, such as when the program fails, the debugging prompt is summoned -`--socket` -: Launches the target program with raw output on the network via sockets +### `--socket` +Launches the target program with raw output on the network via sockets -`--websocket` -: Launches the target program with output on the network via websockets +### `--websocket` +Launches the target program with output on the network via websockets -`--port` -: Sets the debug port (Defaults to 22125) - Must be contained between 0 and 65535 +### `--port` +Sets the debug port (Defaults to 22125) - Must be contained between 0 and 65535 ## OTHER OPTIONS -`--vm` -: Run the virtual machine instead of the naive interpreter (experimental) +### `--vm` +Run the virtual machine instead of the naive interpreter (experimental) The virtual machine is currently under heavy development and, unless you are developing the vm, there is no reason to use this option yet. -`-o` -: Does nothing. Used for compatibility. +### `-o` +Does nothing. Used for compatibility. # DEBUGGER @@ -139,58 +137,58 @@ If you want to trace the modifications or uses of a variable of your choice, the ## DEBUGGER COMMANDS -`n` -: Proceeds to the next instruction (step-over) +### `n` +Proceeds to the next instruction (step-over) -`s` -: Steps in an instruction +### `s` +Steps in an instruction -`finish` -: Steps out of an instruction +### `finish` +Steps out of an instruction -`c` -: Continues the execution until a breakpoint is encountered or until an error/end of program +### `c` +Continues the execution until a breakpoint is encountered or until an error/end of program -`b/break line_number` -: Adds a breakpoint on line *line_number* for the current file +### `b/break line_number` +Adds a breakpoint on line *line_number* for the current file -`b/break file line_number` -: Adds a breakpoint on line *line_number* for the file *file* (Don't forget to add the .nit extension to the command) +### `b/break file line_number` +Adds a breakpoint on line *line_number* for the file *file* (Don't forget to add the .nit extension to the command) -`d/delete line_number` -: Removes a breakpoint on line *line_number* for the current file +### `d/delete line_number` +Removes a breakpoint on line *line_number* for the current file -`d/delete file line_number` -: Removes a breakpoint on line *line_number* for the file *file* +### `d/delete file line_number` +Removes a breakpoint on line *line_number* for the file *file* -`kill` -: Kills the current program (produces a stack trace) +### `kill` +Kills the current program (produces a stack trace) -`variable = value` -: Sets the value of *variable* to *value* (Only supports primitive types for now : Bool, Char, Int, Float) +### `variable = value` +Sets the value of *variable* to *value* (Only supports primitive types for now : Bool, Char, Int, Float) -`p/print variable_name` -: Prints the value of the variable *variable_name* +### `p/print variable_name` +Prints the value of the variable *variable_name* -`p/print stack` -: Prints a stack trace starting with the current frame +### `p/print stack` +Prints a stack trace starting with the current frame -`p/print variable_name[index]` -: Prints the value of the variable contained at the index *index* of variable *variable_name* (*variable_name* must be a subtype of SequenceRead) +### `p/print variable_name[index]` +Prints the value of the variable contained at the index *index* of variable *variable_name* (*variable_name* must be a subtype of SequenceRead) -`p/print variable_name[index_from..index_to]` -: Prints the values of all the variables contained from index *index_from* up to *index_to* in the variable *variable_name* +### `p/print variable_name[index_from..index_to]` +Prints the values of all the variables contained from index *index_from* up to *index_to* in the variable *variable_name* All the print commands also work on any dimension SequenceRead collection. -`variable_name as alias` -: Sets an alias *alias* for the variable *variable_name* +### `variable_name as alias` +Sets an alias *alias* for the variable *variable_name* -`trace variable_name [break/print]` -: Traces the uses of the variable you chose to trace by printing the statement it appears in or by breaking on each use. (The [break/print] part is not mandatory, by default, the print option will be used) +### `trace variable_name [break/print]` +Traces the uses of the variable you chose to trace by printing the statement it appears in or by breaking on each use. (The [break/print] part is not mandatory, by default, the print option will be used) -`untrace variable_name` -: Removes the trace on the variable you chose to trace earlier in the program +### `untrace variable_name` +Removes the trace on the variable you chose to trace earlier in the program # SEE ALSO diff --git a/share/man/nitc.md b/share/man/nitc.md index 21fb966..896eb6d 100644 --- a/share/man/nitc.md +++ b/share/man/nitc.md @@ -1,5 +1,3 @@ -% NITC(1) - # NAME nitc - compiles Nit programs. @@ -46,214 +44,216 @@ See the documentation of these specific modules for details. ## MESSAGES -`-W`, `--warn` -: Show additional warnings (advices). +### `-W`, `--warn` + +Show additional warnings (advices). + +By default, only important warnings are displayed. +May be overridden by `-w`. - By default, only important warnings are displayed. - May be overridden by `-w`. +Important warnings are displayed by default. A warning is considered important when: - Important warnings are displayed by default. A warning is considered important when: +* There is a simple correction. +* There is no reason to let the code this way. +* There is always a real issue (no false positive). - * There is a simple correction. - * There is no reason to let the code this way. - * There is always a real issue (no false positive). +Other warnings, called advices, are not displayed by default to avoid filling the terminal with +unwanted information. +A warning is considered an advice when: - Other warnings, called advices, are not displayed by default to avoid filling the terminal with - unwanted information. - A warning is considered an advice when: +* The correction could be complex. e.g. require a refactorisation or an API change. +* The correction cannot be done. e.g. Code that use a deprecated API for some compatibility reason. +* There is not a real issue (false positive). Note that this should be unlikely. +* Transitional: While a real important warning, it fires a lot in current code, so a transition is needed +in order to let people fix them before promoting the advice to an important warning. - * The correction could be complex. e.g. require a refactorisation or an API change. - * The correction cannot be done. e.g. Code that use a deprecated API for some compatibility reason. - * There is not a real issue (false positive). Note that this should be unlikely. - * Transitional: While a real important warning, it fires a lot in current code, so a transition is needed - in order to let people fix them before promoting the advice to an important warning. +### `-w`, `--warning` -`-w`, `--warning` -: Show/hide a specific warning. +Show/hide a specific warning. - Each type of warning can be individually displayed or hidden. - The `-w` option takes the name of a warning (displayed at the end of the warning message, between parentheses) to activate it; - and "no-{name}" to disable it. - It has precedence over -q and -W. - Multiple `-w` can be given. +Each type of warning can be individually displayed or hidden. +The `-w` option takes the name of a warning (displayed at the end of the warning message, between parentheses) to activate it; +and "no-{name}" to disable it. +It has precedence over -q and -W. +Multiple `-w` can be given. - To show only `missing-doc` warnings in standard" +To show only `missing-doc` warnings in standard" - $ nitc -q -w missing-doc standard + $ nitc -q -w missing-doc standard - To show all warnings and advices, except `missing-doc`: +To show all warnings and advices, except `missing-doc`: - $ nitc -W -w no-missing-doc standard + $ nitc -W -w no-missing-doc standard - To show important warnings except `useless-type-test`, but not advice except `missing-doc`: +To show important warnings except `useless-type-test`, but not advice except `missing-doc`: - $ nitc -w missing-doc -w no-useless-type-test standard + $ nitc -w missing-doc -w no-useless-type-test standard -`-q`, `--quiet` -: Do not show warnings. - May be overridden by `-w` +### `-q`, `--quiet` +Do not show warnings. +May be overridden by `-w` -`--stop-on-first-error` -: Just display the first encountered error then stop. +### `--stop-on-first-error` +Just display the first encountered error then stop. - By default, nitc tries to detect and display more than one error before aborting the compilation. +By default, nitc tries to detect and display more than one error before aborting the compilation. -`--no-color` -: Do not use color to display errors and warnings. +### `--no-color` +Do not use color to display errors and warnings. - Also, do not echo the line. - This options is mainly used by scripts and tools that need parsable error messages. +Also, do not echo the line. +This options is mainly used by scripts and tools that need parsable error messages. -`-v`, `--verbose` -: Additional messages from the tool. - Multiple `-v` can be given to improve the verbosity. +### `-v`, `--verbose` +Additional messages from the tool. +Multiple `-v` can be given to improve the verbosity. - With one `-v`, there is constant number of lines. - With two `-v`, the number of lines is proportional to the number of modules. - With three `-v`, the number of lines is proportional to the number of definition of classes. - With four `-v`, the number of lines is proportional to the number of definition of properties. +With one `-v`, there is constant number of lines. +With two `-v`, the number of lines is proportional to the number of modules. +With three `-v`, the number of lines is proportional to the number of definition of classes. +With four `-v`, the number of lines is proportional to the number of definition of properties. -`--log` -: Generate various log files. +### `--log` +Generate various log files. - The tool will generate some files in the logging directory (see `--log-dir`). - These files are intended to the advanced user and the developers of the tools. +The tool will generate some files in the logging directory (see `--log-dir`). +These files are intended to the advanced user and the developers of the tools. -`--log-dir` -: Directory where to generate log files. +### `--log-dir` +Directory where to generate log files. - By default the directory is called `logs` in the working directory. +By default the directory is called `logs` in the working directory. -`-h`, `-?`, `--help` -: Show Help (the list of options). +### `-h`, `-?`, `--help` +Show Help (the list of options). -`--version` -: Show version and exit. +### `--version` +Show version and exit. ## PATHS -`-I`, `--path` -: Add an additional include path. +### `-I`, `--path` +Add an additional include path. - This option is used to indicate an additional path of a directory containing Nit libraries. +This option is used to indicate an additional path of a directory containing Nit libraries. - The path added with `-I` are searched before those added by the environment variable `NIT_PATH`. +The path added with `-I` are searched before those added by the environment variable `NIT_PATH`. - May be used more than once. +May be used more than once. -`-o`, `--output` -: Output executable name. +### `-o`, `--output` +Output executable name. - Indicates the path and name of the produced executable. +Indicates the path and name of the produced executable. - Note: it is better to use `--dir` if only the directory is important. - This way, the platform extension will be correctly set. +Note: it is better to use `--dir` if only the directory is important. +This way, the platform extension will be correctly set. - `-o` is not usable if multiple programs are compiled at once. +### `-o` is not usable if multiple programs are compiled at once. -`--dir` -: Output directory. +### `--dir` +Output directory. - Produce the executables in the given directory instead of the current directory. +Produce the executables in the given directory instead of the current directory. -`--nit-dir` -: Base directory of the Nit installation. +### `--nit-dir` +Base directory of the Nit installation. - Has precedence over the environment variable `NIT_DIR`. +Has precedence over the environment variable `NIT_DIR`. ## COMPILATION -`--compile-dir` -: Directory used to generate temporary files. +### `--compile-dir` +Directory used to generate temporary files. - By default, it is named `nit_compile` and created in the current directory and destroyed after the compilation. +By default, it is named `nit_compile` and created in the current directory and destroyed after the compilation. - If the option `--compile_dir` or `--no-cc` is used, then the directory is not destroyed and let as is. +If the option `--compile_dir` or `--no-cc` is used, then the directory is not destroyed and let as is. -`--no-cc` -: Do not invoke the C compiler. +### `--no-cc` +Do not invoke the C compiler. - Files in the compilation directory are generated but the C compiler is not invoked. +Files in the compilation directory are generated but the C compiler is not invoked. - This option is mainly used to produce C files distributable then compilable on system that do not have a Nit compiler (e.g. embedded system). - In this case, it is suggested to also use the options `--dir`, `--compile-dir` and `--semi-global`. +This option is mainly used to produce C files distributable then compilable on system that do not have a Nit compiler (e.g. embedded system). +In this case, it is suggested to also use the options `--dir`, `--compile-dir` and `--semi-global`. - $ nitc examples/hello_world.nit --no-cc --dir hello --compile-dir hello --semi-global + $ nitc examples/hello_world.nit --no-cc --dir hello --compile-dir hello --semi-global - Will produce a `hello` directory that contains the required C files to finish the compilation. - Only the C files required for the program are generated. - The final binary will be generated in the same directory. +Will produce a `hello` directory that contains the required C files to finish the compilation. +Only the C files required for the program are generated. +The final binary will be generated in the same directory. - Note that, to be useful, the compilation directory is not destroyed when `--no-cc` is used. +Note that, to be useful, the compilation directory is not destroyed when `--no-cc` is used. -`-m` -: Additional module to mix-in. +### `-m` +Additional module to mix-in. - Additional modules are imported and refine the main module of the program. - This has basically the same effect than implementing a specific module that imports the main module of the program then each one of the mix-in modules. - May be used more than once. +Additional modules are imported and refine the main module of the program. +This has basically the same effect than implementing a specific module that imports the main module of the program then each one of the mix-in modules. +May be used more than once. - This is option is used to weave additional behaviors to existing programs. - Modules designated to bring features to programs by refining basic or specialized services, without any intervention of the main program, are good candidates to be used with the `-m` option. - E.g. `hash_debug`. +This is option is used to weave additional behaviors to existing programs. +Modules designated to bring features to programs by refining basic or specialized services, without any intervention of the main program, are good candidates to be used with the `-m` option. +E.g. `hash_debug`. - An other usage of the `-m` option is to compile program to a specific platform. E.g. `emscripten` or `android`. +An other usage of the `-m` option is to compile program to a specific platform. E.g. `emscripten` or `android`. - A last usage is to develop programs as product lines with a main basic module (vanilla) and specific distinct features as flavor modules, then to combine them at compile-time. +A last usage is to develop programs as product lines with a main basic module (vanilla) and specific distinct features as flavor modules, then to combine them at compile-time. - $ nitc prog_vanilla.nit -m feature_chocolate.nit -m feature_cherry.nit + $ nitc prog_vanilla.nit -m feature_chocolate.nit -m feature_cherry.nit -`-D`, `--define` -: Define a specific property. +### `-D`, `--define` +Define a specific property. - The `-D` option allows to refine a top-level method at compile-time. - This has basically the same effect than implementing a specific module that imports the main module of the program and refines the designated methods. +The `-D` option allows to refine a top-level method at compile-time. +This has basically the same effect than implementing a specific module that imports the main module of the program and refines the designated methods. - The designated method must be top-level function with no parameters that returns a Bool, an Int or a String. +The designated method must be top-level function with no parameters that returns a Bool, an Int or a String. - The argument of the `-D` option is "{name}={value}". - For Bool, the argument can also be just "{name}", in this case, the value is considered to be `true`. +The argument of the `-D` option is "{name}={value}". +For Bool, the argument can also be just "{name}", in this case, the value is considered to be `true`. - $ nitc foo.nit -D prefix=/opt/foo -D port=8080 -D with_ssl + $ nitc foo.nit -D prefix=/opt/foo -D port=8080 -D with_ssl -`--release` -: Compile in release mode and finalize application. +### `--release` +Compile in release mode and finalize application. - Currently, this only affect the android platform. +Currently, this only affect the android platform. -`-g`, `--debug` -: Compile in debug mode. +### `-g`, `--debug` +Compile in debug mode. - Currently removes gcc optimizations. - Also preserves the source-files directory for C-debuggers. +Currently removes gcc optimizations. +Also preserves the source-files directory for C-debuggers. - For more debugging-related options, see also `--hardening` and `NIT_GC_OPTION` +For more debugging-related options, see also `--hardening` and `NIT_GC_OPTION` ## COMPILATION MODES -`nitc` includes distinct compilation modes. +### `nitc` includes distinct compilation modes. -`--separate` -: Use separate compilation (default mode). +### `--separate` +Use separate compilation (default mode). - In separate compilation, modules are compiled independently of their programs. - This makes the recompilation of programs faster since only the modified files need to be recompiled. +In separate compilation, modules are compiled independently of their programs. +This makes the recompilation of programs faster since only the modified files need to be recompiled. -`--global` -: Use global compilation. +### `--global` +Use global compilation. - The produced executables may become huge and the compilation time is prohibitive. - But sometime, they are faster. +The produced executables may become huge and the compilation time is prohibitive. +But sometime, they are faster. - In practice, `--semi-global` produces nearly as fast but smaller executables. +In practice, `--semi-global` produces nearly as fast but smaller executables. -`--erasure` -: Erase generic types. +### `--erasure` +Erase generic types. - Like `--separate` but use an erasure dynamic typing policy for generics and virtual types. - Usually you do not need this, even if you understand the previous sentence. +Like `--separate` but use an erasure dynamic typing policy for generics and virtual types. +Usually you do not need this, even if you understand the previous sentence. ## SEMI-GLOBAL OPTIMIZATIONS @@ -264,30 +264,30 @@ the independence on programs. Therefore, with these options, the produced executables may be faster and smaller but the recompilation time will increase. -`--semi-global` -: Enable all semi-global optimizations. +### `--semi-global` +Enable all semi-global optimizations. -`--rta` -: Activate RTA (Rapid Type Analysis). +### `--rta` +Activate RTA (Rapid Type Analysis). - This option only make sense in `--erasure` to enable some semi-global optimizations. +This option only make sense in `--erasure` to enable some semi-global optimizations. - RTA is implicitly enabled in `--separate` and `--global`. +RTA is implicitly enabled in `--separate` and `--global`. -`--inline-coloring-numbers` -: Inline colors and ids (semi-global). +### `--inline-coloring-numbers` +Inline colors and ids (semi-global). -`--inline-some-methods` -: Allow the separate compiler to inline some methods (semi-global). - Need `--rta`. +### `--inline-some-methods` +Allow the separate compiler to inline some methods (semi-global). +Need `--rta`. -`--direct-call-monomorph` -: Allow the separate compiler to direct call monomorphic sites (semi-global). - Need `--rta`. +### `--direct-call-monomorph` +Allow the separate compiler to direct call monomorphic sites (semi-global). +Need `--rta`. -`--skip-dead-methods` -: Do not compile dead methods (semi-global). - Need `--rta`. +### `--skip-dead-methods` +Do not compile dead methods (semi-global). +Need `--rta`. ## LINK-BOOST OPTIMIZATIONS @@ -296,29 +296,29 @@ In `--separate` and in `--erasure` modes, some optimization can be gained by hij Warning: these optimisations are not portable since they use extra features of the GNU linker `ld`. However, there is very few reasons to not use them if GNU `ld` is available. -`--link-boost` -: Enable all link-boost optimizations. +### `--link-boost` +Enable all link-boost optimizations. -`--colors-are-symbols` -: Store colors as symbols instead of static data. +### `--colors-are-symbols` +Store colors as symbols instead of static data. - By default, the various identifiers used to implement OO-mechanisms are stored as genuine constant static variables. +By default, the various identifiers used to implement OO-mechanisms are stored as genuine constant static variables. - This option uses linker symbols to encode these identifiers. - This makes the compiled program faster since less indirections are required to get the values. - It also produces executables that are a little bit smaller since static memory does not have to store the colors. +This option uses linker symbols to encode these identifiers. +This makes the compiled program faster since less indirections are required to get the values. +It also produces executables that are a little bit smaller since static memory does not have to store the colors. -`--substitute-monomorph` -: Replace monomorphic trampolines with direct call. +### `--substitute-monomorph` +Replace monomorphic trampolines with direct call. - Late-binding is implemented with *trampolines*, that are small functions that just select and jump the to right implementations. - If, at link-time, is it known that the target will always by the same implementation then all calls to the trampoline are replaced by - direct calls to this single implementation. +Late-binding is implemented with *trampolines*, that are small functions that just select and jump the to right implementations. +If, at link-time, is it known that the target will always by the same implementation then all calls to the trampoline are replaced by +direct calls to this single implementation. - Note that using trampolines as indirection slows down the executable. - However, it is expected that the gain of monomorphic direct-calls overcompensates the additional indirections in polymorphic trampoline-calls. +Note that using trampolines as indirection slows down the executable. +However, it is expected that the gain of monomorphic direct-calls overcompensates the additional indirections in polymorphic trampoline-calls. - Note: automatically enable option `--trampoline-call`. +Note: automatically enable option `--trampoline-call`. ## DANGEROUS OPTIMIZATIONS @@ -329,26 +329,26 @@ It also means that incorrect (buggy) programs may have unspecified behaviors In fact, these options are mainly used to bench the compilation results. -`--no-check-all` -: Disable all tests (dangerous). +### `--no-check-all` +Disable all tests (dangerous). -`--no-check-covariance` -: Disable type tests of covariant parameters (dangerous). +### `--no-check-covariance` +Disable type tests of covariant parameters (dangerous). -`--no-check-attr-isset` -: Disable isset tests before each attribute access (dangerous). +### `--no-check-attr-isset` +Disable isset tests before each attribute access (dangerous). -`--no-check-assert` -: Disable the evaluation of explicit `assert` and `as` (dangerous). +### `--no-check-assert` +Disable the evaluation of explicit `assert` and `as` (dangerous). -`--no-check-autocast` -: Disable implicit casts on unsafe expression usage (dangerous). +### `--no-check-autocast` +Disable implicit casts on unsafe expression usage (dangerous). -`--no-check-null` -: Disable tests of null receiver (dangerous). +### `--no-check-null` +Disable tests of null receiver (dangerous). -`--no-check-erasure-cast` -: Disable implicit casts on unsafe return with erasure-typing policy (dangerous). +### `--no-check-erasure-cast` +Disable implicit casts on unsafe return with erasure-typing policy (dangerous). ## UNOPTIMIZATIONS @@ -356,20 +356,20 @@ In fact, these options are mainly used to bench the compilation results. These options are used to debug or to bench the compilation results. Usually you do not need them since they make the generated code slower. -`--hardening` -: Generate contracts in the C code against bugs in the compiler. +### `--hardening` +Generate contracts in the C code against bugs in the compiler. -`--no-shortcut-range` -: Always instantiate a range and its iterator on 'for' loops. +### `--no-shortcut-range` +Always instantiate a range and its iterator on 'for' loops. -`--no-union-attribute` -: Put primitive attributes in a box instead of an union. +### `--no-union-attribute` +Put primitive attributes in a box instead of an union. -`--no-shortcut-equal` -: Always call == in a polymorphic way. +### `--no-shortcut-equal` +Always call == in a polymorphic way. -`--no-tag-primitive` -: Use only boxes for primitive types. +### `--no-tag-primitive` +Use only boxes for primitive types. The separate compiler uses tagged values to encode common primitive types like Int, Bool and Char. This option disables tags and forces such primitive values to be boxed. @@ -378,140 +378,140 @@ The drawback is that each boxing costs a memory allocation thus increases the am However, in some cases, it is possible that this option improves performance since the absence of tags simplify the implementation of OO mechanisms like method calls or equality tests. -`--no-inline-intern` -: Do not inline call to intern methods. +### `--no-inline-intern` +Do not inline call to intern methods. -`--colo-dead-methods` -: Force colorization of dead methods. +### `--colo-dead-methods` +Force colorization of dead methods. -`--no-gcc-directive` -: Disable advanced gcc directives for optimization. +### `--no-gcc-directive` +Disable advanced gcc directives for optimization. -`--trampoline-call` -: Use an indirection when calling. +### `--trampoline-call` +Use an indirection when calling. - Just add the trampolines of `--substitute-monomorph` without doing any aditionnal optimizations. +Just add the trampolines of `--substitute-monomorph` without doing any aditionnal optimizations. ## INTERNAL OPTIONS These options can be used to control the fine behavior of the tool. They are useless for a normal user. -`--disable-phase` -: Disable a specific phase; use `list` to get the list. +### `--disable-phase` +Disable a specific phase; use `list` to get the list. -`--only-parse` -: Only proceed to parse files. +### `--only-parse` +Only proceed to parse files. -`--only-metamodel` -: Stop after meta-model processing. +### `--only-metamodel` +Stop after meta-model processing. -`--ignore-visibility` -: Do not check, and produce errors, on visibility issues. +### `--ignore-visibility` +Do not check, and produce errors, on visibility issues. -`--no-main` -: Do not generate main entry point. +### `--no-main` +Do not generate main entry point. -`--no-stacktrace` -: The compiled program will not display stack traces on runtime errors. +### `--no-stacktrace` +The compiled program will not display stack traces on runtime errors. - Because stack traces rely on libunwind, this option might be useful in order to generate more portable binaries - since libunwind might be non available on the runtime system (or available with an ABI incompatible version). +Because stack traces rely on libunwind, this option might be useful in order to generate more portable binaries +since libunwind might be non available on the runtime system (or available with an ABI incompatible version). - The generated C is API-portable and can be reused, distributed and compiled on any supported system. - If the option `--no-stacktrace` is not used but the development files of the library `libunwind` are not available, then a warning will be displayed - and stack trace will be disabled. +The generated C is API-portable and can be reused, distributed and compiled on any supported system. +If the option `--no-stacktrace` is not used but the development files of the library `libunwind` are not available, then a warning will be displayed +and stack trace will be disabled. - Note that the `--no-stacktrace` option (or this absence) can be toggled manually in the generated Makefile (search `NO_STACKTRACE` in the Makefile). - Moreover, the environment variable `NIT_NO_STACK` (see bellow) can also be used at runtime to disable stack traces. +Note that the `--no-stacktrace` option (or this absence) can be toggled manually in the generated Makefile (search `NO_STACKTRACE` in the Makefile). +Moreover, the environment variable `NIT_NO_STACK` (see bellow) can also be used at runtime to disable stack traces. -`--max-c-lines` -: Maximum number of lines in generated C files. Use 0 for unlimited. +### `--max-c-lines` +Maximum number of lines in generated C files. Use 0 for unlimited. -`--group-c-files` -: Group all generated code in the same series of files. +### `--group-c-files` +Group all generated code in the same series of files. -`--make-flags` -: Additional options to the `make` command. +### `--make-flags` +Additional options to the `make` command. - $ nitc foo.nit --make-flags 'CC=clang' --make-flags 'CFLAGS="-O0 -g"' + $ nitc foo.nit --make-flags 'CC=clang' --make-flags 'CFLAGS="-O0 -g"' -`--typing-test-metrics` -: Enable static and dynamic count of all type tests. +### `--typing-test-metrics` +Enable static and dynamic count of all type tests. -`--invocation-metrics` -: Enable static and dynamic count of all method invocations. +### `--invocation-metrics` +Enable static and dynamic count of all method invocations. -`--isset-checks-metrics` -: Enable static and dynamic count of isset checks before attributes access. +### `--isset-checks-metrics` +Enable static and dynamic count of isset checks before attributes access. -`--tables-metrics` -: Enable static size measuring of tables used for vft, typing and resolution. +### `--tables-metrics` +Enable static size measuring of tables used for vft, typing and resolution. -`--set-dummy-tool` -: Set toolname and version to DUMMY. Useful for testing. +### `--set-dummy-tool` +Set toolname and version to DUMMY. Useful for testing. -`--bash-completion` -: Generate bash_completion file for this program. +### `--bash-completion` +Generate bash_completion file for this program. -`--stub-man` -: Generate a stub manpage in pandoc markdown format. +### `--stub-man` +Generate a stub manpage in pandoc markdown format. -`--keep-going` -: Continue after errors, whatever the consequences. +### `--keep-going` +Continue after errors, whatever the consequences. The tool does not stop after some errors but continue until it produces incorrect result, crashes, erases the hard drive, or just continue forever in an infinite loop. This option is used to test the robustness of the tools by allowing phases to progress on incorrect data. # ENVIRONMENT VARIABLES -`NIT_DIR` -: Base directory of the Nit installation. +### `NIT_DIR` +Base directory of the Nit installation. - When the `NIT_DIR` environment variable is set then it specifies the path of the Nit install directory. +When the `NIT_DIR` environment variable is set then it specifies the path of the Nit install directory. - This directory is used to locate binaries, shared files and the common libraries. +This directory is used to locate binaries, shared files and the common libraries. - When unset, the directory is guessed according to some heuristic. +When unset, the directory is guessed according to some heuristic. - The `--nit-dir` option also set the base directory of the Nit installation but has precedence. +The `--nit-dir` option also set the base directory of the Nit installation but has precedence. -`NIT_PATH` -: Additional include paths. +### `NIT_PATH` +Additional include paths. - The `NIT_PATH` environment variable contains paths of directories containing Nit libraries. - Each path is separated with a column (`:`). +The `NIT_PATH` environment variable contains paths of directories containing Nit libraries. +Each path is separated with a column (`:`). - The `-I` option also add additional paths. +The `-I` option also add additional paths. -`NIT_GC_OPTION` -: Runtime control of the garbage collector. +### `NIT_GC_OPTION` +Runtime control of the garbage collector. - The behavior of the GC of the executables produced by nitc can be tuned with this environment variable. +The behavior of the GC of the executables produced by nitc can be tuned with this environment variable. - The environment variable is used when programs are executed, not when they are compiled. - Thus, you do not need to recompile programs in order to tweak their GC options. +The environment variable is used when programs are executed, not when they are compiled. +Thus, you do not need to recompile programs in order to tweak their GC options. - Available values are: +Available values are: - * boehm: use the Boehm-Demers-Weiser's conservative garbage collector (default). - * malloc: disable the GC and just use `malloc` without doing any `free`. - * large: disable the GC and just allocate a large memory area to use for all instantiation. - * help: show the list of available options. +* boehm: use the Boehm-Demers-Weiser's conservative garbage collector (default). +* malloc: disable the GC and just use `malloc` without doing any `free`. +* large: disable the GC and just allocate a large memory area to use for all instantiation. +* help: show the list of available options. -`NIT_NO_STACK` -: Runtime control of stack traces. +### `NIT_NO_STACK` +Runtime control of stack traces. - By default, stack traces are printed when a runtime errors occurs during the execution of a compiled program. - When setting this environment variable to a non empty value, such stack traces are disabled. +By default, stack traces are printed when a runtime errors occurs during the execution of a compiled program. +When setting this environment variable to a non empty value, such stack traces are disabled. - The environment variable is used when programs are executed, not when they are compiled. - Thus, you do not need to recompile programs in order to disable generated stack traces. +The environment variable is used when programs are executed, not when they are compiled. +Thus, you do not need to recompile programs in order to disable generated stack traces. - Note that stack traces require that, during the compilation, development files of the library `libunwind` are available. - If they are not available, then programs are compiled without any stack trace support. +Note that stack traces require that, during the compilation, development files of the library `libunwind` are available. +If they are not available, then programs are compiled without any stack trace support. - To completely disable stack traces, see the option `--no-stacktrace`. +To completely disable stack traces, see the option `--no-stacktrace`. # SEE ALSO diff --git a/share/man/nitdbg_client.md b/share/man/nitdbg_client.md index 52e2e32..cbe515e 100644 --- a/share/man/nitdbg_client.md +++ b/share/man/nitdbg_client.md @@ -1,5 +1,3 @@ -% NITDBG_CLIENT(1) - # NAME nitdbg_client - network client for remote debugging. @@ -16,13 +14,13 @@ See the interpreter command `nit(1)` for details about remote debugging. # OPTIONS -`--host` -: Sets the host to debug from, use IPV4 only. (Defaults to 127.0.0.1). +### `--host` +Sets the host to debug from, use IPV4 only. (Defaults to 127.0.0.1). -`--port` -: Sets the debug port (Defaults to 22125). +### `--port` +Sets the debug port (Defaults to 22125). - Must be contained between 0 and 65535 +Must be contained between 0 and 65535 # SEE ALSO diff --git a/share/man/nitdoc.md b/share/man/nitdoc.md index 3f5885a..b73e217 100644 --- a/share/man/nitdoc.md +++ b/share/man/nitdoc.md @@ -1,5 +1,3 @@ -% NITDOC(1) - # NAME nitdoc - generates HTML pages of API documentation from Nit source files. @@ -29,89 +27,89 @@ The format of the documentation is a dialect of [markdown] that allows GitHub fe Code blocks are interpreted as snippets of Nit programs and intended to be used as examples of code. When these code snippets are valid, executable and contain at least and `assert` clause, they could be automatically executed and verified. -See niunit(1) for details. +See `nitunit(1)` for details. [markdown]: http://daringfireball.net/projects/markdown # OPTIONS -`-d`, `--dir` -: output directory. +### `-d`, `--dir` +output directory. - Where the HTML files are generated. +Where the HTML files are generated. - By default, the directory is named `doc`. +By default, the directory is named `doc`. -`--source` -: Format to link source code. +### `--source` +Format to link source code. - The format string is used to generated links to some parts of the source-code. - Use `%f` for filename, `%l` for first line, and `%L` for last line. +The format string is used to generated links to some parts of the source-code. +Use `%f` for filename, `%l` for first line, and `%L` for last line. - For instance, the [standard library] use the following value to link to files in GitHub: +For instance, the [standard library] use the following value to link to files in GitHub: - "https://github.com/privat/nit/blob/$(git rev-parse HEAD)/%f#L%l-%L" + "https://github.com/privat/nit/blob/$(git rev-parse HEAD)/%f#L%l-%L" - Here, the `git rev-parse HEAD` is used to link to the current snapshot revision of the file. +Here, the `git rev-parse HEAD` is used to link to the current snapshot revision of the file. -`--no-attribute` -: Ignore the attributes. +### `--no-attribute` +Ignore the attributes. - Note: In Nit, attributes are private. Therefore, this option is only useful - when combined with `--private`. +Note: In Nit, attributes are private. Therefore, this option is only useful +when combined with `--private`. -`--no-dot` -: do not generate graphs with graphviz. +### `--no-dot` +do not generate graphs with graphviz. -`--private` -: also generate private API. +### `--private` +also generate private API. ## CUSTOMIZATION -`--sharedir` -: directory containing nitdoc assets. +### `--sharedir` +directory containing nitdoc assets. - By default `$NIT_DIR/share/nitdoc/` is used. +By default `$NIT_DIR/share/nitdoc/` is used. -`--shareurl` -: use shareurl instead of copy shared files. +### `--shareurl` +use shareurl instead of copy shared files. - By default, assets from the sharedir a copied into the output directory and refered with a relative path in the generated files. - Whith this option, the assets are not copied and the given URL of path is used in the generated files to locate assets. +By default, assets from the sharedir a copied into the output directory and referred with a relative path in the generated files. +With this option, the assets are not copied and the given URL of path is used in the generated files to locate assets. -`--custom-title` -: custom title for homepage. +### `--custom-title` +custom title for homepage. -`--custom-footer-text` -: custom footer text. +### `--custom-footer-text` +custom footer text. -`--custom-overview-text` -: custom intro text for homepage +### `--custom-overview-text` +custom intro text for homepage -`--custom-brand` -: custom link to external site +### `--custom-brand` +custom link to external site ## SERVICES -`--github-upstream` -: Git branch where edited commits will be pulled into (ex: user:repo:branch) +### `--github-upstream` +Git branch where edited commits will be pulled into (ex: user:repo:branch) -`--github-base-sha1` -: Git sha1 of base commit used to create pull request +### `--github-base-sha1` +Git sha1 of base commit used to create pull request -`--github-gitdir` -: Git working directory used to resolve path name (ex: /home/me/myproject/) +### `--github-gitdir` +Git working directory used to resolve path name (ex: /home/me/myproject/) -`--piwik-tracker` -: Piwik tracker URL (ex: `"nitlanguage.org/piwik/"`) +### `--piwik-tracker` +Piwik tracker URL (ex: `"nitlanguage.org/piwik/"`) -`--piwik-site-id` -: Piwik site ID +### `--piwik-site-id` +Piwik site ID ## TESTING -`--test` -: Only print the pages structure. Nothing is generated. +### `--test` +Only print the pages structure. Nothing is generated. # SEE ALSO diff --git a/share/man/nitlight.md b/share/man/nitlight.md index 4529bcb..00c15c2 100644 --- a/share/man/nitlight.md +++ b/share/man/nitlight.md @@ -1,5 +1,3 @@ -% NITLIGHT(1) - # NAME nitlight - generates HTML of highlighted code from Nit source files. @@ -17,49 +15,49 @@ Unlike generic lexical or syntactic highlighter, nitlight use semantic informati Common options of the Nit tools are understood. Here, only the specific one are indicated. -`-f`, `--fragment` -: Omit document header and footer. +### `-f`, `--fragment` +Omit document header and footer. - By default, a complete autonomous HTML document is generated. - If `-f` is given, only the inside of the body part is generated such that it could be integrated - into a HTML document. +By default, a complete autonomous HTML document is generated. +If `-f` is given, only the inside of the body part is generated such that it could be integrated +into a HTML document. -`--line-id-prefix` -: Prefix of the id of each line `` element. +### `--line-id-prefix` +Prefix of the id of each line `` element. - By default, each line is enclosed in its own `` element with an `id` attribute made of the line number prefixed by `L` (e.g. `L1` for the first line). +By default, each line is enclosed in its own `` element with an `id` attribute made of the line number prefixed by `L` (e.g. `L1` for the first line). - This option changes the prefix used. - If an empty string is used, then the `` are generated without `id` attributes. +This option changes the prefix used. +If an empty string is used, then the `` are generated without `id` attributes. - This option is especially usuful with `--fragment` when more than one highlighted code is - included in the same HTML document. - Each fragment can thus be generated with its own distinct prefix, or the id can be disabled alltogether. +This option is especially useful with `--fragment` when more than one highlighted code is +included in the same HTML document. +Each fragment can thus be generated with its own distinct prefix, or the id can be disabled altogether. -`--first-line` -: Start the source file at this line (default: 1). +### `--first-line` +Start the source file at this line (default: 1). - The generated HTML will only contains lines bellow the specified one. +The generated HTML will only contains lines bellow the specified one. -`--last-line` -: End the source file at this line (default: to the end) +### `--last-line` +End the source file at this line (default: to the end) - The generated HTML will only contains lines ebove the specified one. +The generated HTML will only contains lines above the specified one. -`-d`, `--dir` -: Output html files in a specific directory (required if more than one module). +### `-d`, `--dir` +Output html files in a specific directory (required if more than one module). - By default the generated HTML is outputted on the screen. - If this option is used, then HTML files are generated in the specified directory. +By default the generated HTML is outputted on the screen. +If this option is used, then HTML files are generated in the specified directory. - A basic `index.heml` and a `style.css` file are also generated in the directory. +A basic `index.heml` and a `style.css` file are also generated in the directory. -`--full` -: Process also imported modules. +### `--full` +Process also imported modules. - By default, only the modules indicated on the command line are highlighted. +By default, only the modules indicated on the command line are highlighted. - With the `--full` option, all imported modules (even those in standard) are also precessed. +With the `--full` option, all imported modules (even those in standard) are also precessed. # SEE ALSO diff --git a/share/man/nitls.md b/share/man/nitls.md index b8273f4..b7fffc9 100644 --- a/share/man/nitls.md +++ b/share/man/nitls.md @@ -1,5 +1,3 @@ -% NITLS(1) - # NAME nitls - lists the projects, groups and paths of Nit sources files. @@ -45,20 +43,20 @@ Each combination of option Three presentation modes are available. -`-P`, `--project` -: List projects in a flat list (default). +### `-P`, `--project` +List projects in a flat list (default). - Only project are displayed (and not the individual files). +Only project are displayed (and not the individual files). -`-t`, `--tree` -: List source files in their groups and projects. +### `-t`, `--tree` +List source files in their groups and projects. - Each `.nit` file is presented in a tree of projects and groups. +Each `.nit` file is presented in a tree of projects and groups. -`-s`, `--source` -: List source files in a flat list. +### `-s`, `--source` +List source files in a flat list. - Each `.nit` file is presented indivitually. +Each `.nit` file is presented indivitually. The three modes are exclusives. @@ -66,37 +64,37 @@ The default mode is `--project` unless one on the argument is a group, then it i ## COLLECT -`-r`, `--recursive` -: Process directories recursively. +### `-r`, `--recursive` +Process directories recursively. - All `.nit` files found in the specified directory and subdirectories are considered. +All `.nit` files found in the specified directory and subdirectories are considered. -`-d`, `--depends` -: List dependencies of given modules +### `-d`, `--depends` +List dependencies of given modules - All imported modules are also considered. +All imported modules are also considered. - In --tree and --source modes, the modules direclty imported are also displayed. +In --tree and --source modes, the modules direclty imported are also displayed. -`-k`, `--keep` -: Ignore errors and files that are not a Nit source file. +### `-k`, `--keep` +Ignore errors and files that are not a Nit source file. - When a file that is not a valid Nit module is encoutered, it is ignored and the rest of the files are - processed. +When a file that is not a valid Nit module is encoutered, it is ignored and the rest of the files are +processed. - Without this option, an error message is displayed and nitls terminates on such a case. +Without this option, an error message is displayed and nitls terminates on such a case. ## PRESENTATION OPTIONS -`-p`, `--path` -: List only path (instead of name + path). +### `-p`, `--path` +List only path (instead of name + path). - Paths are displayed uncolored. +Paths are displayed uncolored. -`-M` -: List dependencies suitable for a rule in a Makefile. +### `-M` +List dependencies suitable for a rule in a Makefile. - Alias for `-d`, `-p` and `-s`. +Alias for `-d`, `-p` and `-s`. # SEE ALSO diff --git a/share/man/nitmetrics.md b/share/man/nitmetrics.md index dcdb67c..0277161 100644 --- a/share/man/nitmetrics.md +++ b/share/man/nitmetrics.md @@ -1,5 +1,3 @@ -% NITMETRICS(1) - # NAME nitmetrics -- computes various metrics on Nit programs. @@ -12,63 +10,63 @@ nitmetrics [*options*]... FILE... ## METRICS -`--all` -: Compute all metrics +### `--all` +Compute all metrics -`--mmodules` -: Compute metrics about mmodules +### `--mmodules` +Compute metrics about mmodules -`--mclasses` -: Compute metrics about mclasses +### `--mclasses` +Compute metrics about mclasses -`--mendel` -: Compute mendel metrics +### `--mendel` +Compute mendel metrics -`--inheritance` -: Compute metrics about inheritance usage +### `--inheritance` +Compute metrics about inheritance usage -`--refinement` -: Compute metrics about refinement usage +### `--refinement` +Compute metrics about refinement usage -`--self` -: Compute metrics about the usage of explicit and implicit self +### `--self` +Compute metrics about the usage of explicit and implicit self -`--ast` -: Compute metrics about the usage of nodes and identifiers in the AST +### `--ast` +Compute metrics about the usage of nodes and identifiers in the AST -`--nullables` -: Compute metrics on nullables send +### `--nullables` +Compute metrics on nullables send -`--static-types` -: Compute explicit static types metrics +### `--static-types` +Compute explicit static types metrics -`--tables` -: Compute tables metrics +### `--tables` +Compute tables metrics -`--rta` -: Compute RTA metrics +### `--rta` +Compute RTA metrics -`--generate_hyperdoc` -: Generate Hyperdoc +### `--generate_hyperdoc` +Generate Hyperdoc -`--poset` -: Complete metrics on posets +### `--poset` +Complete metrics on posets -`--detect-variance-constraints` -: Detects the definition-site variance constraints on formal parameters. +### `--detect-variance-constraints` +Detects the definition-site variance constraints on formal parameters. - Infers the possible variance annotations of formal types in Nit programs by identifying the existing constraints on the usage of those formal type. +Infers the possible variance annotations of formal types in Nit programs by identifying the existing constraints on the usage of those formal type. ## OUTPUT -`--csv` -: Also export metrics in CSV format. +### `--csv` +Also export metrics in CSV format. -`-d`, `--dir` -: Directory where some statistics files are generated. +### `-d`, `--dir` +Directory where some statistics files are generated. -`--no-colors` -: Disable colors in console outputs. +### `--no-colors` +Disable colors in console outputs. # SEE ALSO diff --git a/share/man/nitpick.md b/share/man/nitpick.md index 001a6ce..45a258f 100644 --- a/share/man/nitpick.md +++ b/share/man/nitpick.md @@ -1,5 +1,3 @@ -% NITPICK(1) - # NAME nitpick - collect potential style and code issues. diff --git a/share/man/nitpretty.md b/share/man/nitpretty.md index 2a023e5..571d4f2 100644 --- a/share/man/nitpretty.md +++ b/share/man/nitpretty.md @@ -1,5 +1,3 @@ -% NITPRETTY(1) - # NAME nitpretty - pretty print Nit code from Nit source files. @@ -10,36 +8,36 @@ nitpretty [*options*]... FILE # OPTIONS -`--dir` -: Working directory (default is '.nitpretty') +### `--dir` +Working directory (default is '.nitpretty') -`-o`, `--output` -: Output name (default is pretty.nit) +### `-o`, `--output` +Output name (default is pretty.nit) -`--diff` -: Show diff between source and output +### `--diff` +Show diff between source and output -`--meld` -: Show diff between source and output using meld +### `--meld` +Show diff between source and output using meld -`--check` -: Check format of Nit source files +### `--check` +Check format of Nit source files - This option creates a temporary pretty printed file then checks if the output - of the diff command on the source file and the pretty printed one is empty. +This option creates a temporary pretty printed file then checks if the output +of the diff command on the source file and the pretty printed one is empty. -`--break-strings` -: Break too long string literals +### `--break-strings` +Break too long string literals -`--inline-do` -: Force do keyword on the same line as the method signature +### `--inline-do` +Force do keyword on the same line as the method signature -`--skip-empty` -: Force formatting of empty lines +### `--skip-empty` +Force formatting of empty lines - By default empty lines are kept as they were typed in the file. - When enabling this option, `nitpretty` will decide where to break lines and - will put empty lines to separate properties and code blocks. +By default empty lines are kept as they were typed in the file. +When enabling this option, `nitpretty` will decide where to break lines and +will put empty lines to separate properties and code blocks. # SPECIFICATION diff --git a/share/man/nitserial.md b/share/man/nitserial.md index 15ad1d3..317e510 100644 --- a/share/man/nitserial.md +++ b/share/man/nitserial.md @@ -1,5 +1,3 @@ -% NITSERIAL(1) - # NAME nitserial - generates a serialization support module @@ -10,11 +8,11 @@ nitserial [*options*]... FILE # OPTIONS -`-o`, `--output` -: Output file (can also be 'stdout') +### `-o`, `--output` +Output file (can also be 'stdout') -`--dir` -: Output directory +### `--dir` +Output directory # SEE ALSO diff --git a/share/man/nitunit.md b/share/man/nitunit.md index b43004f..09d2467 100644 --- a/share/man/nitunit.md +++ b/share/man/nitunit.md @@ -1,5 +1,3 @@ -% NITUNIT(1) - # NAME nitunit - executes the unit tests from Nit source files. @@ -32,24 +30,28 @@ The execution can be verified using `assert`. Example with a class: - module foo - # var foo = new Foo - # assert foo.bar == 10 - class Foo - var bar = 10 - end +~~~ +module foo +# var foo = new Foo +# assert foo.bar == 10 +class Foo + var bar = 10 +end +~~~ Everything used in the test must be declared. To test a method you have to instantiate its class: - module foo +~~~ +module foo +# var foo = new Foo +# assert foo.bar == 10 +class Foo # var foo = new Foo - # assert foo.bar == 10 - class Foo - # var foo = new Foo - # assert foo.baz(1, 2) == 3 - fun baz(a, b: Int) do return a + b - end + # assert foo.baz(1, 2) == 3 + 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. @@ -125,16 +127,18 @@ So for the module `foo.nit` the test suite will be called `test_foo.nit`. The structure of a test suite is the following: - # test suite for module `foo` - module test_foo - import foo # can be intrude to test private things - class TestFoo - # test case for `foo::Foo::baz` - fun test_baz do - var subject = new Foo - assert subject.baz(1, 2) == 3 - end +~~~~ +# test suite for module `foo` +module test_foo +import foo # can be intrude to test private things +class TestFoo + # test case for `foo::Foo::baz` + fun test_baz do + var subject = new Foo + assert subject.baz(1, 2) == 3 end +end +~~~~ Test suite can be executed using the same `nitunit` command: @@ -143,112 +147,118 @@ Test suite can be executed using the same `nitunit` command: `nitunit` will execute a test for each method named `test_*` in a class named `Test*` so multiple tests can be executed for a single method: - class TestFoo - fun test_baz_1 do - var subject = new Foo - assert subject.baz(1, 2) == 3 - end - fun test_baz_2 do - var subject = new Foo - assert subject.baz(1, -2) == -1 - end +~~~~ +class TestFoo + fun test_baz_1 do + var subject = new Foo + assert subject.baz(1, 2) == 3 end + fun test_baz_2 do + var subject = new Foo + assert subject.baz(1, -2) == -1 + end +end +~~~~ `TestSuites` also provide methods to configure the test run: `before_test` and `after_test`: methods called before/after each test case. They can be used to factorize repetitive tasks: - class TestFoo - var subject: Foo - # Mandatory empty init - init do end - # Method executed before each test - fun before_test do - subject = new Foo - end - fun test_baz_1 do - assert subject.baz(1, 2) == 3 - end - fun test_baz_2 do - assert subject.baz(1, -2) == -1 - end +~~~~ +class TestFoo + var subject: Foo + # Mandatory empty init + init do end + # Method executed before each test + fun before_test do + subject = new Foo + end + fun test_baz_1 do + assert subject.baz(1, 2) == 3 + end + fun test_baz_2 do + assert subject.baz(1, -2) == -1 end +end +~~~~ When using custom test attributes, an empty `init` must be declared to allow automatic test running. `before_module` and `after_module`: methods called before/after each test suite. They have to be declared at top level: - module test_bdd_connector - import bdd_connector - # Testing the bdd_connector - class TestConnector - # test cases using a server - end - # Method executed before testing the module - fun before_module do - # start server before all test cases - end - # Method executed after testing the module - fun after_module do - # stop server after all test cases - end +~~~~ +module test_bdd_connector +import bdd_connector +# Testing the bdd_connector +class TestConnector + # test cases using a server +end +# Method executed before testing the module +fun before_module do + # start server before all test cases +end +# Method executed after testing the module +fun after_module do + # stop server after all test cases +end +~~~~ ## Generating test suites - Write test suites for big modules can be a repetitive and boring task... - To make it easier, `nitunit` can generate test skeletons for Nit modules: +Write test suites for big modules can be a repetitive and boring task... +To make it easier, `nitunit` can generate test skeletons for Nit modules: $ nitunit --gen-suite foo.nit - This will generate the test suite `test_foo` containing test case stubs for all public - methods found in `foo.nit`. +This will generate the test suite `test_foo` containing test case stubs for all public +methods found in `foo.nit`. # OPTIONS -`--full` -: Process also imported modules. +### `--full` +Process also imported modules. - By default, only the modules indicated on the command line are tested. +By default, only the modules indicated on the command line are tested. - With the `--full` option, all imported modules (even those in standard) are also precessed. +With the `--full` option, all imported modules (even those in standard) are also precessed. -`-o`, `--output` -: Output name (default is 'nitunit.xml') +### `-o`, `--output` +Output name (default is 'nitunit.xml') - `nitunit` produces a XML file comatible with JUnit. +### `nitunit` produces a XML file comatible with JUnit. -`--dir` -: Working directory (default is '.nitunit') +### `--dir` +Working directory (default is '.nitunit') - In order to execute the tests, nit files are generated then compiled and executed in the giver working directory. +In order to execute the tests, nit files are generated then compiled and executed in the giver working directory. -`--no-act` -: Does not compile and run tests. +### `--no-act` +Does not compile and run tests. -`-p`, `--pattern` -: Only run test case with name that match pattern. Examples: `TestFoo`, `TestFoo*`, `TestFoo::test_foo`, `TestFoo::test_foo*`, `test_foo`, `test_foo*` +### `-p`, `--pattern` +Only run test case with name that match pattern. Examples: `TestFoo`, `TestFoo*`, `TestFoo::test_foo`, `TestFoo::test_foo*`, `test_foo`, `test_foo*` -`-t`, `--target-file` -: Specify test suite location. +### `-t`, `--target-file` +Specify test suite location. ## SUITE GENERATION -`--gen-suite` -: Generate test suite skeleton for a module +### `--gen-suite` +Generate test suite skeleton for a module -`-f`, `--force` -: Force test generation even if file exists. +### `-f`, `--force` +Force test generation even if file exists. - Any existing test suite will be overwritten. +Any existing test suite will be overwritten. -`--private` -: Also generate test case for private methods. +### `--private` +Also generate test case for private methods. -`--only-show` -: Only display the skeleton, do not write any file. +### `--only-show` +Only display the skeleton, do not write any file. # SEE ALSO diff --git a/share/man/nitx.md b/share/man/nitx.md index 4ba5154..2b6f8ba 100644 --- a/share/man/nitx.md +++ b/share/man/nitx.md @@ -1,5 +1,3 @@ -% NITX(1) - # NAME nitx - displays specific pieces of API information from Nit source files. @@ -19,37 +17,37 @@ If no command are given, the program starts an interactive session where command # COMMANDS -`name` -: lookup module, class and property with the corresponding 'name'. +### `name` +lookup module, class and property with the corresponding 'name'. -`param: Type` -: lookup methods using the corresponding 'Type' as parameter. +### `param: Type` +lookup methods using the corresponding 'Type' as parameter. -`return: Type` -: lookup methods returning the corresponding 'Type'. +### `return: Type` +lookup methods returning the corresponding 'Type'. -`new: Type` -: lookup methods creating new instances of 'Type'. +### `new: Type` +lookup methods creating new instances of 'Type'. -`call: Property` -: lookup calls to 'Property'. +### `call: Property` +lookup calls to 'Property'. -`doc: name` -: lookup documentation pages about 'name'. +### `doc: name` +lookup documentation pages about 'name'. -`code: name` -: lookup source code related to 'name'. +### `code: name` +lookup source code related to 'name'. -`:h` -: display an help message about the commands. +### `:h` +display an help message about the commands. -`:q` -: exit the tool. +### `:q` +exit the tool. # OPTIONS -`-q` -: execute a query, display results in console then quit. +### `-q` +execute a query, display results in console then quit. # SEE ALSO diff --git a/src/c_tools.nit b/src/c_tools.nit index 5df891e..9a03c5a 100644 --- a/src/c_tools.nit +++ b/src/c_tools.nit @@ -148,7 +148,7 @@ class ExternCFile if not pkgconfigs.is_empty then pkg = "`pkg-config --cflags {pkgconfigs.join(" ")}`" end - return "$(CC) $(CFLAGS) -Wno-unused-function -Wall {self.cflags} {pkg} -c -o {o} {ff}" + return "$(CC) $(CFLAGS) -Wall -Wno-unused-function {self.cflags} {pkg} -c -o {o} {ff}" end redef fun compiles_to_o_file do return true diff --git a/src/compiler/abstract_compiler.nit b/src/compiler/abstract_compiler.nit index 78d2c31..b58d4a3 100644 --- a/src/compiler/abstract_compiler.nit +++ b/src/compiler/abstract_compiler.nit @@ -654,6 +654,7 @@ abstract class AbstractCompiler self.header.add_decl("#include \n") self.header.add_decl("#include \n") self.header.add_decl("#include \n") + self.header.add_decl("#include \n") self.header.add_decl("#include \"gc_chooser.h\"") self.header.add_decl("#ifdef ANDROID") self.header.add_decl(" #include ") @@ -1506,6 +1507,46 @@ abstract class AbstractCompilerVisitor return res end + # Generate an int8 value + fun int8_instance(value: Int8): RuntimeVariable + do + var t = mmodule.int8_type + var res = new RuntimeVariable("((int8_t){value.to_s})", t, t) + return res + end + + # Generate an int16 value + fun int16_instance(value: Int16): RuntimeVariable + do + var t = mmodule.int16_type + var res = new RuntimeVariable("((int16_t){value.to_s})", t, t) + return res + end + + # Generate a uint16 value + fun uint16_instance(value: UInt16): RuntimeVariable + do + var t = mmodule.uint16_type + var res = new RuntimeVariable("((uint16_t){value.to_s})", t, t) + return res + end + + # Generate an int32 value + fun int32_instance(value: Int32): RuntimeVariable + do + var t = mmodule.int32_type + var res = new RuntimeVariable("((int32_t){value.to_s})", t, t) + return res + end + + # Generate a uint32 value + fun uint32_instance(value: UInt32): RuntimeVariable + do + var t = mmodule.uint32_type + var res = new RuntimeVariable("((uint32_t){value.to_s})", t, t) + return res + end + # Generate a char value fun char_instance(value: Char): RuntimeVariable do @@ -1905,8 +1946,18 @@ redef class MClassType return "uint32_t" else if mclass.name == "Float" then return "double" + else if mclass.name == "Int8" then + return "int8_t" else if mclass.name == "Byte" then return "unsigned char" + else if mclass.name == "Int16" then + return "int16_t" + else if mclass.name == "UInt16" then + return "uint16_t" + else if mclass.name == "Int32" then + return "int32_t" + else if mclass.name == "UInt32" then + return "uint32_t" else if mclass.name == "NativeString" then return "char*" else if mclass.name == "NativeArray" then @@ -1937,8 +1988,18 @@ redef class MClassType return "c" else if mclass.name == "Float" then return "d" + else if mclass.name == "Int8" then + return "i8" else if mclass.name == "Byte" then return "b" + else if mclass.name == "Int16" then + return "i16" + else if mclass.name == "UInt16" then + return "u16" + else if mclass.name == "Int32" then + return "i32" + else if mclass.name == "UInt32" then + return "u32" else if mclass.name == "NativeString" then return "str" else if mclass.name == "NativeArray" then @@ -2160,6 +2221,21 @@ redef class AMethPropdef else if pname == ">=" then v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null))) return true + else if pname == "to_i8" then + v.ret(v.new_expr("(int8_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_i16" then + v.ret(v.new_expr("(int16_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_u16" then + v.ret(v.new_expr("(uint16_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_i32" then + v.ret(v.new_expr("(int32_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_u32" then + v.ret(v.new_expr("(uint32_t){arguments[0]}", ret.as(not null))) + return true else if pname == "to_f" then v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null))) return true @@ -2259,6 +2335,21 @@ redef class AMethPropdef else if pname == "to_f" then v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null))) return true + else if pname == "to_i8" then + v.ret(v.new_expr("(int8_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_i16" then + v.ret(v.new_expr("(int16_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_u16" then + v.ret(v.new_expr("(uint16_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_i32" then + v.ret(v.new_expr("(int32_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_u32" then + v.ret(v.new_expr("(uint32_t){arguments[0]}", ret.as(not null))) + return true else if pname == "ascii" then v.ret(v.new_expr("{arguments[0]}", ret.as(not null))) return true @@ -2334,6 +2425,21 @@ redef class AMethPropdef else if pname == "to_b" then v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null))) return true + else if pname == "to_i8" then + v.ret(v.new_expr("(int8_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_i16" then + v.ret(v.new_expr("(int16_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_u16" then + v.ret(v.new_expr("(uint16_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_i32" then + v.ret(v.new_expr("(int32_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_u32" then + v.ret(v.new_expr("(uint32_t){arguments[0]}", ret.as(not null))) + return true end else if cname == "NativeString" then if pname == "[]" then @@ -2358,6 +2464,456 @@ redef class AMethPropdef else if cname == "NativeArray" then v.native_array_def(pname, ret, arguments) return true + else if cname == "Int8" then + if pname == "output" then + v.add("printf(\"%\"PRIi8 \"\\n\", {arguments.first});") + return true + else if pname == "object_id" then + v.ret(v.new_expr("(long){arguments.first}", ret.as(not null))) + return true + else if pname == "+" then + v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null))) + return true + else if pname == "-" then + v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null))) + return true + else if pname == "unary -" then + v.ret(v.new_expr("-{arguments[0]}", ret.as(not null))) + return true + else if pname == "unary +" then + v.ret(arguments[0]) + return true + else if pname == "*" then + v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null))) + return true + else if pname == "/" then + v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null))) + return true + else if pname == "%" then + v.ret(v.new_expr("{arguments[0]} % {arguments[1]}", ret.as(not null))) + return true + else if pname == "<<" then + v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null))) + return true + else if pname == ">>" then + v.ret(v.new_expr("{arguments[0]} >> {arguments[1]}", ret.as(not null))) + return true + else if pname == "==" then + v.ret(v.equal_test(arguments[0], arguments[1])) + return true + else if pname == "!=" then + var res = v.equal_test(arguments[0], arguments[1]) + v.ret(v.new_expr("!{res}", ret.as(not null))) + return true + else if pname == "<" then + v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null))) + return true + else if pname == ">" then + v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null))) + return true + else if pname == "<=" then + v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null))) + return true + else if pname == ">=" then + v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null))) + return true + else if pname == "to_i" then + v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_b" then + v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_i16" then + v.ret(v.new_expr("(int16_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_u16" then + v.ret(v.new_expr("(uint16_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_i32" then + v.ret(v.new_expr("(int32_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_u32" then + v.ret(v.new_expr("(uint32_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_f" then + v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null))) + return true + else if pname == "ascii" then + v.ret(v.new_expr("{arguments[0]}", ret.as(not null))) + return true + else if pname == "&" then + v.ret(v.new_expr("{arguments[0]} & {arguments[1]}", ret.as(not null))) + return true + else if pname == "|" then + v.ret(v.new_expr("{arguments[0]} | {arguments[1]}", ret.as(not null))) + return true + else if pname == "^" then + v.ret(v.new_expr("{arguments[0]} ^ {arguments[1]}", ret.as(not null))) + return true + else if pname == "unary ~" then + v.ret(v.new_expr("~{arguments[0]}", ret.as(not null))) + return true + end + else if cname == "Int16" then + if pname == "output" then + v.add("printf(\"%\"PRIi16 \"\\n\", {arguments.first});") + return true + else if pname == "object_id" then + v.ret(v.new_expr("(long){arguments.first}", ret.as(not null))) + return true + else if pname == "+" then + v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null))) + return true + else if pname == "-" then + v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null))) + return true + else if pname == "unary -" then + v.ret(v.new_expr("-{arguments[0]}", ret.as(not null))) + return true + else if pname == "unary +" then + v.ret(arguments[0]) + return true + else if pname == "*" then + v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null))) + return true + else if pname == "/" then + v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null))) + return true + else if pname == "%" then + v.ret(v.new_expr("{arguments[0]} % {arguments[1]}", ret.as(not null))) + return true + else if pname == "<<" then + v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null))) + return true + else if pname == ">>" then + v.ret(v.new_expr("{arguments[0]} >> {arguments[1]}", ret.as(not null))) + return true + else if pname == "==" then + v.ret(v.equal_test(arguments[0], arguments[1])) + return true + else if pname == "!=" then + var res = v.equal_test(arguments[0], arguments[1]) + v.ret(v.new_expr("!{res}", ret.as(not null))) + return true + else if pname == "<" then + v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null))) + return true + else if pname == ">" then + v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null))) + return true + else if pname == "<=" then + v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null))) + return true + else if pname == ">=" then + v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null))) + return true + else if pname == "to_i" then + v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_b" then + v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_i8" then + v.ret(v.new_expr("(int8_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_u16" then + v.ret(v.new_expr("(uint16_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_i32" then + v.ret(v.new_expr("(int32_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_u32" then + v.ret(v.new_expr("(uint32_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_f" then + v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null))) + return true + else if pname == "&" then + v.ret(v.new_expr("{arguments[0]} & {arguments[1]}", ret.as(not null))) + return true + else if pname == "|" then + v.ret(v.new_expr("{arguments[0]} | {arguments[1]}", ret.as(not null))) + return true + else if pname == "^" then + v.ret(v.new_expr("{arguments[0]} ^ {arguments[1]}", ret.as(not null))) + return true + else if pname == "unary ~" then + v.ret(v.new_expr("~{arguments[0]}", ret.as(not null))) + return true + else if pname == "ascii" then + v.ret(v.new_expr("{arguments[0]}", ret.as(not null))) + return true + end + else if cname == "UInt16" then + if pname == "output" then + v.add("printf(\"%\"PRIu16 \"\\n\", {arguments.first});") + return true + else if pname == "object_id" then + v.ret(v.new_expr("(long){arguments.first}", ret.as(not null))) + return true + else if pname == "+" then + v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null))) + return true + else if pname == "-" then + v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null))) + return true + else if pname == "unary -" then + v.ret(v.new_expr("-{arguments[0]}", ret.as(not null))) + return true + else if pname == "unary +" then + v.ret(arguments[0]) + return true + else if pname == "*" then + v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null))) + return true + else if pname == "/" then + v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null))) + return true + else if pname == "%" then + v.ret(v.new_expr("{arguments[0]} % {arguments[1]}", ret.as(not null))) + return true + else if pname == "<<" then + v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null))) + return true + else if pname == ">>" then + v.ret(v.new_expr("{arguments[0]} >> {arguments[1]}", ret.as(not null))) + return true + else if pname == "==" then + v.ret(v.equal_test(arguments[0], arguments[1])) + return true + else if pname == "!=" then + var res = v.equal_test(arguments[0], arguments[1]) + v.ret(v.new_expr("!{res}", ret.as(not null))) + return true + else if pname == "<" then + v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null))) + return true + else if pname == ">" then + v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null))) + return true + else if pname == "<=" then + v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null))) + return true + else if pname == ">=" then + v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null))) + return true + else if pname == "to_i" then + v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_b" then + v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_i8" then + v.ret(v.new_expr("(int8_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_i16" then + v.ret(v.new_expr("(int16_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_i32" then + v.ret(v.new_expr("(int32_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_u32" then + v.ret(v.new_expr("(uint32_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_f" then + v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null))) + return true + else if pname == "&" then + v.ret(v.new_expr("{arguments[0]} & {arguments[1]}", ret.as(not null))) + return true + else if pname == "|" then + v.ret(v.new_expr("{arguments[0]} | {arguments[1]}", ret.as(not null))) + return true + else if pname == "^" then + v.ret(v.new_expr("{arguments[0]} ^ {arguments[1]}", ret.as(not null))) + return true + else if pname == "unary ~" then + v.ret(v.new_expr("~{arguments[0]}", ret.as(not null))) + return true + else if pname == "ascii" then + v.ret(v.new_expr("{arguments[0]}", ret.as(not null))) + return true + end + else if cname == "Int32" then + if pname == "output" then + v.add("printf(\"%\"PRIi32 \"\\n\", {arguments.first});") + return true + else if pname == "object_id" then + v.ret(v.new_expr("(long){arguments.first}", ret.as(not null))) + return true + else if pname == "+" then + v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null))) + return true + else if pname == "-" then + v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null))) + return true + else if pname == "unary -" then + v.ret(v.new_expr("-{arguments[0]}", ret.as(not null))) + return true + else if pname == "unary +" then + v.ret(arguments[0]) + return true + else if pname == "*" then + v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null))) + return true + else if pname == "/" then + v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null))) + return true + else if pname == "%" then + v.ret(v.new_expr("{arguments[0]} % {arguments[1]}", ret.as(not null))) + return true + else if pname == "<<" then + v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null))) + return true + else if pname == ">>" then + v.ret(v.new_expr("{arguments[0]} >> {arguments[1]}", ret.as(not null))) + return true + else if pname == "==" then + v.ret(v.equal_test(arguments[0], arguments[1])) + return true + else if pname == "!=" then + var res = v.equal_test(arguments[0], arguments[1]) + v.ret(v.new_expr("!{res}", ret.as(not null))) + return true + else if pname == "<" then + v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null))) + return true + else if pname == ">" then + v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null))) + return true + else if pname == "<=" then + v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null))) + return true + else if pname == ">=" then + v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null))) + return true + else if pname == "to_i" then + v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_b" then + v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_i8" then + v.ret(v.new_expr("(int8_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_i16" then + v.ret(v.new_expr("(int16_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_u16" then + v.ret(v.new_expr("(uint16_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_u32" then + v.ret(v.new_expr("(uint32_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_f" then + v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null))) + return true + else if pname == "&" then + v.ret(v.new_expr("{arguments[0]} & {arguments[1]}", ret.as(not null))) + return true + else if pname == "|" then + v.ret(v.new_expr("{arguments[0]} | {arguments[1]}", ret.as(not null))) + return true + else if pname == "^" then + v.ret(v.new_expr("{arguments[0]} ^ {arguments[1]}", ret.as(not null))) + return true + else if pname == "unary ~" then + v.ret(v.new_expr("~{arguments[0]}", ret.as(not null))) + return true + else if pname == "ascii" then + v.ret(v.new_expr("{arguments[0]}", ret.as(not null))) + return true + end + else if cname == "UInt32" then + if pname == "output" then + v.add("printf(\"%\"PRIu32 \"\\n\", {arguments.first});") + return true + else if pname == "object_id" then + v.ret(v.new_expr("(long){arguments.first}", ret.as(not null))) + return true + else if pname == "+" then + v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null))) + return true + else if pname == "-" then + v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null))) + return true + else if pname == "unary -" then + v.ret(v.new_expr("-{arguments[0]}", ret.as(not null))) + return true + else if pname == "unary +" then + v.ret(arguments[0]) + return true + else if pname == "*" then + v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null))) + return true + else if pname == "/" then + v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null))) + return true + else if pname == "%" then + v.ret(v.new_expr("{arguments[0]} % {arguments[1]}", ret.as(not null))) + return true + else if pname == "<<" then + v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null))) + return true + else if pname == ">>" then + v.ret(v.new_expr("{arguments[0]} >> {arguments[1]}", ret.as(not null))) + return true + else if pname == "==" then + v.ret(v.equal_test(arguments[0], arguments[1])) + return true + else if pname == "!=" then + var res = v.equal_test(arguments[0], arguments[1]) + v.ret(v.new_expr("!{res}", ret.as(not null))) + return true + else if pname == "<" then + v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null))) + return true + else if pname == ">" then + v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null))) + return true + else if pname == "<=" then + v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null))) + return true + else if pname == ">=" then + v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null))) + return true + else if pname == "to_i" then + v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_b" then + v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_i8" then + v.ret(v.new_expr("(int8_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_i16" then + v.ret(v.new_expr("(int16_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_u16" then + v.ret(v.new_expr("(uint16_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_i32" then + v.ret(v.new_expr("(int32_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_f" then + v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null))) + return true + else if pname == "&" then + v.ret(v.new_expr("{arguments[0]} & {arguments[1]}", ret.as(not null))) + return true + else if pname == "|" then + v.ret(v.new_expr("{arguments[0]} | {arguments[1]}", ret.as(not null))) + return true + else if pname == "^" then + v.ret(v.new_expr("{arguments[0]} ^ {arguments[1]}", ret.as(not null))) + return true + else if pname == "unary ~" then + v.ret(v.new_expr("~{arguments[0]}", ret.as(not null))) + return true + else if pname == "ascii" then + v.ret(v.new_expr("{arguments[0]}", ret.as(not null))) + return true + end end if pname == "exit" then v.add("exit({arguments[1]});") @@ -2910,6 +3466,11 @@ redef class AIntegerExpr redef fun expr(v) do if value isa Int then return v.int_instance(value.as(Int)) if value isa Byte then return v.byte_instance(value.as(Byte)) + if value isa Int8 then return v.int8_instance(value.as(Int8)) + if value isa Int16 then return v.int16_instance(value.as(Int16)) + if value isa UInt16 then return v.uint16_instance(value.as(UInt16)) + if value isa Int32 then return v.int32_instance(value.as(Int32)) + if value isa UInt32 then return v.uint32_instance(value.as(UInt32)) # Should never happen abort end diff --git a/src/compiler/separate_compiler.nit b/src/compiler/separate_compiler.nit index 9fd1606..ff5f3ba 100644 --- a/src/compiler/separate_compiler.nit +++ b/src/compiler/separate_compiler.nit @@ -252,7 +252,8 @@ class SeparateCompiler do # Collect all bas box class # FIXME: this is not completely fine with a separate compilation scheme - for classname in ["Int", "Bool", "Byte", "Char", "Float", "NativeString", "Pointer"] do + for classname in ["Int", "Bool", "Byte", "Char", "Float", "NativeString", + "Pointer", "Int8", "Int16", "UInt16", "Int32", "UInt32"] do var classes = self.mainmodule.model.get_mclasses_by_name(classname) if classes == null then continue assert classes.length == 1 else print classes.join(", ") diff --git a/src/doc/vim_autocomplete.nit b/src/doc/vim_autocomplete.nit index 290ed9d..ad5e891 100644 --- a/src/doc/vim_autocomplete.nit +++ b/src/doc/vim_autocomplete.nit @@ -201,28 +201,7 @@ redef class MClassType alpha_comparator.sort props for prop in props do if mclass.name == "Object" or prop.intro.mclassdef.mclass.name != "Object" then - - if prop.visibility == public_visibility then - stream.write "+ " - else stream.write "~ " # protected_visibility - - if prop isa MMethod then - if prop.is_init and prop.name != "init" then stream.write "init " - if prop.is_new and prop.name != "new" then stream.write "new " - end - - stream.write prop.name - - if prop isa MMethod then - stream.write prop.intro.msignature.to_s - end - - var mdoc = prop.intro.mdoc - if mdoc != null then - stream.write " # " - stream.write mdoc.content.first - end - stream.write line_separator + prop.write_synopsis(mainmodule, stream) end end end @@ -307,3 +286,72 @@ private class AutocompletePhase end end end + +redef class MModule + redef fun write_extra_doc(mainmodule, stream) + do + # Introduced classes + var class_intros = collect_intro_mclasses(protected_visibility).to_a + if class_intros.not_empty then + alpha_comparator.sort class_intros + stream.write line_separator*2 + stream.write "## Introduced classes" + + for c in class_intros do + stream.write line_separator + stream.write "* {c.name}" + var doc = c.intro.mdoc + if doc != null then stream.write ": {doc.content.first}" + end + end + + # Introduced properties + var prop_intros = new Array[MPropDef] + for c in mclassdefs do + prop_intros.add_all c.collect_intro_mpropdefs(protected_visibility) + end + + if prop_intros.not_empty then + alpha_comparator.sort prop_intros + stream.write line_separator*2 + stream.write "## Introduced properties" + stream.write line_separator + + for p in prop_intros do + p.mproperty.write_synopsis(mainmodule, stream) + end + end + end +end + +redef class MProperty + private fun write_synopsis(mainmodule: MModule, stream: Writer) + do + if visibility == public_visibility then + stream.write "+ " + else stream.write "~ " # protected_visibility + + if self isa MMethod then + if is_new and name != "new" then + stream.write "new " + else if is_init and name != "init" then + stream.write "init " + end + end + + stream.write name + + if self isa MMethod then + var intro = intro + assert intro isa MMethodDef + stream.write intro.msignature.to_s + end + + var mdoc = intro.mdoc + if mdoc != null then + stream.write " # " + stream.write mdoc.content.first + end + stream.write line_separator + end +end diff --git a/src/ffi/java.nit b/src/ffi/java.nit index dd32712..eca32ac 100644 --- a/src/ffi/java.nit +++ b/src/ffi/java.nit @@ -483,6 +483,11 @@ redef class MClassType if mclass.name == "Int" then return "long" if mclass.name == "Float" then return "double" if mclass.name == "Byte" then return "byte" + if mclass.name == "Int8" then return "byte" + if mclass.name == "Int16" then return "short" + if mclass.name == "UInt16" then return "short" + if mclass.name == "Int32" then return "int" + if mclass.name == "UInt32" then return "int" return super end @@ -495,6 +500,11 @@ redef class MClassType if mclass.name == "Int" then return "jlong" if mclass.name == "Float" then return "jdouble" if mclass.name == "Byte" then return "jbyte" + if mclass.name == "Int8" then return "jbyte" + if mclass.name == "Int16" then return "jshort" + if mclass.name == "UInt16" then return "jshort" + if mclass.name == "Int32" then return "jint" + if mclass.name == "UInt32" then return "jint" return super end @@ -555,6 +565,11 @@ redef class MClassType if mclass.name == "Int" then return "J" if mclass.name == "Float" then return "D" if mclass.name == "Byte" then return "B" + if mclass.name == "Int8" then return "B" + if mclass.name == "Int16" then return "S" + if mclass.name == "UInt16" then return "S" + if mclass.name == "Int32" then return "I" + if mclass.name == "UInt32" then return "I" return super end @@ -568,6 +583,11 @@ redef class MClassType if mclass.name == "Int" then return "Long" if mclass.name == "Float" then return "Double" if mclass.name == "Byte" then return "Byte" + if mclass.name == "Int8" then return "Byte" + if mclass.name == "Int16" then return "Short" + if mclass.name == "UInt16" then return "Short" + if mclass.name == "Int32" then return "Int" + if mclass.name == "UInt32" then return "Int" return super end end diff --git a/src/interpreter/dynamic_loading_ffi/README.md b/src/interpreter/dynamic_loading_ffi/README.md index 3a07c84..1d66f23 100644 --- a/src/interpreter/dynamic_loading_ffi/README.md +++ b/src/interpreter/dynamic_loading_ffi/README.md @@ -41,6 +41,11 @@ This API is compose of 2 main elements: int value_Bool; uint32_t value_Char; uint8_t value_Byte; + int8_t value_Int8; + int16_t value_Int16; + uint16_t value_UInt16; + int32_t value_Int32; + uint32_t value_UInt32; double value_Float; void* value_Pointer; } nit_call_arg; diff --git a/src/interpreter/dynamic_loading_ffi/dynamic_loading_ffi.nit b/src/interpreter/dynamic_loading_ffi/dynamic_loading_ffi.nit index 3f1bf0d..b507c9d 100644 --- a/src/interpreter/dynamic_loading_ffi/dynamic_loading_ffi.nit +++ b/src/interpreter/dynamic_loading_ffi/dynamic_loading_ffi.nit @@ -32,6 +32,11 @@ in "C Header" `{ int value_Bool; uint32_t value_Char; uint8_t value_Byte; + int8_t value_Int8; + int16_t value_Int16; + uint16_t value_UInt16; + int32_t value_Int32; + uint32_t value_UInt32; double value_Float; void* value_Pointer; } nit_call_arg; @@ -77,6 +82,36 @@ private extern class CallArg `{ nit_call_arg* `} # The `Byte` held by this cell fun byte=(value: Byte) `{ self->value_Byte = value; `} + # The `Int` held by this cell + fun int8: Int8 `{ return self->value_Int8; `} + + # The `Int` held by this cell + fun int8=(value: Int8) `{ self->value_Int8 = value; `} + + # The `Int` held by this cell + fun int16: Int16 `{ return self->value_Int16; `} + + # The `Int` held by this cell + fun int16=(value: Int16) `{ self->value_Int16 = value; `} + + # The `Int` held by this cell + fun uint16: UInt16 `{ return self->value_UInt16; `} + + # The `Int` held by this cell + fun uint16=(value: UInt16) `{ self->value_UInt16 = value; `} + + # The `Int` held by this cell + fun int32: Int32 `{ return self->value_Int32; `} + + # The `Int` held by this cell + fun int32=(value: Int32) `{ self->value_Int32 = value; `} + + # The `Int` held by this cell + fun uint32: UInt32 `{ return self->value_UInt32; `} + + # The `Int` held by this cell + fun uint32=(value: UInt32) `{ self->value_UInt32 = value; `} + # The `Float` held by this cell fun float: Float `{ return self->value_Float; `} @@ -115,6 +150,21 @@ private extern class CallArg `{ nit_call_arg* `} else if static_type.name == "Byte" then assert value isa PrimitiveInstance[Byte] self.byte = value.val + else if static_type.name == "Int8" then + assert value isa PrimitiveInstance[Int8] + self.int8 = value.val + else if static_type.name == "Int16" then + assert value isa PrimitiveInstance[Int16] + self.int16 = value.val + else if static_type.name == "UInt16" then + assert value isa PrimitiveInstance[UInt16] + self.uint16 = value.val + else if static_type.name == "Int32" then + assert value isa PrimitiveInstance[Int32] + self.int32 = value.val + else if static_type.name == "UInt32" then + assert value isa PrimitiveInstance[UInt32] + self.uint32 = value.val else if static_type.name == "Float" then assert value isa PrimitiveInstance[Float] self.float = value.val @@ -145,6 +195,16 @@ private extern class CallArg `{ nit_call_arg* `} return v.char_instance(self.char) else if name == "Byte" then return v.byte_instance(self.byte) + else if name == "Int8" then + return v.int8_instance(self.int8) + else if name == "Int16" then + return v.int16_instance(self.int16) + else if name == "UInt16" then + return v.uint16_instance(self.uint16) + else if name == "Int32" then + return v.int32_instance(self.int32) + else if name == "UInt32" then + return v.uint32_instance(self.uint32) else if name == "Float" then return v.float_instance(self.float) else if name == "NativeString" then diff --git a/src/interpreter/dynamic_loading_ffi/on_demand_compiler.nit b/src/interpreter/dynamic_loading_ffi/on_demand_compiler.nit index 5953647..c54d578 100644 --- a/src/interpreter/dynamic_loading_ffi/on_demand_compiler.nit +++ b/src/interpreter/dynamic_loading_ffi/on_demand_compiler.nit @@ -109,7 +109,7 @@ redef class AModule # Link everything in a shared library # TODO customize the compiler - var cmd = "{v.c_compiler} -Wall -shared -Wl,-soname,{mmodule.name}.so -g -o {foreign_code_lib_path} {object_files.join(" ")} {ldflags}" + var cmd = "{v.c_compiler} -Wall -shared -o {foreign_code_lib_path} {object_files.join(" ")} {ldflags}" if sys.system(cmd) != 0 then v.fatal "FFI Error: Failed to link native code using `{cmd}`" return false @@ -143,6 +143,11 @@ typedef union nit_call_arg { int value_Bool; uint32_t value_Char; uint8_t value_Byte; + int8_t value_Int8; + int16_t value_Int16; + uint16_t value_UInt16; + int32_t value_Int32; + uint32_t value_UInt32; double value_Float; void* value_Pointer; } nit_call_arg; diff --git a/src/interpreter/naive_interpreter.nit b/src/interpreter/naive_interpreter.nit index 3d3aa12..1181cf0 100644 --- a/src/interpreter/naive_interpreter.nit +++ b/src/interpreter/naive_interpreter.nit @@ -216,6 +216,51 @@ class NaiveInterpreter return instance end + # Return the int8 instance associated with `val`. + fun int8_instance(val: Int8): Instance + do + var t = mainmodule.int8_type + var instance = new PrimitiveInstance[Int8](t, val) + init_instance_primitive(instance) + return instance + end + + # Return the int16 instance associated with `val`. + fun int16_instance(val: Int16): Instance + do + var t = mainmodule.int16_type + var instance = new PrimitiveInstance[Int16](t, val) + init_instance_primitive(instance) + return instance + end + + # Return the uint16 instance associated with `val`. + fun uint16_instance(val: UInt16): Instance + do + var t = mainmodule.uint16_type + var instance = new PrimitiveInstance[UInt16](t, val) + init_instance_primitive(instance) + return instance + end + + # Return the int32 instance associated with `val`. + fun int32_instance(val: Int32): Instance + do + var t = mainmodule.int32_type + var instance = new PrimitiveInstance[Int32](t, val) + init_instance_primitive(instance) + return instance + end + + # Return the uint32 instance associated with `val`. + fun uint32_instance(val: UInt32): Instance + do + var t = mainmodule.uint32_type + var instance = new PrimitiveInstance[UInt32](t, val) + init_instance_primitive(instance) + return instance + end + # Return the char instance associated with `val`. fun char_instance(val: Char): Instance do @@ -656,6 +701,26 @@ abstract class Instance # else aborts fun to_b: Byte do abort + # Return the integer value if the instance is a int8. + # else aborts + fun to_i8: Int8 do abort + + # Return the integer value if the instance is a int16. + # else aborts + fun to_i16: Int16 do abort + + # Return the integer value if the instance is a uint16. + # else aborts + fun to_u16: UInt16 do abort + + # Return the integer value if the instance is a int32. + # else aborts + fun to_i32: Int32 do abort + + # Return the integer value if the instance is a uint32. + # else aborts + fun to_u32: UInt32 do abort + # The real value encapsulated if the instance is primitive. # Else aborts. fun val: nullable Object do abort @@ -703,6 +768,16 @@ class PrimitiveInstance[E] redef fun to_f do return val.as(Float) redef fun to_b do return val.as(Byte) + + redef fun to_i8 do return val.as(Int8) + + redef fun to_i16 do return val.as(Int16) + + redef fun to_u16 do return val.as(UInt16) + + redef fun to_i32 do return val.as(Int32) + + redef fun to_u32 do return val.as(UInt32) end # Information about local variables in a running method @@ -907,6 +982,16 @@ redef class AMethPropdef return v.int_instance(recvval << args[1].to_i) else if pname == ">>" then return v.int_instance(recvval >> args[1].to_i) + else if pname == "to_i8" then + return v.int8_instance(recvval.to_i8) + else if pname == "to_i16" then + return v.int16_instance(recvval.to_i16) + else if pname == "to_u16" then + return v.uint16_instance(recvval.to_u16) + else if pname == "to_i32" then + return v.int32_instance(recvval.to_i32) + else if pname == "to_u32" then + return v.uint32_instance(recvval.to_u32) else if pname == "rand" then var res = recvval.rand return v.int_instance(res) @@ -945,6 +1030,16 @@ redef class AMethPropdef return v.byte_instance(recvval << args[1].to_i) else if pname == ">>" then return v.byte_instance(recvval >> args[1].to_i) + else if pname == "to_i8" then + return v.int8_instance(recvval.to_i8) + else if pname == "to_i16" then + return v.int16_instance(recvval.to_i16) + else if pname == "to_u16" then + return v.uint16_instance(recvval.to_u16) + else if pname == "to_i32" then + return v.int32_instance(recvval.to_i32) + else if pname == "to_u32" then + return v.uint32_instance(recvval.to_u32) else if pname == "byte_to_s_len" then return v.int_instance(recvval.to_s.length) end @@ -993,6 +1088,16 @@ redef class AMethPropdef return v.int_instance(recv.to_i) else if pname == "to_b" then return v.byte_instance(recv.to_b) + else if pname == "to_i8" then + return v.int8_instance(recv.to_i8) + else if pname == "to_i16" then + return v.int16_instance(recv.to_i16) + else if pname == "to_u16" then + return v.uint16_instance(recv.to_u16) + else if pname == "to_i32" then + return v.int32_instance(recv.to_i32) + else if pname == "to_u32" then + return v.uint32_instance(recv.to_u32) else if pname == "cos" then return v.float_instance(args[0].to_f.cos) else if pname == "sin" then @@ -1073,6 +1178,271 @@ redef class AMethPropdef recvval.copy_to(0, args[2].to_i, args[1].val.as(Array[Instance]), 0) return null end + else if cname == "Int8" then + var recvval = args[0].to_i8 + if pname == "unary -" then + return v.int8_instance(-recvval) + else if pname == "unary +" then + return args[0] + else if pname == "+" then + return v.int8_instance(recvval + args[1].to_i8) + else if pname == "-" then + return v.int8_instance(recvval - args[1].to_i8) + else if pname == "*" then + return v.int8_instance(recvval * args[1].to_i8) + else if pname == "%" then + return v.int8_instance(recvval % args[1].to_i8) + else if pname == "/" then + return v.int8_instance(recvval / args[1].to_i8) + else if pname == "<" then + return v.bool_instance(recvval < args[1].to_i8) + else if pname == ">" then + return v.bool_instance(recvval > args[1].to_i8) + else if pname == "<=" then + return v.bool_instance(recvval <= args[1].to_i8) + else if pname == ">=" then + return v.bool_instance(recvval >= args[1].to_i8) + else if pname == "<=>" then + return v.int_instance(recvval <=> args[1].to_i8) + else if pname == "to_f" then + return v.float_instance(recvval.to_f) + else if pname == "to_i" then + return v.int_instance(recvval.to_i) + else if pname == "to_b" then + return v.byte_instance(recvval.to_b) + else if pname == "to_i16" then + return v.int16_instance(recvval.to_i16) + else if pname == "to_u16" then + return v.uint16_instance(recvval.to_u16) + else if pname == "to_i32" then + return v.int32_instance(recvval.to_i32) + else if pname == "to_u32" then + return v.uint32_instance(recvval.to_u32) + else if pname == "<<" then + return v.int8_instance(recvval << (args[1].to_i)) + else if pname == ">>" then + return v.int8_instance(recvval >> (args[1].to_i)) + else if pname == "&" then + return v.int8_instance(recvval & args[1].to_i8) + else if pname == "|" then + return v.int8_instance(recvval | args[1].to_i8) + else if pname == "^" then + return v.int8_instance(recvval ^ args[1].to_i8) + else if pname == "unary ~" then + return v.int8_instance(~recvval) + end + else if cname == "Int16" then + var recvval = args[0].to_i16 + if pname == "unary -" then + return v.int16_instance(-recvval) + else if pname == "unary +" then + return args[0] + else if pname == "+" then + return v.int16_instance(recvval + args[1].to_i16) + else if pname == "-" then + return v.int16_instance(recvval - args[1].to_i16) + else if pname == "*" then + return v.int16_instance(recvval * args[1].to_i16) + else if pname == "%" then + return v.int16_instance(recvval % args[1].to_i16) + else if pname == "/" then + return v.int16_instance(recvval / args[1].to_i16) + else if pname == "<" then + return v.bool_instance(recvval < args[1].to_i16) + else if pname == ">" then + return v.bool_instance(recvval > args[1].to_i16) + else if pname == "<=" then + return v.bool_instance(recvval <= args[1].to_i16) + else if pname == ">=" then + return v.bool_instance(recvval >= args[1].to_i16) + else if pname == "<=>" then + return v.int_instance(recvval <=> args[1].to_i16) + else if pname == "to_f" then + return v.float_instance(recvval.to_f) + else if pname == "to_i" then + return v.int_instance(recvval.to_i) + else if pname == "to_b" then + return v.byte_instance(recvval.to_b) + else if pname == "to_i8" then + return v.int8_instance(recvval.to_i8) + else if pname == "to_u16" then + return v.uint16_instance(recvval.to_u16) + else if pname == "to_i32" then + return v.int32_instance(recvval.to_i32) + else if pname == "to_u32" then + return v.uint32_instance(recvval.to_u32) + else if pname == "<<" then + return v.int16_instance(recvval << (args[1].to_i)) + else if pname == ">>" then + return v.int16_instance(recvval >> (args[1].to_i)) + else if pname == "&" then + return v.int16_instance(recvval & args[1].to_i16) + else if pname == "|" then + return v.int16_instance(recvval | args[1].to_i16) + else if pname == "^" then + return v.int16_instance(recvval ^ args[1].to_i16) + else if pname == "unary ~" then + return v.int16_instance(~recvval) + end + else if cname == "UInt16" then + var recvval = args[0].to_u16 + if pname == "unary -" then + return v.uint16_instance(-recvval) + else if pname == "unary +" then + return args[0] + else if pname == "+" then + return v.uint16_instance(recvval + args[1].to_u16) + else if pname == "-" then + return v.uint16_instance(recvval - args[1].to_u16) + else if pname == "*" then + return v.uint16_instance(recvval * args[1].to_u16) + else if pname == "%" then + return v.uint16_instance(recvval % args[1].to_u16) + else if pname == "/" then + return v.uint16_instance(recvval / args[1].to_u16) + else if pname == "<" then + return v.bool_instance(recvval < args[1].to_u16) + else if pname == ">" then + return v.bool_instance(recvval > args[1].to_u16) + else if pname == "<=" then + return v.bool_instance(recvval <= args[1].to_u16) + else if pname == ">=" then + return v.bool_instance(recvval >= args[1].to_u16) + else if pname == "<=>" then + return v.int_instance(recvval <=> args[1].to_u16) + else if pname == "to_f" then + return v.float_instance(recvval.to_f) + else if pname == "to_i" then + return v.int_instance(recvval.to_i) + else if pname == "to_b" then + return v.byte_instance(recvval.to_b) + else if pname == "to_i8" then + return v.int8_instance(recvval.to_i8) + else if pname == "to_i16" then + return v.int16_instance(recvval.to_i16) + else if pname == "to_i32" then + return v.int32_instance(recvval.to_i32) + else if pname == "to_u32" then + return v.uint32_instance(recvval.to_u32) + else if pname == "<<" then + return v.uint16_instance(recvval << (args[1].to_i)) + else if pname == ">>" then + return v.uint16_instance(recvval >> (args[1].to_i)) + else if pname == "&" then + return v.uint16_instance(recvval & args[1].to_u16) + else if pname == "|" then + return v.uint16_instance(recvval | args[1].to_u16) + else if pname == "^" then + return v.uint16_instance(recvval ^ args[1].to_u16) + else if pname == "unary ~" then + return v.uint16_instance(~recvval) + end + else if cname == "Int32" then + var recvval = args[0].to_i32 + if pname == "unary -" then + return v.int32_instance(-recvval) + else if pname == "unary +" then + return args[0] + else if pname == "+" then + return v.int32_instance(recvval + args[1].to_i32) + else if pname == "-" then + return v.int32_instance(recvval - args[1].to_i32) + else if pname == "*" then + return v.int32_instance(recvval * args[1].to_i32) + else if pname == "%" then + return v.int32_instance(recvval % args[1].to_i32) + else if pname == "/" then + return v.int32_instance(recvval / args[1].to_i32) + else if pname == "<" then + return v.bool_instance(recvval < args[1].to_i32) + else if pname == ">" then + return v.bool_instance(recvval > args[1].to_i32) + else if pname == "<=" then + return v.bool_instance(recvval <= args[1].to_i32) + else if pname == ">=" then + return v.bool_instance(recvval >= args[1].to_i32) + else if pname == "<=>" then + return v.int_instance(recvval <=> args[1].to_i32) + else if pname == "to_f" then + return v.float_instance(recvval.to_f) + else if pname == "to_i" then + return v.int_instance(recvval.to_i) + else if pname == "to_b" then + return v.byte_instance(recvval.to_b) + else if pname == "to_i8" then + return v.int8_instance(recvval.to_i8) + else if pname == "to_i16" then + return v.int16_instance(recvval.to_i16) + else if pname == "to_u16" then + return v.uint16_instance(recvval.to_u16) + else if pname == "to_u32" then + return v.uint32_instance(recvval.to_u32) + else if pname == "<<" then + return v.int32_instance(recvval << (args[1].to_i)) + else if pname == ">>" then + return v.int32_instance(recvval >> (args[1].to_i)) + else if pname == "&" then + return v.int32_instance(recvval & args[1].to_i32) + else if pname == "|" then + return v.int32_instance(recvval | args[1].to_i32) + else if pname == "^" then + return v.int32_instance(recvval ^ args[1].to_i32) + else if pname == "unary ~" then + return v.int32_instance(~recvval) + end + else if cname == "UInt32" then + var recvval = args[0].to_u32 + if pname == "unary -" then + return v.uint32_instance(-recvval) + else if pname == "unary +" then + return args[0] + else if pname == "+" then + return v.uint32_instance(recvval + args[1].to_u32) + else if pname == "-" then + return v.uint32_instance(recvval - args[1].to_u32) + else if pname == "*" then + return v.uint32_instance(recvval * args[1].to_u32) + else if pname == "%" then + return v.uint32_instance(recvval % args[1].to_u32) + else if pname == "/" then + return v.uint32_instance(recvval / args[1].to_u32) + else if pname == "<" then + return v.bool_instance(recvval < args[1].to_u32) + else if pname == ">" then + return v.bool_instance(recvval > args[1].to_u32) + else if pname == "<=" then + return v.bool_instance(recvval <= args[1].to_u32) + else if pname == ">=" then + return v.bool_instance(recvval >= args[1].to_u32) + else if pname == "<=>" then + return v.int_instance(recvval <=> args[1].to_u32) + else if pname == "to_f" then + return v.float_instance(recvval.to_f) + else if pname == "to_i" then + return v.int_instance(recvval.to_i) + else if pname == "to_b" then + return v.byte_instance(recvval.to_b) + else if pname == "to_i8" then + return v.int8_instance(recvval.to_i8) + else if pname == "to_i16" then + return v.int16_instance(recvval.to_i16) + else if pname == "to_u16" then + return v.uint16_instance(recvval.to_u16) + else if pname == "to_i32" then + return v.int32_instance(recvval.to_i32) + else if pname == "<<" then + return v.uint32_instance(recvval << (args[1].to_i)) + else if pname == ">>" then + return v.uint32_instance(recvval >> (args[1].to_i)) + else if pname == "&" then + return v.uint32_instance(recvval & args[1].to_u32) + else if pname == "|" then + return v.uint32_instance(recvval | args[1].to_u32) + else if pname == "^" then + return v.uint32_instance(recvval ^ args[1].to_u32) + else if pname == "unary ~" then + return v.uint32_instance(~recvval) + end else if pname == "native_argc" then return v.int_instance(v.arguments.length) else if pname == "native_argv" then @@ -1512,6 +1882,11 @@ redef class AIntegerExpr do if value isa Int then return v.int_instance(value.as(Int)) if value isa Byte then return v.byte_instance(value.as(Byte)) + if value isa Int8 then return v.int8_instance(value.as(Int8)) + if value isa Int16 then return v.int16_instance(value.as(Int16)) + if value isa UInt16 then return v.uint16_instance(value.as(UInt16)) + if value isa Int32 then return v.int32_instance(value.as(Int32)) + if value isa UInt32 then return v.uint32_instance(value.as(UInt32)) return null end end diff --git a/src/loader.nit b/src/loader.nit index 4e0e2e8..7d1c564 100644 --- a/src/loader.nit +++ b/src/loader.nit @@ -96,7 +96,7 @@ redef class ModelBuilder fun parse_group(mgroup: MGroup): Array[MModule] do var res = new Array[MModule] - visit_group(mgroup) + scan_group(mgroup) for mg in mgroup.in_nesting.smallers do for mp in mg.module_paths do var nmodule = self.load_module(mp.filepath) @@ -344,16 +344,24 @@ redef class ModelBuilder # See `identify_file`. var identified_files = new Array[ModulePath] - # Identify a source file - # Load the associated project and groups if required + # Identify a source file and load the associated project and groups if required. # - # Silently return `null` if `path` is not a valid module path. + # This method does what the user expects when giving an argument to a Nit tool. + # + # * If `path` is an existing Nit source file (with the `.nit` extension), + # then the associated ModulePath is returned + # * If `path` is a directory (with a `/`), + # then the ModulePath of its default module is returned (if any) + # * If `path` is a simple identifier (eg. `digraph`), + # then the main module of the project `digraph` is searched in `paths` and returned. + # + # Silently return `null` if `path` does not exists or cannot be identified. fun identify_file(path: String): nullable ModulePath do # special case for not a nit file if path.file_extension != "nit" then # search dirless files in known -I paths - if path.dirname == "." then + if not path.chars.has('/') then var res = search_module_in_paths(null, path, self.paths) if res != null then return res end @@ -374,6 +382,11 @@ redef class ModelBuilder path = candidate end + # Does the file exists? + if not path.file_exists then + return null + end + # Fast track, the path is already known var pn = path.basename(".nit") var rp = module_absolute_path(path) @@ -505,13 +518,24 @@ redef class ModelBuilder return mdoc end - # Force the identification of all ModulePath of the group and sub-groups. - fun visit_group(mgroup: MGroup) do + # Force the identification of all ModulePath of the group and sub-groups in the file system. + # + # When a group is scanned, its sub-groups hierarchy is filled (see `MGroup::in_nesting`) + # and the potential modules (and nested modules) are identified (see `MGroup::module_paths`). + # + # Basically, this recursively call `get_mgroup` and `identify_file` on each directory entry. + # + # No-op if the group was already scanned (see `MGroup::scanned`). + fun scan_group(mgroup: MGroup) do + if mgroup.scanned then return + mgroup.scanned = true var p = mgroup.filepath + # a virtual group has nothing to scan + if p == null then return for f in p.files do var fp = p/f var g = get_mgroup(fp) - if g != null then visit_group(g) + if g != null then scan_group(g) identify_file(fp) end end @@ -958,9 +982,17 @@ redef class MGroup # * it has a documentation fun is_interesting: Bool do - return module_paths.length > 1 or mmodules.length > 1 or not in_nesting.direct_smallers.is_empty or mdoc != null + return module_paths.length > 1 or + mmodules.length > 1 or + not in_nesting.direct_smallers.is_empty or + mdoc != null or + (mmodules.length == 1 and default_mmodule == null) end + # Are files and directories in self scanned? + # + # See `ModelBuilder::scan_group`. + var scanned = false end redef class SourceFile diff --git a/src/model/model.nit b/src/model/model.nit index 70c635e..7812cb2 100644 --- a/src/model/model.nit +++ b/src/model/model.nit @@ -209,6 +209,21 @@ redef class MModule # The primitive type `Byte` var byte_type: MClassType = self.get_primitive_class("Byte").mclass_type is lazy + # The primitive type `Int8` + var int8_type: MClassType = self.get_primitive_class("Int8").mclass_type is lazy + + # The primitive type `Int16` + var int16_type: MClassType = self.get_primitive_class("Int16").mclass_type is lazy + + # The primitive type `UInt16` + var uint16_type: MClassType = self.get_primitive_class("UInt16").mclass_type is lazy + + # The primitive type `Int32` + var int32_type: MClassType = self.get_primitive_class("Int32").mclass_type is lazy + + # The primitive type `UInt32` + var uint32_type: MClassType = self.get_primitive_class("UInt32").mclass_type is lazy + # The primitive type `Char` var char_type: MClassType = self.get_primitive_class("Char").mclass_type is lazy diff --git a/src/modelize/modelize_property.nit b/src/modelize/modelize_property.nit index af3ae39..97312f2 100644 --- a/src/modelize/modelize_property.nit +++ b/src/modelize/modelize_property.nit @@ -1341,6 +1341,16 @@ redef class AAttrPropdef cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Int") else if nexpr.value isa Byte then cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Byte") + else if nexpr.value isa Int8 then + cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Int8") + else if nexpr.value isa Int16 then + cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Int16") + else if nexpr.value isa UInt16 then + cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "UInt16") + else if nexpr.value isa Int32 then + cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Int32") + else if nexpr.value isa UInt32 then + cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "UInt32") else # Should not happen, and should be updated as new types are added abort diff --git a/src/nitls.nit b/src/nitls.nit index 8755bfe..7bbe3aa 100644 --- a/src/nitls.nit +++ b/src/nitls.nit @@ -175,7 +175,7 @@ for a in files do var g = mb.get_mgroup(a) var mp = mb.identify_file(a) if g != null and not opt_project.value then - mb.visit_group(g) + mb.scan_group(g) end if g == null and mp == null then # not a group not a module, then look at files in the directory @@ -183,7 +183,7 @@ for a in files do for f in fs do g = mb.get_mgroup(a/f) if g != null and not opt_project.value then - mb.visit_group(g) + mb.scan_group(g) end mp = mb.identify_file(a/f) #print "{a/f}: {mp or else "?"}" diff --git a/src/nitni/nitni_base.nit b/src/nitni/nitni_base.nit index a64c3df..a43e1d7 100644 --- a/src/nitni/nitni_base.nit +++ b/src/nitni/nitni_base.nit @@ -94,6 +94,11 @@ redef class MClassType if name == "Float" then return "double" if name == "Int" then return "long" if name == "Byte" then return "unsigned char" + if name == "Int8" then return "int8_t" + if name == "Int16" then return "int16_t" + if name == "UInt16" then return "uint16_t" + if name == "Int32" then return "int32_t" + if name == "UInt32" then return "uint32_t" if name == "NativeString" then return "char*" if mclass.kind == extern_kind then var ctype = mclass.ctype @@ -110,6 +115,11 @@ redef class MClassType if name == "Float" then return "double" if name == "Int" then return "long" if name == "Byte" then return "unsigned char" + if name == "Int8" then return "int8_t" + if name == "Int16" then return "int16_t" + if name == "UInt16" then return "uint16_t" + if name == "Int32" then return "int32_t" + if name == "UInt32" then return "uint32_t" if name == "NativeString" then return "char*" if mclass.kind == extern_kind then return "void*" return super @@ -121,7 +131,8 @@ redef class MClassType redef fun mangled_cname do return mclass.name redef fun is_cprimitive do return mclass.kind == extern_kind or - (once ["Bool", "Char", "Float", "Int", "NativeString", "Byte"]).has(mclass.name) + (once ["Bool", "Char", "Float", "Int", "NativeString", + "Byte", "Int8", "Int16", "UInt16", "Int32", "UInt32"]).has(mclass.name) end redef class MNullableType diff --git a/src/nitserial.nit b/src/nitserial.nit index 2a416ef..fcaf8fb 100644 --- a/src/nitserial.nit +++ b/src/nitserial.nit @@ -160,7 +160,7 @@ for mmodule in mmodules do var importations = null var mgroup = mmodule.mgroup if toolcontext.opt_depth.value == 1 and mgroup != null then - modelbuilder.visit_group mgroup + modelbuilder.scan_group mgroup target_modules = mgroup.mmodules else if toolcontext.opt_depth.value == 2 then # project diff --git a/src/rapid_type_analysis.nit b/src/rapid_type_analysis.nit index 87e808c..9ef5320 100644 --- a/src/rapid_type_analysis.nit +++ b/src/rapid_type_analysis.nit @@ -213,11 +213,16 @@ class RapidTypeAnalysis # Force primitive types force_alive("Bool") - force_alive("Int") force_alive("Float") force_alive("Char") force_alive("Pointer") force_alive("Byte") + force_alive("Int") + force_alive("Int8") + force_alive("Int16") + force_alive("UInt16") + force_alive("Int32") + force_alive("UInt32") while not todo.is_empty do var mmethoddef = todo.shift diff --git a/src/semantize/typing.nit b/src/semantize/typing.nit index b5f5d0c..935e1fc 100644 --- a/src/semantize/typing.nit +++ b/src/semantize/typing.nit @@ -1389,6 +1389,16 @@ redef class AIntegerExpr mclass = v.get_mclass(self, "Byte") else if value isa Int then mclass = v.get_mclass(self, "Int") + else if value isa Int8 then + mclass = v.get_mclass(self, "Int8") + else if value isa Int16 then + mclass = v.get_mclass(self, "Int16") + else if value isa UInt16 then + mclass = v.get_mclass(self, "UInt16") + else if value isa Int32 then + mclass = v.get_mclass(self, "Int32") + else if value isa UInt32 then + mclass = v.get_mclass(self, "UInt32") end if mclass == null then return # Forward error self.mtype = mclass.mclass_type diff --git a/tests/UTF-8-test.txt b/tests/UTF-8-test.txt new file mode 100644 index 0000000..abd16f7 Binary files /dev/null and b/tests/UTF-8-test.txt differ diff --git a/tests/sav/Darwin/todo b/tests/sav/Darwin/todo index afb008a..c3eac84 100644 --- a/tests/sav/Darwin/todo +++ b/tests/sav/Darwin/todo @@ -2,4 +2,3 @@ fatal error: 'endian.h' file not found Error: package `glesv1_cm` unknown by `pkg-config`, make sure the development package is be installed Error: package `glesv2` unknown by `pkg-config`, make sure the development package is be installed fatal error: 'libintl.h' file not found -ld: unknown option: -soname diff --git a/tests/sav/moles_linux.res b/tests/sav/moles_linux.res deleted file mode 100644 index c1dad34..0000000 --- a/tests/sav/moles_linux.res +++ /dev/null @@ -1,2 +0,0 @@ -../lib/mnit_linux/linux_app.nit:29,16--31: Redef Error: a virtual type cannot be refined. -../lib/mnit_linux/linux_app.nit:30,16--29: Redef Error: a virtual type cannot be refined. diff --git a/tests/sav/niti/moles_android.res b/tests/sav/niti/moles_android.res deleted file mode 100644 index 123fbb3..0000000 --- a/tests/sav/niti/moles_android.res +++ /dev/null @@ -1 +0,0 @@ -../lib/android/platform.nit:18,20--37: Error: target platform `android` unknown. diff --git a/tests/sav/nitpick_args1.res b/tests/sav/nitpick_args1.res index f9e2cbb..84ff5ce 100644 --- a/tests/sav/nitpick_args1.res +++ b/tests/sav/nitpick_args1.res @@ -1,4 +1,3 @@ -../lib/standard/stream.nit:451,6--17: Documentation warning: Undocumented property `buffer_reset` test_advice_repeated_types.nit:36,15--20: Warning: useless type repetition on redefined attribute `_a` test_advice_repeated_types.nit:37,18--20: Warning: useless type repetition on parameter `b1` for redefined method `b` test_advice_repeated_types.nit:38,18--20: Warning: useless type repetition on parameter `c1` for redefined method `c` diff --git a/tests/sav/test_fix_int.res b/tests/sav/test_fix_int.res new file mode 100644 index 0000000..e35445d --- /dev/null +++ b/tests/sav/test_fix_int.res @@ -0,0 +1,84 @@ + +-128 +-128 +0x80 +127 +127 +0x7f +127 +127 +127 +127 + + +-32768 +-32768 +0x00 +32767 +32767 +0xff +-1 +32767 +32767 +32767 + + +0 +0 +0x00 +65535 +65535 +0xff +-1 +-1 +65535 +65535 + + +-2147483648 +-2147483648 +0x00 +2147483647 +2147483647 +0xff +-1 +-1 +65535 +2147483647 + + +0 +0 +0x00 +4294967295 +4294967295 +0xff +-1 +-1 +65535 +-1 + + +0x00 +0 +0x00 +0xff +255 +0xff +-1 +255 +255 +255 + + +256 +256 +0x00 +255 +255 +0xff +-1 +255 +255 +255 + diff --git a/tests/sav/test_glsl_validation.res b/tests/sav/test_glsl_validation.res index 7cb202c..ebd24c8 100644 --- a/tests/sav/test_glsl_validation.res +++ b/tests/sav/test_glsl_validation.res @@ -1,6 +1,4 @@ test_glsl_validation.nit:24,0: Shader error on 'binding' : not supported for this version or the enabled extensions test_glsl_validation.nit:24,0: Shader error on 'binding' : requires uniform or buffer storage qualifier test_glsl_validation.nit:24,0: Shader error on 'binding' : requires block, or sampler/image, or atomic-counter type -test_glsl_validation.nit:28,0: Shader error on 'gl_FragColor' : undeclared identifier -test_glsl_validation.nit:28,0: Shader error on 'assign' : cannot convert from 'mediump 4-component vector of float' to 'float' test_glsl_validation.nit:29,0: Shader error on 'b' : undeclared identifier diff --git a/tests/sav/test_read_all.res b/tests/sav/test_read_all.res new file mode 100644 index 0000000..2f4cc2a --- /dev/null +++ b/tests/sav/test_read_all.res @@ -0,0 +1 @@ +usage ./test_read_all file diff --git a/tests/sav/test_read_all_args1.res b/tests/sav/test_read_all_args1.res new file mode 100644 index 0000000..6228c6e Binary files /dev/null and b/tests/sav/test_read_all_args1.res differ diff --git a/tests/sav/test_string_bytes.res b/tests/sav/test_string_bytes.res index 8d98756..2984735 100644 --- a/tests/sav/test_string_bytes.res +++ b/tests/sav/test_string_bytes.res @@ -4,9 +4,7 @@ [0x6c,0x6f,0x6f,0x63,0x20,0x73,0x69,0x20,0x67,0x6e,0x69,0x72,0x74,0x73,0x20,0x73,0x69,0x68,0x54] [0x6c,0x6f,0x6f,0x63,0x20,0x73,0x69,0x20,0x67,0x6e,0x69,0x72,0x74,0x73,0x20,0x73,0x69,0x68,0x54,0x6c,0x6f,0x6f,0x63,0x20,0x73,0x69,0x20,0x67,0x6e,0x69,0x72,0x74,0x73,0x20,0x73,0x69,0x68,0x54,0x6c,0x6f,0x6f,0x63,0x20,0x73,0x69,0x20,0x67,0x6e,0x69,0x72,0x74,0x73,0x20,0x73,0x69,0x68,0x54,0x6c,0x6f,0x6f,0x63,0x20,0x73,0x69,0x20,0x67,0x6e,0x69,0x72,0x74,0x73,0x20,0x73,0x69,0x68,0x54] [0x6c,0x6f,0x6f,0x63,0x20,0x73,0x69,0x20,0x67,0x6e,0x69,0x72,0x74,0x73,0x20,0x73,0x69,0x68,0x54,0x6c,0x6f,0x6f,0x63,0x20,0x73,0x69,0x20,0x67,0x6e,0x69,0x72,0x74,0x73,0x20,0x73,0x69,0x68,0x54,0x6c,0x6f,0x6f,0x63,0x20,0x73,0x69,0x20,0x67,0x6e,0x69,0x72,0x74,0x73,0x20,0x73,0x69,0x68,0x54,0x6c,0x6f,0x6f,0x63,0x20,0x73,0x69,0x20,0x67,0x6e,0x69,0x72,0x74,0x73,0x20,0x73,0x69,0x68,0x54] -This string is cool -This string is coolA -Ahis string is coolA -This string is cool -This string is coolA -Ahis string is coolA +[0x54,0x68,0x69,0x73,0x20,0x73,0x74,0x72,0x69,0x6e,0x67,0x20,0x69,0x73,0x20,0x63,0x6f,0x6f,0x6c] +[0x6c,0x6f,0x6f,0x63,0x20,0x73,0x69,0x20,0x67,0x6e,0x69,0x72,0x74,0x73,0x20,0x73,0x69,0x68,0x54] +[0x54,0x68,0x69,0x73,0x20,0x73,0x74,0x72,0x69,0x6e,0x67,0x20,0x69,0x73,0x20,0x63,0x6f,0x6f,0x6c] +[0x6c,0x6f,0x6f,0x63,0x20,0x73,0x69,0x20,0x67,0x6e,0x69,0x72,0x74,0x73,0x20,0x73,0x69,0x68,0x54] diff --git a/tests/test_fix_int.nit b/tests/test_fix_int.nit new file mode 100644 index 0000000..f7ecfa7 --- /dev/null +++ b/tests/test_fix_int.nit @@ -0,0 +1,79 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# This file is free software, which comes along with NIT. This software is +# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. You can modify it is you want, provided this header +# is kept unaltered, and a notification of the changes is added. +# You are allowed to redistribute it and sell it, alone or is a part of +# another product. + +# Tests for the fixed-length integers variant of standard +module test_fix_int + +private fun test_int(i, j, l: Numeric) do + print "" + var k = i + j + + print k + print k.to_i + print k.to_b + + k = l + j + + print k + print k.to_i + print k.to_b + + print k.to_i8 + print k.to_i16 + print k.to_u16 + print k.to_i32 + print "" +end + +var i: Numeric +var j: Numeric +var l: Numeric + +j = 126i8 +i = 2i8 +l = 1i8 + +test_int(i, j, l) + +j = 32766i16 +i = 2i16 +l = 1i16 + +test_int(i, j, l) + +j = 65534u16 +i = 2u16 +l = 1u16 + +test_int(i, j, l) + +j = 2147483646i32 +i = 2i32 +l = 1i32 + +test_int(i, j, l) + +j = 4294967294u32 +i = 2u32 +l = 1u32 + +test_int(i, j, l) + +j = 254u8 +i = 2u8 +l = 1u8 + +test_int(i, j, l) + +j = 254 +i = 2 +l = 1 + +test_int(i, j, l) diff --git a/tests/test_glsl_validation.nit b/tests/test_glsl_validation.nit index 950ef7b..147b67a 100644 --- a/tests/test_glsl_validation.nit +++ b/tests/test_glsl_validation.nit @@ -25,7 +25,7 @@ layout(binding = 0) out vec4 outColor; void main() { - gl_FragColor = v_color * texture(vTex, v_texCoord); + outColor = v_color * texture(vTex, v_texCoord); b; } """ @ glsl_fragment_shader diff --git a/tests/test_read_all.args b/tests/test_read_all.args new file mode 100644 index 0000000..e497886 --- /dev/null +++ b/tests/test_read_all.args @@ -0,0 +1 @@ +UTF-8-test.txt diff --git a/tests/test_read_all.nit b/tests/test_read_all.nit new file mode 100644 index 0000000..4f2d7e0 --- /dev/null +++ b/tests/test_read_all.nit @@ -0,0 +1,26 @@ +# 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. + +if args.is_empty then + print "usage ./test_read_all file" + exit -1 +end + +var file = new FileReader.open(args[0]) + +var s = file.read_all + +for i in s do + printn i +end diff --git a/tests/test_string_bytes.nit b/tests/test_string_bytes.nit index 875f5dc..13048d8 100644 --- a/tests/test_string_bytes.nit +++ b/tests/test_string_bytes.nit @@ -28,24 +28,10 @@ print z.bytes.reverse_iterator.to_a var b = new FlatBuffer.from(x) -print b - -b.bytes.add 0x41u8 - -print b - -b.bytes[0] = 0x41u8 - -print b +print b.bytes.to_a +print b.bytes.reverse_iterator.to_a var c = new RopeBuffer.from(x) -print c - -c.bytes.add 0x41u8 - -print c - -c.bytes[0] = 0x41u8 - -print c +print c.bytes +print c.bytes.reverse_iterator.to_a