Merge: Enforce namespace rules
authorJean Privat <jean@pryen.org>
Sat, 10 Jan 2015 02:31:30 +0000 (21:31 -0500)
committerJean Privat <jean@pryen.org>
Sat, 10 Jan 2015 02:31:30 +0000 (21:31 -0500)
Enforce rules indicated in #1047.

So, having homonymous public modules and classes in a same project raises an error.
In the current code there was no conflicting modules. It is not surprising because for a long time the compilers refused homonymous modules even in different projects.
There was only 2 conflicting classes (on a total of 3640). This is more a good surprise since I expected a lot of conflicts. It is some kind of prof that the proposed policy is not that crazy. The two pairs of conflicting classes were `UnicodeChar` in `lib/string_experimentations/utf8.nit` and `lib/string_experimentations/utf8_noindex.nit`, and `Frame` in `naive_interpreter` and `abstract_compiler`. Some commits in the PR rename one of each pair to solve the conflicts.

For public properties, the proposed rule is to have a unique full-name "project::class::name".
There was 11 conflicts, again, it is far less than I expected.
Two of these conflict are resolved in some commits.
The other 9 are currently left as is (and the displayed error is in fact a warning).
All these remaining conflicts are a variation of the same pattern: homonymous options in refinements of ToolContext for different tools. Eg `opt_rta` for `nitmetrics` and for `nitc`.
I am not sure what is the correct way to solve these since the conflict is not only in the name but also in the behavior (a refinement of those two modules will have a broken option parsing). Maybe, behind the name conflict, there is also a bad model that misuses class refinement.

Pull-Request: #1069
Reviewed-by: Alexis Laferrière <alexis.laf@xymus.net>
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>

71 files changed:
VERSION
clib/gc_chooser.h
contrib/friendz/.gitignore [new file with mode: 0644]
contrib/friendz/Makefile
contrib/friendz/README.md
contrib/friendz/art/icon.svg [new file with mode: 0644]
contrib/friendz/src/friendz.nit
contrib/friendz/src/friendz_android.nit
contrib/friendz/src/level.nit
contrib/jwrapper/Makefile
contrib/jwrapper/README.md
contrib/jwrapper/grammar/javap.sablecc
contrib/jwrapper/src/code_generator.nit
contrib/jwrapper/src/javap_visitor.nit
contrib/jwrapper/src/jtype_converter.nit
contrib/jwrapper/src/model.nit [moved from contrib/jwrapper/src/types.nit with 78% similarity]
examples/mnit_ballz/src/ballz_android.nit
examples/mnit_dino/src/dino_android.nit
examples/mnit_moles/src/moles_android.nit
examples/mnit_simple/src/simple_android.nit
lib/android/cardboard.nit [new file with mode: 0644]
lib/android/input_events.nit [new file with mode: 0644]
lib/android/landscape.nit [new file with mode: 0644]
lib/android/portrait.nit [new file with mode: 0644]
lib/glesv2/examples/opengles2_hello_triangle.nit
lib/glesv2/glesv2.nit
lib/gtk/v3_4/gtk_core.nit
lib/gtk/v3_4/gtk_dialogs.nit
lib/java/collections.nit [new file with mode: 0644]
lib/mnit/opengles1.nit
lib/mnit_android/android_app.nit
lib/standard/collection/array.nit
lib/standard/exec_nit.c
src/annotation.nit
src/compiler/abstract_compiler.nit
src/compiler/android_platform.nit
src/compiler/compiler_ffi.nit
src/compiler/global_compiler.nit
src/compiler/separate_compiler.nit
src/compiler/separate_erasure_compiler.nit
src/doc/doc_pages.nit
src/ffi/header_dependency.nit
src/ffi/java.nit
src/frontend/no_warning.nit
src/interpreter/naive_interpreter.nit
src/loader.nit
src/modelbuilder.nit
src/modelize/modelize_class.nit
src/modelize/modelize_property.nit
src/nitdoc.nit
src/nitlight.nit
src/nitmetrics.nit
src/nitpick.nit
src/nitpretty.nit
src/nitserial.nit
src/nituml.nit
src/nitunit.nit
src/phase.nit
src/rapid_type_analysis.nit
src/semantize/typing.nit
src/testing/testing_doc.nit
tests/base_array.nit
tests/base_null.nit [new file with mode: 0644]
tests/bench_add_all.nit [new file with mode: 0644]
tests/sav/base_array_alt2.res [new file with mode: 0644]
tests/sav/base_null.res [new file with mode: 0644]
tests/sav/bench_add_all.res [new file with mode: 0644]
tests/sav/error_annot_c_compiler_alt5.res
tests/sav/test_exec.res
tests/sav/test_new_native_alt1.res
tests/test_exec.nit

diff --git a/VERSION b/VERSION
index 882307c..03776fb 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-v0.6.11
+v0.7
index fa395b0..255e07a 100644 (file)
@@ -20,7 +20,7 @@ void *nit_raw_alloc(size_t); /* allocate raw memory to store a raw stram of byte
 void nit_gcollect(void); /* force a garbage collection */
 void initialize_gc_option(void); /* Select the wanted GC using envvar `NIT_GC_OPTION` */
 
-void gc_set_finializer(void*); /* Tag a pointer for finalization */
+void gc_register_finalizer(void*); /* Tag a pointer for finalization */
 void gc_finalize(void*, void*); /* Finalize a pointer, implemented in the generated code. */
 
 #endif
diff --git a/contrib/friendz/.gitignore b/contrib/friendz/.gitignore
new file mode 100644 (file)
index 0000000..700b511
--- /dev/null
@@ -0,0 +1 @@
+res/
index 0039fff..f236a1d 100644 (file)
@@ -5,7 +5,8 @@ linux:
        ../../bin/nitc -o bin/friendz src/friendz_linux.nit
 
 android:
-       mkdir -p bin
+       mkdir -p bin res
+       ../inkscape_tools/bin/svg_to_icons art/icon.svg --android --out res/
        ../../bin/nitc -o bin/friendz.apk src/friendz_android.nit
 
 doc:
@@ -13,4 +14,4 @@ doc:
        ../../bin/nitdoc -d doc/ src/friendz.nit src/friendz_linux.nit
 
 clean:
