Better implementation for `full_name` and `c_name` that make them shorter and use the project as the namespace of public entities.
Examples of fullnames of entities used in messages
* A public class `A` defined in the module `m` of the project `p` was `p::m::A`, now it is `p::A`.
* A public method `x` defined in a class `A` in the module `m` of the project `p` was `p::m::A::x`, now it is `p::A::x`
Exeaple of fullnames for entities that are used internally:
* The refinement of `A` in a module `p::n` was `p::n#p::m::A`, now it is `p::n#A`
* The redefinition of `x` in a class `B` in `p::n` was `p::n#p::m::B#p::m::A::x`, now it is `p::n#B#A::x`
The `c_name` get some comparable simplifications, so C identifiers will be simpler and will less overflow in unwind or in valgrind.
Note: please ignore the first commits that come from #1069
Pull-Request: #1092
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>
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
../../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:
../../bin/nitdoc -d doc/ src/friendz.nit src/friendz_linux.nit
clean:
- rm -rf bin/ doc/
+ rm -rf bin/ doc/ res/
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/
--- /dev/null
+<?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>
import realtime
import solver
import mnit::tileset
+import app::data_store
+import md5
intrude import grid
intrude import level
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
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
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
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
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
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
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
-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
-# 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 :
`-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`
* 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)
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 '[]'*;
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? ';';
# Services to generate extern class `in "Java"`
module code_generator
-intrude import types
+intrude import model
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
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 = ""
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
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}"
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
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")
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 = ""
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
import javap_test_parser
import code_generator
import jtype_converter
-intrude import types
+intrude import model
class JavaVisitor
super Visitor
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
end
end
-# Constructor declaration in the field declarations
+# Constructor declaration
redef class Nconstructor_declaration
redef fun accept_visitor(v)
do
end
end
-# Variable declaration in the field declarations
+# Variable property declaration
redef class Nvariable_declaration
redef fun accept_visitor(v)
do
end
end
-# Static declaration in the field declarations
+# Static property declaration
redef class Nstatic_declaration
redef fun accept_visitor(v)
do
end
end
-# Identifier of the field
+# Identifier of a variable
redef class Nvariable_id
redef fun accept_visitor(v)
do
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)
# 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
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
end
if not self.has_generic_params then return nit_type
-
+
nit_type.generic_params = new Array[NitType]
for param in generic_params do
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)
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
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
# 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
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
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
sys.system "rsync -vr --delete {root}/ {config.rsync_dir}"
end
+ # Pull data from git repository.
fun fetch do
sys.system "git pull {config.git_origin} {config.git_branch}"
end
return path.simplify_path
end
+ # Transform an id style name into a pretty printed name.
+ #
+ # Used to translate ids in beautiful page names.
fun pretty_name(name: String): String do
name = name.replace("_", " ")
name = name.capitalized
for child in children.values do
if child isa WikiArticle and child.is_index then return child
end
- return new WikiSectionIndex(wiki, self)
+ return new WikiSectionIndex(wiki, "index", self)
end
redef fun tpl_link do return index.tpl_link
# The section described by `self`.
var section: WikiSection
- init(wiki: Nitiwiki, section: WikiSection) do
- super(wiki, "index")
- self.section = section
- end
-
redef var is_dirty = false
redef fun tpl_article do
class TplArticle
super Template
+ # Article title.
var title: nullable Streamable = null
+
+ # Article HTML body.
var body: nullable Streamable = null
+
+ # Sidebar of this article (if any).
var sidebar: nullable TplSidebar = null
+
+ # Breadcrumbs from wiki root to this article.
var breadcrumbs: nullable TplBreadcrumbs = null
+ # Init `self` with a `title`.
init with_title(title: Streamable) do
self.title = title
end
app_name("Ballz")
end
+import android::portrait
+
import game_logic
redef class App
import dino
import mnit_android
+import android::portrait
import android::vibration
redef class ImageSet
module moles_android
-import moles
import mnit_android
+import android::portrait
+
+import moles
redef class Game
redef fun columns do return 3
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;
--- /dev/null
+The `android` module provides support for the Android platform
+
+# Compilation for Android
+
+The compiler generates an APK file as the output when the `android`
+module is imported by the compilation target. The path to the generated
+file can be specified using the `-o` and `--dir` options.
+
+# Host system configuration
+
+To compile for Android, you must install the Android SDK and NDK.
+The tools `android`, `ndk-build` and `ant` must be in your PATH.
+
+# Configure your Android application
+
+The `app.nit` framework and this project offers some services to
+customized the generated Android application.
+
+## Module annotations
+
+* `app_version` specifies the version of the generated APK file.
+It takes 3 arguments: the major, minor and revision version numbers.
+The special function `git_revision` will use the prefix of the hash of the
+latest git commit. The default version is 1.0.
+
+ Example: `app_version(1, 0, git_revision)`
+
+* `app_name` takes a single argument, the visible name of the Android
+application. By default, the compiler would use the name of the target
+module. This name will be used as the name of the main activity and
+as the launcher name.
+
+ Example: `app_name "My App"`
+
+* `java_package` specifies the package used by the generated Java
+classes and the APK file. Once the application is published, this
+value should not be changed. By default, the compiler will use
+the package `org.nitlanguage.{module_name}`.
+
+* Custom information can be added to the Android manifest file
+using the annotations `android_manifest`, `android_manifest_application`
+and `android_manifest_activity`.
+
+ Example usage to specify an extra permission:
+
+ ~~~
+ android_manifest """<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>"""
+ ~~~
+
+* The API version target can be specified with `min_api_version`,
+`max_api_version` and `target_api_version`. These take a single
+integer as argument. They are applied in the Android manifest as
+`minSdkVesion`, `targetSdkVersion` and `maxSdkVersion`.
+
+ See http://developer.android.com/guide/topics/manifest/uses-sdk-element.html
+
+## Project entry points
+
+Importing `android::landscape` or `android::portrait` locks the generated
+application in the specified orientation. This can be useful for games and
+other multimedia applications.
+
+# Compilation modes
+
+There are two compilation modes for the Android platform, debug and release.
+Theses modes are also applied to the generated Android projects.
+The compilation mode is specified as an argument to `nitc`, only
+`--release` can be specified as debug is the default behavior.
+
+## Debug mode
+
+Debug mode enables compiling to an APK file without handling signing keys
+and their password. The APK file can be installed to a local device with
+USB debugging enabled, but it cannot be published on the Play Store.
+
+By default, `nitc` will compile Android applications in debug mode.
+
+## Release mode
+
+Building in release mode will use your private key to sign the
+APK file, it can then be published on the Play Store.
+
+1. Have a keystore with a valid key to sign your APK file.
+
+ To create a new keystore, avoid using the default values of `jarsigner`
+as they change between versions of the Java SDK. You should instead use a
+command similar to the following, replacing `KEYSTORE_PATH` and `KEY_ALIAS`
+with the desired values.
+
+ ~~~
+ keytool -genkey -keystore KEYSTORE_PATH -alias KEY_ALIAS -sigalg MD5withRSA -keyalg RSA -keysize 1024 -validity 10000
+ ~~~
+
+2. Set the environment variables used by `nitc`: `KEYSTORE`, `KEY_ALIAS` and
+optionally `TSA_SERVER`. These settings can be set in a startup script such as
+`~/.bashrc` or in a local Makefile.
+
+ You can use the following commands by replacing the right hand values
+to your own configuration.
+
+ ~~~
+ export KEYSTORE=keystore_path
+ export KEY_ALIAS=key_alias
+ export TSA_SERVER=timestamp_authority_server_url # Optional
+ ~~~
+
+3. Call `nitc` with the `--release` options. You will be prompted for the
+required passwords as needed by `jarsigner`.
# Android services and implementation of app.nit
#
-# To use this module and compile for Android, you must install the
-# Android SDK (with API level 10) and NDK (with the API level 9).
-# The tools `android`, `ndk-build` and `ant` must be in your PATH.
-#
# This module provides basic logging facilities, advanced logging can be
# achieved by importing `android::log`.
module android
--- /dev/null
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# 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
--- /dev/null
+# 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
--- /dev/null
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Config to set the landscape orientation
+module landscape is android_manifest_activity """
+ android:screenOrientation="landscape"
+"""
+
+import platform
--- /dev/null
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Config to set the portrait orientation
+module portrait is android_manifest_activity """
+ android:screenOrientation="portrait"
+"""
+
+import platform
# Keeps the average length of an Array when calling to_s
var arr_len = new Counter[Int]
+ # Compute the average array length.
fun avg_arr_len: Float do
var total = 0
var sum = 0
return sum.to_f / total.to_f
end
+ # Compute the average string length.
fun avg_s_len: Float do
var total = 0
var sum = 0
return sum.to_f / total.to_f
end
+ # Display statistics in standard output.
fun print_stats do
if arr_len.sum == 0 then
print "*** No Array stats ***"
# but cannot be used to add new Events.
var last_turn: nullable ThinGameTurn[G] = null
- init do end
-
# Execute and return a new GameTurn.
#
# This method calls `do_pre_turn` before executing the GameTurn
curl.prim_curl.easy_setopt(new CURLOption.user_agent, name)
end
- init (url: String, curl: nullable Curl)
- do
+ init (url: String, curl: nullable Curl) is old_style_init do
self.url = url
self.curl = curl
end
var body: nullable String = "" is writable
private var supported_outgoing_protocol: Array[String] = ["smtp", "smtps"]
- init (curl: nullable Curl)
- do
+ init (curl: nullable Curl) is old_style_init do
self.curl = curl
end
var error_code: Int
var error_msg: String
-
- init (err_code: Int, err_msg: String)
- do
- self.error_code = err_code
- self.error_msg = err_msg
- end
end
# Success Abstract Response Success Class
super MapIterator[String, String]
private var iterator: Iterator[Couple[String, String]]
- init(map: HeaderMap) do self.iterator = map.arr.iterator
+ init(map: HeaderMap) is old_style_init do self.iterator = map.arr.iterator
redef fun is_ok do return self.iterator.is_ok
redef fun next do self.iterator.next
#
# This file is free software, which comes along with NIT. This software is
# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. You can modify it is you want, provided this header
# is kept unaltered, and a notification of the changes is added.
# You are allowed to redistribute it and sell it, alone or is a part of
do
_streams = streams.iterator
end
- init(streams: IStream ...)
- do
+
+ init(streams: IStream ...) is old_style_init do
_streams = streams.iterator
end
end
_streams = streams
end
- init(streams: OStream ...)
- do
+ init(streams: OStream ...) is old_style_init do
_streams = streams
end
end
#
# ~~~
# var repo = api.load_repo("privat/nit")
-# assert repo isa Repo
+# assert repo != null
# assert repo.name == "nit"
#
# var user = api.load_user("Morriar")
-# assert user isa User
+# assert user != null
# assert user.login == "Morriar"
# ~~~
class GithubAPI
# assert user.login == "Morriar"
fun load_user(login: String): nullable User do
var user = new User(self, login)
- user.load_from_github
- if was_error then return null
- return user
+ return user.load_from_github
end
# Get the Github repo with `full_name`.
# assert repo.default_branch.name == "master"
fun load_repo(full_name: String): nullable Repo do
var repo = new Repo(self, full_name)
- repo.load_from_github
- if was_error then return null
- return repo
+ return repo.load_from_github
end
# Get the Github branch with `name`.
#
# var api = new GithubAPI(get_github_oauth)
# var repo = api.load_repo("privat/nit")
- # assert repo isa Repo
+ # assert repo != null
# var branch = api.load_branch(repo, "master")
# assert branch.name == "master"
# assert branch.commit isa Commit
fun load_branch(repo: Repo, name: String): nullable Branch do
var branch = new Branch(self, repo, name)
- branch.load_from_github
- if was_error then return null
- return branch
+ return branch.load_from_github
end
# Get the Github commit with `sha`.
#
# var api = new GithubAPI(get_github_oauth)
# var repo = api.load_repo("privat/nit")
- # assert repo isa Repo
+ # assert repo != null
# var commit = api.load_commit(repo, "64ce1f")
# assert commit isa Commit
fun load_commit(repo: Repo, sha: String): nullable Commit do
var commit = new Commit(self, repo, sha)
- commit.load_from_github
- if was_error then return null
- return commit
+ return commit.load_from_github
+ end
+
+ # Get the Github issue #`number`.
+ #
+ # Returns `null` if the issue cannot be found.
+ #
+ # var api = new GithubAPI(get_github_oauth)
+ # var repo = api.load_repo("privat/nit")
+ # assert repo != null
+ # var issue = api.load_issue(repo, 1)
+ # assert issue.title == "Doc"
+ fun load_issue(repo: Repo, number: Int): nullable Issue do
+ var issue = new Issue(self, repo, number)
+ return issue.load_from_github
+ end
+
+ # Get the Github pull request #`number`.
+ #
+ # Returns `null` if the pull request cannot be found.
+ #
+ # var api = new GithubAPI(get_github_oauth)
+ # var repo = api.load_repo("privat/nit")
+ # assert repo != null
+ # var pull = api.load_pull(repo, 1)
+ # assert pull.title == "Doc"
+ # assert pull.user.login == "Morriar"
+ fun load_pull(repo: Repo, number: Int): nullable PullRequest do
+ var pull = new PullRequest(self, repo, number)
+ return pull.load_from_github
+ end
+
+ # Get the Github label with `name`.
+ #
+ # Returns `null` if the label cannot be found.
+ #
+ # var api = new GithubAPI(get_github_oauth)
+ # var repo = api.load_repo("privat/nit")
+ # assert repo != null
+ # var labl = api.load_label(repo, "ok_will_merge")
+ # assert labl != null
+ fun load_label(repo: Repo, name: String): nullable Label do
+ var labl = new Label(self, repo, name)
+ return labl.load_from_github
+ end
+
+ # Get the Github milestone with `id`.
+ #
+ # Returns `null` if the milestone cannot be found.
+ #
+ # var api = new GithubAPI(get_github_oauth)
+ # var repo = api.load_repo("privat/nit")
+ # assert repo != null
+ # var stone = api.load_milestone(repo, 4)
+ # assert stone.title == "v1.0prealpha"
+ fun load_milestone(repo: Repo, id: Int): nullable Milestone do
+ var milestone = new Milestone(self, repo, id)
+ return milestone.load_from_github
+ end
+
+ # Get the Github commit comment with `id`.
+ #
+ # Returns `null` if the comment cannot be found.
+ #
+ # var api = new GithubAPI(get_github_oauth)
+ # var repo = api.load_repo("privat/nit")
+ # assert repo != null
+ # var comment = api.load_commit_comment(repo, 8982707)
+ # assert comment.user.login == "Morriar"
+ # assert comment.body == "For testing purposes..."
+ # assert comment.commit.sha == "7eacb86d1e24b7e72bc9ac869bf7182c0300ceca"
+ fun load_commit_comment(repo: Repo, id: Int): nullable CommitComment do
+ var comment = new CommitComment(self, repo, id)
+ return comment.load_from_github
+ end
+
+ # Get the Github issue comment with `id`.
+ #
+ # Returns `null` if the comment cannot be found.
+ #
+ # var api = new GithubAPI(get_github_oauth)
+ # var repo = api.load_repo("privat/nit")
+ # assert repo != null
+ # var comment = api.load_issue_comment(repo, 6020149)
+ # assert comment.user.login == "privat"
+ # assert comment.created_at.to_s == "2012-05-30T20:16:54Z"
+ # assert comment.issue.number == 10
+ fun load_issue_comment(repo: Repo, id: Int): nullable IssueComment do
+ var comment = new IssueComment(self, repo, id)
+ return comment.load_from_github
+ end
+
+ # Get the Github diff comment with `id`.
+ #
+ # Returns `null` if the comment cannot be found.
+ #
+ # var api = new GithubAPI(get_github_oauth)
+ # var repo = api.load_repo("privat/nit")
+ # assert repo != null
+ # var comment = api.load_review_comment(repo, 21010363)
+ # assert comment.path == "src/modelize/modelize_property.nit"
+ # assert comment.original_position == 26
+ # assert comment.pull.number == 945
+ fun load_review_comment(repo: Repo, id: Int): nullable ReviewComment do
+ var comment = new ReviewComment(self, repo, id)
+ return comment.load_from_github
end
end
var json: JsonObject is noinit, protected writable
# Load `json` from Github API.
- private fun load_from_github do
+ private fun load_from_github: nullable SELF do
json = api.load_from_github(key)
+ if api.was_error then return null
+ return self
end
redef fun to_s do return json.to_json
return res
end
+ # List of issues associated with their ids.
+ fun issues: Map[Int, Issue] do
+ api.message(1, "Get issues for {full_name}")
+ var res = new HashMap[Int, Issue]
+ var issue = last_issue
+ if issue == null then return res
+ res[issue.number] = issue
+ while issue.number > 1 do
+ issue = api.load_issue(self, issue.number - 1)
+ assert issue isa Issue
+ res[issue.number] = issue
+ end
+ return res
+ end
+
+ # Get the last published issue.
+ fun last_issue: nullable Issue do
+ var array = api.get("repos/{full_name}/issues")
+ if not array isa JsonArray then return null
+ if array.is_empty then return null
+ var obj = array.first
+ if not obj isa JsonObject then return null
+ return new Issue.from_json(api, self, obj)
+ end
+
+ # List of labels associated with their names.
+ fun labels: Map[String, Label] do
+ api.message(1, "Get labels for {full_name}")
+ var array = api.get("repos/{full_name}/labels")
+ var res = new HashMap[String, Label]
+ if not array isa JsonArray then return res
+ for obj in array do
+ if not obj isa JsonObject then continue
+ var name = obj["name"].to_s
+ res[name] = new Label.from_json(api, self, obj)
+ end
+ return res
+ end
+
+ # List of milestones associated with their ids.
+ fun milestones: Map[Int, Milestone] do
+ api.message(1, "Get milestones for {full_name}")
+ var array = api.get("repos/{full_name}/milestones")
+ var res = new HashMap[Int, Milestone]
+ if array isa JsonArray then
+ for obj in array do
+ if not obj isa JsonObject then continue
+ var number = obj["number"].as(Int)
+ res[number] = new Milestone.from_json(api, self, obj)
+ end
+ end
+ return res
+ end
+
+ # List of pull-requests associated with their ids.
+ #
+ # Implementation notes: because PR numbers are not consecutive,
+ # PR are loaded from pages.
+ # See: https://developer.github.com/v3/pulls/#list-pull-requests
+ fun pulls: Map[Int, PullRequest] do
+ api.message(1, "Get pulls for {full_name}")
+ var res = new HashMap[Int, PullRequest]
+ var page = 1
+ var array = api.get("{key}/pulls?page={page}").as(JsonArray)
+ while not array.is_empty do
+ for obj in array do
+ if not obj isa JsonObject then continue
+ var number = obj["number"].as(Int)
+ res[number] = new PullRequest.from_json(api, self, obj)
+ end
+ page += 1
+ array = api.get("{key}/pulls?page={page}").as(JsonArray)
+ end
+ return res
+ end
+
# Repo default branch.
fun default_branch: Branch do
var name = json["default_branch"].to_s
# Commit message.
fun message: String do return json["commit"].as(JsonObject)["message"].to_s
end
+
+# A Github issue.
+#
+# Should be accessed from `GithubAPI::load_issue`.
+#
+# See <https://developer.github.com/v3/issues/>.
+class Issue
+ super RepoEntity
+
+ redef var key is lazy do return "{repo.key}/issues/{number}"
+
+ # Issue Github ID.
+ var number: Int
+
+ redef init from_json(api, repo, json) do
+ self.number = json["number"].as(Int)
+ super
+ end
+
+ # Issue title.
+ fun title: String do return json["title"].to_s
+
+ # User that created this issue.
+ fun user: User do
+ return new User.from_json(api, json["user"].as(JsonObject))
+ end
+
+ # List of labels on this issue associated to their names.
+ fun labels: Map[String, Label] do
+ var res = new HashMap[String, Label]
+ for obj in json["labels"].as(JsonArray) do
+ if not obj isa JsonObject then continue
+ var name = obj["name"].to_s
+ res[name] = new Label.from_json(api, repo, obj)
+ end
+ return res
+ end
+
+ # State of the issue on Github.
+ fun state: String do return json["state"].to_s
+
+ # Is the issue locked?
+ fun locked: Bool do return json["locked"].as(Bool)
+
+ # Assigned `User` (if any).
+ fun assignee: nullable User do
+ var assignee = json["assignee"]
+ if not assignee isa JsonObject then return null
+ return new User.from_json(api, assignee)
+ end
+
+ # `Milestone` (if any).
+ fun milestone: nullable Milestone do
+ var milestone = json["milestone"]
+ if not milestone isa JsonObject then return null
+ return new Milestone.from_json(api, repo, milestone)
+ end
+
+ # List of comments made on this issue.
+ fun comments: Array[IssueComment] do
+ var res = new Array[IssueComment]
+ var count = comments_count
+ var page = 1
+ var array = api.get("{key}/comments?page={page}")
+ if not array isa JsonArray then
+ return res
+ end
+ while not array.is_empty and res.length < count do
+ for obj in array do
+ if not obj isa JsonObject then continue
+ var id = obj["id"].as(Int)
+ res.add(api.load_issue_comment(repo, id).as(not null))
+ end
+ page += 1
+ array = api.get("{key}/comments?page={page}").as(JsonArray)
+ end
+ return res
+ end
+
+ # Number of comments on this issue.
+ fun comments_count: Int do return json["comments"].to_s.to_i
+
+ # Creation time in ISODate format.
+ fun created_at: ISODate do
+ return new ISODate.from_string(json["created_at"].to_s)
+ end
+
+ # Last update time in ISODate format (if any).
+ fun updated_at: nullable ISODate do
+ var res = json["updated_at"]
+ if res == null then return null
+ return new ISODate.from_string(res.to_s)
+ end
+
+ # Close time in ISODate format (if any).
+ fun closed_at: nullable ISODate do
+ var res = json["closed_at"]
+ if res == null then return null
+ return new ISODate.from_string(res.to_s)
+ end
+
+ # TODO link to pull request
+
+ # Full description of the issue.
+ fun body: String do return json["body"].to_s
+
+ # User that closed this issue (if any).
+ fun closed_by: nullable User do
+ var closer = json["closed_by"]
+ if not closer isa JsonObject then return null
+ return new User.from_json(api, closer)
+ end
+end
+
+# A Github pull request.
+#
+# Should be accessed from `GithubAPI::load_pull`.
+#
+# PullRequest are basically Issues with more data.
+# See <https://developer.github.com/v3/pulls/>.
+class PullRequest
+ super Issue
+
+ redef var key is lazy do return "{repo.key}/pulls/{number}"
+
+ # Merge time in ISODate format (if any).
+ fun merged_at: nullable ISODate do
+ var res = json["merged_at"]
+ if res == null then return null
+ return new ISODate.from_string(res.to_s)
+ end
+
+ # Merge commit SHA.
+ fun merge_commit_sha: String do return json["merge_commit_sha"].to_s
+
+ # Count of comments made on the pull request diff.
+ fun review_comments: Int do return json["review_comments"].to_s.to_i
+
+ # Pull request head (can be a commit SHA or a branch name).
+ fun head: PullRef do
+ var json = json["head"].as(JsonObject)
+ return new PullRef(api, json)
+ end
+
+ # Pull request base (can be a commit SHA or a branch name).
+ fun base: PullRef do
+ var json = json["base"].as(JsonObject)
+ return new PullRef(api, json)
+ end
+
+ # Is this pull request merged?
+ fun merged: Bool do return json["merged"].as(Bool)
+
+ # Is this pull request mergeable?
+ fun mergeable: Bool do return json["mergeable"].as(Bool)
+
+ # Mergeable state of this pull request.
+ #
+ # See <https://developer.github.com/v3/pulls/#list-pull-requests>.
+ fun mergeable_state: Int do return json["mergeable_state"].to_s.to_i
+
+ # User that merged this pull request (if any).
+ fun merged_by: nullable User do
+ var merger = json["merged_by"]
+ if not merger isa JsonObject then return null
+ return new User.from_json(api, merger)
+ end
+
+ # Count of commits in this pull request.
+ fun commits: Int do return json["commits"].to_s.to_i
+
+ # Added line count.
+ fun additions: Int do return json["additions"].to_s.to_i
+
+ # Deleted line count.
+ fun deletions: Int do return json["deletions"].to_s.to_i
+
+ # Changed files count.
+ fun changed_files: Int do return json["changed_files"].to_s.to_i
+end
+
+# A pull request reference (used for head and base).
+class PullRef
+
+ # Api instance that maintains self.
+ var api: GithubAPI
+
+ # JSON representation.
+ var json: JsonObject
+
+ # Label pointed by `self`.
+ fun labl: String do return json["label"].to_s
+
+ # Reference pointed by `self`.
+ fun ref: String do return json["ref"].to_s
+
+ # Commit SHA pointed by `self`.
+ fun sha: String do return json["sha"].to_s
+
+ # User pointed by `self`.
+ fun user: User do
+ return new User.from_json(api, json["user"].as(JsonObject))
+ end
+
+ # Repo pointed by `self`.
+ fun repo: Repo do
+ return new Repo.from_json(api, json["repo"].as(JsonObject))
+ end
+end
+
+# A Github label.
+#
+# Should be accessed from `GithubAPI::load_label`.
+#
+# See <https://developer.github.com/v3/issues/labels/>.
+class Label
+ super RepoEntity
+
+ redef var key is lazy do return "{repo.key}/labels/{name}"
+
+ # Label name.
+ var name: String
+
+ redef init from_json(api, repo, json) do
+ self.name = json["name"].to_s
+ super
+ end
+
+ # Label color code.
+ fun color: String do return json["color"].to_s
+end
+
+# A Github milestone.
+#
+# Should be accessed from `GithubAPI::load_milestone`.
+#
+# See <https://developer.github.com/v3/issues/milestones/>.
+class Milestone
+ super RepoEntity
+
+ redef var key is lazy do return "{repo.key}/milestones/{number}"
+
+ # The milestone id on Github.
+ var number: Int
+
+ redef init from_json(api, repo, json) do
+ super
+ self.number = json["number"].as(Int)
+ end
+
+ # Milestone title.
+ fun title: String do return json["title"].to_s
+
+ # Milestone long description.
+ fun description: String do return json["description"].to_s
+
+ # Count of opened issues linked to this milestone.
+ fun open_issues: Int do return json["open_issues"].to_s.to_i
+
+ # Count of closed issues linked to this milestone.
+ fun closed_issues: Int do return json["closed_issues"].to_s.to_i
+
+ # Milestone state.
+ fun state: String do return json["state"].to_s
+
+ # Creation time in ISODate format.
+ fun created_at: ISODate do
+ return new ISODate.from_string(json["created_at"].to_s)
+ end
+
+ # User that created this milestone.
+ fun creator: User do
+ return new User.from_json(api, json["creator"].as(JsonObject))
+ end
+
+ # Due time in ISODate format (if any).
+ fun due_on: nullable ISODate do
+ var res = json["updated_at"]
+ if res == null then return null
+ return new ISODate.from_string(res.to_s)
+ end
+
+ # Update time in ISODate format (if any).
+ fun updated_at: nullable ISODate do
+ var res = json["updated_at"]
+ if res == null then return null
+ return new ISODate.from_string(res.to_s)
+ end
+
+ # Close time in ISODate format (if any).
+ fun closed_at: nullable ISODate do
+ var res = json["closed_at"]
+ if res == null then return null
+ return new ISODate.from_string(res.to_s)
+ end
+end
+
+# A Github comment
+#
+# There is two kinds of comments:
+#
+# * `CommitComment` are made on a commit page.
+# * `IssueComment` are made on an issue or pull request page.
+# * `ReviewComment` are made on the diff associated to a pull request.
+abstract class Comment
+ super RepoEntity
+
+ # Identifier of this comment.
+ var id: Int
+
+ redef init from_json(api, repo, json) do
+ self.id = json["id"].as(Int)
+ super
+ end
+
+ # User that made this comment.
+ fun user: User do
+ return new User.from_json(api, json["user"].as(JsonObject))
+ end
+
+ # Creation time in ISODate format.
+ fun created_at: ISODate do
+ return new ISODate.from_string(json["created_at"].to_s)
+ end
+
+ # Last update time in ISODate format (if any).
+ fun updated_at: nullable ISODate do
+ if not json.has_key("updated_at") then return null
+ return new ISODate.from_string(json["updated_at"].to_s)
+ end
+
+ # Comment body text.
+ fun body: String do return json["body"].to_s
+end
+
+# A comment made on a commit.
+class CommitComment
+ super Comment
+
+ redef var key is lazy do return "{repo.key}/comments/{id}"
+
+ # Commented commit.
+ fun commit: Commit do
+ return api.load_commit(repo, json["commit_id"].to_s).as(not null)
+ end
+
+ # Position of the comment on the line.
+ fun position: nullable String do
+ if not json.has_key("position") then return null
+ var res = json["position"]
+ if res == null then return null
+ return res.to_s
+ end
+
+ # Line of the comment.
+ fun line: nullable String do
+ if not json.has_key("line") then return null
+ var res = json["line"]
+ if res == null then return null
+ return res.to_s
+ end
+
+ # Path of the commented file.
+ fun path: String do return json["path"].to_s
+end
+
+# Comments made on Github issue and pull request pages.
+#
+# Should be accessed from `GithubAPI::load_issue_comment`.
+#
+# See <https://developer.github.com/v3/issues/comments/>.
+class IssueComment
+ super Comment
+
+ redef var key is lazy do return "{repo.key}/issues/comments/{id}"
+
+ # Issue that contains `self`.
+ fun issue: Issue do
+ var number = issue_url.split("/").last.to_i
+ return api.load_issue(repo, number).as(not null)
+ end
+
+ # Link to the issue document on API.
+ fun issue_url: String do return json["issue_url"].to_s
+end
+
+# Comments made on Github pull request diffs.
+#
+# Should be accessed from `GithubAPI::load_diff_comment`.
+#
+# See <https://developer.github.com/v3/pulls/comments/>.
+class ReviewComment
+ super Comment
+
+ redef var key is lazy do return "{repo.key}/pulls/comments/{id}"
+
+ # Pull request that contains `self`.
+ fun pull: PullRequest do
+ var number = pull_request_url.split("/").last.to_i
+ return api.load_pull(repo, number).as(not null)
+ end
+
+ # Link to the pull request on API.
+ fun pull_request_url: String do return json["pull_request_url"].to_s
+
+ # Diff hunk.
+ fun diff_hunk: String do return json["diff_hunk"].to_s
+
+ # Path of commented file.
+ fun path: String do return json["path"].to_s
+
+ # Position of the comment on the file.
+ fun position: Int do return json["position"].to_s.to_i
+
+ # Original position in the diff.
+ fun original_position: Int do return json["original_position"].to_s.to_i
+
+ # Commit referenced by this comment.
+ fun commit_id: String do return json["commit_id"].to_s
+
+ # Original commit id.
+ fun original_commit_id: String do return json["original_commit_id"].to_s
+end
## 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
# 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
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
# 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
`}
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; `}
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; `}
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
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
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
`}
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 *`}
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 ) );
`}
# 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
# The ini file used to read/store data
var ini_file: String
- init(file: String) do
- self.ini_file = file
- if file.file_exists then load
- end
+ init do if ini_file.file_exists then load
# Get the config value for `key`
#
# assert config.has_key("foo.bar")
# assert not config.has_key("zoo")
fun has_key(key: String): Bool do
- var children = roots
var parts = key.split(".").reversed
var node = get_root(parts.pop)
if node == null then return false
private var roots = new Array[ConfigNode]
private fun set_node(key: String, value: nullable String) do
- var children = roots
var parts = key.split(".").reversed
var k = parts.pop
var root = get_root(k)
end
private fun get_node(key: String): nullable ConfigNode do
- var children = roots
var parts = key.split(".").reversed
var node = get_root(parts.pop)
while not parts.is_empty do
end
private class ConfigNode
- var parent: nullable ConfigNode
+
+ var parent: nullable ConfigNode = null
var children = new HashMap[String, ConfigNode]
var name: String is writable
- var value: nullable String
-
- init(name: String) do
- self.name = name
- end
+ var value: nullable String = null
fun key: String do
if parent == null then
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Basic 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
# SEE: `append_json`
fun to_json: String is abstract
+ # Use `append_json` to implement `to_json`.
+ #
+ # Therefore, one that redefine `append_json` may use the following
+ # redefinition to link `to_json` and `append_json`:
+ #
+ # ~~~nitish
+ # redef fun to_json do return to_json_by_append
+ # ~~~
+ #
+ # Note: This is not the default implementation of `to_json` in order to
+ # avoid cyclic references between `append_json` and `to_json` when none are
+ # implemented.
+ protected fun to_json_by_append: String do
+ var buffer = new RopeBuffer
+ append_json(buffer)
+ return buffer.write_to_string
+ end
+
# Append the JSON representation of `self` to the specified buffer.
#
# SEE: `to_json`
- fun append_json(buffer: Buffer) do
- buffer.append(to_json)
- end
+ fun append_json(buffer: Buffer) do buffer.append(to_json)
end
redef class Text
#
# assert "\t\"http://example.com\"\r\n\0\\".to_json ==
# "\"\\t\\\"http:\\/\\/example.com\\\"\\r\\n\\u0000\\\\\""
- redef fun to_json do
- var buffer = new FlatBuffer
- append_json(buffer)
- return buffer.write_to_string
- end
+ redef fun to_json do return to_json_by_append
# Parse `self` as JSON.
#
# obj = new JsonObject
# obj["baz"] = null
# assert obj.to_json == "\{\"baz\":null\}"
- redef fun to_json do
- var buffer = new FlatBuffer
- append_json(buffer)
- return buffer.write_to_string
- end
+ redef fun to_json do return to_json_by_append
private fun append_json_entry(iterator: MapIterator[String, nullable Jsonable],
buffer: Buffer) do
# assert arr.to_json =="[\"foo\"]"
# arr.pop
# assert arr.to_json =="[]"
- redef fun to_json do
- var buffer = new FlatBuffer
- append_json(buffer)
- return buffer.write_to_string
- end
+ redef fun to_json do return to_json_by_append
private fun append_json_entry(iterator: Iterator[nullable Jsonable],
buffer: Buffer) do
EGLConfig mnit_config;
int32_t mnit_width;
int32_t mnit_height;
- float mnit_zoom;
struct mnit_opengles_Texture {
GLuint texture;
mnit_config = config;
mnit_width = w;
mnit_height = h;
- mnit_zoom = 1.0f;
LOGI("surface", (int)surface);
LOGI("display", (int)display);
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 );
`}
# 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;
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)
return handled
end
-
- redef fun generate_input do poll_looper 0
end
# assert m.has_key("four")
# assert m["four"] == ['i', 'i', 'i', 'i']
# assert m["zzz"] == new Array[Char]
-class MultiHashMap[K: Object, V]
+class MultiHashMap[K, V]
super HashMap[K, Array[V]]
# Add `v` to the array associated with `k`.
# assert hm2[1, "one"] == 1.0
# assert hm2[2, "not-two"] == null
# ~~~~
-class HashMap2[K1: Object, K2: Object, V]
+class HashMap2[K1, K2, V]
private var level1 = new HashMap[K1, HashMap[K2, V]]
# Return the value associated to the keys `k1` and `k2`.
# assert hm3[1, "one", 11] == 1.0
# assert hm3[2, "not-two", 22] == null
# ~~~~
-class HashMap3[K1: Object, K2: Object, K3: Object, V]
+class HashMap3[K1, K2, K3, V]
private var level1 = new HashMap[K1, HashMap2[K2, K3, V]]
# Return the value associated to the keys `k1`, `k2`, and `k3`.
# assert dma["b"] == [65, 66]
# assert dma.default == [65]
# ~~~~
-class DefaultMap[K: Object, V]
+class DefaultMap[K, V]
super HashMap[K, V]
# The default value.
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Provides an interface for services on a Neo4j graphs.
+module neo4j::graph::graph
+
+import neo4j
+import progression
+
+# A Neo4j graph with a local identification scheme for its nodes.
+#
+# An identification scheme can be defined by subclassing `NeoNodeCollection`.
+#
+# `GraphStore` can be subclassed to add ways to save or load a graph. The
+# storing mechanisms may use `nodes.id_of` to identify the nodes in the graph
+# while encoding the relationships.
+class NeoGraph
+ # All the nodes in the graph.
+ var nodes: NeoNodeCollection
+
+ # All the relationships in the graph.
+ var edges: SimpleCollection[NeoEdge] = new Array[NeoEdge]
+
+ # Add a new node to the graph and return it.
+ #
+ # Set the local ID of the node before returning it.
+ #
+ # SEE: `NeoNodeCollection.add`
+ # SEE: `NeoNodeCollection.create_node`
+ # SEE: `NeoNodeCollection.register`
+ fun create_node: NeoNode do return nodes.create_node
+end
+
+# All the nodes in a `NeoGraph`.
+#
+# An identification scheme can be defined throught the `register` and `add`
+# methods. The `id_property` attribute defines where the local ID (that is the
+# ID managed by the collection) is stored in each node.
+abstract class NeoNodeCollection
+ super SimpleCollection[NeoNode]
+
+ # The type of the local IDs.
+ type ID_TYPE: Jsonable
+
+ # The property of the nodes that hold the local ID.
+ var id_property: String
+
+ # Retrieve the node that has the specified local id.
+ #
+ # Note: The default implementation uses `get_or_null`.
+ fun [](id: ID_TYPE): NeoNode do
+ var n = get_or_null(id)
+ assert n isa NeoNode
+ return n
+ end
+
+ # Retrieve the node that has the specified local id, or return `null`.
+ #
+ # Note: The default implementation uses `iterator`.
+ fun get_or_null(id: ID_TYPE): nullable NeoNode do
+ for n in self do
+ if id_of(n) == id then return n
+ end
+ return null
+ end
+
+ # There is a node that has the specified local id?
+ #
+ # Note: The default implementation uses `get_or_null`.
+ fun has_id(id: ID_TYPE): Bool do return get_or_null(id) isa NeoNode
+
+ # Return the local ID of the node.
+ fun id_of(node: NeoNode): ID_TYPE do return node[id_property].as(ID_TYPE)
+
+ # Set the local ID of the specified node.
+ #
+ # Just update the property at `property_id`. Do not check anything.
+ protected fun id_of=(node: NeoNode, id: ID_TYPE) do
+ node[id_property] = id
+ end
+
+ # Enlarge the collection to have at least the specified capacity.
+ #
+ # The capacity is specified in number of nodes. Used to minimize the
+ # number of times the collection need to be resized when adding nodes
+ # in batches.
+ #
+ # Do nothing by default.
+ fun enlarge(cap: Int) do end
+
+ # Add the specified node to the graph and set its local ID.
+ #
+ # SEE: `add`
+ # SEE: `create_node`
+ fun register(node: NeoNode) is abstract
+
+ # Add the specified node to the graph assuming that its local ID is already set.
+ #
+ # SEE: `create_node`
+ # SEE: `register`
+ redef fun add(node: NeoNode) is abstract
+
+ # Add a new node to the graph and return it.
+ #
+ # Set the local ID of the node before returning it.
+ #
+ # SEE: `add`
+ # SEE: `register`
+ fun create_node: NeoNode do
+ var node = new NeoNode
+ register(node)
+ return node
+ end
+
+ # Remove the node with the specified local ID.
+ fun remove_at(id: ID_TYPE) is abstract
+
+ # Remove the specified node.
+ #
+ # The local ID is used instead of `==` to seek the node.
+ fun remove_node(node: NeoNode) do
+ remove_at(id_of(node))
+ end
+
+ redef fun clear do
+ for node in self do remove_node(node)
+ end
+
+ redef fun remove(node: NeoNode) do
+ for n in self do
+ if node == n then
+ remove_node(n)
+ return
+ end
+ end
+ end
+
+ redef fun remove_all(node: NeoNode) do
+ for n in self do
+ if node == n then remove_node(n)
+ end
+ end
+
+ # Optimize the collection, possibly by rewritting it.
+ #
+ # The local ID of the elements may be changed by this method.
+ fun compact do end
+end
+
+# A mean to save and load a Neo4j graph.
+abstract class GraphStore
+ super Trackable
+
+ # The graph to save or load.
+ var graph: NeoGraph
+
+ # Can we save the graph without conflict?
+ fun isolated_save: Bool is abstract
+
+ # Load the graph (or a part of it).
+ #
+ # Do not reset the graph.
+ fun load is abstract
+
+ # Save the graph.
+ fun save do save_part(graph.nodes, graph.edges)
+
+ # Save the specified part of the graph.
+ #
+ # Assume that for each relationship specified, both ends are already saved
+ # or are specified in the same call to this method.
+ fun save_part(nodes: Collection[NeoNode],
+ edges: Collection[NeoEdge]) is abstract
+end
+
+# Save or load a graph using an actual Neo4j database.
+class Neo4jGraphStore
+ super GraphStore
+
+ # The maximum number of entities saved in one request.
+ #
+ # Also defines the granulity of the reported progression.
+ #
+ # TODO Also honor this limit in `load`.
+ var batch_max_size = 512 is writable
+
+ # The Neo4j client to use.
+ var client: Neo4jClient
+
+ # The label to use to retrieve the nodes.
+ var node_label: String
+
+ private var done_part = 0
+ private var total = 0
+
+ # Is the database already contains at least one node with the specified label?
+ fun has_node_label(name: String): Bool do
+ var query = new CypherQuery.from_string(
+ "match n where \{name\} in labels(n) return count(n)")
+ query.params["name"] = name
+ var data = client.cypher(query).as(JsonObject)["data"]
+ var result = data.as(JsonArray).first.as(JsonArray).first.as(Int)
+ return result > 0
+ end
+
+ redef fun isolated_save do return not has_node_label(node_label)
+
+ redef fun load do
+ assert batch_max_size > 0
+ fire_started
+ var db_nodes = client.nodes_with_label(node_label)
+ var nodes = graph.nodes
+ var edges = graph.edges
+ var i = 0
+
+ total = nodes.length * 2
+ done_part = nodes.length
+ fire_progressed(done_part, total)
+ for node in db_nodes do
+ nodes.add(node)
+ edges.add_all(node.out_edges)
+ i += 1
+ if i >= batch_max_size then
+ done_part += batch_max_size
+ fire_progressed(done_part, total)
+ end
+ end
+ fire_done
+ end
+
+ redef fun save_part(nodes, edges) do
+ assert batch_max_size > 0
+ fire_started
+ total = nodes.length + edges.length
+ done_part = 0
+
+ save_entities(nodes)
+ save_entities(edges)
+ fire_done
+ end
+
+ # Save the specified entities.
+ private fun save_entities(neo_entities: Collection[NeoEntity]) do
+ var batch = new NeoBatch(client)
+ var batch_length = 0
+
+ for nentity in neo_entities do
+ batch.save_entity(nentity)
+ batch_length += 1
+ if batch_length >= batch_max_size then
+ do_batch(batch)
+ done_part += batch_max_size
+ fire_progressed(done_part, total)
+ batch = new NeoBatch(client)
+ batch_length = 0
+ end
+ end
+ do_batch(batch)
+ done_part += batch_length
+ end
+
+ # Execute `batch` and check for errors.
+ #
+ # Abort if `batch.execute` returns errors.
+ private fun do_batch(batch: NeoBatch) do
+ var errors = batch.execute
+ assert errors.is_empty else
+ for e in errors do sys.stderr.write("{e}\n")
+ end
+ end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Provides JSON as a mean to store graphs.
+module neo4j::graph::json_graph_store
+
+import graph
+
+# Save or load a graph using a JSON document.
+#
+# The graph (or the specified part of it) is stored as a JSON object with the
+# following properties:
+#
+# * `"nodes"`: An array with all nodes. Each node is an object with the
+# following properties:
+# * `"labels"`: An array of all applied labels.
+# * `"properties"`: An object mapping each defined property to its value.
+# * `"edges"`: An array with all relationships. Each relationship is an object
+# with the following properties:
+# * `"type"`: The type (`String`) of the relationship.
+# * `"properties"`: An object mapping each defined property to its value.
+# * `"from"`: The local ID of the source node.
+# * `"to"`: The local ID of the destination node.
+#
+# ~~~nit
+# import neo4j::graph::sequential_id
+#
+# var graph = new NeoGraph(new SequentialNodeCollection("nid"))
+# var a = new NeoNode
+# a.labels.add "Foo"
+# a["answer"] = 42
+# a["Ultimate question of"] = new JsonArray.from(["life",
+# "the Universe", "and Everything."])
+# graph.nodes.register a
+# var b = graph.create_node
+# b.labels.add "Foo"
+# b.labels.add "Bar"
+# graph.edges.add new NeoEdge(a, "BAZ", b)
+#
+# var ostream = new StringOStream
+# var store = new JsonGraphStore(graph)
+# store.ostream = ostream
+# store.save
+# assert ostream.to_s == """{"nodes":[""" + """
+# {"labels":["Foo"],"properties":{"answer":42,""" + """
+# "Ultimate question of":["life","the Universe","and Everything."],""" + """
+# "nid":1}},""" + """
+# {"labels":["Foo","Bar"],"properties":{"nid":2}}],""" + """
+# "edges":[{"type":"BAZ","properties":{},"from":1,"to":2}]}"""
+#
+# graph.nodes.clear
+# graph.edges.clear
+# store.istream = new StringIStream(ostream.to_s)
+# store.load
+# assert 1 == graph.edges.length
+# for edge in graph.edges do
+# assert "BAZ" == edge.rel_type
+# assert a.labels == edge.from.labels
+# for k, v in a.properties do assert v == edge.from.properties[k]
+# assert b.labels == edge.to.labels
+# for k, v in b.properties do assert v == edge.to.properties[k]
+# end
+# assert 2 == graph.nodes.length
+# ~~~
+class JsonGraphStore
+ super GraphStore
+
+ # The stream to use for `load`.
+ var istream: nullable IStream = null is writable
+
+ # The stream to use for `save` and `save_part`.
+ var ostream: nullable OStream = null is writable
+
+ # Use the specified `IOStream`.
+ init from_io(graph: NeoGraph, iostream: IOStream) do
+ init(graph)
+ istream = iostream
+ ostream = iostream
+ end
+
+ # Use the specified string to load the graph.
+ init from_string(graph: NeoGraph, string: String) do
+ init(graph)
+ istream = new StringIStream(string)
+ end
+
+ redef fun isolated_save do return true
+
+ redef fun load do
+ var istream = self.istream
+ assert istream isa IStream
+ fire_started
+ graph.load_json(istream.read_all)
+ fire_done
+ end
+
+ redef fun save_part(nodes, edges) do
+ var ostream = self.ostream
+ assert ostream isa OStream
+ fire_started
+ ostream.write(graph.to_json)
+ fire_done
+ end
+end
+
+redef class NeoGraph
+ super Jsonable
+
+ # Retrieve the graph from the specified JSON document.
+ #
+ # For the expected format, see `JsonGraphStore`.
+ #
+ # ~~~nit
+ # import neo4j::graph::sequential_id
+ #
+ # var graph = new NeoGraph(new SequentialNodeCollection("node_id"))
+ # var a = new NeoNode
+ # a.labels.add "Foo"
+ # a["answer"] = 42
+ # a["Ultimate question of"] = new JsonArray.from(["life",
+ # "the Universe", "and Everything."])
+ # graph.nodes.register a
+ # var b = graph.create_node
+ # b.labels.add "Foo"
+ # b.labels.add "Bar"
+ # graph.edges.add new NeoEdge(a, "BAZ", b)
+ #
+ # graph = new NeoGraph.from_json(
+ # new SequentialNodeCollection("node_id"), graph.to_json)
+ # assert 1 == graph.edges.length
+ # for edge in graph.edges do
+ # assert "BAZ" == edge.rel_type
+ # assert a.labels == edge.from.labels
+ # for k, v in a.properties do assert v == edge.from.properties[k]
+ # assert b.labels == edge.to.labels
+ # for k, v in b.properties do assert v == edge.to.properties[k]
+ # end
+ # assert 2 == graph.nodes.length
+ # ~~~
+ init from_json(nodes: NeoNodeCollection, t: Text) do
+ from_json_object(nodes, t.parse_json.as(JsonObject))
+ end
+
+ # Retrieve the graph from the specified JSON object.
+ #
+ # For the expected format, see `JsonGraphStore`.
+ init from_json_object(nodes: NeoNodeCollection, o: JsonObject) do
+ init(nodes)
+ load_json_object(o)
+ end
+
+ # Retrieve a part of the graph from the specified JSON document.
+ #
+ # For the expected format, see `JsonGraphStore`.
+ fun load_json(t: Text) do
+ load_json_object(t.parse_json.as(JsonObject))
+ end
+
+ # Retrieve a part of the graph from the specified JSON object.
+ #
+ # For the expected format, see `JsonGraphStore`.
+ fun load_json_object(o: JsonObject) do
+ var json_nodes = o["nodes"].as(JsonArray)
+ var nodes = self.nodes
+ nodes.enlarge(nodes.length)
+ for json_node in json_nodes do
+ assert json_node isa JsonObject
+ var node = new NeoNode.from_json_object(json_node)
+ nodes.add node
+ end
+
+ var json_edges = o["edges"].as(JsonArray)
+ var edges = self.edges
+ if edges isa AbstractArray[NeoEdge] then edges.enlarge(edges.length)
+ for json_edge in json_edges do
+ assert json_edge isa JsonObject
+ var from = nodes[nodes.id_from_jsonable(json_edge["from"])]
+ var to = nodes[nodes.id_from_jsonable(json_edge["to"])]
+ var rel_type = json_edge["type"].as(String)
+ var json_properties = json_edge["properties"].as(JsonObject)
+ var edge = new NeoEdge(from, rel_type, to)
+ edge.properties.recover_with(json_properties)
+ edges.add edge
+ end
+ end
+
+ redef fun to_json do return to_json_by_append
+
+ # Append the JSON representation of `self` to the specified buffer.
+ #
+ # For a description of the format, see `JsonGraphStore`.
+ #
+ # SEE: `to_json`
+ redef fun append_json(b) do
+ b.append "\{\"nodes\":["
+ append_entities_json(nodes, b)
+ b.append "],\"edges\":["
+ append_entities_json(edges, b)
+ b.append "]\}"
+ end
+
+ # Encode `self` in JSON.
+ #
+ # For a description of the format, see `JsonGraphStore`.
+ #
+ # SEE: `append_json`
+ private fun append_entities_json(entities: Collection[NeoEntity],
+ b: Buffer) do
+ var i = entities.iterator
+ if i.is_ok then
+ i.item.append_json_for(self, b)
+ i.next
+ for entity in i do
+ b.add ','
+ entity.append_json_for(self, b)
+ end
+ end
+ end
+end
+
+redef class NeoNodeCollection
+ # Convert the specified JSON value into a local ID.
+ fun id_from_jsonable(id: nullable Jsonable): ID_TYPE do return id.as(ID_TYPE)
+end
+
+redef class NeoEntity
+
+ # Append the JSON representation of the entity to the specified buffer.
+ fun append_json_for(graph: NeoGraph, buffer: Buffer) is abstract
+end
+
+# Make `NeoNode` `Jsonable`.
+redef class NeoNode
+ super Jsonable
+
+ # Retrieve the node from the specified JSON value.
+ #
+ # Note: Here, the `"id"` is optional and ignored.
+ #
+ # SEE: `JsonGraph`
+ #
+ # var node = new NeoNode.from_json("""
+ # {
+ # "labels": ["foo", "Bar"],
+ # "properties": {
+ # "baz": 42
+ # }
+ # }
+ # """)
+ # assert ["foo", "Bar"] == node.labels
+ # assert 42 == node["baz"]
+ init from_json(t: Text) do
+ from_json_object(t.parse_json.as(JsonObject))
+ end
+
+ # Retrieve the node from the specified JSON value.
+ #
+ # Note: Here, the `"id"` is optional and ignored.
+ #
+ # SEE: `JsonGraph`
+ init from_json_object(o: JsonObject) do
+ init
+ var labels = o["labels"].as(JsonArray)
+ for lab in labels do self.labels.add(lab.as(String))
+ var json_properties = o["properties"].as(JsonObject)
+ properties.recover_with(json_properties)
+ end
+
+ redef fun to_json do return to_json_by_append
+
+ # Append the JSON representation of the node to the specified buffer.
+ #
+ # SEE: `JsonGraph`
+ redef fun append_json(b) do
+ b.append "\{\"labels\":["
+ var i = labels.iterator
+ if i.is_ok then
+ i.item.append_json(b)
+ i.next
+ for lab in i do
+ b.add ','
+ lab.append_json(b)
+ end
+ end
+ b.append "],\"properties\":"
+ properties.append_json(b)
+ b.add '}'
+ end
+
+ redef fun to_s do return to_json
+
+ # Append the JSON representation of the node to the specified buffer.
+ redef fun append_json_for(graph: NeoGraph, buffer: Buffer) do
+ append_json(buffer)
+ end
+end
+
+redef class NeoEdge
+
+ # Append the JSON representation of the relationship to the specified buffer.
+ #
+ # Use the IDs specfied by `graph.nodes`.
+ redef fun append_json_for(graph: NeoGraph, buffer: Buffer) do
+ buffer.append "\{\"type\":"
+ rel_type.append_json(buffer)
+ buffer.append ",\"properties\":"
+ properties.append_json(buffer)
+ buffer.append ",\"from\":"
+ graph.nodes.id_of(from).append_json(buffer)
+ buffer.append ",\"to\":"
+ graph.nodes.id_of(to).append_json(buffer)
+ buffer.append "}"
+ end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Provides a sequential identification scheme for Neo4j nodes.
+module neo4j::graph::sequential_id
+
+import graph
+private import pipeline
+
+
+# A Neo4j node collection using a sequential identification scheme.
+#
+# The local IDs are sequential numbers (integers) starting at `1`.
+#
+# Note: When loading nodes, the local IDs should forms a mostly contiguous
+# range starting at `1`. Else, this collection will consume a lot of memory.
+# Futhermore, the local IDs **must** be positive.
+#
+# ~~~nit
+# var nodes = new SequentialNodeCollection("id")
+# var a = nodes.create_node
+# var b = new NeoNode
+# var c = new NeoNode
+#
+# nodes.register b
+# c["id"] = 4
+# nodes.add c
+# assert a["id"] == 1
+# assert b["id"] == 2
+# assert c["id"] == 4
+# assert nodes.to_a == [a, b, c]
+# assert nodes.length == 3
+#
+# nodes.compact
+# assert a["id"] == 1
+# assert b["id"] == 2
+# assert c["id"] == 3
+# assert nodes.to_a == [a, b, c]
+# assert nodes.length == 3
+# ~~~
+class SequentialNodeCollection
+ super NeoNodeCollection
+
+ redef type ID_TYPE: Int
+
+ private var nodes = new Array[nullable NeoNode]
+
+ redef var length = 0
+
+ redef fun iterator do return new NullSkipper[NeoNode](self.nodes.iterator)
+
+ redef fun [](id) do return nodes[id].as(NeoNode)
+
+ redef fun get_or_null(id) do
+ if id < 0 or id > nodes.length then return null
+ return nodes[id]
+ end
+
+ redef fun has_id(id: Int): Bool do
+ return id >= 0 and id < nodes.length and nodes[id] isa NeoNode
+ end
+
+ redef fun enlarge(cap) do nodes.enlarge(cap)
+
+ redef fun register(node) do
+ nodes.add node
+ id_of(node) = nodes.length
+ length += 1
+ end
+
+ redef fun add(node) do
+ var id = node[id_property]
+ assert id isa Int else
+ sys.stderr.write "The local ID must be an `Int`.\n"
+ end
+ assert id >= 0 else
+ sys.stderr.write "The local ID must be greater or equal to 0. Got {id}.\n"
+ end
+ # Pad with nulls.
+ nodes.enlarge(id)
+ var delta = id - nodes.length
+ while delta > 0 do
+ nodes.add null
+ delta -= 1
+ end
+ nodes[id] = node
+ length += 1
+ end
+
+ redef fun remove_at(id) do
+ nodes[id] = null
+ length -= 1
+ end
+
+ redef fun clear do
+ nodes.clear
+ length = 0
+ end
+
+ redef fun compact do
+ var i = iterator
+
+ nodes = new Array[nullable NeoNode]
+ for n in i do
+ nodes.add n
+ id_of(n) = nodes.length
+ end
+ end
+end
+++ /dev/null
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# This file is free software, which comes along with NIT. This software is
-# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE. You can modify it is you want, provided this header
-# is kept unaltered, and a notification of the changes is added.
-# You are allowed to redistribute it and sell it, alone or is a part of
-# another product.
-
-# Uses JSON as a storage medium for a Neo4j subgraph.
-module neo4j::json_store
-
-import neo4j
-private import template
-
-# A Neo4j graph that uses as a storage medium.
-#
-# The graph is stored as a JSON object with the following properties:
-#
-# * `"nodes"`: An array with all nodes. Each node is an object with the
-# following properties:
-# * `"id"`: The ID (`Int`) that uniquely identifies the node in the current
-# graph.
-# * `"labels"`: An array of all applied labels.
-# * `"properties"`: An object mapping each defined property to its value.
-# * `"links"`: An array with all relationships. Each relationship is an object
-# with the following properties:
-# * `"type"`: The type (`String`) of the relationship.
-# * `"properties"`: An object mapping each defined property to its value.
-# * `"from"`: The ID (`Int`) of the source node.
-# * `"to"`: The ID (`Int`) of the destination node.
-#
-# TODO Refine the graph API instead when it will be available.
-class JsonGraph
- super Jsonable
-
- # All nodes in the graph.
- var nodes: SimpleCollection[NeoNode] = new Array[NeoNode]
-
- # All relationships in the graph.
- var links: SimpleCollection[NeoEdge] = new Array[NeoEdge]
-
- # Create an empty graph.
- init do end
-
- # Retrieve the graph from the specified JSON value.
- #
- # var graph = new JsonGraph
- # var a = new NeoNode
- # a.labels.add "Foo"
- # a["answer"] = 42
- # a["Ultimate question of"] = new JsonArray.from(["life",
- # "the Universe", "and Everything."])
- # graph.nodes.add a
- # var b = new NeoNode
- # b.labels.add "Foo"
- # b.labels.add "Bar"
- # graph.nodes.add b
- # graph.links.add new NeoEdge(a, "BAZ", b)
- # #
- # graph = new JsonGraph.from_json(graph.to_json)
- # assert 1 == graph.links.length
- # for link in graph.links do
- # assert "BAZ" == link.rel_type
- # assert a.labels == link.from.labels
- # for k, v in a.properties do assert v == link.from.properties[k]
- # assert b.labels == link.to.labels
- # for k, v in b.properties do assert v == link.to.properties[k]
- # end
- # assert 2 == graph.nodes.length
- init from_json(t: Text) do
- from_json_object(t.parse_json.as(JsonObject))
- end
-
- # Retrieve the graph from the specified JSON object.
- init from_json_object(o: JsonObject) do
- var node_by_id = new HashMap[Int, NeoNode]
- var nodes = o["nodes"].as(JsonArray)
- for json_node in nodes do
- assert json_node isa JsonObject
- var node = new NeoNode.from_json_object(json_node)
- node_by_id[json_node["id"].as(Int)] = node
- self.nodes.add node
- end
- var links = o["links"].as(JsonArray)
- for json_link in links do
- assert json_link isa JsonObject
- var from = node_by_id[json_link["from"].as(Int)]
- var to = node_by_id[json_link["to"].as(Int)]
- var rel_type = json_link["type"].as(String)
- var json_properties = json_link["properties"].as(JsonObject)
- var link = new NeoEdge(from, rel_type, to)
- link.properties.recover_with(json_properties)
- self.links.add link
- end
- end
-
- redef fun to_json do
- var t = new Template
- t.add "\{\"nodes\":["
- var i = 0
- for n in nodes do
- if i > 0 then t.add ","
- t.add n.to_json
- i += 1
- end
- t.add "],\"links\":["
- i = 0
- for link in links do
- if i > 0 then t.add ","
- t.add link.to_json
- i += 1
- end
- t.add "]\}"
- return t.write_to_string
- end
-end
-
-# Make `NeoNode` `Jsonable`.
-redef class NeoNode
- super Jsonable
-
- # Retrieve the node from the specified JSON value.
- #
- # Note: Here, the `"id"` is optional and ignored.
- #
- # SEE: `JsonGraph`
- #
- # var node = new NeoNode.from_json("""
- # {
- # "labels": ["foo", "Bar"],
- # "properties": {
- # "baz": 42
- # }
- # }
- # """)
- # assert ["foo", "Bar"] == node.labels
- # assert 42 == node["baz"]
- init from_json(t: Text) do
- from_json_object(t.parse_json.as(JsonObject))
- end
-
- # Retrieve the node from the specified JSON value.
- #
- # Note: Here, the `"id"` is optional and ignored.
- #
- # SEE: `JsonGraph`
- init from_json_object(o: JsonObject) do
- init
- var labels = o["labels"].as(JsonArray)
- for lab in labels do self.labels.add(lab.as(String))
- var json_properties = o["properties"].as(JsonObject)
- properties.recover_with(json_properties)
- end
-
- # Get the JSON representation of `self`.
- #
- # SEE: `JsonGraph`
- redef fun to_json do
- var t = new Template
- t.add "\{\"id\":"
- t.add object_id.to_json
- t.add ",\"labels\":["
- var i = 0
- for lab in labels do
- if i > 0 then t.add ","
- t.add lab.to_json
- i += 1
- end
- t.add "],\"properties\":"
- t.add properties.to_json
- t.add "}"
- return t.write_to_string
- end
-
- redef fun to_s do return to_json
-end
-
-# Make `NeoEdge` `Jsonable`.
-redef class NeoEdge
- super Jsonable
-
- redef fun to_json do
- var t = new Template
- t.add "\{\"type\":"
- t.add rel_type.to_json
- t.add ",\"properties\":"
- t.add properties.to_json
- t.add ",\"from\":"
- t.add from.object_id.to_json
- t.add ",\"to\":"
- t.add to.object_id.to_json
- t.add "}"
- return t.write_to_string
- end
-
- redef fun to_s do return to_json
-end
private class DephIterator
super Iterator[Node]
+
var stack = new List[Iterator[nullable Node]]
- init(i: Iterator[nullable Node])
- do
+ init(i: Iterator[nullable Node]) is old_style_init do
stack.add i
end
var default_value: VALUE is writable
# Create a new option
- init(help: String, default: VALUE, names: nullable Array[String])
- do
+ init(help: String, default: VALUE, names: nullable Array[String]) is old_style_init do
init_opt(help, default, names)
end
+ # Init option `helptext`, `default_value` and `names`.
+ #
+ # Also set current `value` to `default`.
fun init_opt(help: String, default: VALUE, names: nullable Array[String])
do
if names == null then
return text.to_s
end
+ # Pretty print the default value.
fun pretty_default: String
do
var dv = default_value
# Not really an option. Just add a line of text when displaying the usage
class OptionText
super Option
- init(text: String) do super(text, null, null)
+
+ # Init a new OptionText with `text`.
+ init(text: String) is old_style_init do super(text, null, null)
redef fun pretty(off) do return to_s
super Option
redef type VALUE: Bool
- init(help: String, names: String...) do super(help, false, names)
+ # Init a new OptionBool with a `help` message and `names`.
+ init(help: String, names: String...) is old_style_init do super(help, false, names)
redef fun read_param(it)
do
super Option
redef type VALUE: Int
- init(help: String, names: String...) do super(help, 0, names)
+ # Init a new OptionCount with a `help` message and `names`.
+ init(help: String, names: String...) is old_style_init do super(help, 0, names)
redef fun read_param(it)
do
# Option with one parameter (mandatory by default)
abstract class OptionParameter
super Option
+
+ # Convert `str` to a value of type `VALUE`.
protected fun convert(str: String): VALUE is abstract
# Is the parameter mandatory?
super OptionParameter
redef type VALUE: nullable String
- init(help: String, names: String...) do super(help, null, names)
+ # Init a new OptionString with a `help` message and `names`.
+ init(help: String, names: String...) is old_style_init do super(help, null, names)
redef fun convert(str) do return str
end
class OptionEnum
super OptionParameter
redef type VALUE: Int
+
+ # Values in the enumeration.
var values: Array[String]
- init(values: Array[String], help: String, default: Int, names: String...)
- do
+ # Init a new OptionEnum from `values` with a `help` message and `names`.
+ #
+ # `default` is the index of the default value in `values`.
+ init(values: Array[String], help: String, default: Int, names: String...) is old_style_init do
assert values.length > 0
self.values = values.to_a
super("{help} <{values.join(", ")}>", default, names)
return id
end
+ # Get the value name from `values`.
fun value_name: String do return values[value]
redef fun pretty_default
super OptionParameter
redef type VALUE: Int
- init(help: String, default: Int, names: String...) do super(help, default, names)
+ # Init a new OptionInt with a `help` message, a `default` value and `names`.
+ init(help: String, default: Int, names: String...) is old_style_init do
+ super(help, default, names)
+ end
redef fun convert(str) do return str.to_i
end
super OptionParameter
redef type VALUE: Float
- init(help: String, default: Float, names: String...) do super(help, default, names)
+ # Init a new OptionFloat with a `help` message, a `default` value and `names`.
+ init(help: String, default: Float, names: String...) is old_style_init do
+ super(help, default, names)
+ end
redef fun convert(str) do return str.to_f
end
super OptionParameter
redef type VALUE: Array[String]
- init(help: String, names: String...)
- do
+ # Init a new OptionArray with a `help` message and `names`.
+ init(help: String, names: String...) is old_style_init do
values = new Array[String]
super(help, values, names)
end
end
end
+ # Options parsing errors.
fun get_errors: Array[String]
do
var errors = new Array[String]
end
end
+# Wraps an iterator to skip nulls.
+#
+# ~~~nit
+# var i: Iterator[Int]
+#
+# i = new NullSkipper[Int]([null, 1, null, 2, null: nullable Int].iterator)
+# assert i.to_a == [1, 2]
+#
+# i = new NullSkipper[Int]([1, null, 2, 3: nullable Int].iterator)
+# assert i.to_a == [1, 2, 3]
+# ~~~
+class NullSkipper[E: Object]
+ super Iterator[E]
+
+ # The inner iterator.
+ var inner: Iterator[nullable E]
+
+ redef fun finish do inner.finish
+
+ redef fun is_ok do
+ skip_nulls
+ return inner.is_ok
+ end
+
+ redef fun item do
+ skip_nulls
+ return inner.item.as(E)
+ end
+
+ redef fun next do
+ inner.next
+ skip_nulls
+ end
+
+ private fun skip_nulls do
+ while inner.is_ok and inner.item == null do inner.next
+ end
+end
+
# Interface that reify a function.
# Concrete subclasses must implements the `apply` method.
#
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Event-based interface to track the progression of an operation.
+module progression
+
+# An operation that is trackable using a `ProgressionListener`.
+abstract class Trackable
+
+ # Listen to the progression of the operation.
+ var progression_listeners: SimpleCollection[ProgressionListener] =
+ new Array[ProgressionListener]
+
+ # Notice the registered `ProgessionListener` that the operation started.
+ protected fun fire_started do
+ for l in progression_listeners do
+ l.started
+ l.progressed(0)
+ end
+ end
+
+ # Notice the registered `ProgessionListener` that the operation progressed.
+ #
+ # Parameter:
+ #
+ # * `done_part`: Indicates what is done.
+ # * `total`: Indicates what need to be done, `done_part` included.
+ protected fun fire_progressed(done_part: Int, total: Int) do
+ for l in progression_listeners do
+ l.progressed(done_part * l.progression_max / total)
+ end
+ end
+
+ # Notice the registered `ProgessionListener` that the operation is done.
+ protected fun fire_done do
+ for l in progression_listeners do
+ l.progressed(l.progression_max)
+ l.done
+ end
+ end
+end
+
+# Listens to the progression of a possibly long-running operation.
+interface ProgressionListener
+ # The number that represents a completed operation.
+ fun progression_max: Int do return 100
+
+ # The operation started.
+ fun started do end
+
+ # The operation progressed.
+ #
+ # Parameter:
+ #
+ # * `progression`: Indicator of the progession, between `0` and
+ # `progression_max`.
+ fun progressed(progression: Int) do end
+
+ # The operation is done.
+ fun done do end
+end
# height of the sprite
var height: Int = 100 is writable
+ # X coordinate of left side.
fun left: Int do return x - width/2
+
+ # X coordinate of right side.
fun right: Int do return x + width/2
+
+ # Y coordinate of top.
fun top: Int do return y - height/2
+
+ # Y coordinate of bottom.
fun bottom: Int do return y + height/2
# x velocity (applied by `update')
super LiveObject
super List[E]
- init
- do
- end
-
# Recursively update each live objects that `exists'
redef fun update
do
closed = true
return
end
- socket.setsockopt(new NativeSocketOptLevels.socket, new NativeSocketOptNames.reuseaddr, 1)
+ if not socket.setsockopt(new NativeSocketOptLevels.socket, new NativeSocketOptNames.reuseaddr, 1) then
+ end_reached = true
+ closed = true
+ return
+ end
var hostname = socket.gethostbyname(host)
addrin = new NativeSocketAddrIn.with_hostent(hostname, port)
fun ready_to_read(timeout: Int): Bool
do
if _buffer_pos < _buffer.length then return true
- if eof then return false
+ if end_reached then return false
var events = [new NativeSocketPollValues.pollin]
return pollin(events, timeout).length != 0
end
if closed then return
if socket.close >= 0 then
closed = true
+ end_reached = true
end
end
# Send the data present in the socket buffer
fun flush
do
- socket.setsockopt(new NativeSocketOptLevels.tcp, new NativeSocketOptNames.tcp_nodelay, 1)
- socket.setsockopt(new NativeSocketOptLevels.tcp, new NativeSocketOptNames.tcp_nodelay, 0)
+ if not socket.setsockopt(new NativeSocketOptLevels.tcp, new NativeSocketOptNames.tcp_nodelay, 1) or
+ not socket.setsockopt(new NativeSocketOptLevels.tcp, new NativeSocketOptNames.tcp_nodelay, 0) then
+ closed = true
+ end
end
end
socket = new NativeSocket.socket(new NativeSocketAddressFamilies.af_inet,
new NativeSocketTypes.sock_stream, new NativeSocketProtocolFamilies.pf_null)
assert not socket.address_is_null
- socket.setsockopt(new NativeSocketOptLevels.socket, new NativeSocketOptNames.reuseaddr, 1)
+ if not socket.setsockopt(new NativeSocketOptLevels.socket, new NativeSocketOptNames.reuseaddr, 1) then
+ closed = true
+ return
+ end
addrin = new NativeSocketAddrIn.with(port, new NativeSocketAddressFamilies.af_inet)
address = addrin.address
# Wrapper for the data structure PollFD used for polling on a socket
class PollFD
+ super FinalizableOnce
# The PollFD object
private var poll_struct: NativeSocketPollFD
return response & mask;
`}
+ redef fun finalize_once
+ do
+ poll_struct.free
+ end
end
# Data structure used by the poll function
-private extern class NativeSocketPollFD `{ struct pollfd `}
+private extern class NativeSocketPollFD `{ struct pollfd * `}
- # File descriptor id
- private fun fd: Int `{ return recv.fd; `}
+ # File descriptor
+ fun fd: Int `{ return recv->fd; `}
# List of events to be watched
- private fun events: Int `{ return recv.events; `}
+ fun events: Int `{ return recv->events; `}
# List of events received by the last poll function
- private fun revents: Int `{ return recv.revents; `}
+ fun revents: Int `{ return recv->revents; `}
new (pid: Int, events: NativeSocketPollValues) `{
- struct pollfd poll;
- poll.fd = pid;
- poll.events = events;
+ struct pollfd *poll = malloc(sizeof(struct pollfd));
+ poll->fd = pid;
+ poll->events = events;
return poll;
`}
-
end
extern class NativeSocket `{ int* `}
`}
# Sets an option for the socket
- fun setsockopt(level: NativeSocketOptLevels, option_name: NativeSocketOptNames, option_value: Int) `{
+ #
+ # Returns `true` on success.
+ fun setsockopt(level: NativeSocketOptLevels, option_name: NativeSocketOptNames, option_value: Int): Bool `{
int err = setsockopt(*recv, level, option_name, &option_value, sizeof(int));
if(err != 0){
- perror("Error on setsockopts: ");
- exit(1);
+ return 0;
}
+ return 1;
`}
fun bind(addrIn: NativeSocketAddrIn): Int `{ return bind(*recv, (struct sockaddr*)addrIn, sizeof(*addrIn)); `}
# The array's members are pollfd structures within which fd specifies an open file descriptor and events and revents are bitmasks constructed by
# OR'ing a combination of the pollfd flags.
private fun native_poll(filedesc: NativeSocketPollFD, timeout: Int): Int `{
- int poll_return = poll(&filedesc, 1, timeout);
+ int poll_return = poll(filedesc, 1, timeout);
return poll_return;
`}
# Novell Internet Protocol
new af_ipx `{ return AF_IPX; `}
- # Integrated Services Digital Network
- new af_isdn `{ return AF_ISDN; `}
-
# IPv6
new af_inet6 `{ return AF_INET6; `}
new pf_decnet `{ return PF_DECnet; `}
new pf_route `{ return PF_ROUTE; `}
new pf_ipx `{ return PF_IPX; `}
- new pf_isdn `{ return PF_ISDN; `}
new pf_key `{ return PF_KEY; `}
new pf_inet6 `{ return PF_INET6; `}
new pf_max `{ return PF_MAX; `}
end
# MapRead are abstract associative collections: `key` -> `item`.
-interface MapRead[K: Object, V]
+interface MapRead[K, V]
# Get the item at `key`
#
# var x = new HashMap[String, Int]
# assert map.values.has(1) == true
# assert map.values.has(3) == false
#
-interface Map[K: Object, V]
+interface Map[K, V]
super MapRead[K, V]
# Set the `value` at `key`.
end
# Iterators for Map.
-interface MapIterator[K: Object, V]
+interface MapIterator[K, V]
# The current item.
# Require `is_ok`.
fun item: V is abstract
end
# Iterator on a 'keys' point of view of a map
-class MapKeysIterator[K: Object, V]
+class MapKeysIterator[K, V]
super Iterator[K]
# The original iterator
var original_iterator: MapIterator[K, V]
end
# Iterator on a 'values' point of view of a map
-class MapValuesIterator[K: Object, V]
+class MapValuesIterator[K, V]
super Iterator[V]
# The original iterator
var original_iterator: MapIterator[K, V]
# Associative arrays that internally uses couples to represent each (key, value) pairs.
# This is an helper class that some specific implementation of Map may implements.
-interface CoupleMap[K: Object, V]
+interface CoupleMap[K, V]
super Map[K, V]
# Return the couple of the corresponding key
# Iterator on CoupleMap
#
# Actually it is a wrapper around an iterator of the internal array of the map.
-private class CoupleMapIterator[K: Object, V]
+private class CoupleMapIterator[K, V]
super MapIterator[K, V]
redef fun item do return _iter.item.second
_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
# 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
# Associative arrays implemented with an array of (key, value) pairs.
-class ArrayMap[K: Object, E]
+class ArrayMap[K, E]
super CoupleMap[K, E]
# O(n)
end
end
-private class ArrayMapKeys[K: Object, E]
+private class ArrayMapKeys[K, E]
super RemovableCollection[K]
# The original map
var map: ArrayMap[K, E]
redef fun remove_all(key) do self.remove(key)
end
-private class ArrayMapValues[K: Object, E]
+private class ArrayMapValues[K, E]
super RemovableCollection[E]
# The original map
var map: ArrayMap[K, E]
# You are allowed to redistribute it and sell it, alone or is a part of
# another product.
-# Introduce Hashmap and Hashset.
+# Introduce `HashMap` and `HashSet`.
module hash_collection
import array
+redef class Map[K, V]
+ # Get a `HashMap[K, V]` as default implementation
+ new do return new HashMap[K, V]
+end
+
# A HashCollection is an array of HashNode[K] indexed by the K hash value
-private abstract class HashCollection[K: Object]
+private abstract class HashCollection[K]
type N: HashNode[K]
var array: nullable NativeArray[nullable N] = null # Used to store items
# Return the index of the key k
fun index_at(k: K): Int
do
+ if k == null then return 0
+
var i = k.hash % _capacity
if i < 0 then i = - i
return i
end
- # Return the node assosiated with the key
+ # Return the node associated with the key
fun node_at(k: K): nullable N
do
# cache: `is` is used instead of `==` because it is a faster filter (even if not exact)
return res
end
- # Return the node assosiated with the key (but with the index already known)
+ # Return the node associated with the key (but with the index already known)
fun node_at_idx(i: Int, k: K): nullable N
do
var c = _array[i]
end
end
-private abstract class HashNode[K: Object]
+private abstract class HashNode[K]
var key: K
type N: HashNode[K]
var next_item: nullable N = null
var next_in_bucklet: nullable N = null
end
-# A map implemented with a hash table.
-# Keys of such a map cannot be null and require a working `hash` method
-class HashMap[K: Object, V]
+# A `Map` implemented with a hash table.
+#
+# ~~~
+# var map = new HashMap[nullable String, Int]
+# map[null] = 0
+# map["one"] = 1
+# map["two"] = 2
+#
+# assert map[null] == 0
+# assert map["one"] == 1
+# assert map.keys.has("two")
+# assert map.values.length == 3
+# ~~~
+class HashMap[K, V]
super Map[K, V]
super HashCollection[K]
end
# View of the keys of a HashMap
-private class HashMapKeys[K: Object, V]
+private class HashMapKeys[K, V]
super RemovableCollection[K]
# The original map
var map: HashMap[K, V]
end
# View of the values of a Map
-private class HashMapValues[K: Object, V]
+private class HashMapValues[K, V]
super RemovableCollection[V]
# The original map
var map: HashMap[K, V]
end
end
-private class HashMapNode[K: Object, V]
+private class HashMapNode[K, V]
super HashNode[K]
redef type N: HashMapNode[K, V]
var value: V
end
# A `MapIterator` over a `HashMap`.
-class HashMapIterator[K: Object, V]
+class HashMapIterator[K, V]
super MapIterator[K, V]
redef fun is_ok do return _node != null
/* calls */
execvp(prog, arg);
- abort();
+ _exit(127);
}
else if (id > 0)
{ /* father */
# to use attributes of this instances.
fun finalize do end
end
+
+# An object to be finalized only once
+#
+# This is an utility sub-class to `Finalizable` which ensures that `finalized_once`
+# is called only once per instance. User classes implementing `FinalizableOnce`
+# shoud specialize `finalize_once` and _not_ `finalize`. When manipulating the user
+# class, only `finalize` should be called as it protects `finalize_once`.
+class FinalizableOnce
+ super Finalizable
+
+ # Has `self` been finalized? (either by the GC or an explicit call to `finalize`)
+ var finalized = false
+
+ redef fun finalize
+ do
+ if finalized then return
+
+ finalize_once
+ finalized = true
+ end
+
+ # Real finalization method of `FinalizableOnce`, will be called only once
+ #
+ # See: `Finalizable::finalize` for restrictions on finalizer methods.
+ protected fun finalize_once do end
+end
source = ""
end
+ redef fun read_all do
+ var c = cursor
+ cursor = source.length
+ if c == 0 then return source
+ return source.substring_from(c)
+ end
+
redef fun eof do return cursor >= source.length
end
from = 0
end
- var realFrom = index_from + from
+ var new_from = index_from + from
- if (realFrom + count) > index_to then return new FlatString.with_infos(items, index_to - realFrom + 1, realFrom, index_to)
+ if (new_from + count) > index_to then
+ var new_len = index_to - new_from + 1
+ if new_len <= 0 then return empty
+ return new FlatString.with_infos(items, new_len, new_from, index_to)
+ end
- if count == 0 then return empty
+ if count <= 0 then return empty
- var to = realFrom + count - 1
+ var to = new_from + count - 1
- return new FlatString.with_infos(items, to - realFrom + 1, realFrom, to)
+ return new FlatString.with_infos(items, to - new_from + 1, new_from, to)
end
redef fun empty do return "".as(FlatString)
var i = iterator
var k = i.key
var e = i.item
- s.append("{k}{couple_sep}{e or else "<null>"}")
+ s.append("{k or else "<null>"}{couple_sep}{e or else "<null>"}")
# Concat other items
i.next
s.append(sep)
k = i.key
e = i.item
- s.append("{k}{couple_sep}{e or else "<null>"}")
+ s.append("{k or else "<null>"}{couple_sep}{e or else "<null>"}")
i.next
end
return s.to_s
# A symbol is a unique immutable string
class Symbol
private var string: String
- redef fun to_s do return _string.to_s
-
- # Only used by String::to_symbol
- private init(s: String) do _string = s
+ redef fun to_s do return string.to_s
end
import websocket
-var sock = new WebSocket(8088, 1)
+var sock = new WebSocketListener(8088, 1)
var msg: String
print sys.errno.strerror
end
-sock.accept
+var cli: TCPStream
-while not sock.listener.closed do
- if not sock.connected then sock.accept
- if sys.stdin.poll_in then
- msg = gets
- printn "Received message : {msg}"
- if msg == "exit" then sock.close
- if msg == "disconnect" then sock.disconnect_client
- sock.write(msg)
- end
- if sock.can_read(10) then
- msg = sock.read_line
- if msg != "" then print msg
+while not sock.closed do
+ cli = sock.accept
+ while cli.connected do
+ if sys.stdin.poll_in then
+ msg = gets
+ printn "Received message : {msg}"
+ if msg == "disconnect" then cli.close
+ cli.write(msg)
+ end
+ if cli.can_read(10) then
+ msg = ""
+ while cli.can_read(0) do msg += cli.read(100)
+ if msg != "" then print msg
+ end
end
end
intrude import standard::stream
-# Websocket compatible server, works as an extra layer to the original Sockets
-class WebSocket
- super BufferedIStream
- super OStream
- super PollableIStream
-
- # Client connection to the server
- var client: TCPStream
+# Websocket compatible listener
+#
+# Produces Websocket client-server connections
+class WebSocketListener
+ super Socket
# Socket listening to connections on a defined port
var listener: TCPServer
# Creates a new Websocket server listening on given port with `max_clients` slots available
init(port: Int, max_clients: Int)
do
- _buffer = new FlatBuffer
- _buffer_pos = 0
listener = new TCPServer(port)
listener.listen max_clients
end
- # Accept an incoming connection and initializes the handshake
- fun accept
+ # Accepts an incoming connection
+ fun accept: WebsocketConnection
do
assert not listener.closed
var client = listener.accept
assert client != null
- self.client = client
+ return new WebsocketConnection(listener.port, "", client)
+ end
+
+ # Stop listening for incoming connections
+ fun close
+ do
+ listener.close
+ end
+end
+
+# Connection to a websocket client
+#
+# Can be used to communicate with a client
+class WebsocketConnection
+ super TCPStream
+
+ init do
+ _buffer = new FlatBuffer
+ _buffer_pos = 0
var headers = parse_handshake
var resp = handshake_response(headers)
client.write(resp)
end
- # Disconnect from a client
- fun disconnect_client
- do
- client.close
- end
+ # Client connection to the server
+ var client: TCPStream
- # Disconnects the client if one is connected
- # And stops the server
+ # Disconnect from a client
redef fun close
do
client.close
- listener.close
end
# Parses the input handshake sent by the client
# Reads an HTTP frame
protected fun read_http_frame(buf: Buffer): String
do
- client.append_line_to(buf)
- buf.chars.add('\n')
- if buf.has_substring("\r\n\r\n", buf.length - 4) then return buf.to_s
+ buf.append client.read_line
+ buf.append("\r\n")
+ if buf.has_suffix("\r\n\r\n") then return buf.to_s
return read_http_frame(buf)
end
end
# Checks if a connection to a client is available
- fun connected: Bool do return client.connected
+ redef fun connected do return client.connected
- redef fun write(msg: Text)
+ redef fun write(msg)
do
client.write(frame_message(msg.to_s))
end
unpad_message
end
- redef fun end_reached do return _buffer_pos >= _buffer.length and client.eof
+ redef fun end_reached do return client._buffer_pos >= client._buffer.length and client.end_reached
# Is there some data available to be read ?
fun can_read(timeout: Int): Bool do return client.ready_to_read(timeout)
`--colo-dead-methods`
: Force colorization of dead methods.
+`--colors-are-symbols`
+: Store colors as symbols instead of static data.
+
+ By default, the various identifiers used to implement OO-mechanisms are stored as genuine constant static variables.
+
+ This option uses linker symbols to encode these identifiers.
+ This makes the compiled program faster since less indirections are required to get the values.
+ It also produces executables that are a little bit smaller since static memory does not have to store the colors.
+
+ Warning: the usage of linker symbols is not portable on all toolchains (eg. Mac OS X).
+ Also, this option does nothing on some platforms (like android).
+
`--no-gcc-directive`
: Disable advanced gcc directives for optimization.
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)
# 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)
# Simple indirection to `Toolchain::write_and_make`
protected fun write_and_make(compiler: AbstractCompiler)
do
- var platform = compiler.mainmodule.target_platform
- var toolchain
- if platform == null then
- toolchain = new MakefileToolchain(toolcontext)
- else
- toolchain = platform.toolchain(toolcontext)
- end
+ var platform = compiler.target_platform
+ var toolchain = platform.toolchain(toolcontext)
compile_dir = toolchain.compile_dir
toolchain.write_and_make compiler
end
end
redef class Platform
- fun toolchain(toolcontext: ToolContext): Toolchain is abstract
+ # The specific tool-chain associated to the platform
+ fun toolchain(toolcontext: ToolContext): Toolchain do return new MakefileToolchain(toolcontext)
end
class Toolchain
fun write_files(compiler: AbstractCompiler, compile_dir: String, cfiles: Array[String])
do
- var platform = compiler.mainmodule.target_platform
- if self.toolcontext.opt_stacktrace.value == "nitstack" and (platform == null or platform.supports_libunwind) then compiler.build_c_to_nit_bindings
+ var platform = compiler.target_platform
+ if self.toolcontext.opt_stacktrace.value == "nitstack" and platform.supports_libunwind then compiler.build_c_to_nit_bindings
var cc_opt_with_libgc = "-DWITH_LIBGC"
- if platform != null and not platform.supports_libgc then cc_opt_with_libgc = ""
+ if not platform.supports_libgc then cc_opt_with_libgc = ""
# Add gc_choser.h to aditionnal bodies
var gc_chooser = new ExternCFile("gc_chooser.c", cc_opt_with_libgc)
fun write_makefile(compiler: AbstractCompiler, compile_dir: String, cfiles: Array[String])
do
var mainmodule = compiler.mainmodule
- var platform = compiler.mainmodule.target_platform
+ var platform = compiler.target_platform
var outname = outfile(mainmodule)
makefile.write("CC = ccache cc\nCXX = ccache c++\nCFLAGS = -g -O2 -Wno-unused-value -Wno-switch -Wno-attributes\nCINCL =\nLDFLAGS ?= \nLDLIBS ?= -lm {linker_options.join(" ")}\n\n")
var ost = toolcontext.opt_stacktrace.value
- if (ost == "libunwind" or ost == "nitstack") and (platform == null or platform.supports_libunwind) then makefile.write("NEED_LIBUNWIND := YesPlease\n")
+ if (ost == "libunwind" or ost == "nitstack") and platform.supports_libunwind then makefile.write("NEED_LIBUNWIND := YesPlease\n")
# Dynamic adaptations
# While `platform` enable complex toolchains, they are statically applied
dep_rules.add(o)
end
+ # Generate linker script, if any
+ if not compiler.linker_script.is_empty then
+ var linker_script_path = "{compile_dir}/linker_script"
+ ofiles.add "linker_script"
+ var f = new OFStream.open(linker_script_path)
+ for l in compiler.linker_script do
+ f.write l
+ f.write "\n"
+ end
+ f.close
+ end
+
var java_files = new Array[ExternFile]
var pkgconfigs = new Array[String]
# Is hardening asked? (see --hardening)
fun hardening: Bool do return self.modelbuilder.toolcontext.opt_hardening.value
+ # The targeted specific platform
+ var target_platform: Platform is noinit
+
init
do
self.realmainmodule = mainmodule
+ target_platform = mainmodule.target_platform or else new Platform
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
# Where global declaration are stored (the main .h)
var header: CodeWriter is writable, noinit
+ # Additionnal linker script for `ld`.
+ # Mainly used to do specific link-time symbol resolution
+ var linker_script = new Array[String]
+
# Provide a declaration that can be requested (before or latter) by a visitor
fun provide_declaration(key: String, s: String)
do
var v = self.new_visitor
v.add_decl("#include <signal.h>")
var ost = modelbuilder.toolcontext.opt_stacktrace.value
- var platform = mainmodule.target_platform
+ var platform = target_platform
- if platform != null and not platform.supports_libunwind then ost = "none"
+ if not platform.supports_libunwind then ost = "none"
- var no_main = (platform != null and platform.no_main) or modelbuilder.toolcontext.opt_no_main.value
+ var no_main = platform.no_main or modelbuilder.toolcontext.opt_no_main.value
if ost == "nitstack" or ost == "libunwind" then
v.add_decl("#define UNW_LOCAL_ONLY")
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
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
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
redef fun supports_libunwind do return false
+ redef fun supports_linker_script do return false
+
redef fun toolchain(toolcontext) do return new AndroidToolchain(toolcontext)
end
<application
android:label="@string/app_name"
android:hasCode="true"
- android:debuggable="{{{not release}}}">
+ android:debuggable="{{{not release}}}"
+ {{{icon_declaration}}}>
<!-- Our activity is the built-in NativeActivity framework class.
This will take care of integrating with our NDK code. -->
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
<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)
# Move the apk to the target
var outname = outfile(compiler.mainmodule)
- var src_apk_suffix
if release then
- src_apk_suffix = "release-unsigned"
- else src_apk_suffix = "debug"
+ var apk_path = "{android_project_root}/bin/{compiler.mainmodule.name}-release-unsigned.apk"
+
+ # Sign APK
+ var keystore_path= "KEYSTORE".environ
+ var key_alias= "KEY_ALIAS".environ
+ var tsa_server= "TSA_SERVER".environ
+
+ if key_alias.is_empty then
+ toolcontext.fatal_error(null,
+ "Fatal Error: the environment variable `KEY_ALIAS` must be set to use the `--release` option on Android projects.")
+ end
- toolcontext.exec_and_check(["mv", "{android_project_root}/bin/{compiler.mainmodule.name}-{src_apk_suffix}.apk", outname], "Android project error")
+ args = ["jarsigner", "-sigalg", "MD5withRSA", "-digestalg", "SHA1", apk_path, key_alias]
+
+ ## Use a custom keystore
+ if not keystore_path.is_empty then args.add_all(["-keystore", keystore_path])
+
+ ## Use a TSA server
+ if not tsa_server.is_empty then args.add_all(["-tsa", tsa_server])
+
+ toolcontext.exec_and_check(args, "Android project error")
+
+ # Clean output file
+ if outname.to_path.exists then outname.to_path.delete
+
+ # Align APK
+ args = ["zipalign", "4", apk_path, outname]
+ toolcontext.exec_and_check(args, "Android project error")
+ else
+ # Move to the expected output path
+ args = ["mv", "{android_project_root}/bin/{compiler.mainmodule.name}-debug.apk", outname]
+ toolcontext.exec_and_check(args, "Android project error")
+ end
end
end
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)
ensure_compile_nitni_base(v)
- nitni_ccu.header_c_types.add("#include \"{name}._ffi.h\"\n")
+ nitni_ccu.header_c_types.add("#include \"{c_name}._ffi.h\"\n")
nitni_ccu.header_c_types.add """
extern void nitni_global_ref_incr(void*);
extern void nitni_global_ref_decr(void*);
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
redef class CCompilationUnit
fun write_as_nitni(mmodule: MModule, compdir: String)
do
- var base_name = "{mmodule.name}._nitni"
+ var base_name = "{mmodule.c_name}._nitni"
var h_file = "{base_name}.h"
write_header_to_file( mmodule, "{compdir}/{h_file}", new Array[String],
- "{mmodule.cname.to_s.to_upper}_NITG_NITNI_H")
+ "{mmodule.c_name.to_s.to_upper}_NITG_NITNI_H")
var c_file = "{base_name}.c"
write_body_to_file( mmodule, "{compdir}/{c_file}", ["\"{h_file}\""] )
redef fun supports_libunwind do return false
redef fun supports_libgc do return false
+ redef fun supports_linker_script do return false
redef fun toolchain(toolcontext) do return new EnscriptenToolchain(toolcontext)
end
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
# 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)
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);")
var opt_no_union_attribute = new OptionBool("Put primitive attibutes in a box instead of an union", "--no-union-attribute")
# --no-shortcut-equate
var opt_no_shortcut_equate = new OptionBool("Always call == in a polymorphic way", "--no-shortcut-equal")
+ # --colors-are-symbols
+ var opt_colors_are_symbols = new OptionBool("Store colors as symbols (faster)", "--colors-are-symbols")
+
# --inline-coloring-numbers
var opt_inline_coloring_numbers = new OptionBool("Inline colors and ids (semi-global)", "--inline-coloring-numbers")
# --inline-some-methods
self.option_context.add_option(self.opt_separate)
self.option_context.add_option(self.opt_no_inline_intern)
self.option_context.add_option(self.opt_no_union_attribute)
- self.option_context.add_option(self.opt_no_shortcut_equate)
+ self.option_context.add_option(self.opt_no_shortcut_equate, opt_colors_are_symbols)
self.option_context.add_option(self.opt_inline_coloring_numbers, opt_inline_some_methods, opt_direct_call_monomorph, opt_skip_dead_methods, opt_semi_global)
self.option_context.add_option(self.opt_colo_dead_methods)
self.option_context.add_option(self.opt_tables_metrics)
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
# 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)
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
fun compile_color_const(v: SeparateCompilerVisitor, m: Object, color: Int) do
if color_consts_done.has(m) then return
- if m isa MProperty then
- if modelbuilder.toolcontext.opt_inline_coloring_numbers.value then
- self.provide_declaration(m.const_color, "#define {m.const_color} {color}")
- else
- self.provide_declaration(m.const_color, "extern const int {m.const_color};")
- v.add("const int {m.const_color} = {color};")
- end
- else if m isa MPropDef then
+ if m isa MEntity then
if modelbuilder.toolcontext.opt_inline_coloring_numbers.value then
self.provide_declaration(m.const_color, "#define {m.const_color} {color}")
- else
+ else if not modelbuilder.toolcontext.opt_colors_are_symbols.value or not v.compiler.target_platform.supports_linker_script then
self.provide_declaration(m.const_color, "extern const int {m.const_color};")
v.add("const int {m.const_color} = {color};")
- end
- else if m isa MType then
- if modelbuilder.toolcontext.opt_inline_coloring_numbers.value then
- self.provide_declaration(m.const_color, "#define {m.const_color} {color}")
else
- self.provide_declaration(m.const_color, "extern const int {m.const_color};")
- v.add("const int {m.const_color} = {color};")
+ # The color 'C' is the ``address'' of a false static variable 'XC'
+ self.provide_declaration(m.const_color, "#define {m.const_color} ((long)&X{m.const_color})\nextern const void X{m.const_color};")
+ if color == -1 then color = 0 # Symbols cannot be negative, so just use 0 for dead things
+ # Teach the linker that the address of 'XC' is `color`.
+ linker_script.add("X{m.const_color} = {color};")
end
+ else
+ abort
end
color_consts_done.add(m)
end
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
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
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
redef fun call(v, arguments) do abort
end
-redef class MType
- fun const_color: String do return "COLOR_{c_name}"
+redef class MEntity
+ var const_color: String is lazy do return "COLOR_{c_name}"
end
interface PropertyLayoutElement end
redef class MProperty
super PropertyLayoutElement
- fun const_color: String do return "COLOR_{c_name}"
end
redef class MPropDef
super PropertyLayoutElement
- fun const_color: String do return "COLOR_{c_name}"
end
redef class AMethPropdef
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)
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}));")
end
end
+ redef fun compile_types
+ do
+ compile_color_consts(vt_colors)
+ end
+
redef fun new_visitor do return new SeparateErasureCompilerVisitor(self)
# Stats
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
# write .cpp and .hpp file
cpp_file.header_custom.add("extern \"C\" \{\n")
- cpp_file.header_custom.add("#include \"{mmodule.name}._ffi.h\"\n")
+ cpp_file.header_custom.add("#include \"{mmodule.c_name}._ffi.h\"\n")
cpp_file.header_custom.add("\}\n")
var file = cpp_file.write_to_files(mmodule, compdir)
fun write_to_files(mmodule: MModule, compdir: String): ExternCppFile
do
- var base_name = "{mmodule.name}._ffi"
+ var base_name = "{mmodule.c_name}._ffi"
var h_file = "{base_name}.hpp"
- var guard = "{mmodule.cname.to_s.to_upper}_NIT_HPP"
+ var guard = "{mmodule.c_name.to_s.to_upper}_NIT_HPP"
write_header_to_file(mmodule, "{compdir}/{h_file}", new Array[String], guard)
# include dependancies FFI
for mod in header_dependencies do
- if mod.uses_ffi then ffi_ccu.header_custom.add("#include \"{mod.name}._ffi.h\"\n")
+ if mod.uses_ffi then ffi_ccu.header_custom.add("#include \"{mod.c_name}._ffi.h\"\n")
end
ffi_ccu.write_as_impl(self, compdir)
language.compile_module_block(block, ffi_ccu, mmodule)
end
- ffi_ccu.header_c_base.add( "#include \"{mmodule.name}._nitni.h\"\n" )
+ ffi_ccu.header_c_base.add( "#include \"{mmodule.c_name}._nitni.h\"\n" )
ffi_ccu.body_decl.add("#ifdef ANDROID\n")
ffi_ccu.body_decl.add(" #include <android/log.h>\n")
redef class CCompilationUnit
fun write_as_impl(mmodule: MModule, compdir: String)
do
- var base_name = "{mmodule.name}._ffi"
+ var base_name = "{mmodule.c_name}._ffi"
var h_file = "{base_name}.h"
- var guard = "{mmodule.cname.to_s.to_upper}_NIT_H"
+ var guard = "{mmodule.c_name.to_upper}_NIT_H"
write_header_to_file(mmodule, "{compdir}/{h_file}", new Array[String], guard)
var c_file = "{base_name}.c"
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
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"
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"
# write .m and _m.h file
mmodule.objc_file.header_c_types.add """
- #include "{{{mmodule.cname}}}._ffi.h"
+ #include "{{{mmodule.c_name}}}._ffi.h"
"""
var file = objc_file.write_to_files(mmodule, compdir)
# Write this compilation unit to Objective-C source files
fun write_to_files(mmodule: MModule, compdir: String): ExternObjCFile
do
- var base_name = "{mmodule.cname}._ffi"
+ var base_name = "{mmodule.c_name}._ffi"
var h_file = "{base_name}_m.h"
- var guard = "{mmodule.cname.to_s.to_upper}_NIT_OBJC_H"
+ var guard = "{mmodule.c_name.to_upper}_NIT_OBJC_H"
write_header_to_file(mmodule, compdir/h_file, new Array[String], guard)
var c_file = "{base_name}.m"
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)
sock.close
sys.set_io(ns,ns,ns)
else if self.toolcontext.opt_websocket_mode.value then
- var websock = new WebSocket(toolcontext.opt_debug_port.value, 1)
- websock.accept
- sys.set_io(websock,websock,websock)
+ var websock = new WebSocketListener(toolcontext.opt_debug_port.value, 1)
+ var cli = websock.accept
+ websock.close
+ sys.set_io(cli,cli,cli)
end
end
fun close_stdstreams
do
- if sys.stdin isa WebSocket or sys.stdin isa TCPStream then
+ if sys.stdin isa TCPStream then
sys.stdin.close
sys.stdout.close
sys.stderr.close
do
self.stdin = istream
self.stdout = ostream
- self.stderr = ostream
+ self.stderr = errstream
end
end
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])
module primitive_types
intrude import standard::file
+intrude import standard::string
# Wrapper for `NativeFile`
class PrimitiveNativeFile
- var file: FStream
+ var file: IOS
init native_stdin do
- file = new IFStream.from_fd(0)
+ file = sys.stdin
end
init native_stdout do
- file = new OFStream.from_fd(1)
+ file = sys.stdout
end
init native_stderr do
- file = new OFStream.from_fd(2)
+ file = sys.stderr
end
init io_open_read(path: String) do
file = new OFStream.open(path.to_s)
end
- fun address_is_null: Bool do return file._file.address_is_null
+ fun address_is_null: Bool do
+ if file isa FStream then return file.as(FStream)._file.address_is_null
+ return false
+ end
- fun io_read(buf: NativeString, len: Int): Int do return file._file.io_read(buf, len)
+ fun io_read(buf: NativeString, len: Int): Int do
+ if file isa FStream then return file.as(FStream)._file.io_read(buf, len)
+ var str = file.as(IStream).read(len)
+ str.to_cstring.copy_to(buf, str.length, 0, 0)
+ return str.length
+ end
- fun io_write(buf: NativeString, len: Int): Int do return file._file.io_write(buf, len)
+ fun io_write(buf: NativeString, len: Int): Int do
+ if file isa FStream then return file.as(FStream)._file.io_write(buf, len)
+ file.as(OStream).write(buf.to_s_with_length(len))
+ return len
+ end
- fun io_close: Int do return file._file.io_close
+ fun io_close: Int do
+ if file isa FStream then return file.as(FStream)._file.io_close
+ file.close
+ return 0
+ end
- fun fileno: Int do return file._file.fileno
+ fun fileno: Int do
+ if file isa FStream then return file.as(FStream)._file.fileno
+ return 0
+ end
- fun flush: Int do return file._file.flush
+ fun flush: Int do
+ if file isa FStream then return file.as(FStream)._file.flush
+ return 0
+ end
fun set_buffering_type(size, mode: Int): Int do
- return file._file.set_buffering_type(size, mode)
+ if file isa FStream then return file.as(FStream)._file.set_buffering_type(size, mode)
+ return 0
end
end
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:
#
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}")
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.
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)
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
# 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
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
# 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
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
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>
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 ***"
import parser
import modelbuilder # builder only for externcalls
-private import compiler::abstract_compiler
redef class MMethod
# Short name of this method in C (without the class name)
end
end
-redef class MModule
- # Mangled name of this module in C
- fun cname: String do return c_name # FIXME this is a hack to keep the internal FFI
- # API independent of the compilers while still using the `MModule::c_name` service.
-end
-
redef class MMethodDef
# Name of the function to callback this method from C,
# also used in other functions names used for this method.
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
var opt_meld = new OptionBool("Show diff between source and output using meld",
"--meld")
+ # Break too long string literals.
+ var opt_break_str = new OptionBool("Break too long string literals", "--break-strings")
+
+ # Force `do` on the same line as the method signature.
+ var opt_inline_do = new OptionBool("Force do keyword on the same line as the method signature",
+ "--inline-do")
+
+ # Force formatting on empty lines.
+ #
+ # By default empty lines are kept as they were typed in the file.
+ # When enabling this option, `nitpretty` will decide where to break lines
+ # and will put empty lines to separate properties and code blocks.
+ var opt_skip_empty = new OptionBool("Force formatting of empty lines", "--skip-empty")
+
# Check formatting instead of pretty printing.
#
# This option create a tempory pretty printed file then check if
# process options
var toolcontext = new ToolContext
-toolcontext.option_context.
- add_option(toolcontext.opt_dir, toolcontext.opt_output, toolcontext.opt_diff,
- toolcontext.opt_meld, toolcontext.opt_check)
+var opts = toolcontext.option_context
+opts.add_option(toolcontext.opt_dir, toolcontext.opt_output)
+opts.add_option(toolcontext.opt_diff, toolcontext.opt_meld, toolcontext.opt_check)
+opts.add_option(toolcontext.opt_break_str, toolcontext.opt_inline_do)
+opts.add_option(toolcontext.opt_skip_empty)
toolcontext.tooldescription = "Usage: nitpretty [OPTION]... <file.nit>\n" +
"Pretty print Nit code from Nit source files."
if not dir.file_exists then dir.mkdir
var v = new PrettyPrinterVisitor
+if toolcontext.opt_break_str.value then
+ v.break_strings = true
+end
+if toolcontext.opt_inline_do.value then
+ v.inline_do = true
+end
+if toolcontext.opt_skip_empty.value then
+ v.skip_empty = true
+end
+
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
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
# 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
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
# --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)
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]
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
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
# Sub-classes of `Platform` represent the target platform of a compilation
#
# Services will be added to this class in other modules.
-abstract class Platform
+class Platform
# Does the platform provide and support the library `unwind`?
fun supports_libunwind: Bool do return true
# Does this platform declare its own main function? If so, we won't generate one in Nit.
fun no_main: Bool do return false
+
+ # Does the platform accepts linker scripts?
+ fun supports_linker_script: Bool do return true
end
current_token = nmodule.location.file.first_token
visit nmodule
catch_up nmodule.location.file.last_token
- tpl.add "\n"
+ if skip_empty then tpl.add "\n"
return tpl.as(not null)
end
else
abort
end
- assert current_token.location <= token.location
+ if current_token.location > token.location then return
while current_token != token do visit current_token
end
visit current_token
end
- while current_token isa TEol do skip
+ while current_token isa TEol do visit(current_token)
end
# The template under construction.
if current_length == 0 and last_line_is_blank then return
previous_length = current_length
current_length = 0
+ if skip_empty then wait_addn += 1
+ end
+
+ # Perform `addn` even if not `skip_empty`.
+ fun forcen do
+ if current_length == 0 and last_line_is_blank then return
+ previous_length = current_length
+ current_length = 0
wait_addn += 1
end
consume "."
end
end
+
+ # Do we break string literals that are too long?
+ var break_strings = false is public writable
+
+ # Do we force `do` to be on the same line as the method signature?
+ var inline_do = false is public writable
+
+ # Do we force the deletion of empty lines?
+ var skip_empty = false is public writable
end
# Base framework redefs
if e != first then
if not e_can_inline then
v.add ","
- v.addn
- v.addt
+ v.forcen
+ v.indent += 1
v.addt
+ v.indent -= 1
else
v.add ", "
end
redef fun was_inline do return true
end
+redef class TEol
+ redef fun accept_pretty_printer(v) do
+ if v.skip_empty then
+ super
+ else
+ v.add text
+ v.current_token = next_token
+ end
+ end
+end
+
redef class Prod
redef fun accept_pretty_printer(v) do v.visit first_token
end
redef fun was_inline do
- return first_token.location.line_start == last_token.location.line_end
+ return start_token.location.line_start == last_token.location.line_end
end
end
if is_adoc then
v.addt
super
- v.addn
+ v.forcen
return
end
if is_licence then
super
- v.addn
+ v.forcen
if is_last_in_group then v.addn
return
end
v.addn
v.addt
super
- v.addn
+ v.forcen
v.addn
return
end
if next_token isa TComment and is_first_in_group then v.addn
v.addt
super
- v.addn
+ v.forcen
var prev_token = self.prev_token
if prev_token isa TComment and prev_token.is_inline and is_last_in_group then v.addn
return
end
super
+ if not v.skip_empty then v.forcen
end
# Is `self` part of an `ADoc`?
redef fun accept_pretty_printer(v) do
v.adds
v.consume "is"
-
if v.can_inline(self) then
v.adds
for n_item in n_items do
v.add ", "
end
end
- v.finish_line
- else if n_items.length > 1 then
- v.addn
+ if not was_inline then
+ v.finish_line
+ if v.current_token isa TKwend then v.skip
+ end
+ else
+ v.forcen
v.indent += 1
-
for n_item in n_items do
v.addt
v.visit n_item
v.finish_line
- v.addn
+ if n_item != n_items.last then
+ if was_inline then
+ v.forcen
+ else
+ v.addn
+ end
+ end
end
-
v.indent -= 1
end
- if not was_inline and v.current_token isa TKwend then v.skip
end
redef fun is_inlinable do
redef class AAnnotation
redef fun accept_pretty_printer(v) do
+ if n_visibility != null and not n_visibility isa APublicVisibility then
+ v.visit n_visibility
+ v.adds
+ end
v.visit n_atid
if not n_args.is_empty then
if n_opar == null then
v.visit n_moduledecl
if not n_imports.is_empty then
- v.addn
+ if v.skip_empty then v.addn
for n_import in n_imports do
v.catch_up n_import
end
if not n_classdefs.is_empty then
- v.addn
+ if v.skip_empty then v.addn
for n_classdef in n_classdefs do
v.catch_up n_classdef
end
v.finish_line
- v.addn
+ if v.skip_empty then v.addn
end
end
v.adds
v.visit n_kwend
v.finish_line
- v.addn
+ if v.skip_empty then v.addn
end
end
v.adds
v.visit n_name
v.finish_line
- v.addn
+ if v.skip_empty then v.addn
end
end
v.catch_up n_propdef
if n_propdef.n_doc != null or not v.can_inline(n_propdef) then
- if n_propdef != n_propdefs.first then v.addn
+ if v.skip_empty and n_propdef != n_propdefs.first then v.addn
v.visit n_propdef
- if n_propdef != n_propdefs.last then v.addn
+ if v.skip_empty and n_propdef != n_propdefs.last then v.addn
else
v.visit n_propdef
end
end
else
v.finish_line
- v.addn
+ if v.skip_empty then v.addn
v.indent += 1
for n_superclass in n_superclasses do
end
if not n_superclasses.is_empty and not n_propdefs.is_empty then
- v.addn
+ if v.skip_empty then v.addn
end
super
v.visit n_kwend
v.finish_line
- v.addn
+ if v.skip_empty then v.addn
assert v.indent == 0
end
end
end
+ # Factorize annotations visit for all APropdef.
+ #
+ # Return true if annotations were inlined.
+ fun visit_annotations(v: PrettyPrinterVisitor, n_annotations: nullable AAnnotations): Bool do
+ var res = v.can_inline(n_annotations)
+ if n_annotations != null then v.visit n_annotations
+ return res
+ end
+
+ # Factorize block visit for APropdefs.
+ #
+ # Were annotations printed inline? If so, we need to print the block differently.
+ fun visit_block(v: PrettyPrinterVisitor, n_block: nullable AExpr, annot_inline: Bool) do
+ # var can_inline = v.can_inline(n_block)
+ if n_block == null then return
+ if n_annotations != null and not annot_inline then
+ v.forcen
+ v.addt
+ end
+ if v.inline_do then
+ while not v.current_token isa TKwdo do v.skip
+ end
+ var token = v.current_token
+ var do_inline = true
+ loop
+ if token isa TEol then
+ v.skip
+ if not v.can_inline(n_block) then
+ v.forcen
+ v.addt
+ do_inline = false
+ end
+ end
+ token = v.current_token
+ if token isa TKwdo then break
+ end
+ if annot_inline and do_inline then v.adds
+ v.consume "do"
+
+ if v.can_inline(n_block) and do_inline then
+ v.adds
+
+ if n_block isa ABlockExpr then
+ if n_block.n_expr.is_empty then
+ v.visit n_block.n_kwend
+ else
+ v.visit n_block.n_expr.first
+ v.current_token = n_block.n_kwend
+ v.skip
+ end
+ else
+ v.visit n_block
+ if v.current_token isa TKwend then v.skip
+ end
+ else
+ v.finish_line
+ if was_inline then
+ v.forcen
+ else
+ v.addn
+ end
+ v.indent += 1
+
+ if n_block isa ABlockExpr then
+ n_block.force_block = true
+ v.visit n_block
+ v.catch_up n_block.n_kwend
+ else
+ v.addt
+ v.visit n_block
+ v.forcen
+ end
+
+ v.indent -= 1
+ v.addt
+ if n_block isa ABlockExpr then
+ v.visit n_block.n_kwend
+ else
+ v.add "end"
+ end
+ end
+ v.finish_line
+ end
+
redef fun start_token do
if n_doc == null then return super
return n_doc.last_token.next_token
v.visit n_expr
end
- if n_annotations != null then v.visit n_annotations
+ var annot_inline = visit_annotations(v, n_annotations)
+ visit_block(v, n_block, annot_inline)
v.finish_line
v.addn
end
v.consume ":"
v.adds
v.visit n_type
+ visit_annotations(v, n_annotations)
v.finish_line
v.addn
end
# TODO: Handle extern annotations
var before = v.indent
- var can_inline = v.can_inline(self)
super
if n_kwinit != null then v.visit n_kwinit
if n_kwmeth != null then v.visit n_kwmeth
v.visit n_signature
- if n_annotations != null then
- v.visit n_annotations
- else
- v.adds
- end
+ var annot_inline = visit_annotations(v, n_annotations)
if n_extern_calls != null or n_extern_code_block != null then
- if n_annotations != null then v.adds
+ v.adds
if n_extern_calls != null then v.visit n_extern_calls
if n_extern_code_block != null then v.visit n_extern_code_block
end
- var n_block = self.n_block
-
- if n_block != null then
- while not v.current_token isa TKwdo do v.skip
- if n_annotations != null then
- if v.can_inline(n_annotations) then
- v.adds
- else
- v.addt
- end
- end
- v.consume "do"
-
- if can_inline then
- v.adds
-
- if n_block isa ABlockExpr then
- if n_block.n_expr.is_empty then
- v.visit n_block.n_kwend
- else
- v.visit n_block.n_expr.first
- v.current_token = n_block.n_kwend
- v.skip
- end
- else
- v.visit n_block
- if v.current_token isa TKwend then v.skip
- end
- else
- v.finish_line
- v.addn
- v.indent += 1
-
- if n_block isa ABlockExpr then
- n_block.force_block = true
- v.visit n_block
- v.catch_up n_block.n_kwend
- else
- v.addt
- v.visit n_block
- v.addn
- end
-
- v.indent -= 1
- v.addt
- if n_block isa ABlockExpr then
- v.visit n_block.n_kwend
- else
- v.add "end"
- end
- end
- end
-
- v.finish_line
+ visit_block(v, n_block, annot_inline)
v.addn
assert v.indent == before
end
redef class AMainMethPropdef
redef fun accept_pretty_printer(v) do
v.visit n_block
- v.addn
+ if v.skip_empty then v.addn
end
end
v.visit_list n_extern_calls
else
v.addn
+ v.indent += 1
v.addt
- v.addt
+ v.indent -= 1
v.visit_list n_extern_calls
end
for line in lines do
v.add line.r_trim
- v.addn
+ v.forcen
end
v.addt
else if n_then == null then
v.add "end"
end
-
v.skip_to last_token.last_real_token_in_line
else
v.finish_line
- v.addn
+ if was_inline then
+ v.forcen
+ else if not v.skip_empty and n_then != null and
+ n_then.was_inline and
+ n_then.location.line_end == location.line_start then
+ v.forcen # Xymus fucking syntax
+ else
+ v.addn
+ end
v.indent += 1
if n_then != null then
else
v.addt
v.visit n_then
- v.addn
+ if n_then.was_inline then
+ v.forcen
+ else
+ v.addn
+ end
end
end
v.visit n_else
else
v.finish_line
- v.addn
+ if was_inline then
+ v.forcen
+ else
+ v.addn
+ end
v.indent += 1
if n_else isa ABlockExpr then
else
v.addt
v.visit n_else
- v.addn
+ if n_else.was_inline then
+ v.forcen
+ else
+ v.addn
+ end
end
if last_token isa TKwend then
if not n_expr isa AImplicitSelfExpr and not can_inline then
v.addn
v.addt
- v.addt
end
v.visit n_id
if not can_inline then
v.addn
+ v.indent += 1
v.addt
- v.addt
+ v.indent -= 1
end
v.visit n_id
v.visit n_else
else
v.addn
+ v.indent += 1
if n_else isa ABlockExpr then
- v.indent += 1
n_else.force_block = true
v.visit n_else
v.indent -= 1
v.addt
v.visit n_else.n_kwend
else
- v.indent += 1
v.addt
v.visit n_else
v.addn
v.visit bin_expr2
else
v.addn
+ v.indent += 1
v.addt
- v.addt
+ v.indent -= 1
v.visit bin_expr2
end
end
redef class AStringFormExpr
redef fun accept_pretty_printer(v) do
- var can_inline = v.can_inline(self)
-
- if can_inline then
+ if not v.break_strings then
+ # n_string.force_inline = true
+ v.visit n_string
+ return
+ end
+ if v.can_inline(self) then
+ n_string.force_inline = true
v.visit n_string
else
var text = n_string.text
if v.current_length >= v.max_size and i <= text.length - 3 then
v.add "\" +"
- v.addn
+ if was_inline then
+ v.forcen
+ else
+ v.addn
+ end
v.indent += 1
v.addt
v.indent -= 1
redef class ASuperstringExpr
redef fun accept_pretty_printer(v) do
- for n_expr in n_exprs do v.visit n_expr
+ for n_expr in n_exprs do
+ if not v.break_strings then
+ n_expr.force_inline = true
+ end
+ v.visit n_expr
+ end
end
redef fun must_be_inline do
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
#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)
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
is_col = true
end
- if mapit_cla != null and v.is_subtype(ittype, mapit_cla.get_mtype([objcla.mclass_type, objcla.mclass_type.as_nullable])) then
+ if mapit_cla != null and v.is_subtype(ittype, mapit_cla.get_mtype([objcla.mclass_type.as_nullable, objcla.mclass_type.as_nullable])) then
# Map Iterator
var coltype = ittype.supertype_to(v.mmodule, v.anchor, mapit_cla)
var variables = self.variables
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
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
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)
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
#
# Stops execution and prints errors if the program isn't available or didn't end correctly
fun exec_and_check(args: Array[String], error: String)
- do
- var prog = args.first
- args.remove_at 0
-
- # Is the wanted program available?
- var proc_which = new IProcess.from_a("which", [prog])
- proc_which.wait
- var res = proc_which.status
- if res != 0 then
- print "{error}: executable \"{prog}\" not found"
- exit 1
- end
-
- # Execute the wanted program
- var proc = new Process.from_a(prog, args)
- proc.wait
- res = proc.status
- if res != 0 then
- print "{error}: execution of \"{prog} {args.join(" ")}\" failed"
- exit 1
- end
- end
+ do
+ info("+ {args.join(" ")}", 2)
+
+ var prog = args.first
+ args.remove_at 0
+
+ # Is the wanted program available?
+ var proc_which = new IProcess.from_a("which", [prog])
+ proc_which.wait
+ var res = proc_which.status
+ if res != 0 then
+ print "{error}: executable \"{prog}\" not found"
+ exit 1
+ end
+
+ # Execute the wanted program
+ var proc = new Process.from_a(prog, args)
+ proc.wait
+ res = proc.status
+ if res != 0 then
+ print "{error}: execution of \"{prog} {args.join(" ")}\" failed"
+ exit 1
+ end
+ end
# Global OptionContext
var option_context = new OptionContext
end
#alt1# var b = [10, true]
+#alt2# var c = [null, null]
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import 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
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# 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
+--skip-empty test_pretty/test_mod1.nit
+--skip-empty test_pretty/test_mod2.nit
+--skip-empty test_pretty/test_mod3.nit
+--skip-empty test_pretty/test_class1.nit
+--skip-empty test_pretty/test_class2.nit
+--skip-empty test_pretty/test_class3.nit
+--skip-empty test_pretty/test_prop1.nit
+--skip-empty test_pretty/test_prop2.nit
+--skip-empty test_pretty/test_prop3.nit
+--skip-empty test_pretty/test_loop1.nit
+--skip-empty test_pretty/test_loop2.nit
+--skip-empty test_pretty/test_loop3.nit
+--skip-empty test_pretty/test_call1.nit
+--skip-empty test_pretty/test_call2.nit
+--skip-empty test_pretty/test_if1.nit
+--skip-empty test_pretty/test_if2.nit
+--skip-empty test_pretty/test_if3.nit
+--skip-empty test_pretty/test_op1.nit
+--skip-empty test_pretty/test_op2.nit
+--skip-empty test_pretty/test_op3.nit
+--skip-empty test_pretty/test_extern1.nit
+--skip-empty test_pretty/test_attr1.nit
+--skip-empty test_pretty/test_attr2.nit
+--skip-empty test_pretty/test_comments1.nit
+--skip-empty test_pretty/test_indent1.nit
+--skip-empty test_pretty/test_prims1.nit
+--skip-empty test_pretty/test_annot1.nit
+--skip-empty --break-strings test_pretty/test_prop1.nit
+--skip-empty --break-strings test_pretty/test_indent1.nit
+--skip-empty --inline-do test_pretty/test_prop1.nit
+--skip-empty --inline-do test_pretty/test_indent1.nit
test_pretty/test_mod1.nit
test_pretty/test_mod2.nit
test_pretty/test_mod3.nit
test_pretty/test_indent1.nit
test_pretty/test_prims1.nit
test_pretty/test_annot1.nit
+--break-strings test_pretty/test_prop1.nit
+--break-strings test_pretty/test_indent1.nit
+--inline-do test_pretty/test_prop1.nit
+--inline-do test_pretty/test_indent1.nit
--- /dev/null
+alt/base_array_alt2.nit:28,9--20: Type Error: ambiguous array type null null
--- /dev/null
+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
-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.
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+var a = 1
+var b = 2
+
+# 0
+if a == b then # 1
+ # 2
+else # 3
+ # 4
+end # 5
+
+if a == b then print a # printing a
+
+if a == b then
+ print a # printing a
+end
+
+if a == b then print a
+ # end
+
+if a == b then a = b
+
+if a == b then end
+
+if a == b then end
+
+if a != b then a = b
+
+
+if a > b then
+ a = b
+else
+ a = b
+end
+
+if a < b then
+ a = b
+else if a == b then
+ a = b
+end
+
+if a < b then
+ a = b
+else if a == b then
+ a = b
+else
+ a = b
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+module test_annot1 is platform("android")
+
+class A
+ fun goo is intern
+
+ # test
+ fun foo is a, b
+ fun bar is a, b do print "1"
+ fun baz is
+ a
+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+ do print "2"
+end
+
+class B
+ fun foo is a, b
+
+
+ fun bar is a, b
+ do print "1"
+
+ fun baz is a, b
+ do
+ bar
+ print "2"
+ end
+
+ fun gaz is
+ a
+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+
+ do
+ bar
+ print "2"
+ end
+
+end
# Difference in secondes from start (self if the end time)
fun difftime(start: TimeT): Float `{ return difftime(recv, start); `}
- private fun intern_poll(in_fds: Array[Int], out_fds: Array[Int]): nullable Int is extern import
- Array[Int].length, Array[Int].[], Int.as(nullable Int) `{`}
+ private fun intern_poll(in_fds: Array[Int], out_fds: Array[Int]): nullable Int is
+ extern import Array[Int].length, Array[Int].[], Int.as(nullable Int) `{`}
end
fun address_is_null: Bool is extern "address_is_null"
class Foo
fun bar: Bool do return true
- fun foo(other: Foo): Foo do
+ fun foo(other: Foo): Foo
+ do
if other.bar then
return other
else
return nb
end
- fun gaz: Int do
+ fun gaz: Int
+ do
if bar then # 3
return 1
else
end
end
- fun save_those_nodes(nodes: Collection[Object]) do for node in nodes do count(node)
+ fun save_those_nodes(nodes: Collection[Object]) do
+ for node in nodes do count(node)
+ end
end
fun foo do
end
end
-print "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam tincidun" +
- "t sapien et velit fringilla varius at non eros. Nunc ut ultricies metus, sit a" +
- "met lacinia felis. Donec in facilisis neque, non laoreet nibh. Etiam nec purus" +
- " eu orci congue iaculis eu quis lorem. Ut et blandit erat. Cras fermentum pell" +
- "entesque ante, ut dapibus ipsum placerat sit amet. Vivamus pharetra, sem vitae" +
- " consequat venenatis, diam risus placerat est, sed hendrerit purus justo vitae" +
- " lectus. In id quam mattis, rutrum augue eu, vehicula ipsum. Nulla nec egestas" +
- " turpis, nec ullamcorper odio. Pellentesque vitae arcu justo. Aliquam sed phar" +
- "etra lacus."
+print "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam tincidunt sapien et velit fringilla varius at non eros. Nunc ut ultricies metus, sit amet lacinia felis. Donec in facilisis neque, non laoreet nibh. Etiam nec purus eu orci congue iaculis eu quis lorem. Ut et blandit erat. Cras fermentum pellentesque ante, ut dapibus ipsum placerat sit amet. Vivamus pharetra, sem vitae consequat venenatis, diam risus placerat est, sed hendrerit purus justo vitae lectus. In id quam mattis, rutrum augue eu, vehicula ipsum. Nulla nec egestas turpis, nec ullamcorper odio. Pellentesque vitae arcu justo. Aliquam sed pharetra lacus."
var lorem = "lorem"
var ipsum = "ipsum" # for fun
-print "We also need to handle super strings: {lorem} {ipsum} dolor sit amet, con" +
- "sectetur adipiscing elit. Aliquam tincidunt sapien et velit fringilla varius a" +
- "t non eros. Nunc ut ultricies metus, sit amet lacinia felis. Donec in facilisi" +
- "s neque, non laoreet nibh. Etiam nec purus eu orci congue iaculis eu quis {lorem}" +
- ". Ut et blandit erat. Cras fermentum pellentesque ante, ut dapibus {ipsum} pla" +
- "cerat sit amet. Vivamus pharetra, sem vitae consequat venenatis, diam risus pl" +
- "acerat est, sed hendrerit purus justo vitae lectus. In id quam mattis, rutrum " +
- "augue eu, vehicula ipsum. Nulla nec egestas turpis, nec ullamcorper odio. Pell" +
- "entesque vitae arcu justo. Aliquam sed pharetra lacus." # ending
+print "We also need to handle super strings: {lorem} {ipsum} dolor sit amet, consectetur adipiscing elit. Aliquam tincidunt sapien et velit fringilla varius at non eros. Nunc ut ultricies metus, sit amet lacinia felis. Donec in facilisis neque, non laoreet nibh. Etiam nec purus eu orci congue iaculis eu quis {lorem}. Ut et blandit erat. Cras fermentum pellentesque ante, ut dapibus {ipsum} placerat sit amet. Vivamus pharetra, sem vitae consequat venenatis, diam risus placerat est, sed hendrerit purus justo vitae lectus. In id quam mattis, rutrum augue eu, vehicula ipsum. Nulla nec egestas turpis, nec ullamcorper odio. Pellentesque vitae arcu justo. Aliquam sed pharetra lacus." # ending
var title = "title"
var links = new Array[String] # why not?
module test_annot1 is platform("android")
class A
+ fun goo is intern
+
+ # test
fun foo is a, b
+
fun bar is a, b do print "1"
fun baz is
a
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
- do
- print "2"
- end
+ do print "2"
end
class B
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# comment 1
+class A
+ type FOO: Discrete
+ private var foo: FOO # comment
+
+ # comment 2
+ var bar: Int = 10
+end
+
+class B
+ super A
+
+ redef type FOO: Int
+
+ # comment 3
+ redef fun foo do return bar # comment
+
+ redef fun bar
+ do
+ return 10 # comment 4
+ end
+
+ fun baz do return # comment 5
+ protected fun baz2 do end
+
+ fun other: String do
+ return "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+ "aaaaaaaaaaaaaaaaaaaaaaaaaa"
+ end
+
+ fun foo1(arr: Array[String], len: Int, ind: Int): String
+ do
+ return "Hello World!"
+ end
+end
+
+# end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+class Foo
+ fun bar: Bool do return true
+
+ fun foo(other: Foo): Foo
+ do
+ if other.bar then
+ return other
+ else
+ return self
+ end
+ end
+
+ fun baz: Int do
+ var nb = 0
+
+ while nb < 10 do
+ print nb
+ nb += 1
+ end # 1
+
+ return nb
+ end
+
+ fun gaz: Int
+ do
+ if bar then # 3
+ return 1
+ else
+ return -1 # 4
+ end
+ end
+end
+
+class Test[E]
+ var heap: ArrayHeap[E]
+ init to(comparator: Comparator[E]) do heap = new ArrayHeap[E](comparator)
+
+ init from(comparator: Comparator[E], items: Collection[E]) do
+ heap = new ArrayHeap[E].from(comparator, items.to_a)
+ end
+
+ fun count(k: E): Int do
+ if heap.has(k) then
+ return 1
+ else
+ return 0
+ end
+ end
+
+ fun node_at_idx(i: Int, k: E) do
+ while heap != null do
+ if heap.is_empty or i == k then # FIXME prefilter because the compiler is not smart enought yet
+ break
+ end
+ end
+ end
+
+ fun save_those_nodes(nodes: Collection[Object]) do
+ for node in nodes do count(node)
+ end
+end
+
+fun foo do
+ if last_slash > 0 then
+ return substring(last_slash + 1, length)
+ else
+ return null
+ end
+end
+
+print "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam tincidun" +
+ "t sapien et velit fringilla varius at non eros. Nunc ut ultricies metus, sit a" +
+ "met lacinia felis. Donec in facilisis neque, non laoreet nibh. Etiam nec purus" +
+ " eu orci congue iaculis eu quis lorem. Ut et blandit erat. Cras fermentum pell" +
+ "entesque ante, ut dapibus ipsum placerat sit amet. Vivamus pharetra, sem vitae" +
+ " consequat venenatis, diam risus placerat est, sed hendrerit purus justo vitae" +
+ " lectus. In id quam mattis, rutrum augue eu, vehicula ipsum. Nulla nec egestas" +
+ " turpis, nec ullamcorper odio. Pellentesque vitae arcu justo. Aliquam sed phar" +
+ "etra lacus."
+
+var lorem = "lorem"
+var ipsum = "ipsum" # for fun
+
+print "We also need to handle super strings: {lorem} {ipsum} dolor sit amet, con" +
+ "sectetur adipiscing elit. Aliquam tincidunt sapien et velit fringilla varius a" +
+ "t non eros. Nunc ut ultricies metus, sit amet lacinia felis. Donec in facilisi" +
+ "s neque, non laoreet nibh. Etiam nec purus eu orci congue iaculis eu quis {lorem}" +
+ ". Ut et blandit erat. Cras fermentum pellentesque ante, ut dapibus {ipsum} pla" +
+ "cerat sit amet. Vivamus pharetra, sem vitae consequat venenatis, diam risus pl" +
+ "acerat est, sed hendrerit purus justo vitae lectus. In id quam mattis, rutrum " +
+ "augue eu, vehicula ipsum. Nulla nec egestas turpis, nec ullamcorper odio. Pell" +
+ "entesque vitae arcu justo. Aliquam sed pharetra lacus." # ending
+
+var title = "title"
+var links = new Array[String] # why not?
+
+var body = """
+<!DOCTYPE html>
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
+ <title>{{{title}}}</title>
+</head>
+<body>
+ <div class="container">
+ <h1>{{{title}}}</h1>
+ <ul>
+ <li>{{{links.join("</li>\n\t\t\t<li>")}}}</li>
+ </ul>
+ </div>
+</body>
+</html>"""
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# comment 1
+class A
+ type FOO: Discrete
+ private var foo: FOO # comment
+
+ # comment 2
+ var bar: Int = 10
+end
+
+class B
+ super A
+
+ redef type FOO: Int
+
+ # comment 3
+ redef fun foo do return bar # comment
+
+ redef fun bar do
+ return 10 # comment 4
+ end
+
+ fun baz do return # comment 5
+ protected fun baz2 do end
+
+ fun other: String do
+ return "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ end
+
+ fun foo1(arr: Array[String], len: Int, ind: Int): String do
+ return "Hello World!"
+ end
+end
+
+# end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+class Foo
+ fun bar: Bool do return true
+
+ fun foo(other: Foo): Foo do
+ if other.bar then
+ return other
+ else
+ return self
+ end
+ end
+
+ fun baz: Int do
+ var nb = 0
+
+ while nb < 10 do
+ print nb
+ nb += 1
+ end # 1
+
+ return nb
+ end
+
+ fun gaz: Int do
+ if bar then # 3
+ return 1
+ else
+ return -1 # 4
+ end
+ end
+end
+
+class Test[E]
+ var heap: ArrayHeap[E]
+ init to(comparator: Comparator[E]) do heap = new ArrayHeap[E](comparator)
+
+ init from(comparator: Comparator[E], items: Collection[E]) do
+ heap = new ArrayHeap[E].from(comparator, items.to_a)
+ end
+
+ fun count(k: E): Int do
+ if heap.has(k) then
+ return 1
+ else
+ return 0
+ end
+ end
+
+ fun node_at_idx(i: Int, k: E) do
+ while heap != null do
+ if heap.is_empty or i == k then # FIXME prefilter because the compiler is not smart enought yet
+ break
+ end
+ end
+ end
+
+ fun save_those_nodes(nodes: Collection[Object]) do
+ for node in nodes do count(node)
+ end
+end
+
+fun foo do
+ if last_slash > 0 then
+ return substring(last_slash + 1, length)
+ else
+ return null
+ end
+end
+
+print "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam tincidunt sapien et velit fringilla varius at non eros. Nunc ut ultricies metus, sit amet lacinia felis. Donec in facilisis neque, non laoreet nibh. Etiam nec purus eu orci congue iaculis eu quis lorem. Ut et blandit erat. Cras fermentum pellentesque ante, ut dapibus ipsum placerat sit amet. Vivamus pharetra, sem vitae consequat venenatis, diam risus placerat est, sed hendrerit purus justo vitae lectus. In id quam mattis, rutrum augue eu, vehicula ipsum. Nulla nec egestas turpis, nec ullamcorper odio. Pellentesque vitae arcu justo. Aliquam sed pharetra lacus."
+
+var lorem = "lorem"
+var ipsum = "ipsum" # for fun
+
+print "We also need to handle super strings: {lorem} {ipsum} dolor sit amet, consectetur adipiscing elit. Aliquam tincidunt sapien et velit fringilla varius at non eros. Nunc ut ultricies metus, sit amet lacinia felis. Donec in facilisis neque, non laoreet nibh. Etiam nec purus eu orci congue iaculis eu quis {lorem}. Ut et blandit erat. Cras fermentum pellentesque ante, ut dapibus {ipsum} placerat sit amet. Vivamus pharetra, sem vitae consequat venenatis, diam risus placerat est, sed hendrerit purus justo vitae lectus. In id quam mattis, rutrum augue eu, vehicula ipsum. Nulla nec egestas turpis, nec ullamcorper odio. Pellentesque vitae arcu justo. Aliquam sed pharetra lacus." # ending
+
+var title = "title"
+var links = new Array[String] # why not?
+
+var body = """
+<!DOCTYPE html>
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
+ <title>{{{title}}}</title>
+</head>
+<body>
+ <div class="container">
+ <h1>{{{title}}}</h1>
+ <ul>
+ <li>{{{links.join("</li>\n\t\t\t<li>")}}}</li>
+ </ul>
+ </div>
+</body>
+</html>"""
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+
+# An empty module
+
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Testing only imports
+
+# Module comment
+module test_mod2 # second comment
+
+import standard::kernel
+#import standard::string
+
+import template # no need for string
+# import standard
\ No newline at end of file
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# A simple module
+module test_mod3
+
+# before
+print "Hello World" # comment
+# after
+
+# end
+
+
+
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# comment 1
+interface A end
+
+abstract class B # comment 2
+end
+
+class C end # comment 3
+
+enum D end # comment 4
+
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+module test_class2
+
+
+# comment
+class A end
+
+class B[T] # comment
+end
+
+private class C[U, V: B[A]] end # comment
+
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# comment
+class A end
+
+class B[T] # comment
+ # comment
+ super A # comment
+
+
+ super C[A, B[A]]
+ # comment
+end
+
+class C[U, V: B[A]] end # comment
+
+class D super A end # comment
+
+class E
+
+
+
+ super A # comment
+end
+
+# end
+
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# comment 1
+class A
+ type FOO: Discrete
+ private var foo: FOO # comment
+ # comment 2
+ var bar: Int = 10
+end
+
+class B
+ super A
+
+ redef type FOO: Int
+ # comment 3
+ redef fun foo do return bar # comment
+ redef fun bar
+ do
+ return 10 # comment 4
+ end
+ fun baz do return # comment 5
+ protected fun baz2 do end
+ fun other: String do
+ return "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ end
+
+ fun foo1(arr: Array[String], len: Int, ind: Int): String
+ do
+ return "Hello World!"
+ end
+end
+
+# end
+
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+class A
+ fun foo(a, b: Int): Bool do return true # 1
+
+ fun foo2(a, b: Int): Bool do return true # 2
+
+ fun foo3(a, b: Int): Bool do return true
+
+ fun foo4(a, b: Int): Bool do
+ var res = true # 3
+ return res # 4
+ end
+
+ fun foo5 do end # 5
+ # fun foo6 do end
+end
+
+# end
+
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+class A
+ fun foo(aaaaaaaaaaaaaa,
+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb: Int): Bool do return true # comment
+
+ fun foo2(a, b: Int): Bool do return true # comment
+
+ fun foo3(a, b: Int): Bool do # comment
+ return true # comment
+ end # comment
+
+ fun foo4(a, b: Int): Bool do # comment
+ var res = true # comment
+ return res # comment
+ end # comment
+
+ fun foo5 do end # comment
+
+ fun foo6(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: Int) do print 1
+
+end # comment
\ No newline at end of file
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+var a = 1
+var b = 2
+
+while a != b do # comment 1
+ # comment 2
+ var tmp = a
+ a = b
+ b = tmp
+ # comment 3
+end
+
+# comment 4
+while a != b do a = b # comment 5
+
+while a != b do
+ # comment 6
+end # comment 7
+
+# end
+
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+var a = 0
+var b = 2
+
+do # comment 1
+ # comment 2
+ var tmp = a
+ a = b
+ b = tmp
+ # comment 3
+end
+
+# comment 4
+do a = b # comment 5
+
+do
+ # comment 6
+end
+
+if a > b then loop print a # test
+
+if a > b then loop print a
+
+
+if a > b then loop print a
+
+
+if a > b then
+ loop
+ # comment 7
+ print a
+ end
+end
+
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+var a = 0
+
+for i in [1, 2, 3] do # comment 1
+ # comment 2
+ a += i
+end
+
+# comment 4
+for i in [1..3] do a += i # comment 5
+
+for i in [1..3[ do
+ # comment 6
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+class A
+ fun foo do end
+ fun bar(a: Int): Int do return 1
+ fun baz(a, b: Int) do end
+ fun gaz(a: Int, b: Float...) do end
+end
+
+fun top1 do end
+fun top2(a: Int) do end
+
+# comment 1
+var a = new A # comment 2
+a.foo # comment 3
+a.bar 1 # comment 4
+a.baz(1, 2) # comment 5
+top1 # comment 6
+top2 10 # comment 7
+
+print 10 # comment 8
+
+var b = a.bar(1)
+
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+class A
+ var attr: Int
+ fun foo1=(i: Int) do end
+ fun foo2=(i, j: Int) do end
+ fun [](a: Int): Int is abstract
+ fun []=(a, b: Int) do end
+end
+
+class B
+ fun [](a, b: Int): Int is abstract
+ fun []=(a, b, c: Int) do end
+end
+
+# comment 1
+var a = new A(10) # comment 2
+
+a.foo1 = 10 # comment 3
+a.foo2(1) = 10 # comment 4
+print a[1] # comment 5
+a[1] = 2 # comment 6
+a[2] += 3 # comment 7
+
+var b = new B
+print b[1, 2]
+b[1, 2] = 10
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+var a = 1
+var b = 2
+
+if a == b then a = b
+
+if a != b then
+ a = b
+ a = b
+end
+
+if a > b then
+ b = a
+ a = b
+else
+ a = b
+ a = b
+end
+
+if a < b then
+ a = b
+ a = b
+else if a == b then
+ b = a
+ a = b
+end
+
+if a < b then
+ a = b
+ a = b
+else if a == b then
+ b = b
+ a = b
+else
+ a = b
+ a = b
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# comment
+var a = 1 # comment
+# comment
+var b = 2 # comment
+
+# comment
+if a == b then a = b # comment
+
+# comment
+if a != b then # comment
+ # comment
+ a = b # comment
+ # comment
+ a = b # comment
+ # comment
+end # comment
+
+# comment
+if a > b then # comment
+ # comment
+ b = a # comment
+ # comment
+ a = b # comment
+ # comment
+else # comment
+ # comment
+ a = b # comment
+ # comment
+ a = b # comment
+ # comment
+end # comment
+
+# comment
+if a < b then # comment
+ # comment
+ a = b # comment
+ # comment
+ a = b # comment
+ # comment
+else if a == b then # comment
+ # comment
+ b = a # comment
+ # comment
+ a = b # comment
+ # comment
+end # comment
+
+# comment
+if a < b then # comment
+ # comment
+ a = b # comment
+ # comment
+ a = b # comment
+ # comment
+else if a == b then # comment
+ # comment
+ b = b # comment
+ # comment
+ a = b # comment
+ # comment
+else # comment
+ # comment
+ a = b # comment
+ # comment
+ a = b # comment
+ # comment
+end # comment
\ No newline at end of file
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+var a = 1
+var b = 2
+
+# 0
+if a == b then # 1
+ # 2
+else # 3
+ # 4
+end # 5
+
+if a == b then print a # printing a
+
+if a == b then
+ print a # printing a
+end
+
+if a == b then print a # end
+
+if a == b then a = b
+
+if a == b then end
+
+if a == b then end
+
+if a != b then a = b
+
+if a > b then
+ a = b
+else
+ a = b
+end
+
+if a < b then
+ a = b
+else if a == b then
+ a = b
+end
+
+if a < b then
+ a = b
+else if a == b then
+ a = b
+else
+ a = b
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+var a: nullable Int = 1
+var b: nullable Int = a.as(Int)
+var c: nullable Int = a.as(not null)
+
+assert c isa Int
+assert test1: c isa Int
+assert test2: c isa Int else abort
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+var a = 1
+var b = 2
+
+assert a == 2
+assert not a < 2 # comment 1
+assert a > 2 and b >= 2
+assert b != 2 or a <= 2
+assert b != null # comment 2
+
+# comment 3
+print a + b
+print a - b # comment 4
+print a * b
+print a / b
+print a % b
+
+print -a # comment 5
\ No newline at end of file
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+var a = 1
+var b = 2
+
+assert not a < 2 and (a == b or a > b) # comment 1
+assert not a < 2 and (a == b or ((a > b) or a <= b))
+assert (a > 2 and b >= 2)
+assert (b >= 2)
+
+# comment 3
+var c = a + (b - a)
+var d = (a - b) + c # comment 4
+var e = (-a) # comment 5
+var f = -(a - c)
return errno;
`}
-fun errnoooooooooooooooooooooooooooooooooooooooooooooooooooooooooo: Int is extern `{
- return errno;
-`}
+fun errnoooooooooooooooooooooooooooooooooooooooooooooooooooooooooo: Int is
+ extern `{ return errno; `}
private class A
var my_attr = 1234
extern class TimeT `{time_t`}
new `{ return time(NULL); `}
new from_i(i: Int) `{ return i; `}
+
fun update `{ time(&recv); `}
fun ctime: String import NativeString.to_s_with_copy `{
# Difference in secondes from start (self if the end time)
fun difftime(start: TimeT): Float `{ return difftime(recv, start); `}
- private fun intern_poll(in_fds: Array[Int], out_fds: Array[Int]): nullable Int is import
- Array[Int].length, Array[Int].[], Int.as(nullable Int) `{`}
+ private fun intern_poll(in_fds: Array[Int], out_fds: Array[Int]): nullable Int is
+ extern import Array[Int].length, Array[Int].[], Int.as(nullable Int) `{`}
end
fun address_is_null: Bool is extern "address_is_null"
fun free `{ free(recv); `}
+
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+class A
+ var a: Int # comment
+ private var b: nullable Int # happy
+ protected var c = 10 # ending
+ var d: Int = 10
+
+
+
+
+
+ # Test test...
+ var e: Int is writable
+ var f: Int is protected writable
+ # Adoc
+ var k: Int = 10 is protected writable
+
+
+
+ # more comments
+end # end
+
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+class Foo
+ var a: Int
+ private var b: nullable Int
+ protected var c = 10
+ var d: Int = 10
+end
+
+var foo = new Foo(1, 2)
+print foo._a
+foo._a = 10
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+# toplevel comment
+
+
+
+
+
+
+# block
+# block
+# block
+
+
+
+
+
+# Adoc1
+class A # ending comments
+
+ super Object
+ # super Int
+
+
+ super String
+ # super Truc
+
+
+
+ # inclass comments
+ # comm
+ # ented
+ # blocks
+
+
+
+ # Adoc2
+ fun foo do
+
+ # comment
+
+
+
+ var truc
+
+ # comment
+ # comment
+
+
+
+ # comment
+
+
+ var chose
+
+ # comment
+ end
+
+ # comm
+ # ented
+ # blocks
+
+
+ fun bar do end
+
+
+ fun baz do end
+ # comment before end
+
+end # ending comments
+
+# comm
+# ented
+# blocks
+
+abstract class B # comment
+end
+
+abstract class C end
+
+abstract class B # comment 2
+
+end
+
+abstract class C end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+class Foo
+ fun bar: Bool do return true
+
+ fun foo(other: Foo): Foo
+ do
+ if other.bar then
+ return other
+ else
+ return self
+ end
+ end
+
+ fun baz: Int do
+ var nb = 0
+ while nb < 10 do
+ print nb
+ nb += 1
+ end # 1
+ return nb
+ end
+
+ fun gaz: Int
+ do
+ if bar then # 3
+ return 1
+ else
+ return -1 # 4
+ end
+ end
+end
+
+class Test[E]
+ var heap: ArrayHeap[E]
+
+ init to(comparator: Comparator[E]) do heap = new ArrayHeap[E](comparator)
+
+ init from(comparator: Comparator[E], items: Collection[E]) do
+ heap = new ArrayHeap[E].from(comparator, items.to_a)
+ end
+
+ fun count(k: E): Int do
+ if heap.has(k) then
+ return 1
+ else
+ return 0
+ end
+ end
+
+ fun node_at_idx(i: Int, k: E) do
+ while heap != null do
+ if heap.is_empty or i == k then # FIXME prefilter because the compiler is not smart enought yet
+ break
+ end
+ end
+ end
+
+ fun save_those_nodes(nodes: Collection[Object]) do
+ for node in nodes do count(node)
+ end
+end
+
+fun foo do
+ if last_slash > 0 then
+ return substring(last_slash + 1, length)
+ else
+ return null
+ end
+end
+
+print "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam tincidunt sapien et velit fringilla varius at non eros. Nunc ut ultricies metus, sit amet lacinia felis. Donec in facilisis neque, non laoreet nibh. Etiam nec purus eu orci congue iaculis eu quis lorem. Ut et blandit erat. Cras fermentum pellentesque ante, ut dapibus ipsum placerat sit amet. Vivamus pharetra, sem vitae consequat venenatis, diam risus placerat est, sed hendrerit purus justo vitae lectus. In id quam mattis, rutrum augue eu, vehicula ipsum. Nulla nec egestas turpis, nec ullamcorper odio. Pellentesque vitae arcu justo. Aliquam sed pharetra lacus."
+
+var lorem = "lorem"
+var ipsum = "ipsum" # for fun
+
+print "We also need to handle super strings: {lorem} {ipsum} dolor sit amet, consectetur adipiscing elit. Aliquam tincidunt sapien et velit fringilla varius at non eros. Nunc ut ultricies metus, sit amet lacinia felis. Donec in facilisis neque, non laoreet nibh. Etiam nec purus eu orci congue iaculis eu quis {lorem}. Ut et blandit erat. Cras fermentum pellentesque ante, ut dapibus {ipsum} placerat sit amet. Vivamus pharetra, sem vitae consequat venenatis, diam risus placerat est, sed hendrerit purus justo vitae lectus. In id quam mattis, rutrum augue eu, vehicula ipsum. Nulla nec egestas turpis, nec ullamcorper odio. Pellentesque vitae arcu justo. Aliquam sed pharetra lacus." # ending
+
+var title = "title"
+var links = new Array[String] # why not?
+
+var body = """
+<!DOCTYPE html>
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
+ <title>{{{title}}}</title>
+</head>
+<body>
+ <div class="container">
+ <h1>{{{title}}}</h1>
+ <ul>
+ <li>{{{links.join("</li>\n\t\t\t<li>")}}}</li>
+ </ul>
+ </div>
+</body>
+</html>"""
+
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# prims
+
+var a = true
+var b = false
+
+var c = 10
+var d = -10
+var e = 1.12
+
+var f = -1.12
+var n = 'a'
+var o = null
+var p = 0x12345678
+
+# strings
+
+var g = "test"
+var h1 = "Hello {g}"
+var h2 = "Hello \"{g}\" Hello"
+var h3 = "Hello {g}"
+var m = """
+bla
+ bla
+
+bla"""
+
+# arrays
+
+var j = [1, 2, 3]
+var k = [1..2[
+var l = [1..2]
+
+
+
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+module test_annot1 is platform("android")
+
+class A
+ fun goo is intern
+
+ # test
+ fun foo is a, b
+ fun bar is a, b do print "1"
+ fun baz is
+ a
+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb do print "2"
+end
+
+class B
+ fun foo is a, b
+
+
+ fun bar is a, b do print "1"
+
+ fun baz is a, b
+ do
+ bar
+ print "2"
+ end
+
+ fun gaz is
+ a
+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+ do
+ bar
+ print "2"
+ end
+
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# comment 1
+class A
+ type FOO: Discrete
+ private var foo: FOO # comment
+ # comment 2
+ var bar: Int = 10
+end
+
+class B
+ super A
+
+ redef type FOO: Int
+ # comment 3
+ redef fun foo do return bar # comment
+ redef fun bar
+ do
+ return 10 # comment 4
+ end
+ fun baz do return # comment 5
+ protected fun baz2 do end
+ fun other: String do
+ return "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+ "aaaaaaaaaaaaaaaaaaaaaaaaaa"
+ end
+
+ fun foo1(arr: Array[String], len: Int, ind: Int): String
+ do
+ return "Hello World!"
+ end
+end
+
+# end
+
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+class Foo
+ fun bar: Bool do return true
+
+ fun foo(other: Foo): Foo
+ do
+ if other.bar then
+ return other
+ else
+ return self
+ end
+ end
+
+ fun baz: Int do
+ var nb = 0
+ while nb < 10 do
+ print nb
+ nb += 1
+ end # 1
+ return nb
+ end
+
+ fun gaz: Int
+ do
+ if bar then # 3
+ return 1
+ else
+ return -1 # 4
+ end
+ end
+end
+
+class Test[E]
+ var heap: ArrayHeap[E]
+
+ init to(comparator: Comparator[E]) do heap = new ArrayHeap[E](comparator)
+
+ init from(comparator: Comparator[E], items: Collection[E]) do
+ heap = new ArrayHeap[E].from(comparator, items.to_a)
+ end
+
+ fun count(k: E): Int do
+ if heap.has(k) then
+ return 1
+ else
+ return 0
+ end
+ end
+
+ fun node_at_idx(i: Int, k: E) do
+ while heap != null do
+ if heap.is_empty or i == k then # FIXME prefilter because the compiler is not smart enought yet
+ break
+ end
+ end
+ end
+
+ fun save_those_nodes(nodes: Collection[Object]) do
+ for node in nodes do count(node)
+ end
+end
+
+fun foo do
+ if last_slash > 0 then
+ return substring(last_slash + 1, length)
+ else
+ return null
+ end
+end
+
+print "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam tincidun" +
+ "t sapien et velit fringilla varius at non eros. Nunc ut ultricies metus, sit a" +
+ "met lacinia felis. Donec in facilisis neque, non laoreet nibh. Etiam nec purus" +
+ " eu orci congue iaculis eu quis lorem. Ut et blandit erat. Cras fermentum pell" +
+ "entesque ante, ut dapibus ipsum placerat sit amet. Vivamus pharetra, sem vitae" +
+ " consequat venenatis, diam risus placerat est, sed hendrerit purus justo vitae" +
+ " lectus. In id quam mattis, rutrum augue eu, vehicula ipsum. Nulla nec egestas" +
+ " turpis, nec ullamcorper odio. Pellentesque vitae arcu justo. Aliquam sed phar" +
+ "etra lacus."
+
+var lorem = "lorem"
+var ipsum = "ipsum" # for fun
+
+print "We also need to handle super strings: {lorem} {ipsum} dolor sit amet, con" +
+ "sectetur adipiscing elit. Aliquam tincidunt sapien et velit fringilla varius a" +
+ "t non eros. Nunc ut ultricies metus, sit amet lacinia felis. Donec in facilisi" +
+ "s neque, non laoreet nibh. Etiam nec purus eu orci congue iaculis eu quis {lorem}" +
+ ". Ut et blandit erat. Cras fermentum pellentesque ante, ut dapibus {ipsum} pla" +
+ "cerat sit amet. Vivamus pharetra, sem vitae consequat venenatis, diam risus pl" +
+ "acerat est, sed hendrerit purus justo vitae lectus. In id quam mattis, rutrum " +
+ "augue eu, vehicula ipsum. Nulla nec egestas turpis, nec ullamcorper odio. Pell" +
+ "entesque vitae arcu justo. Aliquam sed pharetra lacus." # ending
+
+var title = "title"
+var links = new Array[String] # why not?
+
+var body = """
+<!DOCTYPE html>
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
+ <title>{{{title}}}</title>
+</head>
+<body>
+ <div class="container">
+ <h1>{{{title}}}</h1>
+ <ul>
+ <li>{{{links.join("</li>\n\t\t\t<li>")}}}</li>
+ </ul>
+ </div>
+</body>
+</html>"""
+
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# comment 1
+class A
+ type FOO: Discrete
+ private var foo: FOO # comment
+ # comment 2
+ var bar: Int = 10
+end
+
+class B
+ super A
+
+ redef type FOO: Int
+ # comment 3
+ redef fun foo do return bar # comment
+ redef fun bar do
+ return 10 # comment 4
+ end
+ fun baz do return # comment 5
+ protected fun baz2 do end
+ fun other: String do
+ return "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ end
+
+ fun foo1(arr: Array[String], len: Int, ind: Int): String do
+ return "Hello World!"
+ end
+end
+
+# end
+
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+class Foo
+ fun bar: Bool do return true
+
+ fun foo(other: Foo): Foo do
+ if other.bar then
+ return other
+ else
+ return self
+ end
+ end
+
+ fun baz: Int do
+ var nb = 0
+ while nb < 10 do
+ print nb
+ nb += 1
+ end # 1
+ return nb
+ end
+
+ fun gaz: Int do
+ if bar then # 3
+ return 1
+ else
+ return -1 # 4
+ end
+ end
+end
+
+class Test[E]
+ var heap: ArrayHeap[E]
+
+ init to(comparator: Comparator[E]) do heap = new ArrayHeap[E](comparator)
+
+ init from(comparator: Comparator[E], items: Collection[E]) do
+ heap = new ArrayHeap[E].from(comparator, items.to_a)
+ end
+
+ fun count(k: E): Int do
+ if heap.has(k) then
+ return 1
+ else
+ return 0
+ end
+ end
+
+ fun node_at_idx(i: Int, k: E) do
+ while heap != null do
+ if heap.is_empty or i == k then # FIXME prefilter because the compiler is not smart enought yet
+ break
+ end
+ end
+ end
+
+ fun save_those_nodes(nodes: Collection[Object]) do
+ for node in nodes do count(node)
+ end
+end
+
+fun foo do
+ if last_slash > 0 then
+ return substring(last_slash + 1, length)
+ else
+ return null
+ end
+end
+
+print "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam tincidunt sapien et velit fringilla varius at non eros. Nunc ut ultricies metus, sit amet lacinia felis. Donec in facilisis neque, non laoreet nibh. Etiam nec purus eu orci congue iaculis eu quis lorem. Ut et blandit erat. Cras fermentum pellentesque ante, ut dapibus ipsum placerat sit amet. Vivamus pharetra, sem vitae consequat venenatis, diam risus placerat est, sed hendrerit purus justo vitae lectus. In id quam mattis, rutrum augue eu, vehicula ipsum. Nulla nec egestas turpis, nec ullamcorper odio. Pellentesque vitae arcu justo. Aliquam sed pharetra lacus."
+
+var lorem = "lorem"
+var ipsum = "ipsum" # for fun
+
+print "We also need to handle super strings: {lorem} {ipsum} dolor sit amet, consectetur adipiscing elit. Aliquam tincidunt sapien et velit fringilla varius at non eros. Nunc ut ultricies metus, sit amet lacinia felis. Donec in facilisis neque, non laoreet nibh. Etiam nec purus eu orci congue iaculis eu quis {lorem}. Ut et blandit erat. Cras fermentum pellentesque ante, ut dapibus {ipsum} placerat sit amet. Vivamus pharetra, sem vitae consequat venenatis, diam risus placerat est, sed hendrerit purus justo vitae lectus. In id quam mattis, rutrum augue eu, vehicula ipsum. Nulla nec egestas turpis, nec ullamcorper odio. Pellentesque vitae arcu justo. Aliquam sed pharetra lacus." # ending
+
+var title = "title"
+var links = new Array[String] # why not?
+
+var body = """
+<!DOCTYPE html>
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
+ <title>{{{title}}}</title>
+</head>
+<body>
+ <div class="container">
+ <h1>{{{title}}}</h1>
+ <ul>
+ <li>{{{links.join("</li>\n\t\t\t<li>")}}}</li>
+ </ul>
+ </div>
+</body>
+</html>"""
+
# comment 3
redef fun foo do return bar # comment
- redef fun bar do
+ redef fun bar
+ do
return 10 # comment 4
end
protected fun baz2 do end
fun other: String do
- return "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
- "aaaaaaaaaaaaaaaaaaaaaaaaaa"
+ return "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ end
+
+ fun foo1(arr: Array[String], len: Int, ind: Int): String
+ do
+ return "Hello World!"
end
end
fun foo5 do end # comment
fun foo6(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: Int) do
- print 1
- end
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: Int) do print 1
end # comment
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
-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
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
module test_annot1 is platform("android")
class A
+ fun goo is intern
+
+ # test
fun foo is a, b
fun bar is a, b do print "1"
fun baz is a, bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb do print "2"
end # comment 5
protected fun baz2 do end
fun other: String do return "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+
+ fun foo1(arr: Array[String], len: Int, ind: Int): String
+ do
+ return "Hello World!"
+ end
end
# end