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