-       rm -rf bin/ doc/
+       rm -rf bin/ doc/ res/
index bd5f5e5..48be94e 100644 (file)
@@ -33,3 +33,8 @@ In challenge level you have to place as much as monster as possible.
 
 This game was originally developed for the [Casual Gameplay Design Competition
 \#9](http://jayisgames.com/cgdc9).
+
+# Artwork
+
+The artwork was created by Sam Hocevar <sam@zoy.org> for the Monsterz arcade
+puzzle game http://sam.zoy.org/monsterz/
diff --git a/contrib/friendz/art/icon.svg b/contrib/friendz/art/icon.svg
new file mode 100644 (file)
index 0000000..3584b06
--- /dev/null
@@ -0,0 +1,327 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="256"
+   height="256"
+   id="svg4386"
+   version="1.1"
+   inkscape:version="0.48.5 r10040"
+   sodipodi:docname="icon.svg">
+  <defs
+     id="defs4388">
+    <radialGradient
+       r="7.7875042"
+       fy="141.32838"
+       fx="106.50102"
+       cy="141.3284"
+       cx="106.50099"
+       gradientTransform="scale(1.02976,0.9711)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient8339"
+       xlink:href="#linearGradient5606"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient5606">
+      <stop
+         id="stop5608"
+         offset="0.0000000"
+         style="stop-color:#000000;stop-opacity:1.0000000;" />
+      <stop
+         id="stop5614"
+         offset="0.20000000"
+         style="stop-color:#000000;stop-opacity:1.0000000;" />
+      <stop
+         id="stop5616"
+         offset="0.30000001"
+         style="stop-color:#ffffff;stop-opacity:1.0000000;" />
+      <stop
+         id="stop5610"
+         offset="1.0000000"
+         style="stop-color:#ffffff;stop-opacity:1.0000000;" />
+    </linearGradient>
+    <filter
+       inkscape:label="Desaturate"
+       x="0"
+       y="0"
+       width="1"
+       height="1"
+       inkscape:menu="Color"
+       inkscape:menu-tooltip="Render in shades of gray by reducing saturation to zero"
+       color-interpolation-filters="sRGB"
+       id="filter3078">
+      <feColorMatrix
+         type="saturate"
+         values="0"
+         id="feColorMatrix3080" />
+    </filter>
+    <filter
+       inkscape:label="Desaturate"
+       x="0"
+       y="0"
+       width="1"
+       height="1"
+       inkscape:menu="Color"
+       inkscape:menu-tooltip="Render in shades of gray by reducing saturation to zero"
+       color-interpolation-filters="sRGB"
+       id="filter3082">
+      <feColorMatrix
+         type="saturate"
+         values="0"
+         id="feColorMatrix3084" />
+    </filter>
+    <filter
+       inkscape:label="Desaturate"
+       x="0"
+       y="0"
+       width="1"
+       height="1"
+       inkscape:menu="Color"
+       inkscape:menu-tooltip="Render in shades of gray by reducing saturation to zero"
+       color-interpolation-filters="sRGB"
+       id="filter3086">
+      <feColorMatrix
+         type="saturate"
+         values="0"
+         id="feColorMatrix3088" />
+    </filter>
+    <filter
+       inkscape:label="Desaturate"
+       x="0"
+       y="0"
+       width="1"
+       height="1"
+       inkscape:menu="Color"
+       inkscape:menu-tooltip="Render in shades of gray by reducing saturation to zero"
+       color-interpolation-filters="sRGB"
+       id="filter3090">
+      <feColorMatrix
+         type="saturate"
+         values="0.71980676328502413"
+         id="feColorMatrix3092" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.98994949"
+     inkscape:cx="76.110583"
+     inkscape:cy="101.8389"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1279"
+     inkscape:window-height="1377"
+     inkscape:window-x="1279"
+     inkscape:window-y="29"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata4391">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(0,-796.36218)">
+    <g
+       inkscape:export-ydpi="72.000000"
+       inkscape:export-xdpi="72.000000"
+       inkscape:export-filename="/home/sam/monsterz/monsterz/tiles.png"
+       transform="matrix(4.2708842,0,0,4.1991018,0.37397342,-2109.743)"
+       id="g8300"
+       style="filter:url(#filter3090)">
+      <g
+         style="stroke:none"
+         inkscape:export-ydpi="72.000000"
+         inkscape:export-xdpi="72.000000"
+         inkscape:export-filename="/home/sam/monsterz/monsterz/test.png"
+         transform="matrix(0.823543,0,0,0.832736,-337.8784,464.3823)"
+         id="g8288">
+        <path
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cc"
+           id="path8290"
+           d="M 427.22149,306.26985 C 400,308.61218 417.5,276.66759 427.5,286.11218"
+           style="fill:#01ff03;fill-opacity:1;fill-rule:evenodd" />
+        <path
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cc"
+           id="path8292"
+           d="m 467.5,283.61218 c 18.75,-6.25 17.5,28.75 -2.5,18.75"
+           style="fill:#01ff03;fill-opacity:1;fill-rule:evenodd" />
+        <path
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="ccc"
+           id="path8294"
+           d="M 428.58387,304.20437 C 406.97719,274.86218 485,259.86218 465,302.36218 c 53.75,37.5 -81.25,70 -36.41613,1.84219 z"
+           style="fill:#01ff03;fill-opacity:1;fill-rule:evenodd" />
+        <path
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cc"
+           id="path8296"
+           d="m 420,292.36218 c -1.95031,4.4858 0,6.25 1.25,7.5"
+           style="fill:none" />
+        <path
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cc"
+           id="path8298"
+           d="m 473.75,289.34798 c 0.60933,3.0142 1.25,4.2642 -1.25,7.44624"
+           style="fill:none" />
+      </g>
+      <path
+         inkscape:connector-curvature="0"
+         sodipodi:nodetypes="ccc"
+         id="path8275"
+         d="m 20,747.36218 c 23.207741,2.5 36.25,-13.75 31.25,-20 -1.25,10 -18.03209,20.56008 -31.25,20 z"
+         style="fill:#000000;fill-opacity:0.1372549;fill-rule:evenodd;stroke:none" />
+      <g
+         id="g8283">
+        <path
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="ccc"
+           id="path8277"
+           d="M 14.300999,703.00709 C 5.5600809,697.36218 -4.2738645,716.11218 7.5,718.61218 c -5,-5.67209 -2.5,-13.75 6.800999,-15.60509 z"
+           style="fill:#ffffff;fill-opacity:0.41176471;fill-rule:evenodd;stroke:none" />
+        <path
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="ccc"
+           id="path8279"
+           d="m 45,698.61218 c -13.75,-11.25 -42.5,-0.73064 -28.75,20 -3.75,-12.5 11.25,-25 28.75,-20 z"
+           style="fill:#ffffff;fill-opacity:0.41176471;fill-rule:evenodd;stroke:none" />
+        <path
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="ccc"
+           id="path8281"
+           d="m 57.5,708.61218 c 1.25,-9.4761 -12.5,-11.25 -10,-4.41905 5.560081,-1.83095 7.321465,0.72043 10,4.41905 z"
+           style="fill:#ffffff;fill-opacity:0.41176471;fill-rule:evenodd;stroke:none" />
+      </g>
+      <g
+         style="fill:none"
+         inkscape:export-ydpi="72.000000"
+         inkscape:export-xdpi="72.000000"
+         inkscape:export-filename="/home/sam/monsterz/monsterz/test.png"
+         transform="matrix(0.823543,0,0,0.832736,-337.8784,464.3823)"
+         id="g7882">
+        <path
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cc"
+           id="path7659"
+           d="M 427.22149,306.26985 C 400,308.61218 417.5,276.66759 427.5,286.11218"
+           style="stroke:#000000;stroke-width:3.11108565;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" />
+        <path
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cc"
+           id="path7661"
+           d="m 467.5,283.61218 c 18.75,-6.25 17.5,28.75 -2.5,18.75"
+           style="stroke:#000000;stroke-width:3.11108565;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" />
+        <path
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="ccc"
+           id="path7657"
+           d="M 428.58387,304.20437 C 406.97719,274.86218 485,259.86218 465,302.36218 c 53.75,37.5 -81.25,70 -36.41613,1.84219 z"
+           style="stroke:#000000;stroke-width:3.11108565;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" />
+        <path
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cc"
+           id="path7663"
+           d="m 420,292.36218 c -1.95031,4.4858 0,6.25 1.25,7.5"
+           style="stroke:#000000;stroke-width:3.11108565;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" />
+        <path
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cc"
+           id="path7665"
+           d="m 473.75,289.34798 c 0.60933,3.0142 1.25,4.2642 -1.25,7.44624"
+           style="stroke:#000000;stroke-width:3.11108565;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" />
+      </g>
+    </g>
+    <g
+       inkscape:export-ydpi="72.000000"
+       inkscape:export-xdpi="72.000000"
+       inkscape:export-filename="/home/sam/monsterz/monsterz/tiles.png"
+       transform="matrix(4.3642738,0,0,-0.17844664,-531.2477,940.61654)"
+       id="g8323"
+       style="filter:url(#filter3090)">
+      <path
+         inkscape:connector-curvature="0"
+         sodipodi:nodetypes="cc"
+         id="path8325"
+         d="M 150.47232,132.96909 150,134.86218"
+         style="fill:none;stroke:#000000;stroke-width:12.36332512;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" />
+      <path
+         inkscape:connector-curvature="0"
+         sodipodi:nodetypes="cc"
+         id="path8327"
+         d="m 153.75,132.96909 0.47232,1.89309"
+         style="fill:none;stroke:#000000;stroke-width:12.36332512;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" />
+    </g>
+    <g
+       inkscape:export-ydpi="72.000000"
+       inkscape:export-xdpi="72.000000"
+       inkscape:export-filename="/home/sam/monsterz/monsterz/tiles.png"
+       transform="matrix(4.3642695,0,0,4.3642084,-733.54667,664.62487)"
+       id="g8329"
+       style="filter:url(#filter3090)">
+      <path
+         inkscape:connector-curvature="0"
+         inkscape:export-ydpi="72.000000"
+         inkscape:export-xdpi="72.000000"
+         inkscape:export-filename="/home/sam/monsterz/monsterz/test.png"
+         sodipodi:nodetypes="cc"
+         id="path8331"
+         d="m 191.8115,62.362183 c 2.83835,1.82034 7.56893,1.99609 11.3534,0"
+         style="fill:none;stroke:#ffffff;stroke-width:2.49998164;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.41176471" />
+      <path
+         inkscape:connector-curvature="0"
+         inkscape:export-ydpi="72.000000"
+         inkscape:export-xdpi="72.000000"
+         inkscape:export-filename="/home/sam/monsterz/monsterz/test.png"
+         sodipodi:nodetypes="cc"
+         id="path8333"
+         d="m 193.0615,64.152194 c 2.83835,1.82034 7.56893,1.99609 11.3534,0"
+         style="fill:none;stroke:#000000;stroke-width:2.49998164;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.1372549" />
+      <path
+         inkscape:connector-curvature="0"
+         inkscape:export-ydpi="72.000000"
+         inkscape:export-xdpi="72.000000"
+         inkscape:export-filename="/home/sam/monsterz/monsterz/test.png"
+         sodipodi:nodetypes="cc"
+         id="path8335"
+         d="m 192.5,63.430263 c 2.83835,1.82034 7.56893,1.99609 11.3534,0"
+         style="fill:none;stroke:#000000;stroke-width:2.49998164;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" />
+    </g>
+    <path
+       inkscape:export-ydpi="72.000000"
+       inkscape:export-xdpi="72.000000"
+       inkscape:export-filename="/home/sam/monsterz/monsterz/tiles.png"
+       transform="matrix(4.2024883,1.3865396,-2.0345896,3.8609453,-52.336063,179.80496)"
+       d="m 115.86819,137.36218 a 6.1977272,6.1227274 0 1 1 -12.39545,0 6.1977272,6.1227274 0 1 1 12.39545,0 z"
+       sodipodi:ry="6.1227274"
+       sodipodi:rx="6.1977272"
+       sodipodi:cy="137.36218"
+       sodipodi:cx="109.67046"
+       id="path8337"
+       style="fill:url(#radialGradient8339);fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.49998115999999992;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;filter:url(#filter3090)"
+       sodipodi:type="arc" />
+  </g>
+</svg>
index 13915e6..2dd8d80 100644 (file)
@@ -17,6 +17,8 @@ import mnit
 import realtime
 import solver
 import mnit::tileset
+import app::data_store
+import md5
 
 intrude import grid
 intrude import level
@@ -1080,8 +1082,8 @@ redef class Game
                level = null
                var i = levels.first
                for l in levels do
-                       if l.get_state == l.l_open then break
                        i = l
+                       if l.get_state == l.l_open then break
                end
                entities.push(new StartButton(self, i))
        end
@@ -1142,7 +1144,8 @@ redef class Game
                end
                var ev = lastev
                if ev isa Event then
-                       display.blit(img[4,0],ev.offset_x-42,ev.offset_y-6)
+                       # Cursor, kept for debugging
+                       #display.blit(img[4,0],ev.offset_x-42,ev.offset_y-6)
                end
                dirty_all = false
        end
@@ -1267,6 +1270,18 @@ redef class Game
                        end
                end
        end
+
+       redef fun load_levels
+       do
+               super
+
+               for level in levels do
+                       var score = app.data_store["s{level.str.md5}"]
+                       if score isa Int then
+                               level.score = score
+                       end
+               end
+       end
 end
 
 # The spash title image
@@ -1634,3 +1649,10 @@ redef class KeyEvent
                return "unknown"
        end
 end
+
+redef class Level
+       redef fun save
+       do
+               app.data_store["s{str.md5}"] = if score > 0 then score else null
+       end
+end
index 94b9d2b..13a139e 100644 (file)
@@ -12,16 +12,26 @@ module friendz_android
 
 import friendz
 import mnit_android
+import android::landscape
 
 redef class App
+       # Zoom applied for the device display from the game logic coordinates
+       var zoom = 1.0
+
        redef fun window_created
        do
                super
-               var w = screen_width
-               display.set_viewport(0,0,w,w*display.height/display.width)
+
+               var h = screen_height
+               display.set_viewport(0,0,h*display.width/display.height,h)
+
+               zoom = display.height.to_f / h.to_f
        end
 end
 
 redef class AndroidPointerEvent
-       redef fun is_motion do return not motion_event.just_went_down
+       redef fun is_motion do return not just_went_down
+
+       redef fun x do return super / app.zoom
+       redef fun y do return super / app.zoom
 end
index d459875..9d8029e 100644 (file)
@@ -96,10 +96,8 @@ class Level
                return true
        end
 
-       fun save
-       do
-               #save_cookie("s"+self.hash, self.score>0?self.score:"")
-       end
+       # Save the score of the level
+       fun save do end
 end
 
 # main game object
@@ -174,8 +172,6 @@ class Game
                for i in [0..levels_code.length[ do
                        var l = new Level(self,i, levels_code[i])
                        levels[i] = l
-                       #var v = read_cookie("s"+l.hash)
-                       #l = v
                end
        end
 
index b554f0d..0932498 100644 (file)
@@ -1,14 +1,22 @@
-default:
-       mkdir -p bin
+all: nitcc grammar bin/jwrapper
+
+nitcc:
        make -C ../nitcc
-       ../nitcc/src/nitcc ./grammar/javap.sablecc
-       ../../bin/nitc ./src/jwrapper.nit -o ./bin/jwrapper
-       mv *.nit ./src/
-       mkdir -p gen
-       mv javap* ./gen/
+
+grammar:
+       ../nitcc/src/nitcc grammar/javap.sablecc
+       mkdir -p src gen
+       mv *.nit src/
+       mv javap* gen/
+
+bin/jwrapper:
+       mkdir -p bin
+       ../../bin/nitc src/jwrapper.nit -o bin/jwrapper
 
 clean:
        rm -f bin/javap_test_parser bin/jwrapper
        rm -f gen/*
        rm -rf .nit_compile/
        rm src/javap_lexer.nit src/javap_parser.nit src/javap_test_parser.nit
+
+.PHONY: grammar bin/jwrapper
index 8cd3bf0..da33dd2 100644 (file)
@@ -1,20 +1,23 @@
-# JWRAPPER : Extern classes generator from java .class
-## Description
-jwrapper is a code generator that creates Nit extern classes `in "Java"` from .class files.
+_jwrapper_, an extern class generator from Java class files
 
-## Installation
-jwrapper is designed to be installed from the `contrib` directory of Nit repository. (http://www.nitlanguage.org)
+# Description
+_jwrapper_ automates wrapping Java classes so they can be accessed from Nit code. It generates Nit extern classes by analyzing Java class files.
+
+_jwrapper_ reuse Nit types of already wrapped Java classes by searching in the `lib/java` and `lib/android` folders in the Nit repository. It won't wrap a class that are already is those folders.
+
+# Installation
+_jwrapper_ is designed to be installed from the `contrib` directory of Nit repository. (http://www.nitlanguage.org)
 
 To initiate installation process, use `make` in the `contrib/jwrapper` directory.
 
-jwrapper relies on `nitcc` that will be automatically compiled from `contrib/nitcc`.
+_jwrapper_ relies on `nitcc` that will be automatically compiled from `contrib/nitcc`.
 
-## Usage
-The jwrapper binary can be found under `jwrapper/bin` directory.
+# Usage
+The _jwrapper_ binary can be found under `contrib/jwrapper/bin` directory.
 
-Since jwrapper uses `grep` to find existing libraries, make sure that the environment variable `NIT_DIR` is properly set to your Nit root directory.
+_jwrapper_ uses `grep` to find existing libraries, make sure that the environment variable `NIT_DIR` is properly set to your Nit root directory.
 
-Since jwrapper uses `javap` to extract data from .class files, the JDK7 or higher has to be installed and must be in your `$PATH`. (Older versions of `javap` do not show generic signatures)
+_jwrapper_ uses `javap` to extract data from .class files, the JDK7 or higher has to be installed and must be in your `$PATH`. (Older versions of `javap` do not show generic signatures)
 
 Usage :
 
@@ -28,7 +31,7 @@ The options are :
 
 `-c, --comment`
 
-* When a method contains at least one unknown type, the code generator will comment the whole method and let the client manage it.
+* When a method contains at least one unknown type, the code generator will comment the whole method and let the client manage it. Unknown types are types that doesn't have an equivalent in Nit as of yet.
 
 `-w, --wrap`
 
@@ -38,18 +41,4 @@ The options are :
 
 * Print the help message
 
-Unknown types are types that doesn't have an equivalent in Nit as of yet.
-
-Jwrapper won't wrap a class that already is in the `lib/android` directory.
-
 Can't use both -c and -w together, either you comment unknown types or you wrap them.
-
-## Limitations
-jwrapper support for java primitive array is limited to one parameter and the return value.
-
-If the method contains more than one primitive array parameter, the method will be commented with a `NOT SUPPORTED` notice.
-
-## TODO List
-* Generate static methods on top-level
-* Extend primitive array support
-* Enhance static overload support (currently, it suffixes the method name with a number)
index 4e9165a..87dfa12 100644 (file)
@@ -13,12 +13,12 @@ multi_files = class_or_interface*;
 
 class_or_interface = class_declaration | interface_declaration;
 
-class_declaration = class_header '{' field_declaration* '}';
+class_declaration = class_header '{' property_declaration* '}';
 
 class_header = modifier* 'class' full_class_name extends_declaration?
                           implements_declaration? throws_declaration?;
 interface_declaration = modifier* 'interface' full_class_name extends_interface_declaration?
-                                               '{' field_declaration* '}';
+                                               '{' property_declaration* '}';
 
 modifier = 'public'|'private'|'protected'|'static'|'final'|'native'|'synchronized'|'abstract'|'threadsafe'|'transient'|'volatile';
 type = type_specifier '[]'*;
@@ -50,7 +50,7 @@ statement_block = '{' statement* '}';
 variable_id = identifier '[]'*;
 method_id = identifier;
 
-field_declaration = method_declaration | constructor_declaration | variable_declaration | static_declaration | ';';
+property_declaration = method_declaration | constructor_declaration | variable_declaration | static_declaration | ';';
 variable_declaration = modifier* type variable_id throws_declaration? ';';
 method_declaration = modifier* generic_param? type method_id '(' parameter_list? ')' throws_declaration? ';';
 constructor_declaration = modifier* full_class_name '(' parameter_list? ')' throws_declaration? ';';
index 6c52a62..0da3c77 100644 (file)
@@ -17,7 +17,7 @@
 # Services to generate extern class `in "Java"`
 module code_generator
 
-intrude import types
+intrude import model
 
 class CodeGenerator
 
@@ -105,7 +105,7 @@ class CodeGenerator
        do
                var temp = new Array[String]
                temp.add("extern class Native{jtype.id} in \"Java\" `\{ {jtype} `\}\n")
-               temp.add("\tsuper JavaObject\n\tredef type SELF: Native{jtype.id}\n\n")
+               temp.add("\tsuper JavaObject\n\n")
 
                return temp.join("")
        end
@@ -121,16 +121,16 @@ class CodeGenerator
 
                var temp = new Array[String]
                temp.add("extern class {nit_type} in \"Java\" `\{ {jtype.to_package_name} `\}\n")
-               temp.add("\tsuper JavaObject\n\tredef type SELF: {nit_type}\n\nend\n")
+               temp.add("\tsuper JavaObject\n\nend\n")
 
                return temp.join("")
        end
 
        fun gen_attribute(jid: String, jtype: JavaType): String
        do
-               return "\tvar {jid.to_snake_case}: {jtype.to_nit_type}\n"
+               return "\tvar {jid.to_nit_method_name}: {jtype.to_nit_type}\n"
        end
-       
+
        fun gen_method(jmethod_id: String, nmethod_id: String, jreturn_type: JavaType, jparam_list: Array[JavaType]): String
        do
                var java_params = ""
@@ -138,7 +138,7 @@ class CodeGenerator
                var nit_id = "arg"
                var nit_id_no = 0
                var nit_types = new Array[NitType]
-               var comment = "" 
+               var comment = ""
 
                # Parameters
                for i in [0..jparam_list.length[ do
@@ -177,7 +177,7 @@ class CodeGenerator
                end
 
                # Method identifier
-               var method_id = nmethod_id.to_snake_case
+               var method_id = nmethod_id.to_nit_method_name
                var nit_signature = new Array[String]
 
                nit_signature.add "\tfun {method_id}"
@@ -207,16 +207,8 @@ class CodeGenerator
                        nit_signature.add ": {return_type} "
                end
 
-               var param_to_copy = param_to_copy(jparam_list, nit_types)
-
                var temp = new Array[String]
 
-               if nb_params > 1 then
-                       comment = "#"
-                       temp.add("\t# NOT SUPPORTED: more than one parameter to copy\n")
-                       temp.add("\t# Has to be implemented manually\n")
-               end
-
                temp.add(comment + nit_signature.join(""))
 
                # FIXME : This huge `if` block is only necessary to copy primitive arrays as long as there's no better way to do it
@@ -224,31 +216,10 @@ class CodeGenerator
                        temp.add(" in \"Java\" `\{\n{comment}\t\trecv.{jmethod_id}({java_params});\n{comment}\t`\}\n")
                # Methods with return type
                else if return_type != null then
-                       if jreturn_type.is_primitive_array then
-                               # Copy one parameter and the return value
-                               if param_to_copy != null then
-                                       var rtype_couple = new Couple[JavaType, NitType](jreturn_type, return_type)
-                                       temp.add(code_warehouse.param_return_copy(rtype_couple, param_to_copy, jmethod_id, java_params))
-                               # Copy the return type
-                               else
-                                       temp.add(code_warehouse.return_type_copy(jreturn_type, return_type, jmethod_id, java_params))
-                               end
-                       # Copy the parameter
-                       else if param_to_copy != null then
-                               temp.add(code_warehouse.param_type_copy(param_to_copy.first, param_to_copy.second, jmethod_id, java_params, true))
-                       # No copy
-                       else
-                               temp.add(" in \"Java\" `\{\n{comment}\t\treturn {jreturn_type.return_cast} recv.{jmethod_id}({java_params});\n{comment}\t`\}\n")
-                       end
+                       temp.add(" in \"Java\" `\{\n{comment}\t\treturn {jreturn_type.return_cast}recv.{jmethod_id}({java_params});\n{comment}\t`\}\n")
                # Methods without return type
                else if jreturn_type.is_void then
-                       # Copy one parameter
-                       if param_to_copy != null then
-                               temp.add(code_warehouse.param_type_copy(param_to_copy.first, param_to_copy.second, jmethod_id, java_params, false))
-                       # No copy
-                       else
-                               temp.add(" in \"Java\" `\{\n{comment}\t\trecv.{jmethod_id}({java_params});\n{comment}\t`\}\n")
-                       end
+                       temp.add(" in \"Java\" `\{\n{comment}\t\trecv.{jmethod_id}({java_params});\n{comment}\t`\}\n")
                # No copy
                else
                        temp.add(" in \"Java\" `\{\n{comment}\t\trecv.{jmethod_id}({java_params});\n{comment}\t`\}\n")
@@ -256,132 +227,11 @@ class CodeGenerator
 
                return temp.join("")
        end
-
-       # Only one primitive array parameter can be copied
-       # If there's none or more than one then `null` is returned
-       fun param_to_copy(jtypes: Array[JavaType], ntypes: Array[NitType]): nullable Couple[JavaType, NitType]
-       do
-               var counter = 0
-               var couple = null
-               for i in [0..jtypes.length[ do
-                       if jtypes[i].is_primitive_array then
-                               counter += 1
-                               couple = new Couple[JavaType, NitType](jtypes[i], ntypes[i])
-                       end
-               end
-
-               nb_params = counter
-
-               if counter > 1 then return null
-               return couple
-       end
 end
 
 # Contains raw code mostly used to copy collections
 class CodeWarehouse
 
-       # Collection as return value
-       fun return_type_copy(java_type: JavaType, nit_type: NitType, jmethod_id, params_id: String): String
-       do
-               var narray_id = "nit_array"
-               var loop_ = create_loop(java_type, nit_type, false, "java_array", narray_id)
-               var imports = create_imports(nit_type, false)
-
-               return """{{{imports}}} in "Java" `{ 
-               {{{java_type.to_s}}} java_array = recv.{{{jmethod_id}}}({{{params_id}}});
-               int {{{narray_id}}} = new_{{{nit_type.id}}}_of_{{{nit_type.generic_params.join("_")}}}();
-
-               {{{loop_}}}
-
-               return {{{narray_id}}};
-       `}
-"""
-       end
-
-       # Collection as parameter
-       fun param_type_copy(java_type: JavaType, nit_type: NitType, jmethod_id, params_id: String, has_return: Bool): String
-       do
-               var narray_id = "nit_array"
-               var jarray_id = "java_array"
-               var loop_ = create_loop(java_type, nit_type, true, jarray_id, narray_id)
-               var imports = create_imports(nit_type, true)
-               var jinstanciation = create_array_instance(java_type, nit_type, jarray_id)
-               var return_str = ""
-               
-               if has_return then
-                       return_str = "return "
-               end
-
-               params_id = params_id.replace(nit_type.arg_id, jarray_id)
-
-               return """{{{imports}}} in "Java" `{ 
-               {{{jinstanciation}}}
-               int {{{narray_id}}} = new_{{{nit_type.id}}}_of_{{{nit_type.generic_params.join("_")}}}();
-
-               {{{loop_}}}
-
-               {{{return_str}}}recv.{{{jmethod_id}}}({{{params_id}}});
-       `}
-"""
-       end
-
-       # One collection parameter and the return type will be copied
-       fun param_return_copy(return_types, param_types: Couple[JavaType, NitType], jmethod_id, params_id: String): String
-       do
-               var narray_id = "nit_array"
-               var narray_id2 = "nit_array2"
-
-               var r_jtype = return_types.first
-               var r_ntype = return_types.second
-
-               var p_jtype = param_types.first
-               var p_ntype = param_types.second
-
-               var r_loop = create_loop(r_jtype, r_ntype, false, "java_array", narray_id)
-               var p_loop = create_loop(p_jtype, p_ntype, true, "java_array2", narray_id2)
-
-               var imports = new Array[String]
-               
-               # Avoid import duplication
-               if p_ntype.to_s != r_ntype.to_s then
-                       imports.add create_imports(p_ntype, true)
-               end
-
-               imports.add create_imports(r_ntype, false)
-
-               params_id = params_id.replace(p_ntype.arg_id, narray_id)
-
-               var jinstanciation = create_array_instance(p_jtype, p_ntype, "java_array")
-
-               return """{{{imports.join(", ")}}} in "Java" `{
-               {{{jinstanciation}}}
-
-               {{{p_loop}}}
-
-               {{{r_jtype.to_s}}} java_array2 = recv.{{{jmethod_id}}}({{{params_id}}});
-               int {{{narray_id2}}} = new_{{{r_ntype.id}}}_of_{{{r_ntype.generic_params.join("_")}}}();
-
-               {{{r_loop}}}
-
-               return {{{narray_id2}}};
-       `}
-"""
-       end
-
-       private fun create_array_instance(java_type: JavaType, nit_type: NitType, jarray_id: String): String
-       do
-               var jtype = java_type.to_s
-               var instanciation = ""
-
-               if java_type.is_primitive_array then
-                       instanciation = "{jtype} {jarray_id} = new {java_type.full_id}[(int)Array_of_{nit_type.generic_params[0]}_length({nit_type.arg_id})];"
-               else
-                       instanciation = "{jtype} {jarray_id} = new {jtype}();"
-               end
-
-               return instanciation
-       end
-
        private fun create_imports(nit_type: NitType, is_param: Bool): String
        do
                var imports = ""
@@ -401,48 +251,29 @@ class CodeWarehouse
                else
                        imports = """ import {{{ntype}}}.iterator, Iterator[{{{gen_type}}}].is_ok, Iterator[{{{gen_type}}}].next, Iterator[{{{gen_type}}}].item"""
                end
-               
+
                return imports
        end
+end
 
-       private fun create_loop(java_type: JavaType, nit_type: NitType, is_param: Bool, jarray_id, narray_id: String): String
+redef class String
+       # Convert the Java method name `self` to the Nit style
+       #
+       # * Converts to snake case
+       # * Strips `Get` and `Set`
+       # * Add suffix `=` to setters
+       fun to_nit_method_name: String
        do
-               var loop_header = ""
-               var loop_body = ""
-               var gen_type = nit_type.generic_params.join("_")
-
-               if is_param then
-                       if java_type.is_primitive_array then
-                               loop_header = "for(int i=0; i < {jarray_id}.length; ++i)"
-                               loop_body   = """\t\t\t{{{jarray_id}}}[i] = {{{java_type.param_cast}}}Array_of_{{{gen_type}}}__index({{{nit_type.arg_id}}}, i);"""
-                       else if nit_type.id == "Array" then
-                               loop_header = """int length = Array_of_{{{gen_type}}}_length((int){{{nit_type.arg_id}}});\n\t\tfor(int i=0; i < length; ++i)"""
-                               loop_body   = """\t\t\t{{{jarray_id}}}.add({{{java_type.param_cast}}}Array_of_{{{gen_type}}}__index({{{narray_id}}}, i));"""
-                       else
-                               loop_header = """int itr = {{{nit_type.id}}}_of_{{{gen_type}}}_iterator({{{nit_type.arg_id}}});\n\t\twhile(Iterator_of_{{{gen_type}}}_is_ok(itr)) {"""
-                               if nit_type.is_map then
-                                       var key_cast = java_type.to_cast(java_type.generic_params[0].id, true)
-                                       var value_cast = java_type.to_cast(java_type.generic_params[1].id, true)
-                                       loop_body   = """\t\t\t{{{jarray_id}}}[{{{key_cast}}}iterator_of_{{{nit_type.id}}}_key(itr)] = {{{value_cast}}}iterator_of_{{{nit_type.id}}}_item(itr);\n\t\t\titerator_of_{{{gen_type}}}_next(itr);\n\t\t}"""
-                               else
-                                       loop_body   = """\t\t\t{{{jarray_id}}}.add({{{java_type.param_cast}}}iterator_of_{{{nit_type.id}}}_item(itr));\n\t\t\titerator_of_{{{gen_type}}}_next(itr);\n\t\t}"""
-                               end
-                       end
+               var name
+               if self.has_prefix("Get") then
+                       name = self.substring_from(3)
+               else if self.has_prefix("Set") then
+                       name = self.substring_from(3)
+                       name += "="
                else
-                       if nit_type.is_map then
-                               var key_cast = java_type.to_cast(java_type.generic_params[0].id, false)
-                               var value_cast = java_type.to_cast(java_type.generic_params[1].id, false)
-                               loop_header = """for (java.util.Map.Entry<{{{java_type.generic_params[0]}}}, {{{java_type.generic_params[1]}}}> e: {{{jarray_id}}})"""
-                               loop_body   = """\t\t\t{{{nit_type.id}}}_of_{{{gen_type}}}_{{{nit_type.generic_params[1]}}}__index_assign({{{narray_id}}}, {{{key_cast}}}e.getKey(), {{{value_cast}}}e.getValue());"""
-                       else if java_type.is_iterable then
-                               loop_header = """for ({{{java_type.generic_params[0]}}} e: {{{jarray_id}}})"""
-                               loop_body   = """\t\t\t{{{nit_type.id}}}_of_{{{gen_type}}}_add({{{narray_id}}}, {{{java_type.return_cast}}}e);"""
-                       else
-                               loop_header = "for(int i=0; i < {jarray_id}.length; ++i)"
-                               loop_body   = """\t\t\t{{{nit_type.id}}}_of_{{{gen_type}}}_add({{{narray_id}}}, {{{java_type.return_cast}}}{{{jarray_id}}}[i]);"""
-                       end
+                       name = self
                end
 
-               return loop_header + "\n" + loop_body
+               return name.to_snake_case
        end
 end
index 1ede6f0..9ee4190 100644 (file)
@@ -21,7 +21,7 @@ module javap_visitor
 import javap_test_parser
 import code_generator
 import jtype_converter
-intrude import types
+intrude import model
 
 class JavaVisitor
        super Visitor
@@ -336,11 +336,11 @@ redef class Nimplements_declaration
        end
 end
 
-#                                          #
-#   F I E L D    D E C L A R A T I O N S   #
-#                                          #
+#                                            #
+# P R O P E R T Y    D E C L A R A T I O N S #
+#                                            #
 
-# Method declaration in the field declarations
+# Method declaration
 redef class Nmethod_declaration
        redef fun accept_visitor(v)
        do
@@ -357,7 +357,7 @@ redef class Nmethod_declaration
        end
 end
 
-# Constructor declaration in the field declarations
+# Constructor declaration
 redef class Nconstructor_declaration
        redef fun accept_visitor(v)
        do
@@ -367,7 +367,7 @@ redef class Nconstructor_declaration
        end
 end
 
-# Variable declaration in the field declarations
+# Variable property declaration
 redef class Nvariable_declaration
        redef fun accept_visitor(v)
        do
@@ -382,7 +382,7 @@ redef class Nvariable_declaration
        end
 end
 
-# Static declaration in the field declarations
+# Static property declaration
 redef class Nstatic_declaration
        redef fun accept_visitor(v)
        do
@@ -392,7 +392,7 @@ redef class Nstatic_declaration
        end
 end
 
-# Identifier of the field
+# Identifier of a variable
 redef class Nvariable_id
        redef fun accept_visitor(v)
        do
index c5a8b29..f70d6ed 100644 (file)
@@ -61,28 +61,6 @@ class JavaTypeConverter
                return_cast_map["CharSequence"] = "(String)"
        end
 
-       init with_collections
-       do
-               self.init
-               # Collections
-               type_map["List"] = "Array"
-               type_map["ArrayList"] = "Array"
-               type_map["LinkedList"] = "List"
-               type_map["Vector"] = "Array"
-       
-               type_map["Set"] = "HashSet"
-               type_map["SortedSet"] = "Still have to make my mind on this one"
-               type_map["HashSet"] = "HashSet"
-               type_map["TreeSet"] = "HashSet"
-               type_map["LinkedHashSet"] = "HashSet"
-               type_map["Map"] = "HashMap"
-               type_map["SortedMap"] = "RBTreeMap"
-               type_map["HashMap"] = "HashMap"
-               type_map["TreeMap"] = "RBTreeMap"
-               type_map["Hashtable"] = "HashMap"
-               type_map["LinkedHashMap"] = "HashMap"
-       end
-
        fun to_nit_type(java_type: String): nullable String
        do
                return self.type_map.get_or_null(java_type)
similarity index 78%
rename from contrib/jwrapper/src/types.nit
rename to contrib/jwrapper/src/model.nit
index 3a14d8d..b77c734 100644 (file)
@@ -15,7 +15,7 @@
 # limitations under the License.
 
 # Contains the java and nit type representation used to convert java to nit code
-module types
+module model
 
 import jtype_converter
 
@@ -53,13 +53,12 @@ class JavaType
        fun to_nit_type: NitType
        do
                var nit_type: NitType
+               var type_id = null
 
-               if self.is_primitive_array then
-                       return self.convert_primitive_array
+               if not is_primitive_array then
+                       type_id = converter.to_nit_type(self.id)
                end
 
-               var type_id = converter.to_nit_type(self.id)
-
                if type_id == null then
                        nit_type = self.extern_name
                        nit_type.is_complete = false
@@ -68,7 +67,7 @@ class JavaType
                end
 
                if not self.has_generic_params then return nit_type
-               
+
                nit_type.generic_params = new Array[NitType]
 
                for param in generic_params do
@@ -82,38 +81,6 @@ class JavaType
                return nit_type
        end
 
-       fun convert_primitive_array: NitType
-       do
-               var nit_type = new NitType("Array")
-
-               var last_nit_type = nit_type
-
-               for i in [1..array_dimension] do
-                       var temp: NitType
-                       last_nit_type.generic_params = new Array[NitType]
-
-                       if i == array_dimension then
-                               var temp_type = converter.to_nit_type(self.id)
-
-                               if temp_type == null then 
-                                       temp = self.extern_name
-                                       nit_type.is_complete = false
-                                       if temp.mod != null then nit_type.mod = temp.mod
-                               else
-                                       temp = new NitType(temp_type)
-                               end
-                       else
-                               temp = new NitType("Array")
-                       end
-
-                       last_nit_type.generic_params.add(temp)
-
-                       last_nit_type = temp
-               end
-               
-               return nit_type
-       end
-
        fun is_iterable: Bool do return iterable.has(self.id)
 
        fun is_collection: Bool do return is_primitive_array or collections_list.has(self.id)
@@ -126,15 +93,16 @@ class JavaType
        do
                if is_wrapped then return new NitType.with_module(find_extern_class.as(not null).first, find_extern_class.as(not null).second)
 
-               var name = "Native" + extern_class_name.join("")
-               var nit_type: NitType
-               if self.is_primitive_array then
-                       nit_type = new NitType.with_generic_params("Array", name)
+               var name
+               if is_primitive_array then
+                       # Primitive arrays have a special naming convention
+                       name = "Native" + extern_class_name.join("").capitalized + "Array"
                else
-                       nit_type = new NitType("Native" + extern_class_name.join(""))
+                       name = "Native" + extern_class_name.join("")
                end
-               nit_type.is_complete = false
 
+               var nit_type = new NitType(name)
+               nit_type.is_complete = false
                return nit_type
        end
 
@@ -155,7 +123,7 @@ class JavaType
                        for i in [0..array_dimension[ do
                                id += "[]"
                        end
-               else if self.has_generic_params then 
+               else if self.has_generic_params then
                        var gen_list = new Array[String]
 
                        for param in generic_params do
@@ -206,12 +174,11 @@ class JavaType
 
        # Search inside `lib/android` directory for already wrapped classes
        # If found, contains the class identifier and the Nit Module name
-       var find_extern_class: nullable Couple[String, NitModule] = find_extern_class_fun is lazy
+       var find_extern_class: nullable Couple[String, NitModule] is lazy do
 
-       private fun find_extern_class_fun: nullable Couple[String, NitModule]
-       do
-               var regex = "extern class Native[a-zA-Z1-9]\\\+[ ]\\\+in[ ]\\\+\"Java\"[ ]*`\{[ ]*" + self.to_s + "\\\+[ ]*`\}"
-               var grep = new IProcess("grep", "-r", regex, "{"NIT_DIR".environ}/lib/android/")
+               var regex = "extern class [a-zA-Z1-9]\\\+[ ]\\\+in[ ]\\\+\"Java\"[ ]*`\{[ ]*" + self.to_s + "\\\+[ ]*`\}"
+               var nit_dir = "NIT_DIR".environ
+               var grep = new IProcess("grep", "-r", regex, nit_dir/"lib/android/", nit_dir/"lib/java/")
                var to_eat = ["private", "extern", "class"]
 
                var output = grep.read_line
@@ -310,7 +277,7 @@ class NitType
        do
                var id = self.identifier
 
-               if self.has_generic_params then 
+               if self.has_generic_params then
                        var gen_list = new Array[String]
 
                        for param in generic_params do
@@ -327,36 +294,36 @@ end
 class JavaClass
        var class_type = new JavaType(new JavaTypeConverter)
        var attributes = new HashMap[String, JavaType]
-       var methods = new HashMap[String, Array[JReturnAndParams]]
+
+       # Methods of this class organized by their name
+       var methods = new HashMap[String, Array[JavaMethod]]
+
        var unknown_types = new HashSet[JavaType]
        var imports = new HashSet[NitModule]
 
        fun add_method(id: String, return_type: JavaType, params: Array[JavaType])
        do
-               var ret_and_params = methods.get_or_default(id, new Array[JReturnAndParams])
-               
-               ret_and_params.add(new JReturnAndParams(return_type, new Array[JavaType].from(params)))
-               methods[id] = ret_and_params
+               var signatures = methods.get_or_default(id, new Array[JavaMethod])
+               signatures.add(new JavaMethod(return_type, new Array[JavaType].from(params)))
+               methods[id] = signatures
        end
 end
 
-class JReturnAndParams
+# A Java method, with its signature
+class JavaMethod
+       # Type returned by the method
        var return_type: JavaType
-       var params: Array[JavaType]
 
-       init(return_type: JavaType, params: Array[JavaType])
-       do
-               self.return_type = return_type
-               self.params = params
-       end
+       # Type of the arguments of the method
+       var params: Array[JavaType]
 end
 
+# A Nit module, use to import the referenced extern classes
 class NitModule
-       var value: String
-
-       init(str: String) do value = str
+       # Name of the module
+       var name: String
 
        redef fun ==(other): Bool do return self.to_s == other.to_s
-       redef fun to_s: String do return self.value
-       redef fun hash: Int do return self.value.hash
+       redef fun to_s: String do return self.name
+       redef fun hash: Int do return self.name.hash
 end
index affb3e9..ace5787 100644 (file)
@@ -19,6 +19,8 @@ module ballz_android is
        app_name("Ballz")
 end
 
+import android::portrait
+
 import game_logic
 
 redef class App
index 1a3459a..aac6d47 100644 (file)
@@ -21,6 +21,7 @@ end
 import dino
 
 import mnit_android
+import android::portrait
 import android::vibration
 
 redef class ImageSet
index ecc8b6e..ad2b1f1 100644 (file)
 
 module moles_android
 
-import moles
 import mnit_android
+import android::portrait
+
+import moles
 
 redef class Game
        redef fun columns do return 3
index bf2bd23..b108f8b 100644 (file)
@@ -18,10 +18,12 @@ module simple_android is
        android_manifest("""<uses-permission android:name="android.permission.VIBRATE" />""")
 end
 
-import simple
 import mnit_android
+import android::portrait
 import serialization
 
+import simple
+
 in "Java" `{
        import android.content.Context;
        import android.widget.Toast;
diff --git a/lib/android/cardboard.nit b/lib/android/cardboard.nit
new file mode 100644 (file)
index 0000000..30ec5eb
--- /dev/null
@@ -0,0 +1,70 @@
+# 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.
+
+# Services from the Google Cardboard SDK for virtual reality on Android
+#
+# Projects using this module should keep the `cardboard.jar` archive in the
+# `libs` folder at the root of the project.
+#
+# External resources:
+# * Download `cardboard.jar` from
+# https://raw.githubusercontent.com/googlesamples/cardboard-java/master/CardboardSample/libs/cardboard.jar
+# * Read about Cardboard at
+# https://developers.google.com/cardboard/
+# * Find the Cardboard SDK documentation at
+# https://developers.google.com/cardboard/android/latest/reference/com/google/vrtoolkit/cardboard/package-summary
+module cardboard
+
+import java::collections
+import native_app_glue
+
+in "Java" `{
+       import com.google.vrtoolkit.cardboard.CardboardActivity;
+       import com.google.vrtoolkit.cardboard.sensors.HeadTracker;
+`}
+
+# Provides head tracking information from the device IMU
+#
+# The corresponding Java class is no longer documented, but it is still useful.
+extern class NativeHeadTracker in "Java" `{ com.google.vrtoolkit.cardboard.sensors.HeadTracker `}
+       super JavaObject
+
+       # Instantiate a new `NativeHeadTracker` for the given `context`
+       new (context: NativeContext) in "Java" `{
+               return HeadTracker.createFromContext(context);
+       `}
+
+       # Start tracking head movement
+       fun start_tracking in "Java" `{ recv.startTracking(); `}
+
+       # Stop tracking head movement
+       fun stop_tracking in "Java" `{ recv.stopTracking(); `}
+
+       # Apply correction to the gyroscope values
+       fun gyro_bias=(matrix: JavaFloatArray) in "Java" `{
+               recv.setGyroBias(matrix);
+       `}
+
+       # Enable finer analysis using the neck as center of movement
+       fun neck_model_enabled=(value: Bool) in "Java" `{
+               recv.setNeckModelEnabled(value);
+       `}
+
+       # Fill `matrix` with the last rotation matrix calculated from head movements
+       #
+       # Require: matrix.length >= offset + 16
+       fun last_head_view(matrix: JavaFloatArray, offset: Int) in "Java" `{
+               recv.getLastHeadView(matrix, (int)offset);
+       `}
+end
diff --git a/lib/android/input_events.nit b/lib/android/input_events.nit
new file mode 100644 (file)
index 0000000..c766a16
--- /dev/null
@@ -0,0 +1,252 @@
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Copyright 2012-2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# Pointer and hardware key events
+module input_events
+
+import mnit_input
+import android
+
+in "C header" `{
+       #include <android/log.h>
+       #include <android_native_app_glue.h>
+
+       #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "mnit", __VA_ARGS__))
+       #ifdef DEBUG
+               #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "mnit", __VA_ARGS__))
+       #else
+               #define LOGI(...) (void)0
+       #endif
+`}
+
+in "C" `{
+       /* Handle inputs from the Android platform and sort them before
+          sending them in the Nit App */
+       static int32_t mnit_handle_input(struct android_app* app, AInputEvent* event) {
+               App nit_app = app->userData;
+               LOGI("handle input %i", (int)pthread_self());
+               if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY) {
+                       LOGI("key");
+                       return App_native_input_key(nit_app, event);
+               }
+               else if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
+                       LOGI("motion");
+                       return App_native_input_motion(nit_app, event);
+               }
+
+               return 0;
+       }
+`}
+
+private extern class NativeAndroidMotionEvent `{AInputEvent *`}
+
+       fun pointers_count: Int `{
+               return AMotionEvent_getPointerCount(recv);
+       `}
+
+       # Did this motion event just started?
+       fun just_went_down: Bool `{
+               return (AMotionEvent_getAction(recv) & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_DOWN;
+       `}
+
+       fun edge: Int `{
+               return AMotionEvent_getEdgeFlags(recv);
+       `}
+
+       # Get the non-primary pointer id that just went down (returns -1 or > 0)
+       fun index_down_pointer: Int `{
+               int a = AMotionEvent_getAction(recv);
+               if ((a & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_POINTER_DOWN)
+                       return (a & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
+               else return -1;
+       `}
+
+       fun action: AMotionEventAction `{ return AMotionEvent_getAction(recv); `}
+end
+
+private extern class AMotionEventAction `{ int32_t `}
+       fun action: Int `{ return recv & AMOTION_EVENT_ACTION_MASK; `}
+
+       fun is_down: Bool do return action == 0
+       fun is_up: Bool do return action == 1
+       fun is_move: Bool do return action == 2
+       fun is_cancel: Bool do return action == 3
+       fun is_outside: Bool do return action == 4
+       fun is_pointer_down: Bool do return action == 5
+       fun is_pointer_up: Bool do return action == 6
+end
+
+# An input event on Android
+interface AndroidInputEvent
+       super InputEvent
+end
+
+# A motion event concerning a single or more `pointers`
+class AndroidMotionEvent
+       super AndroidInputEvent
+       super MotionEvent
+
+       private var native: NativeAndroidMotionEvent
+
+       private var pointers_cache: nullable Array[AndroidPointerEvent] = null
+
+       # Pointers (or fingers) composing this motion event
+       fun pointers: Array[AndroidPointerEvent]
+       do
+               if pointers_cache != null then
+                       return pointers_cache.as(not null)
+               else
+                       var pointers = new Array[AndroidPointerEvent]
+                       var pointers_count = native.pointers_count
+                       for i in [0 .. pointers_count [do
+                               var pointer_event = new AndroidPointerEvent(self, i)
+                               pointers.add(pointer_event)
+                       end
+                       pointers_cache = pointers
+                       return pointers
+               end
+       end
+
+       redef fun just_went_down: Bool do return native.just_went_down
+
+       # Was the top edge of the screen intersected by this event?
+       fun touch_to_edge: Bool do return native.edge == 1
+
+       # Was the bottom edge of the screen intersected by this event?
+       fun touch_bottom_edge: Bool do return native.edge == 2
+
+       # Was the left edge of the screen intersected by this event?
+       fun touch_left_edge: Bool do return native.edge == 4
+
+       # Was the right edge of the screen intersected by this event?
+       fun touch_right_edge: Bool do return native.edge == 8
+
+       redef fun down_pointer: nullable AndroidPointerEvent
+       do
+               if just_went_down then
+                       # The primary pointer went down
+                       return pointers[0]
+               end
+
+               var i = native.index_down_pointer
+               if i > 0 then
+                       # A secondary pointer went down
+                       return pointers[i]
+               else
+                       return null
+               end
+       end
+end
+
+# A pointer event
+class AndroidPointerEvent
+       super PointerEvent
+       super AndroidInputEvent
+
+       private var motion_event: AndroidMotionEvent
+
+       private var pointer_id: Int
+
+       redef fun x: Float do return native_x(motion_event.native, pointer_id)
+
+       private fun native_x(motion_event: NativeAndroidMotionEvent, pointer_id: Int): Float `{
+               return AMotionEvent_getX(motion_event, pointer_id);
+       `}
+
+       redef fun y: Float do return native_y(motion_event.native, pointer_id)
+
+       private fun native_y(motion_event: NativeAndroidMotionEvent, pointer_id: Int): Float `{
+               return AMotionEvent_getY(motion_event, pointer_id);
+       `}
+
+       # Pressure applied by this pointer
+       fun pressure: Float do return native_pressure(motion_event.native, pointer_id)
+
+       private fun native_pressure(motion_event: NativeAndroidMotionEvent, pointer_id: Int): Float `{
+               return AMotionEvent_getPressure(motion_event, pointer_id);
+       `}
+
+       redef fun pressed
+       do
+               var action = motion_event.native.action
+               return action.is_down or action.is_move
+       end
+
+       redef fun depressed do return not pressed
+
+       # Does this pointer just began touching the screen?
+       fun just_went_down: Bool
+       do
+               return motion_event.down_pointer == self
+       end
+end
+
+# An hardware key event
+extern class AndroidKeyEvent `{AInputEvent *`}
+       super KeyEvent
+       super AndroidInputEvent
+
+       private fun action: Int `{ return AKeyEvent_getAction(recv); `}
+
+       redef fun is_down: Bool do return action == 0
+       redef fun is_up: Bool do return action == 1
+
+       # Hardware code of the key raising this event
+       fun key_code: Int `{ return AKeyEvent_getKeyCode(recv); `}
+
+       redef fun to_c `{
+               int code = AKeyEvent_getKeyCode(recv);
+               if (code >= AKEYCODE_0 && code <= AKEYCODE_9)
+                       return '0'+code-AKEYCODE_0;
+               if (code >= AKEYCODE_A && code <= AKEYCODE_Z)
+                       return 'a'+code-AKEYCODE_A;
+               return 0;
+       `}
+
+       # Was this event raised by the back key?
+       fun is_back_key: Bool do return key_code == 4
+
+       # Was this event raised by the menu key?
+       fun is_menu_key: Bool do return key_code == 82
+
+       # Was this event raised by the search key?
+       fun is_search_key: Bool do return key_code == 84
+
+       # Was this event raised by the volume up key?
+       fun is_volume_up: Bool do return key_code == 24
+
+       # Was this event raised by the volume down key?
+       fun is_volume_down: Bool do return key_code == 25
+end
+
+redef class App
+
+       redef fun init_window
+       do
+               set_as_input_handler native_app_glue
+               super
+       end
+
+       private fun set_as_input_handler(app_glue: NativeAppGlue)
+       import native_input_key, native_input_motion `{
+               app_glue->onInputEvent = mnit_handle_input;
+       `}
+
+       # these are used as a callback from native to type incoming events
+       private fun native_input_key(event: AndroidKeyEvent): Bool is abstract
+
+       private fun native_input_motion(event: NativeAndroidMotionEvent): Bool is abstract
+end
diff --git a/lib/android/landscape.nit b/lib/android/landscape.nit
new file mode 100644 (file)
index 0000000..a3fceaf
--- /dev/null
@@ -0,0 +1,20 @@
+# 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.
+
+# Config to set the landscape orientation
+module landscape is android_manifest_activity """
+               android:screenOrientation="landscape"
+"""
+
+import platform
diff --git a/lib/android/portrait.nit b/lib/android/portrait.nit
new file mode 100644 (file)
index 0000000..e8f5720
--- /dev/null
@@ -0,0 +1,20 @@
+# 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.
+
+# Config to set the portrait orientation
+module portrait is android_manifest_activity """
+               android:screenOrientation="portrait"
+"""
+
+import platform
index d62153f..cfab7ae 100644 (file)
@@ -106,16 +106,16 @@ assert egl_bind_opengl_es_api else print "eglBingAPI failed: {egl_display.error}
 ## GLESv2
 #
 
-print "Can compile shaders? {gl_shader_compiler}"
+print "Can compile shaders? {gl.shader_compiler}"
 assert_no_gl_error
 
-assert gl_shader_compiler else print "Cannot compile shaders"
+assert gl.shader_compiler else print "Cannot compile shaders"
 
 # gl program
-print gl_error.to_s
+print gl.error.to_s
 var program = new GLProgram
 if not program.is_ok then
-       print "Program is not ok: {gl_error.to_s}\nLog:"
+       print "Program is not ok: {gl.error.to_s}\nLog:"
        print program.info_log
        abort
 end
@@ -123,27 +123,28 @@ assert_no_gl_error
 
 # vertex shader
 var vertex_shader = new GLVertexShader
-assert vertex_shader.is_ok else print "Vertex shader is not ok: {gl_error}"
+assert vertex_shader.is_ok else print "Vertex shader is not ok: {gl.error}"
 vertex_shader.source = """
 attribute vec4 vPosition;
 void main()
 {
   gl_Position = vPosition;
-}                           """
+}
+""".to_cstring
 vertex_shader.compile
 assert vertex_shader.is_compiled else print "Vertex shader compilation failed with: {vertex_shader.info_log} {program.info_log}"
 assert_no_gl_error
 
 # fragment shader
 var fragment_shader = new GLFragmentShader
-assert fragment_shader.is_ok else print "Fragment shader is not ok: {gl_error}"
+assert fragment_shader.is_ok else print "Fragment shader is not ok: {gl.error}"
 fragment_shader.source = """
 precision mediump float;
 void main()
 {
        gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
 }
-"""
+""".to_cstring
 fragment_shader.compile
 assert fragment_shader.is_compiled else print "Fragment shader compilation failed with: {fragment_shader.info_log}"
 assert_no_gl_error
@@ -159,12 +160,12 @@ assert_no_gl_error
 var vertices = [0.0, 0.5, 0.0, -0.5, -0.5, 0.0, 0.5, -0.5, 0.0]
 var vertex_array = new VertexArray(0, 3, vertices)
 vertex_array.attrib_pointer
-gl_clear_color(0.5, 0.0, 0.5, 1.0)
+gl.clear_color(0.5, 0.0, 0.5, 1.0)
 for i in [0..10000[ do
        printn "."
        assert_no_gl_error
-       gl_viewport(0, 0, width, height)
-       gl_clear_color_buffer
+       gl.viewport(0, 0, width, height)
+       gl.clear((new GLBuffer).color)
        program.use
        vertex_array.enable
        vertex_array.draw_arrays_triangles
index 8d5ec6a..01ca43c 100644 (file)
@@ -199,9 +199,8 @@ end
 # Abstract OpenGL ES shader object, implemented by `GLFragmentShader` and `GLVertexShader`
 extern class GLShader `{GLuint`}
        # Set the source of the shader
-       fun source=(code: String) import String.to_cstring, String.length `{
-               GLchar *c_code = String_to_cstring(code);
-               glShaderSource(recv, 1, (const GLchar * const*)&c_code, NULL);
+       fun source=(code: NativeString) `{
+               glShaderSource(recv, 1, (GLchar const **)&code, NULL);
        `}
 
        # Source of the shader, if available
@@ -318,10 +317,24 @@ extern class GLfloatArray `{GLfloat *`}
        `}
 end
 
+# General type for OpenGL enumerations
+extern class GLEnum `{ GLenum `}
+
+       redef fun hash `{ return recv; `}
+
+       redef fun ==(o) do return o != null and is_same_type(o) and o.hash == self.hash
+end
+
 # An OpenGL ES 2.0 error code
-extern class GLError `{ GLenum `}
+extern class GLError
+       super GLEnum
+
+       # Is there no error?
        fun is_ok: Bool do return is_no_error
+
+       # Is this not an error?
        fun is_no_error: Bool `{ return recv == GL_NO_ERROR; `}
+
        fun is_invalid_enum: Bool `{ return recv == GL_INVALID_ENUM; `}
        fun is_invalid_value: Bool `{ return recv == GL_INVALID_VALUE; `}
        fun is_invalid_operation: Bool `{ return recv == GL_INVALID_OPERATION; `}
@@ -340,65 +353,280 @@ extern class GLError `{ GLenum `}
        end
 end
 
-# Clear the color buffer with `r`, `g`, `b`, `a`
-protected fun gl_clear_color(r, g, b, a: Float) `{ glClearColor(r, g, b, a); `}
-
-# Set the viewport
-protected fun gl_viewport(x, y, width, height: Int) `{ glViewport(x, y, width, height); `}
-
-# Direct call to `glClear`, call with a combinaison of `gl_clear_color_buffer`,
-# `gl_stencil_buffer_bit` and `gl_color_buffer_bit`.
-private fun gl_clear(flag: Int) `{ glClear(flag); `}
-
-protected fun gl_depth_buffer_bit: Int do return 0x0100
-protected fun gl_stencil_buffer_bit: Int do return 0x0400
-protected fun gl_color_buffer_bit: Int do return 0x4000
-
-protected fun gl_clear_color_buffer do gl_clear(gl_color_buffer_bit)
-protected fun gl_clear_depth_buffer do gl_clear(gl_depth_buffer_bit)
-protected fun gl_clear_stencil_buffer do gl_clear(gl_stencil_buffer_bit)
-
-protected fun gl_error: GLError `{ return glGetError(); `}
 protected fun assert_no_gl_error
 do
-       var error = gl_error
+       var error = gl.error
        if not error.is_ok then
                print "GL error: {error}"
                abort
        end
 end
 
-# Query the boolean value at `key`
-private fun gl_get_bool(key: Int): Bool `{
-       GLboolean val;
-       glGetBooleanv(key, &val);
-       return val == GL_TRUE;
-`}
+# Texture minifying function
+#
+# Used by: `GLES::tex_parameter_min_filter`
+extern class GLTextureMinFilter
+       super GLEnum
 
-# Query the floating point value at `key`
-private fun gl_get_float(key: Int): Float `{
-       GLfloat val;
-       glGetFloatv(key, &val);
-       return val;
-`}
+       new nearest `{ return GL_NEAREST; `}
+       new linear `{ return GL_LINEAR; `}
+end
 
-# Query the integer value at `key`
-private fun gl_get_int(key: Int): Int `{
-       GLint val;
-       glGetIntegerv(key, &val);
-       return val;
-`}
+# Texture magnification function
+#
+# Used by: `GLES::tex_parameter_mag_filter`
+extern class GLTextureMagFilter
+       super GLEnum
+
+       new nearest `{ return GL_NEAREST; `}
+       new linear `{ return GL_LINEAR; `}
+       new nearest_mipmap_nearest `{ return GL_NEAREST_MIPMAP_NEAREST; `}
+       new linear_mipmap_nearest `{ return GL_LINEAR_MIPMAP_NEAREST; `}
+       new nearest_mipmap_linear `{ return GL_NEAREST_MIPMAP_LINEAR; `}
+       new linear_mipmap_linear `{ return GL_LINEAR_MIPMAP_LINEAR; `}
+end
+
+# Wrap parameter of a texture
+#
+# Used by: `tex_parameter_wrap_*`
+extern class GLTextureWrap
+       super GLEnum
 
-# Does this driver support shader compilation?
+       new clamp_to_edge `{ return GL_CLAMP_TO_EDGE; `}
+       new mirrored_repeat `{ return GL_MIRRORED_REPEAT; `}
+       new repeat `{ return GL_REPEAT; `}
+end
+
+# Target texture
 #
-# Should always return `true` in OpenGL ES 2.0 and 3.0.
-fun gl_shader_compiler: Bool do return gl_get_bool(0x8DFA)
+# Used by: `tex_parameter_*`
+extern class GLTextureTarget
+       super GLEnum
+
+       new flat `{ return GL_TEXTURE_2D; `}
+       new cube_map `{ return GL_TEXTURE_CUBE_MAP; `}
+end
+
+# A server-side capability
+class GLCap
+
+       # TODO private init
+
+       # Internal OpenGL integer for this capability
+       private var val: Int
+
+       # Enable this server-side capability
+       fun enable do enable_native(val)
+       private fun enable_native(cap: Int) `{ glEnable(cap); `}
+
+       # Disable this server-side capability
+       fun disable do disable_native(val)
+       private fun disable_native(cap: Int) `{ glDisable(cap); `}
+
+       redef fun hash do return val
+       redef fun ==(o) do return o != null and is_same_type(o) and o.hash == self.hash
+end
+redef class Sys
+       private var gles = new GLES is lazy
+end
+
+# Entry points to OpenGL ES 2.0 services
+fun gl: GLES do return sys.gles
+
+# OpenGL ES 2.0 services
+class GLES
+
+       # Clear the color buffer to `red`, `green`, `blue` and `alpha`
+       fun clear_color(red, green, blue, alpha: Float) `{
+               glClearColor(red, green, blue, alpha);
+       `}
+
+       # Set the viewport
+       fun viewport(x, y, width, height: Int) `{ glViewport(x, y, width, height); `}
+
+       # Specify mapping of depth values from normalized device coordinates to window coordinates
+       #
+       # Default at `gl_depth_range(0.0, 1.0)`
+       fun depth_range(near, far: Float) `{ glDepthRangef(near, far); `}
+
+       # Define front- and back-facing polygons
+       #
+       # Front-facing polygons are clockwise if `value`, counter-clockwise otherwise.
+       fun front_face=(value: Bool) `{ glFrontFace(value? GL_CW: GL_CCW); `}
+
+       # Specify whether front- or back-facing polygons can be culled, default is `back` only
+       #
+       # One or both of `front` or `back` must be `true`. If you want to deactivate culling
+       # use `(new GLCap.cull_face).disable`.
+       #
+       # Require: `front or back`
+       fun cull_face(front, back: Bool)
+       do
+               assert not (front or back)
+               cull_face_native(front, back)
+       end
+
+       private fun cull_face_native(front, back: Bool) `{
+               glCullFace(front? back? GL_FRONT_AND_BACK: GL_BACK: GL_FRONT);
+       `}
+
+       # Clear the `buffer`
+       fun clear(buffer: GLBuffer) `{ glClear(buffer); `}
+
+       # Last error from OpenGL ES 2.0
+       fun error: GLError `{ return glGetError(); `}
+
+       # Query the boolean value at `key`
+       private fun get_bool(key: Int): Bool `{
+               GLboolean val;
+               glGetBooleanv(key, &val);
+               return val == GL_TRUE;
+       `}
+
+       # Query the floating point value at `key`
+       private fun get_float(key: Int): Float `{
+               GLfloat val;
+               glGetFloatv(key, &val);
+               return val;
+       `}
+
+       # Query the integer value at `key`
+       private fun get_int(key: Int): Int `{
+               GLint val;
+               glGetIntegerv(key, &val);
+               return val;
+       `}
+
+       # Does this driver support shader compilation?
+       #
+       # Should always return `true` in OpenGL ES 2.0 and 3.0.
+       fun shader_compiler: Bool do return get_bool(0x8DFA)
+
+       # Enable or disable writing into the depth buffer
+       fun depth_mask(value: Bool) `{ glDepthMask(value); `}
+
+       # Set the scale and units used to calculate depth values
+       fun polygon_offset(factor, units: Float) `{ glPolygonOffset(factor, units); `}
+
+       # Specify the width of rasterized lines
+       fun line_width(width: Float) `{ glLineWidth(width); `}
+
+       # Set the pixel arithmetic for the blending operations
+       #
+       # Defaultvalues before assignation:
+       # * `src_factor`: `GLBlendFactor::one`
+       # * `dst_factor`: `GLBlendFactor::zero`
+       fun blend_func(src_factor, dst_factor: GLBlendFactor) `{
+               glBlendFunc(src_factor, dst_factor);
+       `}
+
+       # Specify the value used for depth buffer comparisons
+       #
+       # Default value is `GLDepthFunc::less`
+       #
+       # Foreign: glDepthFunc
+       fun depth_func(func: GLDepthFunc) `{ glDepthFunc(func); `}
+
+       # Copy a block of pixels from the framebuffer of `fomat` and `typ` at `data`
+       #
+       # Foreign: glReadPixel
+       fun read_pixels(x, y, width, height: Int, format: GLPixelFormat, typ: GLPixelType, data: Pointer) `{
+               glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);
+       `}
+
+       # Set the texture minifying function
+       #
+       # Foreign: glTexParameter with GL_TEXTURE_MIN_FILTER
+       fun tex_parameter_min_filter(target: GLTextureTarget, value: GLTextureMinFilter) `{
+               glTexParameteri(target, GL_TEXTURE_MIN_FILTER, value);
+       `}
+
+       # Set the texture magnification function
+       #
+       # Foreign: glTexParameter with GL_TEXTURE_MAG_FILTER
+       fun tex_parameter_mag_filter(target: GLTextureTarget, value: GLTextureMagFilter) `{
+               glTexParameteri(target, GL_TEXTURE_MAG_FILTER, value);
+       `}
+
+       # Set the texture wrap parameter for coordinates _s_
+       #
+       # Foreign: glTexParameter with GL_TEXTURE_WRAP_S
+       fun tex_parameter_wrap_s(target: GLTextureTarget, value: GLTextureWrap) `{
+               glTexParameteri(target, GL_TEXTURE_WRAP_S, value);
+       `}
+
+       # Set the texture wrap parameter for coordinates _t_
+       #
+       # Foreign: glTexParameter with GL_TEXTURE_WRAP_T
+       fun tex_parameter_wrap_t(target: GLTextureTarget, value: GLTextureWrap) `{
+               glTexParameteri(target, GL_TEXTURE_WRAP_T, value);
+       `}
+
+       # Render primitives from array data
+       #
+       # Foreign: glDrawArrays
+       fun draw_arrays(mode: GLDrawMode, from, count: Int) `{ glDrawArrays(mode, from, count); `}
+
+       # OpenGL server-side capabilities
+       var capabilities = new GLCapabilities is lazy
+end
+
+# Entry point to OpenGL server-side capabilities
+class GLCapabilities
+
+       # GL capability: blend the computed fragment color values
+       #
+       # Foreign: GL_BLEND
+       fun blend: GLCap is lazy do return new GLCap(0x0BE2)
+
+       # GL capability: cull polygons based of their winding in window coordinates
+       #
+       # Foreign: GL_CULL_FACE
+       fun cull_face: GLCap is lazy do return new GLCap(0x0B44)
+
+       # GL capability: do depth comparisons and update the depth buffer
+       #
+       # Foreign: GL_DEPTH_TEST
+       fun depth_test: GLCap is lazy do return new GLCap(0x0B71)
+
+       # GL capability: dither color components or indices before they are written to the color buffer
+       #
+       # Foreign: GL_DITHER
+       fun dither: GLCap is lazy do return new GLCap(0x0BE2)
+
+       # GL capability: add an offset to depth values of a polygon fragment before depth test
+       #
+       # Foreign: GL_POLYGON_OFFSET_FILL
+       fun polygon_offset_fill: GLCap is lazy do return new GLCap(0x8037)
+
+       # GL capability: compute a temporary coverage value where each bit is determined by the alpha value at the corresponding location
+       #
+       # Foreign: GL_SAMPLE_ALPHA_TO_COVERAGE
+       fun sample_alpha_to_coverage: GLCap is lazy do return new GLCap(0x809E)
+
+       # GL capability: AND the fragment coverage with the temporary coverage value
+       #
+       # Foreign: GL_SAMPLE_COVERAGE
+       fun sample_coverage: GLCap is lazy do return new GLCap(0x80A0)
+
+       # GL capability: discard fragments that are outside the scissor rectangle
+       #
+       # Foreign: GL_SCISSOR_TEST
+       fun scissor_test: GLCap is lazy do return new GLCap(0x0C11)
+
+       # GL capability: do stencil testing and update the stencil buffer
+       #
+       # Foreign: GL_STENCIL_TEST
+       fun stencil_test: GLCap is lazy do return new GLCap(0x0B90)
+end
 
 # Float related data types of OpenGL ES 2.0 shaders
 #
 # Only data types supported by shader attributes, as seen with
 # `GLProgram::active_attrib_type`.
-extern class GLFloatDataType `{ GLenum `}
+extern class GLFloatDataType
+       super GLEnum
+
        fun is_float: Bool `{ return recv == GL_FLOAT; `}
        fun is_float_vec2: Bool `{ return recv == GL_FLOAT_VEC2; `}
        fun is_float_vec3: Bool `{ return recv == GL_FLOAT_VEC3; `}
@@ -406,6 +634,12 @@ extern class GLFloatDataType `{ GLenum `}
        fun is_float_mat2: Bool `{ return recv == GL_FLOAT_MAT2; `}
        fun is_float_mat3: Bool `{ return recv == GL_FLOAT_MAT3; `}
        fun is_float_mat4: Bool `{ return recv == GL_FLOAT_MAT4; `}
+
+       # Instances of `GLFloatDataType` can be equal to instances of `GLDataType`
+       redef fun ==(o)
+       do
+               return o != null and o isa GLFloatDataType and o.hash == self.hash
+       end
 end
 
 # All data types of OpenGL ES 2.0 shaders
@@ -426,3 +660,100 @@ extern class GLDataType
        fun is_sampler_2d: Bool `{ return recv == GL_SAMPLER_2D; `}
        fun is_sampler_cube: Bool `{ return recv == GL_SAMPLER_CUBE; `}
 end
+
+# Kind of primitives to render with `GLES::draw_arrays`
+extern class GLDrawMode
+       super GLEnum
+
+       new points `{ return GL_POINTS; `}
+       new line_strip `{ return GL_LINE_STRIP; `}
+       new line_loop `{ return GL_LINE_LOOP; `}
+       new lines `{ return GL_LINES; `}
+       new triangle_strip `{ return GL_TRIANGLE_STRIP; `}
+       new triangle_fan `{ return GL_TRIANGLE_FAN; `}
+       new triangles `{ return GL_TRIANGLES; `}
+end
+
+# Pixel arithmetic for blending operations
+#
+# Used by `GLES::blend_func`
+extern class GLBlendFactor
+       super GLEnum
+
+       new zero `{ return GL_ZERO; `}
+       new one `{ return GL_ONE; `}
+       new src_color `{ return GL_SRC_COLOR; `}
+       new one_minus_src_color `{ return GL_ONE_MINUS_SRC_COLOR; `}
+       new dst_color `{ return GL_DST_COLOR; `}
+       new one_minus_dst_color `{ return GL_ONE_MINUS_DST_COLOR; `}
+       new src_alpha `{ return GL_SRC_ALPHA; `}
+       new one_minus_src_alpha `{ return GL_ONE_MINUS_SRC_ALPHA; `}
+       new dst_alpha `{ return GL_DST_ALPHA; `}
+       new one_minus_dst_alpha `{ return GL_ONE_MINUS_DST_ALPHA; `}
+       new constant_color `{ return GL_CONSTANT_COLOR; `}
+       new one_minus_constant_color `{ return GL_ONE_MINUS_CONSTANT_COLOR; `}
+       new constant_alpha `{ return GL_CONSTANT_ALPHA; `}
+       new one_minus_constant_alpha `{ return GL_ONE_MINUS_CONSTANT_ALPHA; `}
+
+       # Used for destination only
+       new src_alpha_saturate `{ return GL_SRC_ALPHA_SATURATE; `}
+end
+
+# Condition under which a pixel will be drawn
+#
+# Used by `GLES::depth_func`
+extern class GLDepthFunc
+       super GLEnum
+
+        new never `{ return GL_NEVER; `}
+        new less `{ return GL_LESS; `}
+        new equal `{ return GL_EQUAL; `}
+        new lequal `{ return GL_LEQUAL; `}
+        new greater `{ return GL_GREATER; `}
+        new not_equal `{ return GL_NOTEQUAL; `}
+        new gequal `{ return GL_GEQUAL; `}
+        new always `{ return GL_ALWAYS; `}
+end
+
+# Format of pixel data
+#
+# Used by `GLES::read_pixels`
+extern class GLPixelFormat
+       super GLEnum
+
+       new alpha `{ return GL_ALPHA; `}
+       new rgb `{ return GL_RGB; `}
+       new rgba `{ return GL_RGBA; `}
+end
+
+# Data type of pixel data
+#
+# Used by `GLES::read_pixels`
+extern class GLPixelType
+       super GLEnum
+
+       new unsigned_byte `{ return GL_UNSIGNED_BYTE; `}
+       new unsigned_short_5_6_5 `{ return GL_UNSIGNED_SHORT_5_6_5; `}
+       new unsigned_short_4_4_4_4 `{ return GL_UNSIGNED_SHORT_4_4_4_4; `}
+       new unsigned_short_5_5_5_1 `{ return GL_UNSIGNED_SHORT_5_5_5_1; `}
+end
+
+# Set of buffers as a bitwise OR mask, used by `GLES::clear`
+#
+# ~~~
+# var buffers = (new GLBuffer).color.depth
+# gl.clear buffers
+# ~~~
+extern class GLBuffer `{ GLbitfield `}
+       # Get an empty set of buffers
+       new `{ return 0; `}
+
+       # Add the color buffer to the returned buffer set
+       fun color: GLBuffer `{ return recv | GL_COLOR_BUFFER_BIT; `}
+
+       # Add the depth buffer to the returned buffer set
+       fun depth: GLBuffer `{ return recv | GL_DEPTH_BUFFER_BIT; `}
+
+       # Add the stencil buffer to the returned buffer set
+       fun stencil: GLBuffer `{ return recv | GL_STENCIL_BUFFER_BIT; `}
+end
index 561139b..f6f10aa 100644 (file)
@@ -116,6 +116,17 @@ extern class GtkWidget `{GtkWidget *`}
        fun visible_self: Bool is extern `{
                return gtk_widget_get_visible(recv);
        `}
+
+       # Destroy the widget
+       fun destroy `{ gtk_widget_destroy(recv); `}
+
+       # Show the widget on screen
+       #
+       # See: `show_all` to recursively show this widget and contained widgets.
+       fun show `{ gtk_widget_show(recv); `}
+
+       # Hide the widget (reverse the effects of `show`)
+       fun hide `{ gtk_widget_hide(recv); `}
 end
 
 #Base class for widgets which contain other widgets
@@ -348,6 +359,13 @@ extern class GtkGrid `{GtkGrid *`}
        `}
 end
 
+# A container box
+#
+# @https://developer.gnome.org/gtk3/3.4/GtkBox.html
+extern class GtkBox `{ GtkBox * `}
+       super GtkContainer
+end
+
 #The tree interface used by GtkTreeView
 #@https://developer.gnome.org/gtk3/stable/GtkTreeModel.html
 extern class GtkTreeModel `{GtkTreeModel *`}
@@ -386,7 +404,7 @@ extern class GtkEntry `{GtkEntry *`}
                 return (GtkEntry *)gtk_entry_new();
        `}
 
-       fun text : String is extern import String.to_cstring`{
+       fun text : String is extern import NativeString.to_s `{
                return NativeString_to_s( (char *)gtk_entry_get_text( recv ) );
        `}
 
index 7da083f..079eb71 100644 (file)
@@ -119,8 +119,8 @@ extern class GtkAboutDialog `{GtkAboutDialog *`}
        #       gtk_about_dialog_set_authors( recv, String_to_cstring( authors_list ) );
        #`}
 
-       fun show ( parent : GtkWindow, params : String ) is extern import String.to_cstring`{
-               gtk_show_about_dialog( parent, String_to_cstring( params ), NULL);
+       fun show_about_dialog(parent: GtkWindow, params: String) import String.to_cstring `{
+               gtk_show_about_dialog(parent, String_to_cstring(params), NULL);
        `}
 end
 
diff --git a/lib/java/collections.nit b/lib/java/collections.nit
new file mode 100644 (file)
index 0000000..4da0250
--- /dev/null
@@ -0,0 +1,130 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Basic Java collections
+#
+# ~~~
+# var coll = new JavaArray(2)
+#
+# assert coll[0].is_java_null
+# coll[0] = "zero".to_java_string
+# coll[1] = "one".to_java_string
+#
+# assert coll.length == 2
+# assert coll.first.to_s == "zero"
+# assert coll[1].to_s == "one"
+# assert [for e in coll do e.to_s] == ["zero", "one"]
+# ~~~
+module collections
+
+import java
+
+# Java primitive array
+#
+# These have fixed size so they offer the same services as `SequenceRead` and
+# `[]=`, but would not support `Sequence::add`.
+extern class AbstractJavaArray[E: Object]
+       super SequenceRead[E]
+       super JavaObject
+
+       # Set the `value` at `key`
+       fun []=(key: Int, value: E) is abstract
+
+       redef fun iterator do return new JavaArrayIterator[E](self)
+
+       redef fun reverse_iterator do return new JavaArrayReverseIterator[E](self)
+end
+
+# Java primitive array `float[]`
+#
+# Note that Nit `Float` is the size of a double, so storing them in a
+# `JavaFloatArray` may lead to a loss of precision.
+extern class JavaFloatArray in "Java" `{ float[] `}
+       super AbstractJavaArray[Float]
+
+       # Get a new array of the given `size`
+       new(size: Int) in "Java" `{ return new float[(int)size]; `}
+
+       redef fun [](i) in "Java" `{ return (double)recv[(int)i]; `}
+
+       redef fun []=(i, e) in "Java" `{ recv[(int)i] = (float)e; `}
+
+       redef fun length in "Java" `{ return recv.length; `}
+end
+
+# Java primitive array `double[]`
+extern class JavaDoubleArray in "Java" `{ double[] `}
+       super AbstractJavaArray[Float]
+
+       # Get a new array of the given `size`
+       new(size: Int) in "Java" `{ return new double[(int)size]; `}
+
+       redef fun [](i) in "Java" `{ return recv[(int)i]; `}
+
+       redef fun []=(i, e) in "Java" `{ recv[(int)i] = (float)e; `}
+
+       redef fun length in "Java" `{ return recv.length; `}
+end
+
+# Java primitive array `Object[]`
+extern class JavaArray in "Java" `{ java.lang.Object[] `}
+       super AbstractJavaArray[JavaObject]
+
+       # Get a new array of the given `size`
+       new(size: Int) in "Java" `{ return new Object[(int)size]; `}
+
+       redef fun [](i) in "Java" `{ return recv[(int)i]; `}
+
+       redef fun []=(i, e) in "Java" `{ recv[(int)i] = e; `}
+
+       redef fun length in "Java" `{ return recv.length; `}
+end
+
+# TODO other primitive arrays:
+# * Java primitive array `byte[]`
+# * Java primitive array `short[]`
+# * Java primitive array `int[]`
+# * Java primitive array `long[]`
+# * Java primitive array `boolean[]`
+# * Java primitive array `char[]`
+
+# An `Iterator` on Java primitive arrays
+private class JavaArrayIterator[E: Object]
+       super IndexedIterator[E]
+
+       var array: AbstractJavaArray[E]
+
+       redef fun item do return array[index]
+
+       redef fun is_ok do return index < array.length
+
+       redef fun next do index += 1
+
+       redef var index = 0
+end
+
+# A reverse `Iterator` on Java primitive arrays
+private class JavaArrayReverseIterator[E: Object]
+       super IndexedIterator[E]
+
+       var array: AbstractJavaArray[E]
+
+       redef fun item do return array[index]
+
+       redef fun is_ok do return index >= 0
+
+       redef fun next do index -= 1
+
+       redef var index = array.length - 1
+end
index ebdd8b6..eb1061b 100644 (file)
@@ -29,7 +29,6 @@ in "C header" `{
        EGLConfig mnit_config;
        int32_t mnit_width;
        int32_t mnit_height;
-       float mnit_zoom;
 
        struct mnit_opengles_Texture {
                GLuint texture;
@@ -207,7 +206,6 @@ class Opengles1Display
                mnit_config = config;
                mnit_width = w;
                mnit_height = h;
-               mnit_zoom = 1.0f;
 
                LOGI("surface", (int)surface);
                LOGI("display", (int)display);
@@ -263,7 +261,6 @@ class Opengles1Display
                glMatrixMode(GL_PROJECTION);
                glLoadIdentity();
                glOrthof(x, x+w, y+h, y, 0.0f, 1.0f);
-               mnit_zoom = ((float)w)/mnit_width;
                glMatrixMode(GL_MODELVIEW);
                glFrontFace( GL_CW );
        `}
index 87afb4a..9d0d6c4 100644 (file)
 # limitations under the License.
 
 # Impements the services of `mnit:app` using the API from the Android ndk
-module android_app is
-       android_manifest_activity """
+module android_app is android_manifest_activity """
                android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
                android:configChanges="orientation|keyboardHidden"
-               android:screenOrientation="portrait""""
-end
+"""
 
 import mnit
 import android
 import mnit::opengles1
-
-in "C header" `{
-       #include <jni.h>
-       #include <errno.h>
-       #include <android/log.h>
-       #include <android_native_app_glue.h>
-
-       #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "mnit", __VA_ARGS__))
-       #ifdef DEBUG
-               #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "mnit", __VA_ARGS__))
-       #else
-               #define LOGI(...) (void)0
-       #endif
-`}
+intrude import ::android::input_events
 
 in "C" `{
        #include <EGL/egl.h>
-       #include <GLES/gl.h>
-       #define GL_GLEXT_PROTOTYPES 1
-       #include <GLES/glext.h>
-       #include <errno.h>
 
        extern EGLDisplay mnit_display;
        extern EGLSurface mnit_surface;
@@ -53,189 +34,28 @@ in "C" `{
        extern EGLConfig mnit_config;
        extern int32_t mnit_width;
        extern int32_t mnit_height;
-       extern float mnit_zoom;
-
-       //int mnit_orientation_changed;
-       float mnit_zoom;
-
-       /* Handle inputs from the Android platform and sort them before
-          sending them in the Nit App */
-       static int32_t mnit_handle_input(struct android_app* app, AInputEvent* event) {
-               App nit_app = app->userData;
-               LOGI("handle input %i", (int)pthread_self());
-               if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY) {
-                       LOGI("key");
-                       return App_extern_input_key(nit_app, event);
-               }
-               else if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
-                       LOGI("motion");
-                       return App_extern_input_motion(nit_app, event);
-               }
-
-               return 0;
-       }
 `}
 
-
-extern class InnerAndroidMotionEvent in "C" `{AInputEvent *`}
-       super Pointer
-       private fun pointers_count: Int is extern `{
-       return AMotionEvent_getPointerCount(recv);
-       `}
-       private fun just_went_down: Bool is extern `{
-       return (AMotionEvent_getAction(recv) & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_DOWN;
-       `}
-       private fun edge: Int is extern `{
-       return AMotionEvent_getEdgeFlags(recv);
-       `}
-       private fun index_down_pointer: Int is extern `{
-       int a = AMotionEvent_getAction(recv);
-       if ((a & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_POINTER_DOWN)
-               return (a & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
-       else return -1;
-       `}
-
-       private fun action: AMotionEventAction `{ return AMotionEvent_getAction(recv); `}
-end
-
-extern class AMotionEventAction `{ int32_t `}
-       protected fun action: Int `{ return recv & AMOTION_EVENT_ACTION_MASK; `}
-       fun is_down: Bool do return action == 0
-       fun is_up: Bool do return action == 1
-       fun is_move: Bool do return action == 2
-       fun is_cancel: Bool do return action == 3
-       fun is_outside: Bool do return action == 4
-       fun is_pointer_down: Bool do return action == 5
-       fun is_pointer_up: Bool do return action == 6
-end
-
-interface AndroidInputEvent
-       super InputEvent
-end
-
-class AndroidMotionEvent
-       super AndroidInputEvent
-       super MotionEvent
-
-       private init(ie: InnerAndroidMotionEvent) do inner_event = ie
-       private var inner_event: InnerAndroidMotionEvent
-
-       private var pointers_cache: nullable Array[AndroidPointerEvent] = null
-       fun pointers: Array[AndroidPointerEvent]
-       do
-               if pointers_cache != null then
-                       return pointers_cache.as(not null)
-               else
-                       var pointers = new Array[AndroidPointerEvent]
-                       var pointers_count = inner_event.pointers_count
-                       for i in [0 .. pointers_count [do
-                               var pointer_event = new AndroidPointerEvent(self, i)
-                               pointers.add(pointer_event)
-                       end
-                       pointers_cache = pointers
-                       return pointers
-               end
-       end
-
-       redef fun just_went_down: Bool do return inner_event.just_went_down
-       fun edge: Int do return inner_event.edge
-
-       redef fun down_pointer: nullable AndroidPointerEvent
-       do
-               var i = inner_event.index_down_pointer
-               if i > 0 then
-                       return pointers[i]
-               else
-                       return null
-               end
-       end
-end
-
-class AndroidPointerEvent
-       super PointerEvent
-       super AndroidInputEvent
-
-       protected var motion_event: AndroidMotionEvent
-       protected var pointer_id: Int
-
-       redef fun x: Float do return extern_x(motion_event.inner_event, pointer_id)
-       private fun extern_x(motion_event: InnerAndroidMotionEvent, pointer_id: Int): Float is extern `{
-               return ((int) AMotionEvent_getX(motion_event, pointer_id));
-       `}
-
-       redef fun y: Float do return extern_y(motion_event.inner_event, pointer_id)
-       private fun extern_y(motion_event: InnerAndroidMotionEvent, pointer_id: Int): Float is extern `{
-               return ((int) AMotionEvent_getY(motion_event, pointer_id));
-       `}
-
-       fun pressure: Float do return extern_pressure(motion_event.inner_event, pointer_id)
-       private fun extern_pressure(motion_event: InnerAndroidMotionEvent, pointer_id: Int): Float is extern `{
-               return AMotionEvent_getPressure(motion_event, pointer_id);
-       `}
-
-       redef fun pressed
-       do
-               var action = motion_event.inner_event.action
-               return action.is_down or action.is_move
-       end
-
-       redef fun depressed do return not pressed
-end
-
-extern class AndroidKeyEvent in "C" `{AInputEvent *`}
-       super KeyEvent
-       super AndroidInputEvent
-
-       fun action: Int is extern `{
-               return AKeyEvent_getAction(recv);
-       `}
-       redef fun is_down: Bool do return action == 0
-       redef fun is_up: Bool do return action == 1
-
-       fun key_code: Int is extern `{
-               return AKeyEvent_getKeyCode(recv);
-       `}
-
-       redef fun to_c `{
-               int code = AKeyEvent_getKeyCode(recv);
-               if (code >= AKEYCODE_0 && code <= AKEYCODE_9)
-                       return '0'+code-AKEYCODE_0;
-               if (code >= AKEYCODE_A && code <= AKEYCODE_Z)
-                       return 'a'+code-AKEYCODE_A;
-               return 0;
-       `}
-
-       fun is_back_key: Bool do return key_code == 4
-       fun is_menu_key: Bool do return key_code == 82
-       fun is_search_key: Bool do return key_code == 84
-
-       fun is_volume_up: Bool do return key_code == 24
-       fun is_volume_down: Bool do return key_code == 25
-end
-
 redef class App
        redef type D: Opengles1Display
 
        redef fun init_window
        do
-               set_as_input_handler native_app_glue
                display = new Opengles1Display
 
                super
        end
 
-       private fun set_as_input_handler(app_glue: NativeAppGlue) import extern_input_key, extern_input_motion `{
-               app_glue->onInputEvent = mnit_handle_input;
-       `}
-
        redef fun full_frame do if not paused then super
 
-       # these are used as a callback from native to type incoming events
-       private fun extern_input_key(event: AndroidKeyEvent): Bool
+       redef fun generate_input do poll_looper 0
+
+       redef fun native_input_key(event)
        do
                return input(event)
        end
-       private fun extern_input_motion(event: InnerAndroidMotionEvent): Bool
+
+       redef fun native_input_motion(event)
        do
                var ie = new AndroidMotionEvent(event)
                var handled = input(ie)
@@ -248,6 +68,4 @@ redef class App
 
                return handled
        end
-
-       redef fun generate_input do poll_looper 0
 end
index 4b73471..68f84e7 100644 (file)
@@ -281,6 +281,32 @@ class Array[E]
                _items[l] = item
        end
 
+       # Slight optimization for arrays
+       redef fun add_all(items)
+       do
+               var l = _length
+               var nl = l + items.length
+               if _capacity < nl then
+                       enlarge nl
+               end
+
+               if items isa Array[E] then
+                       var k = 0
+                       while l < nl do
+                               _items[l] = items._items[k]
+                               l += 1
+                               k += 1
+                       end
+               else
+                       for item in items do
+                               _items[l] = item
+                               l += 1
+                       end
+               end
+
+               _length = nl
+       end
+
        redef fun enlarge(cap)
        do
                var c = _capacity
@@ -348,10 +374,6 @@ class Array[E]
        # The internal storage.
        private var items: nullable NativeArray[E] = null
 
-       # Do not use this method
-       # FIXME: Remove it once modules can intrude non local modules
-       fun intern_items: NativeArray[E] do return _items.as(not null)
-
        # The size of `_items`.
        private var capacity: Int = 0
 
index c69ba64..317e909 100644 (file)
@@ -82,7 +82,7 @@ se_exec_data_t* exec_Process_Process_basic_exec_execute_4(void *s, char *prog, c
 
                /* calls */
                execvp(prog, arg);
-               abort();
+               _exit(127);
        }
        else if (id > 0)
                { /* father */
index 19653a3..882b645 100644 (file)
@@ -87,8 +87,8 @@ redef class ModelBuilder
        do
                var annotations = new Array[AAnnotation]
                for mmod in mmodule.in_importation.greaters do
-                       if not mmodule2nmodule.keys.has(mmod) then continue
-                       var amod = mmodule2nmodule[mmod]
+                       var amod = mmodule2node(mmod)
+                       if amod == null then continue
                        var module_decl = amod.n_moduledecl
                        if module_decl == null then continue
                        var aas = module_decl.get_annotations(name)
@@ -101,8 +101,8 @@ redef class ModelBuilder
        # Obviously, if there is no ast associated to `mmodule`, then nothing is returned.
        fun get_mmodule_annotation(name: String, mmodule: MModule): nullable AAnnotation
        do
-               if not mmodule2nmodule.keys.has(mmodule) then return null
-               var amod = mmodule2nmodule[mmodule]
+               var amod = mmodule2node(mmodule)
+               if amod == null then return null
                var module_decl = amod.n_moduledecl
                if module_decl == null then return null
                var res = module_decl.get_single_annotation(name, self)
index ddd7323..2312544 100644 (file)
@@ -481,6 +481,10 @@ abstract class AbstractCompiler
                self.realmainmodule = mainmodule
        end
 
+       # Do the full code generation of the program `mainmodule`
+       # It is the main method usually called after the instantiation
+       fun do_compilation is abstract
+
        # Force the creation of a new file
        # The point is to avoid contamination between must-be-compiled-separately files
        fun new_file(name: String): CodeFile
@@ -1458,10 +1462,11 @@ abstract class AbstractCompilerVisitor
                self.require_declaration(s)
        end
 
-       # look for a needed .h and .c file for a given .nit source-file
-       # FIXME: bad API, parameter should be a `MModule`, not its source-file
-       fun add_extern(file: String)
+       # Look for a needed .h and .c file for a given module
+       # This is used for the legacy FFI
+       fun add_extern(mmodule: MModule)
        do
+               var file = mmodule.location.file.filename
                file = file.strip_extension(".nit")
                var tryfile = file + ".nit.h"
                if tryfile.file_exists then
@@ -2151,16 +2156,13 @@ redef class AMethPropdef
        do
                var externname
                var at = self.get_single_annotation("extern", v.compiler.modelbuilder)
-               if at != null then
+               if at != null and at.n_args.length == 1 then
                        externname = at.arg_as_string(v.compiler.modelbuilder)
                        if externname == null then return false
                else
                        return false
                end
-               if location.file != null then
-                       var file = location.file.filename
-                       v.add_extern(file)
-               end
+               v.add_extern(mpropdef.mclassdef.mmodule)
                var res: nullable RuntimeVariable = null
                var ret = mpropdef.msignature.return_mtype
                if ret != null then
@@ -2192,10 +2194,7 @@ redef class AMethPropdef
                else
                        return false
                end
-               if location.file != null then
-                       var file = location.file.filename
-                       v.add_extern(file)
-               end
+               v.add_extern(mpropdef.mclassdef.mmodule)
                v.adapt_signature(mpropdef, arguments)
                v.unbox_signature_extern(mpropdef, arguments)
                var ret = arguments.first.mtype
index 1cf6ba8..5d6d312 100644 (file)
@@ -234,21 +234,22 @@ $(call import-module,android/native_app_glue)
                        end
                end
 
-               ### copy resources  (for android)
-               # This will be accessed from `android_project_root`
-               var res_dir
+               ### Copy resources and libs where expected by the SDK
+               var project_root
                if compiler.mainmodule.location.file != null then
                        # it is a real file, use "{file}/../res"
-                       res_dir = "{compiler.mainmodule.location.file.filename.dirname}/../res"
+                       project_root = "{compiler.mainmodule.location.file.filename.dirname}/.."
                else
                        # probably used -m, use "."
-                       res_dir = "res"
+                       project_root = "."
                end
+
+               # Android resources folder
+               var res_dir = project_root / "res"
                if res_dir.file_exists then
                        # copy the res folder to .nit_compile
                        res_dir = res_dir.realpath
-                       var target_res_dir = "{android_project_root}"
-                       toolcontext.exec_and_check(["cp", "-R", res_dir, target_res_dir], "Android project error")
+                       toolcontext.exec_and_check(["cp", "-R", res_dir, android_project_root], "Android project error")
                end
 
                if not res_dir.file_exists or not "{res_dir}/values/strings.xml".file_exists then
@@ -258,6 +259,12 @@ $(call import-module,android/native_app_glue)
     <string name="app_name">{{{app_name}}}</string>
 </resources>""".write_to_file "{dir}/res/values/strings.xml"
                end
+
+               # Android libs folder
+               var libs_dir = project_root / "libs"
+               if libs_dir.file_exists then
+                       toolcontext.exec_and_check(["cp", "-r", libs_dir, android_project_root], "Android project error")
+               end
        end
 
        redef fun write_makefile(compiler, compile_dir, cfiles)
index b6cb920..ca22005 100644 (file)
@@ -27,8 +27,7 @@ redef class MModule
 
        private fun nmodule(v: AbstractCompilerVisitor): nullable AModule
        do
-               var m2n = v.compiler.modelbuilder.mmodule2nmodule
-               return m2n.get_or_null(self)
+               return v.compiler.modelbuilder.mmodule2node(self)
        end
 
        redef fun finalize_ffi(compiler: AbstractCompiler)
@@ -100,7 +99,7 @@ redef class AMethPropdef
        do
                var mmodule = mpropdef.mclassdef.mmodule
                var mainmodule = v.compiler.mainmodule
-               var amodule = v.compiler.modelbuilder.mmodule2nmodule[mmodule]
+               var amodule = v.compiler.modelbuilder.mmodule2node(mmodule)
                var mclass_type = mpropdef.mclassdef.bound_mtype
 
                # Declare as extern
index edc3c80..7a0f162 100644 (file)
@@ -59,6 +59,43 @@ redef class ModelBuilder
                self.toolcontext.info("*** GENERATING C ***", 1)
 
                var compiler = new GlobalCompiler(mainmodule, self, runtime_type_analysis)
+               compiler.do_compilation
+               compiler.display_stats
+
+               var time1 = get_time
+               self.toolcontext.info("*** END GENERATING C: {time1-time0} ***", 2)
+               write_and_make(compiler)
+       end
+end
+
+# Compiler that use global compilation and perform hard optimisations like:
+#   * customization
+#   * switch dispatch
+#   * inlining
+class GlobalCompiler
+       super AbstractCompiler
+
+       redef type VISITOR: GlobalCompilerVisitor
+
+       # The result of the RTA (used to know live types and methods)
+       var runtime_type_analysis: RapidTypeAnalysis
+
+       init
+       do
+               var file = new_file("{mainmodule.c_name}.nitgg")
+               self.header = new CodeWriter(file)
+               self.live_primitive_types = new Array[MClassType]
+               for t in runtime_type_analysis.live_types do
+                       if t.ctype != "val*" or t.mclass.name == "Pointer" then
+                               self.live_primitive_types.add(t)
+                       end
+               end
+       end
+
+       redef fun do_compilation
+       do
+               var compiler = self
+
                compiler.compile_header
 
                if mainmodule.model.get_mclasses_by_name("Pointer") != null then
@@ -89,41 +126,11 @@ redef class ModelBuilder
                # Compile until all runtime_functions are visited
                while not compiler.todos.is_empty do
                        var m = compiler.todos.shift
-                       self.toolcontext.info("Compile {m} ({compiler.seen.length-compiler.todos.length}/{compiler.seen.length})", 3)
+                       modelbuilder.toolcontext.info("Compile {m} ({compiler.seen.length-compiler.todos.length}/{compiler.seen.length})", 3)
                        m.compile_to_c(compiler)
                end
-               self.toolcontext.info("Total methods to compile to C: {compiler.seen.length}", 2)
-
-               compiler.display_stats
-
-               var time1 = get_time
-               self.toolcontext.info("*** END GENERATING C: {time1-time0} ***", 2)
-               write_and_make(compiler)
-       end
-end
-
-# Compiler that use global compilation and perform hard optimisations like:
-#   * customization
-#   * switch dispatch
-#   * inlining
-class GlobalCompiler
-       super AbstractCompiler
-
-       redef type VISITOR: GlobalCompilerVisitor
-
-       # The result of the RTA (used to know live types and methods)
-       var runtime_type_analysis: RapidTypeAnalysis
+               modelbuilder.toolcontext.info("Total methods to compile to C: {compiler.seen.length}", 2)
 
-       init
-       do
-               var file = new_file("{mainmodule.c_name}.nitgg")
-               self.header = new CodeWriter(file)
-               self.live_primitive_types = new Array[MClassType]
-               for t in runtime_type_analysis.live_types do
-                       if t.ctype != "val*" or t.mclass.name == "Pointer" then
-                               self.live_primitive_types.add(t)
-                       end
-               end
        end
 
        # Compile class names (for the class_name and output_class_name methods)
@@ -434,7 +441,7 @@ class GlobalCompilerVisitor
                if args.first.mcasttype isa MNullableType or args.first.mcasttype isa MNullType and consider_null then
                        # The reciever is potentially null, so we have to 3 cases: ==, != or NullPointerException
                        self.add("if ({args.first} == NULL) \{ /* Special null case */")
-                       if m.name == "==" then
+                       if m.name == "==" or m.name == "is_same_instance" then
                                assert res != null
                                if args[1].mcasttype isa MNullableType then
                                        self.add("{res} = ({args[1]} == NULL);")
index 7bb2bc1..1f1cf67 100644 (file)
@@ -90,12 +90,55 @@ redef class ModelBuilder
                self.toolcontext.info("*** GENERATING C ***", 1)
 
                var compiler = new SeparateCompiler(mainmodule, self, runtime_type_analysis)
+               compiler.do_compilation
+               compiler.display_stats
+
+               var time1 = get_time
+               self.toolcontext.info("*** END GENERATING C: {time1-time0} ***", 2)
+               write_and_make(compiler)
+       end
+
+       # Count number of invocations by VFT
+       private var nb_invok_by_tables = 0
+       # Count number of invocations by direct call
+       private var nb_invok_by_direct = 0
+       # Count number of invocations by inlining
+       private var nb_invok_by_inline = 0
+end
+
+# Singleton that store the knowledge about the separate compilation process
+class SeparateCompiler
+       super AbstractCompiler
+
+       redef type VISITOR: SeparateCompilerVisitor
+
+       # The result of the RTA (used to know live types and methods)
+       var runtime_type_analysis: nullable RapidTypeAnalysis
+
+       private var undead_types: Set[MType] = new HashSet[MType]
+       private var live_unresolved_types: Map[MClassDef, Set[MType]] = new HashMap[MClassDef, HashSet[MType]]
+
+       private var type_ids: Map[MType, Int] is noinit
+       private var type_colors: Map[MType, Int] is noinit
+       private var opentype_colors: Map[MType, Int] is noinit
+       protected var method_colors: Map[PropertyLayoutElement, Int] is noinit
+       protected var attr_colors: Map[MAttribute, Int] is noinit
+
+       init do
+               var file = new_file("nit.common")
+               self.header = new CodeWriter(file)
+               self.compile_box_kinds
+       end
+
+       redef fun do_compilation
+       do
+               var compiler = self
                compiler.compile_header
 
                var c_name = mainmodule.c_name
 
                # compile class structures
-               self.toolcontext.info("Property coloring", 2)
+               modelbuilder.toolcontext.info("Property coloring", 2)
                compiler.new_file("{c_name}.classes")
                compiler.do_property_coloring
                for m in mainmodule.in_importation.greaters do
@@ -113,14 +156,22 @@ redef class ModelBuilder
 
                # compile methods
                for m in mainmodule.in_importation.greaters do
-                       self.toolcontext.info("Generate C for module {m.full_name}", 2)
+                       modelbuilder.toolcontext.info("Generate C for module {m.full_name}", 2)
                        compiler.new_file("{m.c_name}.sep")
                        compiler.compile_module_to_c(m)
                end
 
                # compile live & cast type structures
-               self.toolcontext.info("Type coloring", 2)
+               modelbuilder.toolcontext.info("Type coloring", 2)
                compiler.new_file("{c_name}.types")
+               compiler.compile_types
+       end
+
+       # Color and compile type structures and cast information
+       fun compile_types
+       do
+               var compiler = self
+
                var mtypes = compiler.do_type_coloring
                for t in mtypes do
                        compiler.compile_type_to_c(t)
@@ -131,43 +182,6 @@ redef class ModelBuilder
                        compiler.compile_type_to_c(t)
                end
 
-               compiler.display_stats
-
-               var time1 = get_time
-               self.toolcontext.info("*** END GENERATING C: {time1-time0} ***", 2)
-               write_and_make(compiler)
-       end
-
-       # Count number of invocations by VFT
-       private var nb_invok_by_tables = 0
-       # Count number of invocations by direct call
-       private var nb_invok_by_direct = 0
-       # Count number of invocations by inlining
-       private var nb_invok_by_inline = 0
-end
-
-# Singleton that store the knowledge about the separate compilation process
-class SeparateCompiler
-       super AbstractCompiler
-
-       redef type VISITOR: SeparateCompilerVisitor
-
-       # The result of the RTA (used to know live types and methods)
-       var runtime_type_analysis: nullable RapidTypeAnalysis
-
-       private var undead_types: Set[MType] = new HashSet[MType]
-       private var live_unresolved_types: Map[MClassDef, Set[MType]] = new HashMap[MClassDef, HashSet[MType]]
-
-       private var type_ids: Map[MType, Int] is noinit
-       private var type_colors: Map[MType, Int] is noinit
-       private var opentype_colors: Map[MType, Int] is noinit
-       protected var method_colors: Map[PropertyLayoutElement, Int] is noinit
-       protected var attr_colors: Map[MAttribute, Int] is noinit
-
-       init do
-               var file = new_file("nit.common")
-               self.header = new CodeWriter(file)
-               self.compile_box_kinds
        end
 
        redef fun compile_header_structs do
@@ -1063,8 +1077,8 @@ class SeparateCompilerVisitor
        do
                var rta = compiler.runtime_type_analysis
                var mmethod = callsite.mproperty
-               # TODO: Inlining of new-style constructors
-               if compiler.modelbuilder.toolcontext.opt_direct_call_monomorph.value and rta != null and not mmethod.is_root_init then
+               # TODO: Inlining of new-style constructors with initializers
+               if compiler.modelbuilder.toolcontext.opt_direct_call_monomorph.value and rta != null and callsite.mpropdef.initializers.is_empty then
                        var tgs = rta.live_targets(callsite)
                        if tgs.length == 1 then
                                # DIRECT CALL
@@ -1112,10 +1126,10 @@ class SeparateCompilerVisitor
                var res: nullable RuntimeVariable = null
                var recv = arguments.first
                var consider_null = not self.compiler.modelbuilder.toolcontext.opt_no_check_null.value or mmethod.name == "==" or mmethod.name == "!="
-               var maybenull = recv.mcasttype isa MNullableType and consider_null
+               var maybenull = (recv.mcasttype isa MNullableType or recv.mcasttype isa MNullType) and consider_null
                if maybenull then
                        self.add("if ({recv} == NULL) \{")
-                       if mmethod.name == "==" then
+                       if mmethod.name == "==" or mmethod.name == "is_same_instance" then
                                res = self.new_var(bool_type)
                                var arg = arguments[1]
                                if arg.mcasttype isa MNullableType then
@@ -1142,15 +1156,15 @@ class SeparateCompilerVisitor
                else
                        self.add("\{")
                end
-               if not self.compiler.modelbuilder.toolcontext.opt_no_shortcut_equate.value and (mmethod.name == "==" or mmethod.name == "!=") then
-                       if res == null then res = self.new_var(bool_type)
-                       # Recv is not null, thus is arg is, it is easy to conclude (and respect the invariants)
+               if not self.compiler.modelbuilder.toolcontext.opt_no_shortcut_equate.value and (mmethod.name == "==" or mmethod.name == "!=" or mmethod.name == "is_same_instance") then
+                       # Recv is not null, thus if arg is, it is easy to conclude (and respect the invariants)
                        var arg = arguments[1]
                        if arg.mcasttype isa MNullType then
-                               if mmethod.name == "==" then
-                                       self.add("{res} = 0; /* arg is null but recv is not */")
-                               else
+                               if res == null then res = self.new_var(bool_type)
+                               if mmethod.name == "!=" then
                                        self.add("{res} = 1; /* arg is null and recv is not */")
+                               else # `==` and `is_same_instance`
+                                       self.add("{res} = 0; /* arg is null but recv is not */")
                                end
                                self.add("\}") # closes the null case
                                self.add("if (0) \{") # what follow is useless, CC will drop it
index 233bf54..8a33265 100644 (file)
@@ -65,35 +65,8 @@ redef class ModelBuilder
                self.toolcontext.info("*** GENERATING C ***", 1)
 
                var compiler = new SeparateErasureCompiler(mainmodule, self, runtime_type_analysis)
-               compiler.compile_header
-
-               var c_name = mainmodule.c_name
-
-               # compile class structures
-               self.toolcontext.info("Property coloring", 2)
-               compiler.new_file("{c_name}.tables")
-               compiler.do_property_coloring
-               for m in mainmodule.in_importation.greaters do
-                       for mclass in m.intro_mclasses do
-                               compiler.compile_class_to_c(mclass)
-                       end
-               end
-               compiler.compile_color_consts(compiler.vt_colors)
-
-               # The main function of the C
-               compiler.new_file("{c_name}.main")
-               compiler.compile_nitni_global_ref_functions
-               compiler.compile_main_function
-
-               # compile methods
-               for m in mainmodule.in_importation.greaters do
-                       self.toolcontext.info("Generate C for module {m.full_name}", 2)
-                       compiler.new_file("{m.c_name}.sep")
-                       compiler.compile_module_to_c(m)
-               end
-
+               compiler.do_compilation
                compiler.display_stats
-
                var time1 = get_time
                self.toolcontext.info("*** END GENERATING C: {time1-time0} ***", 2)
                write_and_make(compiler)
@@ -298,7 +271,7 @@ class SeparateErasureCompiler
                        self.header.add_decl("\};")
 
                        #Build BOX
-                       self.provide_declaration("BOX_{c_name}", "val* BOX_{c_name}({mtype.ctype});")
+                       self.provide_declaration("BOX_{c_name}", "val* BOX_{c_name}({mtype.ctype_extern});")
                        v.add_decl("/* allocate {mtype} */")
                        v.add_decl("val* BOX_{mtype.c_name}({mtype.ctype} value) \{")
                        v.add("struct instance_{c_name}*res = nit_alloc(sizeof(struct instance_{c_name}));")
@@ -435,6 +408,11 @@ class SeparateErasureCompiler
                end
        end
 
+       redef fun compile_types
+       do
+               compile_color_consts(vt_colors)
+       end
+
        redef fun new_visitor do return new SeparateErasureCompilerVisitor(self)
 
        # Stats
index fc556d6..f8a1250 100644 (file)
@@ -543,8 +543,8 @@ abstract class NitdocPage
                                redef_article.title_classes.add "signature info"
                                redef_article.css_classes.add "nospace"
                                var redef_content = new Template
-                               if mpropdef.mdoc_or_fallback != null then
-                                       redef_content.add mpropdef.mdoc_or_fallback.tpl_comment
+                               if mpropdef.mdoc != null then
+                                       redef_content.add mpropdef.mdoc.tpl_comment
                                end
                                redef_article.content = redef_content
                                subarticle.add_child redef_article
index 485ba1f..10c1db3 100644 (file)
@@ -58,8 +58,8 @@ redef class MModule
                        end
 
                        # does the super module itself has extern dependancies?
-                       var amodule = v.toolcontext.modelbuilder.mmodule2nmodule[m]
-                       if amodule.has_public_c_header then header_dependencies.add(m)
+                       var amodule = v.toolcontext.modelbuilder.mmodule2node(m)
+                       if amodule != null and amodule.has_public_c_header then header_dependencies.add(m)
                end
 
                header_dependencies_cache = header_dependencies
index 9191141..1fa56e9 100644 (file)
@@ -518,6 +518,35 @@ redef class MClassType
                                else break
                        end
 
+                       # Change `float[]` to `[float`
+                       if jni_type.has('[') then
+                               var depth = jni_type.chars.count('[')
+                               var java_type = jni_type.replace("[]", "")
+                               var short
+
+                               if java_type == "boolean" then
+                                       short = "Z"
+                               else if java_type == "byte" then
+                                       short = "B"
+                               else if java_type == "char" then
+                                       short = "C"
+                               else if java_type == "short" then
+                                       short = "S"
+                               else if java_type == "int" then
+                                       short = "I"
+                               else if java_type == "long" then
+                                       short = "J"
+                               else if java_type == "float" then
+                                       short = "F"
+                               else if java_type == "double" then
+                                       short = "D"
+                               else
+                                       short = "L{java_type};"
+                               end
+
+                               return "["*depth + short
+                       end
+
                        return "L{jni_type};"
                end
                if mclass.name == "Bool" then return "Z"
@@ -530,6 +559,7 @@ redef class MClassType
        redef fun jni_signature_alt
        do
                var ftype = mclass.ftype
+
                if ftype isa ForeignJavaType then return "Object"
                if mclass.name == "Bool" then return "Boolean"
                if mclass.name == "Char" then return "Char"
index 3c31b65..931440e 100644 (file)
@@ -32,20 +32,25 @@ private class NoWarningPhase
                var mmodule = nmodule.mmodule
                assert mmodule != null
 
+               var source = nmodule.location.file
+
                # If no decl block then quit
                var nmoduledecl = nmodule.n_moduledecl
-               if nmoduledecl == null then return
+               if nmoduledecl == null then
+                       # Disable `missing-doc` if there is no `module` clause
+                       # Rationale: the presence of a `module` clause is a good heuristic to
+                       # discriminate quick and dirty prototypes from nice and clean modules
+                       if source != null then toolcontext.warning_blacklist[source].add("missing-doc")
+                       return
+               end
 
                var modelbuilder = toolcontext.modelbuilder
 
-               var source = nmodule.location.file
-
                # Disable `missing-doc` for `test_suite`
                if source != null and not nmoduledecl.get_annotations("test_suite").is_empty then
                        toolcontext.warning_blacklist[source].add("missing-doc")
                end
 
-
                # Get all the `no_warning` annotations
                var name = "no_warning"
                var annots = nmoduledecl.get_annotations(name)
index 4bbe635..5cc3892 100644 (file)
@@ -458,7 +458,7 @@ class NaiveInterpreter
        fun send_commons(mproperty: MMethod, args: Array[Instance], mtype: MType): nullable Instance
        do
                if mtype isa MNullType then
-                       if mproperty.name == "==" then
+                       if mproperty.name == "==" or mproperty.name == "is_same_instance" then
                                return self.bool_instance(args[0] == args[1])
                        else if mproperty.name == "!=" then
                                return self.bool_instance(args[0] != args[1])
index 6c5bbf6..58d3506 100644 (file)
@@ -88,6 +88,61 @@ redef class ModelBuilder
                return mmodules.to_a
        end
 
+       # Load recursively all modules of the group `mgroup`.
+       # See `parse` for details.
+       fun parse_group(mgroup: MGroup): Array[MModule]
+       do
+               var res = new Array[MModule]
+               visit_group(mgroup)
+               for mg in mgroup.in_nesting.smallers do
+                       for mp in mg.module_paths do
+                               var nmodule = self.load_module(mp.filepath)
+                               if nmodule == null then continue # Skip error
+                               # Load imported module
+                               build_module_importation(nmodule)
+
+                               res.add(nmodule.mmodule.as(not null))
+                       end
+               end
+               return res
+       end
+
+       # Load a bunch of modules and groups.
+       # Each name can be a module or a group.
+       # If it is a group then recursively all its modules are parsed.
+       # See `parse` for details.
+       fun parse_full(names: Sequence[String]): Array[MModule]
+       do
+               var time0 = get_time
+               # Parse and recursively load
+               self.toolcontext.info("*** PARSE ***", 1)
+               var mmodules = new ArraySet[MModule]
+               for a in names do
+                       var mgroup = self.get_mgroup(a)
+                       if mgroup != null then
+                               mmodules.add_all parse_group(mgroup)
+                               continue
+                       end
+                       var nmodule = self.load_module(a)
+                       if nmodule == null then continue # Skip error
+                       # Load imported module
+                       build_module_importation(nmodule)
+
+                       mmodules.add(nmodule.mmodule.as(not null))
+               end
+               var time1 = get_time
+               self.toolcontext.info("*** END PARSE: {time1-time0} ***", 2)
+
+               self.toolcontext.check_errors
+
+               if toolcontext.opt_only_parse.value then
+                       self.toolcontext.info("*** ONLY PARSE...", 1)
+                       exit(0)
+               end
+
+               return mmodules.to_a
+       end
+
        # The list of directories to search for top level modules
        # The list is initially set with:
        #
@@ -446,9 +501,7 @@ redef class ModelBuilder
        do
                # Check the module name
                var decl = nmodule.n_moduledecl
-               if decl == null then
-                       #warning(nmodule, "Warning: Missing 'module' keyword") #FIXME: NOT YET FOR COMPATIBILITY
-               else
+               if decl != null then
                        var decl_name = decl.n_name.n_id.text
                        if decl_name != mod_name then
                                error(decl.n_name, "Error: module name missmatch; declared {decl_name} file named {mod_name}")
@@ -564,8 +617,18 @@ redef class ModelBuilder
        var nmodules = new Array[AModule]
 
        # Register the nmodule associated to each mmodule
-       # FIXME: why not refine the `MModule` class with a nullable attribute?
-       var mmodule2nmodule = new HashMap[MModule, AModule]
+       #
+       # Public clients need to use `mmodule2node` to access stuff.
+       private var mmodule2nmodule = new HashMap[MModule, AModule]
+
+       # Retrieve the associated AST node of a mmodule.
+       # This method is used to associate model entity with syntactic entities.
+       #
+       # If the module is not associated with a node, returns null.
+       fun mmodule2node(mmodule: MModule): nullable AModule
+       do
+               return mmodule2nmodule.get_or_null(mmodule)
+       end
 end
 
 # File-system location of a module (file) that is identified but not always loaded.
index b38bdac..30f5885 100644 (file)
@@ -86,7 +86,7 @@ redef class ModelBuilder
                model.mmodule_importation_hierarchy.sort(mmodules)
                var nmodules = new Array[AModule]
                for mm in mmodules do
-                       nmodules.add(mmodule2nmodule[mm])
+                       nmodules.add(mmodule2node(mm).as(not null))
                end
                toolcontext.run_phases(nmodules)
 
index 470afb2..8a49296 100644 (file)
@@ -295,9 +295,8 @@ redef class ModelBuilder
                nmodule.build_classes_is_done = true
                var mmodule = nmodule.mmodule.as(not null)
                for imp in mmodule.in_importation.direct_greaters do
-
-                       if not mmodule2nmodule.has_key(imp) then continue
-                       build_classes(mmodule2nmodule[imp])
+                       var nimp = mmodule2node(imp)
+                       if nimp != null then build_classes(nimp)
                end
 
                if errcount != toolcontext.error_count then return
index 01c0166..d8fd96d 100644 (file)
@@ -45,11 +45,16 @@ redef class ModelBuilder
        # Retrieve the associated AST node of a mpropertydef.
        # This method is used to associate model entity with syntactic entities.
        #
-       # If the property definition is not associated with a node, returns node.
+       # If the property definition is not associated with a node, returns `null`.
        fun mpropdef2node(mpropdef: MPropDef): nullable ANode
        do
-               var res: nullable ANode = mpropdef2npropdef.get_or_null(mpropdef)
-               if res != null then return res
+               var res
+               res = mpropdef2npropdef.get_or_null(mpropdef)
+               if res != null then
+                       # Run the phases on it
+                       toolcontext.run_phases_on_npropdef(res)
+                       return res
+               end
                if mpropdef isa MMethodDef and mpropdef.mproperty.is_root_init then
                        res = mclassdef2nclassdef.get_or_null(mpropdef.mclassdef)
                        if res != null then return res
@@ -66,6 +71,8 @@ redef class ModelBuilder
                if n == null then return res
                for npropdef in n.n_propdefs do
                        if npropdef isa AAttrPropdef then
+                               # Run the phases on it
+                               toolcontext.run_phases_on_npropdef(npropdef)
                                res.add(npropdef)
                        end
                end
index 02f3bb1..c1a4851 100644 (file)
@@ -41,7 +41,7 @@ var arguments = toolcontext.option_context.rest
 # build model
 var model = new Model
 var mbuilder = new ModelBuilder(model, toolcontext)
-var mmodules = mbuilder.parse(arguments)
+var mmodules = mbuilder.parse_full(arguments)
 
 if mmodules.is_empty then return
 mbuilder.run_phases
index cc35b10..0c8998b 100644 (file)
@@ -41,7 +41,7 @@ var modelbuilder = new ModelBuilder(model, toolcontext)
 
 var args = toolcontext.option_context.rest
 
-var mmodules = modelbuilder.parse(args)
+var mmodules = modelbuilder.parse_full(args)
 modelbuilder.run_phases
 
 if opt_full.value then mmodules = model.mmodules
@@ -67,7 +67,8 @@ for mm in mmodules do
        if opt_last_line.value != 0 then v.last_line = opt_last_line.value
        if opt_ast.value then v.with_ast = true
        var page = null
-       var m = modelbuilder.mmodule2nmodule[mm]
+       var m = modelbuilder.mmodule2node(mm)
+       assert m != null
        if not opt_fragment.value then
                page = new HTMLTag("html")
                page.add_raw_html """<head>
index ee8b827..3925360 100644 (file)
@@ -36,7 +36,7 @@ var model = new Model
 var modelbuilder = new ModelBuilder(model, toolcontext)
 
 # Here we load an process all modules passed on the command line
-var mmodules = modelbuilder.parse(arguments)
+var mmodules = modelbuilder.parse_full(arguments)
 modelbuilder.run_phases
 
 print "*** METRICS ***"
index c7664a9..57bbce3 100644 (file)
@@ -46,7 +46,7 @@ var model = new Model
 var modelbuilder = new ModelBuilder(model, toolcontext)
 
 # Here we load an process all modules passed on the command line
-var mmodules = modelbuilder.parse(arguments)
+var mmodules = modelbuilder.parse_full(arguments)
 toolcontext.mmodules_to_check.add_all mmodules
 
 modelbuilder.run_phases
index 7ff0b16..af3fae0 100644 (file)
@@ -82,12 +82,11 @@ if not dir.file_exists then dir.mkdir
 var v = new PrettyPrinterVisitor
 
 for mmodule in mmodules do
-       if not mbuilder.mmodule2nmodule.has_key(mmodule) then
+       var nmodule = mbuilder.mmodule2node(mmodule)
+       if nmodule == null then
                print " Error: no source file for module {mmodule}"
                return
        end
-
-       var nmodule = mbuilder.mmodule2nmodule[mmodule]
        var file = "{dir}/{mmodule.name}.nit"
        var tpl = v.pretty_nmodule(nmodule)
        tpl.write_to_file file
index 2fd0f82..4953156 100644 (file)
@@ -127,7 +127,7 @@ end
 var model = new Model
 var modelbuilder = new ModelBuilder(model, toolcontext)
 
-var mmodules = modelbuilder.parse(arguments)
+var mmodules = modelbuilder.parse_full(arguments)
 modelbuilder.run_phases
 
 # Create a distinct support module per targetted modules
index 04cb4b3..9ea9048 100644 (file)
@@ -51,7 +51,7 @@ var arguments = toolcontext.option_context.rest
 # build model
 var model = new Model
 var mbuilder = new ModelBuilder(model, toolcontext)
-var mmodules = mbuilder.parse(arguments)
+var mmodules = mbuilder.parse_full(arguments)
 
 if mmodules.is_empty then return
 mbuilder.run_phases
index c057beb..7969f29 100644 (file)
@@ -53,7 +53,7 @@ end
 var model = new Model
 var modelbuilder = new ModelBuilder(model, toolcontext)
 
-var mmodules = modelbuilder.parse(args)
+var mmodules = modelbuilder.parse_full(args)
 modelbuilder.run_phases
 
 if toolcontext.opt_gen_unit.value then
index 5729313..1a10cf2 100644 (file)
@@ -30,11 +30,14 @@ redef class ToolContext
        # --disable-phase
        var opt_disable_phase = new OptionArray("DEBUG: Disable a specific phase; use `list` to get the list.", "--disable-phase")
 
+       # --disable-phase
+       var opt_sloppy = new OptionBool("DEBUG: force lazy semantic analysis of the source-code", "--sloppy")
+
        redef init
        do
                super
 
-               option_context.add_option(opt_disable_phase)
+               option_context.add_option(opt_disable_phase, opt_sloppy)
        end
 
        redef fun process_options(args)
@@ -62,16 +65,24 @@ redef class ToolContext
                        end
                        if not found then fatal_error(null, "Error: no phase named `{v}`. Use `list` to list all phases.")
                end
+
+               if opt_sloppy.value then semantize_is_lazy = true
        end
 
        # The list of registered phases in the application order.
-       fun phases_list: Sequence[Phase]
-       do
+       var phases_list: Sequence[Phase] is lazy do
                var phases = self.phases.to_a
                self.phases.sort(phases)
                return phases
        end
 
+       # Is `phase_process_npropdef` not called automatically by `run_phases`?
+       #
+       # When set to true, it is the responsibility of the tools
+       #
+       # Is false by default.
+       var semantize_is_lazy = false is writable
+
        # Set of already analyzed modules.
        private var phased_modules = new HashSet[AModule]
 
@@ -111,7 +122,7 @@ redef class ToolContext
                                for nclassdef in nmodule.n_classdefs do
                                        assert phase.toolcontext == self
                                        phase.process_nclassdef(nclassdef)
-                                       for npropdef in nclassdef.n_propdefs do
+                                       if not semantize_is_lazy then for npropdef in nclassdef.n_propdefs do
                                                assert phase.toolcontext == self
                                                phase_process_npropdef(phase, npropdef)
                                        end
@@ -143,6 +154,31 @@ redef class ToolContext
        do
                phase.process_npropdef(npropdef)
        end
+
+       # Run the phase on the given npropdef.
+       # Does nothing if `semantize_is_lazy` is false.
+       fun run_phases_on_npropdef(npropdef: APropdef)
+       do
+               if not semantize_is_lazy then return
+               if npropdef.is_phased then return
+               npropdef.is_phased = true
+
+               #self.info("Semantic analysis of property {npropdef.location.file.filename}", 0)
+
+               var phases = phases_list
+               for phase in phases do
+                       if phase.disabled then continue
+                       assert phase.toolcontext == self
+                       phase_process_npropdef(phase, npropdef)
+                       self.check_errors
+               end
+       end
+end
+
+redef class APropdef
+       # Is the propdef already analyzed by `run_phases_on_npropdef`.
+       # Unused unless `semantize_is_lazy` is true.
+       private var is_phased = false
 end
 
 # Collect all annotation
index 7881db0..2d9fee4 100644 (file)
@@ -87,8 +87,7 @@ class RapidTypeAnalysis
                var anchor = callsite.anchor
                if anchor != null then mtype = mtype.anchor_to(callsite.mmodule, anchor)
                mtype = mtype.as_notnullable
-               assert mtype isa MClassType
-               mtype = mtype.mclass.intro.bound_mtype
+               if mtype isa MClassType then mtype = mtype.mclass.intro.bound_mtype
                var mproperty = callsite.mproperty
                var res = live_targets_cache[mtype, mproperty]
                if res != null then return res
index 1dfaec6..ae697d4 100644 (file)
@@ -266,8 +266,13 @@ private class TypeVisitor
 
                #debug("recv: {recvtype} (aka {unsafe_type})")
                if recvtype isa MNullType then
-                       self.error(node, "Error: Method '{name}' call on 'null'.")
-                       return null
+                       # `null` only accepts some methods of object.
+                       if name == "==" or name == "!=" or name == "is_same_instance" then
+                               unsafe_type = mmodule.object_type.as_nullable
+                       else
+                               self.error(node, "Error: Method '{name}' call on 'null'.")
+                               return null
+                       end
                end
 
                var mproperty = self.try_get_mproperty_by_name2(node, unsafe_type, name)
@@ -756,11 +761,6 @@ redef class AReassignFormExpr
 
                self.read_type = readtype
 
-               if readtype isa MNullType then
-                       v.error(self, "Error: Method '{reassign_name}' call on 'null'.")
-                       return null
-               end
-
                var callsite = v.get_method(self, readtype, reassign_name, false)
                if callsite == null then return null # Skip error
                self.reassign_callsite = callsite
@@ -1243,7 +1243,7 @@ redef class AArrayExpr
                if mtype == null then
                        mtype = v.merge_types(self, mtypes)
                end
-               if mtype == null then
+               if mtype == null or mtype isa MNullType then
                        v.error(self, "Type Error: ambiguous array type {mtypes.join(" ")}")
                        return
                end
@@ -1407,10 +1407,6 @@ redef class ASendExpr
                var name = self.property_name
 
                if recvtype == null then return # Forward error
-               if recvtype isa MNullType then
-                       v.error(self, "Error: Method '{name}' call on 'null'.")
-                       return
-               end
 
                var callsite = v.get_method(self, recvtype, name, self.n_expr isa ASelfExpr)
                if callsite == null then return
@@ -1554,10 +1550,6 @@ redef class ASendReassignFormExpr
                var name = self.property_name
 
                if recvtype == null then return # Forward error
-               if recvtype isa MNullType then
-                       v.error(self, "Error: Method '{name}' call on 'null'.")
-                       return
-               end
 
                var for_self = self.n_expr isa ASelfExpr
                var callsite = v.get_method(self, recvtype, name, for_self)
index f0b8102..e975d85 100644 (file)
@@ -318,9 +318,9 @@ redef class ModelBuilder
        do
                var ts = new HTMLTag("testsuite")
                toolcontext.info("nitunit: doc-unit {mmodule}", 2)
-               if not mmodule2nmodule.has_key(mmodule) then return ts
 
-               var nmodule = mmodule2nmodule[mmodule]
+               var nmodule = mmodule2node(mmodule)
+               if nmodule == null then return ts
 
                # usualy, only the original module must be imported in the unit test.
                var o = mmodule
index f37dd3a..3071768 100644 (file)
@@ -25,3 +25,4 @@ for i in a do
 end
 
 #alt1# var b = [10, true]
+#alt2# var c = [null, null]
diff --git a/tests/base_null.nit b/tests/base_null.nit
new file mode 100644 (file)
index 0000000..78f362a
--- /dev/null
@@ -0,0 +1,42 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import kernel
+
+class A
+       redef fun output do 10.output
+end
+
+var a: Object = new A
+var na: nullable Object = new A
+var nn: nullable Object = null
+
+(null == a).output
+(null == na).output
+(null == nn).output
+(null == null).output
+
+'\n'.output
+
+null.is_same_instance(a).output
+null.is_same_instance(na).output
+null.is_same_instance(nn).output
+null.is_same_instance(null).output
+
+'\n'.output
+
+(null != a).output
+(null != na).output
+(null != nn).output
+(null != null).output
diff --git a/tests/bench_add_all.nit b/tests/bench_add_all.nit
new file mode 100644 (file)
index 0000000..733ac9b
--- /dev/null
@@ -0,0 +1,30 @@
+# 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.
+
+# Performance test for Array::add_all
+
+import standard::collection
+
+var a = new Array[Numeric]
+var b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+for i in 10000.times do
+       a.add_all b
+end
+
+var c = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]
+for i in 10000.times do
+       a.add_all c
+end
+
+a.length.output
diff --git a/tests/sav/base_array_alt2.res b/tests/sav/base_array_alt2.res
new file mode 100644 (file)
index 0000000..e9c5053
--- /dev/null
@@ -0,0 +1 @@
+alt/base_array_alt2.nit:28,9--20: Type Error: ambiguous array type null null
diff --git a/tests/sav/base_null.res b/tests/sav/base_null.res
new file mode 100644 (file)
index 0000000..80acf2a
--- /dev/null
@@ -0,0 +1,16 @@
+base_null.nit:28,2--13: Warning: expression is not null, since it is a `null`.
+base_null.nit:42,2--13: Warning: expression is not null, since it is a `null`.
+false
+false
+true
+true
+
+false
+false
+true
+true
+
+true
+true
+false
+false
diff --git a/tests/sav/bench_add_all.res b/tests/sav/bench_add_all.res
new file mode 100644 (file)
index 0000000..87766d8
--- /dev/null
@@ -0,0 +1 @@
+200000
index 63c96c0..2251e01 100644 (file)
@@ -1,2 +1 @@
-Caught signal : Aborted
 alt/error_annot_c_compiler_alt5.nit:21,57--79: Annotation error: Something went wrong executing the argument of annotation "c_compiler_option", make sure the command is valid.
index 2f109dd..3647533 100644 (file)
@@ -1,3 +1,14 @@
 A hello world!
+0
+
+B hello world!0
+
 C hello world!
-B hello world!D hello world!
\ No newline at end of file
+0
+
+D hello world!0
+
+E
+1
+
+127
index c4db140..d21eb0d 100644 (file)
@@ -1,4 +1,4 @@
-Runtime error: Cast failed. Expected `E`, got `Bool` (../lib/standard/collection/array.nit:786)
+Runtime error: Cast failed. Expected `E`, got `Bool` (../lib/standard/collection/array.nit:808)
 NativeString
 N
 Nit
index 4a1a749..da3bf84 100644 (file)
@@ -18,19 +18,43 @@ import exec
 
 var hw = new Process("echo", "A", "hello", "world!")
 hw.wait
+print hw.status
+
+print ""
 
 var ip = new IProcess("echo", "B hello world!")
 ip.read_line.output
 ip.wait
+print ip.status
+
+print ""
 
 var op = new OProcess.from_a("cat", null)
 op.write("C hello world!\n")
 op.close
 op.wait
+print op.status
+
+print ""
 
 var iop = new IOProcess.from_a("cat", null)
 iop.write("D hello world!\n")
 iop.read_line.output
 iop.close
 iop.wait
+print iop.status
+
+print ""
+
+var e1 = new Process("sh", "-c", "echo E; exit 1")
+e1.wait
+print e1.status
+
+print ""
 
+var ioperr = new IOProcess.from_a("bad command", null)
+ioperr.write("D hello world!\n")
+ioperr.read_line.output
+ioperr.close
+ioperr.wait
+print ioperr.status