Merge: Newstreams
authorJean Privat <jean@pryen.org>
Sat, 13 Dec 2014 07:49:28 +0000 (02:49 -0500)
committerJean Privat <jean@pryen.org>
Sat, 13 Dec 2014 07:49:28 +0000 (02:49 -0500)
Small refactoring of Streams/Files:
- Added a simple error management system
- Removed FDStreams, reified under FStream

Next PR to come: Proposition for renaming of the classes of the stream hierarchy (as requested in #466)

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

407 files changed:
.gitignore
NOTICE
VERSION
contrib/jwrapper/src/code_generator.nit
contrib/jwrapper/src/javap_visitor.nit
contrib/neo_doxygen/Makefile
contrib/neo_doxygen/README.md [new file with mode: 0644]
contrib/neo_doxygen/gen-all.sh
contrib/neo_doxygen/sh-lib/README.md [new file with mode: 0644]
contrib/neo_doxygen/sh-lib/more_sed.sh [new file with mode: 0644]
contrib/neo_doxygen/src/doxml/compounddef.nit
contrib/neo_doxygen/src/doxml/doc.nit
contrib/neo_doxygen/src/doxml/language_specific.nit
contrib/neo_doxygen/src/doxml/listener.nit
contrib/neo_doxygen/src/flush_stdout.nit [new file with mode: 0644]
contrib/neo_doxygen/src/graph_store.nit [new file with mode: 0644]
contrib/neo_doxygen/src/model/class_compound.nit
contrib/neo_doxygen/src/model/graph.nit
contrib/neo_doxygen/src/model/inner_class.nit [new file with mode: 0644]
contrib/neo_doxygen/src/model/location.nit
contrib/neo_doxygen/src/model/member.nit
contrib/neo_doxygen/src/model/model.nit
contrib/neo_doxygen/src/model/module_compound.nit
contrib/neo_doxygen/src/neo_doxygen.nit
contrib/neo_doxygen/src/tests/README.md [new file with mode: 0644]
contrib/neo_doxygen/src/tests/neo_doxygen_dump.nit [new file with mode: 0644]
contrib/neo_doxygen/src/tests/neo_doxygen_file_compound.nit [new file with mode: 0644]
contrib/neo_doxygen/src/tests/neo_doxygen_graph_empty_project.nit [new file with mode: 0644]
contrib/neo_doxygen/src/tests/neo_doxygen_member_resolve_introducer.nit [new file with mode: 0644]
contrib/neo_doxygen/src/tests/tests.nit [new file with mode: 0644]
contrib/neo_doxygen/tests/.gitattributes [new file with mode: 0644]
contrib/neo_doxygen/tests/Makefile [new file with mode: 0644]
contrib/neo_doxygen/tests/README.md [new file with mode: 0644]
contrib/neo_doxygen/tests/doxyproject.mk [new file with mode: 0644]
contrib/neo_doxygen/tests/empty-project/Doxyfile [new file with mode: 0644]
contrib/neo_doxygen/tests/empty-project/README.md [new file with mode: 0644]
contrib/neo_doxygen/tests/empty-project/src/org/example/foo/void.txt [new file with mode: 0644]
contrib/neo_doxygen/tests/empty-project/xml/combine.xslt [new file with mode: 0644]
contrib/neo_doxygen/tests/empty-project/xml/compound.xsd [new file with mode: 0644]
contrib/neo_doxygen/tests/empty-project/xml/index.xml [new file with mode: 0644]
contrib/neo_doxygen/tests/empty-project/xml/index.xsd [new file with mode: 0644]
contrib/neo_doxygen/tests/inner-class/Doxyfile [new file with mode: 0644]
contrib/neo_doxygen/tests/inner-class/README.md [new file with mode: 0644]
contrib/neo_doxygen/tests/inner-class/src/OuterClass.java [new file with mode: 0644]
contrib/neo_doxygen/tests/inner-class/xml/_outer_class_8java.xml [new file with mode: 0644]
contrib/neo_doxygen/tests/inner-class/xml/class_outer_class.xml [new file with mode: 0644]
contrib/neo_doxygen/tests/inner-class/xml/class_outer_class_1_1_inner_class.xml [new file with mode: 0644]
contrib/neo_doxygen/tests/inner-class/xml/combine.xslt [new file with mode: 0644]
contrib/neo_doxygen/tests/inner-class/xml/compound.xsd [new file with mode: 0644]
contrib/neo_doxygen/tests/inner-class/xml/dir_68267d1309a1af8e8297ef4c3efbcdba.xml [new file with mode: 0644]
contrib/neo_doxygen/tests/inner-class/xml/index.xml [new file with mode: 0644]
contrib/neo_doxygen/tests/inner-class/xml/index.xsd [new file with mode: 0644]
contrib/neo_doxygen/tests/java-project/Doxyfile [new file with mode: 0644]
contrib/neo_doxygen/tests/java-project/README.md [new file with mode: 0644]
contrib/neo_doxygen/tests/java-project/src/org/example/foo/A.java [new file with mode: 0644]
contrib/neo_doxygen/tests/java-project/src/org/example/foo/B.java [new file with mode: 0644]
contrib/neo_doxygen/tests/java-project/src/org/example/foo/C.java [new file with mode: 0644]
contrib/neo_doxygen/tests/java-project/src/org/example/foo/EmptyClass.java [new file with mode: 0644]
contrib/neo_doxygen/tests/java-project/xml/_a_8java.xml [new file with mode: 0644]
contrib/neo_doxygen/tests/java-project/xml/_b_8java.xml [new file with mode: 0644]
contrib/neo_doxygen/tests/java-project/xml/_c_8java.xml [new file with mode: 0644]
contrib/neo_doxygen/tests/java-project/xml/_empty_class_8java.xml [new file with mode: 0644]
contrib/neo_doxygen/tests/java-project/xml/classorg_1_1example_1_1foo_1_1_a.xml [new file with mode: 0644]
contrib/neo_doxygen/tests/java-project/xml/classorg_1_1example_1_1foo_1_1_b.xml [new file with mode: 0644]
contrib/neo_doxygen/tests/java-project/xml/classorg_1_1example_1_1foo_1_1_empty_class.xml [new file with mode: 0644]
contrib/neo_doxygen/tests/java-project/xml/combine.xslt [new file with mode: 0644]
contrib/neo_doxygen/tests/java-project/xml/compound.xsd [new file with mode: 0644]
contrib/neo_doxygen/tests/java-project/xml/dir_68267d1309a1af8e8297ef4c3efbcdba.xml [new file with mode: 0644]
contrib/neo_doxygen/tests/java-project/xml/dir_8c35fc67c36f89d827afb23e8c52a418.xml [new file with mode: 0644]
contrib/neo_doxygen/tests/java-project/xml/dir_ad5d6582648a7bbb3a301939a41e6c0b.xml [new file with mode: 0644]
contrib/neo_doxygen/tests/java-project/xml/dir_b8e0663afee48cb679b74bbd21bdf843.xml [new file with mode: 0644]
contrib/neo_doxygen/tests/java-project/xml/index.xml [new file with mode: 0644]
contrib/neo_doxygen/tests/java-project/xml/index.xsd [new file with mode: 0644]
contrib/neo_doxygen/tests/java-project/xml/interfaceorg_1_1example_1_1foo_1_1_c.xml [new file with mode: 0644]
contrib/neo_doxygen/tests/java-project/xml/namespaceorg.xml [new file with mode: 0644]
contrib/neo_doxygen/tests/java-project/xml/namespaceorg_1_1example.xml [new file with mode: 0644]
contrib/neo_doxygen/tests/java-project/xml/namespaceorg_1_1example_1_1foo.xml [new file with mode: 0644]
contrib/neo_doxygen/tests/root-namespace/Doxyfile [new file with mode: 0644]
contrib/neo_doxygen/tests/root-namespace/README.md [new file with mode: 0644]
contrib/neo_doxygen/tests/root-namespace/src/Foo.java [new file with mode: 0644]
contrib/neo_doxygen/tests/root-namespace/xml/_foo_8java.xml [new file with mode: 0644]
contrib/neo_doxygen/tests/root-namespace/xml/class_foo.xml [new file with mode: 0644]
contrib/neo_doxygen/tests/root-namespace/xml/combine.xslt [new file with mode: 0644]
contrib/neo_doxygen/tests/root-namespace/xml/compound.xsd [new file with mode: 0644]
contrib/neo_doxygen/tests/root-namespace/xml/dir_68267d1309a1af8e8297ef4c3efbcdba.xml [new file with mode: 0644]
contrib/neo_doxygen/tests/root-namespace/xml/index.xml [new file with mode: 0644]
contrib/neo_doxygen/tests/root-namespace/xml/index.xsd [new file with mode: 0644]
contrib/nitcc/examples/minilang.nit
contrib/nitcc/src/autom.nit
contrib/nitcc/src/grammar.nit
contrib/nitcc/src/nitcc_lexer0.nit
contrib/nitcc/src/nitcc_semantic.nit
contrib/nitcc/src/re2nfa.nit
contrib/nitiwiki/.gitignore [new file with mode: 0644]
contrib/nitiwiki/Makefile [new file with mode: 0644]
contrib/nitiwiki/README.md [new file with mode: 0644]
contrib/nitiwiki/examples/default/config.ini [new file with mode: 0644]
contrib/nitiwiki/examples/default/pages/index.md [new file with mode: 0644]
contrib/nitiwiki/examples/default/templates/footer.html [new file with mode: 0644]
contrib/nitiwiki/examples/default/templates/header.html [new file with mode: 0644]
contrib/nitiwiki/examples/default/templates/menu.html [new file with mode: 0644]
contrib/nitiwiki/examples/default/templates/template.html [new file with mode: 0644]
contrib/nitiwiki/examples/nitiwiki/assets/css/main.css [new file with mode: 0644]
contrib/nitiwiki/examples/nitiwiki/assets/logo.png [new file with mode: 0644]
contrib/nitiwiki/examples/nitiwiki/config.ini [new file with mode: 0644]
contrib/nitiwiki/examples/nitiwiki/pages/index.md [new symlink]
contrib/nitiwiki/examples/nitiwiki/templates/footer.html [new file with mode: 0644]
contrib/nitiwiki/examples/nitiwiki/templates/header.html [new file with mode: 0644]
contrib/nitiwiki/examples/nitiwiki/templates/menu.html [new file with mode: 0644]
contrib/nitiwiki/examples/nitiwiki/templates/template.html [new file with mode: 0644]
contrib/nitiwiki/src/nitiwiki.nit [new file with mode: 0644]
contrib/nitiwiki/src/wiki_base.nit [new file with mode: 0644]
contrib/nitiwiki/src/wiki_html.nit [new file with mode: 0644]
contrib/nitiwiki/tests/Makefile [new file with mode: 0644]
contrib/nitiwiki/tests/nitiwiki.args [new file with mode: 0644]
contrib/nitiwiki/tests/nitiwiki_render.args [new file with mode: 0644]
contrib/nitiwiki/tests/nitiwiki_status.args [new file with mode: 0644]
contrib/nitiwiki/tests/res/nitiwiki.res [new file with mode: 0644]
contrib/nitiwiki/tests/res/nitiwiki_render.res [new file with mode: 0644]
contrib/nitiwiki/tests/res/nitiwiki_status.res [new file with mode: 0644]
contrib/nitiwiki/tests/tests.sh [new file with mode: 0755]
contrib/nitiwiki/tests/wiki1/assets/css/main.css [new file with mode: 0644]
contrib/nitiwiki/tests/wiki1/config.ini [new file with mode: 0644]
contrib/nitiwiki/tests/wiki1/config2.ini [new file with mode: 0644]
contrib/nitiwiki/tests/wiki1/pages/index.md [new file with mode: 0644]
contrib/nitiwiki/tests/wiki1/templates/footer.html [new file with mode: 0644]
contrib/nitiwiki/tests/wiki1/templates/header.html [new file with mode: 0644]
contrib/nitiwiki/tests/wiki1/templates/menu.html [new file with mode: 0644]
contrib/nitiwiki/tests/wiki1/templates/template.html [new file with mode: 0644]
contrib/online_ide/sources/nit/pnacl_nit.nit
doc/Makefile [new file with mode: 0644]
doc/README [deleted file]
doc/README.md [new file with mode: 0644]
examples/calculator/Makefile
examples/calculator/art/icon.svg [new file with mode: 0644]
examples/calculator/src/calculator_android.nit [new file with mode: 0644]
examples/mnit_simple/src/test_assets_and_resources.nit
examples/rosettacode/empty_program.nit [new file with mode: 0644]
examples/rosettacode/hailstone.nit [new file with mode: 0644]
examples/rosettacode/hamming_number.nit [new file with mode: 0644]
examples/rosettacode/hello_world_text.nit [new file with mode: 0644]
lib/a_star.nit
lib/ai/backtrack.nit
lib/ai/examples/queens.nit
lib/ai/search.nit
lib/android/assets_and_resources.nit
lib/android/audio.nit
lib/android/bundle/bundle.nit
lib/android/examples/Makefile [new file with mode: 0644]
lib/android/examples/art/icon.svg [new file with mode: 0644]
lib/android/examples/src/ui_test.nit [new file with mode: 0644]
lib/android/intent/intent_api10.nit
lib/android/native_app_glue.nit
lib/android/notification/native_notification.nit [new file with mode: 0644]
lib/android/notification/notification.nit [new file with mode: 0644]
lib/android/platform.nit
lib/android/sensors.nit
lib/android/shared_preferences/shared_preferences_api10.nit
lib/android/shared_preferences/shared_preferences_api11.nit
lib/android/toast.nit [new file with mode: 0644]
lib/android/ui.nit [new file with mode: 0644]
lib/android/vibration.nit
lib/app/data_store.nit
lib/base64.nit
lib/bucketed_game.nit
lib/buffered_ropes.nit
lib/c.nit
lib/cocoa/app_kit.nit [new file with mode: 0644]
lib/cocoa/cocoa.nit [new file with mode: 0644]
lib/cocoa/examples/cocoa_extern_types.nit [new file with mode: 0644]
lib/cocoa/examples/cocoa_message_box.nit [new file with mode: 0644]
lib/cocoa/examples/hello_cocoa.nit [new file with mode: 0644]
lib/cocoa/foundation.nit [new file with mode: 0644]
lib/combinations.nit
lib/console.nit
lib/cpp.nit
lib/crypto.nit
lib/csv.nit [deleted file]
lib/csv/csv.nit [new file with mode: 0644]
lib/csv/test_csv.nit [new file with mode: 0644]
lib/dummy_array.nit
lib/egl.nit
lib/emscripten.nit
lib/geometry/boxes.nit
lib/github_api.nit
lib/glesv2/glesv2.nit
lib/gpio.nit
lib/hash_debug.nit
lib/html/html.nit
lib/java/io.nit
lib/java/java.nit
lib/json/dynamic.nit
lib/json/static.nit
lib/json_serialization.nit
lib/jvm.nit
lib/libevent.nit
lib/markdown/markdown.nit
lib/markdown/test_markdown.nit
lib/mnit/mnit_injected_input.nit
lib/mnit_android/android_app.nit
lib/mnit_display.nit
lib/more_collections.nit
lib/mpd.nit
lib/mpi.nit
lib/neo4j/jsonable.nit [new file with mode: 0644]
lib/neo4j/neo4j.nit
lib/opts.nit
lib/ordered_tree.nit
lib/pipeline.nit
lib/pnacl.nit
lib/poset.nit
lib/privileges.nit
lib/pthreads/extra.nit [new file with mode: 0644]
lib/pthreads/pthreads.nit
lib/sax/helpers/attributes_impl.nit
lib/sax/helpers/namespace_support.nit
lib/sax/helpers/sax_locator_impl.nit
lib/sax/helpers/test_namespace_support.nit
lib/sax/input_source.nit
lib/sax/xml_reader.nit
lib/saxophonit/.gitattributes [new file with mode: 0644]
lib/saxophonit/lexer.nit
lib/saxophonit/reader_model.nit
lib/saxophonit/saxophonit.nit
lib/saxophonit/test_saxophonit.nit
lib/saxophonit/test_testing.nit
lib/saxophonit/testing.nit
lib/scene2d.nit
lib/sdl.nit
lib/sdl2/README.md [new file with mode: 0644]
lib/sdl2/all.nit [new file with mode: 0644]
lib/sdl2/events.nit [new file with mode: 0644]
lib/sdl2/examples/minimal/Makefile [new file with mode: 0644]
lib/sdl2/examples/minimal/assets/fighter.png [new file with mode: 0644]
lib/sdl2/examples/minimal/src/minimal.nit [new file with mode: 0644]
lib/sdl2/image.nit [new file with mode: 0644]
lib/sdl2/sdl2.nit [new file with mode: 0644]
lib/sdl2/sdl2_base.nit [new file with mode: 0644]
lib/sdl2/syswm.nit [new file with mode: 0644]
lib/signals.nit
lib/sqlite3/sqlite3.nit
lib/standard/collection/abstract_collection.nit
lib/standard/collection/array.nit
lib/standard/collection/collection.nit
lib/standard/collection/hash_collection.nit
lib/standard/collection/list.nit
lib/standard/collection/range.nit
lib/standard/exec.nit
lib/standard/file.nit
lib/standard/kernel.nit
lib/standard/math.nit
lib/standard/re.nit
lib/standard/ropes.nit
lib/standard/stream.nit
lib/standard/string.nit
lib/standard/string_search.nit
lib/standard/time.nit
lib/string_experimentations/utf8.nit
lib/string_experimentations/utf8_noindex.nit
lib/template/macro.nit
lib/trees/abstract_tree.nit
lib/trees/bintree.nit
lib/trees/rbtree.nit
lib/x11.nit
misc/vim/syntax/nit.vim
misc/vim/syntax_checkers/nit/nitg.vim
share/man/nitls.md
share/man/nitpretty.md
share/man/nitunit.md
share/nitdoc/js/plugins/quicksearch.js
src/astbuilder.nit
src/compiler/abstract_compiler.nit
src/compiler/android_annotations.nit
src/compiler/android_platform.nit
src/compiler/coloring.nit
src/compiler/separate_compiler.nit
src/doc/doc_model.nit
src/doc/doc_pages.nit
src/doc/doc_templates.nit
src/doc/model_ext.nit
src/docdown.nit [moved from src/markdown.nit with 92% similarity]
src/ffi/c.nit
src/ffi/extern_classes.nit
src/ffi/ffi.nit
src/ffi/objc.nit [new file with mode: 0644]
src/frontend/frontend.nit
src/frontend/glsl_validation.nit [new file with mode: 0644]
src/highlight.nit
src/interpreter/debugger.nit
src/interpreter/naive_interpreter.nit
src/loader.nit [new file with mode: 0644]
src/location.nit
src/metrics/mendel_metrics.nit
src/metrics/metrics_base.nit
src/model/mdoc.nit
src/model/mmodule.nit
src/model/model.nit
src/model/mproject.nit
src/model_utils.nit
src/modelbuilder.nit
src/modelbuilder_base.nit [new file with mode: 0644]
src/modelize/modelize_class.nit
src/modelize/modelize_property.nit
src/neo.nit
src/nit.nit
src/nitlight.nit
src/nitls.nit
src/nitni/nitni_base.nit
src/nitpretty.nit
src/pretty.nit [new file with mode: 0644]
src/rapid_type_analysis.nit
src/semantize/typing.nit
src/test_docdown.nit
src/testing/testing_doc.nit
src/testing/testing_suite.nit
src/toolcontext.nit
src/transform.nit
src/vm.nit
tests/Linux.skip [new file with mode: 0644]
tests/Makefile
tests/README.md
tests/base_formal_subtype.nit [new file with mode: 0644]
tests/base_self_type.nit [new file with mode: 0644]
tests/listfull.sh
tests/neo_doxygen_dump.args [new file with mode: 0644]
tests/nitg-g.skip
tests/niti.skip
tests/nitiwiki.args [new file with mode: 0644]
tests/nitunit.args
tests/sav/base_as_notnull2.res
tests/sav/base_as_notnull2_alt1.res
tests/sav/base_as_notnull2_alt2.res
tests/sav/base_as_notnull2_alt3.res
tests/sav/base_formal_subtype.res [new file with mode: 0644]
tests/sav/base_gen_variance2_alt1.res
tests/sav/base_gen_variance2_alt2.res
tests/sav/base_gen_variance3_alt1.res
tests/sav/base_gen_variance_int_alt1.res
tests/sav/base_self_type.res [new file with mode: 0644]
tests/sav/base_self_type_alt1.res [new file with mode: 0644]
tests/sav/base_self_type_alt2.res [new file with mode: 0644]
tests/sav/base_self_type_alt3.res [new file with mode: 0644]
tests/sav/cocoa_extern_types.res [new file with mode: 0644]
tests/sav/cocoa_message_box.res [new file with mode: 0644]
tests/sav/empty_program.res [new file with mode: 0644]
tests/sav/error_class_glob.res
tests/sav/error_redef_alt3.res
tests/sav/error_redef_alt6.res
tests/sav/error_redef_alt9.res
tests/sav/hailstone.res [new file with mode: 0644]
tests/sav/hamming_number.res [new file with mode: 0644]
tests/sav/hello_cocoa.res [new file with mode: 0644]
tests/sav/hello_world_text.res [new file with mode: 0644]
tests/sav/html_page.res
tests/sav/neo_doxygen_dump.res [new file with mode: 0644]
tests/sav/neo_doxygen_dump_args1.res [new file with mode: 0644]
tests/sav/neo_doxygen_dump_args2.res [new file with mode: 0644]
tests/sav/neo_doxygen_dump_args3.res [new file with mode: 0644]
tests/sav/neo_doxygen_dump_args4.res [new file with mode: 0644]
tests/sav/neo_doxygen_dump_args5.res [new file with mode: 0644]
tests/sav/neo_doxygen_dump_args6.res [new file with mode: 0644]
tests/sav/neo_doxygen_dump_args7.res [new file with mode: 0644]
tests/sav/neo_doxygen_file_compound.res [new file with mode: 0644]
tests/sav/neo_doxygen_graph_empty_project.res [new file with mode: 0644]
tests/sav/neo_doxygen_member_resolve_introducer.res [new file with mode: 0644]
tests/sav/nitg-e/base_self_type.res [new file with mode: 0644]
tests/sav/nitg-e/base_self_type_alt2.res [new file with mode: 0644]
tests/sav/nitg-e/fixme/base_gen_reassign_alt4.res
tests/sav/nitg-e/fixme/base_gen_reassign_alt5.res
tests/sav/nitg-e/fixme/base_gen_reassign_alt6.res
tests/sav/nitiwiki.res [new file with mode: 0644]
tests/sav/nitiwiki_args1.res [new file with mode: 0644]
tests/sav/nitiwiki_args2.res [new file with mode: 0644]
tests/sav/nitlight_args1.res
tests/sav/nitls.res
tests/sav/nitls_args1.res
tests/sav/nitls_args2.res
tests/sav/nitls_args3.res
tests/sav/nitls_args4.res
tests/sav/nituml_args3.res
tests/sav/nituml_args4.res
tests/sav/nitunit_args1.res
tests/sav/nitunit_args5.res [new file with mode: 0644]
tests/sav/test_c_alt1.res
tests/sav/test_c_alt2.res
tests/sav/test_c_alt3.res
tests/sav/test_c_alt4.res
tests/sav/test_docdown_args1.res
tests/sav/test_docdown_args2.res [new file with mode: 0644]
tests/sav/test_ffi_objc_types_and_callbacks.res [new file with mode: 0644]
tests/sav/test_glsl_validation.res [new file with mode: 0644]
tests/sav/test_new_native_alt1.res
tests/sav/test_ropes_buffer_add_overflow.res [new file with mode: 0644]
tests/sav/test_ropes_buffer_clear.res [new file with mode: 0644]
tests/sav/test_ropes_buffer_reverse.res [new file with mode: 0644]
tests/sav/test_ropes_buffer_to_s.res [new file with mode: 0644]
tests/test_doc2.nit [new file with mode: 0644]
tests/test_docdown.args [new file with mode: 0644]
tests/test_ffi_objc_types_and_callbacks.nit [new file with mode: 0644]
tests/test_glsl_validation.nit [new file with mode: 0644]
tests/test_markdown.args [deleted file]
tests/test_neo4j.nit
tests/test_ropes_buffer_add_overflow.nit [new file with mode: 0644]
tests/test_ropes_buffer_clear.nit [new file with mode: 0644]
tests/test_ropes_buffer_reverse.nit [new file with mode: 0644]
tests/test_ropes_buffer_to_s.nit [new file with mode: 0644]
tests/tests.sh

index 65ac23a..62da951 100644 (file)
@@ -50,6 +50,8 @@ tests/out
 tests/*.xml
 tests/nitunit
 
+nitunit.xml
+
 *.stub.nit.[ch]
 
 .metadata/*
diff --git a/NOTICE b/NOTICE
index d0fe8c4..2618c42 100644 (file)
--- a/NOTICE
+++ b/NOTICE
@@ -47,6 +47,7 @@ Copyright: 2004-2014 Jean Privat <jean@pryen.org>
            2014      Maxime Leroy <maxime.leroy76@gmail.com>
            2014      Johann Dubois <johann.dubois@outlook.com>
            2014      Jean-Christophe Beaupré <jcbrinfo@users.noreply.github.com>
+           2014      Alexandre Blondin Massé <alexandre.blondin.masse@gmail.com>
 Licence: BSD 2 (see LICENSE-BSD)
 Comment: Use of libraries and resources is basically unrestricted. We hold the copyright
          on the compiler and the tools but not on the programs made by the users.
diff --git a/VERSION b/VERSION
index f50dea7..882307c 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-v0.6.10
+v0.6.11
index 8192855..45ce666 100644 (file)
@@ -221,7 +221,7 @@ class CodeGenerator
 
                # FIXME : This huge `if` block is only necessary to copy primitive arrays as long as there's no better way to do it
                if comment == "#" then
-                       temp.add(" in \"Java\" `\{\n{comment}\t\trecv.{jmethod_id}({java_params}); \n{comment}\t`\}\n")
+                       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
@@ -238,7 +238,7 @@ class CodeGenerator
                                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")
+                               temp.add(" in \"Java\" `\{\n{comment}\t\treturn {jreturn_type.return_cast} recv.{jmethod_id}({java_params});\n{comment}\t`\}\n")
                        end
                # Methods without return type
                else if jreturn_type.is_void then
@@ -247,11 +247,11 @@ class CodeGenerator
                                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")
+                               temp.add(" in \"Java\" `\{\n{comment}\t\trecv.{jmethod_id}({java_params});\n{comment}\t`\}\n")
                        end
                # No copy
                else
-                       temp.add(" in \"Java\" `\{\n{comment}\t\trecv.{jmethod_id}({java_params}); \n{comment}\t`\}\n")
+                       temp.add(" in \"Java\" `\{\n{comment}\t\trecv.{jmethod_id}({java_params});\n{comment}\t`\}\n")
                end
 
                return temp.join("")
index 45edb3d..1ede6f0 100644 (file)
@@ -300,6 +300,7 @@ end
 #                                  #
 #    C L A S S     H E A D E R     #
 #                                  #
+
 redef class Nclass_header
        redef fun accept_visitor(v)
        do
index ed82923..53383f7 100644 (file)
 NITG=../../bin/nitg
 NITG_FLAGS=--dir bin
 NEO4J_DIR=/var/lib/neo4j
+OLD_PWD=${PWD}
 
-.PHONY: bin reset-neo
+.PHONY: bin reset-neo run-tests tests
 
 # Compile the tool.
 bin:
        mkdir -p bin
-       ../../bin/nitg --dir bin src/neo_doxygen.nit
+       $(NITG) $(NITG_FLAGS) src/neo_doxygen.nit
 
 # Reset the local graph.
 reset-neo:
        sudo -u neo4j "${NEO4J_DIR}/bin/neo4j" stop \
        && sudo -u neo4j rm -rf "${NEO4J_DIR}/data/graph.db" \
        && sudo -u neo4j "${NEO4J_DIR}/bin/neo4j" start
+
+# Regenerate the XML documents in `tests`.
+tests:
+       $(MAKE) -C tests
+
+# Run the tests.
+run-tests:
+       cd ../../tests; \
+       ./tests.sh ../contrib/neo_doxygen/src/tests/neo_doxygen_*.nit ; \
+       cd "${OLD_PWD}"
diff --git a/contrib/neo_doxygen/README.md b/contrib/neo_doxygen/README.md
new file mode 100644 (file)
index 0000000..67b0e52
--- /dev/null
@@ -0,0 +1,71 @@
+# neo_doxygen
+
+This project provides a tool to convert a Doxygen XML output into a model in
+Neo4j that is readable by the `nx` tool.
+
+
+## Installation
+
+Ensure that you have a working version of `nitg` in `../../bin` then run `make`
+in the present directory. The executable will be then generated at
+`bin/neo_doxygen`.
+
+
+## Usage
+
+Here is the procedure to generate an HTML documentation of a project using the
+formatting of Nitdoc:
+
+1. First run Doxygen to generate an XML output of the documentation. In order to do
+this, you have to enable the `GENERATE_XML` option. Note that you can disable
+the `XML_PROGRAMLISTING` to speed up the process and save disk space.
+
+       <strong>Important</strong>
+
+       `neo_doxygen` do not read the `index.xml` file to know which file to load. As a
+       result, it may read files let by previous runs of Doxygen. To avoid producing
+       garbage, always clear the destination directory of the XML files before running
+       Doxygen.
+
+       Example: `rm -rf doxygen/xml && doxygen Doxyfile`
+
+2. Use `bin/neo_doxygen` to generate the Neo4j graph. For details, run
+`bin/neo_doxygen --help`.
+
+       <strong>Important</strong>
+
+       `neo_doxygen` do not remove what is already in the graph. So, you have to
+       manualy clear the graph (or at least, the subgraph contaning all the nodes
+       labelled with the specified project name) between each run.
+
+       For an example of how to delete an entire Neo4j database, see
+       `make reset-neo`.
+
+       Example: `make reset-neo && neo_doxygen my_project doxygen/xml`
+
+3. Use the `nx` tool to generate the HTML documentation from the previously
+generated graph.
+
+       Note: `nx` need to be configured before usage. For more details, refer to
+       the documentation of `nx`.
+
+       Example: `nx neo doc my_project`
+
+
+## Shell scripts
+
+The two shell scripts (`gen-one.sh` and `gen-all.sh`) are provided to automate
+the execution of `neo_doxygen` and `nx` for some typical cases and to give a
+starting for the development of similar scripts. In order for them to work,
+each project on which they operate **must** contain the following files:
+
+ * The `.nx_config` configuration file for the `nx` tool, located at the root
+       of the project.
+
+ * The XML documents generated by Doxygen, located in the `doxygen/xml`
+       directory.
+
+Also, they **must** be run with the current working directory set to the present
+directory. `gen-one.sh` handle only one project at a time while `gen-all.sh`
+works on a collection of projects grouped in a directory. For detail about how
+to invoke each script, see the comments in these scripts.
index b43ceab..4a19e9a 100755 (executable)
@@ -23,9 +23,6 @@
 # Also, every project must include the Doxygen XML output in its `doxygen/xml`
 # directory.
 
-NEO_DOXYGEN="${PWD}/bin/neo_doxygen"
-NX="${PWD}/../../bin/nx"
-
 for dir in "$2"/*; do
        if [ -d "$dir" ]; then
                if [ -f "$dir/.nx_config" ]; then
diff --git a/contrib/neo_doxygen/sh-lib/README.md b/contrib/neo_doxygen/sh-lib/README.md
new file mode 100644 (file)
index 0000000..ade333a
--- /dev/null
@@ -0,0 +1 @@
+Libraries used by shell scripts.
diff --git a/contrib/neo_doxygen/sh-lib/more_sed.sh b/contrib/neo_doxygen/sh-lib/more_sed.sh
new file mode 100644 (file)
index 0000000..db58b69
--- /dev/null
@@ -0,0 +1,37 @@
+#! /bin/sh
+
+# 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.
+
+# Functions related to the `sed` utility.
+
+# Replace `$1` by `$2` in the specified files (the rest of the arguments).
+#
+# Replacements are done in place.
+#
+# SETS: `local_1`
+# SETS: `local_2`
+replace() {
+       local_1=`escape_to_bre "$1"`
+       local_2=`escape_to_bre "$2"`
+       shift 2
+       sed -s -i -e s."${local_1}"."${local_2}".g -- "$@"
+       unset local_1
+       unset local_2
+}
+
+# Escape `$1` for inclusion in a POSIX BRE.
+escape_to_bre() {
+       echo "$1" | sed -e 's/\*\|\.\|\^\|\$\|\[\|\\/\\\0/g'
+}
index 4cd42ca..de29397 100644 (file)
@@ -22,7 +22,9 @@ import more_collections
 class CompoundDefListener
        super EntityDefListener
 
+       # The defined compound.
        var compound: Compound is writable, noinit
+
        private var memberdef: MemberDefListener is noinit
        private var param_listener: TypeParamListener is noinit
 
@@ -92,19 +94,20 @@ class CompoundDefListener
        redef fun entity: Entity do return compound
 
        redef fun start_dox_element(local_name: String, atts: Attributes) do
-               if ["compoundname", "innerclass", "innernamespace"].has(local_name) then
+               if "compoundname" == local_name then
                        text.listen_until(dox_uri, local_name)
-                       if ["innerclass", "innernamespace"].has(local_name) then
-                               refid = get_required(atts, "refid")
-                       end
-               else if "basecompoundref" == local_name then
-                       refid = get_optional(atts, "refid", "")
+               else if ["innerclass", "innernamespace", "basecompoundref"].has(local_name) then
                        prot = get_optional(atts, "prot", "")
-                       virt = get_optional(atts, "virt", "")
                        text.listen_until(dox_uri, local_name)
+                       if "basecompoundref" == local_name then
+                               refid = get_optional(atts, "refid", "")
+                               virt = get_optional(atts, "virt", "")
+                       else
+                               refid = get_required(atts, "refid")
+                       end
                else if "memberdef" == local_name then
                        read_member(atts)
-               else if local_name == "sectiondef" then
+               else if "sectiondef" == local_name then
                        member_defaults = section_kinds[get_required(atts, "kind")]
                        if member_defaults.is_special then
                                super # TODO
@@ -117,17 +120,17 @@ class CompoundDefListener
        end
 
        redef fun end_dox_element(local_name: String) do
-               if local_name == "compoundname" then
+               if "compoundname" == local_name then
                        compound.full_name = text.to_s
-               else if local_name == "innerclass" then
-                       compound.declare_class(refid, text.to_s)
-               else if local_name == "innernamespace" then
+               else if "innerclass" == local_name then
+                       compound.declare_class(refid, text.to_s, prot)
+               else if "innernamespace" == local_name then
                        compound.declare_namespace(refid, text.to_s)
                else if "memberdef" == local_name then
                        if not (memberdef.member isa UnknownMember) then
                                compound.declare_member(memberdef.member)
                        end
-               else if local_name == "basecompoundref" then
+               else if "basecompoundref" == local_name then
                        compound.declare_super(refid, text.to_s, prot, virt)
                else if "param" == local_name and compound isa ClassCompound then
                        compound.as(ClassCompound).add_type_parameter(param_listener.parameter)
index 84a880d..da9f09e 100644 (file)
@@ -21,10 +21,12 @@ import listener
 class DocListener
        super TextListener
 
-       var doc: JsonArray = new JsonArray is writable
+       # The read documentation.
+       var doc = new JsonArray is writable
 
        redef fun end_listening do
                super
-               doc.add(to_s)
+               var line = to_s.trim
+               if not line.is_empty then doc.add(line)
        end
 end
index bbc6410..fc03b0f 100644 (file)
@@ -131,7 +131,6 @@ abstract class SourceLanguage
 
                var content = text_array.last.as(String).r_trim
                var link = text.links.first
-               var found = false
 
                if link == null and content.has_suffix(suffix) then
                        content = content.substring(0, content.length - suffix.length).r_trim
@@ -162,7 +161,9 @@ class JavaSource
                # For abstract members, Doxygen put `abstract` at the beginning of the type.
                # We assume that Doxygen do not put annotations in the type (it seems to
                # be the case).
-               member.is_abstract = extract_keyword(type_text, "abstract")
+               if extract_keyword(type_text, "abstract") then
+                       member.is_abstract = true
+               end
                # TODO final
                # TODO void
                # TODO Avoid using `RawType` when possible. Only use `RawType` as a fallback.
index 26de0d2..40d021f 100644 (file)
@@ -36,6 +36,7 @@ abstract class DoxmlListener
                self.locator = locator
        end
 
+       # The Doxygen’s namespace IRI.
        protected fun dox_uri: String do return ""
 
        redef fun start_element(uri: String, local_name: String, qname: String,
@@ -61,6 +62,9 @@ abstract class DoxmlListener
        # See `ContentHandler.start_element` for the description of the parameters.
        protected fun end_dox_element(local_name: String) do end
 
+       # Get the boolean value of the specified attribute.
+       #
+       # `false` by default.
        protected fun get_bool(atts: Attributes, local_name: String): Bool do
                return get_optional(atts, local_name, "no") == "yes"
        end
@@ -197,7 +201,10 @@ end
 class TextListener
        super StackableListener
 
+       # The read text.
        protected var buffer: Buffer = new FlatBuffer
+
+       # Is the last read chunk was ignorable white space?
        private var sp: Bool = false
 
        redef fun listen_until(uri: String, local_name: String) do
diff --git a/contrib/neo_doxygen/src/flush_stdout.nit b/contrib/neo_doxygen/src/flush_stdout.nit
new file mode 100644 (file)
index 0000000..30be3fc
--- /dev/null
@@ -0,0 +1,25 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Add the ability to flush the standard output.
+module flush_stdout
+
+in "C Header" `{
+       #include <stdio.h>
+`}
+
+# Flush the standard output.
+fun flush_stdout in "C" `{
+       fflush(stdout);
+`}
diff --git a/contrib/neo_doxygen/src/graph_store.nit b/contrib/neo_doxygen/src/graph_store.nit
new file mode 100644 (file)
index 0000000..b15ae4f
--- /dev/null
@@ -0,0 +1,117 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# A storage medium for a graph.
+module graph_store
+
+import neo4j
+import console
+import flush_stdout
+
+# A storage medium for a graph.
+#
+# Provides a way to save a Neo4j graph.
+abstract class GraphStore
+
+       # Escape control sequence to save the cursor position.
+       private var term_save_cursor: String = (new TermSaveCursor).to_s
+
+       # Escape control sequence to rewind to the last saved cursor position.
+       private var term_rewind: String = "{new TermRestoreCursor}{new TermEraseDisplayDown}"
+
+       # Is the storage medium already contains at least one node with the specified label?
+       fun has_node_label(name: String): Bool is abstract
+
+       # Save all specified Neo4j entities.
+       fun save_all(neo_entities: Collection[NeoEntity]) is abstract
+
+       # Prepare the output to show the progress.
+       #
+       # This method must be called before the first call to `show_progress` or
+       # `show_done`.
+       protected fun prepare_display do
+               printn "{term_save_cursor} "
+               flush_stdout
+       end
+
+       # Show the progress, in percentage.
+       #
+       # For use in the implementation of `save_all` only.
+       protected fun show_progress(progress: Int) do
+               printn "{term_rewind} {progress}% "
+               flush_stdout
+       end
+
+       # Show a message to indicate that the task finished with success.
+       #
+       # For use in the implementation of `save_all` only.
+       protected fun show_done do
+               print "{term_rewind} Done."
+               flush_stdout
+       end
+end
+
+# An actual Neo4j database as a storage medium.
+class Neo4jStore
+       super GraphStore
+
+       # How many operations can be executed in one batch?
+       private var batch_max_size = 1000
+
+       # The Neo4j client to use.
+       var client: Neo4jClient
+
+       redef fun has_node_label(name: String): Bool do
+               var query = new CypherQuery.from_string(
+                               "match n where \{name\} in labels(n) return count(n)")
+               query.params["name"] = name
+               var data = client.cypher(query).as(JsonObject)["data"]
+               var result = data.as(JsonArray).first.as(JsonArray).first.as(Int)
+               return result > 0
+       end
+
+       redef fun save_all(neo_entities: Collection[NeoEntity]) do
+               var batch = new NeoBatch(client)
+               var len = neo_entities.length
+               var sum = 0
+               var i = 1
+
+               prepare_display
+               for nentity in neo_entities do
+                       batch.save_entity(nentity)
+                       if i == batch_max_size then
+                               do_batch(batch)
+                               sum += batch_max_size
+                               show_progress(sum * 100 / len)
+                               batch = new NeoBatch(client)
+                               i = 1
+                       else
+                               i += 1
+                       end
+               end
+               do_batch(batch)
+               show_done
+       end
+
+       # Execute `batch` and check for errors.
+       #
+       # Abort if `batch.execute` returns errors.
+       private fun do_batch(batch: NeoBatch) do
+               var errors = batch.execute
+               if not errors.is_empty then
+                       for e in errors do sys.stderr.write("{sys.program_name}: {e}\n")
+                       exit(1)
+               end
+       end
+end
index 7663c0a..6727cb3 100644 (file)
@@ -72,8 +72,8 @@ class ClassCompound
                class_def["mdoc"] = doc
        end
 
-       redef fun declare_super(id: String, name: String, prot: String, virt: String) do
-               class_def.declare_super(id, name, prot, virt)
+       redef fun declare_super(id: String, full_name: String, prot: String, virt: String) do
+               class_def.declare_super(id, full_name, prot, virt)
        end
 
        redef fun declare_member(member: Member) do
@@ -109,9 +109,21 @@ end
 class ClassDef
        super CodeBlock
 
+       # The defined class.
        var class_compound: ClassCompound
+
+       # The `model_id` of the base classes.
        var supers: SimpleCollection[String] = new Array[String]
-       var members: SimpleCollection[Member] = new Array[Member]
+
+       # The set of the introduced/redefined members.
+       #
+       # Includes inner classes.
+       #
+       # To ensure that the `full_name` of each member is correctly set,
+       # `declare_member` or `declare_class` should be used to add each member.
+       #
+       # Note: `declare_class` is defined by the `inner_class` module.
+       var members: SimpleCollection[MemberOrInner] = new Array[MemberOrInner]
 
        init do
                super
@@ -119,13 +131,23 @@ class ClassDef
                self["is_intro"] = true
        end
 
-       fun declare_super(id: String, name: String, prot: String, virt: String) do
-               # TODO prot, virt, name
+       # Declare a base compound (usually, a base class).
+       #
+       # Parameters:
+       #
+       # * `id`: `model_id` of the base compound. May be empty.
+       # * `full_name`: qualified name of the base compound. May be empty.
+       # * `prot`: visibility (proctection) of the relationship.
+       # * `virt`: level of virtuality of the relationship.
+       fun declare_super(id: String, full_name: String, prot: String,
+                       virt: String) do
+               # TODO prot, virt, full_name
                if "" != id then
                        supers.add(id)
                end
        end
 
+       # Append the specified member.
        fun declare_member(member: Member) do
                var full_name = self["full_name"]
 
@@ -192,6 +214,7 @@ class ClassType
        # Return the number of arguments.
        fun arity: Int do return arguments.length
 
+       # Is the class generic?
        fun is_generic: Bool do return arity > 0
 
        redef fun put_in_graph do
index e14d817..150983a 100644 (file)
 module model::graph
 
 import neo4j
+import more_collections
 import location
 
 # A Neo4j graph.
 class NeoGraph
+       # All the nodes in the graph.
        var all_nodes: SimpleCollection[NeoNode] = new Array[NeoNode]
+
+       # All the edges in the graph.
        var all_edges: SimpleCollection[NeoEdge] = new Array[NeoEdge]
 
        # Add a relationship between two nodes.
@@ -31,35 +35,76 @@ class NeoGraph
        end
 end
 
-# The project’s graph.
+# A project’s graph.
+#
+# Here is the usual steps to build a project graph:
+#
+# <ul>
+# <li>Instantiate `ProjectGraph` by giving the name that will label the project.</li>
+# <li>For each compound:
+# <ul>
+# <li>Instantiate the compound.</li>
+# <li>Provide all the related data.</li>
+# <li>Call the `put_in_graph` method of the compound.</li>
+# </ul></li>
+# <li>Call the `add_global_modules` method of the project’s graph (defined in
+# the `module_compound` module). This permits to take global classes into
+# account correctly.</li>
+# <li>Call the `put_edges` method of the project’s graph.</li>
+# </ul>
 class ProjectGraph
        super NeoGraph
 
+       # The project’s name.
+       var project_name: String
+
        # The node reperesenting the project.
        #
        # Once the project’s graph is initialized, this node must not be edited.
-       var project: NeoNode = new NeoNode
+       var project = new NeoNode
 
        # Entities by `model_id`.
        var by_id: Map[String, Entity] = new HashMap[String, Entity]
 
+       # Namespaces by `full_name`.
+       var namespaces: Map[String, Namespace] = new HashMap[String, Namespace]
+
+       # For each `ClassCompound` in the graph, the mapping between its `model_id` and its namespace.
+       #
+       # Defaults to the root namespace. An entry is added each time
+       # `Namespace.declare_class` is called.
+       #
+       # Note: In the graph, there is no direct link between a namespace and a
+       # class. It is the role of a module (created internally by a `FileCompound`)
+       # to link a class with its namespace. So, this collection is used by modules
+       # to know which class in a file belong to their related namespace. It is
+       # also used by `FileCompound` to detect classes in the root namespace.
+       var class_to_ns: Map[String, Namespace] is noinit
+
        # Initialize a new project graph using the specified project name.
        #
        # The specified name will label all nodes of the project’s graph.
-       init(name: String) do
-               project.labels.add(name)
+       init do
+               project.labels.add(project_name)
                project.labels.add("MEntity")
                project.labels.add("MProject")
-               project["name"] = name
+               project["name"] = project_name
                all_nodes.add(project)
 
                var root = new RootNamespace(self)
                root.put_in_graph
                by_id[""] = root
+               class_to_ns = new DefaultMap[String, Namespace](root)
        end
 
        # Request to all nodes in the graph to add their related edges.
+       #
+       # Note: For the rare cases where a node need to wait the `put_edges` to add
+       # an implicit node, this method makes sure to call the `put_edges` method
+       # of the newly added nodes only after processing all the nodes that was
+       # already there.
        fun put_edges do
+               all_edges.clear
                add_edge(project, "ROOT", by_id[""])
                for n in all_nodes do
                        if n isa Entity then
@@ -84,10 +129,10 @@ abstract class Entity
        var model_id: String = "" is writable
 
        # Associated documentation.
-       var doc: JsonArray = new JsonArray is writable
+       var doc = new JsonArray is writable
 
        init do
-               self.labels.add(graph.project["name"].to_s)
+               self.labels.add(graph.project_name)
                self.labels.add("MEntity")
        end
 
@@ -120,7 +165,7 @@ abstract class Entity
        #
        # Also set `name` using `name_separator`.
        fun full_name=(full_name: String) do
-               var m: nullable Match = full_name.search_last(name_separator)
+               var m = full_name.search_last(name_separator)
 
                self["full_name"] = full_name
                if m == null then
@@ -139,7 +184,11 @@ abstract class Entity
 
        # Set the full name using the current name and the specified parent name.
        fun parent_name=(parent_name: String) do
-               self["full_name"] = parent_name + name_separator + self["name"].as(not null).to_s
+               if parent_name.is_empty then
+                       self["full_name"] = name
+               else
+                       self["full_name"] = parent_name + name_separator + name
+               end
        end
 
        # Set the location of the entity in the source code.
@@ -204,29 +253,41 @@ abstract class Compound
 
        # Declare an inner namespace.
        #
+       # Note: Althought Doxygen indicates that the name is optional,
+       # declarations with an empty name are not supported yet, except for the root
+       # namespace. For the root namespace, both arguments are empty.
+       #
        # Parameters:
        #
        # * `id`: `model_id` of the inner namespace. May be empty.
-       # * `name`: string identifying the inner namespace. May be empty.
-       fun declare_namespace(id: String, name: String) do end
+       # * `full_name`: qualified name of the inner namespace. Use an empty name
+       # for the root namespace.
+       fun declare_namespace(id: String, full_name: String) do end
 
        # Declare an inner class.
        #
+       # Note: Althought Doxygen indicates that both arguments are optional,
+       # declarations with an empty ID are not supported yet.
+       #
        # Parameters:
        #
-       # * `id`: `model_id` of the inner class. May be empty.
-       # * `name`: string identifying the inner class. May be empty.
-       fun declare_class(id: String, name: String) do end
+       # * `id`: `model_id` of the inner class.
+       # * `full_name`: qualified name of the inner class. Ignored in practice.
+       # * `prot`: visibility (proctection).
+       #
+       # TODO: Handle cases where only the `full_name` is available.
+       fun declare_class(id: String, full_name: String, prot: String) do end
 
        # Declare a base compound (usually, a base class).
        #
        # Parameters:
        #
        # * `id`: `model_id` of the base compound. May be empty.
-       # * `name`: string identifying the base compound. May be empty.
+       # * `full_name`: qualified name of the base compound. May be empty.
        # * `prot`: visibility (proctection) of the relationship.
        # * `virt`: level of virtuality of the relationship.
-       fun declare_super(id: String, name: String, prot: String, virt: String) do end
+       fun declare_super(id: String, full_name: String, prot: String,
+                       virt: String) do end
 end
 
 # An unrecognized compound.
@@ -245,18 +306,28 @@ end
 class Namespace
        super Compound
 
-       # Inner namespaces (IDs).
+       # The inner namespaces.
        #
        # Left empty for the root namespace.
-       var inner_namespaces: SimpleCollection[String] = new Array[String]
+       var inner_namespaces: SimpleCollection[NamespaceRef] = new Array[NamespaceRef]
 
        init do
                super
                self.labels.add("MGroup")
        end
 
-       redef fun declare_namespace(id: String, name: String) do
-               inner_namespaces.add(id)
+       redef fun declare_namespace(id: String, full_name: String) do
+               inner_namespaces.add new NamespaceRef(id, full_name)
+       end
+
+       redef fun declare_class(id: String, full_name: String, prot: String) do
+               graph.class_to_ns[id] = self
+       end
+
+       redef fun put_in_graph do
+               super
+               var full_name = self["full_name"]
+               if full_name isa String then graph.namespaces[full_name] = self
        end
 
        redef fun put_edges do
@@ -269,13 +340,42 @@ class Namespace
                        graph.add_edge(root, "NESTS", self)
                end
                for ns in inner_namespaces do
-                       var node = graph.by_id[ns]
+                       var node = ns.seek_in(graph)
                        graph.add_edge(node, "PARENT", self)
                        graph.add_edge(self, "NESTS", node)
                end
        end
 end
 
+# A reference to a namespace.
+class NamespaceRef
+       # The `model_id` of the target.
+       #
+       # Empty when unknown or for the root namespace.
+       var model_id: String
+
+       # The `full_name` of the target.
+       #
+       # Empty only for the root namespace.
+       var full_name: String
+
+       # Look for the targeted namespace in the specified graph.
+       fun seek_in(graph: ProjectGraph): Namespace do
+               var ns_compound: Namespace
+
+               if model_id.is_empty and not full_name.is_empty then
+                       # ID unspecified. => We have to look by name
+                       assert graph.namespaces.has_key(full_name) else
+                               sys.stderr.write "Namespace `{full_name}` not found."
+                       end
+                       ns_compound = graph.namespaces[full_name]
+               else
+                       ns_compound = graph.by_id[model_id].as(Namespace)
+               end
+               return ns_compound
+       end
+end
+
 # The root namespace of a `ProjectGraph`.
 #
 # This the only entity in the graph whose `model_id` is really `""`.
diff --git a/contrib/neo_doxygen/src/model/inner_class.nit b/contrib/neo_doxygen/src/model/inner_class.nit
new file mode 100644 (file)
index 0000000..91ee697
--- /dev/null
@@ -0,0 +1,122 @@
+# 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.
+
+# Adds the possibility to define inner classses.
+module model::inner_class
+
+import member
+import class_compound
+
+# An inner class.
+class InnerClass
+       super MemberOrInner
+
+       redef type INTRODUCER_TYPE: InnerClassIntroducer
+
+       # The outer class definition.
+       #
+       # Used to correct the short name of the inner class definition when
+       # `put_edges` is called.
+       #
+       # SEE: The notice concerning `name` in `/src/neo.nit`.
+       var outer: ClassDef
+
+       # The `model_id` of the actual inner class (`ClassCompound`).
+       var inner: String
+
+       init do
+               super
+               self.labels.add("MInnerClassDef")
+       end
+
+       redef fun is_intro do return true
+       redef fun create_introducer do return new InnerClassIntroducer(graph, self)
+       redef fun resolve_introducer do return introducer
+
+       redef fun put_edges do
+               super
+               var inner = graph.by_id[self.inner]
+               assert inner isa ClassCompound
+               var inner_def = inner.class_def
+               # Correct the short name of `inner` to avoid name collisions in a module.
+               inner_def.name = "{outer.name}{ns_separator}{name}"
+               graph.add_edge(self, "NESTS", inner_def)
+       end
+end
+
+# A `MProperty` node for an inner class.
+class InnerClassIntroducer
+       super MemberIntroducer
+
+       # The definition.
+       var def: InnerClass
+
+       init do
+               super
+               self.labels.add("MInnerClass")
+       end
+
+       redef fun put_edges do
+               super
+               var inner = graph.by_id[def.inner]
+               assert inner isa ClassCompound
+               var outer = def.outer.class_compound
+               # Correct the short name of `inner` to avoid name collisions in a module.
+               inner.name = "{outer.name}{ns_separator}{name}"
+               graph.add_edge(self, "NESTS", inner)
+       end
+end
+
+# Implements `declare_class`.
+redef class ClassCompound
+       redef fun declare_class(id, full_name, prot) do
+               class_def.declare_class(id, full_name, prot)
+       end
+end
+
+# Implements `declare_class`.
+redef class ClassDef
+
+       # The set of the defined inner classes.
+       #
+       # All `InnerClass` entities registred here are automatically added to the
+       # graph with the `ClassDef`.
+       #
+       # To ensure that the `full_name` of each `InnerClass` entity is correctly
+       # set and that each inner class will be correctly linked, `declare_class`
+       # should be used to add each inner class.
+       var inner_classes: SimpleCollection[InnerClass] = new Array[InnerClass]
+
+       # Declare an inner class.
+       #
+       # Parameters:
+       #
+       # * `id`: `model_id` of the inner class definition.
+       # * `full_name`: qualified name of the inner class definition.
+       # * `prot`: visibility (proctection).
+       fun declare_class(id: String, full_name: String, prot: String) do
+               var member = new InnerClass(graph, self, id)
+               member.full_name = full_name
+               member.visibility = prot
+               members.add member
+               inner_classes.add member
+       end
+
+       redef fun put_in_graph do
+               super
+               for member in inner_classes do
+                       member.put_in_graph
+               end
+       end
+end
index 8652577..f025a12 100644 (file)
@@ -21,10 +21,19 @@ import neo4j
 class Location
        super Jsonable
 
+       # The file’s path.
        var path: nullable String = null is writable
+
+       # The one-based index of the first line.
        var line_start: Int = 1 is writable
+
+       # The one-based index of the last line.
        var line_end: Int = 1 is writable
+
+       # The one-based column index of the first character.
        var column_start: Int = 1 is writable
+
+       # The one-based column index of the last character.
        var column_end: Int = 1 is writable
 
        redef fun to_s: String do
index f29892e..f6d9317 100644 (file)
@@ -18,42 +18,26 @@ module model::member
 import graph
 import type_entity
 
-# A member.
-abstract class Member
+# A member or an inner class.
+abstract class MemberOrInner
        super CodeBlock
 
+       # The type of the introducer.
+       type INTRODUCER_TYPE: MemberIntroducer
+
        # The node used to represent the `MProperty` node.
        #
        # Only defined if `self` is at the root of a reimplementation graph, and
        # only once `put_in_graph` is called.
-       var introducer: nullable MemberIntroducer = null
-
-       # Members that this member redefines/reimplements.
-       var reimplemented: SimpleCollection[String] = new Array[String]
+       var introducer: nullable INTRODUCER_TYPE = null
 
        init do
                super
                self.labels.add("MPropDef")
        end
 
-       # Set the static type.
-       fun static_type=(static_type: nullable TypeEntity) is abstract
-
-       # Get the static type.
-       fun static_type: nullable TypeEntity is abstract
-
-       # Append the specified parameter to the signature.
-       fun add_parameter(parameter: MemberParameter) do end
-
-       # Append a member that is reimplemeneted by `self`.
-       fun reimplement(parent: String) do
-               reimplemented.add(parent)
-       end
-
        # Does this member introduce the property?
-       fun is_intro: Bool do
-               return reimplemented.length <= 0
-       end
+       fun is_intro: Bool is abstract
 
        redef fun put_in_graph do
                super
@@ -92,6 +76,15 @@ abstract class Member
                end
        end
 
+       # Get the visibility.
+       #
+       # Return `""` by default.
+       fun visibility: String do
+               var visibility = self["visibility"]
+               if visibility isa String then return visibility
+               return ""
+       end
+
        redef fun name=(name: String) do
                super
                if introducer != null then
@@ -113,14 +106,41 @@ abstract class Member
                end
        end
 
+       # Create an instance of `MemberIntroducer` that will be linked to `self`.
+       protected fun create_introducer: INTRODUCER_TYPE is abstract
+
+       # Find the nearest reimplementation root.
+       fun resolve_introducer: nullable INTRODUCER_TYPE is abstract
+end
+
+# A member.
+abstract class Member
+       super MemberOrInner
+
+       # Members that this member redefines/reimplements.
+       var reimplemented: SimpleCollection[String] = new Array[String]
+
+       # Set the static type.
+       fun static_type=(static_type: nullable TypeEntity) is abstract
+
+       # Get the static type.
+       fun static_type: nullable TypeEntity is abstract
+
+       # Append the specified parameter to the signature.
+       fun add_parameter(parameter: MemberParameter) do end
+
+       # Append a member that is reimplemeneted by `self`.
+       fun reimplement(parent: String) do
+               reimplemented.add(parent)
+       end
+
+       redef fun is_intro do return reimplemented.length <= 0
+
        # Is the member abstract?
        fun is_abstract=(is_abstract: Bool) do
                self["is_abstract"] = is_abstract
        end
 
-       # Create an instance of `MemberIntroducer` that will be linked to `self`.
-       protected fun create_introducer: MemberIntroducer is abstract
-
        # Find the nearest reimplementation root.
        #
        #     var g = new ProjectGraph("foo")
@@ -139,7 +159,7 @@ abstract class Member
        #     m3.reimplement("3")
        #     m3.put_in_graph
        #     assert m3.resolve_introducer == null
-       fun resolve_introducer: nullable MemberIntroducer do
+       redef fun resolve_introducer do
                if introducer == null then
                        var member_queue = new List[String]
                        var visited = new HashSet[Member]
@@ -174,9 +194,12 @@ class UnknownMember
        redef fun put_edges do end
 end
 
+# A local definition of a method.
 class Method
        super Member
 
+       redef type INTRODUCER_TYPE: MethodIntroducer
+
        # The method’s signature.
        var signature: Signature is noinit, writable
 
@@ -201,9 +224,7 @@ class Method
                signature.parameters.add(parameter)
        end
 
-       redef fun create_introducer: MemberIntroducer do
-               return new MethodIntroducer(graph)
-       end
+       redef fun create_introducer do return new MethodIntroducer(graph)
 
        redef fun put_in_graph do
                super
@@ -216,9 +237,12 @@ class Method
        end
 end
 
+# A local definition of an attribute.
 class Attribute
        super Member
 
+       redef type INTRODUCER_TYPE: AttributeIntroducer
+
        # The declared type.
        redef var static_type: nullable TypeEntity = null is writable
 
@@ -227,9 +251,7 @@ class Attribute
                self.labels.add("MAttributeDef")
        end
 
-       redef fun create_introducer: MemberIntroducer do
-               return new AttributeIntroducer(graph)
-       end
+       redef fun create_introducer do return new AttributeIntroducer(graph)
 
        redef fun put_in_graph do
                super
@@ -256,9 +278,19 @@ abstract class MemberIntroducer
                self["visibility"] = "public"
        end
 
+       # Set the visibility.
        fun visibility=(visibility: String) do
                self["visibility"] = visibility
        end
+
+       # Get the visibility.
+       #
+       # Return `""` by default.
+       fun visibility: String do
+               var visibility = self["visibility"]
+               if visibility isa String then return visibility
+               return ""
+       end
 end
 
 # A `MProperty` node for a method.
index d3c2af9..a89c8f3 100644 (file)
@@ -21,3 +21,4 @@ import graph
 import class_compound
 import module_compound
 import member
+import inner_class
index 6629cc7..404bcac 100644 (file)
@@ -23,12 +23,18 @@ import class_compound
 # Creates one modules by inner namespace. The full name of the modules begin
 # with the namespace’s full name, and end with the unqualified name of the file,
 # without the extension.
+#
+# Note: If a module associated to the root namespace is needed, it is added to
+# the graph only when `put_edges` is called.
 class FileCompound
        super Compound
        super CodeBlock
 
-       # Mapping between inner namespace’s names and corresponding modules.
-       private var inner_namespaces: Map[String, Module] = new HashMap[String, Module]
+       # Modules corresponding to the namespaces defined/redefined in the file.
+       private var inner_namespaces = new Array[Module]
+
+       # `model_id` of the classes declared in the file.
+       private var inner_classes = new Array[String]
 
        # The last component of the path, without the extension.
        #
@@ -46,7 +52,7 @@ class FileCompound
                if location != null and location.path != null then
                        full_name = location.path.as(not null)
                end
-               for m in inner_namespaces.values do m.location = location
+               for m in inner_namespaces do m.location = location
        end
 
        redef fun name=(name: String) do
@@ -60,80 +66,112 @@ class FileCompound
                        basename = name.substring(0, match.from)
                end
                # Update the modules’ name.
-               for ns, m in inner_namespaces do
-                       m.full_name = "{ns}{ns_separator}{basename}"
-               end
+               for m in inner_namespaces do m.update_name
        end
 
-       redef fun declare_namespace(id: String, name: String) do
+       redef fun declare_namespace(id: String, full_name: String) do
                var m: Module
 
-               if inner_namespaces.keys.has(name) then
-                       m = inner_namespaces[name]
-                       if id != "" then m.parent = id
-               else
-                       m = new Module(graph)
-                       m.full_name = "{name}{ns_separator}{basename}"
-                       m.parent = id
-                       m.location = self["location"].as(nullable Location)
-                       inner_namespaces[name] = m
+               assert not full_name.is_empty or id.is_empty else
+                       sys.stderr.write "Inner mamespace declarations without name are not yet supported (except for the root namespace).\n"
                end
+               m = new Module(graph, self, new NamespaceRef(id, full_name))
+               m.location = self["location"].as(nullable Location)
+               inner_namespaces.add m
        end
 
-       redef fun declare_class(id: String, name: String) do
-               var match = name.search_last(ns_separator)
-               var ns_name: String
-               var m: Module
-
-               if match == null then
-                       ns_name = ""
-               else
-                       ns_name = name.substring(0, match.from)
-               end
-               if inner_namespaces.keys.has(ns_name) then
-                       m = inner_namespaces[ns_name]
-               else
-                       declare_namespace("", ns_name)
-                       m = inner_namespaces[ns_name]
+       redef fun declare_class(id, full_name, prot) do
+               assert not id.is_empty else
+                       sys.stderr.write "Inner class declarations without ID are not yet supported.\n"
                end
-               m.declare_class(id, name)
+               inner_classes.add id
        end
 
        redef fun put_in_graph do
                # Do not add `self` to the Neo4j graph...
                # ... but add its modules...
-               for m in inner_namespaces.values do m.put_in_graph
-               # ... and add `self` to the index.
+               for m in inner_namespaces do m.put_in_graph
+               # ... and add `self` to the indexes.
                if model_id != "" then graph.by_id[model_id] = self
+               graph.files.add self
+       end
+
+       # If the file contains some classes in the root namespace, add an implicit
+       # module to handle them.
+       #
+       # This method is called by `ProjectGraph.add_global_modules` and assumes
+       # that all the namespaces are already fully set and put in the graph.
+       fun declare_root_namespace do
+               if has_globals then
+                       declare_namespace("", "")
+                       inner_namespaces.last.put_in_graph
+               end
+       end
+
+       # Does this file contain classes in the root namespace?
+       private fun has_globals: Bool do
+               var root = graph.by_id[""]
+               for c in inner_classes do
+                       if graph.class_to_ns[c] == root then return true
+               end
+               return false
        end
 end
 
-# A module.
-class Module
+# A `MModule` node.
+#
+# For each file, there is one module by inner namespace.
+private class Module
        super Compound
        super CodeBlock
 
-       # The `model_id` of the parent namespace.
-       var parent: String = "" is writable
+       # The file that declares the module.
+       var file_compound: FileCompound
 
-       # The classes defined in the module.
-       var inner_classes: SimpleCollection[String] = new Array[String]
+       # The namespace defined or redefined by the module.
+       var namespace: NamespaceRef
 
        init do
                super
                self.labels.add("MModule")
+               update_name
        end
 
-       redef fun declare_class(id: String, name: String) do
-               inner_classes.add(id)
+       # Update the `full_name` and the `name`.
+       #
+       # Update the short name of the module to the `basename` of the file that
+       # declares it.
+       fun update_name do
+               name = file_compound.basename
+               parent_name = namespace.full_name
        end
 
        redef fun put_edges do
-               graph.add_edge(graph.by_id[parent], "DECLARES", self)
-               for c in inner_classes do
-                       var node = graph.by_id[c].as(ClassCompound)
-                       graph.add_edge(self, "INTRODUCES", node)
-                       graph.add_edge(self, "DEFINES", node.class_def)
+               var ns_compound = namespace.seek_in(graph)
+               graph.add_edge(ns_compound, "DECLARES", self)
+
+               for c in file_compound.inner_classes do
+                       if graph.class_to_ns[c] != ns_compound then continue
+                       var class_compound = graph.by_id[c].as(ClassCompound)
+                       graph.add_edge(self, "INTRODUCES", class_compound)
+                       graph.add_edge(self, "DEFINES", class_compound.class_def)
                end
        end
 end
+
+# Adds the `add_global_modules` phase to `ProjectGraph`.
+redef class ProjectGraph
+
+       # Project’s source files.
+       var files: SimpleCollection[FileCompound] = new Array[FileCompound]
+
+       # Add the modules that define the root namespace.
+       #
+       # **Must** be called before any call to `put_edges`, and after all the
+       # namespaces are fully set and put in the graph.
+       #
+       # Note: This method is not idempotent so it has to be called only once.
+       fun add_global_modules do
+               for f in files do f.declare_root_namespace
+       end
+end
index f26dfc2..48bb5ad 100644 (file)
@@ -20,21 +20,25 @@ module neo_doxygen
 
 import model
 import doxml
+import graph_store
 import console
+import flush_stdout
 import opts
 
 # An importation task.
 class NeoDoxygenJob
-       var client: Neo4jClient
-       var model: ProjectGraph is noinit
 
-       # How many operation can be executed in one batch?
-       private var batch_max_size = 1000
+       # The storage medium to use.
+       var store: GraphStore
+
+       # The loaded project graph.
+       var model: ProjectGraph is noinit
 
-       private var save_cursor: String = (new TermSaveCursor).to_s
+       # Escape control sequence to save the cursor position.
+       private var term_save_cursor: String = (new TermSaveCursor).to_s
 
-       # Escape control sequence to reset the current line.
-       private var reset_line: String = "{new TermRestoreCursor}{new TermEraseDisplayDown}"
+       # Escape control sequence to rewind to the last saved cursor position.
+       private var term_rewind: String = "{new TermRestoreCursor}{new TermEraseDisplayDown}"
 
        # Generate a graph from the specified project model.
        #
@@ -46,29 +50,46 @@ class NeoDoxygenJob
        fun load_project(name: String, dir: String, source: SourceLanguage) do
                check_name name
                model = new ProjectGraph(name)
-               # TODO Let the user select the language.
                var reader = new CompoundFileReader(model, source)
                # Queue for sub-directories.
                var directories = new Array[String]
+               var file_count = 0
 
-               if dir.length > 1 and dir.chars.last == "/" then
-                       dir = dir.substring(0, dir.length - 1)
+               if dir == "" then
+                       printn "Reading the current directory... "
+               else
+                       printn "Reading {dir}... "
                end
-               sys.stdout.write save_cursor
+               flush_stdout
                loop
-                       for f in dir.files do
+                       for f in list_files(dir) do
                                var path = dir/f
                                if path.file_stat.is_dir then
                                        directories.push(path)
                                else if f.has_suffix(".xml") and f != "index.xml" then
-                                       print "{reset_line}Reading {path}..."
                                        reader.read(path)
+                                       file_count += 1
                                end
                        end
                        if directories.length <= 0 then break
                        dir = directories.pop
                end
-               print "{reset_line}Reading... Done."
+               model.add_global_modules
+               print "Done."
+               if file_count < 2 then
+                       print "{file_count} file read."
+               else
+                       print "{file_count} files read."
+               end
+               flush_stdout
+       end
+
+       # List files in a directory.
+       #
+       # This method may be redefined to force the order in which the files
+       # are read by `load_project`.
+       protected fun list_files(dir: String): Collection[String] do
+               return dir.files
        end
 
        # Check the project’s name.
@@ -77,11 +98,7 @@ class NeoDoxygenJob
                        sys.stderr.write("{sys.program_name}: The project’s name must not" +
                                        " begin with an upper case letter. Got `{name}`.\n")
                end
-               var query = new CypherQuery.from_string("match n where \{name\} in labels(n) return count(n)")
-               query.params["name"] = name
-               var data = client.cypher(query).as(JsonObject)["data"]
-               var result = data.as(JsonArray).first.as(JsonArray).first.as(Int)
-               assert name_unused: result == 0 else
+               assert name_unused: not store.has_node_label(name) else
                        sys.stderr.write("{sys.program_name}: The label `{name}` is already" +
                        " used in the specified graph.\n")
                end
@@ -89,49 +106,16 @@ class NeoDoxygenJob
 
        # Save the graph.
        fun save do
-               print "Linking nodes...{save_cursor}"
+               sys.stdout.write "Linking nodes...{term_save_cursor} "
+               flush_stdout
                model.put_edges
-               print "{reset_line} Done."
+               print "{term_rewind} Done."
                var nodes = model.all_nodes
-               print "Saving {nodes.length} nodes...{save_cursor}"
-               push_all(nodes)
+               sys.stdout.write "Saving {nodes.length} nodes..."
+               store.save_all(nodes)
                var edges = model.all_edges
-               print "Saving {edges.length} edges...{save_cursor}"
-               push_all(edges)
-       end
-
-       # Save `neo_entities` in the database using batch mode.
-       private fun push_all(neo_entities: Collection[NeoEntity]) do
-               var batch = new NeoBatch(client)
-               var len = neo_entities.length
-               var sum = 0
-               var i = 1
-
-               for nentity in neo_entities do
-                       batch.save_entity(nentity)
-                       if i == batch_max_size then
-                               do_batch(batch)
-                               sum += batch_max_size
-                               print("{reset_line} {sum * 100 / len}%")
-                               batch = new NeoBatch(client)
-                               i = 1
-                       else
-                               i += 1
-                       end
-               end
-               do_batch(batch)
-               print("{reset_line} Done.")
-       end
-
-       # Execute `batch` and check for errors.
-       #
-       # Abort if `batch.execute` returns errors.
-       private fun do_batch(batch: NeoBatch) do
-               var errors = batch.execute
-               if not errors.is_empty then
-                       for e in errors do sys.stderr.write("{sys.program_name}: {e}\n")
-                       exit(1)
-               end
+               sys.stdout.write "Saving {edges.length} edges..."
+               store.save_all(edges)
        end
 end
 
@@ -199,15 +183,15 @@ class NeoDoxygenCommand
                opt_dest.default_value = default_dest
                option_context.add_option(opt_dest)
 
+               opt_help = new OptionBool("Show the help (this page).",
+                               "-h", "--help")
+               option_context.add_option(opt_help)
+
                var keys = new Array[String].from(sources.keys)
                opt_src_lang = new OptionEnum(keys,
                                "The programming language to assume when processing chunk in the declarations left as-is by Doxygen. Use `any` (the default) to disable any language-specific processing.",
                                keys.index_of("any"), "--src-lang")
                option_context.add_option(opt_src_lang)
-
-               opt_help = new OptionBool("Show the help (this page).",
-                               "-h", "--help")
-               option_context.add_option(opt_help)
        end
 
        # Start the application.
@@ -238,13 +222,18 @@ class NeoDoxygenCommand
                var dest = opt_dest.value
                var project_name = rest[0]
                var dir = rest[1]
-               var neo = new NeoDoxygenJob(new Neo4jClient(dest or else default_dest))
+               var neo = new NeoDoxygenJob(create_store(dest or else default_dest))
 
                neo.load_project(project_name, dir, source)
                neo.save
                return 0
        end
 
+       # Create an instance of `GraphStore` for the specified destination.
+       protected fun create_store(dest: String): GraphStore do
+               return new Neo4jStore(new Neo4jClient(dest))
+       end
+
        # Show the help.
        fun show_help do
                option_context.usage
diff --git a/contrib/neo_doxygen/src/tests/README.md b/contrib/neo_doxygen/src/tests/README.md
new file mode 100644 (file)
index 0000000..fbb4393
--- /dev/null
@@ -0,0 +1,7 @@
+Test scripts for `neo_doxygen`.
+
+The name of each test script is prefixed by `neo_doxygen_` to avoid name
+conflicts in `/tests/sav` and `/tests/out`. The expected output of each script
+is saved as a `*.res` file in `/tests/sav`.
+
+Note: All paths indicated here are relative to the root of the repository.
diff --git a/contrib/neo_doxygen/src/tests/neo_doxygen_dump.nit b/contrib/neo_doxygen/src/tests/neo_doxygen_dump.nit
new file mode 100644 (file)
index 0000000..f52cd01
--- /dev/null
@@ -0,0 +1,58 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# A variant of the `neo_doxygen` program that produces a debugging output of the graph instead of saving it.
+#
+# Note: The `--dest` option is ignored.
+module tests::neo_doxygen_dump
+
+import tests
+import neo_doxygen
+
+redef class Sys
+       redef fun program_name do return "%PROGRAM_NAME%"
+end
+
+redef class NeoDoxygenJob
+       redef fun list_files(dir) do
+               var a = super.to_a
+               default_comparator.sort(a)
+               return a
+       end
+end
+
+redef class NeoDoxygenCommand
+       redef fun create_store(url) do return new DebugStore
+end
+
+# Dummy storage medium that write a debugging output to the standard output.
+#
+# For testing purposes only.
+class DebugStore
+       super GraphStore
+
+       redef fun has_node_label(name) do return false
+
+       redef fun save_all(neo_entities) do
+               print ""
+               for n in neo_entities do
+                       if n isa NeoEdge then
+                               var buffer = new RopeBuffer
+                               n.debug buffer
+                               print buffer
+                       end
+               end
+               print "---===DONE===---"
+       end
+end
diff --git a/contrib/neo_doxygen/src/tests/neo_doxygen_file_compound.nit b/contrib/neo_doxygen/src/tests/neo_doxygen_file_compound.nit
new file mode 100644 (file)
index 0000000..15a7531
--- /dev/null
@@ -0,0 +1,76 @@
+# 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 tests
+import model::module_compound
+
+var graph = new ProjectGraph("foo")
+var file = new FileCompound(graph)
+var file_2 = new FileCompound(graph)
+var bar_class = new ClassCompound(graph)
+var baz_class = new ClassCompound(graph)
+var a_ns = new Namespace(graph)
+var b_ns = new Namespace(graph)
+var c_ns = new Namespace(graph)
+var d_ns = new Namespace(graph)
+var buffer = new RopeBuffer
+
+file.full_name = "Bar.java"
+file.model_id = "_Bar_8java"
+file.declare_class("classa_b_bar", "a::b::Bar", "package")
+file.declare_class("classbaz", "Baz", "")
+file.declare_namespace("", "a::b")
+file.put_in_graph
+
+file_2.full_name = "Bar.java"
+file_2.model_id = "_Bar_8java_2"
+file_2.declare_namespace("namespacec", "c")
+file_2.declare_namespace("", "d")
+file_2.put_in_graph
+
+bar_class.model_id = "classa_b_bar"
+bar_class.full_name = "a::b::Bar"
+bar_class.put_in_graph
+
+baz_class.model_id = "classbaz"
+baz_class.full_name = "Baz"
+baz_class.put_in_graph
+
+a_ns.full_name = "a"
+a_ns.declare_namespace("", "a::b")
+a_ns.put_in_graph
+
+b_ns.full_name = "a::b"
+b_ns.declare_class("classa_b_bar", "", "")
+b_ns.put_in_graph
+
+c_ns.model_id = "namespacec"
+c_ns.full_name = "c"
+c_ns.put_in_graph
+
+d_ns.model_id = "namespaced"
+d_ns.full_name = "d"
+d_ns.put_in_graph
+
+print "---===WITHOUT GLOBALS===---"
+graph.put_edges
+graph.debug buffer
+print buffer
+
+print "---===WITH GLOBALS===---"
+buffer.clear
+graph.add_global_modules
+graph.put_edges
+graph.debug buffer
+print buffer
diff --git a/contrib/neo_doxygen/src/tests/neo_doxygen_graph_empty_project.nit b/contrib/neo_doxygen/src/tests/neo_doxygen_graph_empty_project.nit
new file mode 100644 (file)
index 0000000..f011ae8
--- /dev/null
@@ -0,0 +1,22 @@
+# 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 tests
+
+var graph = new ProjectGraph("foo")
+var buffer = new RopeBuffer
+
+graph.put_edges
+graph.debug buffer
+print buffer
diff --git a/contrib/neo_doxygen/src/tests/neo_doxygen_member_resolve_introducer.nit b/contrib/neo_doxygen/src/tests/neo_doxygen_member_resolve_introducer.nit
new file mode 100644 (file)
index 0000000..4909e9d
--- /dev/null
@@ -0,0 +1,34 @@
+# 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 model::member
+
+# Copied from the documentation of `Member::resolve_introducer`.
+
+var g = new ProjectGraph("foo")
+var m1 = new Attribute(g)
+var m2 = new Attribute(g)
+var m3 = new Attribute(g)
+
+m1.model_id = "1"
+m1.put_in_graph
+m2.reimplement("1")
+m2.put_in_graph
+assert m1.resolve_introducer == m1.introducer
+assert m2.resolve_introducer == m1.introducer
+
+m3.model_id = "3"
+m3.reimplement("3")
+m3.put_in_graph
+assert m3.resolve_introducer == null
diff --git a/contrib/neo_doxygen/src/tests/tests.nit b/contrib/neo_doxygen/src/tests/tests.nit
new file mode 100644 (file)
index 0000000..797886b
--- /dev/null
@@ -0,0 +1,83 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Base module for tests related to `neo_doxygen`.
+module tests::tests
+
+import model::graph
+
+# Adds debugging output to graphs.
+redef class NeoGraph
+
+       # Append the debugging output of all relationships to the specified buffer.
+       fun debug(buffer: Buffer) do
+               buffer.append "# Graph\n"
+               for edge in all_edges do
+                       edge.debug buffer
+               end
+       end
+end
+
+# Adds debugging output to relationships.
+redef class NeoEdge
+
+       # Append the debugging output of this relationship to the specified buffer.
+       #
+       # Append the relationship type, the properties, and the debugging output of
+       # both extremities.
+       fun debug(buffer: Buffer) do
+               var rel_type = self.rel_type or else "?"
+               buffer.append "Edge\n"
+               buffer.append "=type={rel_type.length}:{rel_type}\n"
+               buffer.append "=properties=JsonObject({properties.length}):\n"
+               buffer.append properties.to_json
+               buffer.append "\n----\n=from="
+               from.debug buffer
+               buffer.append "----\n=to="
+               to.debug buffer
+               buffer.append "\n"
+       end
+end
+
+# Adds debugging output to nodes.
+redef class NeoNode
+
+       # Append the debugging output of this node to the specified buffer.
+       #
+       # Append the labels and the properties.
+       fun debug(buffer: Buffer) do
+               buffer.append "Node\n"
+               buffer.append "=labels=Array({labels.length}):\n"
+               for lab in labels do buffer.append "{lab.length}:{lab}\n"
+               buffer.append "=properties=JsonObject({properties.length}):\n"
+               buffer.append properties.to_json
+               buffer.append "\n"
+       end
+end
+
+# Adds debugging output to entities.
+redef class Entity
+
+       # Append the debugging output of this entity to the specified buffer.
+       #
+       # Append the `model_id`, the labels and the properties.
+       redef fun debug(buffer: Buffer) do
+               buffer.append "Entity#{model_id.length}:{model_id}\n"
+               buffer.append "=labels=Array({labels.length}):\n"
+               for lab in labels do buffer.append "{lab.length}:{lab}\n"
+               buffer.append "=properties=JsonObject({properties.length}):\n"
+               buffer.append properties.to_json
+               buffer.append "\n"
+       end
+end
diff --git a/contrib/neo_doxygen/tests/.gitattributes b/contrib/neo_doxygen/tests/.gitattributes
new file mode 100644 (file)
index 0000000..ab22f42
--- /dev/null
@@ -0,0 +1 @@
+/*/xml/*       -diff
diff --git a/contrib/neo_doxygen/tests/Makefile b/contrib/neo_doxygen/tests/Makefile
new file mode 100644 (file)
index 0000000..d90195d
--- /dev/null
@@ -0,0 +1,29 @@
+# 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.
+
+# All the dummy projects.
+PROJECTS=$(dir $(wildcard ./*/Doxyfile))
+
+.PHONY: xml bootstrap
+
+# Regenerate the XML documents.
+xml: bootstrap
+       for p in $(PROJECTS); do $(MAKE) -C "$$p" xml || exit; done
+
+# Generate the Makefiles in the sub-directories.
+bootstrap:
+       for p in $(PROJECTS); do { \
+               echo '# FILE GENERATED BY ../Makefile'"\n" > "$$p/Makefile" || exit; \
+               cat doxyproject.mk >> "$$p/Makefile" || exit; \
+       } ; done
diff --git a/contrib/neo_doxygen/tests/README.md b/contrib/neo_doxygen/tests/README.md
new file mode 100644 (file)
index 0000000..6201ecd
--- /dev/null
@@ -0,0 +1,4 @@
+Data files for tests.
+
+For test scripts, see `../src/tests`. To regenerate the XML documents, run
+`make`.
diff --git a/contrib/neo_doxygen/tests/doxyproject.mk b/contrib/neo_doxygen/tests/doxyproject.mk
new file mode 100644 (file)
index 0000000..b6ce8e0
--- /dev/null
@@ -0,0 +1,35 @@
+# 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.
+
+.PHONY: clean doxygen strip_paths xml
+
+# Regenerate the XML documents.
+xml: strip_paths
+
+clean:
+       rm -rf xml
+
+doxygen: clean
+       doxygen Doxyfile
+
+# Get rid of the absolute paths in the generated files.
+#
+# Doxygen ignores the `STRIP_FROM_PATH` setting when generating a XML output.
+# So, we have to replace the paths manually in order to get reproducible
+# results.
+#
+# WARNING: FOR USE ON TEST DATA ONLY.
+strip_paths: doxygen
+       . ../../sh-lib/more_sed.sh; \
+       replace `readlink -f -- ./src` '%SOURCE_DIRECTORY%' xml/*.xml
diff --git a/contrib/neo_doxygen/tests/empty-project/Doxyfile b/contrib/neo_doxygen/tests/empty-project/Doxyfile
new file mode 100644 (file)
index 0000000..bd06324
--- /dev/null
@@ -0,0 +1,2381 @@
+# Doxyfile 1.8.8
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "Test Project"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       =
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES                =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = YES
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  = src
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS          = *.c \
+                         *.cc \
+                         *.cxx \
+                         *.cpp \
+                         *.c++ \
+                         *.java \
+                         *.ii \
+                         *.ixx \
+                         *.ipp \
+                         *.i++ \
+                         *.inl \
+                         *.idl \
+                         *.ddl \
+                         *.odl \
+                         *.h \
+                         *.hh \
+                         *.hxx \
+                         *.hpp \
+                         *.h++ \
+                         *.cs \
+                         *.d \
+                         *.php \
+                         *.php4 \
+                         *.php5 \
+                         *.phtml \
+                         *.inc \
+                         *.m \
+                         *.markdown \
+                         *.md \
+                         *.mm \
+                         *.dox \
+                         *.py \
+                         *.f90 \
+                         *.f \
+                         *.for \
+                         *.tcl \
+                         *.vhd \
+                         *.vhdl \
+                         *.ucf \
+                         *.qsf \
+                         *.as \
+                         *.js
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = NO
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra stylesheet files is of importance (e.g. the last
+# stylesheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = YES
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT               = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+PLANTUML_JAR_PATH      =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP            = YES
diff --git a/contrib/neo_doxygen/tests/empty-project/README.md b/contrib/neo_doxygen/tests/empty-project/README.md
new file mode 100644 (file)
index 0000000..85bf9fe
--- /dev/null
@@ -0,0 +1,5 @@
+This directory contains an empty project for testing purposes.
+
+To regenerate the XML output located in `xml`, run `make`. If the `Makefile`
+does not exists, you can regenerate it by running `make bootstrap` in the parent
+directory.
diff --git a/contrib/neo_doxygen/tests/empty-project/src/org/example/foo/void.txt b/contrib/neo_doxygen/tests/empty-project/src/org/example/foo/void.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/neo_doxygen/tests/empty-project/xml/combine.xslt b/contrib/neo_doxygen/tests/empty-project/xml/combine.xslt
new file mode 100644 (file)
index 0000000..c148ee4
--- /dev/null
@@ -0,0 +1,15 @@
+<!-- XSLT script to combine the generated output into a single file. 
+     If you have xsltproc you could use:
+     xsltproc combine.xslt index.xml >all.xml
+-->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+  <xsl:output method="xml" version="1.0" indent="no" standalone="yes" />
+  <xsl:template match="/">
+    <doxygen version="{doxygenindex/@version}">
+      <!-- Load all doxgen generated xml files -->
+      <xsl:for-each select="doxygenindex/compound">
+        <xsl:copy-of select="document( concat( @refid, '.xml' ) )/doxygen/*" />
+      </xsl:for-each>
+    </doxygen>
+  </xsl:template>
+</xsl:stylesheet>
diff --git a/contrib/neo_doxygen/tests/empty-project/xml/compound.xsd b/contrib/neo_doxygen/tests/empty-project/xml/compound.xsd
new file mode 100644 (file)
index 0000000..86740f4
--- /dev/null
@@ -0,0 +1,1092 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+  <xsd:element name="doxygen" type="DoxygenType"/>
+
+  <!-- Complex types -->
+
+  <xsd:complexType name="DoxygenType">
+    <xsd:sequence maxOccurs="unbounded">
+      <xsd:element name="compounddef" type="compounddefType" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="version" type="DoxVersionNumber" use="required" />
+  </xsd:complexType>
+
+  <xsd:complexType name="compounddefType">
+    <xsd:sequence>
+      <xsd:element name="compoundname" type="xsd:string"/>
+      <xsd:element name="title" type="xsd:string" minOccurs="0" />
+      <xsd:element name="basecompoundref" type="compoundRefType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="derivedcompoundref" type="compoundRefType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="includes" type="incType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="includedby" type="incType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="incdepgraph" type="graphType" minOccurs="0" />
+      <xsd:element name="invincdepgraph" type="graphType" minOccurs="0" />
+      <xsd:element name="innerdir" type="refType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="innerfile" type="refType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="innerclass" type="refType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="innernamespace" type="refType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="innerpage" type="refType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="innergroup" type="refType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="templateparamlist" type="templateparamlistType" minOccurs="0" />
+      <xsd:element name="sectiondef" type="sectiondefType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" />
+      <xsd:element name="detaileddescription" type="descriptionType" minOccurs="0" />
+      <xsd:element name="inheritancegraph" type="graphType" minOccurs="0" />
+      <xsd:element name="collaborationgraph" type="graphType" minOccurs="0" />
+      <xsd:element name="programlisting" type="listingType" minOccurs="0" />
+      <xsd:element name="location" type="locationType" minOccurs="0" />
+      <xsd:element name="listofallmembers" type="listofallmembersType" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:string" />
+    <xsd:attribute name="kind" type="DoxCompoundKind" />
+    <xsd:attribute name="prot" type="DoxProtectionKind" />
+    <xsd:attribute name="final" type="DoxBool" use="optional"/>
+    <xsd:attribute name="sealed" type="DoxBool" use="optional"/>
+    <xsd:attribute name="abstract" type="DoxBool" use="optional"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="listofallmembersType">
+    <xsd:sequence>
+      <xsd:element name="member" type="memberRefType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="memberRefType">
+    <xsd:sequence>
+      <xsd:element name="scope" />
+      <xsd:element name="name" />
+    </xsd:sequence>
+    <xsd:attribute name="refid" type="xsd:string" />
+    <xsd:attribute name="prot" type="DoxProtectionKind" />
+    <xsd:attribute name="virt" type="DoxVirtualKind" />
+    <xsd:attribute name="ambiguityscope" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="compoundRefType">
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:string">
+        <xsd:attribute name="refid" type="xsd:string" use="optional" />
+        <xsd:attribute name="prot" type="DoxProtectionKind" />
+        <xsd:attribute name="virt" type="DoxVirtualKind" />
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+  <xsd:complexType name="reimplementType">
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:string">
+        <xsd:attribute name="refid" type="xsd:string" />
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+  <xsd:complexType name="incType">
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:string">
+        <xsd:attribute name="refid" type="xsd:string" />
+        <xsd:attribute name="local" type="DoxBool" />
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+  <xsd:complexType name="refType">
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:string">
+        <xsd:attribute name="refid" type="xsd:string" />
+        <xsd:attribute name="prot" type="DoxProtectionKind" use="optional"/>
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+  <xsd:complexType name="refTextType">
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:string">
+       <xsd:attribute name="refid" type="xsd:string" />
+       <xsd:attribute name="kindref" type="DoxRefKind" />
+       <xsd:attribute name="external" type="xsd:string" use="optional"/>
+       <xsd:attribute name="tooltip" type="xsd:string" use="optional"/>
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+  <xsd:complexType name="sectiondefType">
+    <xsd:sequence>
+      <xsd:element name="header" type="xsd:string" minOccurs="0" />
+      <xsd:element name="description" type="descriptionType" minOccurs="0" />
+      <xsd:element name="memberdef" type="memberdefType" maxOccurs="unbounded" />
+    </xsd:sequence>
+    <xsd:attribute name="kind" type="DoxSectionKind" />
+  </xsd:complexType>
+
+  <xsd:complexType name="memberdefType">
+    <xsd:sequence>
+      <xsd:element name="templateparamlist" type="templateparamlistType" minOccurs="0" />
+      <xsd:element name="type" type="linkedTextType" minOccurs="0" />
+      <xsd:element name="definition" minOccurs="0" />
+      <xsd:element name="argsstring" minOccurs="0" />
+      <xsd:element name="name" />
+      <xsd:element name="read" minOccurs="0" />
+      <xsd:element name="write" minOccurs="0" />
+      <xsd:element name="bitfield" minOccurs="0" />
+      <xsd:element name="reimplements" type="reimplementType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="reimplementedby" type="reimplementType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="param" type="paramType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="enumvalue" type="enumvalueType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="initializer" type="linkedTextType" minOccurs="0" />
+      <xsd:element name="exceptions" type="linkedTextType" minOccurs="0" />
+      <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" />
+      <xsd:element name="detaileddescription" type="descriptionType" minOccurs="0" />
+      <xsd:element name="inbodydescription" type="descriptionType" minOccurs="0" />
+      <xsd:element name="location" type="locationType" />
+      <xsd:element name="references" type="referenceType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="referencedby" type="referenceType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+    <xsd:attribute name="kind" type="DoxMemberKind" />
+    <xsd:attribute name="id" type="xsd:string" />
+    <xsd:attribute name="prot" type="DoxProtectionKind" />
+    <xsd:attribute name="static" type="DoxBool" />
+    <xsd:attribute name="const" type="DoxBool" use="optional"/>
+    <xsd:attribute name="explicit" type="DoxBool" use="optional"/>
+    <xsd:attribute name="inline" type="DoxBool" use="optional"/>
+    <xsd:attribute name="virt" type="DoxVirtualKind" use="optional"/>
+    <xsd:attribute name="volatile" type="DoxBool" use="optional"/>
+    <xsd:attribute name="mutable" type="DoxBool" use="optional"/>
+    <!-- Qt property -->
+    <xsd:attribute name="readable" type="DoxBool" use="optional"/>
+    <xsd:attribute name="writable" type="DoxBool" use="optional"/>
+    <!-- C++/CLI variable -->
+    <xsd:attribute name="initonly" type="DoxBool" use="optional"/>
+    <!-- C++/CLI and C# property -->
+    <xsd:attribute name="settable" type="DoxBool" use="optional"/>
+    <xsd:attribute name="gettable" type="DoxBool" use="optional"/>
+    <!-- C++/CLI function -->
+    <xsd:attribute name="final" type="DoxBool" use="optional"/>
+    <xsd:attribute name="sealed" type="DoxBool" use="optional"/>
+    <xsd:attribute name="new" type="DoxBool" use="optional"/>
+    <!-- C++/CLI event -->
+    <xsd:attribute name="add" type="DoxBool" use="optional"/>
+    <xsd:attribute name="remove" type="DoxBool" use="optional"/>
+    <xsd:attribute name="raise" type="DoxBool" use="optional"/>
+    <!-- Objective-C 2.0 protocol method -->
+    <xsd:attribute name="optional" type="DoxBool" use="optional"/>
+    <xsd:attribute name="required" type="DoxBool" use="optional"/>
+    <!-- Objective-C 2.0 property accessor -->
+    <xsd:attribute name="accessor" type="DoxAccessor" use="optional"/>
+    <!-- UNO IDL -->
+    <xsd:attribute name="attribute" type="DoxBool" use="optional"/>
+    <xsd:attribute name="property" type="DoxBool" use="optional"/>
+    <xsd:attribute name="readonly" type="DoxBool" use="optional"/>
+    <xsd:attribute name="bound" type="DoxBool" use="optional"/>
+    <xsd:attribute name="removable" type="DoxBool" use="optional"/>
+    <xsd:attribute name="contrained" type="DoxBool" use="optional"/>
+    <xsd:attribute name="transient" type="DoxBool" use="optional"/>
+    <xsd:attribute name="maybevoid" type="DoxBool" use="optional"/>
+    <xsd:attribute name="maybedefault" type="DoxBool" use="optional"/>
+    <xsd:attribute name="maybeambiguous" type="DoxBool" use="optional"/>
+
+  </xsd:complexType>
+
+  <xsd:complexType name="descriptionType" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="title" type="xsd:string" minOccurs="0"/>          
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect1" type="docSect1Type" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="internal" type="docInternalType" minOccurs="0" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="enumvalueType" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="name" />
+      <xsd:element name="initializer" type="linkedTextType" minOccurs="0" />
+      <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" />
+      <xsd:element name="detaileddescription" type="descriptionType" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:string" />
+    <xsd:attribute name="prot" type="DoxProtectionKind" />
+  </xsd:complexType>
+
+  <xsd:complexType name="templateparamlistType">
+    <xsd:sequence>
+      <xsd:element name="param" type="paramType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="paramType">
+    <xsd:sequence>
+      <xsd:element name="type" type="linkedTextType" minOccurs="0" />
+      <xsd:element name="declname" minOccurs="0" />
+      <xsd:element name="defname" minOccurs="0" />
+      <xsd:element name="array" minOccurs="0" />
+      <xsd:element name="defval" type="linkedTextType" minOccurs="0" />
+      <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="linkedTextType" mixed="true">
+    <xsd:sequence>
+    <xsd:element name="ref" type="refTextType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="graphType">
+    <xsd:sequence>
+      <xsd:element name="node" type="nodeType" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="nodeType">
+    <xsd:sequence>
+      <xsd:element name="label" />
+      <xsd:element name="link" type="linkType" minOccurs="0" />
+      <xsd:element name="childnode" type="childnodeType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="childnodeType">
+    <xsd:sequence>
+      <xsd:element name="edgelabel" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="refid" type="xsd:string" />
+    <xsd:attribute name="relation" type="DoxGraphRelation" />
+  </xsd:complexType>
+
+  <xsd:complexType name="linkType">
+    <xsd:attribute name="refid" type="xsd:string" />
+    <xsd:attribute name="external" type="xsd:string" use="optional"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="listingType">
+    <xsd:sequence>
+      <xsd:element name="codeline" type="codelineType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="codelineType">
+    <xsd:sequence>
+      <xsd:element name="highlight" type="highlightType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+    <xsd:attribute name="lineno" type="xsd:integer" />
+    <xsd:attribute name="refid" type="xsd:string" />
+    <xsd:attribute name="refkind" type="DoxRefKind" />
+    <xsd:attribute name="external" type="DoxBool" />
+  </xsd:complexType>
+
+  <xsd:complexType name="highlightType" mixed="true">
+    <xsd:choice minOccurs="0" maxOccurs="unbounded">
+      <xsd:element name="sp" />
+      <xsd:element name="ref" type="refTextType" />
+    </xsd:choice>
+    <xsd:attribute name="class" type="DoxHighlightClass" />
+  </xsd:complexType>
+
+  <xsd:complexType name="referenceType" mixed="true">
+    <xsd:attribute name="refid" type="xsd:string" />
+    <xsd:attribute name="compoundref" type="xsd:string" use="optional" />
+    <xsd:attribute name="startline" type="xsd:integer" />
+    <xsd:attribute name="endline" type="xsd:integer" />
+  </xsd:complexType>
+
+  <xsd:complexType name="locationType">
+    <xsd:attribute name="file" type="xsd:string" />
+    <xsd:attribute name="line" type="xsd:integer" />
+    <xsd:attribute name="column" type="xsd:integer" use="optional"/>
+    <xsd:attribute name="bodyfile" type="xsd:string" />
+    <xsd:attribute name="bodystart" type="xsd:integer" />
+    <xsd:attribute name="bodyend" type="xsd:integer" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docSect1Type" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="title" type="xsd:string" />       
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect2" type="docSect2Type" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="internal" type="docInternalS1Type" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docSect2Type" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="title" type="xsd:string" />       
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect3" type="docSect3Type" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="internal" type="docInternalS2Type" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docSect3Type" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="title" type="xsd:string" />       
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect4" type="docSect4Type" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="internal" type="docInternalS3Type" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docSect4Type" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="title" type="xsd:string" />       
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="internal" type="docInternalS4Type" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docInternalType" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="para"  type="docParaType"  minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect1" type="docSect1Type" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docInternalS1Type" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="para"  type="docParaType"  minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect2" type="docSect2Type" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docInternalS2Type" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="para"  type="docParaType"  minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect3" type="docSect3Type" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docInternalS3Type" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="para"  type="docParaType"  minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect3" type="docSect4Type" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docInternalS4Type" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="para"  type="docParaType"  minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+  <xsd:group name="docTitleCmdGroup">
+    <xsd:choice>
+      <xsd:element name="ulink" type="docURLLink" />
+      <xsd:element name="bold" type="docMarkupType" />
+      <xsd:element name="emphasis" type="docMarkupType" />
+      <xsd:element name="computeroutput" type="docMarkupType" />
+      <xsd:element name="subscript" type="docMarkupType" />
+      <xsd:element name="superscript" type="docMarkupType" />
+      <xsd:element name="center" type="docMarkupType" />
+      <xsd:element name="small" type="docMarkupType" />
+      <xsd:element name="htmlonly" type="xsd:string" />
+      <xsd:element name="manonly" type="xsd:string" />
+      <xsd:element name="xmlonly" type="xsd:string" />
+      <xsd:element name="rtfonly" type="xsd:string" />
+      <xsd:element name="latexonly" type="xsd:string" />
+      <xsd:element name="dot" type="xsd:string" />
+      <xsd:element name="plantuml" type="xsd:string" />
+      <xsd:element name="anchor" type="docAnchorType" />
+      <xsd:element name="formula" type="docFormulaType" />
+      <xsd:element name="ref" type="docRefTextType" />
+      <xsd:element name="nonbreakablespace" type="docEmptyType" />
+      <xsd:element name="iexcl" type="docEmptyType" />
+      <xsd:element name="cent" type="docEmptyType" />
+      <xsd:element name="pound" type="docEmptyType" />
+      <xsd:element name="curren" type="docEmptyType" />
+      <xsd:element name="yen" type="docEmptyType" />
+      <xsd:element name="brvbar" type="docEmptyType" />
+      <xsd:element name="sect" type="docEmptyType" />
+      <xsd:element name="umlaut" type="docEmptyType" />
+      <xsd:element name="copy" type="docEmptyType" />
+      <xsd:element name="ordf" type="docEmptyType" />
+      <xsd:element name="laquo" type="docEmptyType" />
+      <xsd:element name="not" type="docEmptyType" />
+      <xsd:element name="shy" type="docEmptyType" />
+      <xsd:element name="registered" type="docEmptyType" />
+      <xsd:element name="macr" type="docEmptyType" />
+      <xsd:element name="deg" type="docEmptyType" />
+      <xsd:element name="plusmn" type="docEmptyType" />
+      <xsd:element name="sup2" type="docEmptyType" />
+      <xsd:element name="sup3" type="docEmptyType" />
+      <xsd:element name="acute" type="docEmptyType" />
+      <xsd:element name="micro" type="docEmptyType" />
+      <xsd:element name="para" type="docEmptyType" />
+      <xsd:element name="middot" type="docEmptyType" />
+      <xsd:element name="cedil" type="docEmptyType" />
+      <xsd:element name="sup1" type="docEmptyType" />
+      <xsd:element name="ordm" type="docEmptyType" />
+      <xsd:element name="raquo" type="docEmptyType" />
+      <xsd:element name="frac14" type="docEmptyType" />
+      <xsd:element name="frac12" type="docEmptyType" />
+      <xsd:element name="frac34" type="docEmptyType" />
+      <xsd:element name="iquest" type="docEmptyType" />
+      <xsd:element name="Agrave" type="docEmptyType" />
+      <xsd:element name="Aacute" type="docEmptyType" />
+      <xsd:element name="Acirc" type="docEmptyType" />
+      <xsd:element name="Atilde" type="docEmptyType" />
+      <xsd:element name="Aumlaut" type="docEmptyType" />
+      <xsd:element name="Aring" type="docEmptyType" />
+      <xsd:element name="AElig" type="docEmptyType" />
+      <xsd:element name="Ccedil" type="docEmptyType" />
+      <xsd:element name="Egrave" type="docEmptyType" />
+      <xsd:element name="Eacute" type="docEmptyType" />
+      <xsd:element name="Ecirc" type="docEmptyType" />
+      <xsd:element name="Eumlaut" type="docEmptyType" />
+      <xsd:element name="Igrave" type="docEmptyType" />
+      <xsd:element name="Iacute" type="docEmptyType" />
+      <xsd:element name="Icirc" type="docEmptyType" />
+      <xsd:element name="Iumlaut" type="docEmptyType" />
+      <xsd:element name="ETH" type="docEmptyType" />
+      <xsd:element name="Ntilde" type="docEmptyType" />
+      <xsd:element name="Ograve" type="docEmptyType" />
+      <xsd:element name="Oacute" type="docEmptyType" />
+      <xsd:element name="Ocirc" type="docEmptyType" />
+      <xsd:element name="Otilde" type="docEmptyType" />
+      <xsd:element name="Oumlaut" type="docEmptyType" />
+      <xsd:element name="times" type="docEmptyType" />
+      <xsd:element name="Oslash" type="docEmptyType" />
+      <xsd:element name="Ugrave" type="docEmptyType" />
+      <xsd:element name="Uacute" type="docEmptyType" />
+      <xsd:element name="Ucirc" type="docEmptyType" />
+      <xsd:element name="Uumlaut" type="docEmptyType" />
+      <xsd:element name="Yacute" type="docEmptyType" />
+      <xsd:element name="THORN" type="docEmptyType" />
+      <xsd:element name="szlig" type="docEmptyType" />
+      <xsd:element name="agrave" type="docEmptyType" />
+      <xsd:element name="aacute" type="docEmptyType" />
+      <xsd:element name="acirc" type="docEmptyType" />
+      <xsd:element name="atilde" type="docEmptyType" />
+      <xsd:element name="aumlaut" type="docEmptyType" />
+      <xsd:element name="aring" type="docEmptyType" />
+      <xsd:element name="aelig" type="docEmptyType" />
+      <xsd:element name="ccedil" type="docEmptyType" />
+      <xsd:element name="egrave" type="docEmptyType" />
+      <xsd:element name="eacute" type="docEmptyType" />
+      <xsd:element name="ecirc" type="docEmptyType" />
+      <xsd:element name="eumlaut" type="docEmptyType" />
+      <xsd:element name="igrave" type="docEmptyType" />
+      <xsd:element name="iacute" type="docEmptyType" />
+      <xsd:element name="icirc" type="docEmptyType" />
+      <xsd:element name="iumlaut" type="docEmptyType" />
+      <xsd:element name="eth" type="docEmptyType" />
+      <xsd:element name="ntilde" type="docEmptyType" />
+      <xsd:element name="ograve" type="docEmptyType" />
+      <xsd:element name="oacute" type="docEmptyType" />
+      <xsd:element name="ocirc" type="docEmptyType" />
+      <xsd:element name="otilde" type="docEmptyType" />
+      <xsd:element name="oumlaut" type="docEmptyType" />
+      <xsd:element name="divide" type="docEmptyType" />
+      <xsd:element name="oslash" type="docEmptyType" />
+      <xsd:element name="ugrave" type="docEmptyType" />
+      <xsd:element name="uacute" type="docEmptyType" />
+      <xsd:element name="ucirc" type="docEmptyType" />
+      <xsd:element name="uumlaut" type="docEmptyType" />
+      <xsd:element name="yacute" type="docEmptyType" />
+      <xsd:element name="thorn" type="docEmptyType" />
+      <xsd:element name="yumlaut" type="docEmptyType" />
+      <xsd:element name="fnof" type="docEmptyType" />
+      <xsd:element name="Alpha" type="docEmptyType" />
+      <xsd:element name="Beta" type="docEmptyType" />
+      <xsd:element name="Gamma" type="docEmptyType" />
+      <xsd:element name="Delta" type="docEmptyType" />
+      <xsd:element name="Epsilon" type="docEmptyType" />
+      <xsd:element name="Zeta" type="docEmptyType" />
+      <xsd:element name="Eta" type="docEmptyType" />
+      <xsd:element name="Theta" type="docEmptyType" />
+      <xsd:element name="Iota" type="docEmptyType" />
+      <xsd:element name="Kappa" type="docEmptyType" />
+      <xsd:element name="Lambda" type="docEmptyType" />
+      <xsd:element name="Mu" type="docEmptyType" />
+      <xsd:element name="Nu" type="docEmptyType" />
+      <xsd:element name="Xi" type="docEmptyType" />
+      <xsd:element name="Omicron" type="docEmptyType" />
+      <xsd:element name="Pi" type="docEmptyType" />
+      <xsd:element name="Rho" type="docEmptyType" />
+      <xsd:element name="Sigma" type="docEmptyType" />
+      <xsd:element name="Tau" type="docEmptyType" />
+      <xsd:element name="Upsilon" type="docEmptyType" />
+      <xsd:element name="Phi" type="docEmptyType" />
+      <xsd:element name="Chi" type="docEmptyType" />
+      <xsd:element name="Psi" type="docEmptyType" />
+      <xsd:element name="Omega" type="docEmptyType" />
+      <xsd:element name="alpha" type="docEmptyType" />
+      <xsd:element name="beta" type="docEmptyType" />
+      <xsd:element name="gamma" type="docEmptyType" />
+      <xsd:element name="delta" type="docEmptyType" />
+      <xsd:element name="epsilon" type="docEmptyType" />
+      <xsd:element name="zeta" type="docEmptyType" />
+      <xsd:element name="eta" type="docEmptyType" />
+      <xsd:element name="theta" type="docEmptyType" />
+      <xsd:element name="iota" type="docEmptyType" />
+      <xsd:element name="kappa" type="docEmptyType" />
+      <xsd:element name="lambda" type="docEmptyType" />
+      <xsd:element name="mu" type="docEmptyType" />
+      <xsd:element name="nu" type="docEmptyType" />
+      <xsd:element name="xi" type="docEmptyType" />
+      <xsd:element name="omicron" type="docEmptyType" />
+      <xsd:element name="pi" type="docEmptyType" />
+      <xsd:element name="rho" type="docEmptyType" />
+      <xsd:element name="sigmaf" type="docEmptyType" />
+      <xsd:element name="sigma" type="docEmptyType" />
+      <xsd:element name="tau" type="docEmptyType" />
+      <xsd:element name="upsilon" type="docEmptyType" />
+      <xsd:element name="phi" type="docEmptyType" />
+      <xsd:element name="chi" type="docEmptyType" />
+      <xsd:element name="psi" type="docEmptyType" />
+      <xsd:element name="omega" type="docEmptyType" />
+      <xsd:element name="thetasym" type="docEmptyType" />
+      <xsd:element name="upsih" type="docEmptyType" />
+      <xsd:element name="piv" type="docEmptyType" />
+      <xsd:element name="bull" type="docEmptyType" />
+      <xsd:element name="hellip" type="docEmptyType" />
+      <xsd:element name="prime" type="docEmptyType" />
+      <xsd:element name="Prime" type="docEmptyType" />
+      <xsd:element name="oline" type="docEmptyType" />
+      <xsd:element name="frasl" type="docEmptyType" />
+      <xsd:element name="weierp" type="docEmptyType" />
+      <xsd:element name="image" type="docEmptyType" />
+      <xsd:element name="real" type="docEmptyType" />
+      <xsd:element name="trademark" type="docEmptyType" />
+      <xsd:element name="alefsym" type="docEmptyType" />
+      <xsd:element name="larr" type="docEmptyType" />
+      <xsd:element name="uarr" type="docEmptyType" />
+      <xsd:element name="rarr" type="docEmptyType" />
+      <xsd:element name="darr" type="docEmptyType" />
+      <xsd:element name="harr" type="docEmptyType" />
+      <xsd:element name="crarr" type="docEmptyType" />
+      <xsd:element name="lArr" type="docEmptyType" />
+      <xsd:element name="uArr" type="docEmptyType" />
+      <xsd:element name="rArr" type="docEmptyType" />
+      <xsd:element name="dArr" type="docEmptyType" />
+      <xsd:element name="hArr" type="docEmptyType" />
+      <xsd:element name="forall" type="docEmptyType" />
+      <xsd:element name="part" type="docEmptyType" />
+      <xsd:element name="exist" type="docEmptyType" />
+      <xsd:element name="empty" type="docEmptyType" />
+      <xsd:element name="nabla" type="docEmptyType" />
+      <xsd:element name="isin" type="docEmptyType" />
+      <xsd:element name="notin" type="docEmptyType" />
+      <xsd:element name="ni" type="docEmptyType" />
+      <xsd:element name="prod" type="docEmptyType" />
+      <xsd:element name="sum" type="docEmptyType" />
+      <xsd:element name="minus" type="docEmptyType" />
+      <xsd:element name="lowast" type="docEmptyType" />
+      <xsd:element name="radic" type="docEmptyType" />
+      <xsd:element name="prop" type="docEmptyType" />
+      <xsd:element name="infin" type="docEmptyType" />
+      <xsd:element name="ang" type="docEmptyType" />
+      <xsd:element name="and" type="docEmptyType" />
+      <xsd:element name="or" type="docEmptyType" />
+      <xsd:element name="cap" type="docEmptyType" />
+      <xsd:element name="cup" type="docEmptyType" />
+      <xsd:element name="int" type="docEmptyType" />
+      <xsd:element name="there4" type="docEmptyType" />
+      <xsd:element name="sim" type="docEmptyType" />
+      <xsd:element name="cong" type="docEmptyType" />
+      <xsd:element name="asymp" type="docEmptyType" />
+      <xsd:element name="ne" type="docEmptyType" />
+      <xsd:element name="equiv" type="docEmptyType" />
+      <xsd:element name="le" type="docEmptyType" />
+      <xsd:element name="ge" type="docEmptyType" />
+      <xsd:element name="sub" type="docEmptyType" />
+      <xsd:element name="sup" type="docEmptyType" />
+      <xsd:element name="nsub" type="docEmptyType" />
+      <xsd:element name="sube" type="docEmptyType" />
+      <xsd:element name="supe" type="docEmptyType" />
+      <xsd:element name="oplus" type="docEmptyType" />
+      <xsd:element name="otimes" type="docEmptyType" />
+      <xsd:element name="perp" type="docEmptyType" />
+      <xsd:element name="sdot" type="docEmptyType" />
+      <xsd:element name="lceil" type="docEmptyType" />
+      <xsd:element name="rceil" type="docEmptyType" />
+      <xsd:element name="lfloor" type="docEmptyType" />
+      <xsd:element name="rfloor" type="docEmptyType" />
+      <xsd:element name="lang" type="docEmptyType" />
+      <xsd:element name="rang" type="docEmptyType" />
+      <xsd:element name="loz" type="docEmptyType" />
+      <xsd:element name="spades" type="docEmptyType" />
+      <xsd:element name="clubs" type="docEmptyType" />
+      <xsd:element name="hearts" type="docEmptyType" />
+      <xsd:element name="diams" type="docEmptyType" />
+      <xsd:element name="OElig" type="docEmptyType" />
+      <xsd:element name="oelig" type="docEmptyType" />
+      <xsd:element name="Scaron" type="docEmptyType" />
+      <xsd:element name="scaron" type="docEmptyType" />
+      <xsd:element name="Yumlaut" type="docEmptyType" />
+      <xsd:element name="circ" type="docEmptyType" />
+      <xsd:element name="tilde" type="docEmptyType" />
+      <xsd:element name="ensp" type="docEmptyType" />
+      <xsd:element name="emsp" type="docEmptyType" />
+      <xsd:element name="thinsp" type="docEmptyType" />
+      <xsd:element name="zwnj" type="docEmptyType" />
+      <xsd:element name="zwj" type="docEmptyType" />
+      <xsd:element name="lrm" type="docEmptyType" />
+      <xsd:element name="rlm" type="docEmptyType" />
+      <xsd:element name="ndash" type="docEmptyType" />
+      <xsd:element name="mdash" type="docEmptyType" />
+      <xsd:element name="lsquo" type="docEmptyType" />
+      <xsd:element name="rsquo" type="docEmptyType" />
+      <xsd:element name="sbquo" type="docEmptyType" />
+      <xsd:element name="ldquo" type="docEmptyType" />
+      <xsd:element name="rdquo" type="docEmptyType" />
+      <xsd:element name="bdquo" type="docEmptyType" />
+      <xsd:element name="dagger" type="docEmptyType" />
+      <xsd:element name="Dagger" type="docEmptyType" />
+      <xsd:element name="permil" type="docEmptyType" />
+      <xsd:element name="lsaquo" type="docEmptyType" />
+      <xsd:element name="rsaquo" type="docEmptyType" />
+      <xsd:element name="euro" type="docEmptyType" />
+      <xsd:element name="trademark" type="docEmptyType" />
+    </xsd:choice>
+  </xsd:group>
+
+  <xsd:complexType name="docTitleType" mixed="true">
+    <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+  </xsd:complexType>
+
+  <xsd:group name="docCmdGroup">
+    <xsd:choice>
+      <xsd:group ref="docTitleCmdGroup"/>
+      <xsd:element name="linebreak" type="docEmptyType" />
+      <xsd:element name="hruler" type="docEmptyType" />
+      <xsd:element name="preformatted" type="docMarkupType" />
+      <xsd:element name="programlisting" type="listingType" />
+      <xsd:element name="verbatim" type="xsd:string" />
+      <xsd:element name="indexentry" type="docIndexEntryType" />
+      <xsd:element name="orderedlist" type="docListType" />
+      <xsd:element name="itemizedlist" type="docListType" />
+      <xsd:element name="simplesect" type="docSimpleSectType" />
+      <xsd:element name="title" type="docTitleType" />
+      <xsd:element name="variablelist" type="docVariableListType" />
+      <xsd:element name="table" type="docTableType" />
+      <xsd:element name="heading" type="docHeadingType" />
+      <xsd:element name="image" type="docImageType" />
+      <xsd:element name="dotfile" type="docFileType" />
+      <xsd:element name="mscfile" type="docFileType" />
+      <xsd:element name="diafile" type="docFileType" />
+      <xsd:element name="toclist" type="docTocListType" />
+      <xsd:element name="language" type="docLanguageType" />
+      <xsd:element name="parameterlist" type="docParamListType" />
+      <xsd:element name="xrefsect" type="docXRefSectType" />
+      <xsd:element name="copydoc" type="docCopyType" />
+      <xsd:element name="blockquote" type="docBlockQuoteType" />
+      <xsd:element name="parblock" type="docParBlockType" />
+    </xsd:choice>
+  </xsd:group>
+
+  <xsd:complexType name="docParaType" mixed="true">
+    <xsd:group ref="docCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docMarkupType" mixed="true">
+    <xsd:group ref="docCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docURLLink" mixed="true">
+    <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+    <xsd:attribute name="url" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docAnchorType" mixed="true">
+    <xsd:attribute name="id" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docFormulaType" mixed="true">
+    <xsd:attribute name="id" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docIndexEntryType">
+    <xsd:sequence>
+      <xsd:element name="primaryie" type="xsd:string" />
+      <xsd:element name="secondaryie" type="xsd:string" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docListType">
+    <xsd:sequence>
+      <xsd:element name="listitem" type="docListItemType" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docListItemType">
+    <xsd:sequence>
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docSimpleSectType">
+    <xsd:sequence>
+      <xsd:element name="title" type="docTitleType" minOccurs="0" />
+      <xsd:sequence minOccurs="0" maxOccurs="unbounded">
+        <xsd:element name="para" type="docParaType" minOccurs="1" maxOccurs="unbounded" />
+      </xsd:sequence>
+    </xsd:sequence>
+    <xsd:attribute name="kind" type="DoxSimpleSectKind" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docVarListEntryType">
+    <xsd:sequence>
+      <xsd:element name="term" type="docTitleType" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:group name="docVariableListGroup">
+    <xsd:sequence>
+      <xsd:element name="varlistentry" type="docVarListEntryType" />
+      <xsd:element name="listitem" type="docListItemType" />
+    </xsd:sequence>
+  </xsd:group>
+
+  <xsd:complexType name="docVariableListType">
+    <xsd:sequence>
+      <xsd:group ref="docVariableListGroup" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docRefTextType" mixed="true">
+    <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+    <xsd:attribute name="refid" type="xsd:string" />
+    <xsd:attribute name="kindref" type="DoxRefKind" />
+    <xsd:attribute name="external" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docTableType">
+    <xsd:sequence>
+      <xsd:element name="row" type="docRowType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="caption" type="docCaptionType" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="rows" type="xsd:integer" />
+    <xsd:attribute name="cols" type="xsd:integer" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docRowType">
+    <xsd:sequence>
+      <xsd:element name="entry" type="docEntryType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docEntryType">
+    <xsd:sequence>
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+    <xsd:attribute name="thead" type="DoxBool" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docCaptionType" mixed="true">
+    <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docHeadingType" mixed="true">
+    <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+    <xsd:attribute name="level" type="xsd:integer" /> <!-- todo: range 1-6 -->
+  </xsd:complexType>
+
+  <xsd:complexType name="docImageType" mixed="true">
+    <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+    <xsd:attribute name="type" type="DoxImageKind" /> 
+    <xsd:attribute name="name" type="xsd:string" /> 
+    <xsd:attribute name="width" type="xsd:string" /> 
+    <xsd:attribute name="height" type="xsd:string" /> 
+  </xsd:complexType>
+
+  <xsd:complexType name="docFileType" mixed="true">
+    <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+    <xsd:attribute name="name" type="xsd:string" /> 
+  </xsd:complexType>
+
+  <xsd:complexType name="docTocItemType" mixed="true">
+    <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+    <xsd:attribute name="id" type="xsd:string" /> 
+  </xsd:complexType>
+
+  <xsd:complexType name="docTocListType">
+    <xsd:sequence>
+      <xsd:element name="tocitem" type="docTocItemType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docLanguageType">
+    <xsd:sequence>
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+    <xsd:attribute name="langid" type="xsd:string" /> 
+  </xsd:complexType>
+
+  <xsd:complexType name="docParamListType">
+    <xsd:sequence>
+      <xsd:element name="parameteritem" type="docParamListItem" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+    <xsd:attribute name="kind" type="DoxParamListKind" /> 
+  </xsd:complexType>
+
+  <xsd:complexType name="docParamListItem">
+    <xsd:sequence>
+      <xsd:element name="parameternamelist" type="docParamNameList" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="parameterdescription" type="descriptionType" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docParamNameList">
+    <xsd:sequence>
+      <xsd:element name="parametertype" type="docParamType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="parametername" type="docParamName" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docParamType" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="ref" type="refTextType" minOccurs="0" maxOccurs="1" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docParamName" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="ref" type="refTextType" minOccurs="0" maxOccurs="1" />
+    </xsd:sequence>
+    <xsd:attribute name="direction" type="DoxParamDir" use="optional" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docXRefSectType">
+    <xsd:sequence>
+      <xsd:element name="xreftitle" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="xrefdescription" type="descriptionType" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:string" /> 
+  </xsd:complexType>
+
+  <xsd:complexType name="docCopyType">
+    <xsd:sequence>
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect1" type="docSect1Type" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="internal" type="docInternalType" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="link" type="xsd:string" /> 
+  </xsd:complexType>
+
+  <xsd:complexType name="docBlockQuoteType">
+    <xsd:sequence>
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docParBlockType">
+    <xsd:sequence>
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docEmptyType"/>
+
+  <!-- Simple types -->
+
+  <xsd:simpleType name="DoxBool">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="yes" />
+      <xsd:enumeration value="no" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxGraphRelation">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="include" />
+      <xsd:enumeration value="usage" />
+      <xsd:enumeration value="template-instance" />
+      <xsd:enumeration value="public-inheritance" />
+      <xsd:enumeration value="protected-inheritance" />
+      <xsd:enumeration value="private-inheritance" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxRefKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="compound" />
+      <xsd:enumeration value="member" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxMemberKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="define" />
+      <xsd:enumeration value="property" />
+      <xsd:enumeration value="event" />
+      <xsd:enumeration value="variable" />
+      <xsd:enumeration value="typedef" />
+      <xsd:enumeration value="enum" />
+      <xsd:enumeration value="function" />
+      <xsd:enumeration value="signal" />
+      <xsd:enumeration value="prototype" />
+      <xsd:enumeration value="friend" />
+      <xsd:enumeration value="dcop" />
+      <xsd:enumeration value="slot" />
+      <xsd:enumeration value="interface" />
+      <xsd:enumeration value="service" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxProtectionKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="public" />
+      <xsd:enumeration value="protected" />
+      <xsd:enumeration value="private" />
+      <xsd:enumeration value="package" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxVirtualKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="non-virtual" />
+      <xsd:enumeration value="virtual" />
+      <xsd:enumeration value="pure-virtual" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxCompoundKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="class" />
+      <xsd:enumeration value="struct" />
+      <xsd:enumeration value="union" />
+      <xsd:enumeration value="interface" />
+      <xsd:enumeration value="protocol" />
+      <xsd:enumeration value="category" />
+      <xsd:enumeration value="exception" />
+      <xsd:enumeration value="service" />
+      <xsd:enumeration value="singleton" />
+      <xsd:enumeration value="module" />
+      <xsd:enumeration value="type" />
+      <xsd:enumeration value="file" />
+      <xsd:enumeration value="namespace" />
+      <xsd:enumeration value="group" />
+      <xsd:enumeration value="page" />
+      <xsd:enumeration value="example" />
+      <xsd:enumeration value="dir" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxSectionKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="user-defined" />
+      <xsd:enumeration value="public-type" />
+      <xsd:enumeration value="public-func" />
+      <xsd:enumeration value="public-attrib" />
+      <xsd:enumeration value="public-slot" />
+      <xsd:enumeration value="signal" />
+      <xsd:enumeration value="dcop-func" />
+      <xsd:enumeration value="property" />
+      <xsd:enumeration value="event" />
+      <xsd:enumeration value="public-static-func" />
+      <xsd:enumeration value="public-static-attrib" />
+      <xsd:enumeration value="protected-type" />
+      <xsd:enumeration value="protected-func" />
+      <xsd:enumeration value="protected-attrib" />
+      <xsd:enumeration value="protected-slot" />
+      <xsd:enumeration value="protected-static-func" />
+      <xsd:enumeration value="protected-static-attrib" />
+      <xsd:enumeration value="package-type" />
+      <xsd:enumeration value="package-func" />
+      <xsd:enumeration value="package-attrib" />
+      <xsd:enumeration value="package-static-func" />
+      <xsd:enumeration value="package-static-attrib" />
+      <xsd:enumeration value="private-type" />
+      <xsd:enumeration value="private-func" />
+      <xsd:enumeration value="private-attrib" />
+      <xsd:enumeration value="private-slot" />
+      <xsd:enumeration value="private-static-func" />
+      <xsd:enumeration value="private-static-attrib" />
+      <xsd:enumeration value="friend" />
+      <xsd:enumeration value="related" />
+      <xsd:enumeration value="define" />
+      <xsd:enumeration value="prototype" />
+      <xsd:enumeration value="typedef" />
+      <xsd:enumeration value="enum" />
+      <xsd:enumeration value="func" />
+      <xsd:enumeration value="var" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxHighlightClass">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="comment" />
+      <xsd:enumeration value="normal" />
+      <xsd:enumeration value="preprocessor" />
+      <xsd:enumeration value="keyword" />
+      <xsd:enumeration value="keywordtype" />
+      <xsd:enumeration value="keywordflow" />
+      <xsd:enumeration value="stringliteral" />
+      <xsd:enumeration value="charliteral" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxSimpleSectKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="see" />
+      <xsd:enumeration value="return" />
+      <xsd:enumeration value="author" />
+      <xsd:enumeration value="authors" />
+      <xsd:enumeration value="version" />
+      <xsd:enumeration value="since" />
+      <xsd:enumeration value="date" />
+      <xsd:enumeration value="note" />
+      <xsd:enumeration value="warning" />
+      <xsd:enumeration value="pre" />
+      <xsd:enumeration value="post" />
+      <xsd:enumeration value="copyright" />
+      <xsd:enumeration value="invariant" />
+      <xsd:enumeration value="remark" />
+      <xsd:enumeration value="attention" />
+      <xsd:enumeration value="par" />
+      <xsd:enumeration value="rcs" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxVersionNumber">
+    <xsd:restriction base="xsd:string">
+      <xsd:pattern value="\d+\.\d+.*" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxImageKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="html" />
+      <xsd:enumeration value="latex" />
+      <xsd:enumeration value="rtf" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxParamListKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="param" />
+      <xsd:enumeration value="retval" />
+      <xsd:enumeration value="exception" />
+      <xsd:enumeration value="templateparam" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxCharRange">
+    <xsd:restriction base="xsd:string">
+      <xsd:pattern value="[aeiouncAEIOUNC]" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxParamDir">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="in"/>
+      <xsd:enumeration value="out"/>
+      <xsd:enumeration value="inout"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxAccessor">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="retain"/>
+      <xsd:enumeration value="copy"/>
+      <xsd:enumeration value="assign"/>
+      <xsd:enumeration value="weak"/>
+      <xsd:enumeration value="strong"/>
+      <xsd:enumeration value="unretained"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+</xsd:schema>
+
diff --git a/contrib/neo_doxygen/tests/empty-project/xml/index.xml b/contrib/neo_doxygen/tests/empty-project/xml/index.xml
new file mode 100644 (file)
index 0000000..cb503f1
--- /dev/null
@@ -0,0 +1,3 @@
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygenindex xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="index.xsd" version="1.8.8">
+</doxygenindex>
diff --git a/contrib/neo_doxygen/tests/empty-project/xml/index.xsd b/contrib/neo_doxygen/tests/empty-project/xml/index.xsd
new file mode 100644 (file)
index 0000000..d7ab2a9
--- /dev/null
@@ -0,0 +1,66 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+  <xsd:element name="doxygenindex" type="DoxygenType"/>
+
+  <xsd:complexType name="DoxygenType">
+    <xsd:sequence>
+      <xsd:element name="compound" type="CompoundType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="version" type="xsd:string" use="required"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="CompoundType">
+    <xsd:sequence>
+      <xsd:element name="name" type="xsd:string"/>
+      <xsd:element name="member" type="MemberType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="refid" type="xsd:string" use="required"/>
+    <xsd:attribute name="kind" type="CompoundKind" use="required"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="MemberType">
+    <xsd:sequence>
+      <xsd:element name="name" type="xsd:string"/>
+    </xsd:sequence>
+    <xsd:attribute name="refid" type="xsd:string" use="required"/>
+    <xsd:attribute name="kind" type="MemberKind" use="required"/>
+  </xsd:complexType>
+  
+  <xsd:simpleType name="CompoundKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="class"/>
+      <xsd:enumeration value="struct"/>
+      <xsd:enumeration value="union"/>
+      <xsd:enumeration value="interface"/>
+      <xsd:enumeration value="protocol"/>
+      <xsd:enumeration value="category"/>
+      <xsd:enumeration value="exception"/>
+      <xsd:enumeration value="file"/>
+      <xsd:enumeration value="namespace"/>
+      <xsd:enumeration value="group"/>
+      <xsd:enumeration value="page"/>
+      <xsd:enumeration value="example"/>
+      <xsd:enumeration value="dir"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="MemberKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="define"/>
+      <xsd:enumeration value="property"/>
+      <xsd:enumeration value="event"/>
+      <xsd:enumeration value="variable"/>
+      <xsd:enumeration value="typedef"/>
+      <xsd:enumeration value="enum"/>
+      <xsd:enumeration value="enumvalue"/>
+      <xsd:enumeration value="function"/>
+      <xsd:enumeration value="signal"/>
+      <xsd:enumeration value="prototype"/>
+      <xsd:enumeration value="friend"/>
+      <xsd:enumeration value="dcop"/>
+      <xsd:enumeration value="slot"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+</xsd:schema>
+
diff --git a/contrib/neo_doxygen/tests/inner-class/Doxyfile b/contrib/neo_doxygen/tests/inner-class/Doxyfile
new file mode 100644 (file)
index 0000000..bd06324
--- /dev/null
@@ -0,0 +1,2381 @@
+# Doxyfile 1.8.8
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "Test Project"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       =
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES                =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = YES
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  = src
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS          = *.c \
+                         *.cc \
+                         *.cxx \
+                         *.cpp \
+                         *.c++ \
+                         *.java \
+                         *.ii \
+                         *.ixx \
+                         *.ipp \
+                         *.i++ \
+                         *.inl \
+                         *.idl \
+                         *.ddl \
+                         *.odl \
+                         *.h \
+                         *.hh \
+                         *.hxx \
+                         *.hpp \
+                         *.h++ \
+                         *.cs \
+                         *.d \
+                         *.php \
+                         *.php4 \
+                         *.php5 \
+                         *.phtml \
+                         *.inc \
+                         *.m \
+                         *.markdown \
+                         *.md \
+                         *.mm \
+                         *.dox \
+                         *.py \
+                         *.f90 \
+                         *.f \
+                         *.for \
+                         *.tcl \
+                         *.vhd \
+                         *.vhdl \
+                         *.ucf \
+                         *.qsf \
+                         *.as \
+                         *.js
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = NO
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra stylesheet files is of importance (e.g. the last
+# stylesheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = YES
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT               = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+PLANTUML_JAR_PATH      =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP            = YES
diff --git a/contrib/neo_doxygen/tests/inner-class/README.md b/contrib/neo_doxygen/tests/inner-class/README.md
new file mode 100644 (file)
index 0000000..2a87fc7
--- /dev/null
@@ -0,0 +1,5 @@
+This directory contains a dummy Java project for testing purposes.
+
+To regenerate the XML output located in `xml`, run `make`. If the `Makefile`
+does not exists, you can regenerate it by running `make bootstrap` in the parent
+directory.
diff --git a/contrib/neo_doxygen/tests/inner-class/src/OuterClass.java b/contrib/neo_doxygen/tests/inner-class/src/OuterClass.java
new file mode 100644 (file)
index 0000000..e324e3e
--- /dev/null
@@ -0,0 +1,24 @@
+/* This file is part of NIT ( http://www.nitlanguage.org ).
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * A class with an inner class.
+ */
+public class OuterClass {
+       /**
+        * An instance (non-static) inner class.
+        */
+       public class InnerClass {}
+}
diff --git a/contrib/neo_doxygen/tests/inner-class/xml/_outer_class_8java.xml b/contrib/neo_doxygen/tests/inner-class/xml/_outer_class_8java.xml
new file mode 100644 (file)
index 0000000..0a63600
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+  <compounddef id="_outer_class_8java" kind="file">
+    <compoundname>OuterClass.java</compoundname>
+    <innerclass refid="class_outer_class" prot="public">OuterClass</innerclass>
+    <innerclass refid="class_outer_class_1_1_inner_class" prot="public">OuterClass::InnerClass</innerclass>
+    <briefdescription>
+    </briefdescription>
+    <detaileddescription>
+    </detaileddescription>
+    <location file="%SOURCE_DIRECTORY%/OuterClass.java"/>
+  </compounddef>
+</doxygen>
diff --git a/contrib/neo_doxygen/tests/inner-class/xml/class_outer_class.xml b/contrib/neo_doxygen/tests/inner-class/xml/class_outer_class.xml
new file mode 100644 (file)
index 0000000..0e516fa
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+  <compounddef id="class_outer_class" kind="class" prot="public">
+    <compoundname>OuterClass</compoundname>
+    <innerclass refid="class_outer_class_1_1_inner_class" prot="public">OuterClass::InnerClass</innerclass>
+    <briefdescription>
+    </briefdescription>
+    <detaileddescription>
+<para>A class with an inner class. </para>    </detaileddescription>
+    <location file="%SOURCE_DIRECTORY%/OuterClass.java" line="19" column="1" bodyfile="%SOURCE_DIRECTORY%/OuterClass.java" bodystart="19" bodyend="24"/>
+    <listofallmembers>
+    </listofallmembers>
+  </compounddef>
+</doxygen>
diff --git a/contrib/neo_doxygen/tests/inner-class/xml/class_outer_class_1_1_inner_class.xml b/contrib/neo_doxygen/tests/inner-class/xml/class_outer_class_1_1_inner_class.xml
new file mode 100644 (file)
index 0000000..fdabf85
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+  <compounddef id="class_outer_class_1_1_inner_class" kind="class" prot="public">
+    <compoundname>OuterClass::InnerClass</compoundname>
+    <briefdescription>
+    </briefdescription>
+    <detaileddescription>
+<para>An instance (non-static) inner class. </para>    </detaileddescription>
+    <location file="%SOURCE_DIRECTORY%/OuterClass.java" line="23" column="1" bodyfile="%SOURCE_DIRECTORY%/OuterClass.java" bodystart="23" bodyend="23"/>
+    <listofallmembers>
+    </listofallmembers>
+  </compounddef>
+</doxygen>
diff --git a/contrib/neo_doxygen/tests/inner-class/xml/combine.xslt b/contrib/neo_doxygen/tests/inner-class/xml/combine.xslt
new file mode 100644 (file)
index 0000000..c148ee4
--- /dev/null
@@ -0,0 +1,15 @@
+<!-- XSLT script to combine the generated output into a single file. 
+     If you have xsltproc you could use:
+     xsltproc combine.xslt index.xml >all.xml
+-->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+  <xsl:output method="xml" version="1.0" indent="no" standalone="yes" />
+  <xsl:template match="/">
+    <doxygen version="{doxygenindex/@version}">
+      <!-- Load all doxgen generated xml files -->
+      <xsl:for-each select="doxygenindex/compound">
+        <xsl:copy-of select="document( concat( @refid, '.xml' ) )/doxygen/*" />
+      </xsl:for-each>
+    </doxygen>
+  </xsl:template>
+</xsl:stylesheet>
diff --git a/contrib/neo_doxygen/tests/inner-class/xml/compound.xsd b/contrib/neo_doxygen/tests/inner-class/xml/compound.xsd
new file mode 100644 (file)
index 0000000..86740f4
--- /dev/null
@@ -0,0 +1,1092 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+  <xsd:element name="doxygen" type="DoxygenType"/>
+
+  <!-- Complex types -->
+
+  <xsd:complexType name="DoxygenType">
+    <xsd:sequence maxOccurs="unbounded">
+      <xsd:element name="compounddef" type="compounddefType" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="version" type="DoxVersionNumber" use="required" />
+  </xsd:complexType>
+
+  <xsd:complexType name="compounddefType">
+    <xsd:sequence>
+      <xsd:element name="compoundname" type="xsd:string"/>
+      <xsd:element name="title" type="xsd:string" minOccurs="0" />
+      <xsd:element name="basecompoundref" type="compoundRefType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="derivedcompoundref" type="compoundRefType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="includes" type="incType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="includedby" type="incType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="incdepgraph" type="graphType" minOccurs="0" />
+      <xsd:element name="invincdepgraph" type="graphType" minOccurs="0" />
+      <xsd:element name="innerdir" type="refType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="innerfile" type="refType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="innerclass" type="refType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="innernamespace" type="refType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="innerpage" type="refType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="innergroup" type="refType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="templateparamlist" type="templateparamlistType" minOccurs="0" />
+      <xsd:element name="sectiondef" type="sectiondefType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" />
+      <xsd:element name="detaileddescription" type="descriptionType" minOccurs="0" />
+      <xsd:element name="inheritancegraph" type="graphType" minOccurs="0" />
+      <xsd:element name="collaborationgraph" type="graphType" minOccurs="0" />
+      <xsd:element name="programlisting" type="listingType" minOccurs="0" />
+      <xsd:element name="location" type="locationType" minOccurs="0" />
+      <xsd:element name="listofallmembers" type="listofallmembersType" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:string" />
+    <xsd:attribute name="kind" type="DoxCompoundKind" />
+    <xsd:attribute name="prot" type="DoxProtectionKind" />
+    <xsd:attribute name="final" type="DoxBool" use="optional"/>
+    <xsd:attribute name="sealed" type="DoxBool" use="optional"/>
+    <xsd:attribute name="abstract" type="DoxBool" use="optional"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="listofallmembersType">
+    <xsd:sequence>
+      <xsd:element name="member" type="memberRefType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="memberRefType">
+    <xsd:sequence>
+      <xsd:element name="scope" />
+      <xsd:element name="name" />
+    </xsd:sequence>
+    <xsd:attribute name="refid" type="xsd:string" />
+    <xsd:attribute name="prot" type="DoxProtectionKind" />
+    <xsd:attribute name="virt" type="DoxVirtualKind" />
+    <xsd:attribute name="ambiguityscope" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="compoundRefType">
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:string">
+        <xsd:attribute name="refid" type="xsd:string" use="optional" />
+        <xsd:attribute name="prot" type="DoxProtectionKind" />
+        <xsd:attribute name="virt" type="DoxVirtualKind" />
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+  <xsd:complexType name="reimplementType">
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:string">
+        <xsd:attribute name="refid" type="xsd:string" />
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+  <xsd:complexType name="incType">
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:string">
+        <xsd:attribute name="refid" type="xsd:string" />
+        <xsd:attribute name="local" type="DoxBool" />
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+  <xsd:complexType name="refType">
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:string">
+        <xsd:attribute name="refid" type="xsd:string" />
+        <xsd:attribute name="prot" type="DoxProtectionKind" use="optional"/>
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+  <xsd:complexType name="refTextType">
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:string">
+       <xsd:attribute name="refid" type="xsd:string" />
+       <xsd:attribute name="kindref" type="DoxRefKind" />
+       <xsd:attribute name="external" type="xsd:string" use="optional"/>
+       <xsd:attribute name="tooltip" type="xsd:string" use="optional"/>
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+  <xsd:complexType name="sectiondefType">
+    <xsd:sequence>
+      <xsd:element name="header" type="xsd:string" minOccurs="0" />
+      <xsd:element name="description" type="descriptionType" minOccurs="0" />
+      <xsd:element name="memberdef" type="memberdefType" maxOccurs="unbounded" />
+    </xsd:sequence>
+    <xsd:attribute name="kind" type="DoxSectionKind" />
+  </xsd:complexType>
+
+  <xsd:complexType name="memberdefType">
+    <xsd:sequence>
+      <xsd:element name="templateparamlist" type="templateparamlistType" minOccurs="0" />
+      <xsd:element name="type" type="linkedTextType" minOccurs="0" />
+      <xsd:element name="definition" minOccurs="0" />
+      <xsd:element name="argsstring" minOccurs="0" />
+      <xsd:element name="name" />
+      <xsd:element name="read" minOccurs="0" />
+      <xsd:element name="write" minOccurs="0" />
+      <xsd:element name="bitfield" minOccurs="0" />
+      <xsd:element name="reimplements" type="reimplementType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="reimplementedby" type="reimplementType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="param" type="paramType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="enumvalue" type="enumvalueType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="initializer" type="linkedTextType" minOccurs="0" />
+      <xsd:element name="exceptions" type="linkedTextType" minOccurs="0" />
+      <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" />
+      <xsd:element name="detaileddescription" type="descriptionType" minOccurs="0" />
+      <xsd:element name="inbodydescription" type="descriptionType" minOccurs="0" />
+      <xsd:element name="location" type="locationType" />
+      <xsd:element name="references" type="referenceType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="referencedby" type="referenceType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+    <xsd:attribute name="kind" type="DoxMemberKind" />
+    <xsd:attribute name="id" type="xsd:string" />
+    <xsd:attribute name="prot" type="DoxProtectionKind" />
+    <xsd:attribute name="static" type="DoxBool" />
+    <xsd:attribute name="const" type="DoxBool" use="optional"/>
+    <xsd:attribute name="explicit" type="DoxBool" use="optional"/>
+    <xsd:attribute name="inline" type="DoxBool" use="optional"/>
+    <xsd:attribute name="virt" type="DoxVirtualKind" use="optional"/>
+    <xsd:attribute name="volatile" type="DoxBool" use="optional"/>
+    <xsd:attribute name="mutable" type="DoxBool" use="optional"/>
+    <!-- Qt property -->
+    <xsd:attribute name="readable" type="DoxBool" use="optional"/>
+    <xsd:attribute name="writable" type="DoxBool" use="optional"/>
+    <!-- C++/CLI variable -->
+    <xsd:attribute name="initonly" type="DoxBool" use="optional"/>
+    <!-- C++/CLI and C# property -->
+    <xsd:attribute name="settable" type="DoxBool" use="optional"/>
+    <xsd:attribute name="gettable" type="DoxBool" use="optional"/>
+    <!-- C++/CLI function -->
+    <xsd:attribute name="final" type="DoxBool" use="optional"/>
+    <xsd:attribute name="sealed" type="DoxBool" use="optional"/>
+    <xsd:attribute name="new" type="DoxBool" use="optional"/>
+    <!-- C++/CLI event -->
+    <xsd:attribute name="add" type="DoxBool" use="optional"/>
+    <xsd:attribute name="remove" type="DoxBool" use="optional"/>
+    <xsd:attribute name="raise" type="DoxBool" use="optional"/>
+    <!-- Objective-C 2.0 protocol method -->
+    <xsd:attribute name="optional" type="DoxBool" use="optional"/>
+    <xsd:attribute name="required" type="DoxBool" use="optional"/>
+    <!-- Objective-C 2.0 property accessor -->
+    <xsd:attribute name="accessor" type="DoxAccessor" use="optional"/>
+    <!-- UNO IDL -->
+    <xsd:attribute name="attribute" type="DoxBool" use="optional"/>
+    <xsd:attribute name="property" type="DoxBool" use="optional"/>
+    <xsd:attribute name="readonly" type="DoxBool" use="optional"/>
+    <xsd:attribute name="bound" type="DoxBool" use="optional"/>
+    <xsd:attribute name="removable" type="DoxBool" use="optional"/>
+    <xsd:attribute name="contrained" type="DoxBool" use="optional"/>
+    <xsd:attribute name="transient" type="DoxBool" use="optional"/>
+    <xsd:attribute name="maybevoid" type="DoxBool" use="optional"/>
+    <xsd:attribute name="maybedefault" type="DoxBool" use="optional"/>
+    <xsd:attribute name="maybeambiguous" type="DoxBool" use="optional"/>
+
+  </xsd:complexType>
+
+  <xsd:complexType name="descriptionType" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="title" type="xsd:string" minOccurs="0"/>          
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect1" type="docSect1Type" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="internal" type="docInternalType" minOccurs="0" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="enumvalueType" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="name" />
+      <xsd:element name="initializer" type="linkedTextType" minOccurs="0" />
+      <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" />
+      <xsd:element name="detaileddescription" type="descriptionType" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:string" />
+    <xsd:attribute name="prot" type="DoxProtectionKind" />
+  </xsd:complexType>
+
+  <xsd:complexType name="templateparamlistType">
+    <xsd:sequence>
+      <xsd:element name="param" type="paramType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="paramType">
+    <xsd:sequence>
+      <xsd:element name="type" type="linkedTextType" minOccurs="0" />
+      <xsd:element name="declname" minOccurs="0" />
+      <xsd:element name="defname" minOccurs="0" />
+      <xsd:element name="array" minOccurs="0" />
+      <xsd:element name="defval" type="linkedTextType" minOccurs="0" />
+      <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="linkedTextType" mixed="true">
+    <xsd:sequence>
+    <xsd:element name="ref" type="refTextType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="graphType">
+    <xsd:sequence>
+      <xsd:element name="node" type="nodeType" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="nodeType">
+    <xsd:sequence>
+      <xsd:element name="label" />
+      <xsd:element name="link" type="linkType" minOccurs="0" />
+      <xsd:element name="childnode" type="childnodeType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="childnodeType">
+    <xsd:sequence>
+      <xsd:element name="edgelabel" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="refid" type="xsd:string" />
+    <xsd:attribute name="relation" type="DoxGraphRelation" />
+  </xsd:complexType>
+
+  <xsd:complexType name="linkType">
+    <xsd:attribute name="refid" type="xsd:string" />
+    <xsd:attribute name="external" type="xsd:string" use="optional"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="listingType">
+    <xsd:sequence>
+      <xsd:element name="codeline" type="codelineType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="codelineType">
+    <xsd:sequence>
+      <xsd:element name="highlight" type="highlightType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+    <xsd:attribute name="lineno" type="xsd:integer" />
+    <xsd:attribute name="refid" type="xsd:string" />
+    <xsd:attribute name="refkind" type="DoxRefKind" />
+    <xsd:attribute name="external" type="DoxBool" />
+  </xsd:complexType>
+
+  <xsd:complexType name="highlightType" mixed="true">
+    <xsd:choice minOccurs="0" maxOccurs="unbounded">
+      <xsd:element name="sp" />
+      <xsd:element name="ref" type="refTextType" />
+    </xsd:choice>
+    <xsd:attribute name="class" type="DoxHighlightClass" />
+  </xsd:complexType>
+
+  <xsd:complexType name="referenceType" mixed="true">
+    <xsd:attribute name="refid" type="xsd:string" />
+    <xsd:attribute name="compoundref" type="xsd:string" use="optional" />
+    <xsd:attribute name="startline" type="xsd:integer" />
+    <xsd:attribute name="endline" type="xsd:integer" />
+  </xsd:complexType>
+
+  <xsd:complexType name="locationType">
+    <xsd:attribute name="file" type="xsd:string" />
+    <xsd:attribute name="line" type="xsd:integer" />
+    <xsd:attribute name="column" type="xsd:integer" use="optional"/>
+    <xsd:attribute name="bodyfile" type="xsd:string" />
+    <xsd:attribute name="bodystart" type="xsd:integer" />
+    <xsd:attribute name="bodyend" type="xsd:integer" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docSect1Type" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="title" type="xsd:string" />       
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect2" type="docSect2Type" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="internal" type="docInternalS1Type" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docSect2Type" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="title" type="xsd:string" />       
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect3" type="docSect3Type" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="internal" type="docInternalS2Type" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docSect3Type" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="title" type="xsd:string" />       
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect4" type="docSect4Type" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="internal" type="docInternalS3Type" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docSect4Type" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="title" type="xsd:string" />       
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="internal" type="docInternalS4Type" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docInternalType" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="para"  type="docParaType"  minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect1" type="docSect1Type" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docInternalS1Type" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="para"  type="docParaType"  minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect2" type="docSect2Type" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docInternalS2Type" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="para"  type="docParaType"  minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect3" type="docSect3Type" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docInternalS3Type" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="para"  type="docParaType"  minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect3" type="docSect4Type" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docInternalS4Type" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="para"  type="docParaType"  minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+  <xsd:group name="docTitleCmdGroup">
+    <xsd:choice>
+      <xsd:element name="ulink" type="docURLLink" />
+      <xsd:element name="bold" type="docMarkupType" />
+      <xsd:element name="emphasis" type="docMarkupType" />
+      <xsd:element name="computeroutput" type="docMarkupType" />
+      <xsd:element name="subscript" type="docMarkupType" />
+      <xsd:element name="superscript" type="docMarkupType" />
+      <xsd:element name="center" type="docMarkupType" />
+      <xsd:element name="small" type="docMarkupType" />
+      <xsd:element name="htmlonly" type="xsd:string" />
+      <xsd:element name="manonly" type="xsd:string" />
+      <xsd:element name="xmlonly" type="xsd:string" />
+      <xsd:element name="rtfonly" type="xsd:string" />
+      <xsd:element name="latexonly" type="xsd:string" />
+      <xsd:element name="dot" type="xsd:string" />
+      <xsd:element name="plantuml" type="xsd:string" />
+      <xsd:element name="anchor" type="docAnchorType" />
+      <xsd:element name="formula" type="docFormulaType" />
+      <xsd:element name="ref" type="docRefTextType" />
+      <xsd:element name="nonbreakablespace" type="docEmptyType" />
+      <xsd:element name="iexcl" type="docEmptyType" />
+      <xsd:element name="cent" type="docEmptyType" />
+      <xsd:element name="pound" type="docEmptyType" />
+      <xsd:element name="curren" type="docEmptyType" />
+      <xsd:element name="yen" type="docEmptyType" />
+      <xsd:element name="brvbar" type="docEmptyType" />
+      <xsd:element name="sect" type="docEmptyType" />
+      <xsd:element name="umlaut" type="docEmptyType" />
+      <xsd:element name="copy" type="docEmptyType" />
+      <xsd:element name="ordf" type="docEmptyType" />
+      <xsd:element name="laquo" type="docEmptyType" />
+      <xsd:element name="not" type="docEmptyType" />
+      <xsd:element name="shy" type="docEmptyType" />
+      <xsd:element name="registered" type="docEmptyType" />
+      <xsd:element name="macr" type="docEmptyType" />
+      <xsd:element name="deg" type="docEmptyType" />
+      <xsd:element name="plusmn" type="docEmptyType" />
+      <xsd:element name="sup2" type="docEmptyType" />
+      <xsd:element name="sup3" type="docEmptyType" />
+      <xsd:element name="acute" type="docEmptyType" />
+      <xsd:element name="micro" type="docEmptyType" />
+      <xsd:element name="para" type="docEmptyType" />
+      <xsd:element name="middot" type="docEmptyType" />
+      <xsd:element name="cedil" type="docEmptyType" />
+      <xsd:element name="sup1" type="docEmptyType" />
+      <xsd:element name="ordm" type="docEmptyType" />
+      <xsd:element name="raquo" type="docEmptyType" />
+      <xsd:element name="frac14" type="docEmptyType" />
+      <xsd:element name="frac12" type="docEmptyType" />
+      <xsd:element name="frac34" type="docEmptyType" />
+      <xsd:element name="iquest" type="docEmptyType" />
+      <xsd:element name="Agrave" type="docEmptyType" />
+      <xsd:element name="Aacute" type="docEmptyType" />
+      <xsd:element name="Acirc" type="docEmptyType" />
+      <xsd:element name="Atilde" type="docEmptyType" />
+      <xsd:element name="Aumlaut" type="docEmptyType" />
+      <xsd:element name="Aring" type="docEmptyType" />
+      <xsd:element name="AElig" type="docEmptyType" />
+      <xsd:element name="Ccedil" type="docEmptyType" />
+      <xsd:element name="Egrave" type="docEmptyType" />
+      <xsd:element name="Eacute" type="docEmptyType" />
+      <xsd:element name="Ecirc" type="docEmptyType" />
+      <xsd:element name="Eumlaut" type="docEmptyType" />
+      <xsd:element name="Igrave" type="docEmptyType" />
+      <xsd:element name="Iacute" type="docEmptyType" />
+      <xsd:element name="Icirc" type="docEmptyType" />
+      <xsd:element name="Iumlaut" type="docEmptyType" />
+      <xsd:element name="ETH" type="docEmptyType" />
+      <xsd:element name="Ntilde" type="docEmptyType" />
+      <xsd:element name="Ograve" type="docEmptyType" />
+      <xsd:element name="Oacute" type="docEmptyType" />
+      <xsd:element name="Ocirc" type="docEmptyType" />
+      <xsd:element name="Otilde" type="docEmptyType" />
+      <xsd:element name="Oumlaut" type="docEmptyType" />
+      <xsd:element name="times" type="docEmptyType" />
+      <xsd:element name="Oslash" type="docEmptyType" />
+      <xsd:element name="Ugrave" type="docEmptyType" />
+      <xsd:element name="Uacute" type="docEmptyType" />
+      <xsd:element name="Ucirc" type="docEmptyType" />
+      <xsd:element name="Uumlaut" type="docEmptyType" />
+      <xsd:element name="Yacute" type="docEmptyType" />
+      <xsd:element name="THORN" type="docEmptyType" />
+      <xsd:element name="szlig" type="docEmptyType" />
+      <xsd:element name="agrave" type="docEmptyType" />
+      <xsd:element name="aacute" type="docEmptyType" />
+      <xsd:element name="acirc" type="docEmptyType" />
+      <xsd:element name="atilde" type="docEmptyType" />
+      <xsd:element name="aumlaut" type="docEmptyType" />
+      <xsd:element name="aring" type="docEmptyType" />
+      <xsd:element name="aelig" type="docEmptyType" />
+      <xsd:element name="ccedil" type="docEmptyType" />
+      <xsd:element name="egrave" type="docEmptyType" />
+      <xsd:element name="eacute" type="docEmptyType" />
+      <xsd:element name="ecirc" type="docEmptyType" />
+      <xsd:element name="eumlaut" type="docEmptyType" />
+      <xsd:element name="igrave" type="docEmptyType" />
+      <xsd:element name="iacute" type="docEmptyType" />
+      <xsd:element name="icirc" type="docEmptyType" />
+      <xsd:element name="iumlaut" type="docEmptyType" />
+      <xsd:element name="eth" type="docEmptyType" />
+      <xsd:element name="ntilde" type="docEmptyType" />
+      <xsd:element name="ograve" type="docEmptyType" />
+      <xsd:element name="oacute" type="docEmptyType" />
+      <xsd:element name="ocirc" type="docEmptyType" />
+      <xsd:element name="otilde" type="docEmptyType" />
+      <xsd:element name="oumlaut" type="docEmptyType" />
+      <xsd:element name="divide" type="docEmptyType" />
+      <xsd:element name="oslash" type="docEmptyType" />
+      <xsd:element name="ugrave" type="docEmptyType" />
+      <xsd:element name="uacute" type="docEmptyType" />
+      <xsd:element name="ucirc" type="docEmptyType" />
+      <xsd:element name="uumlaut" type="docEmptyType" />
+      <xsd:element name="yacute" type="docEmptyType" />
+      <xsd:element name="thorn" type="docEmptyType" />
+      <xsd:element name="yumlaut" type="docEmptyType" />
+      <xsd:element name="fnof" type="docEmptyType" />
+      <xsd:element name="Alpha" type="docEmptyType" />
+      <xsd:element name="Beta" type="docEmptyType" />
+      <xsd:element name="Gamma" type="docEmptyType" />
+      <xsd:element name="Delta" type="docEmptyType" />
+      <xsd:element name="Epsilon" type="docEmptyType" />
+      <xsd:element name="Zeta" type="docEmptyType" />
+      <xsd:element name="Eta" type="docEmptyType" />
+      <xsd:element name="Theta" type="docEmptyType" />
+      <xsd:element name="Iota" type="docEmptyType" />
+      <xsd:element name="Kappa" type="docEmptyType" />
+      <xsd:element name="Lambda" type="docEmptyType" />
+      <xsd:element name="Mu" type="docEmptyType" />
+      <xsd:element name="Nu" type="docEmptyType" />
+      <xsd:element name="Xi" type="docEmptyType" />
+      <xsd:element name="Omicron" type="docEmptyType" />
+      <xsd:element name="Pi" type="docEmptyType" />
+      <xsd:element name="Rho" type="docEmptyType" />
+      <xsd:element name="Sigma" type="docEmptyType" />
+      <xsd:element name="Tau" type="docEmptyType" />
+      <xsd:element name="Upsilon" type="docEmptyType" />
+      <xsd:element name="Phi" type="docEmptyType" />
+      <xsd:element name="Chi" type="docEmptyType" />
+      <xsd:element name="Psi" type="docEmptyType" />
+      <xsd:element name="Omega" type="docEmptyType" />
+      <xsd:element name="alpha" type="docEmptyType" />
+      <xsd:element name="beta" type="docEmptyType" />
+      <xsd:element name="gamma" type="docEmptyType" />
+      <xsd:element name="delta" type="docEmptyType" />
+      <xsd:element name="epsilon" type="docEmptyType" />
+      <xsd:element name="zeta" type="docEmptyType" />
+      <xsd:element name="eta" type="docEmptyType" />
+      <xsd:element name="theta" type="docEmptyType" />
+      <xsd:element name="iota" type="docEmptyType" />
+      <xsd:element name="kappa" type="docEmptyType" />
+      <xsd:element name="lambda" type="docEmptyType" />
+      <xsd:element name="mu" type="docEmptyType" />
+      <xsd:element name="nu" type="docEmptyType" />
+      <xsd:element name="xi" type="docEmptyType" />
+      <xsd:element name="omicron" type="docEmptyType" />
+      <xsd:element name="pi" type="docEmptyType" />
+      <xsd:element name="rho" type="docEmptyType" />
+      <xsd:element name="sigmaf" type="docEmptyType" />
+      <xsd:element name="sigma" type="docEmptyType" />
+      <xsd:element name="tau" type="docEmptyType" />
+      <xsd:element name="upsilon" type="docEmptyType" />
+      <xsd:element name="phi" type="docEmptyType" />
+      <xsd:element name="chi" type="docEmptyType" />
+      <xsd:element name="psi" type="docEmptyType" />
+      <xsd:element name="omega" type="docEmptyType" />
+      <xsd:element name="thetasym" type="docEmptyType" />
+      <xsd:element name="upsih" type="docEmptyType" />
+      <xsd:element name="piv" type="docEmptyType" />
+      <xsd:element name="bull" type="docEmptyType" />
+      <xsd:element name="hellip" type="docEmptyType" />
+      <xsd:element name="prime" type="docEmptyType" />
+      <xsd:element name="Prime" type="docEmptyType" />
+      <xsd:element name="oline" type="docEmptyType" />
+      <xsd:element name="frasl" type="docEmptyType" />
+      <xsd:element name="weierp" type="docEmptyType" />
+      <xsd:element name="image" type="docEmptyType" />
+      <xsd:element name="real" type="docEmptyType" />
+      <xsd:element name="trademark" type="docEmptyType" />
+      <xsd:element name="alefsym" type="docEmptyType" />
+      <xsd:element name="larr" type="docEmptyType" />
+      <xsd:element name="uarr" type="docEmptyType" />
+      <xsd:element name="rarr" type="docEmptyType" />
+      <xsd:element name="darr" type="docEmptyType" />
+      <xsd:element name="harr" type="docEmptyType" />
+      <xsd:element name="crarr" type="docEmptyType" />
+      <xsd:element name="lArr" type="docEmptyType" />
+      <xsd:element name="uArr" type="docEmptyType" />
+      <xsd:element name="rArr" type="docEmptyType" />
+      <xsd:element name="dArr" type="docEmptyType" />
+      <xsd:element name="hArr" type="docEmptyType" />
+      <xsd:element name="forall" type="docEmptyType" />
+      <xsd:element name="part" type="docEmptyType" />
+      <xsd:element name="exist" type="docEmptyType" />
+      <xsd:element name="empty" type="docEmptyType" />
+      <xsd:element name="nabla" type="docEmptyType" />
+      <xsd:element name="isin" type="docEmptyType" />
+      <xsd:element name="notin" type="docEmptyType" />
+      <xsd:element name="ni" type="docEmptyType" />
+      <xsd:element name="prod" type="docEmptyType" />
+      <xsd:element name="sum" type="docEmptyType" />
+      <xsd:element name="minus" type="docEmptyType" />
+      <xsd:element name="lowast" type="docEmptyType" />
+      <xsd:element name="radic" type="docEmptyType" />
+      <xsd:element name="prop" type="docEmptyType" />
+      <xsd:element name="infin" type="docEmptyType" />
+      <xsd:element name="ang" type="docEmptyType" />
+      <xsd:element name="and" type="docEmptyType" />
+      <xsd:element name="or" type="docEmptyType" />
+      <xsd:element name="cap" type="docEmptyType" />
+      <xsd:element name="cup" type="docEmptyType" />
+      <xsd:element name="int" type="docEmptyType" />
+      <xsd:element name="there4" type="docEmptyType" />
+      <xsd:element name="sim" type="docEmptyType" />
+      <xsd:element name="cong" type="docEmptyType" />
+      <xsd:element name="asymp" type="docEmptyType" />
+      <xsd:element name="ne" type="docEmptyType" />
+      <xsd:element name="equiv" type="docEmptyType" />
+      <xsd:element name="le" type="docEmptyType" />
+      <xsd:element name="ge" type="docEmptyType" />
+      <xsd:element name="sub" type="docEmptyType" />
+      <xsd:element name="sup" type="docEmptyType" />
+      <xsd:element name="nsub" type="docEmptyType" />
+      <xsd:element name="sube" type="docEmptyType" />
+      <xsd:element name="supe" type="docEmptyType" />
+      <xsd:element name="oplus" type="docEmptyType" />
+      <xsd:element name="otimes" type="docEmptyType" />
+      <xsd:element name="perp" type="docEmptyType" />
+      <xsd:element name="sdot" type="docEmptyType" />
+      <xsd:element name="lceil" type="docEmptyType" />
+      <xsd:element name="rceil" type="docEmptyType" />
+      <xsd:element name="lfloor" type="docEmptyType" />
+      <xsd:element name="rfloor" type="docEmptyType" />
+      <xsd:element name="lang" type="docEmptyType" />
+      <xsd:element name="rang" type="docEmptyType" />
+      <xsd:element name="loz" type="docEmptyType" />
+      <xsd:element name="spades" type="docEmptyType" />
+      <xsd:element name="clubs" type="docEmptyType" />
+      <xsd:element name="hearts" type="docEmptyType" />
+      <xsd:element name="diams" type="docEmptyType" />
+      <xsd:element name="OElig" type="docEmptyType" />
+      <xsd:element name="oelig" type="docEmptyType" />
+      <xsd:element name="Scaron" type="docEmptyType" />
+      <xsd:element name="scaron" type="docEmptyType" />
+      <xsd:element name="Yumlaut" type="docEmptyType" />
+      <xsd:element name="circ" type="docEmptyType" />
+      <xsd:element name="tilde" type="docEmptyType" />
+      <xsd:element name="ensp" type="docEmptyType" />
+      <xsd:element name="emsp" type="docEmptyType" />
+      <xsd:element name="thinsp" type="docEmptyType" />
+      <xsd:element name="zwnj" type="docEmptyType" />
+      <xsd:element name="zwj" type="docEmptyType" />
+      <xsd:element name="lrm" type="docEmptyType" />
+      <xsd:element name="rlm" type="docEmptyType" />
+      <xsd:element name="ndash" type="docEmptyType" />
+      <xsd:element name="mdash" type="docEmptyType" />
+      <xsd:element name="lsquo" type="docEmptyType" />
+      <xsd:element name="rsquo" type="docEmptyType" />
+      <xsd:element name="sbquo" type="docEmptyType" />
+      <xsd:element name="ldquo" type="docEmptyType" />
+      <xsd:element name="rdquo" type="docEmptyType" />
+      <xsd:element name="bdquo" type="docEmptyType" />
+      <xsd:element name="dagger" type="docEmptyType" />
+      <xsd:element name="Dagger" type="docEmptyType" />
+      <xsd:element name="permil" type="docEmptyType" />
+      <xsd:element name="lsaquo" type="docEmptyType" />
+      <xsd:element name="rsaquo" type="docEmptyType" />
+      <xsd:element name="euro" type="docEmptyType" />
+      <xsd:element name="trademark" type="docEmptyType" />
+    </xsd:choice>
+  </xsd:group>
+
+  <xsd:complexType name="docTitleType" mixed="true">
+    <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+  </xsd:complexType>
+
+  <xsd:group name="docCmdGroup">
+    <xsd:choice>
+      <xsd:group ref="docTitleCmdGroup"/>
+      <xsd:element name="linebreak" type="docEmptyType" />
+      <xsd:element name="hruler" type="docEmptyType" />
+      <xsd:element name="preformatted" type="docMarkupType" />
+      <xsd:element name="programlisting" type="listingType" />
+      <xsd:element name="verbatim" type="xsd:string" />
+      <xsd:element name="indexentry" type="docIndexEntryType" />
+      <xsd:element name="orderedlist" type="docListType" />
+      <xsd:element name="itemizedlist" type="docListType" />
+      <xsd:element name="simplesect" type="docSimpleSectType" />
+      <xsd:element name="title" type="docTitleType" />
+      <xsd:element name="variablelist" type="docVariableListType" />
+      <xsd:element name="table" type="docTableType" />
+      <xsd:element name="heading" type="docHeadingType" />
+      <xsd:element name="image" type="docImageType" />
+      <xsd:element name="dotfile" type="docFileType" />
+      <xsd:element name="mscfile" type="docFileType" />
+      <xsd:element name="diafile" type="docFileType" />
+      <xsd:element name="toclist" type="docTocListType" />
+      <xsd:element name="language" type="docLanguageType" />
+      <xsd:element name="parameterlist" type="docParamListType" />
+      <xsd:element name="xrefsect" type="docXRefSectType" />
+      <xsd:element name="copydoc" type="docCopyType" />
+      <xsd:element name="blockquote" type="docBlockQuoteType" />
+      <xsd:element name="parblock" type="docParBlockType" />
+    </xsd:choice>
+  </xsd:group>
+
+  <xsd:complexType name="docParaType" mixed="true">
+    <xsd:group ref="docCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docMarkupType" mixed="true">
+    <xsd:group ref="docCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docURLLink" mixed="true">
+    <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+    <xsd:attribute name="url" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docAnchorType" mixed="true">
+    <xsd:attribute name="id" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docFormulaType" mixed="true">
+    <xsd:attribute name="id" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docIndexEntryType">
+    <xsd:sequence>
+      <xsd:element name="primaryie" type="xsd:string" />
+      <xsd:element name="secondaryie" type="xsd:string" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docListType">
+    <xsd:sequence>
+      <xsd:element name="listitem" type="docListItemType" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docListItemType">
+    <xsd:sequence>
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docSimpleSectType">
+    <xsd:sequence>
+      <xsd:element name="title" type="docTitleType" minOccurs="0" />
+      <xsd:sequence minOccurs="0" maxOccurs="unbounded">
+        <xsd:element name="para" type="docParaType" minOccurs="1" maxOccurs="unbounded" />
+      </xsd:sequence>
+    </xsd:sequence>
+    <xsd:attribute name="kind" type="DoxSimpleSectKind" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docVarListEntryType">
+    <xsd:sequence>
+      <xsd:element name="term" type="docTitleType" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:group name="docVariableListGroup">
+    <xsd:sequence>
+      <xsd:element name="varlistentry" type="docVarListEntryType" />
+      <xsd:element name="listitem" type="docListItemType" />
+    </xsd:sequence>
+  </xsd:group>
+
+  <xsd:complexType name="docVariableListType">
+    <xsd:sequence>
+      <xsd:group ref="docVariableListGroup" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docRefTextType" mixed="true">
+    <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+    <xsd:attribute name="refid" type="xsd:string" />
+    <xsd:attribute name="kindref" type="DoxRefKind" />
+    <xsd:attribute name="external" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docTableType">
+    <xsd:sequence>
+      <xsd:element name="row" type="docRowType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="caption" type="docCaptionType" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="rows" type="xsd:integer" />
+    <xsd:attribute name="cols" type="xsd:integer" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docRowType">
+    <xsd:sequence>
+      <xsd:element name="entry" type="docEntryType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docEntryType">
+    <xsd:sequence>
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+    <xsd:attribute name="thead" type="DoxBool" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docCaptionType" mixed="true">
+    <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docHeadingType" mixed="true">
+    <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+    <xsd:attribute name="level" type="xsd:integer" /> <!-- todo: range 1-6 -->
+  </xsd:complexType>
+
+  <xsd:complexType name="docImageType" mixed="true">
+    <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+    <xsd:attribute name="type" type="DoxImageKind" /> 
+    <xsd:attribute name="name" type="xsd:string" /> 
+    <xsd:attribute name="width" type="xsd:string" /> 
+    <xsd:attribute name="height" type="xsd:string" /> 
+  </xsd:complexType>
+
+  <xsd:complexType name="docFileType" mixed="true">
+    <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+    <xsd:attribute name="name" type="xsd:string" /> 
+  </xsd:complexType>
+
+  <xsd:complexType name="docTocItemType" mixed="true">
+    <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+    <xsd:attribute name="id" type="xsd:string" /> 
+  </xsd:complexType>
+
+  <xsd:complexType name="docTocListType">
+    <xsd:sequence>
+      <xsd:element name="tocitem" type="docTocItemType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docLanguageType">
+    <xsd:sequence>
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+    <xsd:attribute name="langid" type="xsd:string" /> 
+  </xsd:complexType>
+
+  <xsd:complexType name="docParamListType">
+    <xsd:sequence>
+      <xsd:element name="parameteritem" type="docParamListItem" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+    <xsd:attribute name="kind" type="DoxParamListKind" /> 
+  </xsd:complexType>
+
+  <xsd:complexType name="docParamListItem">
+    <xsd:sequence>
+      <xsd:element name="parameternamelist" type="docParamNameList" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="parameterdescription" type="descriptionType" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docParamNameList">
+    <xsd:sequence>
+      <xsd:element name="parametertype" type="docParamType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="parametername" type="docParamName" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docParamType" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="ref" type="refTextType" minOccurs="0" maxOccurs="1" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docParamName" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="ref" type="refTextType" minOccurs="0" maxOccurs="1" />
+    </xsd:sequence>
+    <xsd:attribute name="direction" type="DoxParamDir" use="optional" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docXRefSectType">
+    <xsd:sequence>
+      <xsd:element name="xreftitle" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="xrefdescription" type="descriptionType" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:string" /> 
+  </xsd:complexType>
+
+  <xsd:complexType name="docCopyType">
+    <xsd:sequence>
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect1" type="docSect1Type" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="internal" type="docInternalType" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="link" type="xsd:string" /> 
+  </xsd:complexType>
+
+  <xsd:complexType name="docBlockQuoteType">
+    <xsd:sequence>
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docParBlockType">
+    <xsd:sequence>
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docEmptyType"/>
+
+  <!-- Simple types -->
+
+  <xsd:simpleType name="DoxBool">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="yes" />
+      <xsd:enumeration value="no" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxGraphRelation">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="include" />
+      <xsd:enumeration value="usage" />
+      <xsd:enumeration value="template-instance" />
+      <xsd:enumeration value="public-inheritance" />
+      <xsd:enumeration value="protected-inheritance" />
+      <xsd:enumeration value="private-inheritance" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxRefKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="compound" />
+      <xsd:enumeration value="member" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxMemberKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="define" />
+      <xsd:enumeration value="property" />
+      <xsd:enumeration value="event" />
+      <xsd:enumeration value="variable" />
+      <xsd:enumeration value="typedef" />
+      <xsd:enumeration value="enum" />
+      <xsd:enumeration value="function" />
+      <xsd:enumeration value="signal" />
+      <xsd:enumeration value="prototype" />
+      <xsd:enumeration value="friend" />
+      <xsd:enumeration value="dcop" />
+      <xsd:enumeration value="slot" />
+      <xsd:enumeration value="interface" />
+      <xsd:enumeration value="service" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxProtectionKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="public" />
+      <xsd:enumeration value="protected" />
+      <xsd:enumeration value="private" />
+      <xsd:enumeration value="package" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxVirtualKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="non-virtual" />
+      <xsd:enumeration value="virtual" />
+      <xsd:enumeration value="pure-virtual" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxCompoundKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="class" />
+      <xsd:enumeration value="struct" />
+      <xsd:enumeration value="union" />
+      <xsd:enumeration value="interface" />
+      <xsd:enumeration value="protocol" />
+      <xsd:enumeration value="category" />
+      <xsd:enumeration value="exception" />
+      <xsd:enumeration value="service" />
+      <xsd:enumeration value="singleton" />
+      <xsd:enumeration value="module" />
+      <xsd:enumeration value="type" />
+      <xsd:enumeration value="file" />
+      <xsd:enumeration value="namespace" />
+      <xsd:enumeration value="group" />
+      <xsd:enumeration value="page" />
+      <xsd:enumeration value="example" />
+      <xsd:enumeration value="dir" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxSectionKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="user-defined" />
+      <xsd:enumeration value="public-type" />
+      <xsd:enumeration value="public-func" />
+      <xsd:enumeration value="public-attrib" />
+      <xsd:enumeration value="public-slot" />
+      <xsd:enumeration value="signal" />
+      <xsd:enumeration value="dcop-func" />
+      <xsd:enumeration value="property" />
+      <xsd:enumeration value="event" />
+      <xsd:enumeration value="public-static-func" />
+      <xsd:enumeration value="public-static-attrib" />
+      <xsd:enumeration value="protected-type" />
+      <xsd:enumeration value="protected-func" />
+      <xsd:enumeration value="protected-attrib" />
+      <xsd:enumeration value="protected-slot" />
+      <xsd:enumeration value="protected-static-func" />
+      <xsd:enumeration value="protected-static-attrib" />
+      <xsd:enumeration value="package-type" />
+      <xsd:enumeration value="package-func" />
+      <xsd:enumeration value="package-attrib" />
+      <xsd:enumeration value="package-static-func" />
+      <xsd:enumeration value="package-static-attrib" />
+      <xsd:enumeration value="private-type" />
+      <xsd:enumeration value="private-func" />
+      <xsd:enumeration value="private-attrib" />
+      <xsd:enumeration value="private-slot" />
+      <xsd:enumeration value="private-static-func" />
+      <xsd:enumeration value="private-static-attrib" />
+      <xsd:enumeration value="friend" />
+      <xsd:enumeration value="related" />
+      <xsd:enumeration value="define" />
+      <xsd:enumeration value="prototype" />
+      <xsd:enumeration value="typedef" />
+      <xsd:enumeration value="enum" />
+      <xsd:enumeration value="func" />
+      <xsd:enumeration value="var" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxHighlightClass">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="comment" />
+      <xsd:enumeration value="normal" />
+      <xsd:enumeration value="preprocessor" />
+      <xsd:enumeration value="keyword" />
+      <xsd:enumeration value="keywordtype" />
+      <xsd:enumeration value="keywordflow" />
+      <xsd:enumeration value="stringliteral" />
+      <xsd:enumeration value="charliteral" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxSimpleSectKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="see" />
+      <xsd:enumeration value="return" />
+      <xsd:enumeration value="author" />
+      <xsd:enumeration value="authors" />
+      <xsd:enumeration value="version" />
+      <xsd:enumeration value="since" />
+      <xsd:enumeration value="date" />
+      <xsd:enumeration value="note" />
+      <xsd:enumeration value="warning" />
+      <xsd:enumeration value="pre" />
+      <xsd:enumeration value="post" />
+      <xsd:enumeration value="copyright" />
+      <xsd:enumeration value="invariant" />
+      <xsd:enumeration value="remark" />
+      <xsd:enumeration value="attention" />
+      <xsd:enumeration value="par" />
+      <xsd:enumeration value="rcs" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxVersionNumber">
+    <xsd:restriction base="xsd:string">
+      <xsd:pattern value="\d+\.\d+.*" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxImageKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="html" />
+      <xsd:enumeration value="latex" />
+      <xsd:enumeration value="rtf" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxParamListKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="param" />
+      <xsd:enumeration value="retval" />
+      <xsd:enumeration value="exception" />
+      <xsd:enumeration value="templateparam" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxCharRange">
+    <xsd:restriction base="xsd:string">
+      <xsd:pattern value="[aeiouncAEIOUNC]" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxParamDir">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="in"/>
+      <xsd:enumeration value="out"/>
+      <xsd:enumeration value="inout"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxAccessor">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="retain"/>
+      <xsd:enumeration value="copy"/>
+      <xsd:enumeration value="assign"/>
+      <xsd:enumeration value="weak"/>
+      <xsd:enumeration value="strong"/>
+      <xsd:enumeration value="unretained"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+</xsd:schema>
+
diff --git a/contrib/neo_doxygen/tests/inner-class/xml/dir_68267d1309a1af8e8297ef4c3efbcdba.xml b/contrib/neo_doxygen/tests/inner-class/xml/dir_68267d1309a1af8e8297ef4c3efbcdba.xml
new file mode 100644 (file)
index 0000000..dfa6949
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+  <compounddef id="dir_68267d1309a1af8e8297ef4c3efbcdba" kind="dir">
+    <compoundname>src</compoundname>
+    <innerfile refid="_outer_class_8java">OuterClass.java</innerfile>
+    <briefdescription>
+    </briefdescription>
+    <detaileddescription>
+    </detaileddescription>
+    <location file="%SOURCE_DIRECTORY%/"/>
+  </compounddef>
+</doxygen>
diff --git a/contrib/neo_doxygen/tests/inner-class/xml/index.xml b/contrib/neo_doxygen/tests/inner-class/xml/index.xml
new file mode 100644 (file)
index 0000000..e43d6e0
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygenindex xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="index.xsd" version="1.8.8">
+  <compound refid="class_outer_class_1_1_inner_class" kind="class"><name>OuterClass::InnerClass</name>
+  </compound>
+  <compound refid="class_outer_class" kind="class"><name>OuterClass</name>
+  </compound>
+  <compound refid="_outer_class_8java" kind="file"><name>OuterClass.java</name>
+  </compound>
+  <compound refid="dir_68267d1309a1af8e8297ef4c3efbcdba" kind="dir"><name>src</name>
+  </compound>
+</doxygenindex>
diff --git a/contrib/neo_doxygen/tests/inner-class/xml/index.xsd b/contrib/neo_doxygen/tests/inner-class/xml/index.xsd
new file mode 100644 (file)
index 0000000..d7ab2a9
--- /dev/null
@@ -0,0 +1,66 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+  <xsd:element name="doxygenindex" type="DoxygenType"/>
+
+  <xsd:complexType name="DoxygenType">
+    <xsd:sequence>
+      <xsd:element name="compound" type="CompoundType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="version" type="xsd:string" use="required"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="CompoundType">
+    <xsd:sequence>
+      <xsd:element name="name" type="xsd:string"/>
+      <xsd:element name="member" type="MemberType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="refid" type="xsd:string" use="required"/>
+    <xsd:attribute name="kind" type="CompoundKind" use="required"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="MemberType">
+    <xsd:sequence>
+      <xsd:element name="name" type="xsd:string"/>
+    </xsd:sequence>
+    <xsd:attribute name="refid" type="xsd:string" use="required"/>
+    <xsd:attribute name="kind" type="MemberKind" use="required"/>
+  </xsd:complexType>
+  
+  <xsd:simpleType name="CompoundKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="class"/>
+      <xsd:enumeration value="struct"/>
+      <xsd:enumeration value="union"/>
+      <xsd:enumeration value="interface"/>
+      <xsd:enumeration value="protocol"/>
+      <xsd:enumeration value="category"/>
+      <xsd:enumeration value="exception"/>
+      <xsd:enumeration value="file"/>
+      <xsd:enumeration value="namespace"/>
+      <xsd:enumeration value="group"/>
+      <xsd:enumeration value="page"/>
+      <xsd:enumeration value="example"/>
+      <xsd:enumeration value="dir"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="MemberKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="define"/>
+      <xsd:enumeration value="property"/>
+      <xsd:enumeration value="event"/>
+      <xsd:enumeration value="variable"/>
+      <xsd:enumeration value="typedef"/>
+      <xsd:enumeration value="enum"/>
+      <xsd:enumeration value="enumvalue"/>
+      <xsd:enumeration value="function"/>
+      <xsd:enumeration value="signal"/>
+      <xsd:enumeration value="prototype"/>
+      <xsd:enumeration value="friend"/>
+      <xsd:enumeration value="dcop"/>
+      <xsd:enumeration value="slot"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+</xsd:schema>
+
diff --git a/contrib/neo_doxygen/tests/java-project/Doxyfile b/contrib/neo_doxygen/tests/java-project/Doxyfile
new file mode 100644 (file)
index 0000000..bd06324
--- /dev/null
@@ -0,0 +1,2381 @@
+# Doxyfile 1.8.8
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "Test Project"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       =
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES                =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = YES
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  = src
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS          = *.c \
+                         *.cc \
+                         *.cxx \
+                         *.cpp \
+                         *.c++ \
+                         *.java \
+                         *.ii \
+                         *.ixx \
+                         *.ipp \
+                         *.i++ \
+                         *.inl \
+                         *.idl \
+                         *.ddl \
+                         *.odl \
+                         *.h \
+                         *.hh \
+                         *.hxx \
+                         *.hpp \
+                         *.h++ \
+                         *.cs \
+                         *.d \
+                         *.php \
+                         *.php4 \
+                         *.php5 \
+                         *.phtml \
+                         *.inc \
+                         *.m \
+                         *.markdown \
+                         *.md \
+                         *.mm \
+                         *.dox \
+                         *.py \
+                         *.f90 \
+                         *.f \
+                         *.for \
+                         *.tcl \
+                         *.vhd \
+                         *.vhdl \
+                         *.ucf \
+                         *.qsf \
+                         *.as \
+                         *.js
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = NO
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra stylesheet files is of importance (e.g. the last
+# stylesheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = YES
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT               = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+PLANTUML_JAR_PATH      =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP            = YES
diff --git a/contrib/neo_doxygen/tests/java-project/README.md b/contrib/neo_doxygen/tests/java-project/README.md
new file mode 100644 (file)
index 0000000..2a87fc7
--- /dev/null
@@ -0,0 +1,5 @@
+This directory contains a dummy Java project for testing purposes.
+
+To regenerate the XML output located in `xml`, run `make`. If the `Makefile`
+does not exists, you can regenerate it by running `make bootstrap` in the parent
+directory.
diff --git a/contrib/neo_doxygen/tests/java-project/src/org/example/foo/A.java b/contrib/neo_doxygen/tests/java-project/src/org/example/foo/A.java
new file mode 100644 (file)
index 0000000..4bbd973
--- /dev/null
@@ -0,0 +1,23 @@
+/* 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.
+ */
+
+package org.example.foo;
+
+public abstract class A {
+       /**
+        * Does something...
+        */
+       public abstract boolean bar(int x, EmptyClass y);
+}
diff --git a/contrib/neo_doxygen/tests/java-project/src/org/example/foo/B.java b/contrib/neo_doxygen/tests/java-project/src/org/example/foo/B.java
new file mode 100644 (file)
index 0000000..0599e9d
--- /dev/null
@@ -0,0 +1,29 @@
+/* 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.
+ */
+
+package org.example.foo;
+
+public class B extends A implements C {
+       protected String qux = "quux";
+
+       public boolean bar(int x, EmptyClass y) {
+               return false;
+       }
+
+       /**
+        * Some overriden documentation.
+        */
+       public void baz() {}
+}
diff --git a/contrib/neo_doxygen/tests/java-project/src/org/example/foo/C.java b/contrib/neo_doxygen/tests/java-project/src/org/example/foo/C.java
new file mode 100644 (file)
index 0000000..42d95fa
--- /dev/null
@@ -0,0 +1,31 @@
+/* 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.
+ */
+
+package org.example.foo;
+
+/**
+ * An interface
+ */
+public interface C {
+       /**
+        * “Answer to the Ultimate Question of Life, the Universe, and Everything.“
+        */
+       public static final long THE_ANSWER = 42L;
+
+       /**
+        * A function with implicit modifiers.
+        */
+       void baz();
+}
diff --git a/contrib/neo_doxygen/tests/java-project/src/org/example/foo/EmptyClass.java b/contrib/neo_doxygen/tests/java-project/src/org/example/foo/EmptyClass.java
new file mode 100644 (file)
index 0000000..87ed89e
--- /dev/null
@@ -0,0 +1,21 @@
+/* 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.
+ */
+
+package org.example.foo;
+
+/**
+ * This class is empty and is only visible in this package.
+ */
+class EmptyClass {}
diff --git a/contrib/neo_doxygen/tests/java-project/xml/_a_8java.xml b/contrib/neo_doxygen/tests/java-project/xml/_a_8java.xml
new file mode 100644 (file)
index 0000000..5ce035d
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+  <compounddef id="_a_8java" kind="file">
+    <compoundname>A.java</compoundname>
+    <innerclass refid="classorg_1_1example_1_1foo_1_1_a" prot="public">org::example::foo::A</innerclass>
+    <innernamespace refid="namespaceorg_1_1example_1_1foo">org::example::foo</innernamespace>
+    <briefdescription>
+    </briefdescription>
+    <detaileddescription>
+    </detaileddescription>
+    <location file="%SOURCE_DIRECTORY%/org/example/foo/A.java"/>
+  </compounddef>
+</doxygen>
diff --git a/contrib/neo_doxygen/tests/java-project/xml/_b_8java.xml b/contrib/neo_doxygen/tests/java-project/xml/_b_8java.xml
new file mode 100644 (file)
index 0000000..5d616b9
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+  <compounddef id="_b_8java" kind="file">
+    <compoundname>B.java</compoundname>
+    <innerclass refid="classorg_1_1example_1_1foo_1_1_b" prot="public">org::example::foo::B</innerclass>
+    <innernamespace refid="namespaceorg_1_1example_1_1foo">org::example::foo</innernamespace>
+    <briefdescription>
+    </briefdescription>
+    <detaileddescription>
+    </detaileddescription>
+    <location file="%SOURCE_DIRECTORY%/org/example/foo/B.java"/>
+  </compounddef>
+</doxygen>
diff --git a/contrib/neo_doxygen/tests/java-project/xml/_c_8java.xml b/contrib/neo_doxygen/tests/java-project/xml/_c_8java.xml
new file mode 100644 (file)
index 0000000..d020a7a
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+  <compounddef id="_c_8java" kind="file">
+    <compoundname>C.java</compoundname>
+    <innerclass refid="interfaceorg_1_1example_1_1foo_1_1_c" prot="public">org::example::foo::C</innerclass>
+    <innernamespace refid="namespaceorg_1_1example_1_1foo">org::example::foo</innernamespace>
+    <briefdescription>
+    </briefdescription>
+    <detaileddescription>
+    </detaileddescription>
+    <location file="%SOURCE_DIRECTORY%/org/example/foo/C.java"/>
+  </compounddef>
+</doxygen>
diff --git a/contrib/neo_doxygen/tests/java-project/xml/_empty_class_8java.xml b/contrib/neo_doxygen/tests/java-project/xml/_empty_class_8java.xml
new file mode 100644 (file)
index 0000000..82e6562
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+  <compounddef id="_empty_class_8java" kind="file">
+    <compoundname>EmptyClass.java</compoundname>
+    <innerclass refid="classorg_1_1example_1_1foo_1_1_empty_class" prot="package">org::example::foo::EmptyClass</innerclass>
+    <innernamespace refid="namespaceorg_1_1example_1_1foo">org::example::foo</innernamespace>
+    <briefdescription>
+    </briefdescription>
+    <detaileddescription>
+    </detaileddescription>
+    <location file="%SOURCE_DIRECTORY%/org/example/foo/EmptyClass.java"/>
+  </compounddef>
+</doxygen>
diff --git a/contrib/neo_doxygen/tests/java-project/xml/classorg_1_1example_1_1foo_1_1_a.xml b/contrib/neo_doxygen/tests/java-project/xml/classorg_1_1example_1_1foo_1_1_a.xml
new file mode 100644 (file)
index 0000000..4475075
--- /dev/null
@@ -0,0 +1,50 @@
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+  <compounddef id="classorg_1_1example_1_1foo_1_1_a" kind="class" prot="public" abstract="yes">
+    <compoundname>org::example::foo::A</compoundname>
+    <derivedcompoundref refid="classorg_1_1example_1_1foo_1_1_b" prot="public" virt="non-virtual">org.example.foo.B</derivedcompoundref>
+      <sectiondef kind="public-func">
+      <memberdef kind="function" id="classorg_1_1example_1_1foo_1_1_a_1add415ae4129969055d678c7e7e048852" prot="public" static="no" const="no" explicit="no" inline="no" virt="non-virtual">
+        <type>abstract boolean</type>
+        <definition>abstract boolean org.example.foo.A.bar</definition>
+        <argsstring>(int x, EmptyClass y)</argsstring>
+        <name>bar</name>
+        <param>
+          <type>int</type>
+          <declname>x</declname>
+        </param>
+        <param>
+          <type>EmptyClass</type>
+          <declname>y</declname>
+        </param>
+        <briefdescription>
+        </briefdescription>
+        <detaileddescription>
+<para>Does something... </para>        </detaileddescription>
+        <inbodydescription>
+        </inbodydescription>
+        <location file="%SOURCE_DIRECTORY%/org/example/foo/A.java" line="22" column="1"/>
+      </memberdef>
+      </sectiondef>
+    <briefdescription>
+    </briefdescription>
+    <detaileddescription>
+    </detaileddescription>
+    <inheritancegraph>
+      <node id="0">
+        <label>org.example.foo.A</label>
+        <link refid="classorg_1_1example_1_1foo_1_1_a"/>
+      </node>
+      <node id="1">
+        <label>org.example.foo.B</label>
+        <link refid="classorg_1_1example_1_1foo_1_1_b"/>
+        <childnode refid="0" relation="public-inheritance">
+        </childnode>
+      </node>
+    </inheritancegraph>
+    <location file="%SOURCE_DIRECTORY%/org/example/foo/A.java" line="18" column="1" bodyfile="%SOURCE_DIRECTORY%/org/example/foo/A.java" bodystart="18" bodyend="23"/>
+    <listofallmembers>
+      <member refid="classorg_1_1example_1_1foo_1_1_a_1add415ae4129969055d678c7e7e048852" prot="public" virt="non-virtual"><scope>org::example::foo::A</scope><name>bar</name></member>
+    </listofallmembers>
+  </compounddef>
+</doxygen>
diff --git a/contrib/neo_doxygen/tests/java-project/xml/classorg_1_1example_1_1foo_1_1_b.xml b/contrib/neo_doxygen/tests/java-project/xml/classorg_1_1example_1_1foo_1_1_b.xml
new file mode 100644 (file)
index 0000000..eb1fd6c
--- /dev/null
@@ -0,0 +1,108 @@
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+  <compounddef id="classorg_1_1example_1_1foo_1_1_b" kind="class" prot="public">
+    <compoundname>org::example::foo::B</compoundname>
+    <basecompoundref refid="classorg_1_1example_1_1foo_1_1_a" prot="public" virt="non-virtual">org.example.foo.A</basecompoundref>
+    <basecompoundref refid="interfaceorg_1_1example_1_1foo_1_1_c" prot="public" virt="non-virtual">org.example.foo.C</basecompoundref>
+      <sectiondef kind="protected-attrib">
+      <memberdef kind="variable" id="classorg_1_1example_1_1foo_1_1_b_1ac6b627949b10b9357eefc0cafcae1d87" prot="protected" static="no" mutable="no">
+        <type>String</type>
+        <definition>String org.example.foo.B.qux</definition>
+        <argsstring></argsstring>
+        <name>qux</name>
+        <initializer>= &quot;quux&quot;</initializer>
+        <briefdescription>
+        </briefdescription>
+        <detaileddescription>
+        </detaileddescription>
+        <inbodydescription>
+        </inbodydescription>
+        <location file="%SOURCE_DIRECTORY%/org/example/foo/B.java" line="19" column="1" bodyfile="%SOURCE_DIRECTORY%/org/example/foo/B.java" bodystart="19" bodyend="-1"/>
+      </memberdef>
+      </sectiondef>
+      <sectiondef kind="public-func">
+      <memberdef kind="function" id="classorg_1_1example_1_1foo_1_1_b_1a11e157943665cc9e3a9be1502ebeb3b5" prot="public" static="no" const="no" explicit="no" inline="yes" virt="non-virtual">
+        <type>boolean</type>
+        <definition>boolean org.example.foo.B.bar</definition>
+        <argsstring>(int x, EmptyClass y)</argsstring>
+        <name>bar</name>
+        <param>
+          <type>int</type>
+          <declname>x</declname>
+        </param>
+        <param>
+          <type>EmptyClass</type>
+          <declname>y</declname>
+        </param>
+        <briefdescription>
+        </briefdescription>
+        <detaileddescription>
+        </detaileddescription>
+        <inbodydescription>
+        </inbodydescription>
+        <location file="%SOURCE_DIRECTORY%/org/example/foo/B.java" line="21" column="1" bodyfile="%SOURCE_DIRECTORY%/org/example/foo/B.java" bodystart="21" bodyend="23"/>
+      </memberdef>
+      <memberdef kind="function" id="classorg_1_1example_1_1foo_1_1_b_1a733f4e076f29c7d0c41ed258199ea1d9" prot="public" static="no" const="no" explicit="no" inline="yes" virt="non-virtual">
+        <type>void</type>
+        <definition>void org.example.foo.B.baz</definition>
+        <argsstring>()</argsstring>
+        <name>baz</name>
+        <reimplements refid="interfaceorg_1_1example_1_1foo_1_1_c_1a28ac7ce349ebb3e4a7747a8dd951582b">baz</reimplements>
+        <briefdescription>
+        </briefdescription>
+        <detaileddescription>
+<para>Some overriden documentation. </para>        </detaileddescription>
+        <inbodydescription>
+        </inbodydescription>
+        <location file="%SOURCE_DIRECTORY%/org/example/foo/B.java" line="28" column="1" bodyfile="%SOURCE_DIRECTORY%/org/example/foo/B.java" bodystart="28" bodyend="28"/>
+      </memberdef>
+      </sectiondef>
+    <briefdescription>
+    </briefdescription>
+    <detaileddescription>
+    </detaileddescription>
+    <inheritancegraph>
+      <node id="4">
+        <label>org.example.foo.A</label>
+        <link refid="classorg_1_1example_1_1foo_1_1_a"/>
+      </node>
+      <node id="3">
+        <label>org.example.foo.B</label>
+        <link refid="classorg_1_1example_1_1foo_1_1_b"/>
+        <childnode refid="4" relation="public-inheritance">
+        </childnode>
+        <childnode refid="5" relation="public-inheritance">
+        </childnode>
+      </node>
+      <node id="5">
+        <label>org.example.foo.C</label>
+        <link refid="interfaceorg_1_1example_1_1foo_1_1_c"/>
+      </node>
+    </inheritancegraph>
+    <collaborationgraph>
+      <node id="7">
+        <label>org.example.foo.A</label>
+        <link refid="classorg_1_1example_1_1foo_1_1_a"/>
+      </node>
+      <node id="6">
+        <label>org.example.foo.B</label>
+        <link refid="classorg_1_1example_1_1foo_1_1_b"/>
+        <childnode refid="7" relation="public-inheritance">
+        </childnode>
+        <childnode refid="8" relation="public-inheritance">
+        </childnode>
+      </node>
+      <node id="8">
+        <label>org.example.foo.C</label>
+        <link refid="interfaceorg_1_1example_1_1foo_1_1_c"/>
+      </node>
+    </collaborationgraph>
+    <location file="%SOURCE_DIRECTORY%/org/example/foo/B.java" line="18" column="1" bodyfile="%SOURCE_DIRECTORY%/org/example/foo/B.java" bodystart="18" bodyend="29"/>
+    <listofallmembers>
+      <member refid="classorg_1_1example_1_1foo_1_1_b_1a11e157943665cc9e3a9be1502ebeb3b5" prot="public" virt="non-virtual"><scope>org::example::foo::B</scope><name>bar</name></member>
+      <member refid="classorg_1_1example_1_1foo_1_1_b_1a733f4e076f29c7d0c41ed258199ea1d9" prot="public" virt="non-virtual"><scope>org::example::foo::B</scope><name>baz</name></member>
+      <member refid="classorg_1_1example_1_1foo_1_1_b_1ac6b627949b10b9357eefc0cafcae1d87" prot="protected" virt="non-virtual"><scope>org::example::foo::B</scope><name>qux</name></member>
+      <member refid="interfaceorg_1_1example_1_1foo_1_1_c_1a4e97061eb40b045e820de05b33c43d21" prot="public" virt="non-virtual"><scope>org::example::foo::B</scope><name>THE_ANSWER</name></member>
+    </listofallmembers>
+  </compounddef>
+</doxygen>
diff --git a/contrib/neo_doxygen/tests/java-project/xml/classorg_1_1example_1_1foo_1_1_empty_class.xml b/contrib/neo_doxygen/tests/java-project/xml/classorg_1_1example_1_1foo_1_1_empty_class.xml
new file mode 100644 (file)
index 0000000..9aa6aa2
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+  <compounddef id="classorg_1_1example_1_1foo_1_1_empty_class" kind="class" prot="package">
+    <compoundname>org::example::foo::EmptyClass</compoundname>
+    <briefdescription>
+    </briefdescription>
+    <detaileddescription>
+<para>This class is empty and is only visible in this package. </para>    </detaileddescription>
+    <location file="%SOURCE_DIRECTORY%/org/example/foo/EmptyClass.java" line="21" column="1" bodyfile="%SOURCE_DIRECTORY%/org/example/foo/EmptyClass.java" bodystart="21" bodyend="21"/>
+    <listofallmembers>
+    </listofallmembers>
+  </compounddef>
+</doxygen>
diff --git a/contrib/neo_doxygen/tests/java-project/xml/combine.xslt b/contrib/neo_doxygen/tests/java-project/xml/combine.xslt
new file mode 100644 (file)
index 0000000..c148ee4
--- /dev/null
@@ -0,0 +1,15 @@
+<!-- XSLT script to combine the generated output into a single file. 
+     If you have xsltproc you could use:
+     xsltproc combine.xslt index.xml >all.xml
+-->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+  <xsl:output method="xml" version="1.0" indent="no" standalone="yes" />
+  <xsl:template match="/">
+    <doxygen version="{doxygenindex/@version}">
+      <!-- Load all doxgen generated xml files -->
+      <xsl:for-each select="doxygenindex/compound">
+        <xsl:copy-of select="document( concat( @refid, '.xml' ) )/doxygen/*" />
+      </xsl:for-each>
+    </doxygen>
+  </xsl:template>
+</xsl:stylesheet>
diff --git a/contrib/neo_doxygen/tests/java-project/xml/compound.xsd b/contrib/neo_doxygen/tests/java-project/xml/compound.xsd
new file mode 100644 (file)
index 0000000..86740f4
--- /dev/null
@@ -0,0 +1,1092 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+  <xsd:element name="doxygen" type="DoxygenType"/>
+
+  <!-- Complex types -->
+
+  <xsd:complexType name="DoxygenType">
+    <xsd:sequence maxOccurs="unbounded">
+      <xsd:element name="compounddef" type="compounddefType" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="version" type="DoxVersionNumber" use="required" />
+  </xsd:complexType>
+
+  <xsd:complexType name="compounddefType">
+    <xsd:sequence>
+      <xsd:element name="compoundname" type="xsd:string"/>
+      <xsd:element name="title" type="xsd:string" minOccurs="0" />
+      <xsd:element name="basecompoundref" type="compoundRefType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="derivedcompoundref" type="compoundRefType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="includes" type="incType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="includedby" type="incType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="incdepgraph" type="graphType" minOccurs="0" />
+      <xsd:element name="invincdepgraph" type="graphType" minOccurs="0" />
+      <xsd:element name="innerdir" type="refType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="innerfile" type="refType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="innerclass" type="refType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="innernamespace" type="refType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="innerpage" type="refType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="innergroup" type="refType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="templateparamlist" type="templateparamlistType" minOccurs="0" />
+      <xsd:element name="sectiondef" type="sectiondefType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" />
+      <xsd:element name="detaileddescription" type="descriptionType" minOccurs="0" />
+      <xsd:element name="inheritancegraph" type="graphType" minOccurs="0" />
+      <xsd:element name="collaborationgraph" type="graphType" minOccurs="0" />
+      <xsd:element name="programlisting" type="listingType" minOccurs="0" />
+      <xsd:element name="location" type="locationType" minOccurs="0" />
+      <xsd:element name="listofallmembers" type="listofallmembersType" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:string" />
+    <xsd:attribute name="kind" type="DoxCompoundKind" />
+    <xsd:attribute name="prot" type="DoxProtectionKind" />
+    <xsd:attribute name="final" type="DoxBool" use="optional"/>
+    <xsd:attribute name="sealed" type="DoxBool" use="optional"/>
+    <xsd:attribute name="abstract" type="DoxBool" use="optional"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="listofallmembersType">
+    <xsd:sequence>
+      <xsd:element name="member" type="memberRefType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="memberRefType">
+    <xsd:sequence>
+      <xsd:element name="scope" />
+      <xsd:element name="name" />
+    </xsd:sequence>
+    <xsd:attribute name="refid" type="xsd:string" />
+    <xsd:attribute name="prot" type="DoxProtectionKind" />
+    <xsd:attribute name="virt" type="DoxVirtualKind" />
+    <xsd:attribute name="ambiguityscope" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="compoundRefType">
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:string">
+        <xsd:attribute name="refid" type="xsd:string" use="optional" />
+        <xsd:attribute name="prot" type="DoxProtectionKind" />
+        <xsd:attribute name="virt" type="DoxVirtualKind" />
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+  <xsd:complexType name="reimplementType">
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:string">
+        <xsd:attribute name="refid" type="xsd:string" />
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+  <xsd:complexType name="incType">
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:string">
+        <xsd:attribute name="refid" type="xsd:string" />
+        <xsd:attribute name="local" type="DoxBool" />
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+  <xsd:complexType name="refType">
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:string">
+        <xsd:attribute name="refid" type="xsd:string" />
+        <xsd:attribute name="prot" type="DoxProtectionKind" use="optional"/>
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+  <xsd:complexType name="refTextType">
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:string">
+       <xsd:attribute name="refid" type="xsd:string" />
+       <xsd:attribute name="kindref" type="DoxRefKind" />
+       <xsd:attribute name="external" type="xsd:string" use="optional"/>
+       <xsd:attribute name="tooltip" type="xsd:string" use="optional"/>
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+  <xsd:complexType name="sectiondefType">
+    <xsd:sequence>
+      <xsd:element name="header" type="xsd:string" minOccurs="0" />
+      <xsd:element name="description" type="descriptionType" minOccurs="0" />
+      <xsd:element name="memberdef" type="memberdefType" maxOccurs="unbounded" />
+    </xsd:sequence>
+    <xsd:attribute name="kind" type="DoxSectionKind" />
+  </xsd:complexType>
+
+  <xsd:complexType name="memberdefType">
+    <xsd:sequence>
+      <xsd:element name="templateparamlist" type="templateparamlistType" minOccurs="0" />
+      <xsd:element name="type" type="linkedTextType" minOccurs="0" />
+      <xsd:element name="definition" minOccurs="0" />
+      <xsd:element name="argsstring" minOccurs="0" />
+      <xsd:element name="name" />
+      <xsd:element name="read" minOccurs="0" />
+      <xsd:element name="write" minOccurs="0" />
+      <xsd:element name="bitfield" minOccurs="0" />
+      <xsd:element name="reimplements" type="reimplementType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="reimplementedby" type="reimplementType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="param" type="paramType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="enumvalue" type="enumvalueType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="initializer" type="linkedTextType" minOccurs="0" />
+      <xsd:element name="exceptions" type="linkedTextType" minOccurs="0" />
+      <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" />
+      <xsd:element name="detaileddescription" type="descriptionType" minOccurs="0" />
+      <xsd:element name="inbodydescription" type="descriptionType" minOccurs="0" />
+      <xsd:element name="location" type="locationType" />
+      <xsd:element name="references" type="referenceType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="referencedby" type="referenceType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+    <xsd:attribute name="kind" type="DoxMemberKind" />
+    <xsd:attribute name="id" type="xsd:string" />
+    <xsd:attribute name="prot" type="DoxProtectionKind" />
+    <xsd:attribute name="static" type="DoxBool" />
+    <xsd:attribute name="const" type="DoxBool" use="optional"/>
+    <xsd:attribute name="explicit" type="DoxBool" use="optional"/>
+    <xsd:attribute name="inline" type="DoxBool" use="optional"/>
+    <xsd:attribute name="virt" type="DoxVirtualKind" use="optional"/>
+    <xsd:attribute name="volatile" type="DoxBool" use="optional"/>
+    <xsd:attribute name="mutable" type="DoxBool" use="optional"/>
+    <!-- Qt property -->
+    <xsd:attribute name="readable" type="DoxBool" use="optional"/>
+    <xsd:attribute name="writable" type="DoxBool" use="optional"/>
+    <!-- C++/CLI variable -->
+    <xsd:attribute name="initonly" type="DoxBool" use="optional"/>
+    <!-- C++/CLI and C# property -->
+    <xsd:attribute name="settable" type="DoxBool" use="optional"/>
+    <xsd:attribute name="gettable" type="DoxBool" use="optional"/>
+    <!-- C++/CLI function -->
+    <xsd:attribute name="final" type="DoxBool" use="optional"/>
+    <xsd:attribute name="sealed" type="DoxBool" use="optional"/>
+    <xsd:attribute name="new" type="DoxBool" use="optional"/>
+    <!-- C++/CLI event -->
+    <xsd:attribute name="add" type="DoxBool" use="optional"/>
+    <xsd:attribute name="remove" type="DoxBool" use="optional"/>
+    <xsd:attribute name="raise" type="DoxBool" use="optional"/>
+    <!-- Objective-C 2.0 protocol method -->
+    <xsd:attribute name="optional" type="DoxBool" use="optional"/>
+    <xsd:attribute name="required" type="DoxBool" use="optional"/>
+    <!-- Objective-C 2.0 property accessor -->
+    <xsd:attribute name="accessor" type="DoxAccessor" use="optional"/>
+    <!-- UNO IDL -->
+    <xsd:attribute name="attribute" type="DoxBool" use="optional"/>
+    <xsd:attribute name="property" type="DoxBool" use="optional"/>
+    <xsd:attribute name="readonly" type="DoxBool" use="optional"/>
+    <xsd:attribute name="bound" type="DoxBool" use="optional"/>
+    <xsd:attribute name="removable" type="DoxBool" use="optional"/>
+    <xsd:attribute name="contrained" type="DoxBool" use="optional"/>
+    <xsd:attribute name="transient" type="DoxBool" use="optional"/>
+    <xsd:attribute name="maybevoid" type="DoxBool" use="optional"/>
+    <xsd:attribute name="maybedefault" type="DoxBool" use="optional"/>
+    <xsd:attribute name="maybeambiguous" type="DoxBool" use="optional"/>
+
+  </xsd:complexType>
+
+  <xsd:complexType name="descriptionType" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="title" type="xsd:string" minOccurs="0"/>          
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect1" type="docSect1Type" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="internal" type="docInternalType" minOccurs="0" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="enumvalueType" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="name" />
+      <xsd:element name="initializer" type="linkedTextType" minOccurs="0" />
+      <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" />
+      <xsd:element name="detaileddescription" type="descriptionType" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:string" />
+    <xsd:attribute name="prot" type="DoxProtectionKind" />
+  </xsd:complexType>
+
+  <xsd:complexType name="templateparamlistType">
+    <xsd:sequence>
+      <xsd:element name="param" type="paramType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="paramType">
+    <xsd:sequence>
+      <xsd:element name="type" type="linkedTextType" minOccurs="0" />
+      <xsd:element name="declname" minOccurs="0" />
+      <xsd:element name="defname" minOccurs="0" />
+      <xsd:element name="array" minOccurs="0" />
+      <xsd:element name="defval" type="linkedTextType" minOccurs="0" />
+      <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="linkedTextType" mixed="true">
+    <xsd:sequence>
+    <xsd:element name="ref" type="refTextType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="graphType">
+    <xsd:sequence>
+      <xsd:element name="node" type="nodeType" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="nodeType">
+    <xsd:sequence>
+      <xsd:element name="label" />
+      <xsd:element name="link" type="linkType" minOccurs="0" />
+      <xsd:element name="childnode" type="childnodeType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="childnodeType">
+    <xsd:sequence>
+      <xsd:element name="edgelabel" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="refid" type="xsd:string" />
+    <xsd:attribute name="relation" type="DoxGraphRelation" />
+  </xsd:complexType>
+
+  <xsd:complexType name="linkType">
+    <xsd:attribute name="refid" type="xsd:string" />
+    <xsd:attribute name="external" type="xsd:string" use="optional"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="listingType">
+    <xsd:sequence>
+      <xsd:element name="codeline" type="codelineType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="codelineType">
+    <xsd:sequence>
+      <xsd:element name="highlight" type="highlightType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+    <xsd:attribute name="lineno" type="xsd:integer" />
+    <xsd:attribute name="refid" type="xsd:string" />
+    <xsd:attribute name="refkind" type="DoxRefKind" />
+    <xsd:attribute name="external" type="DoxBool" />
+  </xsd:complexType>
+
+  <xsd:complexType name="highlightType" mixed="true">
+    <xsd:choice minOccurs="0" maxOccurs="unbounded">
+      <xsd:element name="sp" />
+      <xsd:element name="ref" type="refTextType" />
+    </xsd:choice>
+    <xsd:attribute name="class" type="DoxHighlightClass" />
+  </xsd:complexType>
+
+  <xsd:complexType name="referenceType" mixed="true">
+    <xsd:attribute name="refid" type="xsd:string" />
+    <xsd:attribute name="compoundref" type="xsd:string" use="optional" />
+    <xsd:attribute name="startline" type="xsd:integer" />
+    <xsd:attribute name="endline" type="xsd:integer" />
+  </xsd:complexType>
+
+  <xsd:complexType name="locationType">
+    <xsd:attribute name="file" type="xsd:string" />
+    <xsd:attribute name="line" type="xsd:integer" />
+    <xsd:attribute name="column" type="xsd:integer" use="optional"/>
+    <xsd:attribute name="bodyfile" type="xsd:string" />
+    <xsd:attribute name="bodystart" type="xsd:integer" />
+    <xsd:attribute name="bodyend" type="xsd:integer" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docSect1Type" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="title" type="xsd:string" />       
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect2" type="docSect2Type" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="internal" type="docInternalS1Type" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docSect2Type" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="title" type="xsd:string" />       
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect3" type="docSect3Type" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="internal" type="docInternalS2Type" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docSect3Type" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="title" type="xsd:string" />       
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect4" type="docSect4Type" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="internal" type="docInternalS3Type" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docSect4Type" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="title" type="xsd:string" />       
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="internal" type="docInternalS4Type" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docInternalType" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="para"  type="docParaType"  minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect1" type="docSect1Type" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docInternalS1Type" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="para"  type="docParaType"  minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect2" type="docSect2Type" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docInternalS2Type" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="para"  type="docParaType"  minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect3" type="docSect3Type" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docInternalS3Type" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="para"  type="docParaType"  minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect3" type="docSect4Type" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docInternalS4Type" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="para"  type="docParaType"  minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+  <xsd:group name="docTitleCmdGroup">
+    <xsd:choice>
+      <xsd:element name="ulink" type="docURLLink" />
+      <xsd:element name="bold" type="docMarkupType" />
+      <xsd:element name="emphasis" type="docMarkupType" />
+      <xsd:element name="computeroutput" type="docMarkupType" />
+      <xsd:element name="subscript" type="docMarkupType" />
+      <xsd:element name="superscript" type="docMarkupType" />
+      <xsd:element name="center" type="docMarkupType" />
+      <xsd:element name="small" type="docMarkupType" />
+      <xsd:element name="htmlonly" type="xsd:string" />
+      <xsd:element name="manonly" type="xsd:string" />
+      <xsd:element name="xmlonly" type="xsd:string" />
+      <xsd:element name="rtfonly" type="xsd:string" />
+      <xsd:element name="latexonly" type="xsd:string" />
+      <xsd:element name="dot" type="xsd:string" />
+      <xsd:element name="plantuml" type="xsd:string" />
+      <xsd:element name="anchor" type="docAnchorType" />
+      <xsd:element name="formula" type="docFormulaType" />
+      <xsd:element name="ref" type="docRefTextType" />
+      <xsd:element name="nonbreakablespace" type="docEmptyType" />
+      <xsd:element name="iexcl" type="docEmptyType" />
+      <xsd:element name="cent" type="docEmptyType" />
+      <xsd:element name="pound" type="docEmptyType" />
+      <xsd:element name="curren" type="docEmptyType" />
+      <xsd:element name="yen" type="docEmptyType" />
+      <xsd:element name="brvbar" type="docEmptyType" />
+      <xsd:element name="sect" type="docEmptyType" />
+      <xsd:element name="umlaut" type="docEmptyType" />
+      <xsd:element name="copy" type="docEmptyType" />
+      <xsd:element name="ordf" type="docEmptyType" />
+      <xsd:element name="laquo" type="docEmptyType" />
+      <xsd:element name="not" type="docEmptyType" />
+      <xsd:element name="shy" type="docEmptyType" />
+      <xsd:element name="registered" type="docEmptyType" />
+      <xsd:element name="macr" type="docEmptyType" />
+      <xsd:element name="deg" type="docEmptyType" />
+      <xsd:element name="plusmn" type="docEmptyType" />
+      <xsd:element name="sup2" type="docEmptyType" />
+      <xsd:element name="sup3" type="docEmptyType" />
+      <xsd:element name="acute" type="docEmptyType" />
+      <xsd:element name="micro" type="docEmptyType" />
+      <xsd:element name="para" type="docEmptyType" />
+      <xsd:element name="middot" type="docEmptyType" />
+      <xsd:element name="cedil" type="docEmptyType" />
+      <xsd:element name="sup1" type="docEmptyType" />
+      <xsd:element name="ordm" type="docEmptyType" />
+      <xsd:element name="raquo" type="docEmptyType" />
+      <xsd:element name="frac14" type="docEmptyType" />
+      <xsd:element name="frac12" type="docEmptyType" />
+      <xsd:element name="frac34" type="docEmptyType" />
+      <xsd:element name="iquest" type="docEmptyType" />
+      <xsd:element name="Agrave" type="docEmptyType" />
+      <xsd:element name="Aacute" type="docEmptyType" />
+      <xsd:element name="Acirc" type="docEmptyType" />
+      <xsd:element name="Atilde" type="docEmptyType" />
+      <xsd:element name="Aumlaut" type="docEmptyType" />
+      <xsd:element name="Aring" type="docEmptyType" />
+      <xsd:element name="AElig" type="docEmptyType" />
+      <xsd:element name="Ccedil" type="docEmptyType" />
+      <xsd:element name="Egrave" type="docEmptyType" />
+      <xsd:element name="Eacute" type="docEmptyType" />
+      <xsd:element name="Ecirc" type="docEmptyType" />
+      <xsd:element name="Eumlaut" type="docEmptyType" />
+      <xsd:element name="Igrave" type="docEmptyType" />
+      <xsd:element name="Iacute" type="docEmptyType" />
+      <xsd:element name="Icirc" type="docEmptyType" />
+      <xsd:element name="Iumlaut" type="docEmptyType" />
+      <xsd:element name="ETH" type="docEmptyType" />
+      <xsd:element name="Ntilde" type="docEmptyType" />
+      <xsd:element name="Ograve" type="docEmptyType" />
+      <xsd:element name="Oacute" type="docEmptyType" />
+      <xsd:element name="Ocirc" type="docEmptyType" />
+      <xsd:element name="Otilde" type="docEmptyType" />
+      <xsd:element name="Oumlaut" type="docEmptyType" />
+      <xsd:element name="times" type="docEmptyType" />
+      <xsd:element name="Oslash" type="docEmptyType" />
+      <xsd:element name="Ugrave" type="docEmptyType" />
+      <xsd:element name="Uacute" type="docEmptyType" />
+      <xsd:element name="Ucirc" type="docEmptyType" />
+      <xsd:element name="Uumlaut" type="docEmptyType" />
+      <xsd:element name="Yacute" type="docEmptyType" />
+      <xsd:element name="THORN" type="docEmptyType" />
+      <xsd:element name="szlig" type="docEmptyType" />
+      <xsd:element name="agrave" type="docEmptyType" />
+      <xsd:element name="aacute" type="docEmptyType" />
+      <xsd:element name="acirc" type="docEmptyType" />
+      <xsd:element name="atilde" type="docEmptyType" />
+      <xsd:element name="aumlaut" type="docEmptyType" />
+      <xsd:element name="aring" type="docEmptyType" />
+      <xsd:element name="aelig" type="docEmptyType" />
+      <xsd:element name="ccedil" type="docEmptyType" />
+      <xsd:element name="egrave" type="docEmptyType" />
+      <xsd:element name="eacute" type="docEmptyType" />
+      <xsd:element name="ecirc" type="docEmptyType" />
+      <xsd:element name="eumlaut" type="docEmptyType" />
+      <xsd:element name="igrave" type="docEmptyType" />
+      <xsd:element name="iacute" type="docEmptyType" />
+      <xsd:element name="icirc" type="docEmptyType" />
+      <xsd:element name="iumlaut" type="docEmptyType" />
+      <xsd:element name="eth" type="docEmptyType" />
+      <xsd:element name="ntilde" type="docEmptyType" />
+      <xsd:element name="ograve" type="docEmptyType" />
+      <xsd:element name="oacute" type="docEmptyType" />
+      <xsd:element name="ocirc" type="docEmptyType" />
+      <xsd:element name="otilde" type="docEmptyType" />
+      <xsd:element name="oumlaut" type="docEmptyType" />
+      <xsd:element name="divide" type="docEmptyType" />
+      <xsd:element name="oslash" type="docEmptyType" />
+      <xsd:element name="ugrave" type="docEmptyType" />
+      <xsd:element name="uacute" type="docEmptyType" />
+      <xsd:element name="ucirc" type="docEmptyType" />
+      <xsd:element name="uumlaut" type="docEmptyType" />
+      <xsd:element name="yacute" type="docEmptyType" />
+      <xsd:element name="thorn" type="docEmptyType" />
+      <xsd:element name="yumlaut" type="docEmptyType" />
+      <xsd:element name="fnof" type="docEmptyType" />
+      <xsd:element name="Alpha" type="docEmptyType" />
+      <xsd:element name="Beta" type="docEmptyType" />
+      <xsd:element name="Gamma" type="docEmptyType" />
+      <xsd:element name="Delta" type="docEmptyType" />
+      <xsd:element name="Epsilon" type="docEmptyType" />
+      <xsd:element name="Zeta" type="docEmptyType" />
+      <xsd:element name="Eta" type="docEmptyType" />
+      <xsd:element name="Theta" type="docEmptyType" />
+      <xsd:element name="Iota" type="docEmptyType" />
+      <xsd:element name="Kappa" type="docEmptyType" />
+      <xsd:element name="Lambda" type="docEmptyType" />
+      <xsd:element name="Mu" type="docEmptyType" />
+      <xsd:element name="Nu" type="docEmptyType" />
+      <xsd:element name="Xi" type="docEmptyType" />
+      <xsd:element name="Omicron" type="docEmptyType" />
+      <xsd:element name="Pi" type="docEmptyType" />
+      <xsd:element name="Rho" type="docEmptyType" />
+      <xsd:element name="Sigma" type="docEmptyType" />
+      <xsd:element name="Tau" type="docEmptyType" />
+      <xsd:element name="Upsilon" type="docEmptyType" />
+      <xsd:element name="Phi" type="docEmptyType" />
+      <xsd:element name="Chi" type="docEmptyType" />
+      <xsd:element name="Psi" type="docEmptyType" />
+      <xsd:element name="Omega" type="docEmptyType" />
+      <xsd:element name="alpha" type="docEmptyType" />
+      <xsd:element name="beta" type="docEmptyType" />
+      <xsd:element name="gamma" type="docEmptyType" />
+      <xsd:element name="delta" type="docEmptyType" />
+      <xsd:element name="epsilon" type="docEmptyType" />
+      <xsd:element name="zeta" type="docEmptyType" />
+      <xsd:element name="eta" type="docEmptyType" />
+      <xsd:element name="theta" type="docEmptyType" />
+      <xsd:element name="iota" type="docEmptyType" />
+      <xsd:element name="kappa" type="docEmptyType" />
+      <xsd:element name="lambda" type="docEmptyType" />
+      <xsd:element name="mu" type="docEmptyType" />
+      <xsd:element name="nu" type="docEmptyType" />
+      <xsd:element name="xi" type="docEmptyType" />
+      <xsd:element name="omicron" type="docEmptyType" />
+      <xsd:element name="pi" type="docEmptyType" />
+      <xsd:element name="rho" type="docEmptyType" />
+      <xsd:element name="sigmaf" type="docEmptyType" />
+      <xsd:element name="sigma" type="docEmptyType" />
+      <xsd:element name="tau" type="docEmptyType" />
+      <xsd:element name="upsilon" type="docEmptyType" />
+      <xsd:element name="phi" type="docEmptyType" />
+      <xsd:element name="chi" type="docEmptyType" />
+      <xsd:element name="psi" type="docEmptyType" />
+      <xsd:element name="omega" type="docEmptyType" />
+      <xsd:element name="thetasym" type="docEmptyType" />
+      <xsd:element name="upsih" type="docEmptyType" />
+      <xsd:element name="piv" type="docEmptyType" />
+      <xsd:element name="bull" type="docEmptyType" />
+      <xsd:element name="hellip" type="docEmptyType" />
+      <xsd:element name="prime" type="docEmptyType" />
+      <xsd:element name="Prime" type="docEmptyType" />
+      <xsd:element name="oline" type="docEmptyType" />
+      <xsd:element name="frasl" type="docEmptyType" />
+      <xsd:element name="weierp" type="docEmptyType" />
+      <xsd:element name="image" type="docEmptyType" />
+      <xsd:element name="real" type="docEmptyType" />
+      <xsd:element name="trademark" type="docEmptyType" />
+      <xsd:element name="alefsym" type="docEmptyType" />
+      <xsd:element name="larr" type="docEmptyType" />
+      <xsd:element name="uarr" type="docEmptyType" />
+      <xsd:element name="rarr" type="docEmptyType" />
+      <xsd:element name="darr" type="docEmptyType" />
+      <xsd:element name="harr" type="docEmptyType" />
+      <xsd:element name="crarr" type="docEmptyType" />
+      <xsd:element name="lArr" type="docEmptyType" />
+      <xsd:element name="uArr" type="docEmptyType" />
+      <xsd:element name="rArr" type="docEmptyType" />
+      <xsd:element name="dArr" type="docEmptyType" />
+      <xsd:element name="hArr" type="docEmptyType" />
+      <xsd:element name="forall" type="docEmptyType" />
+      <xsd:element name="part" type="docEmptyType" />
+      <xsd:element name="exist" type="docEmptyType" />
+      <xsd:element name="empty" type="docEmptyType" />
+      <xsd:element name="nabla" type="docEmptyType" />
+      <xsd:element name="isin" type="docEmptyType" />
+      <xsd:element name="notin" type="docEmptyType" />
+      <xsd:element name="ni" type="docEmptyType" />
+      <xsd:element name="prod" type="docEmptyType" />
+      <xsd:element name="sum" type="docEmptyType" />
+      <xsd:element name="minus" type="docEmptyType" />
+      <xsd:element name="lowast" type="docEmptyType" />
+      <xsd:element name="radic" type="docEmptyType" />
+      <xsd:element name="prop" type="docEmptyType" />
+      <xsd:element name="infin" type="docEmptyType" />
+      <xsd:element name="ang" type="docEmptyType" />
+      <xsd:element name="and" type="docEmptyType" />
+      <xsd:element name="or" type="docEmptyType" />
+      <xsd:element name="cap" type="docEmptyType" />
+      <xsd:element name="cup" type="docEmptyType" />
+      <xsd:element name="int" type="docEmptyType" />
+      <xsd:element name="there4" type="docEmptyType" />
+      <xsd:element name="sim" type="docEmptyType" />
+      <xsd:element name="cong" type="docEmptyType" />
+      <xsd:element name="asymp" type="docEmptyType" />
+      <xsd:element name="ne" type="docEmptyType" />
+      <xsd:element name="equiv" type="docEmptyType" />
+      <xsd:element name="le" type="docEmptyType" />
+      <xsd:element name="ge" type="docEmptyType" />
+      <xsd:element name="sub" type="docEmptyType" />
+      <xsd:element name="sup" type="docEmptyType" />
+      <xsd:element name="nsub" type="docEmptyType" />
+      <xsd:element name="sube" type="docEmptyType" />
+      <xsd:element name="supe" type="docEmptyType" />
+      <xsd:element name="oplus" type="docEmptyType" />
+      <xsd:element name="otimes" type="docEmptyType" />
+      <xsd:element name="perp" type="docEmptyType" />
+      <xsd:element name="sdot" type="docEmptyType" />
+      <xsd:element name="lceil" type="docEmptyType" />
+      <xsd:element name="rceil" type="docEmptyType" />
+      <xsd:element name="lfloor" type="docEmptyType" />
+      <xsd:element name="rfloor" type="docEmptyType" />
+      <xsd:element name="lang" type="docEmptyType" />
+      <xsd:element name="rang" type="docEmptyType" />
+      <xsd:element name="loz" type="docEmptyType" />
+      <xsd:element name="spades" type="docEmptyType" />
+      <xsd:element name="clubs" type="docEmptyType" />
+      <xsd:element name="hearts" type="docEmptyType" />
+      <xsd:element name="diams" type="docEmptyType" />
+      <xsd:element name="OElig" type="docEmptyType" />
+      <xsd:element name="oelig" type="docEmptyType" />
+      <xsd:element name="Scaron" type="docEmptyType" />
+      <xsd:element name="scaron" type="docEmptyType" />
+      <xsd:element name="Yumlaut" type="docEmptyType" />
+      <xsd:element name="circ" type="docEmptyType" />
+      <xsd:element name="tilde" type="docEmptyType" />
+      <xsd:element name="ensp" type="docEmptyType" />
+      <xsd:element name="emsp" type="docEmptyType" />
+      <xsd:element name="thinsp" type="docEmptyType" />
+      <xsd:element name="zwnj" type="docEmptyType" />
+      <xsd:element name="zwj" type="docEmptyType" />
+      <xsd:element name="lrm" type="docEmptyType" />
+      <xsd:element name="rlm" type="docEmptyType" />
+      <xsd:element name="ndash" type="docEmptyType" />
+      <xsd:element name="mdash" type="docEmptyType" />
+      <xsd:element name="lsquo" type="docEmptyType" />
+      <xsd:element name="rsquo" type="docEmptyType" />
+      <xsd:element name="sbquo" type="docEmptyType" />
+      <xsd:element name="ldquo" type="docEmptyType" />
+      <xsd:element name="rdquo" type="docEmptyType" />
+      <xsd:element name="bdquo" type="docEmptyType" />
+      <xsd:element name="dagger" type="docEmptyType" />
+      <xsd:element name="Dagger" type="docEmptyType" />
+      <xsd:element name="permil" type="docEmptyType" />
+      <xsd:element name="lsaquo" type="docEmptyType" />
+      <xsd:element name="rsaquo" type="docEmptyType" />
+      <xsd:element name="euro" type="docEmptyType" />
+      <xsd:element name="trademark" type="docEmptyType" />
+    </xsd:choice>
+  </xsd:group>
+
+  <xsd:complexType name="docTitleType" mixed="true">
+    <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+  </xsd:complexType>
+
+  <xsd:group name="docCmdGroup">
+    <xsd:choice>
+      <xsd:group ref="docTitleCmdGroup"/>
+      <xsd:element name="linebreak" type="docEmptyType" />
+      <xsd:element name="hruler" type="docEmptyType" />
+      <xsd:element name="preformatted" type="docMarkupType" />
+      <xsd:element name="programlisting" type="listingType" />
+      <xsd:element name="verbatim" type="xsd:string" />
+      <xsd:element name="indexentry" type="docIndexEntryType" />
+      <xsd:element name="orderedlist" type="docListType" />
+      <xsd:element name="itemizedlist" type="docListType" />
+      <xsd:element name="simplesect" type="docSimpleSectType" />
+      <xsd:element name="title" type="docTitleType" />
+      <xsd:element name="variablelist" type="docVariableListType" />
+      <xsd:element name="table" type="docTableType" />
+      <xsd:element name="heading" type="docHeadingType" />
+      <xsd:element name="image" type="docImageType" />
+      <xsd:element name="dotfile" type="docFileType" />
+      <xsd:element name="mscfile" type="docFileType" />
+      <xsd:element name="diafile" type="docFileType" />
+      <xsd:element name="toclist" type="docTocListType" />
+      <xsd:element name="language" type="docLanguageType" />
+      <xsd:element name="parameterlist" type="docParamListType" />
+      <xsd:element name="xrefsect" type="docXRefSectType" />
+      <xsd:element name="copydoc" type="docCopyType" />
+      <xsd:element name="blockquote" type="docBlockQuoteType" />
+      <xsd:element name="parblock" type="docParBlockType" />
+    </xsd:choice>
+  </xsd:group>
+
+  <xsd:complexType name="docParaType" mixed="true">
+    <xsd:group ref="docCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docMarkupType" mixed="true">
+    <xsd:group ref="docCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docURLLink" mixed="true">
+    <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+    <xsd:attribute name="url" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docAnchorType" mixed="true">
+    <xsd:attribute name="id" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docFormulaType" mixed="true">
+    <xsd:attribute name="id" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docIndexEntryType">
+    <xsd:sequence>
+      <xsd:element name="primaryie" type="xsd:string" />
+      <xsd:element name="secondaryie" type="xsd:string" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docListType">
+    <xsd:sequence>
+      <xsd:element name="listitem" type="docListItemType" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docListItemType">
+    <xsd:sequence>
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docSimpleSectType">
+    <xsd:sequence>
+      <xsd:element name="title" type="docTitleType" minOccurs="0" />
+      <xsd:sequence minOccurs="0" maxOccurs="unbounded">
+        <xsd:element name="para" type="docParaType" minOccurs="1" maxOccurs="unbounded" />
+      </xsd:sequence>
+    </xsd:sequence>
+    <xsd:attribute name="kind" type="DoxSimpleSectKind" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docVarListEntryType">
+    <xsd:sequence>
+      <xsd:element name="term" type="docTitleType" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:group name="docVariableListGroup">
+    <xsd:sequence>
+      <xsd:element name="varlistentry" type="docVarListEntryType" />
+      <xsd:element name="listitem" type="docListItemType" />
+    </xsd:sequence>
+  </xsd:group>
+
+  <xsd:complexType name="docVariableListType">
+    <xsd:sequence>
+      <xsd:group ref="docVariableListGroup" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docRefTextType" mixed="true">
+    <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+    <xsd:attribute name="refid" type="xsd:string" />
+    <xsd:attribute name="kindref" type="DoxRefKind" />
+    <xsd:attribute name="external" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docTableType">
+    <xsd:sequence>
+      <xsd:element name="row" type="docRowType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="caption" type="docCaptionType" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="rows" type="xsd:integer" />
+    <xsd:attribute name="cols" type="xsd:integer" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docRowType">
+    <xsd:sequence>
+      <xsd:element name="entry" type="docEntryType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docEntryType">
+    <xsd:sequence>
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+    <xsd:attribute name="thead" type="DoxBool" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docCaptionType" mixed="true">
+    <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docHeadingType" mixed="true">
+    <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+    <xsd:attribute name="level" type="xsd:integer" /> <!-- todo: range 1-6 -->
+  </xsd:complexType>
+
+  <xsd:complexType name="docImageType" mixed="true">
+    <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+    <xsd:attribute name="type" type="DoxImageKind" /> 
+    <xsd:attribute name="name" type="xsd:string" /> 
+    <xsd:attribute name="width" type="xsd:string" /> 
+    <xsd:attribute name="height" type="xsd:string" /> 
+  </xsd:complexType>
+
+  <xsd:complexType name="docFileType" mixed="true">
+    <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+    <xsd:attribute name="name" type="xsd:string" /> 
+  </xsd:complexType>
+
+  <xsd:complexType name="docTocItemType" mixed="true">
+    <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+    <xsd:attribute name="id" type="xsd:string" /> 
+  </xsd:complexType>
+
+  <xsd:complexType name="docTocListType">
+    <xsd:sequence>
+      <xsd:element name="tocitem" type="docTocItemType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docLanguageType">
+    <xsd:sequence>
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+    <xsd:attribute name="langid" type="xsd:string" /> 
+  </xsd:complexType>
+
+  <xsd:complexType name="docParamListType">
+    <xsd:sequence>
+      <xsd:element name="parameteritem" type="docParamListItem" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+    <xsd:attribute name="kind" type="DoxParamListKind" /> 
+  </xsd:complexType>
+
+  <xsd:complexType name="docParamListItem">
+    <xsd:sequence>
+      <xsd:element name="parameternamelist" type="docParamNameList" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="parameterdescription" type="descriptionType" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docParamNameList">
+    <xsd:sequence>
+      <xsd:element name="parametertype" type="docParamType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="parametername" type="docParamName" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docParamType" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="ref" type="refTextType" minOccurs="0" maxOccurs="1" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docParamName" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="ref" type="refTextType" minOccurs="0" maxOccurs="1" />
+    </xsd:sequence>
+    <xsd:attribute name="direction" type="DoxParamDir" use="optional" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docXRefSectType">
+    <xsd:sequence>
+      <xsd:element name="xreftitle" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="xrefdescription" type="descriptionType" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:string" /> 
+  </xsd:complexType>
+
+  <xsd:complexType name="docCopyType">
+    <xsd:sequence>
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect1" type="docSect1Type" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="internal" type="docInternalType" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="link" type="xsd:string" /> 
+  </xsd:complexType>
+
+  <xsd:complexType name="docBlockQuoteType">
+    <xsd:sequence>
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docParBlockType">
+    <xsd:sequence>
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docEmptyType"/>
+
+  <!-- Simple types -->
+
+  <xsd:simpleType name="DoxBool">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="yes" />
+      <xsd:enumeration value="no" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxGraphRelation">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="include" />
+      <xsd:enumeration value="usage" />
+      <xsd:enumeration value="template-instance" />
+      <xsd:enumeration value="public-inheritance" />
+      <xsd:enumeration value="protected-inheritance" />
+      <xsd:enumeration value="private-inheritance" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxRefKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="compound" />
+      <xsd:enumeration value="member" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxMemberKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="define" />
+      <xsd:enumeration value="property" />
+      <xsd:enumeration value="event" />
+      <xsd:enumeration value="variable" />
+      <xsd:enumeration value="typedef" />
+      <xsd:enumeration value="enum" />
+      <xsd:enumeration value="function" />
+      <xsd:enumeration value="signal" />
+      <xsd:enumeration value="prototype" />
+      <xsd:enumeration value="friend" />
+      <xsd:enumeration value="dcop" />
+      <xsd:enumeration value="slot" />
+      <xsd:enumeration value="interface" />
+      <xsd:enumeration value="service" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxProtectionKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="public" />
+      <xsd:enumeration value="protected" />
+      <xsd:enumeration value="private" />
+      <xsd:enumeration value="package" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxVirtualKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="non-virtual" />
+      <xsd:enumeration value="virtual" />
+      <xsd:enumeration value="pure-virtual" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxCompoundKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="class" />
+      <xsd:enumeration value="struct" />
+      <xsd:enumeration value="union" />
+      <xsd:enumeration value="interface" />
+      <xsd:enumeration value="protocol" />
+      <xsd:enumeration value="category" />
+      <xsd:enumeration value="exception" />
+      <xsd:enumeration value="service" />
+      <xsd:enumeration value="singleton" />
+      <xsd:enumeration value="module" />
+      <xsd:enumeration value="type" />
+      <xsd:enumeration value="file" />
+      <xsd:enumeration value="namespace" />
+      <xsd:enumeration value="group" />
+      <xsd:enumeration value="page" />
+      <xsd:enumeration value="example" />
+      <xsd:enumeration value="dir" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxSectionKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="user-defined" />
+      <xsd:enumeration value="public-type" />
+      <xsd:enumeration value="public-func" />
+      <xsd:enumeration value="public-attrib" />
+      <xsd:enumeration value="public-slot" />
+      <xsd:enumeration value="signal" />
+      <xsd:enumeration value="dcop-func" />
+      <xsd:enumeration value="property" />
+      <xsd:enumeration value="event" />
+      <xsd:enumeration value="public-static-func" />
+      <xsd:enumeration value="public-static-attrib" />
+      <xsd:enumeration value="protected-type" />
+      <xsd:enumeration value="protected-func" />
+      <xsd:enumeration value="protected-attrib" />
+      <xsd:enumeration value="protected-slot" />
+      <xsd:enumeration value="protected-static-func" />
+      <xsd:enumeration value="protected-static-attrib" />
+      <xsd:enumeration value="package-type" />
+      <xsd:enumeration value="package-func" />
+      <xsd:enumeration value="package-attrib" />
+      <xsd:enumeration value="package-static-func" />
+      <xsd:enumeration value="package-static-attrib" />
+      <xsd:enumeration value="private-type" />
+      <xsd:enumeration value="private-func" />
+      <xsd:enumeration value="private-attrib" />
+      <xsd:enumeration value="private-slot" />
+      <xsd:enumeration value="private-static-func" />
+      <xsd:enumeration value="private-static-attrib" />
+      <xsd:enumeration value="friend" />
+      <xsd:enumeration value="related" />
+      <xsd:enumeration value="define" />
+      <xsd:enumeration value="prototype" />
+      <xsd:enumeration value="typedef" />
+      <xsd:enumeration value="enum" />
+      <xsd:enumeration value="func" />
+      <xsd:enumeration value="var" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxHighlightClass">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="comment" />
+      <xsd:enumeration value="normal" />
+      <xsd:enumeration value="preprocessor" />
+      <xsd:enumeration value="keyword" />
+      <xsd:enumeration value="keywordtype" />
+      <xsd:enumeration value="keywordflow" />
+      <xsd:enumeration value="stringliteral" />
+      <xsd:enumeration value="charliteral" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxSimpleSectKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="see" />
+      <xsd:enumeration value="return" />
+      <xsd:enumeration value="author" />
+      <xsd:enumeration value="authors" />
+      <xsd:enumeration value="version" />
+      <xsd:enumeration value="since" />
+      <xsd:enumeration value="date" />
+      <xsd:enumeration value="note" />
+      <xsd:enumeration value="warning" />
+      <xsd:enumeration value="pre" />
+      <xsd:enumeration value="post" />
+      <xsd:enumeration value="copyright" />
+      <xsd:enumeration value="invariant" />
+      <xsd:enumeration value="remark" />
+      <xsd:enumeration value="attention" />
+      <xsd:enumeration value="par" />
+      <xsd:enumeration value="rcs" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxVersionNumber">
+    <xsd:restriction base="xsd:string">
+      <xsd:pattern value="\d+\.\d+.*" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxImageKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="html" />
+      <xsd:enumeration value="latex" />
+      <xsd:enumeration value="rtf" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxParamListKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="param" />
+      <xsd:enumeration value="retval" />
+      <xsd:enumeration value="exception" />
+      <xsd:enumeration value="templateparam" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxCharRange">
+    <xsd:restriction base="xsd:string">
+      <xsd:pattern value="[aeiouncAEIOUNC]" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxParamDir">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="in"/>
+      <xsd:enumeration value="out"/>
+      <xsd:enumeration value="inout"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxAccessor">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="retain"/>
+      <xsd:enumeration value="copy"/>
+      <xsd:enumeration value="assign"/>
+      <xsd:enumeration value="weak"/>
+      <xsd:enumeration value="strong"/>
+      <xsd:enumeration value="unretained"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+</xsd:schema>
+
diff --git a/contrib/neo_doxygen/tests/java-project/xml/dir_68267d1309a1af8e8297ef4c3efbcdba.xml b/contrib/neo_doxygen/tests/java-project/xml/dir_68267d1309a1af8e8297ef4c3efbcdba.xml
new file mode 100644 (file)
index 0000000..7113035
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+  <compounddef id="dir_68267d1309a1af8e8297ef4c3efbcdba" kind="dir">
+    <compoundname>src</compoundname>
+    <innerdir refid="dir_b8e0663afee48cb679b74bbd21bdf843">src/org</innerdir>
+    <briefdescription>
+    </briefdescription>
+    <detaileddescription>
+    </detaileddescription>
+    <location file="%SOURCE_DIRECTORY%/"/>
+  </compounddef>
+</doxygen>
diff --git a/contrib/neo_doxygen/tests/java-project/xml/dir_8c35fc67c36f89d827afb23e8c52a418.xml b/contrib/neo_doxygen/tests/java-project/xml/dir_8c35fc67c36f89d827afb23e8c52a418.xml
new file mode 100644 (file)
index 0000000..3d720f8
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+  <compounddef id="dir_8c35fc67c36f89d827afb23e8c52a418" kind="dir">
+    <compoundname>src/org/example</compoundname>
+    <innerdir refid="dir_ad5d6582648a7bbb3a301939a41e6c0b">src/org/example/foo</innerdir>
+    <briefdescription>
+    </briefdescription>
+    <detaileddescription>
+    </detaileddescription>
+    <location file="%SOURCE_DIRECTORY%/org/example/"/>
+  </compounddef>
+</doxygen>
diff --git a/contrib/neo_doxygen/tests/java-project/xml/dir_ad5d6582648a7bbb3a301939a41e6c0b.xml b/contrib/neo_doxygen/tests/java-project/xml/dir_ad5d6582648a7bbb3a301939a41e6c0b.xml
new file mode 100644 (file)
index 0000000..5280bb0
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+  <compounddef id="dir_ad5d6582648a7bbb3a301939a41e6c0b" kind="dir">
+    <compoundname>src/org/example/foo</compoundname>
+    <innerfile refid="_a_8java">A.java</innerfile>
+    <innerfile refid="_b_8java">B.java</innerfile>
+    <innerfile refid="_c_8java">C.java</innerfile>
+    <innerfile refid="_empty_class_8java">EmptyClass.java</innerfile>
+    <briefdescription>
+    </briefdescription>
+    <detaileddescription>
+    </detaileddescription>
+    <location file="%SOURCE_DIRECTORY%/org/example/foo/"/>
+  </compounddef>
+</doxygen>
diff --git a/contrib/neo_doxygen/tests/java-project/xml/dir_b8e0663afee48cb679b74bbd21bdf843.xml b/contrib/neo_doxygen/tests/java-project/xml/dir_b8e0663afee48cb679b74bbd21bdf843.xml
new file mode 100644 (file)
index 0000000..193e7cd
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+  <compounddef id="dir_b8e0663afee48cb679b74bbd21bdf843" kind="dir">
+    <compoundname>src/org</compoundname>
+    <innerdir refid="dir_8c35fc67c36f89d827afb23e8c52a418">src/org/example</innerdir>
+    <briefdescription>
+    </briefdescription>
+    <detaileddescription>
+    </detaileddescription>
+    <location file="%SOURCE_DIRECTORY%/org/"/>
+  </compounddef>
+</doxygen>
diff --git a/contrib/neo_doxygen/tests/java-project/xml/index.xml b/contrib/neo_doxygen/tests/java-project/xml/index.xml
new file mode 100644 (file)
index 0000000..cf3ded8
--- /dev/null
@@ -0,0 +1,39 @@
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygenindex xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="index.xsd" version="1.8.8">
+  <compound refid="classorg_1_1example_1_1foo_1_1_a" kind="class"><name>org::example::foo::A</name>
+    <member refid="classorg_1_1example_1_1foo_1_1_a_1add415ae4129969055d678c7e7e048852" kind="function"><name>bar</name></member>
+  </compound>
+  <compound refid="classorg_1_1example_1_1foo_1_1_b" kind="class"><name>org::example::foo::B</name>
+    <member refid="classorg_1_1example_1_1foo_1_1_b_1ac6b627949b10b9357eefc0cafcae1d87" kind="variable"><name>qux</name></member>
+    <member refid="classorg_1_1example_1_1foo_1_1_b_1a11e157943665cc9e3a9be1502ebeb3b5" kind="function"><name>bar</name></member>
+    <member refid="classorg_1_1example_1_1foo_1_1_b_1a733f4e076f29c7d0c41ed258199ea1d9" kind="function"><name>baz</name></member>
+  </compound>
+  <compound refid="interfaceorg_1_1example_1_1foo_1_1_c" kind="interface"><name>org::example::foo::C</name>
+    <member refid="interfaceorg_1_1example_1_1foo_1_1_c_1a4e97061eb40b045e820de05b33c43d21" kind="variable"><name>THE_ANSWER</name></member>
+    <member refid="interfaceorg_1_1example_1_1foo_1_1_c_1a28ac7ce349ebb3e4a7747a8dd951582b" kind="function"><name>baz</name></member>
+  </compound>
+  <compound refid="classorg_1_1example_1_1foo_1_1_empty_class" kind="class"><name>org::example::foo::EmptyClass</name>
+  </compound>
+  <compound refid="namespaceorg" kind="namespace"><name>org</name>
+  </compound>
+  <compound refid="namespaceorg_1_1example" kind="namespace"><name>org::example</name>
+  </compound>
+  <compound refid="namespaceorg_1_1example_1_1foo" kind="namespace"><name>org::example::foo</name>
+  </compound>
+  <compound refid="_a_8java" kind="file"><name>A.java</name>
+  </compound>
+  <compound refid="_b_8java" kind="file"><name>B.java</name>
+  </compound>
+  <compound refid="_c_8java" kind="file"><name>C.java</name>
+  </compound>
+  <compound refid="_empty_class_8java" kind="file"><name>EmptyClass.java</name>
+  </compound>
+  <compound refid="dir_8c35fc67c36f89d827afb23e8c52a418" kind="dir"><name>src/org/example</name>
+  </compound>
+  <compound refid="dir_ad5d6582648a7bbb3a301939a41e6c0b" kind="dir"><name>src/org/example/foo</name>
+  </compound>
+  <compound refid="dir_b8e0663afee48cb679b74bbd21bdf843" kind="dir"><name>src/org</name>
+  </compound>
+  <compound refid="dir_68267d1309a1af8e8297ef4c3efbcdba" kind="dir"><name>src</name>
+  </compound>
+</doxygenindex>
diff --git a/contrib/neo_doxygen/tests/java-project/xml/index.xsd b/contrib/neo_doxygen/tests/java-project/xml/index.xsd
new file mode 100644 (file)
index 0000000..d7ab2a9
--- /dev/null
@@ -0,0 +1,66 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+  <xsd:element name="doxygenindex" type="DoxygenType"/>
+
+  <xsd:complexType name="DoxygenType">
+    <xsd:sequence>
+      <xsd:element name="compound" type="CompoundType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="version" type="xsd:string" use="required"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="CompoundType">
+    <xsd:sequence>
+      <xsd:element name="name" type="xsd:string"/>
+      <xsd:element name="member" type="MemberType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="refid" type="xsd:string" use="required"/>
+    <xsd:attribute name="kind" type="CompoundKind" use="required"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="MemberType">
+    <xsd:sequence>
+      <xsd:element name="name" type="xsd:string"/>
+    </xsd:sequence>
+    <xsd:attribute name="refid" type="xsd:string" use="required"/>
+    <xsd:attribute name="kind" type="MemberKind" use="required"/>
+  </xsd:complexType>
+  
+  <xsd:simpleType name="CompoundKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="class"/>
+      <xsd:enumeration value="struct"/>
+      <xsd:enumeration value="union"/>
+      <xsd:enumeration value="interface"/>
+      <xsd:enumeration value="protocol"/>
+      <xsd:enumeration value="category"/>
+      <xsd:enumeration value="exception"/>
+      <xsd:enumeration value="file"/>
+      <xsd:enumeration value="namespace"/>
+      <xsd:enumeration value="group"/>
+      <xsd:enumeration value="page"/>
+      <xsd:enumeration value="example"/>
+      <xsd:enumeration value="dir"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="MemberKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="define"/>
+      <xsd:enumeration value="property"/>
+      <xsd:enumeration value="event"/>
+      <xsd:enumeration value="variable"/>
+      <xsd:enumeration value="typedef"/>
+      <xsd:enumeration value="enum"/>
+      <xsd:enumeration value="enumvalue"/>
+      <xsd:enumeration value="function"/>
+      <xsd:enumeration value="signal"/>
+      <xsd:enumeration value="prototype"/>
+      <xsd:enumeration value="friend"/>
+      <xsd:enumeration value="dcop"/>
+      <xsd:enumeration value="slot"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+</xsd:schema>
+
diff --git a/contrib/neo_doxygen/tests/java-project/xml/interfaceorg_1_1example_1_1foo_1_1_c.xml b/contrib/neo_doxygen/tests/java-project/xml/interfaceorg_1_1example_1_1foo_1_1_c.xml
new file mode 100644 (file)
index 0000000..aec6243
--- /dev/null
@@ -0,0 +1,60 @@
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+  <compounddef id="interfaceorg_1_1example_1_1foo_1_1_c" kind="interface" prot="public">
+    <compoundname>org::example::foo::C</compoundname>
+    <derivedcompoundref refid="classorg_1_1example_1_1foo_1_1_b" prot="public" virt="non-virtual">org.example.foo.B</derivedcompoundref>
+      <sectiondef kind="public-static-attrib">
+      <memberdef kind="variable" id="interfaceorg_1_1example_1_1foo_1_1_c_1a4e97061eb40b045e820de05b33c43d21" prot="public" static="yes" mutable="no">
+        <type>final long</type>
+        <definition>final long org.example.foo.C.THE_ANSWER</definition>
+        <argsstring></argsstring>
+        <name>THE_ANSWER</name>
+        <initializer>= 42L</initializer>
+        <briefdescription>
+        </briefdescription>
+        <detaileddescription>
+<para>“Answer to the Ultimate Question of Life, the Universe, and Everything.“ </para>        </detaileddescription>
+        <inbodydescription>
+        </inbodydescription>
+        <location file="%SOURCE_DIRECTORY%/org/example/foo/C.java" line="25" column="1" bodyfile="%SOURCE_DIRECTORY%/org/example/foo/C.java" bodystart="25" bodyend="-1"/>
+      </memberdef>
+      </sectiondef>
+      <sectiondef kind="public-func">
+      <memberdef kind="function" id="interfaceorg_1_1example_1_1foo_1_1_c_1a28ac7ce349ebb3e4a7747a8dd951582b" prot="public" static="no" const="no" explicit="no" inline="no" virt="non-virtual">
+        <type>void</type>
+        <definition>void org.example.foo.C.baz</definition>
+        <argsstring>()</argsstring>
+        <name>baz</name>
+        <reimplementedby refid="classorg_1_1example_1_1foo_1_1_b_1a733f4e076f29c7d0c41ed258199ea1d9">baz</reimplementedby>
+        <briefdescription>
+        </briefdescription>
+        <detaileddescription>
+<para><ref refid="classorg_1_1example_1_1foo_1_1_a" kindref="compound">A</ref> function with implicit modifiers. </para>        </detaileddescription>
+        <inbodydescription>
+        </inbodydescription>
+        <location file="%SOURCE_DIRECTORY%/org/example/foo/C.java" line="30" column="1"/>
+      </memberdef>
+      </sectiondef>
+    <briefdescription>
+    </briefdescription>
+    <detaileddescription>
+<para>An interface </para>    </detaileddescription>
+    <inheritancegraph>
+      <node id="10">
+        <label>org.example.foo.B</label>
+        <link refid="classorg_1_1example_1_1foo_1_1_b"/>
+        <childnode refid="9" relation="public-inheritance">
+        </childnode>
+      </node>
+      <node id="9">
+        <label>org.example.foo.C</label>
+        <link refid="interfaceorg_1_1example_1_1foo_1_1_c"/>
+      </node>
+    </inheritancegraph>
+    <location file="%SOURCE_DIRECTORY%/org/example/foo/C.java" line="21" column="1" bodyfile="%SOURCE_DIRECTORY%/org/example/foo/C.java" bodystart="21" bodyend="31"/>
+    <listofallmembers>
+      <member refid="interfaceorg_1_1example_1_1foo_1_1_c_1a28ac7ce349ebb3e4a7747a8dd951582b" prot="public" virt="non-virtual"><scope>org::example::foo::C</scope><name>baz</name></member>
+      <member refid="interfaceorg_1_1example_1_1foo_1_1_c_1a4e97061eb40b045e820de05b33c43d21" prot="public" virt="non-virtual"><scope>org::example::foo::C</scope><name>THE_ANSWER</name></member>
+    </listofallmembers>
+  </compounddef>
+</doxygen>
diff --git a/contrib/neo_doxygen/tests/java-project/xml/namespaceorg.xml b/contrib/neo_doxygen/tests/java-project/xml/namespaceorg.xml
new file mode 100644 (file)
index 0000000..43d6207
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+  <compounddef id="namespaceorg" kind="namespace">
+    <compoundname>org</compoundname>
+    <innernamespace refid="namespaceorg_1_1example">org::example</innernamespace>
+    <briefdescription>
+    </briefdescription>
+    <detaileddescription>
+    </detaileddescription>
+    <location file="[generated]" line="1" column="1"/>
+  </compounddef>
+</doxygen>
diff --git a/contrib/neo_doxygen/tests/java-project/xml/namespaceorg_1_1example.xml b/contrib/neo_doxygen/tests/java-project/xml/namespaceorg_1_1example.xml
new file mode 100644 (file)
index 0000000..ee8d878
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+  <compounddef id="namespaceorg_1_1example" kind="namespace">
+    <compoundname>org::example</compoundname>
+    <innernamespace refid="namespaceorg_1_1example_1_1foo">org::example::foo</innernamespace>
+    <briefdescription>
+    </briefdescription>
+    <detaileddescription>
+    </detaileddescription>
+    <location file="[generated]" line="1" column="1"/>
+  </compounddef>
+</doxygen>
diff --git a/contrib/neo_doxygen/tests/java-project/xml/namespaceorg_1_1example_1_1foo.xml b/contrib/neo_doxygen/tests/java-project/xml/namespaceorg_1_1example_1_1foo.xml
new file mode 100644 (file)
index 0000000..a307c92
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+  <compounddef id="namespaceorg_1_1example_1_1foo" kind="namespace">
+    <compoundname>org::example::foo</compoundname>
+    <innerclass refid="classorg_1_1example_1_1foo_1_1_a" prot="public">org::example::foo::A</innerclass>
+    <innerclass refid="classorg_1_1example_1_1foo_1_1_b" prot="public">org::example::foo::B</innerclass>
+    <innerclass refid="interfaceorg_1_1example_1_1foo_1_1_c" prot="public">org::example::foo::C</innerclass>
+    <innerclass refid="classorg_1_1example_1_1foo_1_1_empty_class" prot="package">org::example::foo::EmptyClass</innerclass>
+    <briefdescription>
+    </briefdescription>
+    <detaileddescription>
+    </detaileddescription>
+    <location file="%SOURCE_DIRECTORY%/org/example/foo/A.java" line="16" column="1"/>
+  </compounddef>
+</doxygen>
diff --git a/contrib/neo_doxygen/tests/root-namespace/Doxyfile b/contrib/neo_doxygen/tests/root-namespace/Doxyfile
new file mode 100644 (file)
index 0000000..bd06324
--- /dev/null
@@ -0,0 +1,2381 @@
+# Doxyfile 1.8.8
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "Test Project"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       =
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES                =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = YES
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  = src
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS          = *.c \
+                         *.cc \
+                         *.cxx \
+                         *.cpp \
+                         *.c++ \
+                         *.java \
+                         *.ii \
+                         *.ixx \
+                         *.ipp \
+                         *.i++ \
+                         *.inl \
+                         *.idl \
+                         *.ddl \
+                         *.odl \
+                         *.h \
+                         *.hh \
+                         *.hxx \
+                         *.hpp \
+                         *.h++ \
+                         *.cs \
+                         *.d \
+                         *.php \
+                         *.php4 \
+                         *.php5 \
+                         *.phtml \
+                         *.inc \
+                         *.m \
+                         *.markdown \
+                         *.md \
+                         *.mm \
+                         *.dox \
+                         *.py \
+                         *.f90 \
+                         *.f \
+                         *.for \
+                         *.tcl \
+                         *.vhd \
+                         *.vhdl \
+                         *.ucf \
+                         *.qsf \
+                         *.as \
+                         *.js
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = NO
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra stylesheet files is of importance (e.g. the last
+# stylesheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = YES
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT               = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+PLANTUML_JAR_PATH      =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP            = YES
diff --git a/contrib/neo_doxygen/tests/root-namespace/README.md b/contrib/neo_doxygen/tests/root-namespace/README.md
new file mode 100644 (file)
index 0000000..2a87fc7
--- /dev/null
@@ -0,0 +1,5 @@
+This directory contains a dummy Java project for testing purposes.
+
+To regenerate the XML output located in `xml`, run `make`. If the `Makefile`
+does not exists, you can regenerate it by running `make bootstrap` in the parent
+directory.
diff --git a/contrib/neo_doxygen/tests/root-namespace/src/Foo.java b/contrib/neo_doxygen/tests/root-namespace/src/Foo.java
new file mode 100644 (file)
index 0000000..9da779f
--- /dev/null
@@ -0,0 +1,19 @@
+/* This file is part of NIT ( http://www.nitlanguage.org ).
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * A class in the root namespace
+ */
+class Foo {}
diff --git a/contrib/neo_doxygen/tests/root-namespace/xml/_foo_8java.xml b/contrib/neo_doxygen/tests/root-namespace/xml/_foo_8java.xml
new file mode 100644 (file)
index 0000000..ad87211
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+  <compounddef id="_foo_8java" kind="file">
+    <compoundname>Foo.java</compoundname>
+    <innerclass refid="class_foo" prot="package">Foo</innerclass>
+    <briefdescription>
+    </briefdescription>
+    <detaileddescription>
+    </detaileddescription>
+    <location file="%SOURCE_DIRECTORY%/Foo.java"/>
+  </compounddef>
+</doxygen>
diff --git a/contrib/neo_doxygen/tests/root-namespace/xml/class_foo.xml b/contrib/neo_doxygen/tests/root-namespace/xml/class_foo.xml
new file mode 100644 (file)
index 0000000..3ee1155
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+  <compounddef id="class_foo" kind="class" prot="package">
+    <compoundname>Foo</compoundname>
+    <briefdescription>
+    </briefdescription>
+    <detaileddescription>
+<para>A class in the root namespace </para>    </detaileddescription>
+    <location file="%SOURCE_DIRECTORY%/Foo.java" line="19" column="1" bodyfile="%SOURCE_DIRECTORY%/Foo.java" bodystart="19" bodyend="19"/>
+    <listofallmembers>
+    </listofallmembers>
+  </compounddef>
+</doxygen>
diff --git a/contrib/neo_doxygen/tests/root-namespace/xml/combine.xslt b/contrib/neo_doxygen/tests/root-namespace/xml/combine.xslt
new file mode 100644 (file)
index 0000000..c148ee4
--- /dev/null
@@ -0,0 +1,15 @@
+<!-- XSLT script to combine the generated output into a single file. 
+     If you have xsltproc you could use:
+     xsltproc combine.xslt index.xml >all.xml
+-->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+  <xsl:output method="xml" version="1.0" indent="no" standalone="yes" />
+  <xsl:template match="/">
+    <doxygen version="{doxygenindex/@version}">
+      <!-- Load all doxgen generated xml files -->
+      <xsl:for-each select="doxygenindex/compound">
+        <xsl:copy-of select="document( concat( @refid, '.xml' ) )/doxygen/*" />
+      </xsl:for-each>
+    </doxygen>
+  </xsl:template>
+</xsl:stylesheet>
diff --git a/contrib/neo_doxygen/tests/root-namespace/xml/compound.xsd b/contrib/neo_doxygen/tests/root-namespace/xml/compound.xsd
new file mode 100644 (file)
index 0000000..86740f4
--- /dev/null
@@ -0,0 +1,1092 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+  <xsd:element name="doxygen" type="DoxygenType"/>
+
+  <!-- Complex types -->
+
+  <xsd:complexType name="DoxygenType">
+    <xsd:sequence maxOccurs="unbounded">
+      <xsd:element name="compounddef" type="compounddefType" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="version" type="DoxVersionNumber" use="required" />
+  </xsd:complexType>
+
+  <xsd:complexType name="compounddefType">
+    <xsd:sequence>
+      <xsd:element name="compoundname" type="xsd:string"/>
+      <xsd:element name="title" type="xsd:string" minOccurs="0" />
+      <xsd:element name="basecompoundref" type="compoundRefType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="derivedcompoundref" type="compoundRefType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="includes" type="incType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="includedby" type="incType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="incdepgraph" type="graphType" minOccurs="0" />
+      <xsd:element name="invincdepgraph" type="graphType" minOccurs="0" />
+      <xsd:element name="innerdir" type="refType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="innerfile" type="refType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="innerclass" type="refType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="innernamespace" type="refType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="innerpage" type="refType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="innergroup" type="refType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="templateparamlist" type="templateparamlistType" minOccurs="0" />
+      <xsd:element name="sectiondef" type="sectiondefType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" />
+      <xsd:element name="detaileddescription" type="descriptionType" minOccurs="0" />
+      <xsd:element name="inheritancegraph" type="graphType" minOccurs="0" />
+      <xsd:element name="collaborationgraph" type="graphType" minOccurs="0" />
+      <xsd:element name="programlisting" type="listingType" minOccurs="0" />
+      <xsd:element name="location" type="locationType" minOccurs="0" />
+      <xsd:element name="listofallmembers" type="listofallmembersType" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:string" />
+    <xsd:attribute name="kind" type="DoxCompoundKind" />
+    <xsd:attribute name="prot" type="DoxProtectionKind" />
+    <xsd:attribute name="final" type="DoxBool" use="optional"/>
+    <xsd:attribute name="sealed" type="DoxBool" use="optional"/>
+    <xsd:attribute name="abstract" type="DoxBool" use="optional"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="listofallmembersType">
+    <xsd:sequence>
+      <xsd:element name="member" type="memberRefType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="memberRefType">
+    <xsd:sequence>
+      <xsd:element name="scope" />
+      <xsd:element name="name" />
+    </xsd:sequence>
+    <xsd:attribute name="refid" type="xsd:string" />
+    <xsd:attribute name="prot" type="DoxProtectionKind" />
+    <xsd:attribute name="virt" type="DoxVirtualKind" />
+    <xsd:attribute name="ambiguityscope" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="compoundRefType">
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:string">
+        <xsd:attribute name="refid" type="xsd:string" use="optional" />
+        <xsd:attribute name="prot" type="DoxProtectionKind" />
+        <xsd:attribute name="virt" type="DoxVirtualKind" />
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+  <xsd:complexType name="reimplementType">
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:string">
+        <xsd:attribute name="refid" type="xsd:string" />
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+  <xsd:complexType name="incType">
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:string">
+        <xsd:attribute name="refid" type="xsd:string" />
+        <xsd:attribute name="local" type="DoxBool" />
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+  <xsd:complexType name="refType">
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:string">
+        <xsd:attribute name="refid" type="xsd:string" />
+        <xsd:attribute name="prot" type="DoxProtectionKind" use="optional"/>
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+  <xsd:complexType name="refTextType">
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:string">
+       <xsd:attribute name="refid" type="xsd:string" />
+       <xsd:attribute name="kindref" type="DoxRefKind" />
+       <xsd:attribute name="external" type="xsd:string" use="optional"/>
+       <xsd:attribute name="tooltip" type="xsd:string" use="optional"/>
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+  <xsd:complexType name="sectiondefType">
+    <xsd:sequence>
+      <xsd:element name="header" type="xsd:string" minOccurs="0" />
+      <xsd:element name="description" type="descriptionType" minOccurs="0" />
+      <xsd:element name="memberdef" type="memberdefType" maxOccurs="unbounded" />
+    </xsd:sequence>
+    <xsd:attribute name="kind" type="DoxSectionKind" />
+  </xsd:complexType>
+
+  <xsd:complexType name="memberdefType">
+    <xsd:sequence>
+      <xsd:element name="templateparamlist" type="templateparamlistType" minOccurs="0" />
+      <xsd:element name="type" type="linkedTextType" minOccurs="0" />
+      <xsd:element name="definition" minOccurs="0" />
+      <xsd:element name="argsstring" minOccurs="0" />
+      <xsd:element name="name" />
+      <xsd:element name="read" minOccurs="0" />
+      <xsd:element name="write" minOccurs="0" />
+      <xsd:element name="bitfield" minOccurs="0" />
+      <xsd:element name="reimplements" type="reimplementType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="reimplementedby" type="reimplementType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="param" type="paramType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="enumvalue" type="enumvalueType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="initializer" type="linkedTextType" minOccurs="0" />
+      <xsd:element name="exceptions" type="linkedTextType" minOccurs="0" />
+      <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" />
+      <xsd:element name="detaileddescription" type="descriptionType" minOccurs="0" />
+      <xsd:element name="inbodydescription" type="descriptionType" minOccurs="0" />
+      <xsd:element name="location" type="locationType" />
+      <xsd:element name="references" type="referenceType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="referencedby" type="referenceType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+    <xsd:attribute name="kind" type="DoxMemberKind" />
+    <xsd:attribute name="id" type="xsd:string" />
+    <xsd:attribute name="prot" type="DoxProtectionKind" />
+    <xsd:attribute name="static" type="DoxBool" />
+    <xsd:attribute name="const" type="DoxBool" use="optional"/>
+    <xsd:attribute name="explicit" type="DoxBool" use="optional"/>
+    <xsd:attribute name="inline" type="DoxBool" use="optional"/>
+    <xsd:attribute name="virt" type="DoxVirtualKind" use="optional"/>
+    <xsd:attribute name="volatile" type="DoxBool" use="optional"/>
+    <xsd:attribute name="mutable" type="DoxBool" use="optional"/>
+    <!-- Qt property -->
+    <xsd:attribute name="readable" type="DoxBool" use="optional"/>
+    <xsd:attribute name="writable" type="DoxBool" use="optional"/>
+    <!-- C++/CLI variable -->
+    <xsd:attribute name="initonly" type="DoxBool" use="optional"/>
+    <!-- C++/CLI and C# property -->
+    <xsd:attribute name="settable" type="DoxBool" use="optional"/>
+    <xsd:attribute name="gettable" type="DoxBool" use="optional"/>
+    <!-- C++/CLI function -->
+    <xsd:attribute name="final" type="DoxBool" use="optional"/>
+    <xsd:attribute name="sealed" type="DoxBool" use="optional"/>
+    <xsd:attribute name="new" type="DoxBool" use="optional"/>
+    <!-- C++/CLI event -->
+    <xsd:attribute name="add" type="DoxBool" use="optional"/>
+    <xsd:attribute name="remove" type="DoxBool" use="optional"/>
+    <xsd:attribute name="raise" type="DoxBool" use="optional"/>
+    <!-- Objective-C 2.0 protocol method -->
+    <xsd:attribute name="optional" type="DoxBool" use="optional"/>
+    <xsd:attribute name="required" type="DoxBool" use="optional"/>
+    <!-- Objective-C 2.0 property accessor -->
+    <xsd:attribute name="accessor" type="DoxAccessor" use="optional"/>
+    <!-- UNO IDL -->
+    <xsd:attribute name="attribute" type="DoxBool" use="optional"/>
+    <xsd:attribute name="property" type="DoxBool" use="optional"/>
+    <xsd:attribute name="readonly" type="DoxBool" use="optional"/>
+    <xsd:attribute name="bound" type="DoxBool" use="optional"/>
+    <xsd:attribute name="removable" type="DoxBool" use="optional"/>
+    <xsd:attribute name="contrained" type="DoxBool" use="optional"/>
+    <xsd:attribute name="transient" type="DoxBool" use="optional"/>
+    <xsd:attribute name="maybevoid" type="DoxBool" use="optional"/>
+    <xsd:attribute name="maybedefault" type="DoxBool" use="optional"/>
+    <xsd:attribute name="maybeambiguous" type="DoxBool" use="optional"/>
+
+  </xsd:complexType>
+
+  <xsd:complexType name="descriptionType" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="title" type="xsd:string" minOccurs="0"/>          
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect1" type="docSect1Type" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="internal" type="docInternalType" minOccurs="0" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="enumvalueType" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="name" />
+      <xsd:element name="initializer" type="linkedTextType" minOccurs="0" />
+      <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" />
+      <xsd:element name="detaileddescription" type="descriptionType" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:string" />
+    <xsd:attribute name="prot" type="DoxProtectionKind" />
+  </xsd:complexType>
+
+  <xsd:complexType name="templateparamlistType">
+    <xsd:sequence>
+      <xsd:element name="param" type="paramType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="paramType">
+    <xsd:sequence>
+      <xsd:element name="type" type="linkedTextType" minOccurs="0" />
+      <xsd:element name="declname" minOccurs="0" />
+      <xsd:element name="defname" minOccurs="0" />
+      <xsd:element name="array" minOccurs="0" />
+      <xsd:element name="defval" type="linkedTextType" minOccurs="0" />
+      <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="linkedTextType" mixed="true">
+    <xsd:sequence>
+    <xsd:element name="ref" type="refTextType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="graphType">
+    <xsd:sequence>
+      <xsd:element name="node" type="nodeType" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="nodeType">
+    <xsd:sequence>
+      <xsd:element name="label" />
+      <xsd:element name="link" type="linkType" minOccurs="0" />
+      <xsd:element name="childnode" type="childnodeType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="childnodeType">
+    <xsd:sequence>
+      <xsd:element name="edgelabel" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="refid" type="xsd:string" />
+    <xsd:attribute name="relation" type="DoxGraphRelation" />
+  </xsd:complexType>
+
+  <xsd:complexType name="linkType">
+    <xsd:attribute name="refid" type="xsd:string" />
+    <xsd:attribute name="external" type="xsd:string" use="optional"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="listingType">
+    <xsd:sequence>
+      <xsd:element name="codeline" type="codelineType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="codelineType">
+    <xsd:sequence>
+      <xsd:element name="highlight" type="highlightType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+    <xsd:attribute name="lineno" type="xsd:integer" />
+    <xsd:attribute name="refid" type="xsd:string" />
+    <xsd:attribute name="refkind" type="DoxRefKind" />
+    <xsd:attribute name="external" type="DoxBool" />
+  </xsd:complexType>
+
+  <xsd:complexType name="highlightType" mixed="true">
+    <xsd:choice minOccurs="0" maxOccurs="unbounded">
+      <xsd:element name="sp" />
+      <xsd:element name="ref" type="refTextType" />
+    </xsd:choice>
+    <xsd:attribute name="class" type="DoxHighlightClass" />
+  </xsd:complexType>
+
+  <xsd:complexType name="referenceType" mixed="true">
+    <xsd:attribute name="refid" type="xsd:string" />
+    <xsd:attribute name="compoundref" type="xsd:string" use="optional" />
+    <xsd:attribute name="startline" type="xsd:integer" />
+    <xsd:attribute name="endline" type="xsd:integer" />
+  </xsd:complexType>
+
+  <xsd:complexType name="locationType">
+    <xsd:attribute name="file" type="xsd:string" />
+    <xsd:attribute name="line" type="xsd:integer" />
+    <xsd:attribute name="column" type="xsd:integer" use="optional"/>
+    <xsd:attribute name="bodyfile" type="xsd:string" />
+    <xsd:attribute name="bodystart" type="xsd:integer" />
+    <xsd:attribute name="bodyend" type="xsd:integer" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docSect1Type" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="title" type="xsd:string" />       
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect2" type="docSect2Type" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="internal" type="docInternalS1Type" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docSect2Type" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="title" type="xsd:string" />       
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect3" type="docSect3Type" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="internal" type="docInternalS2Type" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docSect3Type" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="title" type="xsd:string" />       
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect4" type="docSect4Type" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="internal" type="docInternalS3Type" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docSect4Type" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="title" type="xsd:string" />       
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="internal" type="docInternalS4Type" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docInternalType" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="para"  type="docParaType"  minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect1" type="docSect1Type" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docInternalS1Type" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="para"  type="docParaType"  minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect2" type="docSect2Type" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docInternalS2Type" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="para"  type="docParaType"  minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect3" type="docSect3Type" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docInternalS3Type" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="para"  type="docParaType"  minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect3" type="docSect4Type" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docInternalS4Type" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="para"  type="docParaType"  minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+  <xsd:group name="docTitleCmdGroup">
+    <xsd:choice>
+      <xsd:element name="ulink" type="docURLLink" />
+      <xsd:element name="bold" type="docMarkupType" />
+      <xsd:element name="emphasis" type="docMarkupType" />
+      <xsd:element name="computeroutput" type="docMarkupType" />
+      <xsd:element name="subscript" type="docMarkupType" />
+      <xsd:element name="superscript" type="docMarkupType" />
+      <xsd:element name="center" type="docMarkupType" />
+      <xsd:element name="small" type="docMarkupType" />
+      <xsd:element name="htmlonly" type="xsd:string" />
+      <xsd:element name="manonly" type="xsd:string" />
+      <xsd:element name="xmlonly" type="xsd:string" />
+      <xsd:element name="rtfonly" type="xsd:string" />
+      <xsd:element name="latexonly" type="xsd:string" />
+      <xsd:element name="dot" type="xsd:string" />
+      <xsd:element name="plantuml" type="xsd:string" />
+      <xsd:element name="anchor" type="docAnchorType" />
+      <xsd:element name="formula" type="docFormulaType" />
+      <xsd:element name="ref" type="docRefTextType" />
+      <xsd:element name="nonbreakablespace" type="docEmptyType" />
+      <xsd:element name="iexcl" type="docEmptyType" />
+      <xsd:element name="cent" type="docEmptyType" />
+      <xsd:element name="pound" type="docEmptyType" />
+      <xsd:element name="curren" type="docEmptyType" />
+      <xsd:element name="yen" type="docEmptyType" />
+      <xsd:element name="brvbar" type="docEmptyType" />
+      <xsd:element name="sect" type="docEmptyType" />
+      <xsd:element name="umlaut" type="docEmptyType" />
+      <xsd:element name="copy" type="docEmptyType" />
+      <xsd:element name="ordf" type="docEmptyType" />
+      <xsd:element name="laquo" type="docEmptyType" />
+      <xsd:element name="not" type="docEmptyType" />
+      <xsd:element name="shy" type="docEmptyType" />
+      <xsd:element name="registered" type="docEmptyType" />
+      <xsd:element name="macr" type="docEmptyType" />
+      <xsd:element name="deg" type="docEmptyType" />
+      <xsd:element name="plusmn" type="docEmptyType" />
+      <xsd:element name="sup2" type="docEmptyType" />
+      <xsd:element name="sup3" type="docEmptyType" />
+      <xsd:element name="acute" type="docEmptyType" />
+      <xsd:element name="micro" type="docEmptyType" />
+      <xsd:element name="para" type="docEmptyType" />
+      <xsd:element name="middot" type="docEmptyType" />
+      <xsd:element name="cedil" type="docEmptyType" />
+      <xsd:element name="sup1" type="docEmptyType" />
+      <xsd:element name="ordm" type="docEmptyType" />
+      <xsd:element name="raquo" type="docEmptyType" />
+      <xsd:element name="frac14" type="docEmptyType" />
+      <xsd:element name="frac12" type="docEmptyType" />
+      <xsd:element name="frac34" type="docEmptyType" />
+      <xsd:element name="iquest" type="docEmptyType" />
+      <xsd:element name="Agrave" type="docEmptyType" />
+      <xsd:element name="Aacute" type="docEmptyType" />
+      <xsd:element name="Acirc" type="docEmptyType" />
+      <xsd:element name="Atilde" type="docEmptyType" />
+      <xsd:element name="Aumlaut" type="docEmptyType" />
+      <xsd:element name="Aring" type="docEmptyType" />
+      <xsd:element name="AElig" type="docEmptyType" />
+      <xsd:element name="Ccedil" type="docEmptyType" />
+      <xsd:element name="Egrave" type="docEmptyType" />
+      <xsd:element name="Eacute" type="docEmptyType" />
+      <xsd:element name="Ecirc" type="docEmptyType" />
+      <xsd:element name="Eumlaut" type="docEmptyType" />
+      <xsd:element name="Igrave" type="docEmptyType" />
+      <xsd:element name="Iacute" type="docEmptyType" />
+      <xsd:element name="Icirc" type="docEmptyType" />
+      <xsd:element name="Iumlaut" type="docEmptyType" />
+      <xsd:element name="ETH" type="docEmptyType" />
+      <xsd:element name="Ntilde" type="docEmptyType" />
+      <xsd:element name="Ograve" type="docEmptyType" />
+      <xsd:element name="Oacute" type="docEmptyType" />
+      <xsd:element name="Ocirc" type="docEmptyType" />
+      <xsd:element name="Otilde" type="docEmptyType" />
+      <xsd:element name="Oumlaut" type="docEmptyType" />
+      <xsd:element name="times" type="docEmptyType" />
+      <xsd:element name="Oslash" type="docEmptyType" />
+      <xsd:element name="Ugrave" type="docEmptyType" />
+      <xsd:element name="Uacute" type="docEmptyType" />
+      <xsd:element name="Ucirc" type="docEmptyType" />
+      <xsd:element name="Uumlaut" type="docEmptyType" />
+      <xsd:element name="Yacute" type="docEmptyType" />
+      <xsd:element name="THORN" type="docEmptyType" />
+      <xsd:element name="szlig" type="docEmptyType" />
+      <xsd:element name="agrave" type="docEmptyType" />
+      <xsd:element name="aacute" type="docEmptyType" />
+      <xsd:element name="acirc" type="docEmptyType" />
+      <xsd:element name="atilde" type="docEmptyType" />
+      <xsd:element name="aumlaut" type="docEmptyType" />
+      <xsd:element name="aring" type="docEmptyType" />
+      <xsd:element name="aelig" type="docEmptyType" />
+      <xsd:element name="ccedil" type="docEmptyType" />
+      <xsd:element name="egrave" type="docEmptyType" />
+      <xsd:element name="eacute" type="docEmptyType" />
+      <xsd:element name="ecirc" type="docEmptyType" />
+      <xsd:element name="eumlaut" type="docEmptyType" />
+      <xsd:element name="igrave" type="docEmptyType" />
+      <xsd:element name="iacute" type="docEmptyType" />
+      <xsd:element name="icirc" type="docEmptyType" />
+      <xsd:element name="iumlaut" type="docEmptyType" />
+      <xsd:element name="eth" type="docEmptyType" />
+      <xsd:element name="ntilde" type="docEmptyType" />
+      <xsd:element name="ograve" type="docEmptyType" />
+      <xsd:element name="oacute" type="docEmptyType" />
+      <xsd:element name="ocirc" type="docEmptyType" />
+      <xsd:element name="otilde" type="docEmptyType" />
+      <xsd:element name="oumlaut" type="docEmptyType" />
+      <xsd:element name="divide" type="docEmptyType" />
+      <xsd:element name="oslash" type="docEmptyType" />
+      <xsd:element name="ugrave" type="docEmptyType" />
+      <xsd:element name="uacute" type="docEmptyType" />
+      <xsd:element name="ucirc" type="docEmptyType" />
+      <xsd:element name="uumlaut" type="docEmptyType" />
+      <xsd:element name="yacute" type="docEmptyType" />
+      <xsd:element name="thorn" type="docEmptyType" />
+      <xsd:element name="yumlaut" type="docEmptyType" />
+      <xsd:element name="fnof" type="docEmptyType" />
+      <xsd:element name="Alpha" type="docEmptyType" />
+      <xsd:element name="Beta" type="docEmptyType" />
+      <xsd:element name="Gamma" type="docEmptyType" />
+      <xsd:element name="Delta" type="docEmptyType" />
+      <xsd:element name="Epsilon" type="docEmptyType" />
+      <xsd:element name="Zeta" type="docEmptyType" />
+      <xsd:element name="Eta" type="docEmptyType" />
+      <xsd:element name="Theta" type="docEmptyType" />
+      <xsd:element name="Iota" type="docEmptyType" />
+      <xsd:element name="Kappa" type="docEmptyType" />
+      <xsd:element name="Lambda" type="docEmptyType" />
+      <xsd:element name="Mu" type="docEmptyType" />
+      <xsd:element name="Nu" type="docEmptyType" />
+      <xsd:element name="Xi" type="docEmptyType" />
+      <xsd:element name="Omicron" type="docEmptyType" />
+      <xsd:element name="Pi" type="docEmptyType" />
+      <xsd:element name="Rho" type="docEmptyType" />
+      <xsd:element name="Sigma" type="docEmptyType" />
+      <xsd:element name="Tau" type="docEmptyType" />
+      <xsd:element name="Upsilon" type="docEmptyType" />
+      <xsd:element name="Phi" type="docEmptyType" />
+      <xsd:element name="Chi" type="docEmptyType" />
+      <xsd:element name="Psi" type="docEmptyType" />
+      <xsd:element name="Omega" type="docEmptyType" />
+      <xsd:element name="alpha" type="docEmptyType" />
+      <xsd:element name="beta" type="docEmptyType" />
+      <xsd:element name="gamma" type="docEmptyType" />
+      <xsd:element name="delta" type="docEmptyType" />
+      <xsd:element name="epsilon" type="docEmptyType" />
+      <xsd:element name="zeta" type="docEmptyType" />
+      <xsd:element name="eta" type="docEmptyType" />
+      <xsd:element name="theta" type="docEmptyType" />
+      <xsd:element name="iota" type="docEmptyType" />
+      <xsd:element name="kappa" type="docEmptyType" />
+      <xsd:element name="lambda" type="docEmptyType" />
+      <xsd:element name="mu" type="docEmptyType" />
+      <xsd:element name="nu" type="docEmptyType" />
+      <xsd:element name="xi" type="docEmptyType" />
+      <xsd:element name="omicron" type="docEmptyType" />
+      <xsd:element name="pi" type="docEmptyType" />
+      <xsd:element name="rho" type="docEmptyType" />
+      <xsd:element name="sigmaf" type="docEmptyType" />
+      <xsd:element name="sigma" type="docEmptyType" />
+      <xsd:element name="tau" type="docEmptyType" />
+      <xsd:element name="upsilon" type="docEmptyType" />
+      <xsd:element name="phi" type="docEmptyType" />
+      <xsd:element name="chi" type="docEmptyType" />
+      <xsd:element name="psi" type="docEmptyType" />
+      <xsd:element name="omega" type="docEmptyType" />
+      <xsd:element name="thetasym" type="docEmptyType" />
+      <xsd:element name="upsih" type="docEmptyType" />
+      <xsd:element name="piv" type="docEmptyType" />
+      <xsd:element name="bull" type="docEmptyType" />
+      <xsd:element name="hellip" type="docEmptyType" />
+      <xsd:element name="prime" type="docEmptyType" />
+      <xsd:element name="Prime" type="docEmptyType" />
+      <xsd:element name="oline" type="docEmptyType" />
+      <xsd:element name="frasl" type="docEmptyType" />
+      <xsd:element name="weierp" type="docEmptyType" />
+      <xsd:element name="image" type="docEmptyType" />
+      <xsd:element name="real" type="docEmptyType" />
+      <xsd:element name="trademark" type="docEmptyType" />
+      <xsd:element name="alefsym" type="docEmptyType" />
+      <xsd:element name="larr" type="docEmptyType" />
+      <xsd:element name="uarr" type="docEmptyType" />
+      <xsd:element name="rarr" type="docEmptyType" />
+      <xsd:element name="darr" type="docEmptyType" />
+      <xsd:element name="harr" type="docEmptyType" />
+      <xsd:element name="crarr" type="docEmptyType" />
+      <xsd:element name="lArr" type="docEmptyType" />
+      <xsd:element name="uArr" type="docEmptyType" />
+      <xsd:element name="rArr" type="docEmptyType" />
+      <xsd:element name="dArr" type="docEmptyType" />
+      <xsd:element name="hArr" type="docEmptyType" />
+      <xsd:element name="forall" type="docEmptyType" />
+      <xsd:element name="part" type="docEmptyType" />
+      <xsd:element name="exist" type="docEmptyType" />
+      <xsd:element name="empty" type="docEmptyType" />
+      <xsd:element name="nabla" type="docEmptyType" />
+      <xsd:element name="isin" type="docEmptyType" />
+      <xsd:element name="notin" type="docEmptyType" />
+      <xsd:element name="ni" type="docEmptyType" />
+      <xsd:element name="prod" type="docEmptyType" />
+      <xsd:element name="sum" type="docEmptyType" />
+      <xsd:element name="minus" type="docEmptyType" />
+      <xsd:element name="lowast" type="docEmptyType" />
+      <xsd:element name="radic" type="docEmptyType" />
+      <xsd:element name="prop" type="docEmptyType" />
+      <xsd:element name="infin" type="docEmptyType" />
+      <xsd:element name="ang" type="docEmptyType" />
+      <xsd:element name="and" type="docEmptyType" />
+      <xsd:element name="or" type="docEmptyType" />
+      <xsd:element name="cap" type="docEmptyType" />
+      <xsd:element name="cup" type="docEmptyType" />
+      <xsd:element name="int" type="docEmptyType" />
+      <xsd:element name="there4" type="docEmptyType" />
+      <xsd:element name="sim" type="docEmptyType" />
+      <xsd:element name="cong" type="docEmptyType" />
+      <xsd:element name="asymp" type="docEmptyType" />
+      <xsd:element name="ne" type="docEmptyType" />
+      <xsd:element name="equiv" type="docEmptyType" />
+      <xsd:element name="le" type="docEmptyType" />
+      <xsd:element name="ge" type="docEmptyType" />
+      <xsd:element name="sub" type="docEmptyType" />
+      <xsd:element name="sup" type="docEmptyType" />
+      <xsd:element name="nsub" type="docEmptyType" />
+      <xsd:element name="sube" type="docEmptyType" />
+      <xsd:element name="supe" type="docEmptyType" />
+      <xsd:element name="oplus" type="docEmptyType" />
+      <xsd:element name="otimes" type="docEmptyType" />
+      <xsd:element name="perp" type="docEmptyType" />
+      <xsd:element name="sdot" type="docEmptyType" />
+      <xsd:element name="lceil" type="docEmptyType" />
+      <xsd:element name="rceil" type="docEmptyType" />
+      <xsd:element name="lfloor" type="docEmptyType" />
+      <xsd:element name="rfloor" type="docEmptyType" />
+      <xsd:element name="lang" type="docEmptyType" />
+      <xsd:element name="rang" type="docEmptyType" />
+      <xsd:element name="loz" type="docEmptyType" />
+      <xsd:element name="spades" type="docEmptyType" />
+      <xsd:element name="clubs" type="docEmptyType" />
+      <xsd:element name="hearts" type="docEmptyType" />
+      <xsd:element name="diams" type="docEmptyType" />
+      <xsd:element name="OElig" type="docEmptyType" />
+      <xsd:element name="oelig" type="docEmptyType" />
+      <xsd:element name="Scaron" type="docEmptyType" />
+      <xsd:element name="scaron" type="docEmptyType" />
+      <xsd:element name="Yumlaut" type="docEmptyType" />
+      <xsd:element name="circ" type="docEmptyType" />
+      <xsd:element name="tilde" type="docEmptyType" />
+      <xsd:element name="ensp" type="docEmptyType" />
+      <xsd:element name="emsp" type="docEmptyType" />
+      <xsd:element name="thinsp" type="docEmptyType" />
+      <xsd:element name="zwnj" type="docEmptyType" />
+      <xsd:element name="zwj" type="docEmptyType" />
+      <xsd:element name="lrm" type="docEmptyType" />
+      <xsd:element name="rlm" type="docEmptyType" />
+      <xsd:element name="ndash" type="docEmptyType" />
+      <xsd:element name="mdash" type="docEmptyType" />
+      <xsd:element name="lsquo" type="docEmptyType" />
+      <xsd:element name="rsquo" type="docEmptyType" />
+      <xsd:element name="sbquo" type="docEmptyType" />
+      <xsd:element name="ldquo" type="docEmptyType" />
+      <xsd:element name="rdquo" type="docEmptyType" />
+      <xsd:element name="bdquo" type="docEmptyType" />
+      <xsd:element name="dagger" type="docEmptyType" />
+      <xsd:element name="Dagger" type="docEmptyType" />
+      <xsd:element name="permil" type="docEmptyType" />
+      <xsd:element name="lsaquo" type="docEmptyType" />
+      <xsd:element name="rsaquo" type="docEmptyType" />
+      <xsd:element name="euro" type="docEmptyType" />
+      <xsd:element name="trademark" type="docEmptyType" />
+    </xsd:choice>
+  </xsd:group>
+
+  <xsd:complexType name="docTitleType" mixed="true">
+    <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+  </xsd:complexType>
+
+  <xsd:group name="docCmdGroup">
+    <xsd:choice>
+      <xsd:group ref="docTitleCmdGroup"/>
+      <xsd:element name="linebreak" type="docEmptyType" />
+      <xsd:element name="hruler" type="docEmptyType" />
+      <xsd:element name="preformatted" type="docMarkupType" />
+      <xsd:element name="programlisting" type="listingType" />
+      <xsd:element name="verbatim" type="xsd:string" />
+      <xsd:element name="indexentry" type="docIndexEntryType" />
+      <xsd:element name="orderedlist" type="docListType" />
+      <xsd:element name="itemizedlist" type="docListType" />
+      <xsd:element name="simplesect" type="docSimpleSectType" />
+      <xsd:element name="title" type="docTitleType" />
+      <xsd:element name="variablelist" type="docVariableListType" />
+      <xsd:element name="table" type="docTableType" />
+      <xsd:element name="heading" type="docHeadingType" />
+      <xsd:element name="image" type="docImageType" />
+      <xsd:element name="dotfile" type="docFileType" />
+      <xsd:element name="mscfile" type="docFileType" />
+      <xsd:element name="diafile" type="docFileType" />
+      <xsd:element name="toclist" type="docTocListType" />
+      <xsd:element name="language" type="docLanguageType" />
+      <xsd:element name="parameterlist" type="docParamListType" />
+      <xsd:element name="xrefsect" type="docXRefSectType" />
+      <xsd:element name="copydoc" type="docCopyType" />
+      <xsd:element name="blockquote" type="docBlockQuoteType" />
+      <xsd:element name="parblock" type="docParBlockType" />
+    </xsd:choice>
+  </xsd:group>
+
+  <xsd:complexType name="docParaType" mixed="true">
+    <xsd:group ref="docCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docMarkupType" mixed="true">
+    <xsd:group ref="docCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docURLLink" mixed="true">
+    <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+    <xsd:attribute name="url" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docAnchorType" mixed="true">
+    <xsd:attribute name="id" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docFormulaType" mixed="true">
+    <xsd:attribute name="id" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docIndexEntryType">
+    <xsd:sequence>
+      <xsd:element name="primaryie" type="xsd:string" />
+      <xsd:element name="secondaryie" type="xsd:string" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docListType">
+    <xsd:sequence>
+      <xsd:element name="listitem" type="docListItemType" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docListItemType">
+    <xsd:sequence>
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docSimpleSectType">
+    <xsd:sequence>
+      <xsd:element name="title" type="docTitleType" minOccurs="0" />
+      <xsd:sequence minOccurs="0" maxOccurs="unbounded">
+        <xsd:element name="para" type="docParaType" minOccurs="1" maxOccurs="unbounded" />
+      </xsd:sequence>
+    </xsd:sequence>
+    <xsd:attribute name="kind" type="DoxSimpleSectKind" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docVarListEntryType">
+    <xsd:sequence>
+      <xsd:element name="term" type="docTitleType" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:group name="docVariableListGroup">
+    <xsd:sequence>
+      <xsd:element name="varlistentry" type="docVarListEntryType" />
+      <xsd:element name="listitem" type="docListItemType" />
+    </xsd:sequence>
+  </xsd:group>
+
+  <xsd:complexType name="docVariableListType">
+    <xsd:sequence>
+      <xsd:group ref="docVariableListGroup" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docRefTextType" mixed="true">
+    <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+    <xsd:attribute name="refid" type="xsd:string" />
+    <xsd:attribute name="kindref" type="DoxRefKind" />
+    <xsd:attribute name="external" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docTableType">
+    <xsd:sequence>
+      <xsd:element name="row" type="docRowType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="caption" type="docCaptionType" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="rows" type="xsd:integer" />
+    <xsd:attribute name="cols" type="xsd:integer" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docRowType">
+    <xsd:sequence>
+      <xsd:element name="entry" type="docEntryType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docEntryType">
+    <xsd:sequence>
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+    <xsd:attribute name="thead" type="DoxBool" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docCaptionType" mixed="true">
+    <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docHeadingType" mixed="true">
+    <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+    <xsd:attribute name="level" type="xsd:integer" /> <!-- todo: range 1-6 -->
+  </xsd:complexType>
+
+  <xsd:complexType name="docImageType" mixed="true">
+    <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+    <xsd:attribute name="type" type="DoxImageKind" /> 
+    <xsd:attribute name="name" type="xsd:string" /> 
+    <xsd:attribute name="width" type="xsd:string" /> 
+    <xsd:attribute name="height" type="xsd:string" /> 
+  </xsd:complexType>
+
+  <xsd:complexType name="docFileType" mixed="true">
+    <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+    <xsd:attribute name="name" type="xsd:string" /> 
+  </xsd:complexType>
+
+  <xsd:complexType name="docTocItemType" mixed="true">
+    <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+    <xsd:attribute name="id" type="xsd:string" /> 
+  </xsd:complexType>
+
+  <xsd:complexType name="docTocListType">
+    <xsd:sequence>
+      <xsd:element name="tocitem" type="docTocItemType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docLanguageType">
+    <xsd:sequence>
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+    <xsd:attribute name="langid" type="xsd:string" /> 
+  </xsd:complexType>
+
+  <xsd:complexType name="docParamListType">
+    <xsd:sequence>
+      <xsd:element name="parameteritem" type="docParamListItem" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+    <xsd:attribute name="kind" type="DoxParamListKind" /> 
+  </xsd:complexType>
+
+  <xsd:complexType name="docParamListItem">
+    <xsd:sequence>
+      <xsd:element name="parameternamelist" type="docParamNameList" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="parameterdescription" type="descriptionType" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docParamNameList">
+    <xsd:sequence>
+      <xsd:element name="parametertype" type="docParamType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="parametername" type="docParamName" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docParamType" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="ref" type="refTextType" minOccurs="0" maxOccurs="1" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docParamName" mixed="true">
+    <xsd:sequence>
+      <xsd:element name="ref" type="refTextType" minOccurs="0" maxOccurs="1" />
+    </xsd:sequence>
+    <xsd:attribute name="direction" type="DoxParamDir" use="optional" />
+  </xsd:complexType>
+
+  <xsd:complexType name="docXRefSectType">
+    <xsd:sequence>
+      <xsd:element name="xreftitle" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="xrefdescription" type="descriptionType" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:string" /> 
+  </xsd:complexType>
+
+  <xsd:complexType name="docCopyType">
+    <xsd:sequence>
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="sect1" type="docSect1Type" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="internal" type="docInternalType" minOccurs="0" />
+    </xsd:sequence>
+    <xsd:attribute name="link" type="xsd:string" /> 
+  </xsd:complexType>
+
+  <xsd:complexType name="docBlockQuoteType">
+    <xsd:sequence>
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docParBlockType">
+    <xsd:sequence>
+      <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="docEmptyType"/>
+
+  <!-- Simple types -->
+
+  <xsd:simpleType name="DoxBool">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="yes" />
+      <xsd:enumeration value="no" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxGraphRelation">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="include" />
+      <xsd:enumeration value="usage" />
+      <xsd:enumeration value="template-instance" />
+      <xsd:enumeration value="public-inheritance" />
+      <xsd:enumeration value="protected-inheritance" />
+      <xsd:enumeration value="private-inheritance" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxRefKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="compound" />
+      <xsd:enumeration value="member" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxMemberKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="define" />
+      <xsd:enumeration value="property" />
+      <xsd:enumeration value="event" />
+      <xsd:enumeration value="variable" />
+      <xsd:enumeration value="typedef" />
+      <xsd:enumeration value="enum" />
+      <xsd:enumeration value="function" />
+      <xsd:enumeration value="signal" />
+      <xsd:enumeration value="prototype" />
+      <xsd:enumeration value="friend" />
+      <xsd:enumeration value="dcop" />
+      <xsd:enumeration value="slot" />
+      <xsd:enumeration value="interface" />
+      <xsd:enumeration value="service" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxProtectionKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="public" />
+      <xsd:enumeration value="protected" />
+      <xsd:enumeration value="private" />
+      <xsd:enumeration value="package" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxVirtualKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="non-virtual" />
+      <xsd:enumeration value="virtual" />
+      <xsd:enumeration value="pure-virtual" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxCompoundKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="class" />
+      <xsd:enumeration value="struct" />
+      <xsd:enumeration value="union" />
+      <xsd:enumeration value="interface" />
+      <xsd:enumeration value="protocol" />
+      <xsd:enumeration value="category" />
+      <xsd:enumeration value="exception" />
+      <xsd:enumeration value="service" />
+      <xsd:enumeration value="singleton" />
+      <xsd:enumeration value="module" />
+      <xsd:enumeration value="type" />
+      <xsd:enumeration value="file" />
+      <xsd:enumeration value="namespace" />
+      <xsd:enumeration value="group" />
+      <xsd:enumeration value="page" />
+      <xsd:enumeration value="example" />
+      <xsd:enumeration value="dir" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxSectionKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="user-defined" />
+      <xsd:enumeration value="public-type" />
+      <xsd:enumeration value="public-func" />
+      <xsd:enumeration value="public-attrib" />
+      <xsd:enumeration value="public-slot" />
+      <xsd:enumeration value="signal" />
+      <xsd:enumeration value="dcop-func" />
+      <xsd:enumeration value="property" />
+      <xsd:enumeration value="event" />
+      <xsd:enumeration value="public-static-func" />
+      <xsd:enumeration value="public-static-attrib" />
+      <xsd:enumeration value="protected-type" />
+      <xsd:enumeration value="protected-func" />
+      <xsd:enumeration value="protected-attrib" />
+      <xsd:enumeration value="protected-slot" />
+      <xsd:enumeration value="protected-static-func" />
+      <xsd:enumeration value="protected-static-attrib" />
+      <xsd:enumeration value="package-type" />
+      <xsd:enumeration value="package-func" />
+      <xsd:enumeration value="package-attrib" />
+      <xsd:enumeration value="package-static-func" />
+      <xsd:enumeration value="package-static-attrib" />
+      <xsd:enumeration value="private-type" />
+      <xsd:enumeration value="private-func" />
+      <xsd:enumeration value="private-attrib" />
+      <xsd:enumeration value="private-slot" />
+      <xsd:enumeration value="private-static-func" />
+      <xsd:enumeration value="private-static-attrib" />
+      <xsd:enumeration value="friend" />
+      <xsd:enumeration value="related" />
+      <xsd:enumeration value="define" />
+      <xsd:enumeration value="prototype" />
+      <xsd:enumeration value="typedef" />
+      <xsd:enumeration value="enum" />
+      <xsd:enumeration value="func" />
+      <xsd:enumeration value="var" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxHighlightClass">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="comment" />
+      <xsd:enumeration value="normal" />
+      <xsd:enumeration value="preprocessor" />
+      <xsd:enumeration value="keyword" />
+      <xsd:enumeration value="keywordtype" />
+      <xsd:enumeration value="keywordflow" />
+      <xsd:enumeration value="stringliteral" />
+      <xsd:enumeration value="charliteral" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxSimpleSectKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="see" />
+      <xsd:enumeration value="return" />
+      <xsd:enumeration value="author" />
+      <xsd:enumeration value="authors" />
+      <xsd:enumeration value="version" />
+      <xsd:enumeration value="since" />
+      <xsd:enumeration value="date" />
+      <xsd:enumeration value="note" />
+      <xsd:enumeration value="warning" />
+      <xsd:enumeration value="pre" />
+      <xsd:enumeration value="post" />
+      <xsd:enumeration value="copyright" />
+      <xsd:enumeration value="invariant" />
+      <xsd:enumeration value="remark" />
+      <xsd:enumeration value="attention" />
+      <xsd:enumeration value="par" />
+      <xsd:enumeration value="rcs" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxVersionNumber">
+    <xsd:restriction base="xsd:string">
+      <xsd:pattern value="\d+\.\d+.*" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxImageKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="html" />
+      <xsd:enumeration value="latex" />
+      <xsd:enumeration value="rtf" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxParamListKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="param" />
+      <xsd:enumeration value="retval" />
+      <xsd:enumeration value="exception" />
+      <xsd:enumeration value="templateparam" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxCharRange">
+    <xsd:restriction base="xsd:string">
+      <xsd:pattern value="[aeiouncAEIOUNC]" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxParamDir">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="in"/>
+      <xsd:enumeration value="out"/>
+      <xsd:enumeration value="inout"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="DoxAccessor">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="retain"/>
+      <xsd:enumeration value="copy"/>
+      <xsd:enumeration value="assign"/>
+      <xsd:enumeration value="weak"/>
+      <xsd:enumeration value="strong"/>
+      <xsd:enumeration value="unretained"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+</xsd:schema>
+
diff --git a/contrib/neo_doxygen/tests/root-namespace/xml/dir_68267d1309a1af8e8297ef4c3efbcdba.xml b/contrib/neo_doxygen/tests/root-namespace/xml/dir_68267d1309a1af8e8297ef4c3efbcdba.xml
new file mode 100644 (file)
index 0000000..6e59cc5
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+  <compounddef id="dir_68267d1309a1af8e8297ef4c3efbcdba" kind="dir">
+    <compoundname>src</compoundname>
+    <innerfile refid="_foo_8java">Foo.java</innerfile>
+    <briefdescription>
+    </briefdescription>
+    <detaileddescription>
+    </detaileddescription>
+    <location file="%SOURCE_DIRECTORY%/"/>
+  </compounddef>
+</doxygen>
diff --git a/contrib/neo_doxygen/tests/root-namespace/xml/index.xml b/contrib/neo_doxygen/tests/root-namespace/xml/index.xml
new file mode 100644 (file)
index 0000000..68a2afb
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygenindex xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="index.xsd" version="1.8.8">
+  <compound refid="class_foo" kind="class"><name>Foo</name>
+  </compound>
+  <compound refid="_foo_8java" kind="file"><name>Foo.java</name>
+  </compound>
+  <compound refid="dir_68267d1309a1af8e8297ef4c3efbcdba" kind="dir"><name>src</name>
+  </compound>
+</doxygenindex>
diff --git a/contrib/neo_doxygen/tests/root-namespace/xml/index.xsd b/contrib/neo_doxygen/tests/root-namespace/xml/index.xsd
new file mode 100644 (file)
index 0000000..d7ab2a9
--- /dev/null
@@ -0,0 +1,66 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+  <xsd:element name="doxygenindex" type="DoxygenType"/>
+
+  <xsd:complexType name="DoxygenType">
+    <xsd:sequence>
+      <xsd:element name="compound" type="CompoundType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="version" type="xsd:string" use="required"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="CompoundType">
+    <xsd:sequence>
+      <xsd:element name="name" type="xsd:string"/>
+      <xsd:element name="member" type="MemberType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="refid" type="xsd:string" use="required"/>
+    <xsd:attribute name="kind" type="CompoundKind" use="required"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="MemberType">
+    <xsd:sequence>
+      <xsd:element name="name" type="xsd:string"/>
+    </xsd:sequence>
+    <xsd:attribute name="refid" type="xsd:string" use="required"/>
+    <xsd:attribute name="kind" type="MemberKind" use="required"/>
+  </xsd:complexType>
+  
+  <xsd:simpleType name="CompoundKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="class"/>
+      <xsd:enumeration value="struct"/>
+      <xsd:enumeration value="union"/>
+      <xsd:enumeration value="interface"/>
+      <xsd:enumeration value="protocol"/>
+      <xsd:enumeration value="category"/>
+      <xsd:enumeration value="exception"/>
+      <xsd:enumeration value="file"/>
+      <xsd:enumeration value="namespace"/>
+      <xsd:enumeration value="group"/>
+      <xsd:enumeration value="page"/>
+      <xsd:enumeration value="example"/>
+      <xsd:enumeration value="dir"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="MemberKind">
+    <xsd:restriction base="xsd:string">
+      <xsd:enumeration value="define"/>
+      <xsd:enumeration value="property"/>
+      <xsd:enumeration value="event"/>
+      <xsd:enumeration value="variable"/>
+      <xsd:enumeration value="typedef"/>
+      <xsd:enumeration value="enum"/>
+      <xsd:enumeration value="enumvalue"/>
+      <xsd:enumeration value="function"/>
+      <xsd:enumeration value="signal"/>
+      <xsd:enumeration value="prototype"/>
+      <xsd:enumeration value="friend"/>
+      <xsd:enumeration value="dcop"/>
+      <xsd:enumeration value="slot"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+</xsd:schema>
+
index 4160f01..e316369 100644 (file)
@@ -1,15 +1,23 @@
 import minilang_test_parser
 
+# An naive recursive stack-based interpreter of the minilang language.
 class Interpretor
        super Visitor
+
+       # A stack of numeric values
        var stack = new Array[Int]
+
+       # A stack of boolean values
        var bstack = new Array[Bool]
+
+       # The current values assigned to each variable
        var vars = new HashMap[String, Int]
 
        redef fun visit(n) do n.accept_calculator(self)
 end
 
 redef class Node
+       # Execution of the node by the interpreter `v`
        fun accept_calculator(v: Interpretor) do visit_children(v)
 end
 
index 8825b01..5ece999 100644 (file)
@@ -23,18 +23,18 @@ class Automaton
        # The start state
        var start: State
 
-       # State that are accect states
+       # State that are accept states
        var accept = new Array[State]
 
        # All states
        var states = new Array[State]
 
-       # Tokens associated on accept states
-       # use `add_tag` to update
+       # Tokens associated on accept states.
+       # Use `add_tag` to update
        var tags = new HashMap[State, Set[Token]]
 
-       # Accept states associated on tokens
-       # use `add_tag` to update
+       # Accept states associated on tokens.
+       # Use `add_tag` to update
        var retrotags = new HashMap[Token, Set[State]]
 
        # Tag all accept states
@@ -66,7 +66,7 @@ class Automaton
                assert retrotags[t].has(s)
        end
 
-       # Remove all occurences of a tag in an automaton
+       # Remove all occurrences of a tag in an automaton
        fun clear_tag(t: Token)
        do
                if not retrotags.has_key(t) then return
@@ -78,7 +78,7 @@ class Automaton
                retrotags.keys.remove(t)
        end
 
-       # Remove tokens from conflicting state according the the inclusion of language
+       # Remove tokens from conflicting state according the inclusion of language.
        # REQUIRE: self isa DFA automaton
        fun solve_token_inclusion
        do
@@ -101,8 +101,8 @@ class Automaton
                end
        end
 
-       # Initialize a new automaton for the empty language
-       # one state, no accept, no transition
+       # Initialize a new automaton for the empty language.
+       # One state, no accept, no transition.
        init empty
        do
                var state = new State
@@ -110,8 +110,8 @@ class Automaton
                states.add state
        end
 
-       # Initialize a new automaton for the empty-string language
-       # one state, is accept, no transition
+       # Initialize a new automaton for the empty-string language.
+       # One state, is accept, no transition.
        init epsilon
        do
                var state = new State
@@ -120,8 +120,8 @@ class Automaton
                states.add state
        end
 
-       # Initialize a new automation for the language that accepts only a single symbol
-       # Two state, the second is accept, one transition on `symbol`
+       # Initialize a new automation for the language that accepts only a single symbol.
+       # Two state, the second is accept, one transition on `symbol`.
        init atom(symbol: Int)
        do
                var s = new State
@@ -148,8 +148,8 @@ class Automaton
                states.add a
        end
 
-       # Contatenate `other` to `self`
-       # other is modified and invalidated.
+       # Concatenate `other` to `self`.
+       # Other is modified and invalidated.
        fun concat(other: Automaton)
        do
                var s2 = other.start
@@ -160,7 +160,7 @@ class Automaton
                states.add_all other.states
        end
 
-       # `self` become the alternation of `self` and `other`
+       # `self` become the alternation of `self` and `other`.
        # `other` is modified and invalidated.
        fun alternate(other: Automaton)
        do
@@ -184,9 +184,9 @@ class Automaton
                states.add_all other.states
        end
 
-       # Return a new automaton that recognize `self` but not `other`
-       # For a theorical POV, this is the substraction of languages.
-       # Note: the implementation use `to_dfa` internally, so the theorical complexity is not cheap.
+       # Return a new automaton that recognize `self` but not `other`.
+       # For a theoretical POV, this is the subtraction of languages.
+       # Note: the implementation use `to_dfa` internally, so the theoretical complexity is not cheap.
        fun except(other: Automaton): Automaton
        do
                var ta = new Token("1")
@@ -209,8 +209,8 @@ class Automaton
                return c
        end
 
-       # `self` absorbs all states, transisions, tags, and acceptations of `other`
-       # An epsilon transition is added between `self.start` and `other.start`
+       # `self` absorbs all states, transitions, tags, and acceptations of `other`.
+       # An epsilon transition is added between `self.start` and `other.start`.
        fun absorb(other: Automaton)
        do
                states.add_all other.states
@@ -494,8 +494,8 @@ class Automaton
                f.close
        end
 
-       # Transform a NFA to a DFA
-       # note: the DFA is not miminized
+       # Transform a NFA to a DFA.
+       # note: the DFA is not minimized.
        fun to_dfa: Automaton
        do
                trim
@@ -581,8 +581,8 @@ class Automaton
                return dfa
        end
 
-       # epsilon-closure on a state of states
-       # used by `to_dfa`
+       # Epsilon-closure on a state of states.
+       # Used by `to_dfa`.
        private fun eclosure(states: Collection[State]): Set[State]
        do
                var res = new ArraySet[State]
@@ -601,8 +601,8 @@ class Automaton
                return res
        end
 
-       # trans on a set of states
-       # Used by `to_dfa`
+       # Trans on a set of states.
+       # Used by `to_dfa`.
        fun trans(states: Collection[State], symbol: Int): Set[State]
        do
                var res = new ArraySet[State]
@@ -621,9 +621,9 @@ class Automaton
                return res
        end
 
-       # Generate the Nit source code of the lexer
-       # `filepath` is the name of the ouptit file
-       # `parser` is the name of the parser module (used to import the token classes)
+       # Generate the Nit source code of the lexer.
+       # `filepath` is the name of the output file.
+       # `parser` is the name of the parser module (used to import the token classes).
        fun gen_to_nit(filepath: String, name: String, parser: nullable String)
        do
                var gen = new DFAGenerator(filepath, name, self, parser)
@@ -638,12 +638,9 @@ private class DFAGenerator
        var automaton: Automaton
        var parser: nullable String
 
-       var out: OStream
-       init(filepath: String, name: String, automaton: Automaton, parser: nullable String) do
-               self.filepath = filepath
-               self.name = name
-               self.automaton = automaton
-               self.parser = parser
+       var out: OStream is noinit
+
+       init do
                self.out = new OFStream.open(filepath)
        end
 
@@ -747,9 +744,9 @@ end
 # A state in a finite automaton
 class State
        # Outgoing transitions
-
        var outs = new Array[Transition]
-       # Ingoing tyransitions
+
+       # Ingoing transitions
        var ins = new Array[Transition]
 
        # Add a transitions to `to` on `symbol` (null means epsilon)
@@ -761,6 +758,8 @@ class State
                return t
        end
 
+       # Get the first state following the transition `i`.
+       # Null if no transition for `i`.
        fun trans(i: Int): nullable State
        do
                for t in outs do
@@ -778,7 +777,12 @@ end
 
 # A range of symbols on a transition
 class TSymbol
+       # The first symbol in the range
        var first: Int
+
+       # The last symbol if any.
+       #
+       # `null` means infinity.
        var last: nullable Int
 
        redef fun to_s
@@ -808,8 +812,8 @@ class Transition
        # The symbol on the transition (null means epsilon)
        var symbol: nullable TSymbol
 
-       # Remove the transition from the automaton
-       # Detash from `from` and `to`
+       # Remove the transition from the automaton.
+       # Detach from `from` and `to`.
        fun delete
        do
                from.outs.remove(self)
index 620b0a0..eea312f 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# A gramar describing a language
+# A grammar describing a language
 class Gram
-       # The productions (non-terminal) of the conctete grammar
+       # The productions (non-terminal) of the concrete grammar
        var prods = new Array[Production]
 
-       # The additionnal abstract productions of the grammar
+       # The additional abstract productions of the grammar
        # TODO clean AST
        var ast_prods = new Array[Production]
 
@@ -35,7 +35,7 @@ class Gram
                                res.append("{p.name} =\n")
                        end
                        var last = null
-                       if not p.alts.is_empty then p.alts.last
+                       if not p.alts.is_empty then last = p.alts.last
                        for a in p.alts do
                                res.append("\t\{{a.name}:\} {a.elems.join(" ")}")
                                if a.codes == null then a.make_codes
@@ -55,7 +55,7 @@ class Gram
                return res.to_s
        end
 
-       # Inline (ie. remove from the conctete grammar) some production
+       # Inline (ie. remove from the concrete grammar) some production
        # REQUIRE: no circular production in `prods`
        fun inline(prods: Collection[Production])
        do
@@ -322,14 +322,14 @@ class Production
        # The alternative of the production
        var alts = new Array[Alternative]
 
-       # Additionnal alternatives in the AST
+       # Additional alternatives in the AST
        var ast_alts = new Array[Alternative]
 
        # Is self the accept production
        var accept = false
 
        # Is self transformed to a other production for the AST
-       # FIXME: cleaup AST
+       # FIXME: cleanup AST
        var spe: nullable Production = null is writable
 
        # Is self contains only a single alternative (then no need for a abstract production class in the AST)
@@ -345,8 +345,10 @@ class Production
 
        # Is the production nullable
        var is_nullable = false
+
        # The first tokens of the production
        var firsts = new HashSet[Item]
+
        # The tokens that may follows the production (as in SLR)
        var afters = new HashSet[Item]
 
@@ -432,7 +434,7 @@ class Alternative
        # Is the alternative unparsable? (ie not in the automaton)
        var phony = false is writable
 
-       # Imitialize codes with the elements
+       # Initialize codes with the elements
        fun make_codes
        do
                if codes != null then return
@@ -445,20 +447,27 @@ class Alternative
        end
 end
 
-# A step in the construction of the AST. used to modelize transformations
+# A step in the construction of the AST.
+# Used to model transformations
 interface Code
 end
+
 # Get a element from the stack
 class CodePop
        super Code
        redef fun to_s do return "pop"
 end
-# Allocate a new AST node for an alternative using the correct number of poped elements
+
+# Allocate a new AST node for an alternative using the correct number of popped elements
 class CodeNew
        super Code
+
+       # The associated alternative
        var alt: Alternative
+
        redef fun to_s do return "New {alt.name}/{alt.elems.length}"
 end
+
 # Get null
 class CodeNull
        super Code
@@ -477,7 +486,7 @@ abstract class Element
        # The mangled name of the element
        fun cname: String do return "N{name.to_cmangle}"
 
-       # the name of the class in the AST
+       # The name of the class in the AST
        fun acname: String do
                var res = acname_cache
                if res == null then
@@ -486,15 +495,17 @@ abstract class Element
                end
                return res
        end
+
+       # The name of the class in the AST
        fun acname=(s: String) do acname_cache = s
 end
 
 # A terminal element
 class Token
        super Element
-       # States of the LR automatio that shift on self
+       # States of the LR automaton that shift on self
        var shifts = new ArraySet[LRState]
-       # States of the LR automatio that reduce on self in the lookahead(1)
+       # States of the LR automaton that reduce on self in the lookahead(1)
        var reduces = new ArraySet[LRState]
 end
 
@@ -872,13 +883,13 @@ end
 
 # A state in a LR automaton
 class LRState
-       # name of the automaton (short part from the start)
+       # Name of the automaton (short part from the start)
        var name: String
 
-       # malglen name
+       # Mangled name
        fun cname: String do return name.to_cmangle
 
-       # number
+       # Number
        var number: Int = -1
 
        # Set of all items
@@ -893,7 +904,7 @@ class LRState
        # Ingoing transitions
        var outs = new Array[LRTransition]
 
-       # trans function
+       # Trans function
        fun trans(e: Element): nullable LRState
        do
                for t in outs do if t.elem == e then return t.to
@@ -915,7 +926,7 @@ class LRState
                return true
        end
 
-       # Recusively extends item outside the core
+       # Recursively extends item outside the core
        fun extends(i: Item)
        do
                var e = i.next
@@ -940,7 +951,7 @@ class LRState
        var gotos = new ArraySet[Production]
        # Reduction guarded by tokens
        var guarded_reduce = new HashMap[Token, Set[Item]]
-       # Shitfs guarded by tokens
+       # Shifts guarded by tokens
        var guarded_shift = new HashMap[Token, Set[Item]]
 
        # Does the state need a guard to perform an action?
@@ -949,7 +960,7 @@ class LRState
        # Is the state LR0?
        fun is_lr0: Bool do return reduces.length <= 1 and shifts.is_empty or reduces.is_empty
 
-       # compute guards and conflicts
+       # Compute guards and conflicts
        fun analysis
        do
                # Extends the core
@@ -1031,7 +1042,7 @@ class LRState
                end
        end
 
-       # Return `i` and all other items of the state that expands, directly or undirectly, to `i`
+       # Return `i` and all other items of the state that expands, directly or indirectly, to `i`
        fun back_expand(i: Item): Set[Item]
        do
                var res = new ArraySet[Item]
@@ -1056,7 +1067,7 @@ end
 class LRTransition
        # The origin state
        var from: LRState
-       # The testination state
+       # The destination state
        var to: LRState
        # The element labeling the transition
        var elem: Element
@@ -1085,14 +1096,14 @@ class Item
                return b.to_s
        end
 
-       # The element thatr follow the dot, null if the fdot is at the end
+       # The element that follows the dot, null if the dot is at the end
        fun next: nullable Element
        do
                if pos >= alt.elems.length then return null
                return alt.elems[pos]
        end
 
-       # SLR loohahead
+       # SLR lookahead
        fun lookahead: Set[Token]
        do
                var res = new HashSet[Token]
index 7fa876f..f3ff58d 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Ad-hoc hand-writen lexer for nitcc
-# This avoid to commit (and relyon ) a generated lexer
-#
+# Ad-hoc hand-written lexer for nitcc
+# This avoid to commit (and rely on) a generated lexer
 module nitcc_lexer0
 
 # Required for the tokens definitions
 import nitcc_parser
 
-# Hand-writen lexer of nitcc
-# Used only for the boostrap of the tool.
+# Hand-written lexer of nitcc.
+# Used only for the bootstrap of the tool.
 class Lexer_nitcc
+       # The text to tokenize
        var text: String
 
-       var iter: Iterator[Char] = "".chars.iterator
+       # The iterator on text
+       private var iter: Iterator[Char] is noinit
+
+       # The current position
        var pos = 0
 
-       var tokens = new Array[NToken]
+       # The tokens currently produced
+       private var tokens = new Array[NToken]
 
+       # Tokenize and returns the tokens
        fun lex: Array[NToken]
        do
                iter = text.chars.iterator
@@ -88,13 +93,13 @@ class Lexer_nitcc
                return tokens
        end
 
-       fun error(c: Char)
+       private fun error(c: Char)
        do
                print "pos {pos}: Lexer error on '{c}'."
                abort
        end
 
-       fun str
+       private fun str
        do
                var b = new FlatBuffer
                b.add('\'')
@@ -121,7 +126,7 @@ class Lexer_nitcc
                abort
        end
 
-       fun id(c: Char)
+       private fun id(c: Char)
        do
                var b = new FlatBuffer
                b.add c
@@ -138,7 +143,7 @@ class Lexer_nitcc
                tokens.add token
        end
 
-       fun kw(c: Char)
+       private fun kw(c: Char)
        do
                var b = new FlatBuffer
                b.add c
@@ -155,7 +160,7 @@ class Lexer_nitcc
                tokens.add token
        end
 
-       fun trim
+       private fun trim
        do
                while iter.is_ok and iter.item <= ' ' do
                        iter.next
index 73baa05..af417d4 100644 (file)
@@ -28,6 +28,7 @@ import re2nfa
 class CollectNameVisitor
        super Visitor
 
+       # All the productions
        var nprods = new Array[Nprod]
 
        # Symbol table to associate things (prods and exprs) with their name
@@ -44,7 +45,7 @@ class CollectNameVisitor
        # The current production, used to initialize priorities
        var prod: nullable Production = null
 
-       # The current priority counter to name tranformed productions
+       # The current priority counter to name transformed productions
        var pricpt: Int = 0
 
        # Run the semantic analysis of the grammar
@@ -53,13 +54,13 @@ class CollectNameVisitor
                # First visit to collect names
                enter_visit(n)
 
-               # Second visit to use collectec names and build rhings
+               # Second visit to use collected names and build things
                var v2 = new CheckNameVisitor(self)
                v2.enter_visit(n)
 
-               # Inline all the ?
+               # Inline all the `?`
                gram.inline(v2.quesizes.values)
-               # Inlile all the prods sufixed by '_imline' #TODO use a real keyword
+               # Inline all the prods suffixed by '_inline' #TODO use a real keyword
                for p in gram.prods do
                        if not p.name.has_suffix("_inline") then continue
                        print "inline {p}"
@@ -102,14 +103,14 @@ private class CheckNameVisitor
        # The collected element names, for the alternative
        var elems_names = new Array[nullable String]
 
-       # The collected elementname, for the nelem
+       # The collected element names, for the nelem
        var elemname: nullable String = null
 
        # Is the alternative transformed, for the alternative
        var trans = false
 
        # The current priority class
-       # Used the check, and tranform the grammar
+       # Used the check, and transform the grammar
        var pri: nullable Npriority = null
 
        # Known ignored tokens
@@ -119,7 +120,7 @@ private class CheckNameVisitor
        var rejecteds = new Array[Element]
 
        # Pool of elements that are modified with + (reuse them!)
-       private var plusizes = new HashMap[Element, Production]
+       var plusizes = new HashMap[Element, Production]
 
        # Create a + version of an element
        fun plusize(e: Element): Production
@@ -136,7 +137,7 @@ private class CheckNameVisitor
        end
 
        # Pool of elements that are modified with ? (reuse them!)
-       private var quesizes = new HashMap[Element, Production]
+       var quesizes = new HashMap[Element, Production]
 
        # Create a ? version of an element
        fun quesize(e: Element): Production
@@ -155,14 +156,13 @@ private class CheckNameVisitor
        end
 
        # The current nexpr, used to track dependency on named expressions (see `Nexpr::precs`)
-       var nexpr: nullable Nexpr
+       var nexpr: nullable Nexpr = null
 
        # The current production, used to initialize alternatives
-       var prod: nullable Production
+       var prod: nullable Production = null
 
        # The main visitor, used to access the grammar of the symbol table
        var v1: CollectNameVisitor
-       init(v1: CollectNameVisitor) do self.v1 = v1
 
        redef fun visit(n) do n.accept_check_name_visitor(self)
 end
@@ -204,7 +204,7 @@ redef class Nexpr
        # The associated NFA (cached, see `build_nfa`)
        private var nfa: nullable Automaton
 
-       # Build the NFA, possibily building the NFA of required expressions
+       # Build the NFA, possibly building the NFA of required expressions
        # Print an error if there is a circular dependency
        # The result is cached
        fun build_nfa: Automaton do
@@ -269,7 +269,7 @@ redef class Nign
                                abort
                        else if e isa Token then
                                # The token was build and registered during the visit
-                               # So, unregister then, the bit Ignred token will be build later
+                               # So, unregister them, the big Ignored token will be build later
                                v.v1.gram.tokens.remove(e)
                        else
                                abort
@@ -298,13 +298,13 @@ redef class Nrej
 end
 
 redef class Nprod
-       # The associated main production
-       # ie the last priority class
+       # The associated main production.
+       # i.e. the last priority class.
        var prod: nullable Production
 
-       # The associated most-priority production
-       # ie the first priority class
-       # If there is no priority then `sub_prod == prod`
+       # The associated most-priority production.
+       # i.e. the first priority class.
+       # If there is no priority then `sub_prod == prod`.
        var sub_prod: nullable Production
 
        redef fun accept_collect_prod(v) do
@@ -376,13 +376,14 @@ redef class Natrans
 end
 
 redef class Npriority
+       # It is the last priority group?
        var is_last = false
 
        # The associated production
        var prod: nullable Production
 
-       # The production in the with the next less priority class
-       # null is there is no priority or if the first priority class
+       # The production in the with the next less priority class.
+       # `null` if there is no priority or if the first priority class.
        var next: nullable Production
 
        redef fun accept_collect_prod(v) do
@@ -409,7 +410,7 @@ redef class Npriority
                v.pri = self
                super
 
-               # Inject a new alternative that goes to the next less prioty class
+               # Inject a new alternative that goes to the next less priority class
                var alt = prod.new_alt2(prod.name + "_" + prod.alts.length.to_s, [next.as(not null)])
                alt.trans = true
                alt.codes = [new CodePop]
@@ -462,6 +463,8 @@ redef class Npriority_unary
 end
 
 redef class Alternative
+       # The short name of the alternative.
+       # Used for errors
        var short_name: nullable String
 end
 
index 6bca660..d0d90ac 100644 (file)
@@ -37,7 +37,6 @@ redef class Nstr
        redef fun make_rfa: Automaton
        do
                var a = new Automaton.epsilon
-               var val
                for c in self.value.chars do
                        var b = new Automaton.atom(c.ascii)
                        a.concat(b)
diff --git a/contrib/nitiwiki/.gitignore b/contrib/nitiwiki/.gitignore
new file mode 100644 (file)
index 0000000..89f9ac0
--- /dev/null
@@ -0,0 +1 @@
+out/
diff --git a/contrib/nitiwiki/Makefile b/contrib/nitiwiki/Makefile
new file mode 100644 (file)
index 0000000..8e385f9
--- /dev/null
@@ -0,0 +1,15 @@
+all: nitiwiki
+
+nitiwiki:
+       mkdir -p bin
+       ../../bin/nitc src/nitiwiki.nit -o bin/nitiwiki
+
+tests: nitiwiki
+       cd tests; make
+
+doc:
+       ../../bin/nitdoc -d doc src/nitiwiki.nit
+
+clean:
+       rm -rf bin
+       rm -rf -- .nit_compile 2> /dev/null || true
diff --git a/contrib/nitiwiki/README.md b/contrib/nitiwiki/README.md
new file mode 100644 (file)
index 0000000..abe84ad
--- /dev/null
@@ -0,0 +1,291 @@
+# nitiwiki, a simple wiki manager based on markdown.
+
+Basically, nitiwiki compiles a set of markdown files into an HTML wiki.
+
+The wiki content is structured by `sections` represented by the wiki folders. Sections can contain `articles` represented by markdown files.
+
+Features:
+
+* automatic wiki structure from folders hierarchy
+* automatic site menu
+* automatic sitemap
+* automatic summaries
+* easy and rapid templating
+* customizable section templates and menus
+* rsync synchronization
+* git synchronization
+
+## Wiki structure
+
+Basic wiki structure:
+
+       root
+       |- assets
+       |- out
+       |- pages
+       |- templates
+       |       |- footer.html
+       |       |- header.html
+       |       |- menu.html
+       |       `- template.html
+       `- config.ini
+
+### pages
+
+This is where goes all the content of your wiki.
+Nitiwiki will render an article for each markdown file found in `pages`.
+
+You can categorize your content in sections using sub-folders:
+
+       pages
+       |- section1
+       |       `- index.md
+       |- section2
+       |       `- index.md
+       |- page1.md
+       |- page2.md
+       `- index.md
+
+### assets
+
+This is where you store CSS and JavaScript files used in the design of your site.
+
+You can also use this directory to put some images or other files that will be
+used in all your pages.
+
+       assets
+       |- css
+       |- js
+       `- logo.png
+
+### templates
+
+This folder contains the templates used to generate the HTML pages of your wiki.
+
+The main template is called `template.html`.
+It contains the HTML structure of your pages and some macros that will be replaced
+by the wiki articles.
+
+### out
+
+This is where your wiki will be rendered by nitiwiki.
+Do not put anything in this folder since it will be overwritten at the
+next wiki rendering.
+
+The wiki rendering consists in:
+
+1. copy the `assets` directory to `out`
+2. copy attached article files from `pages` to `out`
+3. translate markdown files from `pages` to html files in `out`
+
+### config.ini
+
+This is the main config file of your wiki. For more details see [Configure the wiki](#Configure_the_wiki).
+
+## Manage the wiki
+
+### Create a new wiki
+
+Just move to the directory where you want to store your source files and type:
+
+       nitiwiki init
+
+This command will import the base structure of your wiki in the current directory.
+At this point nitiwiki has created the main configuration file of your site:
+`config.ini`.
+
+### Configure the wiki
+
+All the nitiwiki configuration is done using
+[ini files](http://en.wikipedia.org/wiki/INI_file).
+
+The wiki configuration is contained in the `config.ini` file located at the root
+directory of your wiki.
+This file can be edited to change nitiwiki settings.
+
+Settings:
+
+* `wiki.name`: Displayed name
+* `wiki.desc`: Long description
+* `wiki.logo`: Logo image url
+* `wiki.root_url`: Base url used to resolve links
+* `wiki.root_dir`: Absolute path of base directory
+* `wiki.source_dir`: Source directory (relative path from `wiki.root_dir`)
+* `wiki.out_dir`: Output directory (relative)
+* `wiki.assets_dir`: Assets directory (relative)
+* `wiki.templates_dir`: Templates directory (relative)
+* `wiki.template`: Wiki main template file
+* `wiki.header`: Wiki main header template file
+* `wiki.footer`: Wiki main footer template file
+* `wiki.menu`: Wiki main menu template file
+* `wiki.rsync_dir`: Directory used to rsync output
+* `wiki.git_origin`: Git origin used to fetch data
+* `wiki.git_branch`: Git branch used to fetch data
+
+For more details on each option see `WikiConfig`.
+
+### Add content
+
+To add content in your wiki simply add markdown files (with `.md` extension) into the `pages/` folder.
+
+Once you have done your changes, use:
+
+       nitiwiki --status
+
+This will show the impacts of your changes on the wiki structure.
+
+Then type:
+
+       nitiwiki --render
+
+This will the generate the html output of your new content.
+The option `--force` can be used to regenerate all the wiki.
+This can be uselful when you perform changes on the template files.
+
+### Configure sections
+
+Section appearance can be customized using config files.
+
+Each section in the `pages/` folder can contain a `config.ini` file.
+Options set on a section will be propagated to all its children unless
+they have their own config file.
+
+Allowed options are:
+
+* `section.title`: Custom title for this section
+* `section.template`: Custom template file
+* `section.header`: Custom header template file
+* `section.footer`: Custom footer template file
+* `section.menu`: Custom menu template file
+* `section.is_hidden`: Set this to `true` will hide the section in all menus and
+  sitemaps.
+
+## Customize templates
+
+Templating your wiki involves modifying 4 template files:
+
+* `template.html`
+* `header.html`
+* `footer.html`
+* `menu.html`
+
+Each of these file contains an HTML skeletton used by nitiwiki to render your files.
+Templates can contains macros marked `%MACRO%` that will be replaced by dynamic content.
+
+Every template can access to:
+
+* `ROOT_URL`: Wiki root url
+* `TITLE`: Wiki name
+* `SUBTITLE`: Wiki description
+* `LOGO`: Wiki logo image path
+
+Additionnal macros can be used in specialized templates.
+
+### Main template
+
+The template file `template.html` represents the overall structure of your wiki pages.
+
+       <!DOCTYPE html>
+       <html>
+               <head>
+                       <title>%TITLE%</title>
+                       <link href="%ROOT_URL%/assets/css/main.css" rel="stylesheet">
+               </head>
+               <body>
+                       %HEADER%
+                       %TOP_MENU%
+                       <div>
+                               %BODY%
+                               %FOOTER%
+                       </div>
+               </body>
+       </html>
+
+Additionnal macros:
+
+* `HEADER`: Wiki header (see [Header template](#Header_template))
+* `FOOTER`: Wiki footer (see [Footer template](#Footer_template))
+* `TOP_MENU`: Wiki top menu (see [Topmenu template](#Topmenu_template))
+* `HEADER`: Wiki header (see [Header template](#Header_template))
+* `BODY`: Wiki body content
+
+### Header template
+
+The template file `header.html` is generated on top of all the wiki pages.
+
+       <header>
+               <a href="#"><img src="%ROOT_URL%/%LOGO%" alt="logo"/></a>
+               <h2>%SUBTITLE%</h2>
+               <h1>%TITLE%</h1>
+       </header>
+
+### Footer template
+
+The template file `footer.html` is generated on the bottom of all the wiki pages.
+
+       <footer>
+               <p>%TITLE% &copy; %YEAR%</p>
+               <p>last modification %GEN_TIME%</p>
+       </footer>
+
+Additionnal macros:
+
+* `YEAR`: Current year
+* `GEN_TIME`: Page generation date
+
+### Topmenu template
+
+The template file `menu.html` contains the menu structure generated on all your pages.
+
+Its content can be static:
+
+       <nav class="menu">
+               <ul class="nav navbar-nav">
+                       <li><a href="#">Home</a></li>
+                       <li><a href="#">Page1</a></li>
+                       <li><a href="#">Page2</a></li>
+               </ul>
+       </nav>
+
+Or dynamic using the macro `MENUS`:
+
+       <nav class="menu">
+               <ul class="nav navbar-nav">
+               %MENUS%
+               </ul>
+       </nav>
+
+## Advanced usages
+
+### Working with git
+
+nitiwiki allows you to store your wiki changes in git.
+Using the option `--fetch` will update the local wiki instance
+according to git informations found in the config file.
+
+Be sure to set `wiki.git_origin` and `wiki.git_branch`
+in order to correctly pull changes.
+
+To automatically update your wiki when changes are pushed on the
+origin repository you can use the following command in a git hook:
+
+       nitiwiki --fetch --render
+
+### Working with a remote server
+
+Sometimes you cannot do what you want on your webserver (like setting crons).
+For this purpose, nitiwiki provide a quick way to update a distant instance
+through `ssh` using `rsync`.
+
+With the option `--rsync`, nitwiki will update a distant location with the
+last rendered output. This way you can manually update your webserver
+after changes or set a cron on a different server that you can control.
+
+Using the following command in your cron will update the web server instance
+from git:
+
+       nitiwiki --fetch --render --rsync
+
+Be sure to set `wiki.rsync_dir` in order to correctly push your changes.
+When using `--rsync`, keep in mind that the rendered output must be configured
+to work on the web server and set `wiki.root_url` accordingly.
diff --git a/contrib/nitiwiki/examples/default/config.ini b/contrib/nitiwiki/examples/default/config.ini
new file mode 100644 (file)
index 0000000..21e85ef
--- /dev/null
@@ -0,0 +1,5 @@
+wiki.name=MyWiki
+wiki.desc=proudly powered by nit
+wiki.logo=assets/logo.png
+wiki.root_url=http://localhost/
+wiki.root_dir=/full/path/to/your/wiki/root/dir
diff --git a/contrib/nitiwiki/examples/default/pages/index.md b/contrib/nitiwiki/examples/default/pages/index.md
new file mode 100644 (file)
index 0000000..b212ceb
--- /dev/null
@@ -0,0 +1 @@
+# Welcome on nitiwiki
diff --git a/contrib/nitiwiki/examples/default/templates/footer.html b/contrib/nitiwiki/examples/default/templates/footer.html
new file mode 100644 (file)
index 0000000..7c8de99
--- /dev/null
@@ -0,0 +1,4 @@
+<footer>
+    <p>%TITLE% &copy; %YEAR%</p>
+    <p>last modification %GEN_TIME%</p>
+</footer>
diff --git a/contrib/nitiwiki/examples/default/templates/header.html b/contrib/nitiwiki/examples/default/templates/header.html
new file mode 100644 (file)
index 0000000..d86aac9
--- /dev/null
@@ -0,0 +1,5 @@
+<header>
+    <a href="#"><img src="%ROOT_URL%/%LOGO%" alt="logo"/></a>
+    <h2>%SUBTITLE%</h2>
+    <h1>%TITLE%</h1>
+</header>
diff --git a/contrib/nitiwiki/examples/default/templates/menu.html b/contrib/nitiwiki/examples/default/templates/menu.html
new file mode 100644 (file)
index 0000000..76a6f95
--- /dev/null
@@ -0,0 +1,5 @@
+<nav class="menu">
+    <ul class="nav navbar-nav">
+    %MENUS%
+    </ul>
+</nav>
diff --git a/contrib/nitiwiki/examples/default/templates/template.html b/contrib/nitiwiki/examples/default/templates/template.html
new file mode 100644 (file)
index 0000000..692a999
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>%TITLE%</title>
+        <link href="%ROOT_URL%/assets/css/main.css" rel="stylesheet">
+    </head>
+    <body>
+        %HEADER%
+        %TOP_MENU%
+        <div>
+            %BODY%
+            %FOOTER%
+        </div>
+    </body>
+</html>
diff --git a/contrib/nitiwiki/examples/nitiwiki/assets/css/main.css b/contrib/nitiwiki/examples/nitiwiki/assets/css/main.css
new file mode 100644 (file)
index 0000000..c00394a
--- /dev/null
@@ -0,0 +1,30 @@
+header { margin: 15px 0; }
+header img {
+       padding: 10px;
+       float: left;
+}
+header h1, header h2 { display: none; }
+
+footer {
+       margin-top: 30px;
+       text-align: center;
+}
+
+.menu {
+       border-top: 6px solid #47CA42;
+       background-color: #0d8921;
+}
+
+.menu .navbar-brand, .menu a { color: #fff; }
+.menu .navbar-nav>.active>a, .menu .navbar-nav>li>a:hover { background-color: #47CA42; }
+
+.sidebar { margin-top: 20px; }
+
+.summary a { color: #333; }
+.summary a:hover { text-decoration: none; }
+.summary a:hover, .summary li:active>a { color: #428bca; }
+.summary li { padding: 2px 0; font-weight: bold }
+.summary li li { font-size: 13px;}
+.summary li li li { font-size: 12px; font-weight: normal }
+
+.breadcrumb { margin-top: 20px; }
diff --git a/contrib/nitiwiki/examples/nitiwiki/assets/logo.png b/contrib/nitiwiki/examples/nitiwiki/assets/logo.png
new file mode 100644 (file)
index 0000000..daccc80
Binary files /dev/null and b/contrib/nitiwiki/examples/nitiwiki/assets/logo.png differ
diff --git a/contrib/nitiwiki/examples/nitiwiki/config.ini b/contrib/nitiwiki/examples/nitiwiki/config.ini
new file mode 100644 (file)
index 0000000..16eaffe
--- /dev/null
@@ -0,0 +1,6 @@
+wiki.name=nitiwiki
+wiki.desc=proudly powered by nit
+wiki.logo=assets/logo.png
+wiki.root_url=http://moz-code.org/nitiwiki/
+wiki.root_dir=.
+wiki.rsync_dir=moz-code.org:nitiwiki/
diff --git a/contrib/nitiwiki/examples/nitiwiki/pages/index.md b/contrib/nitiwiki/examples/nitiwiki/pages/index.md
new file mode 120000 (symlink)
index 0000000..8a33348
--- /dev/null
@@ -0,0 +1 @@
+../../../README.md
\ No newline at end of file
diff --git a/contrib/nitiwiki/examples/nitiwiki/templates/footer.html b/contrib/nitiwiki/examples/nitiwiki/templates/footer.html
new file mode 100644 (file)
index 0000000..94229ea
--- /dev/null
@@ -0,0 +1,10 @@
+<footer class="row">
+       <div class="container-fluid">
+               <div class="well well-sm">
+                       <p><strong>%TITLE% &copy; %YEAR%</strong></p>
+                       <p class="text-muted"><em>last modification %GEN_TIME%</em></p>
+                       <p class="text-muted">Proudly powered by
+                               <a href="http://nitlanguage.org">nit</a>!</p>
+               </div>
+       </div>
+</footer>
diff --git a/contrib/nitiwiki/examples/nitiwiki/templates/header.html b/contrib/nitiwiki/examples/nitiwiki/templates/header.html
new file mode 100644 (file)
index 0000000..8b06ab8
--- /dev/null
@@ -0,0 +1,9 @@
+<div class="container-fluid header">
+       <div class="container">
+               <header>
+                       <a href="http://uqam.ca"><img src="%ROOT_URL%/%LOGO%" alt="logo" /></a>
+                       <h2>%SUBTITLE%</h2>
+                       <h1>%TITLE%</h1>
+               </header>
+       </div>
+</div>
diff --git a/contrib/nitiwiki/examples/nitiwiki/templates/menu.html b/contrib/nitiwiki/examples/nitiwiki/templates/menu.html
new file mode 100644 (file)
index 0000000..1ff832e
--- /dev/null
@@ -0,0 +1,20 @@
+<nav class="menu" role="navigation">
+       <div class="container">
+               <!-- Brand and toggle get grouped for better mobile display -->
+               <div class="navbar-header">
+                       <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
+                               <span class="sr-only">Toggle navigation</span>
+                               <span class="icon-bar"></span>
+                               <span class="icon-bar"></span>
+                               <span class="icon-bar"></span>
+                       </button>
+                       <a class="navbar-brand" href="%ROOT_URL%index.html">%TITLE%</a>
+               </div>
+               <!-- Collect the nav links, forms, and other content for toggling -->
+               <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
+                       <ul class="nav navbar-nav">
+                       %MENUS%
+                       </ul>
+               </div><!-- /.navbar-collapse -->
+       </div>
+</nav>
diff --git a/contrib/nitiwiki/examples/nitiwiki/templates/template.html b/contrib/nitiwiki/examples/nitiwiki/templates/template.html
new file mode 100644 (file)
index 0000000..7c43833
--- /dev/null
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html lang="en">
+       <head>
+               <meta charset="utf-8">
+               <meta http-equiv="X-UA-Compatible" content="IE=edge">
+               <meta name="viewport" content="width=device-width, initial-scale=1">
+               <title>%TITLE%</title>
+
+               <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet">
+               <link href="%ROOT_URL%/assets/css/main.css" rel="stylesheet">
+
+               <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
+               <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
+               <!--[if lt IE 9]>
+               <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
+               <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
+               <![endif]-->
+       </head>
+       <body>
+               %HEADER%
+               %TOP_MENU%
+               <div class="container">
+                       <div class="row">
+                               %BODY%
+                       </div>
+                       %FOOTER%
+               </div>
+
+               <script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
+               <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>
+       </body>
+</html>
diff --git a/contrib/nitiwiki/src/nitiwiki.nit b/contrib/nitiwiki/src/nitiwiki.nit
new file mode 100644 (file)
index 0000000..200f971
--- /dev/null
@@ -0,0 +1,163 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# A wiki engine based on markdown files and git.
+module nitiwiki
+
+import wiki_html
+
+# Locate nit directory
+private fun compute_nit_dir(opt_nit_dir: OptionString): String do
+       # the option has precedence
+       var res = opt_nit_dir.value
+       if res != null then
+               if not check_nit_dir(res) then
+                       print "Fatal Error: --nit-dir does not seem to be a valid base Nit directory: {res}"
+                       exit 1
+               end
+               return res
+       end
+
+       # then the environ variable has precedence
+       res = "NIT_DIR".environ
+       if not res.is_empty then
+               if not check_nit_dir(res) then
+                       print "Fatal Error: NIT_DIR does not seem to be a valid base Nit directory: {res}"
+                       exit 1
+               end
+               return res
+       end
+
+       # find the runpath of the program from argv[0]
+       res = "{sys.program_name.dirname}/.."
+       if check_nit_dir(res) then return res.simplify_path
+
+       # find the runpath of the process from /proc
+       var exe = "/proc/self/exe"
+       if exe.file_exists then
+               res = exe.realpath
+               res = res.dirname.join_path("..")
+               if check_nit_dir(res) then return res.simplify_path
+       end
+
+       # search in the PATH
+       var ps = "PATH".environ.split(":")
+       for p in ps do
+               res = p/".."
+               if check_nit_dir(res) then return res.simplify_path
+       end
+
+       print "Fatal Error: Cannot locate a valid base nit directory. It is quite unexpected. Try to set the environment variable `NIT_DIR` or to use the `--nit-dir` option."
+       exit 1
+       abort
+end
+
+private fun check_nit_dir(res: String): Bool do
+       return res.file_exists and "{res}/src/nit.nit".file_exists
+end
+
+var opt_help = new OptionBool("Display this help message", "-h", "--help")
+var opt_verbose = new OptionCount("Verbose level", "-v")
+var opt_config = new OptionString("Path to config.ini file", "-c", "--config")
+var opt_init = new OptionBool("Initialize a new wiki in the current directory", "--init")
+var opt_status = new OptionBool("Display wiki status", "-s", "--status")
+var opt_render = new OptionBool("Render the out directory from markdown sources", "-r", "--render")
+var opt_force = new OptionBool("Force render even if source files are unchanged", "-f", "--force")
+var opt_clean = new OptionBool("Clean the output directory", "--clean")
+var opt_rsync = new OptionBool("Synchronize outdir with distant wiki using rsync", "-s", "--rsync")
+var opt_fetch = new OptionBool("Render local source from git repo", "--fetch")
+var opt_nit_dir = new OptionString("Nit base directory", "--nit-dir")
+
+var context = new OptionContext
+context.add_option(opt_help, opt_verbose, opt_config)
+context.add_option(opt_init, opt_status, opt_render, opt_force)
+context.add_option(opt_clean, opt_rsync, opt_fetch, opt_nit_dir)
+context.parse(args)
+
+var config_filename = "config.ini"
+
+# --help
+if opt_help.value then
+       context.usage
+       exit 0
+end
+
+# --init
+if opt_init.value then
+       if config_filename.file_exists then
+               print "Already in a nitiwiki directory."
+               exit 0
+       end
+       var nitiwiki_home = "{compute_nit_dir(opt_nit_dir)}/contrib/nitiwiki"
+       var tpl = "{nitiwiki_home}/examples/default/"
+       if not tpl.file_exists then
+               print "Cannot find {tpl} files."
+               print "Maybe your NIT_DIR is not set properly?"
+               print "You can initialize nitiwiki manually by copying the default skeletton here."
+               exit 1
+       end
+       sys.system "cp -R {tpl}/* ."
+       print "Initialized new nitiwiki."
+       print "Set wiki settings by editing {config_filename}."
+       exit 0
+end
+
+# load config files
+
+# --config
+var config_file = opt_config.value
+if config_file == null then
+       config_file = config_filename
+end
+
+if not config_file.file_exists then
+       print "Not in a nitiwiki directory."
+       print "Use --init to initialize one here."
+       exit 0
+end
+
+var config = new WikiConfig(config_file)
+var wiki = new Nitiwiki(config)
+
+# --verbose
+wiki.verbose_level = opt_verbose.value
+
+# --clean
+if opt_clean.value then
+       wiki.clean
+end
+
+# --fetch
+if opt_fetch.value then
+       wiki.fetch
+end
+
+# --render
+if opt_render.value then
+       wiki.parse
+       # --force
+       wiki.force_render = opt_force.value
+       wiki.render
+end
+
+# --rsync
+if opt_rsync.value then
+       wiki.sync
+end
+
+# --status
+if opt_status.value or args.is_empty then
+       wiki.parse
+       wiki.status
+end
diff --git a/contrib/nitiwiki/src/wiki_base.nit b/contrib/nitiwiki/src/wiki_base.nit
new file mode 100644 (file)
index 0000000..2c0276b
--- /dev/null
@@ -0,0 +1,744 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Base entities of a nitiwiki.
+module wiki_base
+
+import template::macro
+import markdown
+import opts
+import ini
+
+# A Nitiwiki instance.
+#
+# Nitiwiki provide all base services used by `WikiSection` and `WikiArticle`.
+# It manages content and renders pages.
+#
+# Each nitiwiki instance is linked to a config file.
+# This file show to `nitiwiki` that a wiki is present in the current directory.
+# Without it, nitiwiki will consider the directory as empty.
+class Nitiwiki
+
+       # Wiki config object.
+       var config: WikiConfig
+
+       # Default config filename.
+       var config_filename = "config.ini"
+
+       # Force render on all file even if the source is unmodified.
+       var force_render = false is writable
+
+       # Verbosity level.
+       var verbose_level = 0 is writable
+
+       # Delete all the output files.
+       fun clean do
+               var out_dir = expand_path(config.root_dir, config.out_dir)
+               if out_dir.file_exists then out_dir.rmdir
+       end
+
+       # Synchronize local output with the distant `WikiConfig::rsync_dir`.
+       fun sync do
+               var root = expand_path(config.root_dir, config.out_dir)
+               sys.system "rsync -vr --delete {root}/ {config.rsync_dir}"
+       end
+
+       fun fetch do
+               sys.system "git pull {config.git_origin} {config.git_branch}"
+       end
+
+       # Analyze wiki files from `dir` to build wiki entries.
+       #
+       # This method build a hierarchical structure of `WikiSection` and `WikiArticle`
+       # based on the markdown source structure.
+       fun parse do
+               var dir = expand_path(config.root_dir, config.source_dir)
+               root_section = new_section(dir)
+               var files = list_md_files(dir)
+               for file in files do
+                       new_article(file)
+               end
+       end
+
+       # Show wiki status.
+       fun status do
+               print "nitiWiki"
+               print "name: {config.wiki_name}"
+               print "config: {config.ini_file}"
+               print "url: {config.root_url}"
+               print ""
+               if root_section.is_dirty then
+                       print "There is modified files:"
+                       var paths = entries.keys.to_a
+                       var s = new DefaultComparator
+                       s.sort(paths)
+                       for path in paths do
+                               var entry = entries[path]
+                               if not entry.is_dirty then continue
+                               var name = entry.name
+                               if entry.has_source then name = entry.src_path.to_s
+                               if entry.is_new then
+                                       print " + {name}"
+                               else
+                                       print " * {name}"
+                               end
+                       end
+                       print ""
+                       print "Use nitiwiki --render to render modified files"
+               else
+                       print "Wiki is up-to-date"
+                       print ""
+                       print "Use nitiwiki --fetch to pull modification from origin"
+                       print "Use nitiwiki --rsync to synchronize distant output"
+               end
+       end
+
+       # Display msg if `level >= verbose_level`
+       fun message(msg: String, level: Int) do
+               if level <= verbose_level then print msg
+       end
+
+       # List markdown source files from a directory.
+       fun list_md_files(dir: String): Array[String] do
+               var files = new Array[String]
+               var pipe = new IProcess("find", dir, "-name", "*.md")
+               while not pipe.eof do
+                       var file = pipe.read_line
+                       if file == "" then break # last line
+                       file = file.substring(0, file.length - 1) # strip last oef
+                       var name = file.basename(".md")
+                       if name == "header" or name == "footer" or name == "menu" then continue
+                       files.add file
+               end
+               pipe.close
+               pipe.wait
+               if pipe.status != 0 then exit 1
+               var s = new DefaultComparator
+               s.sort(files)
+               return files
+       end
+
+       # Does `src` have been modified since `target` creation?
+       #
+       # Always returns `true` if `--force` is on.
+       fun need_render(src, target: String): Bool do
+               if force_render then return true
+               if not target.file_exists then return true
+               return src.file_stat.mtime >= target.file_stat.mtime
+       end
+
+       # Create a new `WikiSection`.
+       #
+       # `path` is used to determine the place in the wiki hierarchy.
+       protected fun new_section(path: String): WikiSection do
+               path = path.simplify_path
+               if entries.has_key(path) then return entries[path].as(WikiSection)
+               var root = expand_path(config.root_dir, config.source_dir)
+               var name = path.basename("")
+               var section = new WikiSection(self, name)
+               entries[path] = section
+               if path == root then return section
+               var ppath = path.dirname
+               if ppath != path  then
+                       var parent = new_section(ppath)
+                       parent.add_child(section)
+               end
+               section.try_load_config
+               return section
+       end
+
+       # Create a new `WikiArticle`.
+       #
+       # `path` is used to determine the ancestor sections.
+       protected fun new_article(path: String): WikiArticle do
+               if entries.has_key(path) then return entries[path].as(WikiArticle)
+               var article = new WikiArticle.from_source(self, path)
+               var section = new_section(path.dirname)
+               section.add_child(article)
+               entries[path] = article
+               return article
+       end
+
+       # Wiki entries found in the last `lookup_hierarchy`.
+       var entries = new HashMap[String, WikiEntry]
+
+       # The root `WikiSection` of the site found in the last `lookup_hierarchy`.
+       var root_section: WikiSection is noinit
+
+       # Does a template named `name` exists for this wiki?
+       fun has_template(name: String): Bool do
+               return expand_path(config.root_dir, config.templates_dir, name).file_exists
+       end
+
+       # Load a template file as a `TemplateString`.
+       #
+       # REQUIRE: `has_template`
+       fun load_template(name: String): TemplateString do
+               assert has_template(name)
+               var file = expand_path(config.root_dir, config.templates_dir, name)
+               var tpl = new TemplateString.from_file(file)
+               if tpl.has_macro("ROOT_URL") then
+                       tpl.replace("ROOT_URL", config.root_url)
+               end
+               if tpl.has_macro("TITLE") then
+                       tpl.replace("TITLE", config.wiki_name)
+               end
+               if tpl.has_macro("SUBTITLE") then
+                       tpl.replace("SUBTITLE", config.wiki_desc)
+               end
+               if tpl.has_macro("LOGO") then
+                       tpl.replace("LOGO", config.wiki_logo)
+               end
+               return tpl
+       end
+
+       # Join `parts` as a path and simplify it
+       fun expand_path(parts: String...): String do
+               var path = ""
+               for part in parts do
+                       path = path.join_path(part)
+               end
+               return path.simplify_path
+       end
+
+       fun pretty_name(name: String): String do
+               name = name.replace("_", " ")
+               name = name.capitalized
+               return name
+       end
+end
+
+# A wiki is composed of hierarchical entries.
+abstract class WikiEntry
+
+       # `Nitiwiki` this entry belongs to.
+       var wiki: Nitiwiki
+
+       # Entry data
+
+       # Entry internal name.
+       #
+       # Mainly used in urls.
+       var name: String
+
+       # Displayed title for `self`.
+       #
+       # If `self` is the root entry then display the wiki `WikiConfig::wiki_name` instead.
+       fun title: String do
+               if is_root then return wiki.config.wiki_name
+               return wiki.pretty_name(name)
+       end
+
+       # Is this section rendered from a source document?
+       #
+       # Source is an abstract concept at this level.
+       # It can represent a directory, a source file,
+       # a part of a file, everything needed to
+       # extend this base framework.
+       fun has_source: Bool do return src_path != null
+
+       # Entry creation time.
+       #
+       # Returns `-1` if not `has_source`.
+       fun create_time: Int do
+               if not has_source then return -1
+               return src_full_path.file_stat.ctime
+       end
+
+       # Entry last modification time.
+       #
+       # Returns `-1` if not `has_source`.
+       fun last_edit_time: Int do
+               if not has_source then return -1
+               return src_full_path.file_stat.mtime
+       end
+
+       # Entry list rendering time.
+       #
+       # Returns `-1` if `is_new`.
+       fun last_render_time: Int do
+               if is_new then return -1
+               return out_full_path.file_stat.mtime
+       end
+
+       # Entries hierarchy
+
+       # Type of the parent entry.
+       type PARENT: WikiEntry
+
+       # Parent entry if any.
+       var parent: nullable PARENT = null
+
+       # Does `self` have a parent?
+       fun is_root: Bool do return parent == null
+
+       # Children labelled by `name`.
+       var children = new HashMap[String, WikiEntry]
+
+       # Does `self` have a child nammed `name`?
+       fun has_child(name: String): Bool do return children.keys.has(name)
+
+       # Retrieve the child called `name`.
+       fun child(name: String): WikiEntry do return children[name]
+
+       # Add a sub-entry to `self`.
+       fun add_child(entry: WikiEntry) do
+               entry.parent = self
+               children[entry.name] = entry
+       end
+
+       # Paths and urls
+
+       # Breadcrumbs from the `Nitiwiki::root_section` to `self`.
+       #
+       # Result is returned as an array containg ordered entries:
+       # `breadcrumbs.first` is the root entry and
+       # `breadcrumbs.last == self`
+       fun breadcrumbs: Array[WikiEntry] is cached do
+               var path = new Array[WikiEntry]
+               var entry: nullable WikiEntry = self
+               while entry != null and not entry.is_root do
+                       path.add entry
+                       entry = entry.parent
+               end
+               return path.reversed
+       end
+
+       # Relative path from `wiki.config.root_dir` to source if any.
+       fun src_path: nullable String is abstract
+
+       # Absolute path to the source if any.
+       fun src_full_path: nullable String do
+               var src = src_path
+               if src == null then return null
+               return wiki.config.root_dir.join_path(src)
+       end
+
+       # Relative path from `wiki.config.root_dir` to rendered output.
+       #
+       # Like `src_path`, this method can represent a
+       # directory or a file.
+       fun out_path: String is abstract
+
+       # Absolute path to the output.
+       fun out_full_path: String do return wiki.config.root_dir.join_path(out_path)
+
+       # Rendering
+
+       # Does `self` have already been rendered?
+       fun is_new: Bool do return not out_full_path.file_exists
+
+       # Does `self` rendered output is outdated?
+       #
+       # Returns `true` if `is_new` then check in children.
+       fun is_dirty: Bool do
+               if is_new then return true
+               if has_source then
+                       if last_edit_time >= last_render_time then return true
+               end
+               for child in children.values do
+                       if child.is_dirty then return true
+               end
+               return false
+       end
+
+       # Render `self` and `children` is needed.
+       fun render do for child in children.values do child.render
+
+       # Templating
+
+       # Template file for `self`.
+       #
+       # Each entity can use a custom template.
+       # By default the template is inherited from the parent.
+       #
+       # If the root does not have a custom template,
+       # then returns the main wiki template file.
+       fun template_file: String do
+               if is_root then return wiki.config.template_file
+               return parent.template_file
+       end
+
+       # Header template file for `self`.
+       #
+       # Behave like `template_file`.
+       fun header_file: String do
+               if is_root then return wiki.config.header_file
+               return parent.header_file
+       end
+
+       # Footer template file for `self`.
+       #
+       # Behave like `template_file`.
+       fun footer_file: String do
+               if is_root then return wiki.config.footer_file
+               return parent.footer_file
+       end
+
+       # Menu template file for `self`.
+       #
+       # Behave like `template_file`.
+       fun menu_file: String do
+               if is_root then return wiki.config.menu_file
+               return parent.menu_file
+       end
+
+       # Display the entry `name`.
+       redef fun to_s do return name
+end
+
+# Each WikiSection is related to a source directory.
+#
+# A section can contain other sub-sections or pages.
+class WikiSection
+       super WikiEntry
+
+       # A section can only have another section as parent.
+       redef type PARENT: WikiSection
+
+       redef fun title do
+               if has_config then
+                       var title = config.title
+                       if title != null then return title
+               end
+               return super
+       end
+
+       # Is this section hidden?
+       #
+       # Hidden section are rendered but not linked in menus.
+       fun is_hidden: Bool do
+               if has_config then return config.is_hidden
+               return false
+       end
+
+       # Source directory.
+       redef fun src_path: String do
+               if parent == null then
+                       return wiki.config.source_dir
+               else
+                       return wiki.expand_path(parent.src_path, name)
+               end
+       end
+
+       # Config
+
+       # Custom configuration file for this section.
+       var config: nullable SectionConfig = null
+
+       # Does this section have its own config file?
+       fun has_config: Bool do return config != null
+
+       # Try to load the config file for this section.
+       private fun try_load_config do
+               var cfile = wiki.expand_path(wiki.config.root_dir, src_path, wiki.config_filename)
+               if not cfile.file_exists then return
+               wiki.message("Custom config for section {name}", 2)
+               config = new SectionConfig(cfile)
+       end
+
+       # Templating
+
+       # Also check custom config.
+       redef fun template_file do
+               if has_config then
+                       var tpl = config.template_file
+                       if tpl != null then return tpl
+               end
+               if is_root then return wiki.config.template_file
+               return parent.template_file
+       end
+
+       # Also check custom config.
+       redef fun header_file do
+               if has_config then
+                       var tpl = config.header_file
+                       if tpl != null then return tpl
+               end
+               if is_root then return wiki.config.header_file
+               return parent.header_file
+       end
+
+       # Also check custom config.
+       redef fun footer_file do
+               if has_config then
+                       var tpl = config.footer_file
+                       if tpl != null then return tpl
+               end
+               if is_root then return wiki.config.footer_file
+               return parent.footer_file
+       end
+
+       # Also check custom config.
+       redef fun menu_file do
+               if has_config then
+                       var tpl = config.menu_file
+                       if tpl != null then return tpl
+               end
+               if is_root then return wiki.config.menu_file
+               return parent.menu_file
+       end
+end
+
+# Each WikiArticle is related to a HTML file.
+#
+# Article can be created from scratch using this API or
+# automatically from a markdown source file (see: `from_source`).
+class WikiArticle
+       super WikiEntry
+
+       # Articles can only have `WikiSection` as parents.
+       redef type PARENT: WikiSection
+
+       redef fun title: String do
+               if name == "index" and parent != null then return parent.title
+               return super
+       end
+
+       # Page content.
+       #
+       # What you want to be displayed in the page.
+       var content: nullable Streamable = null
+
+       # Headlines ids and titles.
+       var headlines = new ArrayMap[String, HeadLine]
+
+       # Create a new articleu sing a markdown source file.
+       init from_source(wiki: Nitiwiki, md_file: String) do
+               src_full_path = md_file
+               init(wiki, md_file.basename(".md"))
+               var md_proc = new MarkdownProcessor
+               content = md_proc.process(md)
+               headlines = md_proc.emitter.decorator.headlines
+       end
+
+       redef var src_full_path: nullable String = null
+
+       redef fun src_path do
+               if src_full_path == null then return null
+               return src_full_path.substring_from(wiki.config.root_dir.length)
+       end
+
+       # The page markdown source content.
+       #
+       # Extract the markdown text from `source_file`.
+       #
+       # REQUIRE: `has_source`.
+       fun md: String is cached do
+               assert has_source
+               var file = new IFStream.open(src_full_path.to_s)
+               var md = file.read_all
+               file.close
+               return md
+       end
+
+       # Returns true if has source and
+       # `last_edit_date` > 'last_render_date'.
+       redef fun is_dirty do
+               if super then return true
+               if has_source then
+                       return wiki.need_render(src_full_path.to_s, out_full_path)
+               end
+               return false
+       end
+
+       redef fun to_s do return "{name} ({parent or else "null"})"
+end
+
+# Wiki configuration class.
+#
+# This class provides services that ensure static typing when accessing the `config.ini` file.
+class WikiConfig
+       super ConfigTree
+
+       # Returns the config value at `key` or return `default` if no key was found.
+       private fun value_or_default(key: String, default: String): String do
+               if not has_key(key) then return default
+               return self[key]
+       end
+
+       # Site name displayed.
+       #
+       # The title is used as home title and in headers.
+       #
+       # * key: `wiki.name`
+       # * default: `MyWiki`
+       fun wiki_name: String is cached do return value_or_default("wiki.name", "MyWiki")
+
+       # Site description.
+       #
+       # Displayed in header.
+       #
+       # * key: `wiki.desc`
+       # * default: ``
+       fun wiki_desc: String is cached do return value_or_default("wiki.desc", "")
+
+       # Site logo url.
+       #
+       # Url of the image to be displayed in header.
+       #
+       # * key: `wiki.logo`
+       # * default: ``
+       fun wiki_logo: String is cached do return value_or_default("wiki.logo", "")
+
+       # Root url of the wiki.
+       #
+       # * key: `wiki.root_url`
+       # * default: `http://localhost/`
+       fun root_url: String is cached do return value_or_default("wiki.root_url", "http://localhost/")
+
+
+       # Root directory of the wiki.
+       #
+       # Directory where the wiki files are stored locally.
+       #
+       # * key: `wiki.root_dir`
+       # * default: `./`
+       fun root_dir: String is cached do return value_or_default("wiki.root_dir", "./").simplify_path
+
+       # Pages directory.
+       #
+       # Directory where markdown source files are stored.
+       #
+       # * key: `wiki.source_dir
+       # * default: `pages/`
+       fun source_dir: String is cached do
+               return value_or_default("wiki.source_dir", "pages/").simplify_path
+       end
+
+       # Output directory.
+       #
+       # Directory where public wiki files are generated.
+       # **This path MUST be relative to `root_dir`.**
+       #
+       # * key: `wiki.out_dir`
+       # * default: `out/`
+       fun out_dir: String is cached do return value_or_default("wiki.out_dir", "out/").simplify_path
+
+       # Asset files directory.
+       #
+       # Directory where public assets like JS scripts or CSS files are stored.
+       # **This path MUST be relative to `root_dir`.**
+       #
+       # * key: `wiki.assets_dir`
+       # * default: `assets/`
+       fun assets_dir: String is cached do
+               return value_or_default("wiki.assets_dir", "assets/").simplify_path
+       end
+
+       # Template files directory.
+       #
+       # Directory where template used in HTML generation are stored.
+       # **This path MUST be relative to `root_dir`.**
+       #
+       # * key: `wiki.templates_dir`
+       # * default: `templates/`
+       fun templates_dir: String is cached do
+               return value_or_default("wiki.templates_dir", "templates/").simplify_path
+       end
+
+       # Main template file.
+       #
+       # The main template is used to specify the overall structure of a page.
+       #
+       # * key: `wiki.template`
+       # * default: `template.html`
+       fun template_file: String is cached do
+               return value_or_default("wiki.template", "template.html")
+       end
+
+       # Main header template file.
+       #
+       # Used to specify the structure of the page header.
+       # This is generally the place where you want to put your logo and wiki title.
+       #
+       # * key: `wiki.header`
+       # * default: `header.html`
+       fun header_file: String is cached do
+               return value_or_default("wiki.header", "header.html")
+       end
+
+       # Main menu template file.
+       #
+       # Used to specify the menu structure.
+       #
+       # * key: `wiki.menu`
+       # * default: `menu.html`
+       fun menu_file: String is cached do
+               return value_or_default("wiki.menu", "menu.html")
+       end
+
+       # Main footer file.
+       #
+       # The main footer is used to specify the structure of the page footer.
+       # This is generally the place where you want to put your copyright.
+       #
+       # * key: `wiki.footer`
+       # * default: `footer.html`
+       fun footer_file: String is cached do
+               return value_or_default("wiki.footer", "footer.html")
+       end
+
+       # Directory used by rsync to upload wiki files.
+       #
+       # This information is used to update your distant wiki files (like the webserver).
+       #
+       # * key: `wiki.rsync_dir`
+       # * default: ``
+       fun rsync_dir: String is cached do return value_or_default("wiki.rsync_dir", "")
+
+       # Remote repository used to pull modifications on sources.
+       #
+       # * key: `wiki.git_origin`
+       # * default: `origin`
+       fun git_origin: String is cached do return value_or_default("wiki.git_origin", "origin")
+
+       # Remote branch used to pull modifications on sources.
+       #
+       # * key: `wiki.git_branch`
+       # * default: `master`
+       fun git_branch: String is cached do return value_or_default("wiki.git_branch", "master")
+end
+
+# WikiSection custom configuration.
+#
+# Each section can provide its own config file to customize
+# appearance or behavior.
+class SectionConfig
+       super ConfigTree
+
+       # Returns the config value at `key` or `null` if no key was found.
+       private fun value_or_null(key: String): nullable String do
+               if not has_key(key) then return null
+               return self[key]
+       end
+
+       # Is this section hidden in sitemap and trees and menus?
+       fun is_hidden: Bool do return value_or_null("section.hidden") == "true"
+
+       # Custom section title if any.
+       fun title: nullable String do return value_or_null("section.title")
+
+       # Custom template file if any.
+       fun template_file: nullable String do return value_or_null("section.template")
+
+       # Custom header file if any.
+       fun header_file: nullable String do return value_or_null("section.header")
+
+       # Custom menu file if any.
+       fun menu_file: nullable String do return value_or_null("section.menu")
+
+       # Custom footer file if any.
+       fun footer_file: nullable String do return value_or_null("section.footer")
+end
diff --git a/contrib/nitiwiki/src/wiki_html.nit b/contrib/nitiwiki/src/wiki_html.nit
new file mode 100644 (file)
index 0000000..266e1d9
--- /dev/null
@@ -0,0 +1,437 @@
+# 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.
+
+# HTML wiki rendering
+module wiki_html
+
+import wiki_base
+
+redef class Nitiwiki
+
+       # Render HTML output looking for changes in the markdown sources.
+       fun render do
+               if not root_section.is_dirty and not force_render then return
+               var out_dir = expand_path(config.root_dir, config.out_dir)
+               out_dir.mkdir
+               copy_assets
+               root_section.add_child make_sitemap
+               root_section.render
+       end
+
+       # Copy the asset directory to the (public) output directory.
+       private fun copy_assets do
+               var src = expand_path(config.root_dir, config.assets_dir)
+               var out = expand_path(config.root_dir, config.out_dir)
+               if need_render(src, expand_path(out, config.assets_dir)) then
+                       if src.file_exists then sys.system "cp -R {src} {out}"
+               end
+       end
+
+       # Build the wiki sitemap page.
+       private fun make_sitemap: WikiSitemap do
+               var sitemap = new WikiSitemap(self, "sitemap")
+               sitemap.is_dirty = true
+               return sitemap
+       end
+end
+
+redef class WikiEntry
+
+       # Url to `self` once generated.
+       fun url: String do return wiki.config.root_url.join_path(breadcrumbs.join("/"))
+
+       # Get a `<a>` template link to `self`
+       fun tpl_link: Streamable do
+               return "<a href=\"{url}\">{title}</a>"
+       end
+end
+
+redef class WikiSection
+
+       # Output directory (where to ouput the HTML pages for this section).
+       redef fun out_path: String do
+               if parent == null then
+                       return wiki.config.out_dir
+               else
+                       return wiki.expand_path(parent.out_path, name)
+               end
+       end
+
+       redef fun render do
+               if not is_dirty and not wiki.force_render then return
+               if is_new then
+                       out_full_path.mkdir
+               else
+                       sys.system "touch {out_full_path}"
+               end
+               if has_source then
+                       wiki.message("Render section {out_path}", 1)
+                       copy_files
+               end
+               var index = self.index
+               if index isa WikiSectionIndex then
+                       index.is_dirty = true
+                       add_child index
+               end
+               super
+       end
+
+       # Copy attached files from `src_path` to `out_path`.
+       private fun copy_files do
+               assert has_source
+               var dir = src_full_path.to_s
+               for name in dir.files do
+                       if name == wiki.config_filename then continue
+                       if name.has_suffix(".md") then continue
+                       if has_child(name) then continue
+                       var src = wiki.expand_path(dir, name)
+                       var out = wiki.expand_path(out_full_path, name)
+                       if not wiki.need_render(src, out) then continue
+                       sys.system "cp -R {src} {out_full_path}"
+               end
+       end
+
+       # The index page for this section.
+       #
+       # If no file `index.md` exists for this section,
+       # a summary is generated using contained articles.
+       fun index: WikiArticle is cached do
+               for child in children.values do
+                       if child isa WikiArticle and child.is_index then return child
+               end
+               return new WikiSectionIndex(wiki, self)
+       end
+
+       redef fun tpl_link do return index.tpl_link
+
+       # Render the section hierarchy as a html tree.
+       #
+       # `limit` is used to specify the max-depth of the tree.
+       #
+       # The generated tree will be something like this:
+       #
+       # ~~~html
+       # <ul>
+       #  <li>section 1</li>
+       #  <li>section 2
+       #   <ul>
+       #    <li>section 2.1</li>
+       #    <li>section 2.2</li>
+       #   </ul>
+       #  </li>
+       # </ul>
+       # ~~~
+       fun tpl_tree(limit: Int): Template do
+               return tpl_tree_intern(limit, 1)
+       end
+
+       # Build the template tree for this section recursively.
+       protected fun tpl_tree_intern(limit, count: Int): Template do
+               var out = new Template
+               var index = index
+               out.add "<li>"
+               out.add tpl_link
+               if (limit < 0 or count < limit) and
+                  (children.length > 1 or (children.length == 1)) then
+                       out.add " <ul>"
+                       for child in children.values do
+                               if child == index then continue
+                               if child isa WikiArticle then
+                                       out.add "<li>"
+                                       out.add child.tpl_link
+                                       out.add "</li>"
+                               else if child isa WikiSection and not child.is_hidden then
+                                       out.add child.tpl_tree_intern(limit, count + 1)
+                               end
+                       end
+                       out.add " </ul>"
+               end
+               out.add "</li>"
+               return out
+       end
+end
+
+redef class WikiArticle
+
+       redef fun out_path: String do
+               if parent == null then
+                       return wiki.expand_path(wiki.config.out_dir, "{name}.html")
+               else
+                       return wiki.expand_path(parent.out_path, "{name}.html")
+               end
+       end
+
+       redef fun url do
+               if parent == null then
+                       return wiki.config.root_url.join_path("{name}.html")
+               else
+                       return parent.url.join_path("{name}.html")
+               end
+       end
+
+       # Is `self` an index page?
+       #
+       # Checks if `self.name == "index"`.
+       fun is_index: Bool do return name == "index"
+
+       redef fun render do
+               if not is_dirty and not wiki.force_render then return
+               wiki.message("Render article {name}", 2)
+               var file = out_full_path
+               file.dirname.mkdir
+               tpl_page.write_to_file file
+               super
+       end
+
+
+       # Replace macros in the template by wiki data.
+       private fun tpl_page: TemplateString do
+               var tpl = wiki.load_template(template_file)
+               if tpl.has_macro("TOP_MENU") then
+                       tpl.replace("TOP_MENU", tpl_menu)
+               end
+               if tpl.has_macro("HEADER") then
+                       tpl.replace("HEADER", tpl_header)
+               end
+               if tpl.has_macro("BODY") then
+                       tpl.replace("BODY", tpl_article)
+               end
+               if tpl.has_macro("FOOTER") then
+                       tpl.replace("FOOTER", tpl_footer)
+               end
+               return tpl
+       end
+
+       # Generate the HTML header for this article.
+       fun tpl_header: Streamable do
+               var file = header_file
+               if not wiki.has_template(file) then return ""
+               return wiki.load_template(file)
+       end
+
+       # Generate the HTML page for this article.
+       fun tpl_article: TplArticle do
+               var article = new TplArticle
+               article.body = content
+               article.breadcrumbs = new TplBreadcrumbs(self)
+               tpl_sidebar.blocks.add tpl_summary
+               article.sidebar = tpl_sidebar
+               return article
+       end
+
+       # Sidebar for this page.
+       var tpl_sidebar = new TplSidebar
+
+       # Generate the HTML summary for this article.
+       #
+       # Based on `headlines`
+       fun tpl_summary: Streamable do
+               var headlines = self.headlines
+               var tpl = new Template
+               tpl.add "<ul class=\"summary list-unstyled\">"
+               var iter = headlines.iterator
+               while iter.is_ok do
+                       var hl = iter.item
+                       # parse title as markdown
+                       var title = hl.title.md_to_html.to_s
+                       title = title.substring(3, title.length - 8)
+                       tpl.add "<li><a href=\"#{hl.id}\">{title}</a>"
+                       iter.next
+                       if iter.is_ok then
+                               if iter.item.level > hl.level then
+                                       tpl.add "<ul class=\"list-unstyled\">"
+                               else if iter.item.level < hl.level then
+                                       tpl.add "</li>"
+                                       tpl.add "</ul>"
+                               end
+                       else
+                               tpl.add "</li>"
+                       end
+               end
+               tpl.add "</ul>"
+               return tpl
+       end
+
+       # Generate the HTML menu for this article.
+       fun tpl_menu: Streamable do
+               var file = menu_file
+               if not wiki.has_template(file) then return ""
+               var tpl = wiki.load_template(file)
+               if tpl.has_macro("MENUS") then
+                       var items = new Template
+                       for child in wiki.root_section.children.values do
+                               if child isa WikiArticle and child.is_index then continue
+                               if child isa WikiSection and child.is_hidden then continue
+                               items.add "<li"
+                               if self == child or self.breadcrumbs.has(child) then
+                                       items.add " class=\"active\""
+                               end
+                               items.add ">"
+                               items.add child.tpl_link
+                               items.add "</li>"
+                       end
+                       tpl.replace("MENUS", items)
+               end
+               return tpl
+       end
+
+       # Generate the HTML footer for this article.
+       fun tpl_footer: Streamable do
+               var file = footer_file
+               if not wiki.has_template(file) then return ""
+               var tpl = wiki.load_template(file)
+               var time = new Tm.gmtime
+               if tpl.has_macro("YEAR") then
+                       tpl.replace("YEAR", (time.year + 1900).to_s)
+               end
+               if tpl.has_macro("GEN_TIME") then
+                       tpl.replace("GEN_TIME", time.to_s)
+               end
+               return tpl
+       end
+end
+
+# A `WikiArticle` that contains the sitemap tree.
+class WikiSitemap
+       super WikiArticle
+
+       redef fun tpl_article do
+               var article = new TplArticle.with_title("Sitemap")
+               article.body = new TplPageTree(wiki.root_section, -1)
+               return article
+       end
+
+       redef var is_dirty = false
+end
+
+# A `WikiArticle` that contains the section index tree.
+class WikiSectionIndex
+       super WikiArticle
+
+       # The section described by `self`.
+       var section: WikiSection
+
+       init(wiki: Nitiwiki, section: WikiSection) do
+               super(wiki, "index")
+               self.section = section
+       end
+
+       redef var is_dirty = false
+
+       redef fun tpl_article do
+               var article = new TplArticle.with_title(section.title)
+               article.body = new TplPageTree(section, -1)
+               article.breadcrumbs = new TplBreadcrumbs(self)
+               return article
+       end
+end
+
+# Article HTML output.
+class TplArticle
+       super Template
+
+       var title: nullable Streamable = null
+       var body: nullable Streamable = null
+       var sidebar: nullable TplSidebar = null
+       var breadcrumbs: nullable TplBreadcrumbs = null
+
+       init with_title(title: Streamable) do
+               self.title = title
+       end
+
+       redef fun rendering do
+               if sidebar != null then
+                       add "<div class=\"col-sm-3 sidebar\">"
+                       add sidebar.as(not null)
+                       add "</div>"
+                       add "<div class=\"col-sm-9 content\">"
+               else
+                       add "<div class=\"col-sm-12 content\">"
+               end
+               if body != null then
+                       add "<article>"
+                       if breadcrumbs != null then
+                               add breadcrumbs.as(not null)
+                       end
+                       if title != null then
+                               add "<h1>"
+                               add title.as(not null)
+                               add "</h1>"
+                       end
+                       add     body.as(not null)
+                       add " </article>"
+               end
+               add "</div>"
+       end
+end
+
+# A collection of HTML blocks displayed on the side of a page.
+class TplSidebar
+       super Template
+
+       # Blocks are `Stremable` pieces that will be rendered in the sidebar.
+       var blocks = new Array[Streamable]
+
+       redef fun rendering do
+               for block in blocks do
+                       add "<div class=\"sideblock\">"
+                       add block
+                       add "</div>"
+               end
+       end
+end
+
+# An HTML breadcrumbs that show the path from a `WikiArticle` to the `Nitiwiki` root.
+class TplBreadcrumbs
+       super Template
+
+       # Bread crumb article.
+       var article: WikiArticle
+
+       redef fun rendering do
+               var path = article.breadcrumbs
+               if path.is_empty or path.length <= 2 and article.is_index then return
+               add "<ol class=\"breadcrumb\">"
+               for entry in path do
+                       if entry == path.last then
+                               add "<li class=\"active\">"
+                               add entry.title
+                               add "</li>"
+                       else
+                               if article.parent == entry and article.is_index then continue
+                               add "<li>"
+                               add entry.tpl_link
+                               add "</li>"
+                       end
+               end
+               add "</ol>"
+       end
+end
+
+# An HTML tree that show the section pages structure.
+class TplPageTree
+       super Template
+
+       # Builds the page tree from `root`.
+       var root: WikiSection
+
+       # Limits the tree depth to `max_depth` levels.
+       var max_depth: Int
+
+       redef fun rendering do
+               add "<ul>"
+               add root.tpl_tree(-1)
+               add "</ul>"
+       end
+end
diff --git a/contrib/nitiwiki/tests/Makefile b/contrib/nitiwiki/tests/Makefile
new file mode 100644 (file)
index 0000000..0dce637
--- /dev/null
@@ -0,0 +1,21 @@
+# Copyright 2013 Alexandre Terrasa <alexandre@moz-code.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.
+
+all: tests
+
+tests: clean
+       ./tests.sh
+
+clean:
+       rm -rf out/
diff --git a/contrib/nitiwiki/tests/nitiwiki.args b/contrib/nitiwiki/tests/nitiwiki.args
new file mode 100644 (file)
index 0000000..b5abeca
--- /dev/null
@@ -0,0 +1 @@
+nitiwiki
diff --git a/contrib/nitiwiki/tests/nitiwiki_render.args b/contrib/nitiwiki/tests/nitiwiki_render.args
new file mode 100644 (file)
index 0000000..6f7050e
--- /dev/null
@@ -0,0 +1 @@
+nitiwiki --config wiki1/config.ini --clean --render -v
diff --git a/contrib/nitiwiki/tests/nitiwiki_status.args b/contrib/nitiwiki/tests/nitiwiki_status.args
new file mode 100644 (file)
index 0000000..aa96d13
--- /dev/null
@@ -0,0 +1 @@
+nitiwiki --config wiki1/config.ini --clean --status
diff --git a/contrib/nitiwiki/tests/res/nitiwiki.res b/contrib/nitiwiki/tests/res/nitiwiki.res
new file mode 100644 (file)
index 0000000..232b5ef
--- /dev/null
@@ -0,0 +1,2 @@
+Not in a nitiwiki directory.
+Use --init to initialize one here.
diff --git a/contrib/nitiwiki/tests/res/nitiwiki_render.res b/contrib/nitiwiki/tests/res/nitiwiki_render.res
new file mode 100644 (file)
index 0000000..adf25a7
--- /dev/null
@@ -0,0 +1 @@
+Render section out
diff --git a/contrib/nitiwiki/tests/res/nitiwiki_status.res b/contrib/nitiwiki/tests/res/nitiwiki_status.res
new file mode 100644 (file)
index 0000000..936a764
--- /dev/null
@@ -0,0 +1,10 @@
+nitiWiki
+name: wiki1
+config: wiki1/config.ini
+url: http://localhost/
+
+There is modified files:
+ + pages
+ + /pages/index.md
+
+Use nitiwiki --render to render modified files
diff --git a/contrib/nitiwiki/tests/tests.sh b/contrib/nitiwiki/tests/tests.sh
new file mode 100755 (executable)
index 0000000..2acbe94
--- /dev/null
@@ -0,0 +1,92 @@
+#!/bin/bash
+
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexandre Terrasa <alexandre@moz-code.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.
+
+BIN=../bin
+OUT=./out
+RES=./res
+
+# check args files
+test_args()
+{
+       local test="$1"
+       local args=`cat $test.args`
+       local outdir=$OUT/$test.files
+
+       echo $BIN/$args > $OUT/$test.bin
+       chmod +x $OUT/$test.bin
+       OUTDIR=$outdir $OUT/$test.bin > $OUT/$test.res 2> $OUT/$test.err
+
+       if [ -r $outdir ]; then
+               ls -aR $outdir >> $OUT/$test.res
+       fi
+
+       diff $OUT/$test.res $RES/$test.res > $OUT/$test.diff 2> /dev/null
+}
+
+# return
+#  0 if the sav not exists
+#  1 if the file does match
+#  2 if the file does not match
+check_result() {
+       local test="$1"
+
+       if [ ! -r "$RES/$test.res" ]; then
+               return 0
+       elif [ ! -s $OUT/$test.diff ]; then
+               return 1
+       else
+               return 2
+       fi
+}
+
+echo "Testing..."
+echo ""
+
+rm -rf $OUT 2>/dev/null
+mkdir $OUT 2>/dev/null
+
+all=0
+ok=0
+ko=0
+sk=0
+
+for file in `ls *.args`; do
+       ((all++))
+       test="${file%.*}"
+       echo -n "* $test: "
+
+       test_args $test
+       check_result $test
+
+       case "$?" in
+               0)
+                       echo "skip ($test.res not found)"
+                       ((sk++))
+                       continue;;
+               1)
+                       echo "success"
+                       ((ok++))
+                       ;;
+               2)
+                       echo "error (diff $OUT/$test.res $RES/$test.res)"
+                       ((ko++))
+                       ;;
+       esac
+done
+echo ""
+echo "==> success $ok/$all ($ko tests failed, $sk skipped)"
diff --git a/contrib/nitiwiki/tests/wiki1/assets/css/main.css b/contrib/nitiwiki/tests/wiki1/assets/css/main.css
new file mode 100644 (file)
index 0000000..d58b78d
--- /dev/null
@@ -0,0 +1 @@
+dummy { margin: 0 }
diff --git a/contrib/nitiwiki/tests/wiki1/config.ini b/contrib/nitiwiki/tests/wiki1/config.ini
new file mode 100644 (file)
index 0000000..c24bdd7
--- /dev/null
@@ -0,0 +1,2 @@
+wiki.name=wiki1
+wiki.root_dir=wiki1/
diff --git a/contrib/nitiwiki/tests/wiki1/config2.ini b/contrib/nitiwiki/tests/wiki1/config2.ini
new file mode 100644 (file)
index 0000000..4ebb07b
--- /dev/null
@@ -0,0 +1,3 @@
+wiki.name=wiki2
+wiki.desc=the one used by nit/tests.sh
+wiki.root_dir=../contrib/nitiwiki/tests/wiki1/
diff --git a/contrib/nitiwiki/tests/wiki1/pages/index.md b/contrib/nitiwiki/tests/wiki1/pages/index.md
new file mode 100644 (file)
index 0000000..cc0be1e
--- /dev/null
@@ -0,0 +1 @@
+# Hello World!
diff --git a/contrib/nitiwiki/tests/wiki1/templates/footer.html b/contrib/nitiwiki/tests/wiki1/templates/footer.html
new file mode 100644 (file)
index 0000000..7506b39
--- /dev/null
@@ -0,0 +1,10 @@
+<div class="row footer">
+       <div class="container-fluid">
+               <div class="well well-sm">
+                       <p><strong>%TITLE% &copy; %YEAR%</strong></p>
+                       <p class="text-muted"><em>last modification %GEN_TIME%</em></p>
+                       <p class="text-muted">Proudly powered by
+                               <a href="http://nitlanguage.org">nit</a>!</p>
+               </div>
+       </div>
+</div>
diff --git a/contrib/nitiwiki/tests/wiki1/templates/header.html b/contrib/nitiwiki/tests/wiki1/templates/header.html
new file mode 100644 (file)
index 0000000..1cb06bf
--- /dev/null
@@ -0,0 +1,9 @@
+<div class="container-fluid header">
+       <div class="container">
+               <div class="header">
+                       <a href="http://uqam.ca"><img src="%ROOT_URL%/%LOGO%" alt="logo" /></a>
+                       <h2>%SUBTITLE%</h2>
+                       <h1>%TITLE%</h1>
+               </div>
+       </div>
+</div>
diff --git a/contrib/nitiwiki/tests/wiki1/templates/menu.html b/contrib/nitiwiki/tests/wiki1/templates/menu.html
new file mode 100644 (file)
index 0000000..1ff832e
--- /dev/null
@@ -0,0 +1,20 @@
+<nav class="menu" role="navigation">
+       <div class="container">
+               <!-- Brand and toggle get grouped for better mobile display -->
+               <div class="navbar-header">
+                       <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
+                               <span class="sr-only">Toggle navigation</span>
+                               <span class="icon-bar"></span>
+                               <span class="icon-bar"></span>
+                               <span class="icon-bar"></span>
+                       </button>
+                       <a class="navbar-brand" href="%ROOT_URL%index.html">%TITLE%</a>
+               </div>
+               <!-- Collect the nav links, forms, and other content for toggling -->
+               <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
+                       <ul class="nav navbar-nav">
+                       %MENUS%
+                       </ul>
+               </div><!-- /.navbar-collapse -->
+       </div>
+</nav>
diff --git a/contrib/nitiwiki/tests/wiki1/templates/template.html b/contrib/nitiwiki/tests/wiki1/templates/template.html
new file mode 100644 (file)
index 0000000..6b3b126
--- /dev/null
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html lang="en">
+       <head>
+               <meta charset="utf-8">
+               <meta http-equiv="X-UA-Compatible" content="IE=edge">
+               <meta name="viewport" content="width=device-width, initial-scale=1">
+               <title>%TITLE%</title>
+
+               <link href="%ROOT_URL%/assets/vendors/bootstrap/bootstrap-3.2.0-dist/css/bootstrap.min.css" rel="stylesheet">
+               <link href="%ROOT_URL%/assets/css/main.css" rel="stylesheet">
+
+               <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
+               <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
+               <!--[if lt IE 9]>
+               <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
+               <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
+               <![endif]-->
+       </head>
+       <body>
+               %HEADER%
+               %TOP_MENU%
+               <div class="container">
+                       <div class="row">
+                               %BODY%
+                       </div>
+                       %FOOTER%
+               </div>
+
+               <script src="%ROOT_URL%/vendors/jquery/jquery-1.11.1.min.js"></script>
+               <script src="%ROOT_URL%/vendors/bootstrap/bootstrap-3.2.0-dist/js/bootstrap.min.js"></script>
+       </body>
+</html>
index d50b84a..7d0e701 100644 (file)
@@ -21,7 +21,7 @@ import interpreter::naive_interpreter
 import interpreter::debugger
 import pnacl
 intrude import toolcontext
-intrude import modelbuilder
+intrude import loader
 intrude import standard::file
 
 # We redefine exit to start a new thread before killing the one that called exit.
diff --git a/doc/Makefile b/doc/Makefile
new file mode 100644 (file)
index 0000000..91ae0c8
--- /dev/null
@@ -0,0 +1,2 @@
+all:
+       ${MAKE} docs -C ..
diff --git a/doc/README b/doc/README
deleted file mode 100644 (file)
index 0e23e6a..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-This directory contains various documentation for Nit
-
-* advanced_options [TXT]: documentation for advanced options of the compiler and run-time execution.
-* stdlib [HTML]: Autodocumentation for the Nit standard library.
-
-For more documentation, visit http://nitlanguage.org/doc/
diff --git a/doc/README.md b/doc/README.md
new file mode 100644 (file)
index 0000000..406cb02
--- /dev/null
@@ -0,0 +1,12 @@
+This directory contains auto-documentation generated by nitdoc.
+
+ * [stdlib](http://nitlanguage.org/doc/stdlib/): the Nit libraries (from `../lib/`).
+ * [nitc](http://nitlanguage.org/doc/nitc/): the Nit tools (from `../src/`).
+
+Run `make` to produce them.
+
+Specific documentation can be found elsewhere:
+
+ * The manpages of the Nit tools are in the directory `../share/man`
+ * The documentation of the other tools and programs are in their subdirectories in `../examples` and `../contrib`
+ * For more documentation, visit <http://nitlanguage.org/doc/>
index 9782660..acb600b 100644 (file)
@@ -1,3 +1,8 @@
 all:
        mkdir -p bin/
-       ../../bin/nitg --dir bin/ src/calculator_test.nit src/calculator_gtk.nit
+       ../../bin/nitg --dir bin/ src/calculator_gtk.nit src/calculator_test.nit
+
+android:
+       mkdir -p bin/ res/
+       ../../contrib/inkscape_tools/bin/svg_to_icons art/icon.svg --android --out res/
+       ../../bin/nitg -o bin/calculator.apk src/calculator_android.nit
diff --git a/examples/calculator/art/icon.svg b/examples/calculator/art/icon.svg
new file mode 100644 (file)
index 0000000..ccd533c
--- /dev/null
@@ -0,0 +1,139 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="512"
+   height="512"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.5 r10040"
+   sodipodi:docname="icon.svg">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.9899495"
+     inkscape:cx="58.64005"
+     inkscape:cy="380.00465"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1601"
+     inkscape:window-height="1316"
+     inkscape:window-x="2646"
+     inkscape:window-y="84"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(0,-540.36218)">
+    <rect
+       style="fill:#4d4d4d;fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect2987"
+       width="500"
+       height="500"
+       x="5.9999847"
+       y="546.36218"
+       rx="64"
+       ry="64" />
+    <rect
+       ry="48"
+       rx="48"
+       y="569.2193"
+       x="32.42857"
+       height="211.42856"
+       width="211.42856"
+       id="rect2989"
+       style="fill:#cccccc;fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none" />
+    <rect
+       style="fill:#cccccc;fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect2991"
+       width="211.42856"
+       height="211.42856"
+       x="268.14285"
+       y="569.2193"
+       rx="48"
+       ry="48" />
+    <rect
+       style="fill:#cccccc;fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect2993"
+       width="211.42856"
+       height="211.42856"
+       x="32.42857"
+       y="806.36218"
+       rx="48"
+       ry="48" />
+    <rect
+       ry="48"
+       rx="48"
+       y="806.36218"
+       x="268.14285"
+       height="211.42856"
+       width="211.42856"
+       id="rect2995"
+       style="fill:#cccccc;fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none" />
+    <text
+       xml:space="preserve"
+       style="font-size:269.1137085px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+       x="299.74573"
+       y="770.06946"
+       id="text2997"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan2999"
+         x="299.74573"
+         y="770.06946">+</tspan></text>
+    <path
+       inkscape:connector-curvature="0"
+       id="path3018"
+       style="font-size:269.1137085px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+       d="m 313.14886,921.9317 0,-19.71047 121.41654,0 0,19.71047"
+       sodipodi:nodetypes="cccc" />
+    <path
+       inkscape:connector-curvature="0"
+       id="path2995"
+       style="font-size:202.30386353px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+       d="m 170.83821,674.43965 c -1e-4,11.65624 -0.8562,22.0941 -2.56831,31.31363 -1.64645,9.21961 -4.34646,17.02331 -8.10005,23.41114 -3.68792,6.38786 -8.46234,11.26106 -14.32328,14.61962 -5.86108,3.35856 -12.97332,5.03783 -21.33673,5.03784 -7.77084,-10e-6 -14.5538,-1.67928 -20.34892,-5.03784 -5.729341,-3.35856 -10.50376,-8.23176 -14.323274,-14.61962 -3.753702,-6.38783 -6.585427,-14.19153 -8.495182,-23.41114 -1.843926,-9.21953 -2.765883,-19.65739 -2.765873,-31.31363 -10e-6,-11.6561 0.823166,-22.09397 2.46953,-31.31364 1.712193,-9.21946 4.379282,-16.99024 8.001275,-23.31236 3.687807,-6.38772 8.4293,-11.26092 14.224494,-14.61961 5.86097,-3.35842 12.94028,-5.0377 21.23795,-5.03784 7.83658,1.4e-4 14.65247,1.67942 20.4477,5.03784 5.79508,3.29284 10.60243,8.13311 14.42206,14.52083 3.81944,6.32212 6.68409,14.09289 8.59396,23.31236 1.90967,9.21967 2.86455,19.69047 2.86465,31.41242 m -73.9871,0 c -2.8e-5,9.87818 0.493877,18.50506 1.481718,25.88067 0.987781,7.3757 2.568282,13.53305 4.741492,18.47208 2.17315,4.87322 5.00488,8.56105 8.49518,11.06349 3.55608,2.43662 7.86952,3.65492 12.94034,3.6549 5.07071,2e-5 9.38415,-1.21828 12.94033,-3.6549 3.55605,-2.43658 6.45363,-6.09148 8.69275,-10.96471 2.30481,-4.87317 3.95116,-10.9976 4.93906,-18.3733 1.05358,-7.44146 1.58041,-16.1342 1.5805,-26.07823 -9e-5,-9.87804 -0.52692,-18.50492 -1.5805,-25.88068 -0.9879,-7.37555 -2.63425,-13.49998 -4.93906,-18.3733 -2.23912,-4.87308 -5.1367,-8.52798 -8.69275,-10.96471 -3.55618,-2.43647 -7.86962,-3.65477 -12.94033,-3.6549 -5.07082,1.3e-4 -9.38426,1.21843 -12.94034,3.6549 -3.4903,2.43673 -6.32203,6.09163 -8.49518,10.96471 -2.17321,4.87332 -3.753711,10.99775 -4.741492,18.3733 -0.987841,7.37576 -1.481746,16.00264 -1.481718,25.88068" />
+    <path
+       inkscape:connector-curvature="0"
+       id="path2997"
+       style="font-size:202.30386353px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+       d="m 179.68975,735.88154 c -1e-5,-2.50244 0.32926,-4.60977 0.98782,-6.32199 0.65852,-1.77805 1.54755,-3.19391 2.66709,-4.2476 1.1195,-1.11949 2.43658,-1.90974 3.95125,-2.37074 1.51462,-0.52681 3.16097,-0.79023 4.93905,-0.79025 1.71218,2e-5 3.32561,0.26344 4.84028,0.79025 1.58047,0.461 2.93048,1.25125 4.05003,2.37074 1.11948,1.05369 2.00851,2.46955 2.66709,4.2476 0.65851,1.71222 0.98778,3.81955 0.98782,6.32199 -4e-5,2.43661 -0.32931,4.54394 -0.98782,6.322 -0.65858,1.71221 -1.54761,3.12807 -2.66709,4.24759 -1.11955,1.11952 -2.46956,1.94269 -4.05003,2.46953 -1.51467,0.52683 -3.1281,0.79024 -4.84028,0.79025 -1.77808,-10e-6 -3.42443,-0.26342 -4.93905,-0.79025 -1.51467,-0.52684 -2.83175,-1.35001 -3.95125,-2.46953 -1.11954,-1.11952 -2.00857,-2.53538 -2.66709,-4.24759 -0.65856,-1.77806 -0.98783,-3.88539 -0.98782,-6.322" />
+    <text
+       xml:space="preserve"
+       style="font-size:269.1137085px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+       x="64.031456"
+       y="1006.8839"
+       id="text3013"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3015"
+         x="64.031456"
+         y="1006.8839">=</tspan></text>
+  </g>
+</svg>
diff --git a/examples/calculator/src/calculator_android.nit b/examples/calculator/src/calculator_android.nit
new file mode 100644 (file)
index 0000000..e66fea8
--- /dev/null
@@ -0,0 +1,108 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Android calculator application
+module calculator_android is
+       app_name "app.nit Calc."
+       app_version(0, 1, git_revision)
+       java_package "org.nitlanguage.calculator"
+
+       # Use a translucent background and lock in portrait mode
+       android_manifest_activity """
+               android:theme="@android:style/Theme.Holo.Wallpaper"
+               android:screenOrientation="portrait""""
+end
+
+import android
+import android::ui
+
+import calculator_logic
+
+redef class App
+       private var context = new CalculatorContext
+
+       # The main display, at the top of the screen
+       private var display: EditText
+
+       # Maps operators as `String` to their `Button`
+       private var op2but = new HashMap[String, Button]
+
+       # Has this window been initialized?
+       private var inited = false
+
+       redef fun init_window
+       do
+               super
+
+               if inited then return
+               inited = true
+
+               # Setup UI
+               var context = native_activity
+               var layout = new NativeLinearLayout(context)
+               layout.set_vertical
+
+               # Display screen
+               var display = new EditText
+               layout.add_view_with_weight(display.native, 1.0)
+               display.text_size = 36.0
+               self.display = display
+
+               # Buttons; numbers and operators
+               var ops = [["7", "8", "9", "+"],
+                          ["4", "5", "6", "-"],
+                          ["1", "2", "3", "*"],
+                          ["0", ".", "C", "/"],
+                          ["="]]
+
+               for line in ops do
+                       var buts_layout = new NativeLinearLayout(context)
+                       buts_layout.set_horizontal
+                       layout.add_view_with_weight(buts_layout, 1.0)
+
+                       for op in line do
+                               var but = new Button
+                               but.text = op
+                               but.text_size = 40
+                               buts_layout.add_view_with_weight(but.native, 1.0)
+                               op2but[op] = but
+                       end
+               end
+
+               context.content_view = layout
+       end
+
+       redef fun catch_event(event)
+       do
+               if event isa ClickEvent then
+                       var sender = event.sender
+                       var op = sender.text
+
+                       if op == "." then
+                               sender.enabled = false
+                               context.switch_to_decimals
+                       else if op.is_numeric then
+                               var n = op.to_i
+                               context.push_digit n
+                       else
+                               op2but["."].enabled = true
+                               context.push_op op.chars.first
+                       end
+
+                       display.text = context.display_text
+               end
+       end
+end
index b2564bf..c4ffc7f 100644 (file)
@@ -33,14 +33,14 @@ redef class App
        # Testing the assets manager
        fun test_assets
        do
-               assert asset_manager.bitmap("fighter.png") != null
+               assert asset_manager.bitmap("fighter.png").width == 32
        end
 
        # Testing the resources manager
        fun test_resources do
                assert resource_manager.string("string_test") == "string test"
                assert resource_manager.boolean("test_bool") == true
-               assert resource_manager.dimension("test_dimen_1") != null
-               assert resource_manager.dimension("test_dimen_2") != null
+               assert resource_manager.dimension("test_dimen_1") == 25
+               assert resource_manager.dimension("test_dimen_2") == 150
        end
 end
diff --git a/examples/rosettacode/empty_program.nit b/examples/rosettacode/empty_program.nit
new file mode 100644 (file)
index 0000000..3b4a7fb
--- /dev/null
@@ -0,0 +1,7 @@
+#!/usr/bin/env nit
+#
+# This file is part of NIT ( http://www.nitlanguage.org ).
+# This program is public domain
+
+# Task: Empty program
+# SEE: <http://rosettacode.org/wiki/Empty_program>
diff --git a/examples/rosettacode/hailstone.nit b/examples/rosettacode/hailstone.nit
new file mode 100644 (file)
index 0000000..c1351e1
--- /dev/null
@@ -0,0 +1,57 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+# This program is public domain
+# Copyright 2014 amineorion <amineorion@gmail.com>
+#
+# 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.
+#
+# Task: Hailstone sequence
+# SEE: <http://rosettacode.org/wiki/Hailstone_sequence>
+#
+# Not optimize version.
+
+module hailstone
+
+fun hailstone (n: Int): Array[Int]
+do
+       var sequence = [n]
+       while n != 1 do
+               if n.bin_and(0x01) == 0 then
+                       n = n / 2
+               else
+                       n = 3 * n + 1
+               end
+               sequence.add(n)
+       end
+       return sequence
+end
+var sequence27 = hailstone(27)
+var size27 = sequence27.length
+print "Sequence for 27 has {size27} begin with: {sequence27[0]}, " +
+                "{sequence27[1]}, {sequence27[2]}, {sequence27[3]} " +
+                "and end with: {sequence27[size27 - 4]}, {sequence27[size27 - 3]}, " +
+                "{sequence27[size27 - 2]}, {sequence27[size27 - 1]}"
+
+var max: Int = hailstone(1).length
+var max_sequence = hailstone(1)
+var max_element = 1
+
+for i in [2..100000] do
+       var sequence = hailstone(i)
+       if max < sequence.length then
+               max = sequence.length
+               max_element = i
+               max_sequence = sequence
+       end
+end
+print "The number with longest sequence is {max_element} " +
+               "with length of {max_sequence.length}"
diff --git a/examples/rosettacode/hamming_number.nit b/examples/rosettacode/hamming_number.nit
new file mode 100644 (file)
index 0000000..3ff8a44
--- /dev/null
@@ -0,0 +1,129 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+# This program is public domain
+# Copyright 2014 amineorion <amineorion@gmail.com>
+#
+# 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.
+#
+# Task: Hamming numbers
+# SEE: <http://rosettacode.org/wiki/Hamming_numbers>
+#
+# Version that don't support 1,000,000th position of Hamming number yet.
+
+module hamming_number
+
+class HammingTriple
+       super Comparable
+
+       var a: Int
+       var b: Int
+       var c: Int
+
+       redef type OTHER: HammingTriple
+
+       init(a: Int, b: Int, c: Int)
+       do
+               self.a = a
+               self.b = b
+               self.c = c
+       end
+
+       redef fun >(other: OTHER): Bool
+       do
+               if a > other.a and b > other.b and c > other.c then
+                       return true
+               end
+
+               if a < other.a and b < other.b and c < other.c then
+                       return false
+               end
+
+               if self == other then
+                       return false
+               end
+
+               var log1 = log
+               var log2 = other.log
+
+               if not log1.is_approx(log2, 0.000001) then
+                       return log1 > log2
+               end
+               return false
+       end
+
+       fun log: Float
+       do
+               return a.to_f * 2.0.log + b.to_f * 3.0.log + c.to_f * 5.0.log
+       end
+
+       redef fun ==(o)
+       do
+               return o isa HammingTriple and a == o.a and b == o.b and c == o.c
+       end
+
+       fun calcul: Int
+       do
+               return (2 ** a) * (3 ** b) * (5 ** c)
+       end
+
+       redef fun to_s: String
+       do
+               return "a: {a}, b: {b}, c: {c}"
+       end
+end
+
+class HammingArray
+       super Array[HammingTriple]
+
+       fun get_min: HammingTriple
+       do
+               var min = self[0]
+               var min_index = 0
+               for i in [1..length[ do
+                       if min > self[i] then
+                               min = self[i]
+                               min_index = i
+                       end
+               end
+               remove_at(min_index)
+               return min
+       end
+end
+
+fun hamming(limit_position: Int): Int
+do
+       var hamming_triple = new HammingArray
+       hamming_triple.add(new HammingTriple(0, 0, 0))
+       loop
+               var current = hamming_triple.get_min
+               limit_position -= 1
+               if limit_position == 0 then
+                       return current.calcul
+               end
+
+               if current.a == 0 and current.b == 0 then
+                       hamming_triple.add(new HammingTriple(current.a, current.b, current.c + 1))
+               end
+
+               if current.a == 0 then
+                       hamming_triple.add(new HammingTriple(current.a, current.b + 1, current.c))
+               end
+
+               hamming_triple.add(new HammingTriple(current.a + 1, current.b, current.c))
+       end
+end
+
+for i in [1..20] do
+       print "{i}: {hamming(i)}"
+end
+
+print "1691: {hamming(1691)}"
diff --git a/examples/rosettacode/hello_world_text.nit b/examples/rosettacode/hello_world_text.nit
new file mode 100644 (file)
index 0000000..0248dd5
--- /dev/null
@@ -0,0 +1,8 @@
+#!/usr/bin/env nit
+#
+# This file is part of NIT ( http://www.nitlanguage.org ).
+# This program is public domain
+
+# Task: Hello World/Text
+# SEE: <http://rosettacode.org/wiki/Hello_world/Text>
+print "Goodbye, World!"
index 4108268..0c5ed80 100644 (file)
@@ -57,14 +57,14 @@ module a_star
 
 # General graph node
 class Node
+       # Type of the others nodes in the `graph`
        type N: Node
 
        # parent graph
        var graph: Graph[N, Link]
 
-       init(graph: Graph[N, Link])
+       init
        do
-               self.graph = graph
                graph.add_node(self)
        end
 
@@ -116,7 +116,7 @@ class Node
                loop
                        var frontier_node: nullable N = null
 
-                       var bucket_searched: Int = 0
+                       var bucket_searched = 0
 
                        # find next valid node in frontier/buckets
                        loop
@@ -186,29 +186,36 @@ end
 
 # Link between two nodes and associated to a graph
 class Link
+       # Type of the nodes in `graph`
        type N: Node
+
+       # Type of the other links in `graph`
        type L: Link
 
+       # The graph to which belongs `self`
        var graph: Graph[N, L]
 
+       # Origin of this link
        var from: N
+
+       # Endpoint of this link
        var to: N
 
-       init(graph: Graph[N, L], from, to: N)
+       init
        do
-               self.graph = graph
-               self.from = from
-               self.to = to
-
                graph.add_link(self)
        end
 end
 
 # General graph
 class Graph[N: Node, L: Link]
+       # Nodes in this graph
        var nodes: Set[N] = new HashSet[N]
+
+       # Links in this graph
        var links: Set[L] = new HashSet[L]
 
+       # Add a `node` to this graph
        fun add_node(node: N): N
        do
                nodes.add(node)
@@ -216,6 +223,7 @@ class Graph[N: Node, L: Link]
                return node
        end
 
+       # Add a `link` to this graph
        fun add_link(link: L): L
        do
                links.add(link)
@@ -225,20 +233,22 @@ class Graph[N: Node, L: Link]
                return link
        end
 
-       # used to check if nodes have been searched in one pathfinding
-       var pathfinding_current_evocation: Int = 0
+       # Used to check if nodes have been searched in one pathfinding
+       private var pathfinding_current_evocation: Int = 0
 end
 
-# Result from pathfinding, a walkable path
+# Result from path finding and a walkable path
 class Path[N]
 
+       # The total cost of this path
        var total_cost: Int
 
+       # The list of nodes composing this path
        var nodes = new List[N]
 
-       init (cost: Int) do total_cost = cost
+       private var at: Int = 0
 
-       var at: Int = 0
+       # Step on the path and get the next node to travel
        fun step: N
        do
                assert nodes.length >= at else print "a_star::Path::step failed, is at_end_of_path"
@@ -249,16 +259,22 @@ class Path[N]
                return s
        end
 
+       # Peek at the next step of the path
        fun peek_step: N do return nodes[at]
 
+       # Are we at the end of this path?
        fun at_end_of_path: Bool do return at >= nodes.length
 end
 
 # Context related to an evocation of pathfinding
 class PathContext
+       # Type of the nodes in `graph`
        type N: Node
+
+       # Type of the links in `graph`
        type L: Link
 
+       # Graph to which is associated `self`
        var graph: Graph[N, L]
 
        # Worst cost of all the link's costs
@@ -273,6 +289,7 @@ class PathContext
        # Heuristic
        fun heuristic_cost(a, b: N): Int is abstract
 
+       # The worst cost suggested by the heuristic
        fun worst_heuristic_cost: Int is abstract
 end
 
@@ -292,12 +309,13 @@ class ConstantPathContext
        redef fun worst_heuristic_cost do return 0
 end
 
+# A `PathContext` for graphs with `WeightedLink`
 class WeightedPathContext
        super PathContext
 
        redef type L: WeightedLink
 
-       init(graph: Graph[N, L])
+       init
        do
                super
 
@@ -309,7 +327,7 @@ class WeightedPathContext
                self.worst_cost = worst_cost
        end
 
-       redef var worst_cost: Int
+       redef var worst_cost: Int is noinit
 
        redef fun cost(l) do
                return l.weight
@@ -319,17 +337,12 @@ class WeightedPathContext
        redef fun worst_heuristic_cost do return 0
 end
 
+# A `Link` with a `weight`
 class WeightedLink
        super Link
 
+       # The `weight`, or cost, of this link
        var weight: Int
-
-       init(graph: Graph[N, L], from, to: N, weight: Int)
-       do
-               super
-
-               self.weight = weight
-       end
 end
 
 # Advanced path conditions with customizable accept states
index 0232b4c..550df10 100644 (file)
@@ -86,7 +86,7 @@ end
 # 2. Apply the method `run`, that will search and return a solution.
 # 3. Retrieve information from the solution.
 #
-# ~~~~
+# ~~~~nitish
 # var p: BacktrackProblem = new MyProblem
 # var solver = p.solve
 # var res = solver.run
index d25e129..0e86903 100644 (file)
@@ -14,7 +14,7 @@
 # The constraint is that two queens cannot be on the same row, column or diagonal.
 #
 # Eg. a solution to the 8-queens problem is
-# ~~~
+# ~~~raw
 # +--------+
 # |Q.......|
 # |....Q...|
index 21a349d..64904ee 100644 (file)
@@ -199,7 +199,7 @@ end
 # 2. Apply the method `run`, that will search and return a solution.
 # 3. Retrieve information from the solution.
 #
-# ~~~~
+# ~~~~nitish
 # var p: SearchProblem = new MyProblem
 # var res = p.astar.run
 # if res != null then print "Found plan with {res.depth} actions, that cost {res.cost}: {res.plan.join(", ")}"
index 9470dd8..82ae3d1 100644 (file)
@@ -46,7 +46,6 @@ in "Java" `{
 # This is a low-level class, use `AssetManager` instead
 extern class NativeAssetManager in "Java" `{ android.content.res.AssetManager `}
        super JavaObject
-       redef type SELF: NativeAssetManager
 
        fun close in "Java" `{ recv.close(); `}
 
@@ -172,7 +171,6 @@ end
 # This is a low-level class, use `ResourcesManager` instead
 extern class NativeResources in "Java" `{ android.content.res.Resources `}
        super JavaObject
-       redef type SELF: NativeResources
 
        fun get_assets:NativeAssetManager in "Java" `{ return recv.getAssets(); `}
        fun get_color(id: Int): Int in "Java" `{ return recv.getColor((int)id); `}
@@ -283,7 +281,6 @@ end
 # An android Bitmap, get an instance using the AssetManager or the ResourceManager
 extern class NativeBitmap in "Java" `{ android.graphics.Bitmap `}
        super JavaObject
-       redef type SELF: NativeBitmap
 
        # Create a NativeBitmap from a NativeInputStream retrieved with `open` function of the AssetManager
        # Called by the AssetManager
@@ -299,7 +296,6 @@ end
 # Android AssetFileDescriptor, can be retrieve by AssetManager and used to load a sound in a SoundPool
 extern class NativeAssetFileDescriptor in "Java" `{ android.content.res.AssetFileDescriptor `}
        super JavaObject
-       redef type SELF: NativeAssetFileDescriptor
 
        fun close in "Java" `{
                try {
index e640621..366c7d4 100644 (file)
@@ -38,7 +38,6 @@ in "Java" `{
 # AudioManager of the application, used to manage the audio mode
 extern class NativeAudioManager in "Java" `{ android.media.AudioManager `}
        super JavaObject
-       redef type SELF: NativeAudioManager
 
        fun mode: Int in "Java" `{ return recv.getMode(); `}
        fun mode=(i: Int) in "Java" `{ recv.setMode((int)i); `}
@@ -61,7 +60,6 @@ end
 # This is a low-level class, use `MediaPlater` instead
 extern class NativeMediaPlayer in "Java" `{ android.media.MediaPlayer `}
        super JavaObject
-       redef type SELF: NativeMediaPlayer
 
        new in "Java" `{ return new MediaPlayer(); `}
        fun start in "Java" `{ recv.start(); `}
@@ -108,7 +106,6 @@ end
 # This is a low-level class, use `SoundPool`instead
 extern class NativeSoundPool in "Java" `{ android.media.SoundPool `}
        super JavaObject
-       redef type SELF: NativeSoundPool
 
        new(max_streams, stream_type, src_quality: Int) in "Java" `{
                return new SoundPool((int)max_streams, (int)stream_type, (int)src_quality);
index 9528e05..5a083d2 100644 (file)
@@ -31,7 +31,6 @@ in "Java" `{
 
 extern class NativeBundle in "Java" `{ android.os.Bundle `}
        super JavaObject
-       redef type SELF: NativeBundle
 
        fun clone: JavaObject in "Java" `{ return recv.clone(); `}
        fun size: Int in "Java" `{ return recv.size(); `}
diff --git a/lib/android/examples/Makefile b/lib/android/examples/Makefile
new file mode 100644 (file)
index 0000000..5255657
--- /dev/null
@@ -0,0 +1,11 @@
+android:
+       mkdir -p bin/ res/
+       ../../../contrib/inkscape_tools/bin/svg_to_icons art/icon.svg --android --out res/
+       ../../../bin/nitg --dir bin/ src/ui_test.nit
+       adb install -r bin/ui_test.apk
+
+install: android
+       adb install -r bin/ui.apk
+
+clean:
+       rm -rf bin
diff --git a/lib/android/examples/art/icon.svg b/lib/android/examples/art/icon.svg
new file mode 100644 (file)
index 0000000..fb46e63
--- /dev/null
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="512"
+   height="512"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.5 r10040"
+   sodipodi:docname="icon.svg">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#000000"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.98994949"
+     inkscape:cx="309.32788"
+     inkscape:cy="302.66563"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1311"
+     inkscape:window-height="960"
+     inkscape:window-x="3037"
+     inkscape:window-y="440"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(0,-540.36218)">
+    <path
+       style="font-size:320.10992432px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:-55.78796005px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+       d="M 116.09375,542.95593 C 95.970238,546.76157 75.866352,550.69664 55.75,554.54968 37.271066,654.48453 18.600595,754.38392 0.1875,854.33093 c 4.5670667,-0.0224 11.88925,-3.92217 14.989244,-1.88564 2.348097,12.30965 6.527711,24.13426 7.951802,36.55472 4.55774,23.64215 8.603147,47.44405 14.058954,70.86217 20.446729,-3.97475 40.892439,-7.95532 61.34375,-11.90625 0.806348,-6.01877 0.340643,-13.9623 0.6875,-18.84375 5.52874,12.6291 21.06261,15.98721 33.375,12.9375 18.4814,-4.95238 37.89007,-7.63966 56.75,-11.59375 -0.61826,-2.8783 4.8827,-0.79167 7.02749,-1.68038 14.16686,-1.03878 27.37606,-6.02271 41.41001,-7.38212 46.67851,-52.63829 -1.21449,-16.83212 30.65625,78.40625 17.19389,35.71392 58.70592,54.88142 97.40613,52.07812 21.55059,0.3486 43.28622,-5.5501 61.25012,-17.3281 0,7.9479 0,15.8958 0,23.8437 12.8637,-12.8518 32.06959,-10.4444 48.6875,-10.5625 12.08275,-0.4504 26.74579,-3.3417 33.09375,-14.75 2.84788,-8.0897 -0.35571,-16.9124 0.875,-25.25 0,-68.40622 0,-136.81247 0,-205.21872 -12.80081,2.58433 -25.80422,3.15955 -39,2.65625 -4.49542,-0.0745 -2.70343,-6.71819 -9.375,-2.8125 -14.41967,4.34039 -29.68137,2.22535 -44.53125,3.3125 -1.97068,-10.5394 -3.89878,-21.08667 -5.875,-31.625 43.54527,5.39974 90.52353,-22.98463 100.5,-66.625 11.74182,-45.53602 0.57063,-96.29858 -28.34375,-133 -18.76502,-21.52312 -47.96855,-34.21533 -76.77629,-30.338 -17.82405,1.69881 -35.28672,8.34732 -49.69246,18.74425 -12.97547,-7.86574 -27.99494,0.14323 -41.46466,1.78058 -8.5847,1.6356 -17.16935,3.2715 -25.75409,4.90692 2.25786,4.53438 -2.9589,1.63366 -5.28125,1.90625 -24.37251,-2.08163 -49.75835,4.12727 -69.28125,18.9375 -12.98942,-8.01584 -28.14096,-0.0134 -41.65179,1.65749 -7.26996,1.39739 -14.54254,2.78105 -21.81696,4.15501 C 140.087,578.41196 128.739,560.57354 117.4375,542.70593 l -0.98313,0.18291 z"
+       id="path3034"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccc" />
+    <text
+       transform="matrix(1.0172511,-0.19643198,0.1830023,0.94770357,0,0)"
+       sodipodi:linespacing="125%"
+       id="text2999"
+       y="843.55823"
+       x="-121.33073"
+       style="font-size:338.93121338px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:-0.06177186px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       xml:space="preserve"><tspan
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;letter-spacing:-59.06808853px;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+         y="843.55823"
+         x="-121.33073"
+         id="tspan3001"
+         sodipodi:role="line">App</tspan></text>
+    <text
+       transform="matrix(1.0172511,-0.19643198,0.1830023,0.94770357,0,0)"
+       xml:space="preserve"
+       style="font-size:171.81326294px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="-132.6741"
+       y="958.20111"
+       id="text3003"
+       sodipodi:linespacing="125%"><tspan
+         style="letter-spacing:-22.57948303px"
+         sodipodi:role="line"
+         id="tspan3005"
+         x="-132.6741"
+         y="958.20111">nit</tspan></text>
+    <text
+       transform="scale(1.0360431,0.96521081)"
+       sodipodi:linespacing="125%"
+       id="text3007"
+       y="1056.8173"
+       x="253.55678"
+       style="font-size:265.30044556px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       xml:space="preserve"><tspan
+         y="1056.8173"
+         x="253.55678"
+         id="tspan3009"
+         sodipodi:role="line"
+         style="letter-spacing:-34.865448px">UI</tspan></text>
+  </g>
+</svg>
diff --git a/lib/android/examples/src/ui_test.nit b/lib/android/examples/src/ui_test.nit
new file mode 100644 (file)
index 0000000..f6c2a1b
--- /dev/null
@@ -0,0 +1,91 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Test for app.nit's UI services
+module ui_test is
+       app_name("app.nit UI test")
+       app_version(0, 1, git_revision)
+       java_package("org.nitlanguage.ui_test")
+       android_manifest_activity """android:theme="@android:style/Theme.Light""""
+end
+
+import android
+import android::ui
+import android::toast
+import android::notification
+
+redef class App
+
+       var but_notif: Button
+       var but_toast: Button
+
+       var notif: nullable Notification = null
+
+       var inited = false
+       redef fun init_window
+       do
+               super
+
+               if inited then return
+               inited = true
+
+               # Setup UI
+               var context = native_activity
+               var layout = new NativeLinearLayout(context)
+               layout.set_vertical
+
+               but_notif = new Button
+               but_notif.text = "Show Notification"
+               layout.add_view but_notif.native
+
+               but_toast = new Button
+               but_toast.text = "Show Toast"
+               layout.add_view but_toast.native
+
+               context.content_view = layout
+       end
+
+       fun act_notif
+       do
+               var notif = self.notif
+               if notif == null then
+                       notif = new Notification("From app.nit", "Some content...")
+                       notif.ticker = "Ticker text..."
+                       notif.show
+                       self.notif = notif
+               else
+                       notif.cancel
+                       self.notif = null
+               end
+       end
+
+       fun act_toast
+       do
+               toast("Sample toast from app.nit at {get_time}", false)
+       end
+
+       redef fun catch_event(event)
+       do
+               if event isa ClickEvent then
+                       var sender = event.sender
+                       if sender == but_notif then
+                               act_notif
+                       else if sender == but_toast then
+                               act_toast
+                       end
+               end
+       end
+end
index d07a817..005b475 100644 (file)
@@ -33,7 +33,6 @@ in "Java" `{
 
 extern class NativeIntent in "Java" `{ android.content.Intent `}
        super JavaObject
-       redef type SELF: NativeIntent
 
        fun add_category(category: JavaString) in "Java" `{ recv.addCategory(category); `}
        fun add_flags(flags: Int) in "Java" `{ recv.addFlags((int)flags); `}
@@ -647,8 +646,8 @@ class Intent
 
        # The general action to be performed
        #
-       # Example :
-       # ~~~
+       # ~~~nitish
+       # # TODO better example
        # intent.action = intent_action.view.to_s
        # ~~~
        fun action=(action: String)
@@ -668,8 +667,8 @@ class Intent
        # Add category to the intent
        # Only activities providing all of the requested categories will be used
        #
-       # Example :
-       # ~~~
+       # ~~~nitish
+       # # TODO better example
        # intent.add_category(intent_category.home.to_s)
        # ~~~
        # Returns `self` allowing fluent programming
@@ -721,8 +720,8 @@ class Intent
 
        # Add a flag to be used by the intent
        #
-       # Example :
-       # ~~~
+       # ~~~nitish
+       # # TODO better example
        # intent.add_flags(intent_flag.activity_new_task)
        # ~~~
        # Returns `self` allowing fluent programming
index 50368de..fc5a19f 100644 (file)
@@ -114,12 +114,22 @@ in "C body" `{
        }
 `}
 
+# An Android activity context
+extern class NativeContext in "Java" `{ android.content.Context `}
+       super JavaObject
+end
+
+# A wrapper of context
+extern class NativeContextWrapper in "Java" `{ android.content.ContextWrapper `}
+       super NativeContext
+end
+
 # Android SDK's `android.app.NativeActivity`.
 #
 # Can be used to get anything related to the `Context` of the activity in Java
 # and as anchor to execute Java UI code.
 extern class NativeActivity in "Java" `{ android.app.NativeActivity `}
-       super JavaObject
+       super NativeContextWrapper
 end
 
 redef class App
@@ -252,11 +262,11 @@ extern class NdkNativeActivity `{ ANativeActivity * `}
        # The `NativeActivity`, as in the Java object, associated to `self`
        fun java_native_activity: NativeActivity `{ return recv->clazz; `}
 
-       # Path to this application's internal data directory.
+       # Path to this application's internal data directory.
        fun internal_data_path: NativeString `{ return (char*)recv->internalDataPath; `}
     
        # Path to this application's external (removable/mountable) data directory.
-       fun external_data_path: NativeString `{ return (char*)recv->externalDataPath; `}
+       fun external_data_path: NativeString `{ return (char*)recv->externalDataPath; `}
     
        # The platform's SDK version code.
        fun sdk_version: Int `{ return recv->sdkVersion; `}
diff --git a/lib/android/notification/native_notification.nit b/lib/android/notification/native_notification.nit
new file mode 100644 (file)
index 0000000..988727f
--- /dev/null
@@ -0,0 +1,71 @@
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Native Java classes for notifications
+module native_notification is min_api_version 11
+
+import android::assets_and_resources
+
+in "Java" `{
+       import android.content.Context;
+       import android.app.NotificationManager;
+       import android.app.Notification;
+`}
+
+redef class NativeActivity
+       fun notification_manager: NativeNotificationManager in "Java" `{
+               return (NotificationManager)recv.getSystemService(Context.NOTIFICATION_SERVICE);
+       `}
+end
+
+extern class NativeNotificationManager in "Java" `{ android.app.NotificationManager `}
+
+       fun notify(tag: JavaString, id: Int, notif: NativeNotification) in "Java" `{
+               recv.notify(tag, (int)id, notif);
+       `}
+
+       fun cancel(tag: JavaString, id: Int) in "Java" `{ recv.cancel(tag, (int)id); `}
+
+       fun cancel_all in "Java" `{ recv.cancelAll(); `}
+end
+
+extern class NativeNotification in "Java" `{ android.app.Notification `}
+end
+
+extern class NativeNotificationBuilder in "Java" `{ android.app.Notification$Builder `}
+
+       new (context: NativeActivity) in "Java" `{ return new Notification.Builder(context); `}
+
+       fun create: NativeNotification in "Java" `{
+               // Deprecated since API 16, which introduces `build`,
+               // refinement and global compilation should prevent warnings.
+               return recv.getNotification();
+       `}
+
+       fun title=(value: JavaString) in "Java" `{ recv.setContentTitle(value); `}
+
+       fun text=(value: JavaString) in "Java" `{ recv.setContentText(value); `}
+
+       fun ticker=(value: JavaString) in "Java" `{ recv.setTicker(value); `}
+
+       fun small_icon=(value: Int) in "Java" `{ recv.setSmallIcon((int)value); `}
+
+       fun auto_cancel=(value: Bool) in "Java" `{ recv.setAutoCancel(value); `}
+
+       fun number=(value: Int) in "Java" `{ recv.setNumber((int)value); `}
+
+       fun ongoing=(value: Bool) in "Java" `{ recv.setOngoing(value); `}
+end
diff --git a/lib/android/notification/notification.nit b/lib/android/notification/notification.nit
new file mode 100644 (file)
index 0000000..a4d34d4
--- /dev/null
@@ -0,0 +1,132 @@
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Services to show notification in the Android status bar
+#
+# ~~~~nitish
+# # Create and show a notification
+# var notif = new Notification("My Title", "Some content")
+# notif.ticker = "Ticker text"
+# notif.show
+#
+# # Update the notification
+# notif.text = "New content!"
+# notif.ongoing = true # Make it un-dismissable
+# notif.show
+#
+# # Hide the notification
+# notif.cancel
+# ~~~~
+#
+# For more information, see:
+# http://developer.android.com/guide/topics/ui/notifiers/notifications.html
+module notification
+
+import standard
+private import native_notification
+
+# An Android notification, shown at the top of the screen
+class Notification
+       # Title of this notification
+       var title: nullable Text is writable
+
+       # Text content of this notification
+       var text: nullable Text is writable
+
+       # Text to show in the bar as the notification appears
+       var ticker: nullable Text = null is writable
+
+       # Name of a resource found in the `res/drawable-*` folders to use for the small icon
+       #
+       # By default, we use the app's icon, named "icon". A valid icon must be used
+       # to display notifications.
+       var small_icon: nullable Text = null is writable
+
+       # Number to display on the bottom right part of the notification
+       var number: nullable Int = null is writable
+
+       # Is this notification ongoing? Not user dismissable.
+       var ongoing: Bool = false is writable
+
+       private var id: nullable Int = null
+       private var tag = "app.nit notification"
+
+       # Show the notification
+       fun show
+       do
+               sys.jni_env.push_local_frame(8)
+
+               var context = app.native_activity
+               var builder = new NativeNotificationBuilder(context)
+
+               # If no custom icon is specified, use app's
+               var small_icon = self.small_icon
+               if small_icon == null then small_icon = "icon"
+               var small_icon_id = app.resource_manager.other_id(small_icon.to_s, "drawable")
+               builder.small_icon = small_icon_id
+
+               # Other options
+               if title != null then builder.title = title.to_java_string
+               if text != null then builder.text = text.to_java_string
+               if ticker != null then builder.ticker = ticker.to_java_string
+               builder.ongoing = ongoing
+
+               var notif = builder.create
+               var manager = context.notification_manager
+
+               var id = self.id
+               if id == null then id = sys.next_notification_id
+               manager.notify(tag.to_java_string, id, notif)
+
+               self.id = id
+
+               sys.jni_env.pop_local_frame
+       end
+
+       # Was this notification shown with `show`?
+       #
+       # This does not indicates whether is has been dismissed or not. Only that
+       # it was shown at least once.
+       private fun was_shown: Bool do return id != null
+
+       # Cancel this notification and hide it if it is currently displayed
+       fun cancel
+       do
+               var id = self.id
+               if id != null then
+                       sys.jni_env.push_local_frame(8)
+
+                       var manager = app.native_activity.notification_manager
+                       manager.cancel(tag.to_java_string, id)
+
+                       self.id = null
+
+                       sys.jni_env.pop_local_frame
+               end
+       end
+end
+
+redef class Sys
+       private var next_notification_id_cache = 0
+
+       # Returns a unique ID for new notifications
+       private fun next_notification_id: Int
+       do
+               var id = next_notification_id_cache
+               next_notification_id_cache = id + 1
+               return id
+       end
+end
index dab001d..fca03e0 100644 (file)
@@ -21,6 +21,8 @@ module platform is
        new_annotation max_api_version
        new_annotation target_api_version
        new_annotation android_manifest
+       new_annotation android_manifest_application
+       new_annotation android_manifest_activity
 end
 
 import java
index 4c28466..a38dd60 100644 (file)
@@ -18,7 +18,8 @@
 # The sensor support is implemented in android_app module, so the user can enable the type of sensor he wants to use.
 # There is an example of how you can use the android sensors in nit/examples/mnit_ballz :
 #
-# ~~~~
+# ~~~~nitish
+# #FIXME rewrite the example
 # var app = new MyApp
 # app.sensors_support_enabled = true
 # app.accelerometer.enabled = true
index 8635f86..94aac59 100644 (file)
@@ -33,7 +33,6 @@ in "Java" `{
 
 extern class NativeSharedPreferences in "Java" `{ android.content.SharedPreferences `}
        super JavaObject
-       redef type SELF: NativeSharedPreferences
        
        fun contains(key: JavaString): Bool in "Java" `{ return recv.contains(key); `}
        fun get_all: HashMap[JavaString, JavaObject] import HashMap[JavaString, JavaObject],
@@ -113,7 +112,6 @@ end
 
 extern class NativeSharedPreferencesEditor in "Java" `{ android.content.SharedPreferences$Editor `}
        super JavaObject
-       redef type SELF: NativeSharedPreferencesEditor
 
        fun clear: NativeSharedPreferencesEditor in "Java" `{ return recv.clear(); `}
        fun commit: Bool in "Java" `{ return recv.commit(); `}
@@ -207,15 +205,14 @@ class SharedPreferences
        #
        # User has to manage local stack deallocation himself
        #
-       # Example :
-       # ~~~
+       # ~~~nitish
        # var foo = new HashMap[JavaString, JavaObject]
        # # ...
        # for key, value in foo do
        #      key.delete_local_ref
        #      value.delete_local_ref
        # end
-       # ~~~
+       # ~~~
        # *You should use Nit getters instead and get each value one by one* 
        fun all: nullable HashMap[JavaString, JavaObject]
        do 
index 50d88e9..cb55acc 100644 (file)
@@ -73,10 +73,9 @@ redef class SharedPreferences
        #
        # User has to manage local stack deallocation himself
        #
-       # Example :
-       # ~~~
-       # var a_hash_set = shared_preferences.string_set("A key")
-       # ...
+       # ~~~nitish
+       # var a_hash_set = app.shared_preferences.string_set("A key")
+       # # ...
        # for element in a_hash_set do element.delete_local_ref
        # ~~~
        fun string_set(key: String): HashSet[JavaString] 
@@ -92,10 +91,9 @@ redef class SharedPreferences
        #
        # User has to manage local stack deallocation himself
        #
-       # Example :
-       # ~~~
+       # ~~~nitish
        # var foo = new HashSet[JavaString]
-       # shared_preferences.add_string_set("A key", foo)
+       # app.shared_preferences.add_string_set("A key", foo)
        # for element in foo do element.delete_local_ref
        # ~~~
        fun add_string_set(key: String, value: HashSet[JavaString]): SharedPreferences
diff --git a/lib/android/toast.nit b/lib/android/toast.nit
new file mode 100644 (file)
index 0000000..dd8e149
--- /dev/null
@@ -0,0 +1,49 @@
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Services to display a _toast_, a small popup on Android
+module toast
+
+import native_app_glue
+
+in "Java" `{
+       import android.widget.Toast;
+`}
+
+redef class App
+       # Display a _toast_ with `message`, for longer if `is_long`
+       fun toast(message: String, is_long: Bool)
+       do
+               var jstr = message.to_java_string
+               native_toast(jstr, is_long)
+               jstr.delete_local_ref
+       end
+
+       private fun native_toast(message: JavaString, is_long: Bool)
+       import native_activity in "Java" `{
+               final android.app.NativeActivity context = App_native_activity(recv);
+               final CharSequence final_message = message;
+               final int duration = is_long? Toast.LENGTH_LONG: Toast.LENGTH_SHORT;
+
+               context.runOnUiThread(new Runnable() {
+                       @Override
+                       public void run()  {
+                               Toast toast = Toast.makeText(context, final_message, duration);
+                               toast.show();
+                       }
+               });
+       `}
+end
diff --git a/lib/android/ui.nit b/lib/android/ui.nit
new file mode 100644 (file)
index 0000000..98ee444
--- /dev/null
@@ -0,0 +1,417 @@
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Views and services to use the Android native user interface
+#
+# Events, such as a button click, come from the UI thread and are then
+# passed to the main thread. It is recommended to specialize one of the
+# methods of the main thread to customize the response to a given event.
+#
+# This graph shows the path of a button click:
+# ~~~raw
+#     UI Thread     #   Main thread
+#
+#       User
+#        |
+#        V
+# Button::click_ui --> Button::click
+#                           |
+#                           V
+#                    App::catch_event
+# ~~~
+module ui is min_api_version 14
+
+import native_app_glue
+import pthreads::concurrent_collections
+
+in "Java" `{
+       import android.app.NativeActivity;
+
+       import android.view.Gravity;
+       import android.view.MotionEvent;
+       import android.view.ViewGroup;
+       import android.view.ViewGroup.MarginLayoutParams;
+
+       import android.widget.Button;
+       import android.widget.LinearLayout;
+       import android.widget.GridLayout;
+       import android.widget.PopupWindow;
+       import android.widget.TextView;
+
+       import java.lang.*;
+       import java.util.*;
+`}
+
+# An event from the `app.nit` framework
+interface AppEvent
+       # Reaction to this event
+       fun react do end
+end
+
+# A control click event
+class ClickEvent
+       super AppEvent
+
+       # Sender of this event
+       var sender: Button
+
+       redef fun react do sender.click self
+end
+
+# Receiver of events not handled directly by the sender
+interface EventCatcher
+       fun catch_event(event: AppEvent) do end
+end
+
+redef class App
+       super EventCatcher
+
+       # Queue of events to be received by the main thread
+       var event_queue = new ConcurrentList[AppEvent]
+
+       # Call `react` on all `AppEvent` available in `event_queue`
+       protected fun loop_on_ui_callbacks
+       do
+               var queue = event_queue
+               while not queue.is_empty do
+                       var event = queue.pop
+                       event.react
+               end
+       end
+
+       redef fun run
+       do
+               loop
+                       # Process Android events
+                       poll_looper 100
+
+                       # Process app.nit events
+                       loop_on_ui_callbacks
+               end
+       end
+end
+
+redef extern class NativeActivity
+
+       # Fill this entire `NativeActivity` with `popup`
+       #
+       # This is a workaround for the use on `takeSurface` in `NativeActivity.java`
+       #
+       # TODO replace NativeActivity by our own NitActivity
+       private fun dedicate_to_popup(popup: NativePopupWindow, popup_layout: NativeViewGroup) in "Java" `{
+               final LinearLayout final_main_layout = new LinearLayout(recv);
+               final ViewGroup final_popup_layout = popup_layout;
+               final PopupWindow final_popup = popup;
+               final NativeActivity final_recv = recv;
+
+               recv.runOnUiThread(new Runnable() {
+                       @Override
+                       public void run()  {
+                               MarginLayoutParams params = new MarginLayoutParams(
+                                       LinearLayout.LayoutParams.MATCH_PARENT,
+                                       LinearLayout.LayoutParams.MATCH_PARENT);
+
+                               final_recv.setContentView(final_main_layout, params);
+
+                               final_popup.showAtLocation(final_popup_layout, Gravity.TOP, 0, 40);
+                       }
+               });
+       `}
+
+       # Set the main layout of this activity
+       fun content_view=(layout: NativeViewGroup)
+       do
+               var popup = new NativePopupWindow(self)
+               popup.content_view = layout
+               dedicate_to_popup(popup, layout)
+       end
+
+       # Set the real content view of this activity, without hack
+       #
+       # TODO bring use this instead of the hack with `dedicate_to_pupup`
+       private fun real_content_view=(layout: NativeViewGroup) in "Java" `{
+               final ViewGroup final_layout = layout;
+               final NativeActivity final_recv = recv;
+
+               recv.runOnUiThread(new Runnable() {
+                       @Override
+                       public void run()  {
+                               final_recv.setContentView(final_layout);
+
+                               final_layout.requestFocus();
+                       }
+               });
+       `}
+end
+
+# An `Object` that raises events
+abstract class Eventful
+       var event_catcher: EventCatcher = app is lazy, writable
+end
+
+#
+## Nity classes and services
+#
+
+# An Android control with text
+abstract class TextView
+       super Finalizable
+       super Eventful
+
+       # Native Java variant to this Nity class
+       type NATIVE: NativeTextView
+
+       # The native Java object encapsulated by `self`
+       var native: NATIVE is noinit
+
+       # Get the text of this view
+       fun text: String
+       do
+               var jstr = native.text
+               var str = jstr.to_s
+               jstr.delete_local_ref
+               return str
+       end
+
+       # Set the text of this view
+       fun text=(value: Text)
+       do
+               var jstr = value.to_s.to_java_string
+               native.text = jstr
+               jstr.delete_local_ref
+       end
+
+       # Get whether this view is enabled or not
+       fun enabled: Bool do return native.enabled
+
+       # Set if this view is enabled
+       fun enabled=(val: Bool) do native.enabled = val
+
+       # Set the size of the text in this view at `dpi`
+       fun text_size=(dpi: Numeric) do native.text_size = dpi.to_f
+
+       private var finalized = false
+       redef fun finalize
+       do
+               if not finalized then
+                       native.delete_global_ref
+                       finalized = true
+               end
+       end
+end
+
+# An Android button
+class Button
+       super TextView
+
+       redef type NATIVE: NativeButton
+
+       init
+       do
+               var native = new NativeButton(app.native_activity, app.event_queue, self)
+               self.native = native.new_global_ref
+       end
+
+       # Click event on the Main thread
+       #
+       # By default, this method calls `app.catch_event`. It can be specialized
+       # with custom behavior or the receiver of `catch_event` can be changed
+       # with `event_catcher=`.
+       fun click(event: AppEvent) do event_catcher.catch_event(event)
+
+       # Click event on the UI thread
+       #
+       # This method is called on the UI thread and redirects the event to `click`
+       # throught `App::event_queue`. In most cases, you should implement `click`
+       # and leave `click_ui` as is.
+       fun click_ui do app.event_queue.add(new ClickEvent(self))
+end
+
+# An Android editable text field
+class EditText
+       super TextView
+
+       redef type NATIVE: NativeEditText
+
+       init
+       do
+               var native = new NativeEditText(app.native_activity)
+               self.native = native.new_global_ref
+       end
+end
+
+#
+## Native classes
+#
+
+# A `View` for Android
+extern class NativeView in "Java" `{ android.view.View `}
+       super JavaObject
+
+       fun minimum_width=(val: Int) in "Java" `{ recv.setMinimumWidth((int)val); `}
+       fun minimum_height=(val: Int) in "Java" `{ recv.setMinimumHeight((int)val); `}
+end
+
+# A collection of `NativeView`
+extern class NativeViewGroup in "Java" `{ android.view.ViewGroup `}
+       super NativeView
+
+       fun add_view(view: NativeView) in "Java" `{ recv.addView(view); `}
+end
+
+# A `NativeViewGroup` organized in a line
+extern class NativeLinearLayout in "Java" `{ android.widget.LinearLayout `}
+       super NativeViewGroup
+
+       new(context: NativeActivity) in "Java" `{ return new LinearLayout(context); `}
+
+       fun set_vertical in "Java" `{ recv.setOrientation(LinearLayout.VERTICAL); `}
+       fun set_horizontal in "Java" `{ recv.setOrientation(LinearLayout.HORIZONTAL); `}
+
+       redef fun add_view(view) in "Java"
+       `{
+               MarginLayoutParams params = new MarginLayoutParams(
+                       LinearLayout.LayoutParams.MATCH_PARENT,
+                       LinearLayout.LayoutParams.WRAP_CONTENT);
+               recv.addView(view, params);
+       `}
+
+       fun add_view_with_weight(view: NativeView, weight: Float)
+       in "Java" `{
+               recv.addView(view, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT, (float)weight));
+       `}
+end
+
+# A `NativeViewGroup` organized as a grid
+extern class NativeGridLayout in "Java" `{ android.widget.GridLayout `}
+       super NativeViewGroup
+
+       new(context: NativeActivity) in "Java" `{ return new android.widget.GridLayout(context); `}
+
+       fun row_count=(val: Int) in "Java" `{ recv.setRowCount((int)val); `}
+
+       fun column_count=(val: Int) in "Java" `{ recv.setColumnCount((int)val); `}
+
+       redef fun add_view(view) in "Java" `{ recv.addView(view); `}
+end
+
+extern class NativePopupWindow in "Java" `{ android.widget.PopupWindow `}
+       super NativeView
+
+       new (context: NativeActivity) in "Java" `{
+               PopupWindow recv = new PopupWindow(context);
+               recv.setWindowLayoutMode(LinearLayout.LayoutParams.MATCH_PARENT,
+                       LinearLayout.LayoutParams.MATCH_PARENT);
+               recv.setClippingEnabled(false);
+               return recv;
+       `}
+
+       fun content_view=(layout: NativeViewGroup) in "Java" `{ recv.setContentView(layout); `}
+end
+
+extern class NativeTextView in "Java" `{ android.widget.TextView `}
+       super NativeView
+
+       new (context: NativeActivity) in "Java" `{ return new TextView(context); `}
+
+       fun text: JavaString in "Java" `{ return recv.getText().toString(); `}
+
+       fun text=(value: JavaString) in "Java" `{
+
+               android.util.Log.d("Nity", "1");
+               final TextView final_recv = recv;
+               final String final_value = value;
+
+               android.util.Log.d("Nity", "4");
+               ((NativeActivity)recv.getContext()).runOnUiThread(new Runnable() {
+                       @Override
+                       public void run()  {
+                               android.util.Log.d("Nity", "-5");
+                               android.util.Log.d("Nity", final_value);
+                               android.util.Log.d("Nity", "-5.5");
+                               final_recv.setText(final_value);
+                               android.util.Log.d("Nity", "-6");
+                       }
+               });
+               android.util.Log.d("Nity", "7");
+       `}
+
+       fun enabled: Bool in "Java" `{ return recv.isEnabled(); `}
+       fun enabled=(value: Bool) in "Java" `{
+               final TextView final_recv = recv;
+               final boolean final_value = value;
+
+               ((NativeActivity)recv.getContext()).runOnUiThread(new Runnable() {
+                       @Override
+                       public void run()  {
+                               final_recv.setEnabled(final_value);
+                       }
+               });
+       `}
+
+       fun gravity_center in "Java" `{
+               recv.setGravity(Gravity.CENTER);
+       `}
+
+       fun text_size=(dpi: Float) in "Java" `{
+               recv.setTextSize(android.util.TypedValue.COMPLEX_UNIT_DIP, (float)dpi);
+       `}
+end
+
+extern class NativeEditText in "Java" `{ android.widget.EditText `}
+       super NativeTextView
+
+       redef type SELF: NativeEditText
+
+       new (context: NativeActivity) in "Java" `{ return new android.widget.EditText(context); `}
+
+       fun width=(val: Int) in "Java" `{ recv.setWidth((int)val); `}
+
+       fun input_type_text in "Java" `{ recv.setInputType(android.text.InputType.TYPE_CLASS_TEXT); `}
+
+       redef fun new_global_ref: SELF import sys, Sys.jni_env `{
+               Sys sys = NativeEditText_sys(recv);
+               JNIEnv *env = Sys_jni_env(sys);
+               return (*env)->NewGlobalRef(env, recv);
+       `}
+end
+
+extern class NativeButton in "Java" `{ android.widget.Button `}
+       super NativeTextView
+
+       redef type SELF: NativeButton
+
+       new (context: NativeActivity, queue: ConcurrentList[AppEvent], sender_object: Object) import Button.click_ui in "Java" `{
+               final int final_sender_object = sender_object;
+
+               return new Button(context){
+                       @Override
+                       public boolean onTouchEvent(MotionEvent event) {
+                               if(event.getAction() == MotionEvent.ACTION_DOWN) {
+                                       Button_click_ui(final_sender_object);
+                                       return true;
+                               }
+                               return false;
+                       }
+               };
+       `}
+
+       redef fun new_global_ref: SELF import sys, Sys.jni_env `{
+               Sys sys = NativeButton_sys(recv);
+               JNIEnv *env = Sys_jni_env(sys);
+               return (*env)->NewGlobalRef(env, recv);
+       `}
+end
index 6226285..f56dbef 100644 (file)
@@ -26,7 +26,6 @@ import native_app_glue
 # Handle to an Android vibrator
 extern class Vibrator in "Java" `{ android.os.Vibrator `}
        super JavaObject
-       redef type SELF: Vibrator
 
        # Vibrate for `n` miliseconds
        fun vibrate(n: Int) in "Java" `{ recv.vibrate(n); `}
index afb6a1d..13891fc 100644 (file)
@@ -34,5 +34,5 @@ interface DataStore
        fun [](key: String): nullable Object is abstract
 
        # Store `value` at `key`
-       fun []=(key: String, value: Serializable) is abstract
+       fun []=(key: String, value: nullable Serializable) is abstract
 end
index 2d941e9..7b78d78 100644 (file)
@@ -36,6 +36,10 @@ redef class String
        # Encodes the receiver string to base64.
        # By default, uses "=" for padding.
        fun encode_base64 : String do return encode_base64_custom_padding( '=' )
+
+       # Encodes the receiver string to base64 using a custom padding character.
+       #
+       # If using the default padding character `=`, see `encode_base64`.
        fun encode_base64_custom_padding( padding : Char ) : String
        do
                var base64_chars = once base64_chars
@@ -78,6 +82,10 @@ redef class String
        # Decodes the receiver string from base64.
        # By default, uses "=" for padding.
        fun decode_base64 : String do return decode_base64_custom_padding( '=' )
+
+       # Decodes the receiver string to base64 using a custom padding character.
+       #
+       # If using the default padding character `=`, see `decode_base64`.
        fun decode_base64_custom_padding( padding : Char ) : String
        do
                var inverted_base64_chars = once inverted_base64_chars
index 09a4ee8..703ff5c 100644 (file)
@@ -24,6 +24,8 @@ module bucketed_game
 
 # Something acting on the game
 class Turnable[G: Game]
+
+       # Execute `turn` for this instance.
        fun do_turn(turn: GameTurn[G]) is abstract
 end
 
@@ -39,9 +41,11 @@ class Bucketable[G: Game]
        fun cancel_act do act_at = null
 end
 
-# Optiomized organization of `Bucketable` instances
+# Optimized organization of `Bucketable` instances
 class Buckets[G: Game]
        super Turnable[G]
+
+       # Bucket type used in this implementation.
        type BUCKET: HashSet[Bucketable[G]]
 
        private var buckets: Array[BUCKET] is noinit
@@ -59,6 +63,7 @@ class Buckets[G: Game]
                end
        end
 
+       # Add the Bucketable event `e` at `at_tick`.
        fun add_at(e: Bucketable[G], at_tick: Int)
        do
                var at_key = key_for_tick(at_tick)
@@ -103,6 +108,8 @@ end
 
 # Game related event
 interface GameEvent
+
+       # Apply `self` to `game` logic.
        fun apply( game : ThinGame ) is abstract
 end
 
@@ -113,39 +120,43 @@ end
 
 # Game logic on the client
 class ThinGame
+
+       # Game tick when `self` should act.
+       #
+       # Default is 0.
        var tick: Int = 0 is protected writable
 end
 
 # Game turn on the client
 class ThinGameTurn[G: ThinGame]
-       var tick: Int = 0 is protected writable
 
-       var events: List[GameEvent] = new List[GameEvent] is protected writable
+       # Game tick when `self` should act.
+       var tick: Int is protected writable
 
-       init (t: Int) do tick = t
+       # List of game events occured for `self`.
+       var events = new List[GameEvent] is protected writable
 end
 
 # Game turn on the full logic
 class GameTurn[G: Game]
        super ThinGameTurn[G]
+
+       # Game that `self` belongs to.
        var game: G
 
-       init (g: G)
-       do
-               super(g.tick)
-               game = g
+       # Create a new game turn for `game`.
+       init (game: G) is old_style_init do
+               super(game.tick)
+               self.game = game
        end
 
-       fun act_next(e: Bucketable[G])
-       do
-               game.buckets.add_at(e, tick + 1)
-       end
+       # Insert the Bucketable event `e` to be executed at next tick.
+       fun act_next(e: Bucketable[G]) do game.buckets.add_at(e, tick + 1)
 
-       fun act_in(e: Bucketable[G], t: Int)
-       do
-               game.buckets.add_at(e, tick + t)
-       end
+       # Insert the Bucketable event `e` to be executed at tick `t`.
+       fun act_in(e: Bucketable[G], t: Int) do game.buckets.add_at(e, tick + t)
 
+       # Add and `apply` a game `event`.
        fun add_event( event : GameEvent )
        do
                event.apply( game )
@@ -156,8 +167,11 @@ end
 # Full game logic
 class Game
        super ThinGame
+
+       # Game type used in this implementation.
        type G: Game
 
+       # Bucket list in this game.
        var buckets: Buckets[G] = new Buckets[G]
 
        # Last turn executed in this game
@@ -167,6 +181,10 @@ class Game
 
        init do end
 
+       # Execute and return a new GameTurn.
+       #
+       # This method calls `do_pre_turn` before executing the GameTurn
+       # and `do_post_turn` after.
        fun do_turn: GameTurn[G]
        do
                var turn = new GameTurn[G](self)
@@ -182,6 +200,15 @@ class Game
                return turn
        end
 
+       # Execute something before executing the current GameTurn.
+       #
+       # Should be redefined by clients to add a pre-turn behavior.
+       # See `Game::do_turn`.
        fun do_pre_turn(turn: GameTurn[G]) do end
+
+       # Execute something after executing the current GameTurn.
+       #
+       # Should be redefined by clients to add a post-turn behavior.
+       # See `Game::do_turn`.
        fun do_post_turn(turn: GameTurn[G]) do end
 end
index b287871..bbed4ea 100644 (file)
@@ -68,10 +68,13 @@ end
 private class LeafSubstrings
        super IndexedIterator[Text]
 
-       var str: String
+       var leaf: Leaf
+       var str: String is noinit
        var avail = true
 
-       init(l: Leaf) do str = new FlatString.with_infos(l.buf.ns, l.length, 0, l.length - 1)
+       init do
+               str = new FlatString.with_infos(leaf.buf.ns, leaf.length, 0, leaf.length - 1)
+       end
 
        redef fun is_ok do return avail
 
@@ -86,8 +89,8 @@ end
 private class Leaf
        super RopeString
 
-       private var buf: ManualBuffer
-       private var bns: NativeString is noinit
+       var buf: ManualBuffer
+       var bns: NativeString is noinit
        redef var length: Int is noinit
 
        redef fun empty do return new Leaf(new ManualBuffer)
@@ -240,7 +243,6 @@ redef class Concat
 
        redef fun +(o) do
                var s = o.to_s
-               var mlen = length
                var slen = s.length
                if s isa FlatString then
                        var r = right
@@ -286,7 +288,6 @@ redef class FlatString
                        return new Concat(sl + self, s.right)
                else if s isa Leaf then
                        if slen + mlen > maxlen then return new Concat(self, s)
-                       var mits = items
                        var mifrom = index_from
                        var sb = s.buf
                        var b = new ManualBuffer
index fdc7e99..d94ae8e 100644 (file)
--- a/lib/c.nit
+++ b/lib/c.nit
@@ -23,15 +23,56 @@ intrude import standard::collection::array
 abstract class CArray[E]
        super AbstractArrayRead[E]
 
-       private init(length: Int) do self._length = length
+       # The corresponding C type
+       type NATIVE: NativeCArray
+
+       # Pointer to the real C array
+       var native_array: NATIVE is noinit
+
+       private init(length: Int) is old_style_init do self._length = length
+
+       redef fun [](index)
+       do
+               assert not destroyed
+               assert index >= 0 and index < length
+               return native_array[index]
+       end
+
+       # Set `val` at `index`.
+       fun []=(index: Int, val: E)
+       do
+               assert not destroyed
+               assert index >= 0 and index < length
+               native_array[index] = val
+       end
+
+       # Was this instance destroyed?
+       #
+       # See `CArray::destroy`.
+       var destroyed = false
+
+       # Free used memory used by `native_array`.
+       #
+       # Also set `destroyed` to true.
+       fun destroy
+       do
+               if destroyed then return
+
+               native_array.free
+               destroyed = true
+       end
 end
 
 # A native C array, as in a pointer to the first element of the array
 extern class NativeCArray `{ void * `}
+
+       # Type of contained elements.
        type E: nullable Object
-       type SELF: NativeCArray
 
+       # Get element at `index`.
        fun [](index: E): E is abstract
+
+       # Set `val` at `index`.
        fun []=(index: E, val: E) is abstract
 
        # Return pointer to the address to the second element of this array
@@ -43,45 +84,69 @@ end
 # Wrapper around an array of `int` in C (`int*`) with length and destroy state
 class CIntArray
        super CArray[Int]
+       redef type NATIVE: NativeCIntArray
 
-       var native_array: NativeCIntArray
-       init(size: Int)
-       do
+       # Initialize a new CIntArray of `size` elements.
+       init(size: Int) is old_style_init do
                native_array = new NativeCIntArray(size)
                super size
        end
 
-       redef fun [](index)
+       # Build from an `Array[Int]`
+       new from(array: Array[Int])
        do
-               assert not destroyed
-               assert index >= 0 and index < length
-               return native_array[index]
+               var carray = new CIntArray(array.length)
+               for i in array.length.times do
+                       carray[i] = array[i]
+               end
+               return carray
        end
+end
 
-       fun []=(index: Int, val: Int)
-       do
-               assert not destroyed
-               assert index >= 0 and index < length
-               native_array[index] = val
+# An array of `int` in C (`int*`)
+extern class NativeCIntArray `{ int* `}
+       super NativeCArray
+       redef type E: Int
+
+       # Initialize a new NativeCIntArray of `size` elements.
+       new(size: Int) `{ return calloc(size, sizeof(int)); `}
+
+       redef fun [](index) `{ return recv[index]; `}
+       redef fun []=(index, val) `{ recv[index] = val; `}
+
+       redef fun +(offset) `{ return recv + offset; `}
+end
+
+# Wrapper around an array of `unsigned char` in C (`unsigned char*`) with length and destroy state
+class CByteArray
+       super CArray[Int]
+       redef type NATIVE: NativeCByteArray
+
+       # Allocate a new array of `size`
+       init(size: Int) is old_style_init do
+               native_array = new NativeCByteArray(size)
+               super size
        end
 
-       var destroyed = false
-       fun destroy
+       # Build from an `Array[Int]`
+       new from(array: Array[Int])
        do
-               if destroyed then return
-
-               native_array.free
-               destroyed = true
+               var carray = new CByteArray(array.length)
+               for i in array.length.times do
+                       carray[i] = array[i]
+               end
+               return carray
        end
 end
 
-# An array of `int` in C (`int*`)
-extern class NativeCIntArray `{ int* `}
+# An array of `unsigned char` in C (`unsigned char*`)
+extern class NativeCByteArray `{ unsigned char* `}
        super NativeCArray
        redef type E: Int
-       redef type SELF: NativeCIntArray
 
-       new(size: Int) `{ return calloc(size, sizeof(int)); `}
+       # Allocate a new array of `size`
+       new(size: Int) `{ return calloc(size, sizeof(unsigned char)); `}
+
        redef fun [](index) `{ return recv[index]; `}
        redef fun []=(index, val) `{ recv[index] = val; `}
 
@@ -91,7 +156,6 @@ end
 redef class NativeString
        super NativeCArray
        redef type E: Char
-       redef type SELF: NativeString
 
        redef fun +(offset) `{ return recv + offset; `}
 end
diff --git a/lib/cocoa/app_kit.nit b/lib/cocoa/app_kit.nit
new file mode 100644 (file)
index 0000000..91bc87c
--- /dev/null
@@ -0,0 +1,38 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# The Application Kit provides services to create GUI
+module app_kit is c_linker_option "-framework AppKit"
+
+import foundation
+
+in "ObjC Header" `{
+       #import <AppKit/AppKit.h>
+`}
+
+# A simple message box
+extern class NSAlert in "ObjC" `{ NSAlert * `}
+       super NSObject
+
+       # Allocate and instanciate a new `NSAlert`
+       new in "ObjC" `{ return [[NSAlert alloc] init]; `}
+
+       # Set the content of this message box
+       fun message_text=(text: NSString) in "ObjC" `{ [recv setMessageText:text]; `}
+
+       # Show this message box
+       fun run_modal in "ObjC" `{ [recv runModal]; `}
+end
diff --git a/lib/cocoa/cocoa.nit b/lib/cocoa/cocoa.nit
new file mode 100644 (file)
index 0000000..99c6b12
--- /dev/null
@@ -0,0 +1,26 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# The Cocoa API is the development layer of OS X
+#
+# This module is only compatible with OS X.
+#
+# This wrapper of the Cocoa API regroups the Foundation Kit and the
+# Application Kit.
+module cocoa is c_linker_option "-framework Cocoa"
+
+import foundation
+import app_kit
diff --git a/lib/cocoa/examples/cocoa_extern_types.nit b/lib/cocoa/examples/cocoa_extern_types.nit
new file mode 100644 (file)
index 0000000..775e6e4
--- /dev/null
@@ -0,0 +1,43 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Test extern classes from the Cocoa framework and extern factories
+module cocoa_extern_types
+
+import cocoa
+
+in "ObjC Header" `{
+       // for `NSString::hello`
+       #import <Foundation/Foundation.h>
+`}
+
+redef extern class NSString
+
+       # Additionnal factory
+       new hello in "ObjC" `{ return @"Factory Hello"; `}
+end
+
+# Print a custom string to the log
+fun nslog(text: NSString) in "ObjC" `{
+       NSLog(text);
+`}
+
+nslog "Hello using to_nsstring".to_nsstring
+nslog new NSString.hello
+
+var msg_box = new NSAlert
+msg_box.message_text = "From Nit".to_nsstring
+if "NIT_TESTING".environ != "true" then msg_box.run_modal
diff --git a/lib/cocoa/examples/cocoa_message_box.nit b/lib/cocoa/examples/cocoa_message_box.nit
new file mode 100644 (file)
index 0000000..72e35d7
--- /dev/null
@@ -0,0 +1,32 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Simple message box using the Cocoa framework
+module cocoa_message_box
+
+import cocoa
+
+in "ObjC" `{
+       #import <Cocoa/Cocoa.h>
+`}
+
+fun dialog in "ObjC" `{
+       NSAlert *alert = [[[NSAlert alloc] init] autorelease];
+       [alert setMessageText:@"Hello world!"];
+       [alert runModal];
+`}
+
+if "NIT_TESTING".environ != "true" then dialog
diff --git a/lib/cocoa/examples/hello_cocoa.nit b/lib/cocoa/examples/hello_cocoa.nit
new file mode 100644 (file)
index 0000000..3a2b168
--- /dev/null
@@ -0,0 +1,33 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Hello world using the Cocoa framework
+module hello_cocoa
+
+import cocoa::foundation
+
+in "ObjC" `{
+       #import <Foundation/Foundation.h>
+`}
+
+# Print `"Hello world!"` to the log
+fun hello_world in "ObjC" `{
+       @autoreleasepool {
+               NSLog(@"Hello World!");
+       }
+`}
+
+hello_world
diff --git a/lib/cocoa/foundation.nit b/lib/cocoa/foundation.nit
new file mode 100644 (file)
index 0000000..ab027fd
--- /dev/null
@@ -0,0 +1,47 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# The Foundation Kit provides basic Objective-C classes and structures
+module foundation is c_linker_option "-framework Foundation"
+
+in "ObjC Header" `{
+       #import <Foundation/Foundation.h>
+`}
+
+# Base of the Foundation framework class hierarchy
+extern class NSObject in "ObjC" `{ NSObject * `}
+end
+
+# String of the Foundation Kit
+#
+# Created using `Text::to_nsstring`.
+extern class NSString in "ObjC" `{ NSString * `}
+       super NSObject
+end
+
+redef class NativeString
+       # Get a `NSString` from `self` with the specified `length`
+       fun to_nsstring(length: Int): NSString in "ObjC" `{
+               return [[NSString alloc] initWithBytes:recv
+                       length:length
+                       encoding:NSASCIIStringEncoding];
+       `}
+end
+
+redef class Text
+       # Get a `NSString` from `self`
+       fun to_nsstring: NSString do return to_cstring.to_nsstring(length)
+end
index 4076c03..cb1612a 100644 (file)
@@ -120,7 +120,7 @@ private class CartesianIterator[E]
        var collection: CartesianCollection[E]
 
        # The array of iterations that will be increased in the lexicographic order.
-       private var iterators = new Array[Iterator[E]]
+       var iterators = new Array[Iterator[E]]
 
        init
        do
@@ -314,8 +314,8 @@ private class CombinationIterator[E]
        super Iterator[SequenceRead[E]]
        var product: CombinationCollection[E]
 
-       private var iterators = new Array[Iterator[E]]
-       private var indices = new Array[Int]
+       var iterators = new Array[Iterator[E]]
+       var indices = new Array[Int]
 
        var are_sorted: Bool is noinit
        var are_unique: Bool is noinit
@@ -374,7 +374,7 @@ private class CombinationIterator[E]
                end
        end
 
-       private fun next_free(rank: Int, start: Int): Int
+       fun next_free(rank: Int, start: Int): Int
        do
                loop
                        for i in [0..rank[ do
@@ -388,7 +388,7 @@ private class CombinationIterator[E]
                return start
        end
 
-       private fun reset_iterator(rank: Int): Iterator[E]
+       fun reset_iterator(rank: Int): Iterator[E]
        do
                var it = product.collection.iterator
                iterators[rank] = it
index e922a84..c0a8772 100644 (file)
@@ -44,8 +44,6 @@ end
 class TermMoveUp
        super TermDirectionalMove
 
-       init do end
-
        # Move by the specified number of cells.
        init by(magnitude: Int) do self.magnitude = magnitude
 
@@ -56,8 +54,6 @@ end
 class TermMoveDown
        super TermDirectionalMove
 
-       init do end
-
        # Move by the specified number of cells.
        init by(magnitude: Int) do self.magnitude = magnitude
 
@@ -68,8 +64,6 @@ end
 class TermMoveFoward
        super TermDirectionalMove
 
-       init do end
-
        # Move by the specified number of cells.
        init by(magnitude: Int) do self.magnitude = magnitude
 
@@ -80,8 +74,6 @@ end
 class TermMoveBackward
        super TermDirectionalMove
 
-       init do end
-
        # Move by the specified number of cells.
        init by(magnitude: Int) do self.magnitude = magnitude
 
@@ -102,8 +94,6 @@ class TermMove
        # 1 is the left.
        var column: Int = 1
 
-       init do end
-
        # Move at the specified position.
        #
        # (1, 1) is the top-left corner of the display.
index 3d4daf6..6fe897a 100644 (file)
@@ -23,12 +23,14 @@ end
 extern class CppString in "C++" `{ std::string* `}
 end
 
-redef class String
-       fun to_cpp_string: CppString do return to_cstring.to_cpp_string
+redef class Text
+       # Get `self` as a `CppString`
+       fun to_cpp_string: CppString do return to_cstring.to_cpp_string(length)
 end
 
 redef class NativeString
-       fun to_cpp_string: CppString in "C++" `{
-               return new std::string(recv);
+       # Get `self` as a `CppString`
+       fun to_cpp_string(length: Int): CppString in "C++" `{
+               return new std::string(recv, length);
        `}
 end
index a84358f..a4abbd1 100644 (file)
@@ -69,7 +69,6 @@ redef class String
                var rot = x % 26
                if rot < 0 then rot += 26
                var d = new FlatBuffer.with_capacity(length)
-               var p = 0
                for i in chars do
                        d.add i.rot(rot)
                end
diff --git a/lib/csv.nit b/lib/csv.nit
deleted file mode 100644 (file)
index 82fbb05..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-# 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.
-
-# CSV output facilities
-module csv
-
-# A CSV document representation
-class CSVDocument
-       super Streamable
-
-       var header: Array[String] = new Array[String] is writable
-       var lines: Array[Array[String]] = new Array[Array[String]]
-
-       fun set_header(values: Object...) do
-               header.clear
-               for value in values do
-                       header.add(value.to_s)
-               end
-       end
-
-       fun add_line(values: Object...) do
-               if values.length != header.length then
-                       print "CSV error: header declares {header.length} columns, line contains {values.length} values"
-                       abort
-               end
-               var line = new Array[String]
-               for value in values do
-                       line.add(value.to_s)
-               end
-               lines.add(line)
-       end
-
-       private fun write_line_to(line: Collection[String], stream: OStream)
-       do
-               var i = line.iterator
-               if i.is_ok then
-                       stream.write(i.item)
-                       i.next
-                       while i.is_ok do
-                               stream.write(";")
-                               stream.write(i.item)
-                               i.next
-                       end
-               end
-               stream.write("\n")
-       end
-
-       redef fun write_to(stream)
-       do
-               write_line_to(header, stream)
-               for line in lines do write_line_to(line, stream)
-       end
-
-       # deprecated alias for `write_to_file`
-       fun save(file: String) do write_to_file(file)
-end
diff --git a/lib/csv/csv.nit b/lib/csv/csv.nit
new file mode 100644 (file)
index 0000000..441f95c
--- /dev/null
@@ -0,0 +1,385 @@
+# 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.
+
+# CSV document handling.
+module csv
+
+# Specifies a CSV format.
+class CsvFormat
+       # The character that delimits escaped value.
+       #
+       # The delimiter is escaped by doubling it.
+       var delimiter: Char
+
+       # The character that split each cell in a row.
+       var separator: Char
+
+       # The character that ends a row (end of line).
+       var eol: String
+
+       # Escape sequence for the delimiter.
+       private var escaping = "{delimiter}{delimiter}" is lazy
+
+       # Escape the specified cell.
+       private fun escape_cell(cell: String): Text do
+               var result = new RopeBuffer
+               result.add delimiter
+               result.append cell.replace(delimiter, escaping)
+               result.add delimiter
+               return result
+       end
+
+       # Can the specified value be inserted without any escaping?
+       private fun is_value_clean(value: String): Bool do
+               for c in value.chars do
+                       if c == delimiter then return false
+                       if c == separator then return false
+                       if eol.chars.has(c) then return false
+               end
+               return true
+       end
+end
+
+# A CSV document representation.
+class CsvDocument
+       super Streamable
+
+       # The format to use.
+       #
+       # Defaults to `rfc4180`.
+       var format: CsvFormat = rfc4180 is writable
+
+       # The header.
+       #
+       # Contains the name of all fields in this table.
+       var header: Array[String] = new Array[String] is writable
+
+       # The list of the records.
+       #
+       # All records must have the same length than `header`.
+       var records: Array[Array[String]] = new Array[Array[String]]
+
+       # Replace the header by the specified row.
+       fun set_header(values: Object...) do
+               header.clear
+               for value in values do header.add(value.to_s)
+       end
+
+       # Append the specfied record.
+       fun add_record(values: Object...) do
+               assert values.length == header.length else
+                       sys.stderr.write "CSV error: Header declares {header.length} columns, record contains {values.length} values.\n"
+               end
+               var record = new Array[String]
+               for value in values do record.add(value.to_s)
+               records.add(record)
+       end
+
+       redef fun write_to(stream) do
+               var writer = new CsvWriter.with_format(stream, format)
+               writer.write_sequence(header)
+               for record in records do writer.write_sequence(record)
+       end
+
+       # Deprecated alias for `write_to_file`.
+       fun save(file: String) do write_to_file(file)
+
+       # Load from the specified stream.
+       #
+       # Parameters:
+       #
+       # * `stream`: Input stream.
+       # * `has_header`: Is the first row the header?
+       # * `skip_empty`: Do we skip the empty lines?
+       # For details, see `CsvReader.skip_empty`.
+       fun load_from(stream: IStream, has_header: Bool, skip_empty: Bool) do
+               var reader = new CsvReader.with_format(stream, format)
+               reader.skip_empty = skip_empty
+               if has_header then
+                       if reader.is_ok then
+                               header = reader.item
+                       else
+                               header.clear
+                       end
+               end
+               records.clear
+               for record in reader do records.add(record)
+       end
+
+       # Load from the specified file.
+       #
+       # Parameters:
+       #
+       # * `path`: Path of the file.
+       # * `has_header`: Is the first row the header?
+       # * `skip_empty`: Do we skip the empty lines?
+       fun load(path: String, has_header: Bool, skip_empty: Bool) do
+               var istream = new IFStream.open(path)
+               load_from(istream, has_header, skip_empty)
+               istream.close
+       end
+end
+
+# Appends CSV rows to a file.
+#
+# By default, uses the format recommended by RFC 4180 (see `rfc4180`).
+#
+# Note: If a row contains only an empty cell, its representation is
+# undistinguishable from an empty line. This is because the empty values are
+# always written unescaped in order to avoid them to be interpreted as escaped
+# delimiters by some parsers.
+#
+# ~~~nit
+# var out = new StringOStream
+# var writer = new CsvWriter(out)
+# writer.write_row(1, 2.0, "foo\nbar")
+# writer.write_sequence([""])
+# assert out.to_s == """1,2.0,"foo\nbar"\r\n\r\n"""
+# ~~~
+class CsvWriter
+
+       # The output stream.
+       var ostream: OStream
+
+       # The format to use.
+       #
+       # Defaults to `rfc4180`.
+       var format: CsvFormat = rfc4180
+
+       # Do we escape all cells (except empty ones)?
+       #
+       # If `false` (the default), escape only cells that contain a metacharacter
+       # of the format. In all cases, empty cells are not escaped. This option
+       # permits to choose between the optimization of the performances (when
+       # `true`) and optimization of the size of the output (when `false`).
+       #
+       # Note: Escaping may not be correctly recognized by some parsers.
+       var always_escape = false is writable
+
+       # Create a new writer with the specified format.
+       init with_format(ostream:OStream, format: CsvFormat) do
+               self.ostream = ostream
+               self.format = format
+       end
+
+       # Append the specified sequence as a row.
+       #
+       # The representation of each cell is determined by `to_s`.
+       fun write_sequence(row: SequenceRead[Object]) do
+               if not row.is_empty then
+                       var i = row.iterator
+                       var separator = format.separator.to_s
+                       write_cell i.item.to_s
+                       i.next
+                       for cell in i do
+                               ostream.write separator
+                               write_cell cell.to_s
+                       end
+               end
+               ostream.write format.eol
+       end
+
+       # Append the specified row.
+       #
+       # The representation of each cell is determined by `to_s`.
+       fun write_row(row: Object...) do write_sequence(row)
+
+       # Close the output stream.
+       fun close do ostream.close
+
+       private fun write_cell(cell: String) do
+               if cell.is_empty then return
+               if not always_escape and format.is_value_clean(cell) then
+                       ostream.write cell
+               else
+                       ostream.write format.escape_cell(cell)
+               end
+       end
+end
+
+# Reads rows from a CSV file.
+#
+# By default, uses the format recommended by RFC 4180 (see `rfc4180`).
+#
+# ~~~nit
+# var example = new StringIStream("""
+# foo,bar\r
+# "Hello, word!",1234.5 + 42\r
+# "Something\r
+# ""else""\", baz\r
+# """)
+# var reader = new CsvReader(example)
+# var table = new Array[Array[String]]
+#
+# for row in reader do table.add row
+# assert table == [
+#                      ["foo","bar"],
+#                      ["Hello, word!","1234.5 + 42"],
+#                      ["Something\r\n\"else\""," baz"]
+#              ]
+# ~~~
+class CsvReader
+       super Iterator[Array[String]]
+
+       # The input stream.
+       var istream: IStream
+
+       # The format to use.
+       #
+       # Defaults to `rfc4180`.
+       var format: CsvFormat = rfc4180 is lazy
+
+       # Do we skip the empty lines?
+       #
+       # Note: Even if this attribute is `false`, the presence of an line ending at
+       # end of the last row does not change the number of returned rows.
+       # This is because the line endings are processed as terminators, not as
+       # separators. Therefore, when there is more than one line ending at the end
+       # of the file, the additional lines are interpreted as empty rows that
+       # are skipped only if `skip_empty` is set to `true`.
+       #
+       # `false` by default.
+       var skip_empty: Bool = false is writable
+
+       # The last read row.
+       private var row: nullable Array[String] = null
+
+       # Did we read something?
+       private var started = false
+
+       # Create a new reader with the specified format.
+       init with_format(istream:IStream, format: CsvFormat) do
+               self.istream = istream
+               self.format = format
+       end
+
+       # Read the first row, if needed.
+       fun prepare do
+               if not started then
+                       row = read_row
+                       started = true
+               end
+       end
+
+       redef fun next do
+               prepare
+               assert is_ok else
+                       sys.stderr.write "Already at the end of the stream.\n"
+               end
+               row = read_row
+       end
+
+       # Return the last read row.
+       redef fun item do
+               prepare
+               return row.as(not null)
+       end
+
+       redef fun is_ok do
+               prepare
+               return row != null
+       end
+
+       # Free some internal ressources and set `is_ok` to `false`.
+       #
+       # Do not close the input stream.
+       redef fun finish do row = null
+
+       # Close the input stream.
+       fun close do istream.close
+
+       private fun read_row: nullable Array[String] do
+               if istream.eof then return null
+               var row = new Array[String]
+               var value = new RopeBuffer
+
+               # Number of unescaped characters since the last delimiter or separator.
+               var unescaped = 0
+
+               # Do we read the start of a row?
+               var got_row = false
+
+               # Do we found a delimited string in the current cell?
+               var got_delimiter = false
+
+               loop
+                       var i = istream.read_char
+                       var c: Char
+
+                       if i < 0 then
+                               if got_row then
+                                       row.add value.to_s
+                                       return row
+                               else
+                                       return null
+                               end
+                       end
+                       c = i.ascii
+
+                       if c == format.delimiter then
+                               if got_delimiter and unescaped == 0 then
+                                       # Got an escaped delimiter.
+                                       value.add format.delimiter
+                               end
+                               # Read all bytes until the delimiter.
+                               loop
+                                       i = istream.read_char
+                                       assert not_eof: i >= 0 else
+                                               sys.stderr.write "Unexpected end of file before the end of a delimited value.\n"
+                                       end
+                                       c = i.ascii
+                                       if c == format.delimiter then break
+                                       value.add c
+                               end
+                               unescaped = 0
+                               got_row = true
+                               got_delimiter = true
+                       else if c == format.separator then
+                               # Flush the value to the row.
+                               row.add value.to_s
+                               value.clear
+                               unescaped = 0
+                               got_delimiter = false
+                       else
+                               value.add c
+                               unescaped += 1
+                               if unescaped >= format.eol.length and
+                                               value.has_suffix(format.eol) then
+                                       var value_trimed = value.substring(0,
+                                                       value.length - format.eol.length).to_s
+                                       if skip_empty and row.is_empty and
+                                                       value_trimed.is_empty and
+                                                       not got_delimiter then
+                                               # Skip the empty line.
+                                               value.clear
+                                               unescaped = 0
+                                               got_row = false
+                                       else
+                                               row.add value_trimed
+                                               return row
+                                       end
+                               else
+                                       got_row = true
+                               end
+                       end
+               end
+       end
+end
+
+# The CSV format recommended by [RFC 4180](https://tools.ietf.org/html/rfc4180).
+#
+# * `delimiter`: `'"'`
+# * `separator`: `','`
+# * `eol`: `"\r\n"`
+fun rfc4180: CsvFormat do return once new CsvFormat('"', ',', "\r\n")
diff --git a/lib/csv/test_csv.nit b/lib/csv/test_csv.nit
new file mode 100644 (file)
index 0000000..074fced
--- /dev/null
@@ -0,0 +1,202 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Tests for `csv`.
+module test_csv is test_suite
+
+import test_suite
+import csv
+
+class TestCsvWriter
+       super TestSuite
+
+       # The custom CSV format used in the tests.
+       private var custom_format = new CsvFormat('/', ':', "#")
+
+       # Expect to write `row` as `expected_rfc4180` and as `expected_custom`.
+       #
+       # Parameters:
+       #
+       # * `always_escape`: value of the `always_escape` option.
+       # * `row`: row to write.
+       # * `expected_rfc4180`: expected result in RFC 4180.
+       # * `expected_custom`: expected result in the custom CSV format.
+       private fun expect(always_escape: Bool, row: SequenceRead[String],
+                       expected_rfc4180: String,
+                       expected_custom: String) do
+               var out = new StringOStream
+               var writer = new CsvWriter(out)
+
+               writer.always_escape = always_escape
+               writer.write_sequence(row)
+               assert out.to_s == expected_rfc4180 else
+                       sys.stderr.write "\nFormat: RFC 4180\n"
+                       sys.stderr.write "Expecting: \"{expected_rfc4180.escape_to_nit}\"\n"
+                       sys.stderr.write "Got: \"{out.to_s.escape_to_nit}\"\n"
+               end
+               writer.close
+
+               out = new StringOStream
+               writer = new CsvWriter.with_format(out, custom_format)
+               writer.always_escape = always_escape
+               writer.write_sequence(row)
+               assert out.to_s == expected_custom else
+                       sys.stderr.write "\nFormat: {custom_format.delimiter}"
+                       sys.stderr.write " {custom_format.separator}"
+                       sys.stderr.write " {custom_format.eol.escape_to_nit}\n"
+                       sys.stderr.write "Expecting: \"{expected_custom.escape_to_nit}\"\n"
+                       sys.stderr.write "Got: \"{out.to_s.escape_to_nit}\"\n"
+               end
+               writer.close
+       end
+
+       fun test_empty do expect(true, new Array[String], "\r\n", "#")
+
+       fun test_one_cell do expect(true, ["foo/\"\r\n,"],
+                       "\"foo/\"\"\r\n,\"\r\n",
+                       "/foo//\"\r\n,/#")
+
+       fun test_optimize_size_escaped do expect(false, ["foo/\"\r\n,"],
+                       "\"foo/\"\"\r\n,\"\r\n",
+                       "/foo//\"\r\n,/#")
+
+       fun test_optimize_size_eol do expect(false, ["foo\r#\n"],
+                       "\"foo\r#\n\"\r\n",
+                       "/foo\r#\n/#")
+
+       fun test_optimize_size_unescaped do expect(false, ["foo"],
+                       "foo\r\n",
+                       "foo#")
+
+       fun test_multiple_cells do expect(true, ["1", "", "/"],
+                       "\"1\",,\"/\"\r\n",
+                       "/1/::////#")
+
+       fun test_multiple_cells_optimize_size do expect(false, ["1", "", "/"],
+                       "1,,/\r\n",
+                       "1::////#")
+end
+
+class TestCsvReader
+       super TestSuite
+
+       # The custom CSV format used in the tests.
+       private var custom_format = new CsvFormat('/', ':', "#")
+
+       # Expect to read `expected`.
+       #
+       # Parameters:
+       #
+       # * `skip_empty`: value of the `skip_empty` option.
+       # * `modal_escaping`: value of the `modal_escaping` option.
+       # * `input_rfc4180`: input in the RFC 4180 format.
+       # * `input_custom`: input in the custom CSV format.
+       # * `expected`: expected resulting table.
+       private fun expect(skip_empty: Bool,
+                       input_rfc4180: String,
+                       input_custom: String,
+                       expected: SequenceRead[SequenceRead[String]]) do
+               var istream: IStream
+               var reader: CsvReader
+               var i = 0
+
+               istream = new StringIStream(input_rfc4180)
+               reader = new CsvReader(istream)
+               reader.skip_empty = skip_empty
+               assert_table_equals("RFC 4180", reader, expected.iterator)
+
+               istream = new StringIStream(input_custom)
+               reader = new CsvReader.with_format(istream, custom_format)
+               reader.skip_empty = skip_empty
+               assert_table_equals("{custom_format.delimiter} " +
+                               "{custom_format.separator} " +
+                               "{custom_format.eol.escape_to_nit}", reader, expected.iterator)
+       end
+
+       # Check if tables are equal.
+       private fun assert_table_equals(format: String,
+                       actual: Iterator[SequenceRead[String]],
+                       expected: Iterator[SequenceRead[String]]) do
+               var i = 0
+
+               for actual_row in actual do
+                       assert expected.is_ok else fail(format,"Too many rows.")
+                       var expected_row = expected.item
+                       assert_row_equals(format, i, actual_row, expected_row)
+                       expected.next
+                       i += 1
+               end
+               assert not expected.is_ok else fail(format, "Not enough rows.")
+               expected.finish
+       end
+
+       # Check if rows are equal.
+       private fun assert_row_equals(format: String,
+                       row_index: Int,
+                       actual: SequenceRead[String],
+                       expected: SequenceRead[String]) do
+               assert actual == expected else
+                       fail(format, """
+At row {{{row_index}}}.
+Expecting: {{{expected.join("|")}}}
+Got: {{{actual.join("|")}}}""")
+               end
+       end
+
+       # Output an error message with an indication of the format used.
+       private fun fail(format: Text, message: Text) do
+               sys.stderr.write "\nFormat: {format}\n"
+               sys.stderr.write message
+               sys.stderr.write "\n"
+       end
+
+       fun test_empty do expect(false, "", "", new Array[Array[String]])
+
+       fun test_empty_eol do expect(false, "\r\n", "#", [[""]])
+
+       fun test_empty_skip do expect(true, "", "", new Array[Array[String]])
+
+       fun test_empty_skip1 do expect(true, "\r\n", "#", new Array[Array[String]])
+
+       fun test_empty_skip2 do expect(true, "\r\n\r\n", "##", new Array[Array[String]])
+
+       fun test_escaped do expect(false, "\"foo/\"\"\r\n,\"\r\n",
+                       "/foo//\"\r\n,/#", [["foo/\"\r\n,"]])
+
+       fun test_unescaped do expect(false, "foo bar\r\n",
+                       "foo bar#", [["foo bar"]])
+
+       fun test_escaped_no_eol do expect(false, "\"foo/\"\"\r\n,\"",
+                       "/foo//\"\r\n,/", [["foo/\"\r\n,"]])
+
+       fun test_unescaped_no_eol do expect(false, "foo bar",
+                       "foo bar", [["foo bar"]])
+
+       fun test_multiple_cells do expect(false, "\"1\",,\"/\"\r\n",
+                       "/1/::////#", [["1", "", "/"]])
+
+       fun test_multiple_cells_unescaped do expect(false, "1,,/\r\n",
+                       "1::////#", [["1", "", "/"]])
+
+       fun test_modal_escaping do expect(false, """a"b""/c","d"e""",
+                       """/ab"///c:d/e/""", [["""ab"/c""", "de"]])
+
+       fun test_skip_start do expect(true, "\r\n1,,/\r\n",
+                       "#1::////#", [["1", "", "/"]])
+
+       fun test_dont_skip_empty_delimited do expect(true, "\"\"\r\n",
+                       "//#", [[""]])
+
+       fun test_dont_skip_multiple_empty_cells do expect(true, ",\r\n",
+                       ":#", [["",""]])
+
+       fun test_mutiple_rows do expect(false, "\"a\r\nb#\",c\r\nd,\r\n,e\r\n",
+                       "/a\r\nb#/:c#d:#:e#", [["a\r\nb#", "c"], ["d", ""], ["", "e"]])
+end
index 88e7008..9061e53 100644 (file)
@@ -1,6 +1,7 @@
 # This file is part of NIT ( http://www.nitlanguage.org ).
 #
 # Copyright 2008 Floréal Morandat <morandat@lirmm.fr>
+# Copyright 2014 Alexandre Terrasa <alexandre@moz-code.org>
 #
 # This file is free software, which comes along with NIT.  This software is
 # distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
@@ -10,6 +11,7 @@
 # You  are  allowed  to  redistribute it and sell it, alone or is a part of
 # another product.
 
+# A `Set` that contains only integers.
 class DummyArray
        super Set[Int]
        private var capacity: Int
@@ -75,14 +77,15 @@ class DummyArray
                return _values[pos]
        end
 
-       init(capacity: Int)
-       do
+       # initialize a new DummyArray with `capacity`.
+       init(capacity: Int) is old_style_init do
                _capacity = capacity
                _keys = new NativeArray[Int](capacity)
                _values = new NativeArray[Int](capacity)
        end
 end
 
+# An iterator over a `DummyArray`.
 class DummyIterator
        super Iterator[Int]
        private var array: DummyArray
@@ -101,8 +104,8 @@ class DummyIterator
 
        redef fun next do _pos = _pos + 1 end
 
-       init(array: DummyArray)
-       do
+       # Initialize an iterator for `array`.
+       init(array: DummyArray) is old_style_init do
                _pos = 0
                _array = array
        end
index e349a0d..5c50387 100644 (file)
@@ -167,13 +167,13 @@ extern class EGLDisplay `{ EGLDisplay `}
                return NativeString_to_s((char *)eglQueryString(recv, name));
        `}
 
-       fun vendor: String do return query_string("3053".to_hex)
+       fun vendor: String do return query_string(0x3053)
 
-       fun version: String do return query_string("3054".to_hex)
+       fun version: String do return query_string(0x3054)
 
-       fun extensions: Array[String] do return query_string("3055".to_hex).split_with(" ")
+       fun extensions: Array[String] do return query_string(0x3055).split_with(" ")
 
-       fun client_apis: Array[String] do return query_string("308D".to_hex).split_with(" ")
+       fun client_apis: Array[String] do return query_string(0x308D).split_with(" ")
 
        fun swap_buffers(surface: EGLSurface) `{ eglSwapBuffers(recv, surface); `}
 end
@@ -208,23 +208,23 @@ class EGLConfigAttribs
        var display: EGLDisplay
        var config: EGLConfig
 
-       fun buffer_size: Int do return display.config_attrib(config, "3020".to_hex)
-       fun alpha_size: Int do return display.config_attrib(config, "3021".to_hex)
-       fun blue_size: Int do return display.config_attrib(config, "3022".to_hex)
-       fun green_size: Int do return display.config_attrib(config, "3023".to_hex)
-       fun red_size: Int do return display.config_attrib(config, "3024".to_hex)
-       fun depth_size: Int do return display.config_attrib(config, "3025".to_hex)
-       fun stencil_size: Int do return display.config_attrib(config, "3026".to_hex)
+       fun buffer_size: Int do return display.config_attrib(config, 0x3020)
+       fun alpha_size: Int do return display.config_attrib(config, 0x3021)
+       fun blue_size: Int do return display.config_attrib(config, 0x3022)
+       fun green_size: Int do return display.config_attrib(config, 0x3023)
+       fun red_size: Int do return display.config_attrib(config, 0x3024)
+       fun depth_size: Int do return display.config_attrib(config, 0x3025)
+       fun stencil_size: Int do return display.config_attrib(config, 0x3026)
 
-       fun native_visual_id: Int do return display.config_attrib(config, "302E".to_hex)
-       fun native_visual_type: Int do return display.config_attrib(config, "302F".to_hex)
+       fun native_visual_id: Int do return display.config_attrib(config, 0x302E)
+       fun native_visual_type: Int do return display.config_attrib(config, 0x302F)
 
        fun caveat: EGLConfigCaveat do
-               return new EGLConfigCaveat.from_i(display.config_attrib(config, "3027".to_hex))
+               return new EGLConfigCaveat.from_i(display.config_attrib(config, 0x3027))
        end
 
        fun conformant: EGLConformant do
-               return new EGLConformant.from_i(display.config_attrib(config, "3042".to_hex))
+               return new EGLConformant.from_i(display.config_attrib(config, 0x3042))
        end
 end
 
@@ -290,21 +290,21 @@ class EGLSurfaceAttribs
        var display: EGLDisplay
        var surface: EGLSurface
 
-       fun height: Int do return display.query_surface(surface, "3056".to_hex)
-       fun width: Int do return display.query_surface(surface, "3057".to_hex)
-       fun largest_pbuffer: Int do return display.query_surface(surface, "3058".to_hex)
-       fun texture_format: Int do return display.query_surface(surface, "3080".to_hex)
-       fun texture_target: Int do return display.query_surface(surface, "3081".to_hex)
-       fun mipmap_texture: Int do return display.query_surface(surface, "3082".to_hex)
-       fun mipmap_level: Int do return display.query_surface(surface, "3083".to_hex)
-       fun render_buffer: Int do return display.query_surface(surface, "3086".to_hex)
-       fun vg_colorspace: Int do return display.query_surface(surface, "3087".to_hex)
-       fun vg_alpha_format: Int do return display.query_surface(surface, "3088".to_hex)
-       fun horizontal_resolution: Int do return display.query_surface(surface, "3090".to_hex)
-       fun vertical_resolution: Int do return display.query_surface(surface, "3091".to_hex)
-       fun pixel_aspect_ratio: Int do return display.query_surface(surface, "3092".to_hex)
-       fun swap_behavior: Int do return display.query_surface(surface, "3093".to_hex)
-       fun multisample_resolve: Int do return display.query_surface(surface, "3099".to_hex)
+       fun height: Int do return display.query_surface(surface, 0x3056)
+       fun width: Int do return display.query_surface(surface, 0x3057)
+       fun largest_pbuffer: Int do return display.query_surface(surface, 0x3058)
+       fun texture_format: Int do return display.query_surface(surface, 0x3080)
+       fun texture_target: Int do return display.query_surface(surface, 0x3081)
+       fun mipmap_texture: Int do return display.query_surface(surface, 0x3082)
+       fun mipmap_level: Int do return display.query_surface(surface, 0x3083)
+       fun render_buffer: Int do return display.query_surface(surface, 0x3086)
+       fun vg_colorspace: Int do return display.query_surface(surface, 0x3087)
+       fun vg_alpha_format: Int do return display.query_surface(surface, 0x3088)
+       fun horizontal_resolution: Int do return display.query_surface(surface, 0x3090)
+       fun vertical_resolution: Int do return display.query_surface(surface, 0x3091)
+       fun pixel_aspect_ratio: Int do return display.query_surface(surface, 0x3092)
+       fun swap_behavior: Int do return display.query_surface(surface, 0x3093)
+       fun multisample_resolve: Int do return display.query_surface(surface, 0x3099)
 end
 
 extern class EGLError `{ EGLint `}
@@ -405,26 +405,26 @@ class EGLConfigChooser
        end
 
        fun close do
-               insert_attrib_key "3038".to_hex
+               insert_attrib_key 0x3038
                closed = true
        end
 
-       fun surface_type=(flag: Int) do insert_attrib_with_val("3033".to_hex, flag)
+       fun surface_type=(flag: Int) do insert_attrib_with_val(0x3033, flag)
        fun surface_type_egl do surface_type = 4
 
-       fun blue_size=(size: Int) do insert_attrib_with_val("3022".to_hex, size)
-       fun green_size=(size: Int) do insert_attrib_with_val("3023".to_hex, size)
-       fun red_size=(size: Int) do insert_attrib_with_val("3024".to_hex, size)
+       fun blue_size=(size: Int) do insert_attrib_with_val(0x3022, size)
+       fun green_size=(size: Int) do insert_attrib_with_val(0x3023, size)
+       fun red_size=(size: Int) do insert_attrib_with_val(0x3024, size)
 
-       fun buffer_size=(size: Int) do insert_attrib_with_val("3020".to_hex, size)
-       fun alpha_size=(size: Int) do insert_attrib_with_val("3021".to_hex, size)
-       fun depth_size=(size: Int) do insert_attrib_with_val("3025".to_hex, size)
-       fun stencil_size=(size: Int) do insert_attrib_with_val("3026".to_hex, size)
-       fun sample_buffers=(size: Int) do insert_attrib_with_val("3031".to_hex, size)
+       fun buffer_size=(size: Int) do insert_attrib_with_val(0x3020, size)
+       fun alpha_size=(size: Int) do insert_attrib_with_val(0x3021, size)
+       fun depth_size=(size: Int) do insert_attrib_with_val(0x3025, size)
+       fun stencil_size=(size: Int) do insert_attrib_with_val(0x3026, size)
+       fun sample_buffers=(size: Int) do insert_attrib_with_val(0x3031, size)
 
-       fun caveat=(caveat: EGLConfigCaveat) do insert_attrib_with_val("3050".to_hex, caveat.to_i)
+       fun caveat=(caveat: EGLConfigCaveat) do insert_attrib_with_val(0x3050, caveat.to_i)
 
-       fun conformant=(conformant: EGLConformant) do insert_attrib_with_val("3042".to_hex, conformant.to_i)
+       fun conformant=(conformant: EGLConformant) do insert_attrib_with_val(0x3042, conformant.to_i)
 
        fun choose(display: EGLDisplay): nullable Array[EGLConfig]
        do
index d46f4d1..3fd2fff 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+# Platform for the _emscripten_ framework
+#
+# Importing this module from your project will tell _nitg_ to compile
+# to JavaScript for the _emscripten_ framework.
 module emscripten is platform
 
 `{
@@ -21,12 +25,16 @@ module emscripten is platform
        #include <gc.h>
 `}
 
-redef class String
+redef class Text
+       # Run `self` as JavaScript code
        fun run_js do run_js_native(self.escape_to_js.to_cstring)
+
        private fun run_js_native(script: NativeString) `{ emscripten_run_script(script); `}
 
-       fun escape_to_js: String do return self.replace('\n', "\\n")
+       # Escape the content of `self` to pass to JavaScript code
+       fun escape_to_js: Text do return replace('\n', "\\n")
 
+       # Raise a JavaScript alert
        fun alert do "alert('{self.escape_to_js}')".run_js
 end
 
index 1596c1e..b8c9798 100644 (file)
@@ -75,12 +75,12 @@ interface Boxed[N: Numeric]
                        self.top >= other.bottom and other.top >= self.bottom
        end
 
-       # Create a bounding box that englobes the actual bounding box.
+       # Create a bounding box that encloses the actual bounding box.
        # `dist` is the distance between the inner boundaries and the outer boundaries.
        # ~~~
        # var p = new Point[Int](5,10)
        # var b = p.padded(3)
-       # assert b.top == 2 and b.bot = 8 and b.left == 7 and b.right == 13
+       # assert b.left == 2 and b.right == 8 and b.top == 13 and b.bottom == 7
        # ~~~
        fun padded(dist: N): Box[N] do return new Box[N].lrtb(left - dist, right + dist, top + dist, bottom - dist)
 end
index 39fca84..0c32345 100644 (file)
@@ -24,7 +24,7 @@ class GithubCurl
        super Curl
 
        # Headers to use on all requests
-       var header: HeaderMap
+       var header: HeaderMap is noinit
 
        # OAuth token
        var auth: String
@@ -33,12 +33,7 @@ class GithubCurl
        # Eg. "Awesome-Octocat-App"
        var user_agent: String
 
-       init(auth: String, user_agent: String)
-       do
-               super
-               self.auth = auth
-               self.user_agent = user_agent
-
+       init do
                header = new HeaderMap
                header["Authorization"] = "token {auth}"
        end
index 9123bc8..8d5ec6a 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# OpenGL graphics rendering library for embedded systems, version 2.0.
+# OpenGL graphics rendering library for embedded systems, version 2.0
+#
+# This is a low-level wrapper, it can be useful for developers already familiar
+# with the C API of OpenGL. Most developers will prefer to use higher level
+# wrappers such as `mnit` and `gammit`.
+#
+# Defines the annotations `glsl_vertex_shader` and `glsl_fragment_shader`
+# applicable on string literals to check shader code using `glslangValidator`.
+# The tool must be in PATH. It can be downloaded from
+# https://www.khronos.org/opengles/sdk/tools/Reference-Compiler/
 #
 # Most services of this module are a direct wrapper of the underlying
 # C library. If a method or class is not documented in Nit, refer to
 # the official documentation by the Khronos Group at:
 # http://www.khronos.org/opengles/sdk/docs/man/
-module glesv2 is pkgconfig
+module glesv2 is
+       pkgconfig
+       new_annotation glsl_vertex_shader
+       new_annotation glsl_fragment_shader
+end
+
 
 in "C Header" `{
        #include <GLES2/gl2.h>
 `}
 
-# Opengl ES program to which we attach shaders
+# OpenGL ES program to which we attach shaders
 extern class GLProgram `{GLuint`}
+       # Create a new program
+       #
+       # The newly created instance should be checked using `is_ok`.
        new `{ return glCreateProgram(); `}
 
+       # Is this a valid program?
        fun is_ok: Bool `{ return glIsProgram(recv); `}
 
+       # Attach a `shader` to this program
        fun attach_shader(shader: GLShader) `{ glAttachShader(recv, shader); `}
 
+       # Set the location for the attribute by `name`
        fun bind_attrib_location(index: Int, name: String) import String.to_cstring `{
                GLchar *c_name = String_to_cstring(name);
                glBindAttribLocation(recv, index, c_name);
        `}
 
+       # Get the location of the attribute by `name`
+       #
+       # Returns `-1` if there is no active attribute named `name`.
        fun attrib_location(name: String): Int import String.to_cstring `{
                GLchar *c_name = String_to_cstring(name);
                return glGetAttribLocation(recv, c_name);
        `}
 
+       # Get the location of the uniform by `name`
+       #
+       # Returns `-1` if there is no active uniform named `name`.
+       fun uniform_location(name: String): Int import String.to_cstring `{
+               GLchar *c_name = String_to_cstring(name);
+               return glGetUniformLocation(recv, c_name);
+       `}
+
+       # Query information on this program
        fun query(pname: Int): Int `{
                int val;
                glGetProgramiv(recv, pname, &val);
                return val;
        `}
 
+       # Try to link this program
+       #
+       # Check result using `in_linked` and `info_log`.
        fun link `{ glLinkProgram(recv); `}
-       fun is_linked: Bool do return query("8B82".to_hex) != 0
 
+       # Is this program linked?
+       fun is_linked: Bool do return query(0x8B82) != 0
+
+       # Use this program for the following operations
        fun use `{ glUseProgram(recv); `}
 
+       # Delete this program
        fun delete `{ glDeleteProgram(recv); `}
-       fun is_deleted: Bool do return query("8B80".to_hex) != 0
 
+       # Has this program been deleted?
+       fun is_deleted: Bool do return query(0x8B80) != 0
+
+       # Validate whether this program can be executed in the current OpenGL state
+       #
+       # Check results using `is_validated` and `info_log`.
        fun validate `{ glValidateProgram(recv); `}
-       fun is_validated: Bool do return query("8B83".to_hex) != 0
 
+       # Boolean result of `validate`, must be called after `validate`
+       fun is_validated: Bool do return query(0x8B83) != 0
+
+       # Retrieve the information log of this program
+       #
+       # Useful with `link` and `validate`
        fun info_log: String import NativeString.to_s `{
                int size;
                glGetProgramiv(recv, GL_INFO_LOG_LENGTH, &size);
@@ -68,37 +117,137 @@ extern class GLProgram `{GLuint`}
                glGetProgramInfoLog(recv, size, NULL, msg);
                return NativeString_to_s(msg);
        `}
+
+       # Number of active uniform in this program
+       #
+       # This should be the number of uniforms declared in all shader, except
+       # unused uniforms which may have been optimized out.
+       fun n_active_uniforms: Int do return query(0x8B86)
+
+       # Length of the longest uniform name in this program, including `\n`
+       fun active_uniform_max_length: Int do return query(0x8B87)
+
+       # Number of active attributes in this program
+       #
+       # This should be the number of uniforms declared in all shader, except
+       # unused uniforms which may have been optimized out.
+       fun n_active_attributes: Int do return query(0x8B89)
+
+       # Length of the longest uniform name in this program, including `\n`
+       fun active_attribute_max_length: Int do return query(0x8B8A)
+
+       # Number of shaders attached to this program
+       fun n_attached_shaders: Int do return query(0x8B85)
+
+       # Name of the active attribute at `index`
+       fun active_attrib_name(index: Int): String
+       do
+               var max_size = active_attribute_max_length
+               return active_attrib_name_native(index, max_size).to_s
+       end
+       private fun active_attrib_name_native(index, max_size: Int): NativeString `{
+               char *name = malloc(max_size);
+               glGetActiveAttrib(recv, index, max_size, NULL, NULL, NULL, name);
+               return name;
+       `}
+
+       # Size of the active attribute at `index`
+       fun active_attrib_size(index: Int): Int `{
+               int size;
+               glGetActiveAttrib(recv, index, 0, NULL, NULL, &size, NULL);
+               return size;
+       `}
+
+       # Type of the active attribute at `index`
+       #
+       # May only be float related data types (single float, vectors and matrix).
+       fun active_attrib_type(index: Int): GLFloatDataType `{
+               GLenum type;
+               glGetActiveAttrib(recv, index, 0, NULL, &type, NULL, NULL);
+               return type;
+       `}
+
+       # Name of the active uniform at `index`
+       fun active_uniform_name(index: Int): String
+       do
+               var max_size = active_attribute_max_length
+               return active_uniform_name_native(index, max_size).to_s
+       end
+       private fun active_uniform_name_native(index, max_size: Int): NativeString `{
+               char *name = malloc(max_size);
+               glGetActiveUniform(recv, index, max_size, NULL, NULL, NULL, name);
+               return name;
+       `}
+
+       # Size of the active uniform at `index`
+       fun active_uniform_size(index: Int): Int `{
+               int size;
+               glGetActiveUniform(recv, index, 0, NULL, NULL, &size, NULL);
+               return size;
+       `}
+
+       # Type of the active uniform at `index`
+       #
+       # May be any data type supported by OpenGL ES 2.0 shaders.
+       fun active_uniform_type(index: Int): GLDataType `{
+               GLenum type;
+               glGetActiveUniform(recv, index, 0, NULL, &type, NULL, NULL);
+               return type;
+       `}
 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: nullable String import NativeString.to_s `{
-               int size;
-               glGetShaderiv(recv, GL_SHADER_SOURCE_LENGTH, &size);
-               if (size == 0) return NULL;
+
+       # Source of the shader, if available
+       #
+       # Returns `null` if the source is not available, usually when the shader
+       # was created from a binary file.
+       fun source: nullable String
+       do
+               var size = query(0x8B88)
+               if size == 0 then return null
+               return source_native(size).to_s
+       end
+
+       private fun source_native(size: Int): NativeString `{
                GLchar *code = malloc(size);
                glGetShaderSource(recv, size, NULL, code);
-               return NativeString_to_s(code);
+               return code;
        `}
 
+       # Query information on this shader
        protected fun query(pname: Int): Int `{
                int val;
                glGetShaderiv(recv, pname, &val);
                return val;
        `}
 
+       # Try to compile `source` into a binary GPU program
+       #
+       # Check the result using `is_compiled` and `info_log`
        fun compile `{ glCompileShader(recv); `}
-       fun is_compiled: Bool do return query("8B81".to_hex) != 0
 
+       # Has this shader been compiled?
+       fun is_compiled: Bool do return query(0x8B81) != 0
+
+       # Delete this shader
        fun delete `{ glDeleteShader(recv); `}
-       fun is_deleted: Bool do return query("8B80".to_hex) != 0
 
+       # Has this shader been deleted?
+       fun is_deleted: Bool do return query(0x8B80) != 0
+
+       # Is this a valid shader?
        fun is_ok: Bool `{ return glIsShader(recv); `}
 
+       # Retrieve the information log of this shader
+       #
+       # Useful with `link` and `validate`
        fun info_log: String import NativeString.to_s `{
                int size;
                glGetShaderiv(recv, GL_INFO_LOG_LENGTH, &size);
@@ -106,25 +255,35 @@ extern class GLShader `{GLuint`}
                glGetShaderInfoLog(recv, size, NULL, msg);
                return NativeString_to_s(msg);
        `}
-
 end
 
+# An OpenGL ES 2.0 fragment shader
 extern class GLFragmentShader
        super GLShader
 
+       # Create a new fragment shader
+       #
+       # The newly created instance should be checked using `is_ok`.
        new `{ return glCreateShader(GL_FRAGMENT_SHADER); `}
 end
 
+# An OpenGL ES 2.0 vertex shader
 extern class GLVertexShader
        super GLShader
 
+       # Create a new fragment shader
+       #
+       # The newly created instance should be checked using `is_ok`.
        new `{ return glCreateShader(GL_VERTEX_SHADER); `}
 end
 
 # An array of `Float` associated to a program variable
 class VertexArray
        var index: Int
+
+       # Number of data per vertex
        var count: Int
+
        protected var glfloat_array: GLfloatArray
 
        init(index, count: Int, array: Array[Float])
@@ -159,6 +318,7 @@ extern class GLfloatArray `{GLfloat *`}
        `}
 end
 
+# An OpenGL ES 2.0 error code
 extern class GLError `{ GLenum `}
        fun is_ok: Bool do return is_no_error
        fun is_no_error: Bool `{ return recv == GL_NO_ERROR; `}
@@ -180,24 +340,19 @@ 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); `}
-protected fun gl_vertex_attrib_pointer_int(index, length: Int, normalize: Bool, stride: Int, vertex: Array[Int]) import Array[Int].length, Array[Int].intern_items `{
-       int* c_vertex = Array_of_Int_intern_items(vertex);
-       glVertexAttribPointer(index, length, GL_INT, normalize, stride, c_vertex);
-`}
-protected fun gl_vertex_attrib_pointer_float(index, length: Int, normalize: Bool, stride: Int, vertex: Array[Float]) import Array[Float].length, Array[Float].intern_items `{
-       int* c_vertex = Array_of_Float_intern_items(vertex);
-       glVertexAttribPointer(index, length, GL_FLOAT, normalize, stride, c_vertex);
-`}
 
 # 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 once "0100".to_hex
-protected fun gl_stencil_buffer_bit: Int do return once "0400".to_hex
-protected fun gl_color_buffer_bit: Int do return once "4000".to_hex
+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)
@@ -213,20 +368,61 @@ do
        end
 end
 
+# Query the boolean value at `key`
 private fun gl_get_bool(key: Int): Bool `{
        GLboolean val;
-       glGetBooleanv(GL_SHADER_COMPILER, &val);
+       glGetBooleanv(key, &val);
        return val == GL_TRUE;
 `}
+
+# Query the floating point value at `key`
 private fun gl_get_float(key: Int): Float `{
        GLfloat val;
        glGetFloatv(key, &val);
        return val;
 `}
+
+# Query the integer value at `key`
 private fun gl_get_int(key: Int): Int `{
        GLint val;
        glGetIntegerv(key, &val);
        return val;
 `}
 
-fun gl_shader_compiler: Bool do return gl_get_bool("8DFA".to_hex)
+# Does this driver support shader compilation?
+#
+# Should always return `true` in OpenGL ES 2.0 and 3.0.
+fun gl_shader_compiler: Bool do return gl_get_bool(0x8DFA)
+
+# 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 `}
+       fun is_float: Bool `{ return recv == GL_FLOAT; `}
+       fun is_float_vec2: Bool `{ return recv == GL_FLOAT_VEC2; `}
+       fun is_float_vec3: Bool `{ return recv == GL_FLOAT_VEC3; `}
+       fun is_float_vec4: Bool `{ return recv == GL_FLOAT_VEC4; `}
+       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; `}
+end
+
+# All data types of OpenGL ES 2.0 shaders
+#
+# These types can be used by shader uniforms, as seen with
+# `GLProgram::active_uniform_type`.
+extern class GLDataType
+       super GLFloatDataType
+
+       fun is_int: Bool `{ return recv == GL_INT; `}
+       fun is_int_vec2: Bool `{ return recv == GL_INT_VEC2; `}
+       fun is_int_vec3: Bool `{ return recv == GL_INT_VEC3; `}
+       fun is_int_vec4: Bool `{ return recv == GL_INT_VEC4; `}
+       fun is_bool: Bool `{ return recv == GL_BOOL; `}
+       fun is_bool_vec2: Bool `{ return recv == GL_BOOL_VEC2; `}
+       fun is_bool_vec3: Bool `{ return recv == GL_BOOL_VEC3; `}
+       fun is_bool_vec4: Bool `{ return recv == GL_BOOL_VEC4; `}
+       fun is_sampler_2d: Bool `{ return recv == GL_SAMPLER_2D; `}
+       fun is_sampler_cube: Bool `{ return recv == GL_SAMPLER_CUBE; `}
+end
index 820f608..cea53cb 100644 (file)
@@ -17,6 +17,8 @@
 # GPIO related functionnalities
 module gpio
 
+# A physical binary pin
 interface Pin
+       # Set the output of this pin
        fun write(high: Bool) is abstract
 end
index 8426097..1626437 100644 (file)
@@ -136,7 +136,7 @@ redef class HashCollection[K]
        # Count and update length of collisions for `node_at_idx`
        # Note for dynamic call-graph analysis: callers of this functions are
        # responsible of collisions.
-       private fun gt_collide(i: Int, k: K)
+       fun gt_collide(i: Int, k: K)
        do
                var c = _array[i]
                sys.gt_coll += 1
@@ -159,7 +159,7 @@ redef class HashCollection[K]
        # Count and update length of collisions for `store`
        # Note for dynamic call-graph analysis: callers of this functions are
        # responsible of collisions.
-       private fun st_collide(i: Int, n: N)
+       fun st_collide(i: Int, n: N)
        do
                var c = _array[i]
                sys.st_coll += 1
index f58bdf6..f7ae180 100644 (file)
@@ -119,7 +119,7 @@ class HTMLTag
        # Set a 'value' for 'key'
        #     var img = new HTMLTag("img")
        #     img.attr("src", "./image.png").attr("alt", "image")
-       #     assert img.write_to_string      == """<img src="./image.png" alt="image"/>"""
+       #     assert img.write_to_string      == """<img src=".&#47;image.png" alt="image"/>"""
        fun attr(key: String, value: String): HTMLTag do
                attrs[key] = value
                return self
index 04245a5..4ab4eab 100644 (file)
@@ -32,7 +32,6 @@ in "Java" `{
 
 extern class NativeFile in "Java" `{ java.io.File `}
        super JavaObject
-       redef type SELF: NativeFile
 
        fun can_execute: Bool in "Java" `{ return recv.canExecute(); `}
        fun can_read: Bool in "Java" `{ return recv.canRead(); `}
@@ -77,7 +76,6 @@ end
 
 extern class NativeFileInputStream in "Java" `{ java.io.FileInputStream `}
        super JavaObject
-       redef type SELF: NativeFileInputStream
 
        fun available: Int in "Java" `{
                try {
@@ -114,7 +112,6 @@ end
 
 extern class NativeFileOutputStream in "Java" `{ java.io.FileOutputStream `}
        super JavaObject
-       redef type SELF: NativeFileOutputStream
 
        fun close in "Java" `{
                try {
@@ -141,7 +138,7 @@ end
 
 extern class NativeFileDescriptor in "Java" `{ java.io.FileDescriptor `}
        super JavaObject
-       redef type SELF: NativeFileDescriptor
+
        fun sync in "Java" `{
                try{
                        recv.sync();
@@ -154,7 +151,6 @@ end
 
 extern class NativeInputStream in "Java" `{ java.io.InputStream `}
        super JavaObject
-       redef type SELF: NativeInputStream
 
        fun available: Int in "Java" `{
                try {
index 0b6a652..c3db430 100644 (file)
@@ -98,8 +98,6 @@ end
 extern class JavaString in "Java" `{ java.lang.String `}
        super JavaObject
 
-       redef type SELF: JavaString
-
        # Get the string from Java and copy it to Nit memory
        fun to_cstring: NativeString import sys, Sys.jni_env `{
                Sys sys = JavaString_sys(recv);
@@ -140,7 +138,6 @@ redef class Text
 end
 
 redef extern class JavaObject
-       type SELF: JavaObject
 
        # Returns a global reference to the Java object behind this reference
        #
index d15ceb7..1ee3ce7 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Dynamic interface to read Json strings.
+# Dynamic interface to read JSON strings.
 #
 # `String::to_json_value` returns a `JsonValue` which can be queried
-# to get the underlying Json data. It can also be used as any Json types.
+# to get the underlying JSON data.
 module dynamic
 
 import error
 private import static
 
+# Wraps a JSON value.
+#
+# Offer methods to query the type, to dynamicaly cast the underlying value and
+# to query elements (in case of a JSON object or a JSON array).
+#
+# Use `String::to_json_value` to get a `JsonValue` from a string.
 class JsonValue
+
+       # The wrapped JSON value.
        var value: nullable Object
 
        # Is this value null?
@@ -74,8 +82,8 @@ class JsonValue
        #
        # require: `self.is_numeric`
        #
-       #     assert "1.234".to_json_value.to_numeric = 1.234
-       #     assert "1234".to_json_value.to_numeric = 1234
+       #     assert "1.234".to_json_value.to_numeric == 1.234
+       #     assert "1234".to_json_value.to_numeric == 1234
        fun to_numeric: Numeric
        do
                if is_int then return to_i
index 29e5c22..bb578fd 100644 (file)
@@ -319,7 +319,8 @@ end
 # Redef parser
 
 redef class Nvalue
-       fun to_nit_object: nullable Jsonable is abstract
+       # The represented value.
+       private fun to_nit_object: nullable Jsonable is abstract
 end
 
 redef class Nvalue_number
@@ -348,7 +349,8 @@ redef class Nvalue_null
 end
 
 redef class Nstring
-       fun to_nit_string: String do
+       # The represented string.
+       private fun to_nit_string: String do
                var res = new FlatBuffer
                var i = 1
                while i < text.length - 1 do
@@ -398,7 +400,8 @@ redef class Nvalue_object
 end
 
 redef class Nmembers
-       fun pairs: Array[Npair] is abstract
+       # All the key-value pairs.
+       private fun pairs: Array[Npair] is abstract
 end
 
 redef class Nmembers_tail
@@ -415,8 +418,11 @@ redef class Nmembers_head
 end
 
 redef class Npair
-       fun name: String do return n_string.to_nit_string
-       fun value: nullable Jsonable do return n_value.to_nit_object
+       # The represented key.
+       private fun name: String do return n_string.to_nit_string
+
+       # The represented value.
+       private fun value: nullable Jsonable do return n_value.to_nit_object
 end
 
 redef class Nvalue_array
@@ -433,7 +439,8 @@ redef class Nvalue_array
 end
 
 redef class Nelements
-       fun items: Array[Nvalue] is abstract
+       # All the items.
+       private fun items: Array[Nvalue] is abstract
 end
 
 redef class Nelements_tail
index f090b24..c41426d 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+# Handles serialization and deserialization of objects to/from Json.
 module json_serialization
 
 import serialization
 import json::static
 
+# Serializer of Nit objects to Json string.
 class JsonSerializer
        super Serializer
 
        # Target writing stream
        var stream: OStream
 
-       init(stream: OStream) do self.stream = stream
-
        redef fun serialize(object)
        do
                if object == null then
@@ -52,9 +52,10 @@ class JsonSerializer
                end
        end
 
-       # Map of references to already serialized objects
+       # Map of references to already serialized objects.
        var refs_map = new HashMap[Serializable,Int]
 
+       # Get the internal serialized reference for this `object`.
        private fun ref_id_for(object: Serializable): Int
        do
                if refs_map.keys.has(object) then
@@ -67,18 +68,28 @@ class JsonSerializer
        end
 end
 
-# Deserializer from a Json string
+# Deserializer from a Json string.
 class JsonDeserializer
        super Deserializer
 
-       var root: nullable Jsonable
+       # Json text to deserialize from.
+       private var text: Text
+
+       # Root json object parsed from input text.
+       var root: nullable Jsonable is noinit
+
+       # Depth-first path in the serialized object tree.
        var path = new Array[JsonObject]
+
+       # Map of refenrences to already deserialized objects.
        var id_to_object = new HashMap[Int, Object]
 
+       # Last encountered object reference id.
+       #
+       # See `id_to_object`.
        var just_opened_id: nullable Int = null
 
-       init(text: Text)
-       do
+       init do
                var root = text.parse_json
                if root isa JsonObject then path.add(root)
                self.root = root
@@ -246,6 +257,7 @@ redef class Array[E]
                end
        end
 
+       # Instanciate a new `Array` from its serialized representation.
        init from_deserializer(v: Deserializer)
        do
                if v isa JsonDeserializer then
index 8012746..6063f23 100644 (file)
@@ -30,7 +30,8 @@ in "C Header" `{
 # Utility to select options to create the VM using `create_jvm`
 #
 # Usage example:
-# ~~~~
+#
+# ~~~~nitish
 # var builder = new JavaVMBuilder
 # builder.options.add "-Djava.class.path=."
 # var jvm = builder.create_jvm
index 525915c..9ff7ed0 100644 (file)
@@ -92,8 +92,9 @@ extern class NativeEventBase `{ struct event_base * `}
 
        # Create a new event_base to use with the rest of Libevent
        new `{ return event_base_new(); `}
+
+       # Has `self` been correctly initialized?
        fun is_valid: Bool do return not address_is_null
-       #fun creation_ok
 
        # Event dispatching loop
        #
@@ -154,7 +155,7 @@ class Connection
        # Write a string to the connection
        fun write(str: String)
        do
-               var res = native_buffer_event.write(str.to_cstring, str.length)
+               native_buffer_event.write(str.to_cstring, str.length)
        end
 
        # Write a file to the connection
@@ -175,6 +176,7 @@ end
 
 # A buffer event structure, strongly associated to a connection, an input buffer and an output_buffer
 extern class NativeBufferEvent `{ struct bufferevent * `}
+       # Write `length` bytes of `line`
        fun write(line: NativeString, length: Int): Int `{
                return bufferevent_write(recv, line, length);
        `}
@@ -205,6 +207,7 @@ extern class NativeEvBuffer `{ struct evbuffer * `}
        fun length: Int `{ return evbuffer_get_length(recv); `}
 end
 
+# An input buffer
 extern class InputNativeEvBuffer
        super NativeEvBuffer
 
@@ -212,6 +215,7 @@ extern class InputNativeEvBuffer
        fun drain(length: Int) `{ evbuffer_drain(recv, length); `}
 end
 
+# An output buffer
 extern class OutputNativeEvBuffer
        super NativeEvBuffer
 
@@ -270,6 +274,7 @@ end
 
 # Factory to listen on sockets and create new `Connection`
 class ConnectionFactory
+       # The `NativeEventBase` for the dispatch loop of this factory
        var event_base: NativeEventBase
 
        # On new connection, create the handler `Connection` object
index add43e1..3d0a0a1 100644 (file)
@@ -33,6 +33,88 @@ class MarkdownProcessor
        # `MarkdownEmitter` used for ouput.
        var emitter: MarkdownEmitter is noinit
 
+       # Work in extended mode (default).
+       #
+       # Behavior changes when using extended mode:
+       #
+       # * Lists and code blocks end a paragraph
+       #
+       #   In normal markdown the following:
+       #
+       #               This is a paragraph
+       #               * and this is not a list
+       #
+       #   Will produce:
+       #
+       #               <p>This is a paragraph
+       #               * and this is not a list</p>
+       #
+       #       When using extended mode this changes to:
+       #
+       #               <p>This is a paragraph</p>
+       #               <ul>
+       #               <li>and this is not a list</li>
+       #               </ul>
+       #
+       # * Fences code blocks
+       #
+       #   If you don't want to indent your all your code with 4 spaces,
+       #   you can wrap your code in ``` ``` ``` or `~~~`.
+       #
+       #       Here's an example:
+       #
+       #               ```
+       #               fun test do
+       #                       print "Hello World!"
+       #               end
+       #               ```
+       #
+       # * Code blocks meta
+       #
+       #   If you want to use syntax highlighting tools, most of them need to know what kind
+       #   of language they are highlighting.
+       #   You can add an optional language identifier after the fence declaration to output
+       #   it in the HTML render.
+       #
+       #               ```nit
+       #               import markdown
+       #
+       #               print "# Hello World!".md_to_html
+       #               ```
+       #
+       #   Becomes
+       #
+       #               <pre class="nit"><code>import markdown
+       #
+       #               print "Hello World!".md_to_html
+       #               </code></pre>
+       #
+       # * Underscores (Emphasis)
+       #
+       #   Underscores in the middle of a word like:
+       #
+       #               Con_cat_this
+       #
+       #       normally produces this:
+       #
+       #               <p>Con<em>cat</em>this</p>
+       #
+       #   With extended mode they don't result in emphasis.
+       #
+       #               <p>Con_cat_this</p>
+       #
+       # * Strikethrough
+       #
+       #   Like in [GFM](https://help.github.com/articles/github-flavored-markdown),
+       #   strikethrought span is marked with `~~`.
+       #
+       #               ~~Mistaken text.~~
+       #
+       #   becomes
+       #
+       #               <del>Mistaken text.</del>
+       var ext_mode = true
+
        init do self.emitter = new MarkdownEmitter(self)
 
        # Process the mardown `input` string and return the processed output.
@@ -219,12 +301,14 @@ class MarkdownProcessor
                if value[leading] == '#' then return new LineHeadline
                if value[leading] == '>' then return new LineBlockquote
 
-               if value.length - leading - trailing > 2 then
-                       if value[leading] == '`' and md.count_chars_start('`') >= 3 then
-                               return new LineFence
-                       end
-                       if value[leading] == '~' and md.count_chars_start('~') >= 3 then
-                               return new LineFence
+               if ext_mode then
+                       if value.length - leading - trailing > 2 then
+                               if value[leading] == '`' and md.count_chars_start('`') >= 3 then
+                                       return new LineFence
+                               end
+                               if value[leading] == '~' and md.count_chars_start('~') >= 3 then
+                                       return new LineFence
+                               end
                        end
                end
 
@@ -307,6 +391,14 @@ class MarkdownProcessor
                                        return new TokenEmUnderscore(pos, c)
                                end
                        end
+                       if ext_mode then
+                               if (c0.is_letter or c0.is_digit) and c0 != '_' and
+                                  (c1.is_letter or c1.is_digit) then
+                                       return new TokenNone(pos, c)
+                               else
+                                       return new TokenEmUnderscore(pos, c)
+                               end
+                       end
                        if c0 != ' ' or c1 != ' ' then
                                return new TokenEmUnderscore(pos, c)
                        else
@@ -335,13 +427,12 @@ class MarkdownProcessor
                        return new TokenHTML(pos, c)
                else if c == '&' then
                        return new TokenEntity(pos, c)
-               else if c == '^' then
-                       if c0 == '^' or c1 == '^' then
-                               return new TokenNone(pos, c)
-                       else
-                               return new TokenSuper(pos, c)
-                       end
                else
+                       if ext_mode then
+                               if c == '~' and c1 == '~' then
+                                       return new TokenStrike(pos, c)
+                               end
+                       end
                        return new TokenNone(pos, c)
                end
        end
@@ -464,9 +555,9 @@ end
 # A Link Reference.
 # Links that are specified somewhere in the mardown document to be reused as shortcuts.
 #
-# Example:
-#
-#    [1]: http://example.com/ "Optional title"
+# ~~~raw
+# [1]: http://example.com/ "Optional title"
+# ~~~
 class LinkRef
 
        # Link href
@@ -519,8 +610,10 @@ interface Decorator
        # Render a strong text.
        fun add_strong(v: MarkdownEmitter, text: Text) is abstract
 
-       # Render a super text.
-       fun add_super(v: MarkdownEmitter, text: Text) is abstract
+       # Render a strike text.
+       #
+       # Extended mode only (see `MarkdownProcessor::ext_mode`)
+       fun add_strike(v: MarkdownEmitter, text: Text) is abstract
 
        # Render a link.
        fun add_link(v: MarkdownEmitter, link: Text, name: Text, comment: nullable Text) is abstract
@@ -594,7 +687,11 @@ class HTMLDecorator
        end
 
        redef fun add_code(v, block) do
-               v.add "<pre><code>"
+               if block isa BlockFence and block.meta != null then
+                       v.add "<pre class=\"{block.meta.to_s}\"><code>"
+               else
+                       v.add "<pre><code>"
+               end
                v.emit_in block
                v.add "</code></pre>\n"
        end
@@ -635,10 +732,10 @@ class HTMLDecorator
                v.add "</strong>"
        end
 
-       redef fun add_super(v, text) do
-               v.add "<sup>"
+       redef fun add_strike(v, text) do
+               v.add "<del>"
                v.add text
-               v.add "</sup>"
+               v.add "</del>"
        end
 
        redef fun add_image(v, link, name, comment) do
@@ -1032,6 +1129,9 @@ end
 class BlockFence
        super BlockCode
 
+       # Any string found after fence token.
+       var meta: nullable Text
+
        # Fence code lines start at 0 spaces.
        redef var line_start = 0
 end
@@ -1409,10 +1509,10 @@ class LineOther
                var was_empty = line.prev_empty
                while line != null and not line.is_empty do
                        var t = v.line_kind(line)
-                       if v.in_list and t isa LineList then
+                       if (v.in_list or v.ext_mode) and t isa LineList then
                                break
                        end
-                       if t isa LineCode or t isa LineFence then
+                       if v.ext_mode and (t isa LineCode or t isa LineFence) then
                                break
                        end
                        if t isa LineHeadline or t isa LineHeadline1 or t isa LineHeadline2 or
@@ -1551,7 +1651,8 @@ class LineFence
                else
                        block = v.current_block.split(v.current_block.last_line.as(not null))
                end
-               block.kind = new BlockFence(block)
+               var meta = block.first_line.value.meta_from_fence
+               block.kind = new BlockFence(block, meta)
                block.first_line.clear
                var last = block.last_line
                if last != null and v.line_kind(last) isa LineFence then
@@ -2038,17 +2139,19 @@ class TokenEscape
        end
 end
 
-# A markdown super token.
-class TokenSuper
+# A markdown strike token.
+#
+# Extended mode only (see `MarkdownProcessor::ext_mode`)
+class TokenStrike
        super Token
 
        redef fun emit(v) do
                var tmp = v.push_buffer
-               var b = v.emit_text_until(v.current_text.as(not null), pos + 1, self)
+               var b = v.emit_text_until(v.current_text.as(not null), pos + 2, self)
                v.pop_buffer
                if b > 0 then
-                       v.decorator.add_super(v, tmp)
-                       v.current_pos = b
+                       v.decorator.add_strike(v, tmp)
+                       v.current_pos = b + 1
                else
                        v.addc char
                end
@@ -2288,6 +2391,18 @@ redef class Text
                return pos
        end
 
+       # Extract string found at end of fence opening.
+       private fun meta_from_fence: nullable Text do
+               for i in [0..chars.length[ do
+                       var c = chars[i]
+                       print c
+                       if c != ' ' and c != '`' and c != '~' then
+                               return substring_from(i).trim
+                       end
+               end
+               return null
+       end
+
        # Is `self` an unsafe HTML element?
        private fun is_html_unsafe: Bool do return html_unsafe_tags.has(self.write_to_string)
 
index dd7fd58..a8d3b9f 100644 (file)
@@ -407,6 +407,36 @@ sit amet, consectetuer adipiscing elit.</p>
                assert res == exp
        end
 
+       fun test_process_list11 do
+               var test = """
+This is a paragraph
+* and this is not a list
+"""
+               var exp = """
+<p>This is a paragraph
+* and this is not a list</p>
+"""
+               var proc = new MarkdownProcessor
+               proc.ext_mode = false
+               var res = proc.process(test).write_to_string
+               assert res == exp
+       end
+
+       fun test_process_list_ext do
+               var test = """
+This is a paragraph
+* and this is not a list
+"""
+               var exp = """
+<p>This is a paragraph</p>
+<ul>
+<li>and this is not a list</li>
+</ul>
+"""
+               var res = test.md_to_html.write_to_string
+               assert res == exp
+       end
+
        fun test_process_code1 do
                var test = """
 This is a normal paragraph:
@@ -448,7 +478,7 @@ end tell
                assert res == exp
        end
 
-       fun test_process_code3 do
+       fun test_process_code_ext1 do
                var test = """
 Here is an example of AppleScript:
 ~~~
@@ -476,7 +506,7 @@ end tell
                assert res == exp
        end
 
-       fun test_process_code4 do
+       fun test_process_code_ext2 do
                var test = """
 Here is an example of AppleScript:
 ```
@@ -504,6 +534,49 @@ end tell
                assert res == exp
        end
 
+       fun test_process_code_ext3 do
+               var proc = new MarkdownProcessor
+               proc.ext_mode = false
+
+               var test = """
+Here is an example of AppleScript:
+    beep
+"""
+               var exp = """
+<p>Here is an example of AppleScript:
+beep</p>
+"""
+               var res = proc.process(test).write_to_string
+               assert res == exp
+       end
+
+       fun test_process_code_ext4 do
+               var test = """
+Here is an example of AppleScript:
+    beep
+"""
+               var exp = """
+<p>Here is an example of AppleScript:</p>
+<pre><code>beep
+</code></pre>
+"""
+               var res = test.md_to_html.write_to_string
+               assert res == exp
+       end
+
+       fun test_process_code_ext5 do
+               var test = """
+```nit
+print "Hello World!"
+```
+"""
+               var exp = """
+<pre class="nit"><code>print "Hello World!"
+</code></pre>
+"""
+               var res = test.md_to_html.write_to_string
+               assert res == exp
+       end
 
        fun test_process_nesting1 do
                var test = """
@@ -641,6 +714,22 @@ __double underscores__
                assert res == exp
        end
 
+       fun test_process_emph3 do
+               var proc = new MarkdownProcessor
+               proc.ext_mode = false
+               var test = "Con_cat_this"
+               var exp = "<p>Con<em>cat</em>this</p>\n"
+               var res = proc.process(test).write_to_string
+               assert res == exp
+       end
+
+       fun test_process_emph_ext do
+               var test = "Con_cat_this"
+               var exp = "<p>Con_cat_this</p>\n"
+               var res = test.md_to_html.write_to_string
+               assert res == exp
+       end
+
        fun test_process_xml1 do
                var test = """
 This is a regular paragraph.
@@ -908,6 +997,23 @@ break</a> with a line-ending space.</p>
                assert res == exp
        end
 
+       fun test_process_strike do
+               var proc = new MarkdownProcessor
+               proc.ext_mode = false
+               var test = "This is how you ~~strike text~~"
+               var exp = "<p>This is how you ~~strike text~~</p>\n"
+               var res = proc.process(test).write_to_string
+               assert exp == res
+       end
+
+       fun test_process_strike_ext do
+               var test = "This is how you ~~strike text~~"
+               var exp = "<p>This is how you <del>strike text</del></p>\n"
+               var res = test.md_to_html.write_to_string
+               assert exp == res
+       end
+
+
        fun test_daring_encoding do
                var test = """
 AT&T has an ampersand in their name.
@@ -1275,6 +1381,9 @@ Here's how you put `` `backticks` `` in a code span.
        end
 
        fun test_daring_pars do
+               var proc = new MarkdownProcessor
+               proc.ext_mode = false
+
                var test = """
 In Markdown 1.0.0 and earlier. Version
 8. This line turns into a list item.
@@ -1295,7 +1404,7 @@ list item.</p>
 <p>Here's one with a bullet.
 * criminey.</p>
 """
-               var res = test.md_to_html.write_to_string
+               var res = proc.process(test).write_to_string
                assert res == exp
        end
 
@@ -2462,10 +2571,6 @@ class TestLine
                assert v.line_kind(subject) isa LineHeadline
                subject = new MDLine("    code")
                assert v.line_kind(subject) isa LineCode
-               subject = new MDLine("  ~~~")
-               assert v.line_kind(subject) isa LineFence
-               subject = new MDLine("  ```")
-               assert v.line_kind(subject) isa LineFence
                subject = new MDLine("   Title  ")
                subject.next = new MDLine("== ")
                assert v.line_kind(subject) isa LineHeadline1
@@ -2498,6 +2603,14 @@ class TestLine
                assert v.line_kind(subject) isa LineOList
        end
 
+       fun test_line_type_ext do
+               var v = new MarkdownProcessor
+               subject = new MDLine("  ~~~")
+               assert v.line_kind(subject) isa LineFence
+               subject = new MDLine("  ```")
+               assert v.line_kind(subject) isa LineFence
+       end
+
        fun test_count_chars do
                subject = new MDLine("")
                assert subject.count_chars('*') == 0
index a72b34d..9d8a819 100644 (file)
@@ -24,7 +24,7 @@
 #
 # The input event file is made of event descriptions, one event by line.
 #
-# ~~~
+# ~~~raw
 # 10 click 10.0 20.0
 # 20 quit
 # ~~~
index 725c612..87afb4a 100644 (file)
 # limitations under the License.
 
 # Impements the services of `mnit:app` using the API from the Android ndk
-module android_app
+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
index 7e474b7..fad361e 100644 (file)
@@ -84,7 +84,7 @@ interface Drawable
        # Draw image by specifying the positon of each image corners
        # Corners are in counter-clockwise order stating top left
        # a is top left, b is bottom left, c is bottom right and d is top right
-       # ~~~
+       # ~~~raw
        # a-d
        # | |
        # b-c
index bd441a1..1bcc514 100644 (file)
@@ -48,13 +48,19 @@ class MultiHashMap[K: Object, V]
                self[key] = res
                return res
        end
-
-       init do end
 end
 
 # Simple way to store an `HashMap[K1, HashMap[K2, V]]`
+#
+# ~~~~
+# var hm2 = new HashMap2[Int, String, Float]
+# hm2[1, "one"] = 1.0
+# hm2[2, "two"] = 2.0
+# assert hm2[1, "one"] == 1.0
+# assert hm2[2, "not-two"] == null
+# ~~~~
 class HashMap2[K1: Object, K2: Object, V]
-       private var level1: HashMap[K1, HashMap[K2, V]] = new HashMap[K1, HashMap[K2, V]]
+       private var level1 = new HashMap[K1, HashMap[K2, V]]
 
        # Return the value associated to the keys `k1` and `k2`.
        # Return `null` if no such a value.
@@ -83,8 +89,16 @@ class HashMap2[K1: Object, K2: Object, V]
 end
 
 # Simple way to store an `HashMap[K1, HashMap[K2, HashMap[K3, V]]]`
+#
+# ~~~~
+# var hm3 = new HashMap3[Int, String, Int, Float]
+# hm3[1, "one", 11] = 1.0
+# hm3[2, "two", 22] = 2.0
+# assert hm3[1, "one", 11] == 1.0
+# assert hm3[2, "not-two", 22] == null
+# ~~~~
 class HashMap3[K1: Object, K2: Object, K3: Object, V]
-       private var level1: HashMap[K1, HashMap2[K2, K3, V]] = new HashMap[K1, HashMap2[K2, K3, V]]
+       private var level1 = new HashMap[K1, HashMap2[K2, K3, V]]
 
        # Return the value associated to the keys `k1`, `k2`, and `k3`.
        # Return `null` if no such a value.
@@ -112,6 +126,45 @@ class HashMap3[K1: Object, K2: Object, K3: Object, V]
 end
 
 # A map with a default value.
+#
+# ~~~~
+# var dm = new DefaultMap[String, Int](10)
+# assert dm["a"] == 10
+# ~~~~
+#
+# The default value is used when the key is not present.
+# And getting a default value does not register the key.
+#
+# ~~~~
+# assert dm["a"] == 10
+# assert dm.length == 0
+# assert dm.has_key("a") == false
+# ~~~~
+#
+# It also means that removed key retrieve the default value.
+#
+# ~~~~
+# dm["a"] = 2
+# assert dm["a"] == 2
+# dm.keys.remove("a")
+# assert dm["a"] == 10
+# ~~~~
+#
+# Warning: the default value is used as is, so using mutable object might
+# cause side-effects.
+#
+# ~~~~
+# var dma = new DefaultMap[String, Array[Int]](new Array[Int])
+#
+# dma["a"].add(65)
+# assert dma["a"] == [65]
+# assert dma.default == [65]
+# assert dma["c"] == [65]
+#
+# dma["b"] += [66]
+# assert dma["b"] == [65, 66]
+# assert dma.default == [65]
+# ~~~~
 class DefaultMap[K: Object, V]
        super HashMap[K, V]
 
index 9a56b95..97c38f2 100644 (file)
@@ -21,12 +21,20 @@ import socket
 
 # Connection to a MPD server
 class MPDConnection
+
+       # Socket connection to server.
        var socket: nullable Socket = null
 
+       # Server hostname.
        var host: String
+
+       # Server port.
        var port: Int
+
+       # Server password.
        var password: nullable String
 
+       # Last occured error.
        var error: nullable String = null
 
        # Connect to the MPD server
@@ -130,6 +138,7 @@ class MPDConnection
                error = "Cannot get volume"
        end
 
+       # Set MPD server volume.
        fun volume=(vol: Int) do write_and_check("setvol {vol}\n")
 
        # Pause music playing on the MPD server
@@ -179,6 +188,7 @@ class MPDConnection
                end
        end
 
+       # Load playlist named `name`.
        fun load_playlist(name: String)
        do
                write_and_check "load \"{name}\""
@@ -187,23 +197,44 @@ end
 
 # MPD song info
 class SongInfo
+       # Song album.
        var album: String
+
+       # Song artist.
        var artist: String
+
+       # Song title.
        var title: String
+
+       # Song total duration.
        var time: Int
 end
 
 # MPD server status
 class ServerStatus
+
+       # MPD server volume.
        var volume: nullable Int
 
+       # Playback state (play/stop/pause).
        var state: String
+
+       # Is MPD server playing?
        fun playing: Bool do return state == "play"
+
+       # Is MPD server stopped?
        fun stopped: Bool do return state == "stop"
 
+       # Time elapsed within the current song.
        var elapsed: nullable Int
+
+       # TODO comment
        var time_at: nullable Int
+
+       # Total time of the current song.
        var time_total: nullable Int
+
+       # Get the cursor position on the song duration.
        fun time_ratio: nullable Float do
                if time_at == null or time_total == null then return null
                return time_at.to_f / time_total.to_f
index 20ff9af..01137f7 100644 (file)
@@ -117,32 +117,40 @@ class MPI
                # Deserialize message
                var deserializer = new JsonDeserializer(buffer)
                var deserialized = deserializer.deserialize
-               
+
                if deserialized == null then print "|{buffer}|{buffer.chars.join("-")}| {buffer.length}"
 
                return deserialized
        end
 
+       # Send an empty buffer, only for the `tag`
        fun send_empty(dest: Rank, tag: Tag, comm: Comm): SuccessOrError
        `{
                return MPI_Send(NULL, 0, MPI_CHAR, dest, tag, comm);
        `}
 
+       # Receive an empty buffer, only for the `tag`
        fun recv_empty(dest: Rank, tag: Tag, comm: Comm): SuccessOrError
        `{
                return MPI_Recv(NULL, 0, MPI_CHAR, dest, tag, comm, MPI_STATUS_IGNORE);
        `}
 
-       fun native_send(data: NativeCArray, count: Int, data_type: DataType, dest: Rank, tag: Tag, comm: Comm): SuccessOrError
+       # Send a `NativeCArray` `buffer` with a given `count` of `data_type`
+       fun native_send(buffer: NativeCArray, count: Int, data_type: DataType, dest: Rank, tag: Tag, comm: Comm): SuccessOrError
        `{
-               return MPI_Send(data, count, data_type, dest, tag, comm);
+               return MPI_Send(buffer, count, data_type, dest, tag, comm);
        `}
 
-       fun native_recv(data: NativeCArray, count: Int, data_type: DataType, dest: Rank, tag: Tag, comm: Comm, status: Status): SuccessOrError
+       # Receive into a `NativeCArray` `buffer` with a given `count` of `data_type`
+       fun native_recv(buffer: NativeCArray, count: Int, data_type: DataType, dest: Rank, tag: Tag, comm: Comm, status: Status): SuccessOrError
        `{
-               return MPI_Recv(data, count, data_type, dest, tag, comm, status);
+               return MPI_Recv(buffer, count, data_type, dest, tag, comm, status);
        `}
 
+       # Probe for the next data to receive, store the result in `status`
+       #
+       # Note: If you encounter an error where the next receive does not correspond
+       # to the last `probe`, call this method twice to ensure a correct result.
        fun probe(source: Rank, tag: Tag, comm: Comm, status: Status): SuccessOrError
        `{
                return MPI_Probe(source, tag, comm, status);
@@ -157,8 +165,13 @@ end
 
 # An MPI communicator
 extern class Comm `{ MPI_Comm `}
+       # The _null_ communicator, targeting no processors
        new null_ `{ return MPI_COMM_NULL; `}
+
+       # The _world_ communicator, targeting all processors
        new world `{ return MPI_COMM_WORLD; `}
+
+       # The _self_ communicator, targeting this processor only
        new self_ `{ return MPI_COMM_SELF; `}
 
        # Number of processors in this communicator
@@ -178,19 +191,46 @@ end
 
 # An MPI data type
 extern class DataType `{ MPI_Datatype `}
+       # Get a MPI char.
        new char `{ return MPI_CHAR; `}
+
+       # Get a MPI short.
        new short `{ return MPI_SHORT; `}
+
+       # Get a MPI int.
        new int `{ return MPI_INT; `}
+
+       # Get a MPI long.
        new long `{ return MPI_LONG; `}
+
+       # Get a MPI long long.
        new long_long `{ return MPI_LONG_LONG; `}
+
+       # Get a MPI unsigned char.
        new unsigned_char `{ return MPI_UNSIGNED_CHAR; `}
+
+       # Get a MPI unsigned short.
        new unsigned_short `{ return MPI_UNSIGNED_SHORT; `}
+
+       # Get a MPI unsigned int.
        new unsigned `{ return MPI_UNSIGNED; `}
+
+       # Get a MPI unsigned long.
        new unsigned_long `{ return MPI_UNSIGNED_LONG; `}
+
+       # Get a MPI unsigned long long.
        new unsigned_long_long `{ return MPI_UNSIGNED_LONG_LONG; `}
+
+       # Get a MPI float.
        new float `{ return MPI_FLOAT; `}
+
+       # Get a MPI double.
        new double `{ return MPI_DOUBLE; `}
+
+       # Get a MPI long double.
        new long_double `{ return MPI_LONG_DOUBLE; `}
+
+       # Get a MPI byte.
        new byte `{ return MPI_BYTE; `}
 end
 
@@ -222,21 +262,60 @@ end
 
 # An MPI operation
 #
-# Used with the `reduce` method
+# Used with the `reduce` method.
+#
+# See <http://www.mpi-forum.org/docs/mpi-1.1/mpi-11-html/node78.html>
 extern class Op `{ MPI_Op `}
+       # Get a MPI null operation.
        new op_null `{ return MPI_OP_NULL; `}
+
+       # Get a MPI maximum operation.
        new max `{ return MPI_MAX; `}
+
+       # Get a MPI minimum operation.
        new min `{ return MPI_MIN; `}
+
+       # Get a MPI sum operation.
        new sum `{ return MPI_SUM; `}
+
+       # Get a MPI product operation.
        new prod `{ return MPI_PROD; `}
+
+       # Get a MPI logical and operation.
        new land `{ return MPI_LAND; `}
+
+       # Get a MPI bit-wise and operation.
        new band `{ return MPI_BAND; `}
+
+       # Get a MPI logical or operation.
        new lor `{ return MPI_LOR; `}
+
+       # Get a MPI bit-wise or operation.
        new bor `{ return MPI_BOR; `}
+
+       # Get a MPI logical xor operation.
        new lxor `{ return MPI_LXOR; `}
+
+       # Get a MPI bit-wise xor operation.
        new bxor `{ return MPI_BXOR; `}
+
+       # Get a MPI minloc operation.
+       #
+       # Used to compute a global minimum and also an index attached
+       # to the minimum value.
+       #
+       # See <http://www.mpi-forum.org/docs/mpi-1.1/mpi-11-html/node79.html#Node79>
        new minloc `{ return MPI_MINLOC; `}
+
+       # Get a MPI maxloc operation.
+       #
+       # Used to compute a global maximum and also an index attached
+       # to the maximum value.
+       #
+       # See <http://www.mpi-forum.org/docs/mpi-1.1/mpi-11-html/node79.html#Node79>
        new maxloc `{ return MPI_MAXLOC; `}
+
+       # Get a MPI replace operation.
        new replace `{ return MPI_REPLACE; `}
 end
 
@@ -278,6 +357,7 @@ end
 
 # An MPI rank within a communcator
 extern class Rank `{ int `}
+       # Special rank accepting any processor
        new any `{ return MPI_ANY_SOURCE; `}
 
        # This Rank as an `Int`
@@ -287,6 +367,7 @@ end
 
 # An MPI tag, can be defined using `Int::tag`
 extern class Tag `{ int `}
+       # Special tag accepting any tag
        new any `{ return MPI_ANY_TAG; `}
 
        # This tag as an `Int`
diff --git a/lib/neo4j/jsonable.nit b/lib/neo4j/jsonable.nit
new file mode 100644 (file)
index 0000000..3578d59
--- /dev/null
@@ -0,0 +1,434 @@
+# 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.
+
+# Introduce base classes and services for JSON handling.
+module jsonable
+
+import standard
+private import json::json_parser
+private import json::json_lexer
+
+# Something that can be translated to JSON
+interface Jsonable
+       # Get the JSON representation of `self`
+       fun to_json: String is abstract
+end
+
+redef class String
+       super Jsonable
+
+       redef fun to_json do
+               var res = new FlatBuffer
+               res.add '\"'
+               for i in [0..self.length[ do
+                       var char = self[i]
+                       if char == '\\' then
+                               res.append("\\\\")
+                               continue
+                       else if char == '\"' then
+                               res.append("\\\"")
+                               continue
+                       else if char == '\/' then
+                               res.append("\\/")
+                               continue
+                       else if char == '\n' then
+                               res.append("\\n")
+                               continue
+                       else if char == '\r' then
+                               res.append("\\r")
+                               continue
+                       else if char == '\t' then
+                               res.append("\\t")
+                               continue
+                       end
+                       res.add char
+               end
+               res.add '\"'
+               return res.write_to_string
+       end
+end
+
+redef class Int
+       super Jsonable
+
+       redef fun to_json do return self.to_s
+end
+
+redef class Float
+       super Jsonable
+
+       redef fun to_json do return self.to_s
+end
+
+redef class Bool
+       super Jsonable
+
+       redef fun to_json do return self.to_s
+end
+
+# A JSON Object representation that behaves like a `Map`
+class JsonObject
+       super Jsonable
+       super Map[String, nullable Jsonable]
+
+       private var map = new HashMap[String, nullable Jsonable]
+
+       # Create an empty `JsonObject`
+       #
+       #     var obj = new JsonObject
+       #     assert obj.is_empty
+       init do end
+
+       # Init the JSON Object from a Nit `Map`
+       #
+       #     var map = new HashMap[String, String]
+       #     map["foo"] = "bar"
+       #     map["goo"] = "baz"
+       #     var obj = new JsonObject.from(map)
+       #     assert obj.length == 2
+       #     assert obj["foo"] == "bar"
+       #     assert obj["goo"] == "baz"
+       init from(items: Map[String, nullable Jsonable]) do
+               for k, v in items do map[k] = v
+       end
+
+       redef fun [](key) do return map[key]
+       redef fun []=(key, value) do map[key] = value
+       redef fun clear do map.clear
+       redef fun has_key(key) do return map.has_key(key)
+       redef fun is_empty do return map.is_empty
+       redef fun iterator do return map.iterator
+       redef fun keys do return map.keys
+       redef fun values do return map.values
+       redef fun length do return map.length
+
+       # Advanced query to get a value within `self` or its children.
+       #
+       # A query is composed of the keys to each object seperated by '.'.
+       #
+       # REQUIRE `self.has_key(query)`
+       #
+       #     var obj1 = new JsonObject
+       #     obj1["baz"] = "foobarbaz"
+       #     var obj2 = new JsonObject
+       #     obj2["bar"] = obj1
+       #     var obj3 = new JsonObject
+       #     obj3["foo"] = obj2
+       #     assert obj3.get("foo.bar.baz") == "foobarbaz"
+       fun get(query: String): nullable Jsonable do
+               var keys = query.split(".").reversed
+               var key = keys.pop
+
+               assert has_key(key)
+               var node = self[key]
+
+               while not keys.is_empty do
+                       key = keys.pop
+                       assert node isa JsonObject and node.has_key(key)
+                       node = node[key]
+               end
+               return node
+       end
+
+       # Create an empty `JsonObject`
+       #
+       #     var obj = new JsonObject
+       #     obj["foo"] = "bar"
+       #     assert obj.to_json == "\{\"foo\": \"bar\"\}"
+       redef fun to_json do
+               var tpl = new Array[String]
+               tpl.add "\{"
+               var vals = new Array[String]
+               for k, v in self do
+                       if v == null then
+                               vals.add "{k.to_json}: null"
+                       else
+                               vals.add "{k.to_json}: {v.to_json}"
+                       end
+               end
+               tpl.add vals.join(",")
+               tpl.add "\}"
+               return tpl.join("")
+       end
+
+       redef fun to_s do return to_json
+end
+
+# A JSON Array representation that behaves like a `Sequence`
+class JsonArray
+       super Jsonable
+       super Sequence[nullable Jsonable]
+
+       private var array = new Array[nullable Jsonable]
+
+       init do end
+
+       # init the JSON Array from a Nit `Collection`
+       init from(items: Collection[nullable Jsonable]) do
+               array.add_all(items)
+       end
+
+       redef fun [](key) do return array[key]
+       redef fun []=(key, value) do array[key] = value
+       redef fun clear do array.clear
+       redef fun insert(item, index) do array.insert(item, index)
+       redef fun is_empty do return array.is_empty
+       redef fun iterator do return array.iterator
+       redef fun length do return array.length
+       redef fun pop do return array.pop
+       redef fun push(value) do array.push(value)
+       redef fun remove_at(index) do array.remove_at(index)
+       redef fun shift do return array.shift
+       redef fun unshift(e) do array.unshift(e)
+
+       redef fun to_json do
+               var tpl = new Array[String]
+               tpl.add "["
+               var vals = new Array[String]
+               for v in self do
+                       if v == null then
+                               vals.add "null"
+                       else
+                               vals.add v.to_json
+                       end
+               end
+               tpl.add vals.join(",")
+               tpl.add "]"
+               return tpl.join("")
+       end
+
+       redef fun to_s do return to_json
+end
+
+# An error in JSON format that can be returned by tools using JSON like parsers.
+#
+#     var error = new JsonError("ErrorCode", "ErrorMessage")
+#     assert error.to_s == "ErrorCode: ErrorMessage"
+#     assert error.to_json == "\{\"error\": \"ErrorCode\", \"message\": \"ErrorMessage\"\}"
+class JsonError
+       super Jsonable
+
+       # The error code
+       var error: String
+
+       # The error message
+       var message: String
+
+       redef fun to_json do
+               var tpl = new Array[String]
+               tpl.add "\{"
+               tpl.add "\"error\": {error.to_json}, "
+               tpl.add "\"message\": {message.to_json}"
+               tpl.add "\}"
+               return tpl.join("")
+       end
+
+       redef fun to_s do return "{error}: {message}"
+end
+
+# Redef parser
+
+redef class Nvalue
+       private fun to_nit_object: nullable Jsonable is abstract
+end
+
+redef class Nvalue_number
+       redef fun to_nit_object
+       do
+               var text = n_number.text
+               if text.chars.has('.') or text.chars.has('e') or text.chars.has('E') then return text.to_f
+               return text.to_i
+       end
+end
+
+redef class Nvalue_string
+       redef fun to_nit_object do return n_string.to_nit_string
+end
+
+redef class Nvalue_true
+       redef fun to_nit_object do return true
+end
+
+redef class Nvalue_false
+       redef fun to_nit_object do return false
+end
+
+redef class Nvalue_null
+       redef fun to_nit_object do return null
+end
+
+redef class Nstring
+       # FIXME support \n, etc.
+       fun to_nit_string: String do
+               var res = new FlatBuffer
+               var skip = false
+               for i in [1..text.length-2] do
+                       if skip then
+                               skip = false
+                               continue
+                       end
+                       var char = text[i]
+                       if char == '\\' and i < text.length - 2 then
+                               if text[i + 1] == '\\' then
+                                       res.add('\\')
+                                       skip = true
+                                       continue
+                               end
+                               if text[i + 1] == '\"' then
+                                       res.add('\"')
+                                       skip = true
+                                       continue
+                               end
+                               if text[i + 1] == '/' then
+                                       res.add('\/')
+                                       skip = true
+                                       continue
+                               end
+                               if text[i + 1] == 'n' then
+                                       res.add('\n')
+                                       skip = true
+                                       continue
+                               end
+                               if text[i + 1] == 'r' then
+                                       res.add('\r')
+                                       skip = true
+                                       continue
+                               end
+                               if text[i + 1] == 't' then
+                                       res.add('\t')
+                                       skip = true
+                                       continue
+                               end
+                       end
+                       res.add char
+               end
+               return res.write_to_string
+       end
+end
+
+redef class Nvalue_object
+       redef fun to_nit_object
+       do
+               var obj = new JsonObject
+               var members = n_members
+               if members != null then
+                       var pairs = members.pairs
+                       for pair in pairs do obj[pair.name] = pair.value
+               end
+               return obj
+       end
+end
+
+redef class Nmembers
+       fun pairs: Array[Npair] is abstract
+end
+
+redef class Nmembers_tail
+       redef fun pairs
+       do
+               var arr = n_members.pairs
+               arr.add n_pair
+               return arr
+       end
+end
+
+redef class Nmembers_head
+       redef fun pairs do return [n_pair]
+end
+
+redef class Npair
+       fun name: String do return n_string.to_nit_string
+       fun value: nullable Jsonable do return n_value.to_nit_object
+end
+
+redef class Nvalue_array
+       redef fun to_nit_object
+       do
+               var arr = new JsonArray
+               var elements = n_elements
+               if elements != null then
+                       var items = elements.items
+                       for item in items do arr.add(item.to_nit_object)
+               end
+               return arr
+       end
+end
+
+redef class Nelements
+       fun items: Array[Nvalue] is abstract
+end
+
+redef class Nelements_tail
+       redef fun items
+       do
+               var items = n_elements.items
+               items.add(n_value)
+               return items
+       end
+end
+
+redef class Nelements_head
+       redef fun items do return [n_value]
+end
+
+redef class Text
+       # Parse a JSON String as Jsonable entities
+       #
+       # Example with `JsonObject`"
+       #
+       #     var obj = "\{\"foo\": \{\"bar\": true, \"goo\": [1, 2, 3]\}\}".to_jsonable
+       #     assert obj isa JsonObject
+       #     assert obj["foo"] isa JsonObject
+       #     assert obj["foo"].as(JsonObject)["bar"] == true
+       #
+       # Example with `JsonArray`
+       #
+       #     var arr = "[1, 2, 3]".to_jsonable
+       #     assert arr isa JsonArray
+       #     assert arr.length == 3
+       #     assert arr.first == 1
+       #     assert arr.last == 3
+       #
+       # Example with `String`
+       #
+       #     var str = "\"foo, bar, baz\"".to_jsonable
+       #     assert str isa String
+       #     assert str == "foo, bar, baz"
+       #
+       # Malformed JSON input returns a `JsonError` object
+       #
+       #     var bad = "\{foo: \"bar\"\}".to_jsonable
+       #     assert bad isa JsonError
+       #     assert bad.error == "JsonLexerError"
+       fun to_jsonable: nullable Jsonable
+       do
+               var lexer = new Lexer_json(to_s)
+               var parser = new Parser_json
+               var tokens = lexer.lex
+               parser.tokens.add_all(tokens)
+               var root_node = parser.parse
+               if root_node isa NStart then
+                       return root_node.n_0.to_nit_object
+               else if root_node isa NLexerError then
+                       var pos = root_node.position
+                       var msg =  "{root_node.message} at {pos or else "<unknown>"} for {root_node}"
+                       return new JsonError("JsonLexerError", msg)
+               else if root_node isa NParserError then
+                       var pos = root_node.position
+                       var msg = "{root_node.message} at {pos or else "<unknown>"} for {root_node}"
+                       return new JsonError("JsonParsingError", msg)
+               else abort
+       end
+end
+
index efe4f6a..f03e2f0 100644 (file)
@@ -124,7 +124,7 @@ class Neo4jClient
                self.cypher_url = root["cypher"].to_s
        end
 
-       fun service_root: Jsonable do return get("{base_url}/db/data")
+       fun service_root: Jsonable do return get(base_url / "db/data")
 
        # Is the connection with the Neo4j server ok?
        fun is_ok: Bool do return service_root isa JsonObject
@@ -260,7 +260,7 @@ class Neo4jClient
        #     assert nodes.has(andres)
        #     assert nodes.has(kate)
        fun nodes_with_label(lbl: String): Array[NeoNode] do
-               var res = get("{base_url}/db/data/label/{lbl}/nodes")
+               var res = get(base_url / "db/data/label/{lbl.to_percent_encoding}/nodes")
                var nodes = new Array[NeoNode]
                for json in res.as(JsonArray) do
                        var obj = json.as(JsonObject)
@@ -287,7 +287,21 @@ class Neo4jClient
        #     assert not nodes.has(kate)
        fun nodes_with_labels(labels: Array[String]): Array[NeoNode] do
                assert not labels.is_empty
-               var res = cypher(new CypherQuery.from_string("MATCH (n:{labels.join(":")}) RETURN n"))
+
+               # Build the query.
+               var buffer = new RopeBuffer
+               buffer.append "match n where \{label_0\} in labels(n)"
+               for i in [1..labels.length[ do
+                       buffer.append " and \{label_{i}\} in labels(n)"
+               end
+               buffer.append " return n"
+               var query = new CypherQuery.from_string(buffer.write_to_string)
+               for i in [0..labels.length[ do
+                       query.params["label_{i}"] = labels[i]
+               end
+
+               # Retrieve the answer.
+               var res = cypher(query)
                var nodes = new Array[NeoNode]
                for json in res.as(JsonObject)["data"].as(JsonArray) do
                        var obj = json.as(JsonArray).first.as(JsonObject)
@@ -527,7 +541,7 @@ abstract class NeoEntity
        private var internal_properties: nullable JsonObject = null
 
        private fun load_properties: JsonObject do
-               var obj = neo.get("{url.to_s}/properties").as(JsonObject)
+               var obj = neo.get(url.to_s / "properties").as(JsonObject)
                internal_properties = obj
                return obj
        end
@@ -612,7 +626,7 @@ class NeoNode
 
        private fun load_labels: Array[String] do
                var labels = new Array[String]
-               var res = neo.get("{url.to_s}/labels")
+               var res = neo.get(url.to_s / "labels")
                if res isa JsonArray then
                        for val in res do labels.add val.to_s
                end
@@ -627,7 +641,7 @@ class NeoNode
 
        private fun load_in_edges: List[NeoEdge] do
                var edges = new List[NeoEdge]
-               var res = neo.get("{url.to_s}/relationships/in").as(JsonArray)
+               var res = neo.get(url.to_s / "relationships/in").as(JsonArray)
                for obj in res do
                        edges.add(new NeoEdge.from_json(neo, obj.as(JsonObject)))
                end
@@ -642,7 +656,7 @@ class NeoNode
 
        private fun load_out_edges: List[NeoEdge] do
                var edges = new List[NeoEdge]
-               var res = neo.get("{url.to_s}/relationships/out")
+               var res = neo.get(url.to_s / "relationships/out")
                for obj in res.as(JsonArray) do
                        edges.add(new NeoEdge.from_json(neo, obj.as(JsonObject)))
                end
index 5e36142..5a226b9 100644 (file)
@@ -354,7 +354,7 @@ class OptionContext
 
        fun get_errors: Array[String]
        do
-               var errors: Array[String] = new Array[String]
+               var errors = new Array[String]
                errors.add_all(errors)
                for o in options do
                        for e in o.errors do
index 34ca522..5c42f46 100644 (file)
@@ -21,24 +21,57 @@ module ordered_tree
 #
 # Ordered tree are tree where the elements of a same parent are in a specific order
 #
-# The class can be used as it to work with generic tree.
-# The class can also be specialized to provide more specific behavior.
+# Elements of the trees are added with the `add` method that takes a parent and
+# a sub-element.
+# If the parent is `null`, then the element is considered a root.
+#
+# ~~~~
+# var t = new OrderedTree[String]
+# t.add(null, "root")
+# t.add("root", "child1")
+# t.add("root", "child2")
+# t.add("child1", "grand-child")
+# assert t.length == 4
+# ~~~~
+#
+# By default, the elements with a same parent
+# are visited in the order they are added.
+#
+# ~~~
+# assert t.to_a == ["root", "child1", "grand-child", "child2"]
+# assert t.write_to_string == """
+# root
+# |--child1
+# |  `--grand-child
+# `--child2
+# """
+# ~~~
+#
+# The `sort_with` method can be used reorder elements
+#
+# ~~~
+# t.add("root", "aaa")
+# assert t.to_a == ["root", "child1", "grand-child", "child2", "aaa"]
+# t.sort_with(alpha_comparator)
+# assert t.to_a == ["root", "aaa", "child1", "grand-child", "child2"]
+# ~~~
+#
+# This class can be used as it to work with generic trees but can also be specialized to provide more specific
+# behavior or display. It is why the internal attributes are mutable.
 class OrderedTree[E: Object]
        super Streamable
        super Collection[E]
 
-       # Sequence
+       # The roots of the tree (in sequence)
        var roots = new Array[E]
+
+       # The branches of the trees.
+       # For each element, the ordered array of its direct sub-elements.
        var sub = new HashMap[E, Array[E]]
 
-       # Add a new element `e` in the tree
+       # Add a new element `e` in the tree.
        # `p` is the parent of `e`.
        # if `p` is null, then `e` is a root element.
-       #
-       # By defauld, the elements with a same parent 
-       # are displayed in the order they are added.
-       #
-       # The `sort_with` method can be used reorder elements
        fun add(p: nullable E, e: E)
        do
                if p == null then
@@ -54,7 +87,6 @@ class OrderedTree[E: Object]
        # Write a ASCII-style tree and use the `display` method to label elements
        redef fun write_to(stream: OStream)
        do
-               var last = roots.last
                for r in roots do
                        stream.write display(r)
                        stream.write "\n"
index 31d007b..be553ad 100644 (file)
@@ -14,9 +14,8 @@
 
 # Pipelined filters and operations on iterators.
 #
-# This module enhance `Iterator`s with some methods that enable a
-# pipeline-like programing that offers the manupulation of
-# collections trough connected filters with reasonable memory constraints.
+# This module enhances `Iterator` with some methods that enable a pipeline-like programing.
+# The processing of elements in a pipeline is done trough connected filters that are implemented with reasonable memory constraints.
 module pipeline
 
 redef interface Iterator[E]
@@ -35,6 +34,8 @@ redef interface Iterator[E]
 
        # Filter: sort with a given `comparator`.
        # Important: require O(n) memory.
+       #
+       #    assert ["a", "c", "b"].iterator.sort_with(alpha_comparator).to_a  == ["a", "b", "c"]
        fun sort_with(comparator: Comparator): Iterator[E]
        do
                var a = self.to_a
index bd25a22..70b8e7c 100644 (file)
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-#
-# Targets the PNaCl platform
+
+# Provides PNaCl support for Nit.
 #
 # To use this module and compile for PNaCl, you must install the
 # NaCl SDK (This file is based on Pepper 33).
 # If NACL_SDK_ROOT is not set in your PATH, you have to work in
 # 'nacl_sdk/pepper_your_pepper_version/getting_started/your_project_folder'.
-#
-# Provides PNaCl support for Nit.
 module pnacl is platform
 
 import standard
index 9549e48..a5425dd 100644 (file)
 # Pre order sets and partial order set (ie hierarchies)
 module poset
 
-# Preorder set graph.
-# This class modelize an incremental preorder graph where new node and edges can be added (but no removal)
-# Preorder graph has two caracteristics:
+# Pre-order set graph.
+# This class models an incremental pre-order graph where new nodes and edges can be added (but not removed).
+# Pre-order graph has two characteristics:
 #  * reflexivity: an element is in relation with itself (ie `self.has(e) implies self.has_edge(e,e)`)
 #  * transitivity: `(self.has_edge(e,f) and self.has_edge(f,g)) implies self.has_edge(e,g)`
+#
+# Nodes and edges are added to the POSet.
+#
+# ~~~
+# var pos = new POSet[String]
+# pos.add_edge("A", "B") # add A->B
+# pos.add_edge("B", "C") # add B->C
+# pos.add_node("D") # add unconnected node "D"
+#
+# # A -> B -> C    D
+#
+# assert pos.has_edge("A", "B") == true  # direct
+# ~~~
+#
+# Since a poset is transitive, direct and indirect edges are considered by default.
+# Direct edges (transitive-reduction) can also be considered independently.
+#
+# ~~~
+# assert pos.has_edge("A", "C") == true  # indirect
+# assert pos.has_edge("A", "D") == false # no edge
+# assert pos.has_edge("B", "A") == false # edges are directed
+#
+# assert pos.has_direct_edge("A", "B") == true  # direct
+# assert pos.has_direct_edge("A", "C") == false # indirect
+# ~~~
+#
+# POSet are dynamic.
+# It means that the transitivity is updated while new nodes and edges are added.
+# The transitive-reduction (*direct edges*)) is also updated,
+# so adding new edges can make some direct edge to disappear.
+#
+# ~~~
+# pos.add_edge("A","D")
+# pos.add_edge("D","B")
+# pos.add_edge("A","E")
+# pos.add_edge("E","C")
+#
+# # A -> D -> B
+# # |         |
+# # v         v
+# # E ------> C
+#
+# assert pos.has_edge("D", "C") == true # new indirect edge
+# assert pos.has_edge("A", "B") == true # still an edge
+# assert pos.has_direct_edge("A", "B") == false  # but no-more a direct one
+# ~~~
+#
+# Thanks to the `[]` method, elements can be considered relatively to the poset.
+# SEE `POSetElement`
 class POSet[E: Object]
        super Collection[E]
        super Comparator
@@ -31,7 +80,7 @@ class POSet[E: Object]
        redef fun iterator do return elements.keys.iterator
 
        # All the nodes
-       private var elements: HashMap[E, POSetElement[E]] = new HashMap[E, POSetElement[E]]
+       private var elements = new HashMap[E, POSetElement[E]]
 
        redef fun has(e) do return self.elements.keys.has(e)
 
@@ -50,14 +99,15 @@ class POSet[E: Object]
        end
 
        # Return a view of `e` in the poset.
-       # This allows to asks manipulate elements in thier relation with others elements.
+       # This allows to view the elements in their relation with others elements.
        #
-       #     var poset: POSet[Something] # ...
-       #     for x in poset do
-       #         for y in poset[x].direct_greaters do
-       #             print "{x} -> {y}"
-       #         end
-       #     end
+       #     var poset = new POSet[String]
+       #     poset.add_chain(["A", "B", "D"])
+       #     poset.add_chain(["A", "C", "D"])
+       #     var a = poset["A"]
+       #     assert a.direct_greaters.has_exactly(["B", "C"])
+       #     assert a.greaters.has_exactly(["A", "B", "C", "D"])
+       #     assert a.direct_smallers.is_empty
        #
        # REQUIRE: has(e)
        fun [](e: E): POSetElement[E]
@@ -69,9 +119,18 @@ class POSet[E: Object]
        # Add an edge from `f` to `t`.
        # Because a POSet is transitive, all transitive edges are also added to the graph.
        # If the edge already exists, the this function does nothing.
+       #
+       # ~~~
+       # var pos = new POSet[String]
+       # pos.add_edge("A", "B") # add A->B
+       # assert pos.has_edge("A", "C") == false
+       # pos.add_edge("B", "C") # add B->C
+       # assert pos.has_edge("A", "C") == true
+       # ~~~
+       #
        # If a reverse edge (from `t` to `f`) already exists, a loop is created.
        #
-       # FIXME: Do somethind clever to manage loops.
+       # FIXME: Do something clever to manage loops.
        fun add_edge(f, t: E)
        do
                var fe = add_node(f)
@@ -108,8 +167,38 @@ class POSet[E: Object]
                te.dfroms.add f
        end
 
+       # Add an edge between all elements of `es` in order.
+       #
+       # ~~~~
+       # var pos = new POSet[String]
+       # pos.add_chain(["A", "B", "C", "D"])
+       # assert pos.has_direct_edge("A", "B")
+       # assert pos.has_direct_edge("B", "C")
+       # assert pos.has_direct_edge("C", "D")
+       # ~~~~
+       fun add_chain(es: SequenceRead[E])
+       do
+               if es.is_empty then return
+               var i = es.iterator
+               var e = i.item
+               i.next
+               for f in i do
+                       add_edge(e, f)
+                       e = f
+               end
+       end
+
        # Is there an edge (transitive or not) from `f` to `t`?
+       #
+       # SEE: `add_edge`
+       #
        # Since the POSet is reflexive, true is returned if `f == t`.
+       #
+       # ~~~
+       # var pos = new POSet[String]
+       # pos.add_node("A")
+       # assert pos.has_edge("A", "A") == true
+       # ~~~
        fun has_edge(f,t: E): Bool
        do
                if not elements.keys.has(f) then return false
@@ -118,6 +207,15 @@ class POSet[E: Object]
        end
 
        # Is there a direct edge from `f` to `t`?
+       #
+       # ~~~
+       # var pos = new POSet[String]
+       # pos.add_chain(["A", "B", "C"]) # add A->B->C
+       # assert pos.has_direct_edge("A", "B") == true
+       # assert pos.has_direct_edge("A", "C") == false
+       # assert pos.has_edge("A", "C")        == true
+       # ~~~
+       #
        # Note that because of loops, the result may not be the expected one.
        fun has_direct_edge(f,t: E): Bool
        do
@@ -128,21 +226,26 @@ class POSet[E: Object]
 
        # Write the POSet as a graphviz digraph.
        #
-       # Nodes are identified with their `to_s`.
+       # Nodes are labeled with their `to_s` so homonymous nodes may appear.
        # Edges are unlabeled.
        fun write_dot(f: OStream)
        do
                f.write "digraph \{\n"
+               var ids = new HashMap[E, Int]
+               for x in elements.keys do
+                       ids[x] = ids.length
+               end
                for x in elements.keys do
                        var xstr = x.to_s.escape_to_dot
-                       f.write "\"{xstr}\";\n"
+                       var nx = "n{ids[x]}"
+                       f.write "{nx}[label=\"{xstr}\"];\n"
                        var xe = self.elements[x]
                        for y in xe.dtos do
-                               var ystr = y.to_s.escape_to_dot
+                               var ny = "n{ids[y]}"
                                if self.has_edge(y,x) then
-                                       f.write "\"{xstr}\" -> \"{ystr}\"[dir=both];\n"
+                                       f.write "{nx} -> {ny}[dir=both];\n"
                                else
-                                       f.write "\"{xstr}\" -> \"{ystr}\";\n"
+                                       f.write "{nx} -> {ny};\n"
                                end
                        end
                end
@@ -156,19 +259,38 @@ class POSet[E: Object]
        fun show_dot
        do
                var f = new OProcess("dot", "-Txlib")
-               f.write "\}\n"
                write_dot(f)
                f.close
                f.wait
        end
 
        # Compare two elements in an arbitrary total order.
-       # Tis function is mainly used to sort elements of the set in an arbitrary linear extension.
-       # if a<b then return -1
-       # if a>b then return 1
+       #
+       # This function is mainly used to sort elements of the set in an coherent way.
+       #
+       # ~~~~
+       # var pos = new POSet[String]
+       # pos.add_chain(["A", "B", "C", "D", "E"])
+       # pos.add_chain(["A", "X", "C", "Y", "E"])
+       # var a = ["X", "C", "E", "A", "D"]
+       # pos.sort(a)
+       # assert a == ["E", "D", "C", "X", "A"]
+       # ~~~~
+       #
+       # POSet are not necessarily total orders because some distinct elements may be incomparable (neither greater or smaller).
+       # Therefore this method relies on arbitrary linear extension.
+       # This linear extension is a lawful total order (transitive, anti-symmetric, reflexive, and total), so can be used to compare the elements.
+       #
+       # The abstract behavior of the method is thus the following:
+       #
+       # ~~~~nitish
        # if a == b then return 0
-       # else return -1 or 1
-       # The total order is stable unless a new node or a new edge is added
+       # if has_edge(b, a) then return -1
+       # if has_edge(a, b) then return 1
+       # return -1 or 1 # according to the linear extension.
+       # ~~~~
+       #
+       # Note that the linear extension is stable, unless a new node or a new edge is added.
        redef fun compare(a, b: E): Int
        do
                var ae = self.elements[a]
@@ -203,6 +325,8 @@ class POSet[E: Object]
                return res
        end
 
+       # Filter elements to return only the greatest ones
+       #
        # ~~~
        # var s = new POSet[String]
        # s.add_edge("B", "A")
@@ -213,7 +337,6 @@ class POSet[E: Object]
        # assert s.select_greatest(["A", "B", "C"]) == ["A"]
        # assert s.select_greatest(["B", "C", "D"]) == ["B", "C"]
        # ~~~
-       # Filter elements to return only the greatest ones
        fun select_greatest(elements: Collection[E]): Array[E]
        do
                var res = new Array[E]
@@ -228,6 +351,13 @@ class POSet[E: Object]
        end
 
        # Sort a sorted array of poset elements using linearization order
+       # ~~~~
+       # var pos = new POSet[String]
+       # pos.add_chain(["A", "B", "C", "D", "E"])
+       # pos.add_chain(["A", "X", "C", "Y", "E"])
+       # var a = pos.linearize(["X", "C", "E", "A", "D"])
+       # assert a == ["E", "D", "C", "X", "A"]
+       # ~~~~
        fun linearize(elements: Collection[E]): Array[E] do
                var lin = elements.to_a
                sort(lin)
@@ -240,13 +370,15 @@ end
 #
 # For instance, one common usage is to add a specific attribute for each poset a class belong.
 #
-#     class Thing
-#         var in_some_relation: POSetElement[Thing]
-#         var in_other_relation: POSetElement[Thing]
-#     end
-#     var t: Thing # ...
-#     t.in_some_relation.greaters
-#
+# ~~~nitish
+# class Thing
+#     var in_some_relation: POSetElement[Thing]
+#     var in_other_relation: POSetElement[Thing]
+# end
+# var t: Thing
+# # ...
+# t.in_some_relation.greaters
+# ~~~
 class POSetElement[E: Object]
        # The poset self belong to
        var poset: POSet[E]
@@ -265,12 +397,24 @@ class POSetElement[E: Object]
 
        # Return the set of all elements `t` that have an edge from `element` to `t`.
        # Since the POSet is reflexive, element is included in the set.
+       #
+       # ~~~~
+       # var pos = new POSet[String]
+       # pos.add_chain(["A", "B", "C", "D"])
+       # assert pos["B"].greaters.has_exactly(["B", "C", "D"])
+       # ~~~~
        fun greaters: Collection[E]
        do
                return self.tos
        end
 
        # Return the set of all elements `t` that have a direct edge from `element` to `t`.
+       #
+       # ~~~~
+       # var pos = new POSet[String]
+       # pos.add_chain(["A", "B", "C", "D"])
+       # assert pos["B"].direct_greaters.has_exactly(["C"])
+       # ~~~~
        fun direct_greaters: Collection[E]
        do
                return self.dtos
@@ -278,30 +422,67 @@ class POSetElement[E: Object]
 
        # Return the set of all elements `f` that have an edge from `f` to `element`.
        # Since the POSet is reflexive, element is included in the set.
+       #
+       # ~~~~
+       # var pos = new POSet[String]
+       # pos.add_chain(["A", "B", "C", "D"])
+       # assert pos["C"].smallers.has_exactly(["A", "B", "C"])
+       # ~~~~
        fun smallers: Collection[E]
        do
                return self.froms
        end
 
        # Return the set of all elements `f` that have an edge from `f` to `element`.
+       #
+       # ~~~~
+       # var pos = new POSet[String]
+       # pos.add_chain(["A", "B", "C", "D"])
+       # assert pos["C"].direct_smallers.has_exactly(["B"])
+       # ~~~~
        fun direct_smallers: Collection[E]
        do
                return self.dfroms
        end
 
        # Is there an edge from `element` to `t`?
+       #
+       # ~~~~
+       # var pos = new POSet[String]
+       # pos.add_chain(["A", "B", "C", "D"])
+       # assert     pos["B"] <= "D"
+       # assert     pos["B"] <= "C"
+       # assert     pos["B"] <= "B"
+       # assert not pos["B"] <= "A"
+       # ~~~~
        fun <=(t: E): Bool
        do
                return self.tos.has(t)
        end
 
        # Is `t != element` and is there an edge from `element` to `t`?
+       #
+       # ~~~~
+       # var pos = new POSet[String]
+       # pos.add_chain(["A", "B", "C", "D"])
+       # assert     pos["B"] < "D"
+       # assert     pos["B"] < "C"
+       # assert not pos["B"] < "B"
+       # assert not pos["B"] < "A"
+       # ~~~~
        fun <(t: E): Bool
        do
                return t != self.element and self.tos.has(t)
        end
 
        # The length of the shortest path to the root of the poset hierarchy
+       #
+       # ~~~~
+       # var pos = new POSet[String]
+       # pos.add_chain(["A", "B", "C", "D"])
+       # assert pos["A"].depth == 3
+       # assert pos["D"].depth == 0
+       # ~~~~
        fun depth: Int do
                if direct_greaters.is_empty then
                        return 0
index 7a5503f..f17a28e 100644 (file)
@@ -75,8 +75,11 @@ class OptionUserAndGroup
 
        redef type VALUE: nullable UserGroup
 
-       init for_dropping_privileges do init("Drop privileges to user:group or simply user", "-u", "--usergroup")
-       init(help: String, names: String...) do super(help, null, names)
+       # Create an `OptionUserAndGroup` for dropping privileges
+       init for_dropping_privileges
+       do
+               init("Drop privileges to user:group or simply user", null, ["-u", "--usergroup"])
+       end
 
        redef fun convert(str)
        do
@@ -87,8 +90,7 @@ class OptionUserAndGroup
                        return new UserGroup(words[0], words[1])
                else
                        errors.add("Option {names.join(", ")} expected parameter in the format \"user:group\" or simply \"user\".\n")
-                       abort # FIXME only for nitc, remove and replace with next line when FFI is working in nitg
-                       #return null
+                       return null
                end
        end
 end
diff --git a/lib/pthreads/extra.nit b/lib/pthreads/extra.nit
new file mode 100644 (file)
index 0000000..416b174
--- /dev/null
@@ -0,0 +1,62 @@
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Offers some POSIX threads services that are not available on all platforms
+module extra is
+       c_compiler_option("-pthread")
+       c_linker_option("-pthread")
+end
+
+intrude import pthreads
+
+in "C" `{
+       // TODO protect with: #ifdef WITH_LIBGC
+       #ifndef ANDROID
+               #define GC_THREADS
+               #include <gc.h>
+       #endif
+`}
+
+redef extern class NativePthread
+       fun cancel: Bool `{
+               return pthread_cancel(*recv);
+       `}
+end
+
+redef class Thread
+       # Cancel the execution of the thread
+       fun cancel
+       do
+               if native == null then return
+               native.cancel
+               native = null
+       end
+end
+
+# Does not return if the running thread is to be cancelled
+fun test_cancel `{ pthread_testcancel(); `}
+
+private extern class NativePthreadBarrier in "C" `{ pthread_barrier_t * `}
+       new(count: Int) `{
+               pthread_barrier_t *barrier = malloc(sizeof(pthread_barrier_t));
+               int res = pthread_barrier_init(barrier, NULL, count);
+               return barrier;
+       `}
+
+       fun destroy `{ pthread_barrier_destroy(recv); `}
+
+       fun wait `{ pthread_barrier_wait(recv); `}
+end
index 1e76e28..bce93c4 100644 (file)
@@ -18,6 +18,7 @@
 module pthreads is
        c_compiler_option("-pthread")
        c_linker_option("-pthread")
+       pkgconfig "bdw-gc"
 end
 
 #
@@ -34,9 +35,10 @@ in "C" `{
        // TODO protect with: #ifdef WITH_LIBGC
        // We might have to add the next line to gc_chooser.c too, especially
        // if we get an error like "thread not registered with GC".
+       #ifndef ANDROID
                #define GC_THREADS
                #include <gc.h>
-       //#endif
+       #endif
 `}
 
 redef class Sys
@@ -114,17 +116,7 @@ private extern class NativePthread in "C" `{ pthread_t * `}
                return (nullable_Object)thread_return;
        `}
 
-       fun cancel: Bool `{
-               return pthread_cancel(*recv);
-       `}
-
-       fun attr: NativePthreadAttr `{
-               pthread_attr_t *pattr = malloc(sizeof(pthread_attr_t));
-               pthread_getattr_np(*recv, pattr);
-               return pattr;
-       `}
-
-       fun equal(other: NativePthread): Bool `{ pthread_equal(*recv, *other); `}
+       fun equal(other: NativePthread): Bool `{ return pthread_equal(*recv, *other); `}
 
        fun kill(signal: Int) `{ pthread_kill(*recv, signal); `}
 end
@@ -192,18 +184,6 @@ private extern class NativePthreadMutexAttr in "C" `{ pthread_mutexattr_t * `}
        # pthread_mutexattr_setrobust_np
 end
 
-private extern class NativePthreadBarrier in "C" `{ pthread_barrier_t * `}
-       new(count: Int) `{
-               pthread_barrier_t *barrier = malloc(sizeof(pthread_barrier_t));
-               int res = pthread_barrier_init(barrier, NULL, count);
-               return barrier;
-       `}
-
-       fun destroy `{ pthread_barrier_destroy(recv); `}
-
-       fun wait `{ pthread_barrier_wait(recv); `}
-end
-
 private extern class NativePthreadKey in "C" `{ pthread_key_t * `}
        new `{
                pthread_key_t *key = malloc(sizeof(pthread_key_t));
@@ -222,6 +202,27 @@ private extern class NativePthreadKey in "C" `{ pthread_key_t * `}
        `}
 end
 
+private extern class NativePthreadCond in "C" `{ pthread_cond_t * `}
+       new `{
+               pthread_cond_t cond;
+               int r = pthread_cond_init(&cond, NULL);
+               if (r == 0) {
+                       pthread_cond_t *pcond = malloc(sizeof(pthread_cond_t));
+                       memmove(pcond, &cond, sizeof(pthread_cond_t));
+                       return pcond;
+               }
+               return NULL;
+       `}
+
+       fun destroy `{ pthread_cond_destroy(recv); `}
+
+       fun signal `{ pthread_cond_signal(recv); `}
+
+       fun broadcast `{ pthread_cond_broadcast(recv);  `}
+
+       fun wait(mutex: NativePthreadMutex) `{ pthread_cond_wait(recv, mutex); `}
+end
+
 #
 ## Nity part
 #
@@ -272,14 +273,6 @@ abstract class Thread
                return r
        end
 
-       # Cancel the execution of the thread
-       fun cancel
-       do
-               if native == null then return
-               native.cancel
-               native = null
-       end
-
        redef fun finalize
        do
                if native == null then return
@@ -298,9 +291,6 @@ end
 # Exit current thread and return `value` to caller of `Thread::join`
 fun exit_thread(value: nullable Object) `{ pthread_exit(value); `}
 
-# Does not return if the running thread is to be cancelled
-fun test_cancel `{ pthread_testcancel(); `}
-
 # Returns the handle to the running `Thread`
 fun thread: Thread
 do
@@ -364,24 +354,36 @@ end
 class Barrier
        super Finalizable
 
+       private var mutex = new Mutex
+       private var cond: nullable NativePthreadCond = new NativePthreadCond
+
        # Number of threads that must be waiting for `wait` to unblock
        var count: Int
 
-       private var native: nullable NativePthreadBarrier is noinit
-
-       init do native = new NativePthreadBarrier(count)
+       private var threads_waiting = 0
 
        # Wait at this barrier and block until there are a `count` threads waiting
-       fun wait do native.wait
+       fun wait
+       do
+               mutex.lock
+               threads_waiting += 1
+               if threads_waiting == count then
+                       threads_waiting = 0
+                       cond.broadcast
+               else
+                       cond.wait(mutex.native.as(not null))
+               end
+               mutex.unlock
+       end
 
        redef fun finalize
        do
-               var native = self.native
-               if native != null then
-                       native.destroy
-                       native.free
+               var cond = self.cond
+               if cond != null then
+                       cond.destroy
+                       cond.free
                end
-               self.native = null
+               self.cond = null
        end
 end
 
index ce84faf..97f16d8 100644 (file)
@@ -30,7 +30,7 @@ import sax::attributes
 class AttributesImpl
        super Attributes
 
-       private var data: Array[String] = new Array[String]
+       private var data = new Array[String]
        redef var length: Int = 0
 
        redef fun uri(index: Int): nullable String do
index e682321..ce8682e 100644 (file)
@@ -74,8 +74,8 @@ class NamespaceSupport
        # to the `xmlns` prefix.
        var nsdecl = "http://www.w3.org/xmlns/2000/"
 
-       private var contexts: Array[Context] = new Array[Context].with_capacity(32)
-       private var current_context: Context = new Context
+       private var contexts = new Array[Context].with_capacity(32)
+       private var current_context = new Context
        private var context_position: Int = 0
 
        init do
@@ -398,38 +398,35 @@ end
 # from [SAX 2.0](http://www.saxproject.org).
 private class Context
 
-       private var empty: Collection[String] = new Array[String].with_capacity(0)
+       var empty: Collection[String] = new Array[String].with_capacity(0)
 
        # `prefix` -> `uri`
-       private var prefix_table: nullable Map[String, String] = null
+       var prefix_table: nullable Map[String, String] = null
 
        # Cache of `process_name` for elements.
        #
        # `qname -> [uri, local_name, qname]`
-       private var element_name_table: nullable Map[String, Array[String]] = null
+       var element_name_table: nullable Map[String, Array[String]] = null
 
        # Cache of `process_name` for attributes.
        #
        # `qname -> [uri, local_name, qname]`
-       private var attribute_name_table: nullable Map[String, Array[String]] = null
+       var attribute_name_table: nullable Map[String, Array[String]] = null
 
        # Namespace in absence of prefix.
-       private var default_ns: nullable String = null
+       var default_ns: nullable String = null
 
        # Can we currently declare prefixes in this context?
        var decls_ok: Bool = true is writable
 
        # All prefixes declared in this context.
-       private var declarations: nullable Array[String] = null
+       var declarations: nullable Array[String] = null
 
        # Was `copy_tables` called since the last call to `parent=`?
-       private var decl_seen: Bool = false
+       var decl_seen: Bool = false
 
        # Parent context.
-       private var p_parent: nullable Context = null
-
-       init do
-       end
+       var p_parent: nullable Context = null
 
        # (Re)set the parent of this Namespace context.
        #
@@ -649,7 +646,7 @@ private class Context
        #
        # This class is optimized for the normal case where most
        # elements do not contain Namespace declarations.
-       private fun copy_tables do
+       fun copy_tables do
                if prefix_table != null then
                        var old_prefix_table = prefix_table.as(not null)
                        prefix_table = new HashMap[String, String]
index c736a46..eb04677 100644 (file)
@@ -19,24 +19,17 @@ import sax::sax_locator
 # can use it to make a persistent snapshot of a locator at any
 # point during a document parse:
 #
-#     module example
-#     #
-#     import sax::helpers::SAXLocatorImpl
-#     import sax::ContentHandler
-#     #
+#     import sax::helpers::sax_locator_impl
+#     import sax::content_handler
+#
 #     class Example super ContentHandler
-#      private var _locator: nullable SAXLocator = null
+#      private var locator: SAXLocator
 #      private var start_loc: nullable SAXLocator = null
-#     #
-#      fun locator=(Locator locator) do
-#              # note the locator
-#              _locator = locator
-#      end
-#     #
-#      fun start_document do
+#
+#      redef fun start_document do
 #              # save the location of the start of the document
 #              # for future use.
-#              start_loc = new SAXLocatorImpl.from(locator)
+#              start_loc = new SAXLocatorImpl.with(locator)
 #      end
 #     end
 #
index 5798c33..3892e12 100644 (file)
@@ -132,7 +132,6 @@ class TestNamespaceSupport
        end
 
        fun test_prefixes do
-               var subject = sample
                var res = sample.prefixes
 
                assert 3 == res.length else
@@ -171,7 +170,6 @@ class TestNamespaceSupport
        end
 
        fun test_declared_prefixes do
-               var subject = sample
                var res = sample.declared_prefixes
 
                assert 2 == res.length else
index b3a27d8..cdf7afb 100644 (file)
@@ -41,8 +41,6 @@ module sax::input_source
 # from [SAX 2.0](http://www.saxproject.org).
 class InputSource
 
-       init do end
-
        # Create a new input source with the specified system identifier.
        #
        # Applications may use `public_id=` to include a public identifier as well,
index c158532..6f80e77 100644 (file)
@@ -275,9 +275,11 @@ interface XMLReader
        # document from a system identifier. It is the exact
        # equivalent of the following:
        #
-       #     var source = new InputSouce
-       #     source.system_id = system_id
-       #     parse(source)
+       # ~~~nitish
+       # var source = new InputSouce
+       # source.system_id = system_id
+       # parse(source)
+       # ~~~
        #
        # If the system identifier is a URL, it must be fully resolved
        # by the application before it is passed to the parser.
diff --git a/lib/saxophonit/.gitattributes b/lib/saxophonit/.gitattributes
new file mode 100644 (file)
index 0000000..a1c762f
--- /dev/null
@@ -0,0 +1 @@
+/lexer.nit     diff
index 4f77ab8..07277ef 100644 (file)
@@ -20,8 +20,14 @@ import reader_model
 # They both foward the cursor to the next byte on success, but only `expect`
 # functions fire a fatal error on mismatch.
 class XophonLexer
+
+       # The model.
        var reader_model: XophonReaderModel
+
+       # The input to read from.
        var input: IStream is writable
+
+       # Alias to `reader_model.locator`.
        private var locator: SAXLocatorImpl is noinit
 
        init do
index ff2299a..a5e1365 100644 (file)
@@ -36,6 +36,7 @@ class XophonReaderModel
        # “Namespaces in XML”.
        private var qname_re: Regex = "^[^:]+(:[^:]+)?$".to_re
 
+       # The locator that is used to indicate the current location.
        var locator: nullable SAXLocatorImpl = null is writable
 
 
index 1860db7..02e6104 100644 (file)
@@ -125,7 +125,6 @@ class XophonReader
        end
 
        redef fun parse(input: InputSource) do
-               var stream: IStream
                var system_id: nullable MaybeError[String, Error] = null
                model.locator = new SAXLocatorImpl
 
@@ -182,7 +181,6 @@ class XophonReader
 
        # Expect a `document` production.
        private fun expect_document: Bool do
-               var success = true
                var got_doctype = false
                var got_element = false
 
index b1b1efc..270ed22 100644 (file)
@@ -193,4 +193,22 @@ class TestSaxophonit
                expected.end_document
                assert_equals
        end
+
+       fun test_mixed do
+               var atts = new AttributesImpl
+
+               # TODO For the moment, ignorable white space is not detected.
+               before_test
+               parse_string("<foo>  \r\n\n<bar>  baz  </bar></foo>")
+               expected.document_locator = new SAXLocatorImpl
+               expected.start_document
+               expected.start_element("", "foo", "foo", atts)
+               expected.characters("  \n\n")
+               expected.start_element("", "bar", "bar", atts)
+               expected.characters("  baz  ")
+               expected.end_element("", "bar", "bar")
+               expected.end_element("", "foo", "foo")
+               expected.end_document
+               assert_equals
+       end
 end
index 3bedb3b..c2ace75 100644 (file)
@@ -35,8 +35,8 @@ class TestSaxEventLogger
        private var del_em: String is noinit
 
 
-       private var a: SAXEventLogger = new SAXEventLogger
-       private var b: SAXEventLogger = new SAXEventLogger
+       private var a = new SAXEventLogger
+       private var b = new SAXEventLogger
 
        private var init_done: Bool = false
 
index c940b15..a3f4b15 100644 (file)
@@ -40,7 +40,7 @@ class SAXEventLogger
        # order they fired (the oldest first). Two event loggers have equivalent
        # logs if and only if they received the same events in the same order and
        # with equivalent arguments.
-       private var log: Array[Array[String]] = new Array[Array[String]]
+       private var log = new Array[Array[String]]
 
        # http://xml.org/sax/properties/declaration-handler
        private var decl_handler: nullable DeclHandler = null
@@ -190,8 +190,6 @@ class SAXEventLogger
        # in the specified entry.
        private fun diff_append_deletion(buf: Buffer, log: Array[Array[String]],
                        entry_index: Int, sorted_mismatches: Collection[Int]) do
-               var sub_buf = new FlatBuffer
-
                buf.append(term_deletion)
                buf.append("< {entry_index}|")
                diff_append_mismatch_entry(buf, log[entry_index], sorted_mismatches,
@@ -547,10 +545,10 @@ abstract class SAXTestSuite
        super TestSuite
 
        # Logger of the expected event sequence.
-       var expected: SAXEventLogger = new SAXEventLogger
+       var expected = new SAXEventLogger
 
        # Logger of the actual event sequence.
-       var actual: SAXEventLogger = new SAXEventLogger
+       var actual = new SAXEventLogger
 
        # The tested SAX reader.
        var reader: XMLReader is noinit
index ac5a571..b01c3e5 100644 (file)
@@ -151,8 +151,8 @@ interface View
        # This method must be implemented for each specific view.
        # A traditional way of implementation is to use a double-dispatch mechanism
        #
-       # Exemple:
        #     class MyView
+       #         super View
        #         redef fun draw_sprite(s) do s.draw_on_myview(self)
        #     end
        #     redef class Sprite
index df270e4..5225f9f 100644 (file)
@@ -92,17 +92,14 @@ extern class SDLDisplay `{SDL_Surface *`}
                SDL_FillRect(recv, NULL, SDL_MapRGB(recv->format,ri,gi,bi));
        `}
 
+       # SDL events since the last call to this method
        fun events: Sequence[SDLInputEvent]
        do
-               var new_event: nullable Object = null
-               var events = new List[SDLInputEvent]
+               var events = new Array[SDLInputEvent]
                loop
-                       new_event = poll_event
-                       if new_event != null then # new_event isa Event then #
-                               events.add(new_event)
-                       else
-                               break
-                       end
+                       var new_event = poll_event
+                       if new_event == null then break
+                       events.add new_event
                end
                return events
        end
@@ -173,7 +170,7 @@ extern class SDLDrawable `{SDL_Surface*`}
        redef type I: SDLImage
 
        redef fun blit(img, x, y) do native_blit(img, x.to_i, y.to_i)
-       fun native_blit(img: I, x, y: Int) `{
+       private fun native_blit(img: I, x, y: Int) `{
                SDL_Rect dst;
                dst.x = x;
                dst.y = y;
@@ -283,6 +280,24 @@ class SDLMouseButtonEvent
        redef var pressed: Bool
        redef fun depressed: Bool do return not pressed
 
+       # Is this event raised by the left button?
+       fun is_left_button: Bool do return button == 1
+
+       # Is this event raised by the right button?
+       fun is_right_button: Bool do return button == 2
+
+       # Is this event raised by the middle button?
+       fun is_middle_button: Bool do return button == 3
+
+       # Is this event raised by the wheel going down?
+       fun is_down_wheel: Bool do return button == 4
+
+       # Is this event raised by the wheel going up?
+       fun is_up_wheel: Bool do return button == 5
+
+       # Is this event raised by the wheel?
+       fun is_wheel: Bool do return is_down_wheel or is_up_wheel
+
        init (x, y: Float, button: Int, pressed: Bool)
        do
                super(x, y)
diff --git a/lib/sdl2/README.md b/lib/sdl2/README.md
new file mode 100644 (file)
index 0000000..53bf506
--- /dev/null
@@ -0,0 +1,13 @@
+This is a low-level wrapper of the SDL 2.0 library (as `sdl2`) and SDL_image 2.0 (as `sdl2::image`).
+
+The main entry point of this project, `sdl2`, exposes some features of the base
+library: video, events, syswm, etc. The alternative entry point `sdl2::image` offers
+mainly `SDLSurface::load` to load images from PNG, JPG or TIF files.
+
+You can also import `sdl2::all` to get `sdl2` and all its sister libraries, which is only
+`sdl2::image` at this point.
+
+# Examples
+
+See the `minimal` example within this project at `examples/minimal` for a simple example
+of how to use this project.
diff --git a/lib/sdl2/all.nit b/lib/sdl2/all.nit
new file mode 100644 (file)
index 0000000..9ace922
--- /dev/null
@@ -0,0 +1,21 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Unites the main `sdl2` module and its sister library `sdl2::image`
+module all
+
+import sdl2
+import image
diff --git a/lib/sdl2/events.nit b/lib/sdl2/events.nit
new file mode 100644 (file)
index 0000000..0ad457d
--- /dev/null
@@ -0,0 +1,165 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# SDL 2 events and related services
+module events is pkgconfig "sdl2"
+
+import sdl2_base
+
+in "C Header" `{
+       #include <SDL2/SDL_events.h>
+`}
+
+# A temporary buffer for a SDL 2 event
+#
+# An instance of this class should be used to call `poll_event` and `to_event`.
+extern class SDLEventBuffer `{SDL_Event *`}
+       # Allocate memory for a new `SDLEventBuffer`
+       new malloc `{ return malloc(sizeof(SDL_Event)); `}
+
+       # Poll and event into `self`
+       #
+       # Returns `true` if an event was available.
+       fun poll_event: Bool `{ return SDL_PollEvent(recv); `}
+
+       # Get a reference to the data at `self` as a precise `SDLEvent`
+       #
+       # Returns `null` if the event is unknown.
+       #
+       # Note: The returned `SDLEvent` is just a different Nit instance pointing to the same data.
+       # A call to `poll_event` will invalidate any instances returned previously by `to_event`.
+       #
+       # TODO remove `nullable` from the return type once all cases are correctly handled.
+       fun to_event: nullable SDLEvent
+       do
+               if is_quit then return to_quit
+               if is_mouse_motion then return to_mouse_motion
+               if is_mouse_button_down then return to_mouse_button_down
+               if is_mouse_button_up then return to_mouse_button_up
+               return null
+       end
+
+       # Is this a quit event?
+       fun is_quit: Bool `{ return recv->type == SDL_QUIT; `}
+
+       # Get a reference to data at `self` as a `SDLQuitEvent`
+       fun to_quit: SDLQuitEvent `{ return recv; `}
+
+       # Is this a mouse motion event?
+       fun is_mouse_motion: Bool `{ return recv->type == SDL_MOUSEMOTION; `}
+
+       # Get a reference to data at `self` as a `SDLMouseMotionEvent`
+       fun to_mouse_motion: SDLMouseMotionEvent `{ return recv; `}
+
+       # Is this a mouse button down event?
+       fun is_mouse_button_down: Bool `{ return recv->type == SDL_MOUSEBUTTONDOWN; `}
+
+       # Get a reference to data at `self` as a `SDLMouseButtonDownEvent`
+       fun to_mouse_button_down: SDLMouseButtonDownEvent `{ return recv; `}
+
+       # Is this a mouse button up event?
+       fun is_mouse_button_up: Bool `{ return recv->type == SDL_MOUSEBUTTONUP; `}
+
+       # Get a reference to data at `self` as a `SDLMouseButtonUpEvent`
+       fun to_mouse_button_up: SDLMouseButtonUpEvent `{ return recv; `}
+
+       # TODO other SDL events:
+       #
+       # SDL_CommonEvent common
+       # SDL_WindowEvent window
+       # SDL_KeyboardEvent key
+       # SDL_TextEditingEvent edit
+       # SDL_TextInputEvent text
+       # SDL_MouseWheelEvent wheel
+       # SDL_JoyAxisEvent jaxis
+       # SDL_JoyBallEvent jball
+       # SDL_JoyHatEvent jhat;
+       # SDL_JoyButtonEvent jbutton
+       # SDL_JoyDeviceEvent jdevice
+       # SDL_ControllerAxisEvent caxis
+       # SDL_ControllerButtonEvent cbutton
+       # SDL_ControllerDeviceEvent cdevice
+       # SDL_QuitEvent quit
+       # SDL_UserEvent user
+       # SDL_SysWMEvent syswm
+       # SDL_TouchFingerEvent tfinger
+       # SDL_MultiGestureEvent mgesture
+       # SDL_DollarGestureEvent dgesture
+       # SDL_DropEvent drop
+end
+
+# An event from SDL 2
+extern class SDLEvent `{SDL_Event *`}
+end
+
+# A quit event, usually from the close window button
+extern class SDLQuitEvent
+       super SDLEvent
+end
+
+# A mouse event
+extern class SDLMouseEvent
+       super SDLEvent
+
+       # Implementation note
+       #
+       # Even if the structures are different between the mouse events, the first
+       # four fields of each events are common to all of them.
+
+       # Which mouse, pointer or finger raised this event
+       fun which: Int `{ return recv->motion.which; `}
+end
+
+# A mouse motion event
+extern class SDLMouseMotionEvent
+       super SDLMouseEvent
+
+       # X coordinate on screen of this event
+       fun x: Int `{ return recv->motion.x; `}
+
+       # Y coordinate on screen of this event
+       fun y: Int `{ return recv->motion.y; `}
+
+       # Difference on the X axis between this event and the previous one
+       fun xrel: Int `{ return recv->motion.xrel; `}
+
+       # Difference on the Y axis between this event and the previous one
+       fun yrel: Int `{ return recv->motion.yrel; `}
+end
+
+# A mouse button event
+#
+# This could as well be an abstract class. All instances of `SDLMouseButtonEvent`
+# is either a `SDLMouseButtonUpEvent` or a `SDLMouseButtonDownEvent`.
+extern class SDLMouseButtonEvent
+       super SDLMouseEvent
+
+       # X coordinate on screen of this event
+       fun x: Int `{ return recv->button.x; `}
+
+       # Y coordinate on screen of this event
+       fun y: Int `{ return recv->button.y; `}
+end
+
+# A mouse button release event
+extern class SDLMouseButtonUpEvent
+       super SDLMouseButtonEvent
+end
+
+# A mouse button click event
+extern class SDLMouseButtonDownEvent
+       super SDLMouseButtonEvent
+end
diff --git a/lib/sdl2/examples/minimal/Makefile b/lib/sdl2/examples/minimal/Makefile
new file mode 100644 (file)
index 0000000..993e0e5
--- /dev/null
@@ -0,0 +1,3 @@
+all:
+       mkdir -p bin/
+       ../../../../bin/nitg -o bin/minimal src/minimal.nit
diff --git a/lib/sdl2/examples/minimal/assets/fighter.png b/lib/sdl2/examples/minimal/assets/fighter.png
new file mode 100644 (file)
index 0000000..cf0feaa
Binary files /dev/null and b/lib/sdl2/examples/minimal/assets/fighter.png differ
diff --git a/lib/sdl2/examples/minimal/src/minimal.nit b/lib/sdl2/examples/minimal/src/minimal.nit
new file mode 100644 (file)
index 0000000..7666c10
--- /dev/null
@@ -0,0 +1,120 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# An example to test and demonstrate the `sdl2` lib with `image` and `events`
+module minimal
+
+import sdl2::all
+
+# Check for an error, then print and clear it
+#
+# Some errors are not fatal, so we ignore them at this level.
+fun check_error(loc: String)
+do
+       var error = sys.sdl.error.to_s
+       if not error.is_empty then
+               print "at {loc}: {error}"
+               sys.sdl.clear_error
+       end
+end
+
+# Init `sdl2`, including video and events
+sys.sdl.initialize((new SDLInitFlags).video)
+check_error "init"
+
+# Init `sdl2::image`
+sdl.img.initialize((new SDLImgInitFlags).png)
+check_error "img_init"
+
+# Create a window
+var window = new SDLWindow("Window title!".to_cstring, 800, 600, (new SDLWindowFlags).opengl)
+check_error "window"
+
+# Create a render, the suffested one
+var renderer = new SDLRenderer(window, -1, (new SDLRendererFlags).accelerated)
+check_error "renderer"
+
+# Load an image
+var surface = new SDLSurface.load("assets/fighter.png".to_cstring)
+check_error "surface"
+assert not surface.address_is_null
+
+# Alternative code to load a BMP image without `sdl2::image`
+#
+# var surface = new SDLSurface.load_bmp("assets/fighter.bmp".to_cstring)
+
+# Set the window icon
+window.icon = surface
+check_error "icon"
+
+# Get a texture out of that surface
+var texture = new SDLTexture.from_surface(renderer, surface)
+check_error "texture"
+
+# Allocate memory for reusable objects
+var event = new SDLEventBuffer.malloc
+var src = new SDLRect.nil
+var dst = new SDLRect(0, 0, 128, 128)
+
+# Set the colors we will be using
+var white = new SDLColor(255, 255, 255, 255)
+var green = new SDLColor(  0, 255,   0, 255)
+var spacy = new SDLColor( 25,  25,  50, 255)
+
+loop
+       # Loop over events until we get a quit event
+       while event.poll_event do
+               var higher_event = event.to_event
+               if higher_event isa SDLQuitEvent then
+                       break label out
+               else if higher_event isa SDLMouseButtonDownEvent then
+                       # Update `dst` to be centered on the latest click
+                       dst.x = higher_event.x - dst.w/2
+                       dst.y = higher_event.y - dst.h/2
+               end
+       end
+
+       # Clear the screen with a spacy color
+       renderer.draw_color = spacy
+       renderer.clear
+
+       # Draw the target box for the following `copy`
+       renderer.draw_color = green
+       renderer.draw_rect dst
+
+       # Copy a texture to the screen
+       renderer.draw_color = white
+       renderer.copy(texture, src, dst)
+
+       # Copy the back buffer to the screen
+       renderer.present
+
+       check_error "present"
+
+       33.delay
+end label out
+
+# Free all resources
+event.free
+src.free
+dst.free
+
+texture.free
+surface.free
+
+window.destroy
+sdl.img.quit
+sys.sdl.quit
diff --git a/lib/sdl2/image.nit b/lib/sdl2/image.nit
new file mode 100644 (file)
index 0000000..6dc53b3
--- /dev/null
@@ -0,0 +1,78 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Services of the SDL_image 2.0 library
+#
+# Offers `SDLSurface::load` which supports more image formats than `sdl2::sdl2`
+# alone: JPG, PNG, TIF, GIT, ICO and much more.
+module image is
+       pkgconfig "sdl2"
+       c_linker_option "-lSDL2_image"
+end
+
+import sdl2
+
+in "C" `{
+       #include <SDL2/SDL_image.h>
+`}
+
+redef class SDL
+       # Access to the global methods of `sdl2::image`
+       var img = new IMG is lazy
+end
+
+# Holds the global methods of `sdl2::image`
+class IMG
+       # Get the `IMG` singleton
+       new do return once new IMG.internal
+
+       # TODO make this private and only called through `sys.sdl.img`
+       init internal do end
+
+       # Initialize the image library
+       fun initialize(flags: SDLImgInitFlags): SDLImgInitFlags `{
+               return IMG_Init(flags);
+       `}
+
+       # Finalize and clean up the image library
+       fun quit `{ IMG_Quit(); `}
+
+       # Get the latest image library error
+       fun error: NativeString `{ return (char*)IMG_GetError(); `}
+end
+
+redef extern class SDLSurface
+       # Load the image at `path` inferring its type from the file extension
+       new load(path: NativeString) `{ return IMG_Load(path); `}
+end
+
+# Flags from `sys.sdl.img.initialize`
+extern class SDLImgInitFlags `{ int `}
+       # Get the default empty flag set
+       new `{ return 0; `}
+
+       # Add the JPG support to this flag set
+       fun jpg: SDLImgInitFlags `{ return recv | IMG_INIT_JPG; `}
+
+       # Add the PNG support to this flag set
+       fun png: SDLImgInitFlags `{ return recv | IMG_INIT_PNG; `}
+
+       # Add the TIF support to this flag set
+       fun tif: SDLImgInitFlags `{ return recv | IMG_INIT_TIF; `}
+
+       # Add the WEBP support to this flag set
+       fun webp: SDLImgInitFlags `{ return recv | IMG_INIT_WEBP; `}
+end
diff --git a/lib/sdl2/sdl2.nit b/lib/sdl2/sdl2.nit
new file mode 100644 (file)
index 0000000..7455b97
--- /dev/null
@@ -0,0 +1,22 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Simple DirectMedia Layer (SDL) 2.0 services for easy window creation and 2D drawing
+module sdl2
+
+import sdl2_base
+import events
+import syswm
diff --git a/lib/sdl2/sdl2_base.nit b/lib/sdl2/sdl2_base.nit
new file mode 100644 (file)
index 0000000..ee129d7
--- /dev/null
@@ -0,0 +1,536 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Basic SDL 2 features
+module sdl2_base is pkgconfig "sdl2"
+
+in "C header" `{
+       #include <SDL2/SDL.h>
+`}
+
+redef class Sys
+       # Access to the global methods of `sdl2`
+       var sdl = new SDL is lazy
+end
+
+# Holds the global methods of `sdl2`
+class SDL
+       super Finalizable
+
+       # Get the `SDL` singleton
+       new do return once new SDL.internal
+
+       # TODO make this private and only called through `sys.sdl`
+       init internal do end
+
+       # Initialize the given SDL `subsystems`
+       fun initialize(subsystems: SDLInitFlags): Bool `{ return SDL_Init(subsystems); `}
+
+       # Returns the latest SDL error
+       #
+       # After calling this method, you should also call `clear_error`.
+       fun error: NativeString `{ return (char*)SDL_GetError(); `}
+
+       # Clear the SDL error
+       fun clear_error `{ SDL_ClearError(); `}
+
+       # Quit SDL
+       fun quit `{ SDL_Quit(); `}
+
+       # Was SDL initialized?
+       fun was_initialized: Bool do return not initialized_subsystems((new SDLInitFlags).everything).is_empty
+
+       # What SDL subsystems are initialized? You can use a mask of `subsystems` to restrict the query.
+       #
+       # Returns the flags of the initialized subsystems.
+       fun initialized_subsystems(subsystems: SDLInitFlags): SDLInitFlags `{ return SDL_WasInit(subsystems); `}
+
+       # The number of CPU on the system
+       fun cpu_count: Int `{ return SDL_GetCPUCount(); `}
+
+       # Amount of RAM configured on the system
+       fun system_ram: Int `{ return SDL_GetSystemRAM(); `}
+
+       # Show a simple message box
+       fun show_simple_message_box(level: SDLMessageBoxFlags, title, content: NativeString) `{
+               SDL_ShowSimpleMessageBox(level, title, content, NULL);
+       `}
+
+       redef fun finalize do if was_initialized then quit
+
+       # Function that should be called from the SDL main method
+       #
+       # This method should not normally be used, refer to the SDL source code
+       # before use.
+       fun set_main_ready `{ SDL_SetMainReady(); `}
+end
+
+# Flags for `sys.sdl.initialize` and related methods
+extern class SDLInitFlags `{ Uint32 `}
+       # Get the default empty flag set
+       new `{ return 0; `}
+
+       # Add the timer subsystem
+       fun timer: SDLInitFlags `{ return recv | SDL_INIT_TIMER; `}
+
+       # Add the audio subsystem
+       fun audio: SDLInitFlags `{ return recv | SDL_INIT_AUDIO; `}
+
+       # Add the video subsystem
+       fun video: SDLInitFlags `{ return recv | SDL_INIT_VIDEO; `}
+
+       # Add the joystick subsystem
+       #
+       # Implied by `gamecontroller`
+       fun joystick: SDLInitFlags `{ return recv | SDL_INIT_JOYSTICK; `}
+
+       # Add the haptic subsystem
+       fun haptic: SDLInitFlags `{ return recv | SDL_INIT_HAPTIC; `}
+
+       # Add the gamecontroller subsystem
+       fun gamecontroller: SDLInitFlags `{ return recv | SDL_INIT_GAMECONTROLLER; `}
+
+       # Add the events subsystem
+       #
+       # Implied by `video` and `joystick`
+       fun events: SDLInitFlags `{ return recv | SDL_INIT_EVENTS; `}
+
+       # Add all subsystems
+       fun everything: SDLInitFlags `{ return recv | SDL_INIT_EVERYTHING; `}
+
+       # Is this flag set empty?
+       fun is_empty: Bool `{ return recv == 0; `}
+
+       # TODO add all other is_
+end
+
+# A window created by SDL
+extern class SDLWindow `{ SDL_Window * `}
+       # Create a window with the given `title`, `width` and `height`, also apply the `flags`
+       new (title: NativeString, width, height: Int, flags: SDLWindowFlags) `{
+               return SDL_CreateWindow(title,
+                       SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
+                       width, height, flags);
+       `}
+
+       # Has this window been correctly initialized?
+       fun initialized: Bool do return not address_is_null
+
+       # Destroy this window
+       fun destroy `{ SDL_DestroyWindow(recv); `}
+
+       # Get the `SDLWindowFlags` describing the status of the window
+       fun flags: SDLWindowFlags `{ return SDL_GetWindowFlags(recv); `}
+
+       # Show a simple message box
+       #
+       # Similar to `sys.sdl.show_simple_message_box` but attached to this window
+       fun show_simple_message_box(level: SDLMessageBoxFlags, title, content: NativeString) `{
+               SDL_ShowSimpleMessageBox(level, title, content, recv);
+       `}
+
+       # Set the icon of this window
+       fun icon=(icon: SDLSurface) `{ SDL_SetWindowIcon(recv, icon); `}
+end
+
+# Flags for `SDLWindow::new` and returned by `SDLWindow::flags`
+extern class SDLWindowFlags `{ Uint32 `}
+       # Get the default empty flag set
+       new `{ return 0; `}
+
+       # Add the flag requesting a fullscreen window
+       fun fullscreen: SDLWindowFlags `{ return recv | SDL_WINDOW_FULLSCREEN; `}
+
+       # Add the flag requesting a fullscreen window for the current desktop
+       fun fullscreen_desktop: SDLWindowFlags `{ return recv | SDL_WINDOW_FULLSCREEN_DESKTOP; `}
+
+       # Add the flag requesting a window usable with an OpenGL context
+       fun opengl: SDLWindowFlags `{ return recv | SDL_WINDOW_OPENGL; `}
+
+       # Add the flag requesting a hidden window
+       fun hidden: SDLWindowFlags `{ return recv | SDL_WINDOW_HIDDEN; `}
+
+       # Add the flag requesting a borderless window
+       fun borderless: SDLWindowFlags `{ return recv | SDL_WINDOW_BORDERLESS; `}
+
+       # Add the flag requesting a resizable window
+       fun resizable: SDLWindowFlags `{ return recv | SDL_WINDOW_RESIZABLE; `}
+
+       # Add the flag requesting a minimized window
+       fun minimized: SDLWindowFlags `{ return recv | SDL_WINDOW_MINIMIZED; `}
+
+       # Add the flag requesting a maximimez window
+       fun maximized: SDLWindowFlags `{ return recv | SDL_WINDOW_MAXIMIZED; `}
+
+       # Add the flag to grab the input focus
+       fun input_grabbed: SDLWindowFlags `{ return recv | SDL_WINDOW_INPUT_GRABBED; `}
+
+       # Add the flag to request a window using the system High-DPI mode
+       fun allow_highdpi: SDLWindowFlags `{
+               #if SDL_VERSION_ATLEAST(2, 0, 2)
+                       return recv | SDL_WINDOW_ALLOW_HIGHDPI;
+               #else
+                       return recv;
+               #endif
+       `}
+
+       # Is the window shown?
+       #
+       # Can only be queried because it is ignored by `SDLWindow::new`
+       fun is_shown: Bool `{ return recv & SDL_WINDOW_SHOWN; `}
+
+       # Does the window has the input focus?
+       #
+       # Can only be queried because it is ignored by `SDLWindow::new`
+       fun has_input_focus: Bool `{ return recv & SDL_WINDOW_INPUT_FOCUS; `}
+
+       # Does the window has the mouse focus?
+       #
+       # Can only be queried because it is ignored by `SDLWindow::new`
+       fun has_mouse_focus: Bool `{ return recv & SDL_WINDOW_MOUSE_FOCUS; `}
+
+       # TODO add all other `is_` methods, as needed
+end
+
+redef universal Int
+       # Suspend execution for `recv` milliseconds
+       fun delay `{ SDL_Delay(recv); `}
+end
+
+# A renderer, maybe software or hardware
+extern class SDLRenderer `{ SDL_Renderer * `}
+       # Create a new `SDLRenderer` for the `window` using the `index`th renderer according to `flags`
+       #
+       # Use an `index` of `-1` to get the default renderer for the given flags.
+       new (window: SDLWindow, index: Int, flags: SDLRendererFlags) `{
+               return SDL_CreateRenderer(window, index, flags);
+       `}
+
+       # Create a new software `SDLRenderer`
+       new software(surface: SDLSurface) `{
+               return SDL_CreateSoftwareRenderer(surface);
+       `}
+
+       # Destroy this renderer
+       fun destroy `{ SDL_DestroyRenderer(recv); `}
+
+       # Clear the rendering target with the current `draw_color`
+       fun clear `{ SDL_RenderClear(recv); `}
+
+       # Copy the rectangle at `src` from `texture` to fill the `dst` at the rendering `target`
+       #
+       # If `dst` has a different size than `src`, the image will be stretched.
+       #
+       # If `src == null` the whole source texture will be drawn, and if
+       # `dst == null` then the texture will fill the rendering `target`.
+       fun copy(texture: SDLTexture, src, dst: nullable SDLRect)
+       do
+               if src == null then src = new SDLRect.nil
+               if dst == null then dst = new SDLRect.nil
+
+               native_copy(texture, src, dst)
+       end
+
+       private fun native_copy(texture: SDLTexture, src, dst: SDLRect) `{
+               SDL_RenderCopy(recv, texture, src, dst);
+       `}
+
+       # Update the screen with all rendering since the previous call
+       fun present `{ SDL_RenderPresent(recv); `}
+
+       # Get the `SDLRendererInfo` for this renderer
+       fun info_copy(out: SDLRendererInfo) `{ SDL_GetRendererInfo(recv, out); `}
+
+       # Set the drawing color
+       fun draw_color=(val: SDLColor) `{
+               SDL_SetRenderDrawColor(recv, val->r, val->g, val->b, val->a);
+       `}
+
+       # Get the drawing color of this renderer
+       #
+       # The returned `SDLColor` is malloced here and must be freed by the called.
+       # For a more efficient usage, it is recommended to use instead `draw_color_copy`.
+       fun draw_color: SDLColor
+       do
+               var color = new SDLColor.malloc
+               draw_color_copy color
+               return color
+       end
+
+       # Copy the drawing color of this renderer in `color`
+       fun draw_color_copy(color: SDLColor) `{
+               SDL_GetRenderDrawColor(recv, &color->r, &color->g, &color->b, &color->a);
+       `}
+
+       # Fill a rectangle with the current `draw_color`
+       #
+       # If `rect.address_is_null` then fills the entire screen.
+       fun fill_rect(rect: SDLRect) `{ SDL_RenderFillRect(recv, rect); `}
+
+       # Draw a rectangle with the current `draw_color`
+       fun draw_rect(rect: SDLRect) `{ SDL_RenderDrawRect(recv, rect); `}
+
+       # Draw a point with the current `draw_color`
+       fun draw_point(x, y: Int) `{ SDL_RenderDrawPoint(recv, x, y); `}
+
+       # Draw a line with the current `draw_color`
+       fun draw_line(x1, y1, x2, y2: Int) `{ SDL_RenderDrawLine(recv, x1, y1, x2, y2); `}
+
+       # Set the viewport of this renderer
+       fun viewport=(rect: SDLRect) `{ SDL_RenderSetViewport(recv, rect); `}
+
+       # Get the rendering target of this renderer
+       fun target: SDLTexture `{ return SDL_GetRenderTarget(recv); `}
+
+       # Set the rendering target of this renderer
+       fun target=(val: SDLTexture) `{ SDL_SetRenderTarget(recv, val); `}
+
+       # TODO add other renderer related methods:
+       #
+       # draw_rects
+       # draw_lines
+end
+
+# A color
+extern class SDLColor `{ SDL_Color *`}
+       # Allocate the memory for a new `SDLColor`, it must then be freed with `free`
+       new malloc `{ return malloc(sizeof(SDL_Color)); `}
+
+       # Allocate the memory for a new `SDLColor` and fill it with `r`, `g`, `b` and `a`
+       #
+       # As with `malloc`, the new instances must then be freed with `free`.
+       new (r, g, b, a: Int)
+       do
+               var color = new SDLColor.malloc
+               color.set(r, g, b, a)
+               return color
+       end
+
+       # Set this instance's `r`, `g`, `b` and `a`
+       fun set(r, g, b, a: Int)
+       do
+               self.r = r
+               self.g = g
+               self.b = b
+               self.a = a
+       end
+
+       # The red component of this color `[0..255]`
+       fun r: Int `{ return recv->r; `}
+
+       # Set the red component of this color `[0..255]`
+       fun r=(val: Int) `{ recv->r = val; `}
+
+       # The green component of this color `[0..255]`
+       fun g: Int `{ return recv->g; `}
+
+       # Set the green component of this color `[0..255]`
+       fun g=(val: Int) `{ recv->g = val; `}
+
+       # The blue component of this color `[0..255]`
+       fun b: Int `{ return recv->b; `}
+
+       # Set the blue component of this color `[0..255]`
+       fun b=(val: Int) `{ recv->b = val; `}
+
+       # The alpha component of this color `[0..255]`
+       fun a: Int `{ return recv->a; `}
+
+       # Set the ralpha component of this color `[0..255]`
+       fun a=(val: Int) `{ recv->a = val; `}
+
+       # TODO implement the related `SDL_Palette` and related methods
+end
+
+# Flags for `SDLRenderer::new`
+extern class SDLRendererFlags `{ Uint32 `}
+       # Get the default empty flag set
+       new `{ return 0; `}
+
+       # Add the flag to request a software renderer
+       fun software: SDLRendererFlags `{ return recv | SDL_RENDERER_SOFTWARE; `}
+
+       # Add the flag to request an accelerated renderer
+       #
+       # This is the default option.
+       fun accelerated: SDLRendererFlags `{ return recv | SDL_RENDERER_ACCELERATED; `}
+
+       # Add the flag to request a renderer where `SDLRenderer::present` is synchronized with the refresh rate
+       fun presentvsync: SDLRendererFlags `{ return recv | SDL_RENDERER_PRESENTVSYNC; `}
+
+       # Add the flag to request a renderer able to render to a texture
+       fun targettexture: SDLRendererFlags `{ return recv | SDL_RENDERER_TARGETTEXTURE; `}
+end
+
+# A bitmap surface
+extern class SDLSurface `{ SDL_Surface * `}
+
+       # Load the BMP file at `path`
+       new load_bmp(path: NativeString) `{ return SDL_LoadBMP(path); `}
+
+       redef fun free `{ SDL_FreeSurface(recv); `}
+
+       # Save this texture to a BMP file
+       fun save_bmp(path: NativeString) `{ SDL_SaveBMP(recv, path); `}
+end
+
+# A loaded bitmap texture
+extern class SDLTexture `{ SDL_Texture * `}
+       # Get a `SDLTexture` from a `surface`, for a given `renderer`
+       new from_surface(renderer: SDLRenderer, surface: SDLSurface) `{
+               return SDL_CreateTextureFromSurface(renderer, surface);
+       `}
+
+       # Destroy this texture
+       fun destroy `{ SDL_DestroyTexture(recv); `}
+
+       # Width of this texture
+       fun width: Int `{
+               int val;
+               SDL_QueryTexture(recv, NULL, NULL, &val, NULL);
+               return val;
+       `}
+
+       # Height of this texture
+       fun height: Int `{
+               int val;
+               SDL_QueryTexture(recv, NULL, NULL, NULL, &val);
+               return val;
+       `}
+
+       # TODO other queries: format and access
+end
+
+# A rectangle
+extern class SDLRect `{SDL_Rect *`}
+       # Get a null rectangle (on the C side), should be used only internally
+       new nil `{ return NULL; `}
+
+       # Allocate the memory for a new `SDLRect`, it must then be freed with `free`
+       new malloc`{ return malloc(sizeof(SDL_Rect)); `}
+
+       # Allocate the memory for a new `SDLRect` and fill it with `x`, `y`, `w` and `h`
+       #
+       # As with `malloc`, the new instances must then be freed with `free`.
+       new (x, y, w, h: Int)
+       do
+               var rect = new SDLRect.malloc
+               rect.set(x, y, w, h)
+               return rect
+       end
+
+       # Set this instance's `x`, `y`, `w` and `h`
+       fun set(x, y, w, h: Int)
+       do
+               self.x = x
+               self.y = y
+               self.w = w
+               self.h = h
+       end
+
+       # X coordinate of the top left corner
+       fun x: Int `{ return recv->x; `}
+
+       # Set the X coordinate of the top left corner
+       fun x=(val: Int) `{ recv->x = val; `}
+
+       # Y coordinate of the top left corner
+       fun y: Int `{ return recv->y; `}
+
+       # Set the Y coordinate of the top left corner
+       fun y=(val: Int) `{ recv->y = val; `}
+
+       # Width of this rectangle
+       fun w: Int `{ return recv->w; `}
+
+       # Set the width of this rectangle
+       fun w=(val: Int) `{ recv->w = val; `}
+
+       # Height of this rectangle
+       fun h: Int `{ return recv->h; `}
+
+       # Set the height of this rectangle
+       fun h=(val: Int) `{ recv->h = val; `}
+
+       # TODO implement other `SDLRect` related methods:
+       #
+       # SDL_EnclosePoints
+       # SDL_HasIntersection
+       # SDL_IntersectRect
+       # SDL_IntersectRectAndLine
+       # SDL_PointInRect
+       # SDL_RectEmpty
+       # SDL_RectEquals
+       # SDL_UnionRect
+end
+
+# A point with `x` and `y`
+extern class SDLPoint `{SDL_Point *`}
+       # Get a null rectangle (on the C side), should be used only internally
+       new nil `{ return NULL; `}
+
+       # Allocate the memory for a new `SDLPoint`, it must the be freed with `free`
+       new malloc`{ return malloc(sizeof(SDL_Point)); `}
+
+       # Allocate the memory for a new `SDLPoint` and fill it with `x` and `y`
+       #
+       # As with `malloc`, the new instances must the be freed with `free`.
+       new (x, y: Int) do
+               var point = new SDLPoint.malloc
+               point.x = x
+               point.y = y
+               return point
+       end
+
+       # X coordinate of this point
+       fun x: Int `{ return recv->x; `}
+
+       # Set the X coordinate of this point
+       fun x=(val: Int) `{ recv->x = val; `}
+
+       # Y coordinate of this point
+       fun y: Int `{ return recv->y; `}
+
+       # Set the Y coordinate of this point
+       fun y=(val: Int) `{ recv->y = val; `}
+end
+
+# Flag to set the icon in `sys.sdl.show_simple_message_box` and `SDLWindow::show_simple_message_box`
+extern class SDLMessageBoxFlags `{  Uint32 `}
+       # Request the error icon
+       new error `{ return SDL_MESSAGEBOX_ERROR; `}
+
+       # Request the warning icon
+       new warning `{ return SDL_MESSAGEBOX_WARNING; `}
+
+       # Request the information icon
+       new information `{ return SDL_MESSAGEBOX_INFORMATION; `}
+end
+
+# Information on a `SDLRenderer`
+extern class SDLRendererInfo `{ SDL_RendererInfo * `}
+       # Allocate the memory for a new `SDLRenderer`, it must then be freed with `free`
+       new malloc `{ return malloc(sizeof(SDL_RendererInfo)); `}
+
+       # Name of the renderer's driver
+       fun name: NativeString `{ return (char*)recv->name; `}
+
+       # Maximum texture width supported by the renderer
+       fun max_texture_width: Int `{ return recv->max_texture_width; `}
+
+       # Maximum texture height supported by the renderer
+       fun max_texture_height: Int `{ return recv->max_texture_height; `}
+end
diff --git a/lib/sdl2/syswm.nit b/lib/sdl2/syswm.nit
new file mode 100644 (file)
index 0000000..97ec28a
--- /dev/null
@@ -0,0 +1,108 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Window manager related SDL 2 services
+module syswm is pkgconfig "sdl2"
+
+import sdl2_base
+
+in "C Header" `{
+       #include <SDL2/SDL_syswm.h>
+`}
+
+redef extern class SDLWindow
+       # Get the `SDLSysVMInfo` for the system running this window
+       #
+       # The returned value must be freed.
+       fun wm_info: SDLSysWMInfo `{
+               SDL_SysWMinfo *val = malloc(sizeof(SDL_SysWMinfo));
+
+               SDL_VERSION(&val->version);
+
+               if(SDL_GetWindowWMInfo(recv, val) <= 0) {
+                       free(val);
+                       return NULL;
+               }
+
+               return val;
+       `}
+end
+
+# Information on the window manager
+#
+# Created using `SDLWindow::vm_info`
+extern class SDLSysWMInfo `{ SDL_SysWMinfo * `}
+       # Is this an unknown window manager?
+       fun is_unknown: Bool `{ return recv->subsystem == SDL_SYSWM_UNKNOWN; `}
+
+       # Is this a Windows system?
+       fun is_windows: Bool `{ return recv->subsystem == SDL_SYSWM_WINDOWS; `}
+
+       # Is this the X11 window manager?
+       fun is_x11: Bool `{ return recv->subsystem == SDL_SYSWM_X11; `}
+
+       # Is this a direct DirectFB?
+       fun is_direcfb: Bool `{ return recv->subsystem == SDL_SYSWM_DIRECTFB; `}
+
+       # Is this system an OS X?
+       fun is_cocoa: Bool `{ return recv->subsystem == SDL_SYSWM_COCOA; `}
+
+       # Is this system an iOS?
+       fun is_uikit: Bool `{ return recv->subsystem == SDL_SYSWM_UIKIT; `}
+
+       # It this window manager Wayland?
+       fun is_wayland: Bool `{
+               #if SDL_VERSION_ATLEAST(2, 0, 2)
+                       return recv->subsystem == SDL_SYSWM_WAYLAND;
+               #else
+                       return 0;
+               #endif
+       `}
+
+       # It this window manager Mir?
+       fun is_mir: Bool `{
+               #if SDL_VERSION_ATLEAST(2, 0, 3)
+                       return recv->subsystem == SDL_SYSWM_MIR;
+               #else
+                       return 0;
+               #endif
+       `}
+
+       # Is this system a Windows RT?
+       fun is_winrt: Bool `{
+               #if SDL_VERSION_ATLEAST(2, 0, 3)
+                       return recv->subsystem == SDL_SYSWM_WINRT;
+               #else
+                       return 0;
+               #endif
+       `}
+
+       # Is this system an Android?
+       fun is_android: Bool `{
+               #if SDL_VERSION_ATLEAST(2, 0, 4)
+                       return recv->subsystem == SDL_SYSWM_ANDROID;
+               #else
+                       return 0;
+               #endif
+       `}
+
+       # Returns the handle of this window on a X11 window system
+       #
+       # Require: `is_x11`
+       fun x11_window_handle: Pointer `{
+               return (void*)recv->info.x11.window;
+       `}
+end
index f1044e8..f9709da 100644 (file)
@@ -47,7 +47,7 @@
 # r.handle_signal(sigint, true)
 # r.handle_signal(sigalarm, true)
 #
-# Ask system to receive a `sigalarm` signal in 1 second
+# # Ask system to receive a `sigalarm` signal in 1 second
 # set_alarm(1)
 #
 # loop
index 05cbed0..23b1ef7 100644 (file)
@@ -114,8 +114,6 @@ end
 class Statement
        private var native_statement: NativeStatement
 
-       private init(ns: NativeStatement) do self.native_statement = ns
-
        # Is this statement usable?
        var is_open = true
 
@@ -134,12 +132,11 @@ class Statement
        end
 end
 
+# A row from a `Statement`
 class StatementRow
        # Statement linked to `self`
        var statement: Statement
 
-       private init(s: Statement) do self.statement = s
-
        # Number of entries in this row
        #
        # require: `self.statement.is_open`
@@ -161,12 +158,6 @@ class StatementEntry
 
        private var index: Int
 
-       private init(s: Statement, i: Int)
-       do
-               self.statement = s
-               self.index = i
-       end
-
        # Name of the column
        #
        # require: `self.statement.is_open`
@@ -258,17 +249,15 @@ class StatementIterator
        # Statement linked to `self`
        var statement: Statement
 
-       private init(s: Statement)
+       init
        do
-               self.statement = s
-               self.item = new StatementRow(s)
-
+               self.item = new StatementRow(statement)
                self.is_ok = statement.native_statement.step.is_row
        end
 
-       redef var item: StatementRow
+       redef var item: StatementRow is noinit
 
-       redef var is_ok: Bool
+       redef var is_ok: Bool is noinit
 
        # require: `self.statement.is_open`
        redef fun next
@@ -310,12 +299,9 @@ end
 class Blob
        super Sqlite3Data
 
-       private init(pointer: Pointer, length: Int)
-       do
-               self.pointer = pointer
-               self.length = length
-       end
-
+       # Pointer to the beginning of the blob
        var pointer: Pointer
+
+       # Size of the blob
        var length: Int
 end
index a439ec1..3b7f908 100644 (file)
@@ -33,25 +33,29 @@ import kernel
 # Subclasses often provide a more efficient implementation.
 #
 # Because of the `iterator` method, Collections instances can use
-# the `for` control structure:
+# the `for` control structure.
 #
-#         var x: Collection[U]
-#         # ...
-#         for u in x do
-#             # u is a U
-#             # ...
-#         end
+# ~~~nitish
+# var x: Collection[U]
+# # ...
+# for u in x do
+#     # u is a U
+#     # ...
+# end
+# ~~~
 #
-# that is equivalent with
+# that is equivalent with the following:
 #
-#         var x: Collection[U]
-#         # ...
-#         var i = x.iterator
-#         while i.is_ok do
-#             var u = i.item # u is a U
-#             # ...
-#             i.next
-#         end
+# ~~~nitish
+# var x: Collection[U]
+# # ...
+# var i = x.iterator
+#     while i.is_ok do
+#     var u = i.item # u is a U
+#     # ...
+#     i.next
+# end
+# ~~~
 interface Collection[E]
        # Get a new iterator on the collection.
        fun iterator: Iterator[E] is abstract
@@ -123,17 +127,48 @@ interface Collection[E]
                return iterator.item
        end
 
-       # Is the collection contains all the elements of `other`?
+       # Does the collection contain at least each element of `other`?
        #
-       #    assert [1,1,1].has_all([1])         == true
-       #    assert [1,1,1].has_all([1,2])       == false
        #    assert [1,3,4,2].has_all([1..2])    == true
        #    assert [1,3,4,2].has_all([1..5])    == false
+       #
+       # Repeated elements in the collections are not considered.
+       #
+       #    assert [1,1,1].has_all([1])         == true
+       #    assert [1..5].has_all([1,1,1])      == true
+       #
+       # Note that the default implementation is general and correct for any lawful Collections.
+       # It is memory-efficient but relies on `has` so may be CPU-inefficient for some kind of collections.
        fun has_all(other: Collection[E]): Bool
        do
                for x in other do if not has(x) then return false
                return true
        end
+
+       # Does the collection contain exactly all the elements of `other`?
+       #
+       # The same elements must be present in both `self` and `other`,
+       # but the order of the elements in the collections are not considered.
+       #
+       #    assert [1..3].has_exactly([3,1,2]) == true  # the same elements
+       #    assert [1..3].has_exactly([3,1])   == false # 2 is not in the array
+       #    assert [1..2].has_exactly([3,1,2]) == false # 3 is not in the range
+       #
+       # Repeated elements must be present in both collections in the same amount.
+       # So basically it is a multi-set comparison.
+       #
+       #    assert [1,2,3,2].has_exactly([1,2,2,3]) == true  # the same elements
+       #    assert [1,2,3,2].has_exactly([1,2,3])   == false # more 2 in the first array
+       #    assert [1,2,3].has_exactly([1,2,2,3])   == false # more 2 in the second array
+       #
+       # Note that the default implementation is general and correct for any lawful Collections.
+       # It is memory-efficient but relies on `count` so may be CPU-inefficient for some kind of collections.
+       fun has_exactly(other: Collection[E]): Bool
+       do
+               if length != other.length then return false
+               for e in self do if self.count(e) != other.count(e) then return false
+               return true
+       end
 end
 
 # Instances of the Iterator class generates a series of elements, one at a time.
@@ -207,7 +242,7 @@ private class ContainerIterator[E]
 
        redef var is_ok: Bool = true
 
-       private var container: Container[E]
+       var container: Container[E]
 end
 
 # Items can be removed from this collection
@@ -334,6 +369,10 @@ interface Set[E: Object]
                return nhs
        end
 
+       # Returns a new instance of `Set`.
+       #
+       # Depends on the subclass, mainly used for copy services
+       # like `union` or `intersection`.
        protected fun new_set: Set[E] is abstract
 end
 
@@ -944,7 +983,7 @@ private class CoupleMapIterator[K: Object, V]
                _iter.next
        end
 
-       private var iter: Iterator[Couple[K,V]]
+       var iter: Iterator[Couple[K,V]]
 end
 
 # Some tools ###################################################################
index ca6e9fa..add6077 100644 (file)
@@ -109,7 +109,7 @@ abstract class AbstractArrayRead[E]
        #     var b = [10, 20, 30, 40, 50]
        #     a.copy_to(1, 2, b, 2)
        #     assert b      ==  [10, 20, 2, 3, 50]
-       protected fun copy_to(start: Int, len: Int, dest: AbstractArray[E], new_start: Int)
+       fun copy_to(start: Int, len: Int, dest: AbstractArray[E], new_start: Int)
        do
                # TODO native one
                var i = len
@@ -429,7 +429,7 @@ private class ArrayIterator[E]
 
        redef var index = 0
 
-       private var array: AbstractArrayRead[E]
+       var array: AbstractArrayRead[E]
 end
 
 private class ArrayReverseIterator[E]
@@ -508,7 +508,7 @@ private class ArraySetIterator[E: Object]
 
        redef fun item: E do return _iter.item
 
-       private var iter: ArrayIterator[E]
+       var iter: ArrayIterator[E]
 end
 
 
@@ -778,8 +778,14 @@ universal NativeArray[E]
        fun length: Int is intern
        # Use `self` to initialize a standard Nit Array.
        fun to_a: Array[E] do return new Array[E].with_native(self, length)
+
+       # Get item at `index`.
        fun [](index: Int): E is intern
+
+       # Set `item` at `index`.
        fun []=(index: Int, item: E) is intern
+
+       # Copy `length` items to `dest`.
        fun copy_to(dest: NativeArray[E], length: Int) is intern
        #fun =(o: NativeArray[E]): Bool is intern
        #fun !=(o: NativeArray[E]): Bool is intern
index 9d5e678..0701cc7 100644 (file)
@@ -21,6 +21,8 @@ import hash_collection
 import union_find
 
 redef class Sequence[E]
+
+       # Copy the content of `self` between `start` and `len` to a new Array.
        fun subarray(start, len: Int): Array[E]
        do
                var a = new Array[E].with_capacity(len)
index 92b8d5c..d389c5a 100644 (file)
@@ -19,18 +19,18 @@ import array
 private abstract class HashCollection[K: Object]
        type N: HashNode[K]
 
-       private var array: nullable NativeArray[nullable N] = null # Used to store items
-       private var capacity: Int = 0 # Size of _array
-       private var the_length: Int = 0 # Number of items in the map
+       var array: nullable NativeArray[nullable N] = null # Used to store items
+       var capacity: Int = 0 # Size of _array
+       var the_length: Int = 0 # Number of items in the map
 
-       private var first_item: nullable N = null # First added item (used to visit items in nice order)
-       private var last_item: nullable N = null # Last added item (same)
+       var first_item: nullable N = null # First added item (used to visit items in nice order)
+       var last_item: nullable N = null # Last added item (same)
 
        # The last key accessed (used for cache)
-       private var last_accessed_key: nullable K = null
+       var last_accessed_key: nullable K = null
 
        # The last node accessed (used for cache)
-       private var last_accessed_node: nullable N = null
+       var last_accessed_node: nullable N = null
 
        # Return the index of the key k
        fun index_at(k: K): Int
@@ -191,12 +191,12 @@ private abstract class HashCollection[K: Object]
 end
 
 private abstract class HashNode[K: Object]
-       private var key: K
+       var key: K
        type N: HashNode[K]
-       private var next_item: nullable N = null
-       private var prev_item: nullable N = null
-       private var prev_in_bucklet: nullable N = null
-       private var next_in_bucklet: nullable N = null
+       var next_item: nullable N = null
+       var prev_item: nullable N = null
+       var prev_in_bucklet: nullable N = null
+       var next_in_bucklet: nullable N = null
 end
 
 # A map implemented with a hash table.
@@ -343,9 +343,10 @@ end
 private class HashMapNode[K: Object, V]
        super HashNode[K]
        redef type N: HashMapNode[K, V]
-       private var value: V
+       var value: V
 end
 
+# A `MapIterator` over a `HashMap`.
 class HashMapIterator[K: Object, V]
        super MapIterator[K, V]
        redef fun is_ok do return _node != null
@@ -465,10 +466,10 @@ private class HashSetIterator[E: Object]
        end
 
        # The set to iterate on
-       private var set: HashSet[E]
+       var set: HashSet[E]
 
        # The position in the internal map storage
-       private var node: nullable HashSetNode[E] = null
+       var node: nullable HashSetNode[E] = null
 
        init
        do
index 49fb693..ae1b675 100644 (file)
@@ -278,6 +278,7 @@ class ListIterator[E]
        super IndexedIterator[E]
        redef fun item do return _node.item
 
+       # Set item `e` at self `index`.
        fun item=(e: E) do _node.item = e
 
        redef fun is_ok do return not _node == null
index a79f218..61b5194 100644 (file)
@@ -27,10 +27,17 @@ class Range[E: Discrete]
        # Get the element after the last one.
        var after: E
 
+       #     assert [1..10].has(5)
+       #     assert [1..10].has(10)
+       #     assert not [1..10[.has(10)
        redef fun has(item) do return item >= first and item <= last
 
+       #     assert [1..1].has_only(1)
+       #     assert not [1..10].has_only(1)
        redef fun has_only(item) do return first == item and item == last or is_empty
 
+       #     assert [1..10].count(1)   == 1
+       #     assert [1..10].count(0)   == 0
        redef fun count(item)
        do
                if has(item) then
@@ -42,8 +49,13 @@ class Range[E: Discrete]
 
        redef fun iterator do return new IteratorRange[E](self)
 
+       #     assert [1..10].length             == 10
+       #     assert [1..10[.length             == 9
+       #     assert [1..1].length              == 1
+       #     assert [1..-10].length    == 0
        redef fun length
        do
+               if is_empty then return 0
                var nb = first.distance(after)
                if nb > 0 then
                        return nb
@@ -52,12 +64,19 @@ class Range[E: Discrete]
                end
        end
 
+       #     assert not [1..10[.is_empty
+       #     assert not [1..1].is_empty
+       #     assert [1..-10].is_empty
        redef fun is_empty do return first >= after
 
        # Create a range [`from`, `to`].
-       # The syntax `[from..to[` is equivalent.
-       init(from: E, to: E)
-       do
+       # The syntax `[from..to]` is equivalent.
+       #
+       #     var a = [10..15]
+       #     var b = new Range[Int] (10,15)
+       #     assert a == b
+       #     assert a.to_a == [10, 11, 12, 13, 14, 15]
+       init(from: E, to: E) is old_style_init do
                first = from
                last = to
                after = to.successor(1)
@@ -65,18 +84,46 @@ class Range[E: Discrete]
 
        # Create a range [`from`, `to`[.
        # The syntax `[from..to[` is equivalent.
+       #
+       #     var a = [10..15[
+       #     var b = new Range[Int].without_last(10,15)
+       #     assert a == b
+       #     assert a.to_a == [10, 11, 12, 13, 14]
        init without_last(from: E, to: E)
        do
                first = from
                last = to.predecessor(1)
                after = to
        end
+
+       # Two ranges are equals if they have the same first and last elements.
+       #
+       #     var a = new Range[Int](10, 15)
+       #     var b = new Range[Int].without_last(10, 15)
+       #     assert a == [10..15]
+       #     assert a == [10..16[
+       #     assert not a == [10..15[
+       #     assert b == [10..15[
+       #     assert b == [10..14]
+       #     assert not b == [10..15]
+       redef fun ==(o) do
+               return o isa Range[E] and self.first == o.first and self.last == o.last
+       end
+
+       #     var a = new Range[Int](10, 15)
+       #     assert a.hash == 455
+       #     var b = new Range[Int].without_last(10, 15)
+       #     assert b.hash == 432
+       redef fun hash do
+               # 11 and 23 are magic numbers empirically determined to be not so bad.
+               return first.hash * 11 + last.hash * 23
+       end
 end
 
 private class IteratorRange[E: Discrete]
        # Iterator on ranges.
        super Iterator[E]
-       private var range: Range[E]
+       var range: Range[E]
        redef var item is noinit
 
        redef fun is_ok do return _item < _range.after
index 941c2ce..79f9bfd 100644 (file)
@@ -48,8 +48,7 @@ class Process
        var arguments: nullable Array[String]
 
        # Launch a command with some arguments
-       init(command: String, arguments: String...)
-       do
+       init(command: String, arguments: String...) is old_style_init do
                self.command = command
                self.arguments = arguments
                execute
@@ -92,6 +91,8 @@ end
 class IProcess
        super Process
        super IStream
+
+       # File Descriptor used for the input.
        var stream_in: IFStream is noinit
 
        redef fun close do stream_in.close
@@ -113,6 +114,8 @@ end
 class OProcess
        super Process
        super OStream
+
+       # File Descriptor used for the output.
        var stream_out: OStream is noinit
 
        redef fun close do stream_out.close
@@ -159,6 +162,9 @@ redef class Sys
 end
 
 redef class NativeString
+       # Execute self as a shell command.
+       #
+       # See the posix function system(3).
        fun system: Int is extern "string_NativeString_NativeString_system_0"
 end
 
index 369d991..a7c48db 100644 (file)
@@ -40,6 +40,7 @@ abstract class FStream
        # The FILE *.
        private var file: nullable NativeFile = null
 
+       # The status of a file. see POSIX stat(2).
        fun file_stat: FileStat do return _file.file_stat
 
        # File descriptor of this file
@@ -229,6 +230,7 @@ private fun wipe_write: NativeString do return "w".to_cstring
 
 ###############################################################################
 
+# Standard input stream.
 class Stdin
        super IFStream
 
@@ -241,6 +243,7 @@ class Stdin
        redef fun poll_in: Bool is extern "file_stdin_poll_in"
 end
 
+# Standard output stream.
 class Stdout
        super OFStream
        init do
@@ -250,6 +253,7 @@ class Stdout
        end
 end
 
+# Standard error stream.
 class Stderr
        super OFStream
        init do
@@ -612,7 +616,7 @@ redef class String
        end
 
        # returns files contained within the directory represented by self
-       fun files : Set[ String ] is extern import HashSet[String], HashSet[String].add, NativeString.to_s, String.to_cstring, HashSet[String].as(Set[String]) `{
+       fun files: Array[String] is extern import Array[String], Array[String].add, NativeString.to_s, String.to_cstring `{
                char *dir_path;
                DIR *dir;
 
@@ -624,22 +628,22 @@ redef class String
                }
                else
                {
-                       HashSet_of_String results;
+                       Array_of_String results;
                        String file_name;
                        struct dirent *de;
 
-                       results = new_HashSet_of_String();
+                       results = new_Array_of_String();
 
                        while ( ( de = readdir( dir ) ) != NULL )
                                if ( strcmp( de->d_name, ".." ) != 0 &&
                                        strcmp( de->d_name, "." ) != 0 )
                                {
                                        file_name = NativeString_to_s( strdup( de->d_name ) );
-                                       HashSet_of_String_add( results, file_name );
+                                       Array_of_String_add( results, file_name );
                                }
 
                        closedir( dir );
-                       return HashSet_of_String_as_Set_of_String( results );
+                       return results;
                }
        `}
 end
index 2e9c9ae..d65b135 100644 (file)
@@ -30,6 +30,28 @@ import end # Mark this module is a top level one. (must be only one)
 #
 # Currently, Object is also used to collect all top-level methods.
 interface Object
+       # Type of this instance, automatically specialized in every class
+       #
+       # A common use case of the virtual type `SELF` is to type an attribute and
+       # store another instance of the same type as `self`. It can also be used as as
+       # return type to a method producing a copy of `self` or returning an instance
+       # expected to be the exact same type as self.
+       #
+       # This virtual type must be used with caution as it can hinder specialization.
+       # In fact, it imposes strict restrictions on all sub-classes and their usage.
+       # For example, using `SELF` as a return type of a method `foo`
+       # forces all subclasses to ensure that `foo` returns the correct and updated
+       # type.
+       # A dangerous usage take the form of a method typed by `SELF` which creates
+       # and returns a new instance.
+       # If not correctly specialized, this method would break when invoked on a
+       # sub-class.
+       #
+       # A general rule for safe usage of `SELF` is to ensure that inputs typed
+       # `SELF` are stored in attributes typed `SELF` and returned by methods typed
+       # `SELF`, pretty much the same things as you would do with parameter types.
+       type SELF: Object
+
        # The unique object identifier in the class.
        # Unless specific code, you should not use this method.
        # The identifier is used internally to provide a hash value.
@@ -331,6 +353,21 @@ universal Float
                end
        end
 
+       # Compare float numbers with a given precision.
+       #
+       # Because of the loss of precision in floating numbers,
+       # the `==` method is often not the best way to compare them.
+       #
+       # ~~~
+       # assert 0.01.is_approx(0.02, 0.1)   == true
+       # assert 0.01.is_approx(0.02, 0.001) == false
+       # ~~~
+       fun is_approx(other, precision: Float): Bool
+       do
+               assert precision >= 0.0
+               return self <= other + precision and self >= other - precision
+       end
+
        redef fun max(other)
        do
                if self < other then
@@ -377,6 +414,13 @@ universal Int
        redef fun -(i) is intern
        redef fun *(i) is intern
        redef fun /(i) is intern
+
+       # Modulo of `self` with `i`.
+       #
+       # Finds the remainder of division of `self` by `i`.
+       #
+       #     assert 5 % 2                      == 1
+       #     assert 10 % 2                     == 0
        fun %(i: Int): Int is intern
 
        redef fun zero do return 0
index 2bbb6aa..1d1437b 100644 (file)
@@ -114,17 +114,66 @@ redef class Int
 end
 
 redef class Float
+
+       # Returns the non-negative square root of `self`.
+       #
+       #     assert 9.0.sqrt == 3.0
+       #     #assert 3.0.sqrt == 1.732
+       #     assert 1.0.sqrt == 1.0
+       #     assert 0.0.sqrt == 0.0
        fun sqrt: Float is extern "kernel_Float_Float_sqrt_0"
+
+       # Computes the cosine of `self` (expressed in radians).
+       #
+       #     #assert pi.cos == -1.0
        fun cos: Float is extern "kernel_Float_Float_cos_0"
+
+       # Computes the sine of `self` (expressed in radians).
+       #
+       #     #assert pi.sin == 0.0
        fun sin: Float is extern "kernel_Float_Float_sin_0"
+
+       # Computes the cosine of x (expressed in radians).
+       #
+       #     #assert 0.0.tan == 0.0
        fun tan: Float is extern "kernel_Float_Float_tan_0"
+
+       # Computes the arc cosine of `self`.
+       #
+       #     #assert 0.0.acos == pi / 2.0
        fun acos: Float is extern "kernel_Float_Float_acos_0"
+
+       # Computes the arc sine of `self`.
+       #
+       #     #assert 1.0.asin == pi / 2.0
        fun asin: Float is extern "kernel_Float_Float_asin_0"
+
+       # Computes the arc tangent of `self`.
+       #
+       #     #assert 0.0.tan == 0.0
        fun atan: Float is extern "kernel_Float_Float_atan_0"
+
+       # Returns the absolute value of `self`.
+       #
+       #     assert 12.0.abs == 12.0
+       #     assert (-34.56).abs == 34.56
+       #     assert -34.56.abs == -34.56
        fun abs: Float `{ return fabs(recv); `}
 
+       # Returns `self` raised at `e` power.
+       #
+       #     #assert 2.0.pow(0.0) == 1.0
+       #     #assert 2.0.pow(3.0) == 8.0
+       #     #assert 0.0.pow(9.0) == 0.0
        fun pow(e: Float): Float is extern "kernel_Float_Float_pow_1"
+
+       # Returns the logarithm of `self`.
+       #
+       #     assert 0.0.log.is_inf == -1
+       #     #assert 1.0.log == 0.0
        fun log: Float is extern "kernel_Float_Float_log_0"
+
+       # Returns **e** raised to `self`.
        fun exp: Float is extern "kernel_Float_Float_exp_0"
 
        #     assert 1.1.ceil == 2.0
@@ -138,11 +187,22 @@ redef class Float
        #     assert 2.0.floor == 2.0
        #     assert (-1.5).floor == -2.0
        fun floor: Float `{ return floor(recv); `}
+
+       # Rounds the value of a float to its nearest integer value
+       #
+       #     assert 1.67.round == 2.0
+       #     assert 1.34.round == 1.0
+       #     assert -1.34.round == -1.0
+       #     assert -1.67.round == -2.0
+       fun round: Float is extern "round"
        
        # Returns a random `Float` in `[0.0 .. self[`.
        fun rand: Float is extern "kernel_Float_Float_rand_0"
-       fun hypot_with( b : Float ) : Float is extern "hypotf"
 
+       # Returns the euclidean distance from `b`.
+       fun hypot_with(b : Float): Float is extern "hypotf"
+
+       # Returns true is self is not a number.
        fun is_nan: Bool is extern "isnan"
 
        # Is the float an infinite value
@@ -185,7 +245,13 @@ redef class Sys
        end
 end
 
+# Computes the arc tangent given `x` and `y`.
+#
+#     assert atan2(-0.0, 1.0) == -0.0
+#     assert atan2(0.0, 1.0) == 0.0
 fun atan2(x: Float, y: Float): Float is extern "kernel_Any_Any_atan2_2"
+
+# Approximate value of **pi**.
 fun pi: Float is extern "kernel_Any_Any_pi_0"
 
 # Initialize the pseudo-random generator with the given seed.
index 97cb7cb..a58aba0 100644 (file)
@@ -74,7 +74,7 @@ private extern class NativeRegex `{ regex_t* `}
                return message;
        `}
 
-       # This field holds the number of parenthetical subexpressions in the regular expression that was compiled.
+       # Number of parenthetical subexpressions in this compiled regular expression
        fun re_nsub: Int `{ return recv->re_nsub; `}
 end
 
@@ -180,7 +180,12 @@ class Regex
        private var native: nullable NativeRegex = null
 
        # Cache of a single `regmatch_t` to prevent many calls to `malloc`
-       private var native_match = new NativeMatchArray.malloc(1) is lazy
+       private var native_match: NativeMatchArray is lazy do
+               native_match_is_init = true
+               return new NativeMatchArray.malloc(native.re_nsub+1)
+       end
+
+       private var native_match_is_init = false
 
        # `cflags` of the last successful `compile`
        private var cflags_cache = 0
@@ -249,7 +254,10 @@ class Regex
                        native.regfree
                        native.free
                        self.native = null
-                       self.native_match.free
+
+                       if native_match_is_init then
+                               self.native_match.free
+                       end
                end
        end
 
@@ -348,13 +356,26 @@ class Regex
                text = text.to_s
                var cstr = text.substring_from(from).to_cstring
                var eflags = gather_eflags
-               var match = self.native_match
-               var matches = new Array[Match]
+               var native_match = self.native_match
 
-               var res = native.regexec(cstr, 1, match, eflags)
+               var nsub = native.re_nsub
+               var res = native.regexec(cstr, nsub+1, native_match, eflags)
 
                # Found one?
-               if res == 0 then return new Match(text, from + match.rm_so, match.rm_eo - match.rm_so)
+               if res == 0 then
+                       var match = new Match(text,
+                               from + native_match.rm_so,
+                               native_match.rm_eo - native_match.rm_so)
+
+                       # Add sub expressions
+                       for i in [1..nsub] do
+                               match.subs.add new Match( text,
+                                       native_match[i].rm_so,
+                                       native_match[i].rm_eo - native_match[i].rm_so)
+                       end
+
+                       return match
+               end
 
                # No more match?
                if res.is_nomatch then return null
@@ -381,18 +402,30 @@ class Regex
                var cstr = text.to_cstring
                var eflags = gather_eflags
                var eflags_or_notbol = eflags.bin_or(flag_notbol)
-               var match = self.native_match
+               var native_match = self.native_match
                var matches = new Array[Match]
 
-               var res = native.regexec(cstr, 1, match, eflags)
+               var nsub = native.re_nsub
+               var res = native.regexec(cstr, nsub+1, native_match, eflags)
                var d = 0
                while res == 0 do
-                       matches.add new Match(text, d + match.rm_so, match.rm_eo - match.rm_so)
-                       if d == match.rm_eo then
+                       var match = new Match(text,
+                               d + native_match.rm_so,
+                               native_match.rm_eo - native_match.rm_so)
+                       matches.add match
+
+                       # Add sub expressions
+                       for i in [1..nsub] do
+                               match.subs.add new Match( text,
+                                       d + native_match[i].rm_so,
+                                       native_match[i].rm_eo - native_match[i].rm_so)
+                       end
+
+                       if d == native_match.rm_eo then
                                d += 1
-                       else d = d + match.rm_eo
-                       cstr = cstr.substring_from(match.rm_eo)
-                       res = native.regexec(cstr, 1, match, eflags_or_notbol)
+                       else d = d + native_match.rm_eo
+                       cstr = cstr.substring_from(native_match.rm_eo)
+                       res = native.regexec(cstr, nsub+1, native_match, eflags_or_notbol)
                end
 
                # No more match?
@@ -406,3 +439,34 @@ class Regex
 
        redef fun to_s do return "/{string}/"
 end
+
+redef class Match
+       # Parenthesized subexpressions in this match
+       #
+       # ~~~
+       # var re = "c (d e+) f".to_re
+       # var match = "a b c d eee f g".search(re)
+       # assert match.subs.length == 1
+       # assert match.subs.first.to_s == "d eee"
+       # ~~~
+       var subs = new Array[Match] is lazy
+
+       # Get the `n`th expression in this match
+       #
+       # `n == 0` returns this match, and a greater `n` returns the corresponding
+       # subexpression.
+       #
+       # Require: `n >= 0 and n <= subs.length`
+       #
+       # ~~~
+       # var re = "c (d e+) f".to_re
+       # var match = "a b c d eee f g".search(re)
+       # assert match[0].to_s == "c d eee f"
+       # assert match[1].to_s == "d eee"
+       # ~~~
+       fun [](n: Int): Match do
+               if n == 0 then return self
+               assert n > 0 and n <= subs.length
+               return subs[n-1]
+       end
+end
index c4915fd..d7bc8e8 100644 (file)
@@ -94,7 +94,7 @@ private class Concat
        # Right child of the node
        var right: String
 
-       init(l: String, r: String) do
+       init(l: String, r: String) is old_style_init do
                left = l
                right = r
                length = l.length + r.length
@@ -145,7 +145,6 @@ private class Concat
 
        redef fun +(o) do
                var s = o.to_s
-               var mlen = length
                var slen = s.length
                if s isa Concat then
                        return new Concat(self, s)
@@ -230,6 +229,7 @@ class RopeBuffer
                var nns = new NativeString(buf_size)
                var blen = rpos - dumped
                ns.copy_to(nns, blen, dumped, 0)
+               ns = nns
                dumped = 0
                rpos = blen
                written = false
@@ -241,6 +241,11 @@ class RopeBuffer
                str = ""
                length = 0
                rpos = 0
+               dumped = 0
+               if written then
+                       ns = new NativeString(buf_size)
+                       written = false
+               end
        end
 
        redef fun substring(from, count) do
@@ -278,15 +283,7 @@ class RopeBuffer
                var slen = s.length
                length += slen
                var rp = rpos
-               if s isa Rope then
-                       if rp > 0 and dumped != rp then
-                               str += new FlatString.with_infos(ns, rp - dumped, dumped, rp - 1)
-                               dumped = rp
-                       end
-                       str = str + s
-                       return
-               end
-               if slen > maxlen then
+               if s isa Rope or slen > maxlen then
                        if rp > 0 and dumped != rp then
                                str += new FlatString.with_infos(ns, rp - dumped, dumped, rp - 1)
                                dumped = rp
@@ -326,12 +323,11 @@ class RopeBuffer
                        return
                end
                if slen <= remsp then
-                       sits.copy_to(ns, slen, begin, rp)
-                       if rp == buf_size then
-                               rpos = buf_size
+                       if remsp <= 0 then
                                dump_buffer
                                rpos = 0
                        else
+                               sits.copy_to(ns, slen, begin, rp)
                                rpos += slen
                        end
                else
@@ -346,14 +342,13 @@ class RopeBuffer
 
        redef fun add(c) do
                var rp = rpos
-               length += 1
-               ns[rp] = c
-               rp += 1
-               if rp == buf_size then
-                       rpos = rp
+               if rp >= buf_size then
                        dump_buffer
                        rp = 0
                end
+               ns[rp] = c
+               rp += 1
+               length += 1
                rpos = rp
        end
 
@@ -393,15 +388,12 @@ class RopeBuffer
        end
 
        redef fun reverse do
-               str = str.reversed
-               var nns = new NativeString(buf_size)
-               var j = rpos
-               var mits = ns
-               for i in [0 .. rpos[ do
-                       nns[i] = mits[j]
-                       j -= 1
+               # Flush the buffer in order to only have to reverse `str`.
+               if rpos > 0 and dumped != rpos then
+                       str += new FlatString.with_infos(ns, rpos - dumped, dumped, rpos - 1)
+                       dumped = rpos
                end
-               ns = nns
+               str = str.reversed
        end
 
        redef fun upper do
@@ -485,7 +477,7 @@ private class RopeReviter
        # the Rope traversal.
        var subs: IndexedIterator[String]
 
-       init(root: RopeString) do
+       init(root: RopeString) is old_style_init do
                pos = root.length - 1
                subs = new ReverseRopeSubstrings(root)
                ns = subs.item
@@ -532,7 +524,7 @@ private class RopeIter
        # Position (char) in the Rope (0-indexed)
        var pos: Int
 
-       init(root: RopeString) do
+       init(root: RopeString) is old_style_init do
                subs = new RopeSubstrings(root)
                pns = 0
                str = subs.item
@@ -578,7 +570,7 @@ private class ReverseRopeSubstrings
        # Current leaf
        var str: String is noinit
 
-       init(root: RopeString) do
+       init(root: RopeString) is old_style_init do
                var r = new RopeIterPiece(root, false, true, null)
                pos = root.length - 1
                var lnod: String = root
@@ -627,7 +619,7 @@ private class ReverseRopeSubstrings
 
        redef fun next do
                if pos < 0 then return
-               var curr: nullable RopeIterPiece = iter.prev
+               var curr = iter.prev
                var currit = curr.node
                while curr != null do
                        currit = curr.node
@@ -663,7 +655,7 @@ private class RopeBufSubstringIterator
        # Did we attain the buffered part ?
        var nsstr_done = false
 
-       init(str: RopeBuffer) do
+       init(str: RopeBuffer) is old_style_init do
                iter = str.str.substrings
                nsstr = new FlatString.with_infos(str.ns, str.rpos - str.dumped, str.dumped, str.rpos - 1)
                if str.length == 0 then nsstr_done = true
@@ -700,7 +692,7 @@ private class RopeSubstrings
        # Current leaf
        var str: String is noinit
 
-       init(root: RopeString) do
+       init(root: RopeString) is old_style_init do
                var r = new RopeIterPiece(root, true, false, null)
                pos = 0
                max = root.length - 1
@@ -754,7 +746,7 @@ private class RopeSubstrings
                pos += str.length
                if pos > max then return
                var it = iter.prev
-               var rnod: String = it.node
+               var rnod = it.node
                loop
                        if not rnod isa Concat then
                                it.ldone = true
@@ -786,7 +778,7 @@ private class RopeChars
 
        var tgt: RopeString
 
-       init(s: RopeString) do tgt = s
+       init(s: RopeString) is old_style_init do tgt = s
 
        redef fun [](i) do
                return tgt[i]
@@ -798,20 +790,26 @@ private class RopeChars
 
 end
 
+# An Iterator over a RopeBuffer.
 class RopeBufferIter
        super IndexedIterator[Char]
 
+       # Subiterator.
        var sit: IndexedIterator[Char]
 
+       # Native string iterated over.
        var ns: NativeString
 
+       # Current position in `ns`.
        var pns: Int
 
+       # Maximum position iterable.
        var maxpos: Int
 
        redef var index: Int
 
-       init(t: RopeBuffer) do
+       # Init the iterator from a RopeBuffer.
+       init(t: RopeBuffer) is old_style_init do
                ns = t.ns
                maxpos = t.rpos
                sit = t.str.chars.iterator
@@ -819,6 +817,7 @@ class RopeBufferIter
                index = 0
        end
 
+       # Init the iterator from a RopeBuffer starting from `pos`.
        init from(t: RopeBuffer, pos: Int) do
                ns = t.ns
                maxpos = t.length
@@ -844,24 +843,30 @@ class RopeBufferIter
        end
 end
 
+# Reverse iterator over a RopeBuffer.
 class RopeBufferReviter
        super IndexedIterator[Char]
 
+       # Subiterator.
        var sit: IndexedIterator[Char]
 
+       # Native string iterated over.
        var ns: NativeString
 
+       # Current position in `ns`.
        var pns: Int
 
        redef var index: Int
 
-       init(tgt: RopeBuffer) do
+       # Init the iterator from a RopeBuffer.
+       init(tgt: RopeBuffer) is old_style_init do
                sit = tgt.str.chars.reverse_iterator
                pns = tgt.rpos - 1
                index = tgt.length - 1
                ns = tgt.ns
        end
 
+       # Init the iterator from a RopeBuffer starting from `pos`.
        init from(tgt: RopeBuffer, pos: Int) do
                sit = tgt.str.chars.reverse_iterator_from(pos - tgt.rpos - tgt.dumped)
                pns = pos - tgt.str.length
index f928fac..933523a 100644 (file)
@@ -61,6 +61,30 @@ abstract class IStream
        end
 
        # Read a string until the end of the line.
+       #
+       # The line terminator '\n', if any, is preserved in each line.
+       # Use the method `Text::chomp` to safely remove it.
+       #
+       # ~~~
+       # var txt = "Hello\n\nWorld\n"
+       # var i = new StringIStream(txt)
+       # assert i.read_line == "Hello\n"
+       # assert i.read_line == "\n"
+       # assert i.read_line == "World\n"
+       # assert i.eof
+       # ~~~
+       #
+       # If `\n` is not present at the end of the result, it means that
+       # a non-eol terminated last line was returned.
+       #
+       # ~~~
+       # var i2 = new StringIStream("hello")
+       # assert not i2.eof
+       # assert i2.read_line == "hello"
+       # assert i2.eof
+       # ~~~
+       #
+       # NOTE: Only LINE FEED (`\n`) is considered to delimit the end of lines.
        fun read_line: String
        do
                if last_error != null then return ""
@@ -70,6 +94,29 @@ abstract class IStream
                return s.to_s
        end
 
+       # Read all the lines until the eof.
+       #
+       # The line terminator '\n' is removed in each line,
+       #
+       # ~~~
+       # var txt = "Hello\n\nWorld\n"
+       # var i = new StringIStream(txt)
+       # assert i.read_lines == ["Hello", "", "World"]
+       # ~~~
+       #
+       # This method is more efficient that splitting
+       # the result of `read_all`.
+       #
+       # NOTE: Only LINE FEED (`\n`) is considered to delimit the end of lines.
+       fun read_lines: Array[String]
+       do
+               var res = new Array[String]
+               while not eof do
+                       res.add read_line.chomp
+               end
+               return res
+       end
+
        # Read all the stream until the eof.
        fun read_all: String
        do
@@ -83,6 +130,8 @@ abstract class IStream
        end
 
        # Read a string until the end of the line and append it to `s`.
+       #
+       # SEE: `read_line` for details.
        fun append_line_to(s: Buffer)
        do
                if last_error != null then return
@@ -263,6 +312,7 @@ abstract class BufferedIStream
        end
 end
 
+# An Input/Output Stream
 abstract class IOStream
        super IStream
        super OStream
@@ -283,7 +333,9 @@ class StringOStream
                content.add(str.to_s)
        end
 
+       # Is the stream closed?
        protected var closed = false
+
        redef fun close do closed = true
 end
 
index 48cb238..604386f 100644 (file)
@@ -385,6 +385,19 @@ abstract class Text
        #     assert "\na\nb\tc\t".trim          == "a\nb\tc"
        fun trim: SELFTYPE do return (self.l_trim).r_trim
 
+       # Returns `self` removed from its last `\n` (if any).
+       #
+       #    assert "Hello\n".chomp == "Hello"
+       #    assert "Hello".chomp   == "Hello"
+       #    assert "\n\n\n".chomp  == "\n\n"
+       #
+       # This method is mainly used to remove the LINE_FEED character from lines of text.
+       fun chomp: SELFTYPE
+       do
+               if self.chars.last != '\n' then return self
+               return substring(0, length-1)
+       end
+
        # Justify a self in a space of `length`
        #
        # `left` is the space ratio on the left side.
@@ -640,9 +653,11 @@ abstract class Text
                return buf.to_s
        end
 
-       # Escape the four characters `<`, `>`, `&`, and `"` with their html counterpart
+       # Escape the characters `<`, `>`, `&`, `"`, `'` and `/` as HTML/XML entity references.
        #
-       #     assert "a&b->\"x\"".html_escape      ==  "a&amp;b-&gt;&quot;x&quot;"
+       #     assert "a&b-<>\"x\"/'".html_escape      ==  "a&amp;b-&lt;&gt;&#34;x&#34;&#47;&#39;"
+       #
+       # SEE: <https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet#RULE_.231_-_HTML_Escape_Before_Inserting_Untrusted_Data_into_HTML_Element_Content>
        fun html_escape: SELFTYPE
        do
                var buf = new FlatBuffer
@@ -656,7 +671,11 @@ abstract class Text
                        else if c == '>' then
                                buf.append "&gt;"
                        else if c == '"' then
-                               buf.append "&quot;"
+                               buf.append "&#34;"
+                       else if c == '\'' then
+                               buf.append "&#39;"
+                       else if c == '/' then
+                               buf.append "&#47;"
                        else buf.add c
                end
 
@@ -757,8 +776,6 @@ abstract class FlatText
 
        redef var length: Int = 0
 
-       init do end
-
        redef fun output
        do
                var i = 0
@@ -778,7 +795,7 @@ private abstract class StringCharView
 
        type SELFTYPE: Text
 
-       private var target: SELFTYPE
+       var target: SELFTYPE
 
        redef fun is_empty do return target.is_empty
 
@@ -799,6 +816,11 @@ private abstract class BufferCharView
 
 end
 
+# A `String` holds and manipulates an arbitrary sequence of characters.
+#
+# String objects may be created using literals.
+#
+#     assert "Hello World!" isa String
 abstract class String
        super Text
 
@@ -819,6 +841,9 @@ abstract class String
        #     assert "abc" * 0 == ""
        fun *(i: Int): SELFTYPE is abstract
 
+       # Insert `s` at `pos`.
+       #
+       #     assert "helloworld".insert_at(" ", 5)     == "hello world"
        fun insert_at(s: String, pos: Int): SELFTYPE is abstract
 
        redef fun substrings: Iterator[String] is abstract
@@ -1313,6 +1338,7 @@ private class FlatStringCharView
 
 end
 
+# A mutable sequence of characters.
 abstract class Buffer
        super Text
 
@@ -1398,7 +1424,7 @@ abstract class Buffer
        #
        # SEE: `Char::is_letter` for the definition of a letter.
        #
-       #    var b = new FlatBuffer.from("jAVAsCriPt")"
+       #    var b = new FlatBuffer.from("jAVAsCriPt")
        #    b.capitalize
        #    assert b == "Javascript"
        #    b = new FlatBuffer.from("i am root")
@@ -1411,7 +1437,7 @@ abstract class Buffer
                if length == 0 then return
                var c = self[0].to_upper
                self[0] = c
-               var prev: Char = c
+               var prev = c
                for i in [1 .. length[ do
                        prev = c
                        c = self[i]
@@ -1529,6 +1555,7 @@ class FlatBuffer
        # Create a new empty string.
        init do end
 
+       # Create a new string copied from `s`.
        init from(s: Text)
        do
                capacity = s.length + 1
@@ -1713,7 +1740,6 @@ private class FlatBufferCharView
 
        redef fun append(s)
        do
-               var my_items = target.items
                var s_length = s.length
                if target.capacity < s.length then enlarge(s_length + target.length)
        end
@@ -2118,8 +2144,14 @@ end
 extern class NativeString `{ char* `}
        # Creates a new NativeString with a capacity of `length`
        new(length: Int) is intern
+
+       # Get char at `index`.
        fun [](index: Int): Char is intern
+
+       # Set char `item` at index.
        fun []=(index: Int, item: Char) is intern
+
+       # Copy `self` to `dest`.
        fun copy_to(dest: NativeString, length: Int, from: Int, to: Int) is intern
 
        # Position of the first nul character.
@@ -2129,7 +2161,11 @@ extern class NativeString `{ char* `}
                while self[l] != '\0' do l += 1
                return l
        end
+
+       # Parse `self` as an Int.
        fun atoi: Int is intern
+
+       # Parse `self` as a Float.
        fun atof: Float is extern "atof"
 
        redef fun to_s
@@ -2137,6 +2173,7 @@ extern class NativeString `{ char* `}
                return to_s_with_length(cstring_length)
        end
 
+       # Returns `self` as a String of `length`.
        fun to_s_with_length(length: Int): FlatString
        do
                assert length >= 0
@@ -2144,6 +2181,7 @@ extern class NativeString `{ char* `}
                return str
        end
 
+       # Returns `self` as a new String.
        fun to_s_with_copy: FlatString
        do
                var length = cstring_length
index 9b1fb8a..9965bb1 100644 (file)
@@ -85,6 +85,7 @@ interface Pattern
                return res
        end
 
+       # Is `self` in `s`?
        protected fun is_in(s: Text): Bool do return search_index_in(s, 0) != -1
 end
 
@@ -204,7 +205,6 @@ class BM_Pattern
 
        private fun compute_gs
        do
-               var x = _motif
                var m = _length
                var suff = suffixes
                var i = 0
index 11ba1fe..07ed861 100644 (file)
@@ -31,11 +31,17 @@ end
 
 # Time since epoch
 extern class TimeT `{time_t`}
+
+       # Returns Time since epoch from now.
        new `{ return time(NULL); `}
+
+       # Returns Time since epoch from `i` (expressed in seconds).
        new from_i(i: Int) `{ return i; `}
 
+       # Update current time.
        fun update `{ time(&recv); `}
 
+       # Convert `self` to a human readable String.
        fun ctime: String import NativeString.to_s_with_copy `{
                return NativeString_to_s_with_copy( ctime(&recv) );
        `}
@@ -44,50 +50,81 @@ extern class TimeT `{time_t`}
        fun difftime(start: TimeT): Float `{ return difftime(recv, start); `}
 
        redef fun to_s do return ctime.replace("\n", "")
+
+       # Convert self to Int (expressed as seconds since epoch).
        fun to_i: Int `{ return (int)recv; `}
 end
 
 # Time structure
 extern class Tm `{struct tm *`}
+
+       # Create a new Time structure expressed in Coordinated Universal Time (UTC).
        new gmtime `{
                struct tm *tm;
                time_t t = time(NULL);
                tm = gmtime(&t);
                return tm;
        `}
+
+       # Create a new Time structure expressed in UTC from `t`.
        new gmtime_from_timet(t: TimeT) `{
                struct tm *tm;
                tm = gmtime(&t);
                return tm;
        `}
 
+       # Create a new Time structure expressed in the local timezone.
        new localtime `{
                struct tm *tm;
                time_t t = time(NULL);
                tm = localtime(&t);
                return tm;
        `}
+
+       # Create a new Time structure expressed in the local timezone from `t`.
        new localtime_from_timet(t: TimeT) `{
                struct tm *tm;
                tm = localtime(&t);
                return tm;
        `}
 
+       # Convert `self` as a TimeT.
        fun to_timet: TimeT `{ return mktime(recv); `}
 
+       # Seconds after the minute.
        fun sec: Int `{ return recv->tm_sec; `}
+
+       # Minutes after the hour.
        fun min: Int `{ return recv->tm_min; `}
+
+       # hours since midnight.
        fun hour: Int `{ return recv->tm_hour; `}
+
+       # Day of the month.
        fun mday: Int `{ return recv->tm_mday; `}
+
+       # Months since January.
        fun mon: Int `{ return recv->tm_mon; `}
+
+       # Years since 1900.
        fun year: Int `{ return recv->tm_year; `}
+
+       # Days since Sunday.
        fun wday: Int `{ return recv->tm_wday; `}
+
+       # Days since January 1st.
        fun yday: Int `{ return recv->tm_yday; `}
+
+       # Is `self` in Daylight Saving Time.
        fun is_dst: Bool `{ return recv->tm_isdst; `}
 
+       # Convert `self` to a human readable String.
        fun asctime: String import NativeString.to_s_with_copy `{
                return NativeString_to_s_with_copy( asctime(recv) );
        `}
+
+       # Convert `self` to a human readable String corresponding to `format`.
+       # TODO document allowed format.
        fun strftime(format: String): String import String.to_cstring, NativeString.to_s `{
                char* buf, *c_format;
                size_t res;
index b7a74ce..34edd00 100644 (file)
@@ -47,6 +47,7 @@ extern class UnicodeChar `{ UTF8Char* `}
        #
        # As per the specification :
        #
+       # ~~~raw
        #  Length  |        UTF-8 octet sequence
        #          |              (binary)
        # ---------+-------------------------------------------------
@@ -54,6 +55,7 @@ extern class UnicodeChar `{ UTF8Char* `}
        #  2       | 110xxxxx 10xxxxxx
        #  3       | 1110xxxx 10xxxxxx 10xxxxxx
        #  4       | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+       # ~~~
        private fun len: Int `{
                char* ns = recv->ns;
                int pos = recv->pos;
index db51f0a..547cbf7 100644 (file)
@@ -53,6 +53,7 @@ extern class UnicodeChar `{ uint32_t* `}
        #
        # As per the specification :
        #
+       # ~~~raw
        #  Length  |        UTF-8 octet sequence
        #          |              (binary)
        # ---------+-------------------------------------------------
@@ -60,6 +61,7 @@ extern class UnicodeChar `{ uint32_t* `}
        #  2       | 110xxxxx 10xxxxxx
        #  3       | 1110xxxx 10xxxxxx 10xxxxxx
        #  4       | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+       # ~~~
        fun len: Int `{
                uint32_t s = *recv;
                if(s <= 127) {return 1;}
index 0b1c9e4..2796a3c 100644 (file)
@@ -47,16 +47,18 @@ import template
 #
 # In external file `example.tpl`:
 #
-#    <!DOCTYPE html>
-#    <html lang="en">
-#     <head>
-#      <title>%TITLE%</title>
-#     </head>
-#     <body>
-#      <h1>%TITLE%</h1>
-#      <p>%ARTICLE%</p>
-#     </body>
-#    </html>
+# ~~~html
+# <!DOCTYPE html>
+# <html lang="en">
+#  <head>
+#   <title>%TITLE%</title>
+#  </head>
+#  <body>
+#   <h1>%TITLE%</h1>
+#   <p>%ARTICLE%</p>
+#  </body>
+# </html>
+# ~~~
 #
 # Loading the template file using `TemplateString`:
 #
index d05663e..6626036 100644 (file)
@@ -42,7 +42,7 @@ end
 class TreeNode[K: Comparable, E]
 
        # TreeNode type
-       type SELF: TreeNode[K, E]
+       type N: TreeNode[K, E]
 
        # `key` for this node
        var key: K
@@ -51,7 +51,7 @@ class TreeNode[K: Comparable, E]
        var value: E
 
        # Direct parent of this node (null if the node is root)
-       var parent: nullable SELF = null is writable
+       var parent: nullable N = null is writable
 
        redef fun to_s do return "\{{value or else ""}\}"
 
index b689700..feb9671 100644 (file)
@@ -244,11 +244,13 @@ class BinTreeMap[K: Comparable, E]
 
        # Perform left rotation on `node`
        #
+       # ~~~raw
        #     N             Y
        #    / \     >     / \
        #   a   Y         N   c
        #      / \   <   / \
        #     b   c     a   b
+       # ~~~
        #
        protected fun rotate_left(node: N) do
                var y = node.right
@@ -270,11 +272,13 @@ class BinTreeMap[K: Comparable, E]
 
        # Perform right rotation on `node`
        #
+       # ~~~raw
        #     N             Y
        #    / \     >     / \
        #   a   Y         N   c
        #      / \   <   / \
        #     b   c     a   b
+       # ~~~
        #
        protected fun rotate_right(node: N) do
                var y = node.left
@@ -370,38 +374,38 @@ class BinTreeNode[K: Comparable, E]
        private var prev: nullable BinTreeNode[K, E]
        private var next: nullable BinTreeNode[K, E]
 
-       redef type SELF: BinTreeNode[K, E]
+       redef type N: BinTreeNode[K, E]
 
        init(key: K, item: E) do
                super(key, item)
        end
 
-       private var left_node: nullable SELF = null
+       private var left_node: nullable N = null
 
        # `left` tree node child (null if node has no left child)
-       fun left: nullable SELF do return left_node
+       fun left: nullable N do return left_node
 
        # set `left` child for this node (or null if left no child)
        # ENSURE: node.key < key (only if node != null)
-       fun left=(node: nullable SELF) do
+       fun left=(node: nullable N) do
                #assert node != null implies node.key < key
                left_node = node
        end
 
-       private var right_node: nullable SELF = null
+       private var right_node: nullable N = null
 
        # `right` tree node child (null if node has no right child)
-       fun right: nullable SELF do return right_node
+       fun right: nullable N do return right_node
 
        # set `right` child for this node (or null if right no child)
        # ENSURE: node.key < key (only if node != null)
-       fun right=(node: nullable SELF) do
+       fun right=(node: nullable N) do
                #assert node != null implies node.key > key
                right_node = node
        end
 
        # `parent` of the `parent` of this node (null if root)
-       fun grandparent: nullable SELF do
+       fun grandparent: nullable N do
                if parent == null then
                        return null
                else
@@ -411,7 +415,7 @@ class BinTreeNode[K: Comparable, E]
 
        # Other child of the `grandparent`
        # `left` or `right` depends on the position of the current node against its parent
-       fun uncle: nullable SELF do
+       fun uncle: nullable N do
                var g = grandparent
                if g == null then
                        return null
@@ -426,7 +430,7 @@ class BinTreeNode[K: Comparable, E]
 
        # Other child of the parent
        # `left` or `right` depends on the position of the current node against its parent
-       fun sibling: nullable SELF do
+       fun sibling: nullable N do
                if parent == null then
                        return null
                else if self == parent.left then
index ce17feb..51ddfc0 100644 (file)
@@ -32,17 +32,17 @@ import bintree
 
 # Red-Black Tree Map
 # Properties of a Red-Black tree map:
-#  * every node is either red or black
-#  * root is black
-#  * every leaf (null) is black
-#  * if a node is red, then both its children are black
-#  * for each node, all simple path from the node to descendant
-#    leaves contain the same number of black nodes
+# * every node is either red or black
+# * root is black
+# * every leaf (null) is black
+# * if a node is red, then both its children are black
+# * for each node, all simple path from the node to descendant
+#   leaves contain the same number of black nodes
 #
 # Operations:
-#  * search average O(lg n) worst O(lg n)
-#  * insert average O(lg n) worst O(lg n)
-#  * delete average O(lg n) worst O(lg n)
+# * search average O(lg n) worst O(lg n)
+# * insert average O(lg n) worst O(lg n)
+# * delete average O(lg n) worst O(lg n)
 class RBTreeMap[K: Comparable, E]
        super BinTreeMap[K, E]
 
@@ -130,7 +130,7 @@ end
 class RBTreeNode[K: Comparable, E]
        super BinTreeNode[K, E]
 
-       redef type SELF: RBTreeNode[K, E]
+       redef type N: RBTreeNode[K, E]
 
        # Is the node red?
        private var is_red = true
index df0b984..1ba2d13 100644 (file)
 # Serices from the X11 library
 module x11 is pkgconfig
 
+`{
+       #include <X11/Xlib.h>
+`}
+
 # Open the current display from the environment variables
 #
 # See <http://www.x.org/releases/X11R7.7/doc/man/man3/XOpenDisplay.3.xhtml>
index 737b4a1..18a579a 100644 (file)
@@ -131,25 +131,31 @@ hi def link NITFFIDelimiters              Keyword
 " FFI Python
 syntax include @FFIPython syntax/python.vim
 unlet b:current_syntax
-syn match NITFFILanguage       '"Python"' nextgroup=NITFFIBlockPython skipwhite
+syn match NITFFILanguage       /\c"Python"/ nextgroup=NITFFIBlockPython skipwhite
 syn region NITFFIBlockPython matchgroup=NITFFI start='`{' matchgroup=NITFFI end='`}' keepend fold contains=@FFIPython
 
 " FFI Java
 syntax include @FFIJava syntax/java.vim
 unlet b:current_syntax
-syn match NITFFILanguage       '"Java"' nextgroup=NITFFIBlockJava skipwhite
+syn match NITFFILanguage       /\c"Java\(\| inner\)"/ nextgroup=NITFFIBlockJava skipwhite
 syn region NITFFIBlockJava matchgroup=NITFFI start='`{' matchgroup=NITFFI end='`}' keepend fold contains=@FFIJava
 
 " FFI C++
 syntax include @FFICpp syntax/cpp.vim
 unlet b:current_syntax
-syn match NITFFILanguage       '"C++"' nextgroup=NITFFIBlockCpp skipwhite
+syn match NITFFILanguage       /\c"C++\(\| header\| body\)"/ nextgroup=NITFFIBlockCpp skipwhite
 syn region NITFFIBlockCpp matchgroup=NITFFI start='`{' matchgroup=NITFFI end='`}' keepend fold contains=@FFICpp
 
+" FFI Objective-C
+syntax include @FFIObjC syntax/objc.vim
+unlet b:current_syntax
+syn match NITFFILanguage       /\c"ObjC\(\| Header\| Body\)"/ nextgroup=NITFFIBlockObjC skipwhite
+syn region NITFFIBlockObjC matchgroup=NITFFI start='`{' matchgroup=NITFFI end='`}' keepend fold contains=@FFIObjC
+
 " FFI C (the last one is the default)
 syntax include @FFIC syntax/c.vim
 unlet b:current_syntax
-syn match NITFFILanguage               '"C\(\| header\| body\)"'       nextgroup=NITFFIBlockC skipwhite
+syn match NITFFILanguage               /\c"C\(\| header\| body\)"/     nextgroup=NITFFIBlockC skipwhite
 syn region NITFFIBlockC matchgroup=NITFFI start='`{' matchgroup=NITFFI end='`}' keepend fold contains=@FFIC
 
 hi def link NITFFILanguage             Define
index 22494b7..af8d698 100644 (file)
@@ -72,6 +72,7 @@ function! SyntaxCheckers_nit_nitg_GetLocList()
                                   \ '%f:%l\,%c--%*[0-9]\,%*[0-9]:',
                                   \ '%f:%l\,%c:' ]
        let ef_type = [ ' %tarning: ',
+                                 \ ' %tocumentation warning: ',
                                  \ '' ]
 
        " generate errorformat from combinations
@@ -82,7 +83,16 @@ function! SyntaxCheckers_nit_nitg_GetLocList()
                endfor
        endfor
 
-       return SyntasticMake({ 'makeprg': makeprg, 'errorformat':errorformat })
+       let loclist = SyntasticMake({ 'makeprg': makeprg, 'errorformat': errorformat, 'postprocess': ['guards'] })
+
+       for e in loclist
+               if e['type'] ==? 'd' " is a documentation warning
+                       let e['type'] = 'w'
+                       let e['subtype'] = 'Style'
+               endif
+       endfor
+
+       return loclist
 endfunction
 
 call g:SyntasticRegistry.CreateAndRegisterChecker({
index 2d1f0a7..b8273f4 100644 (file)
@@ -6,7 +6,7 @@ nitls - lists the projects, groups and paths of Nit sources files.
 
 # SYNOPSIS
 
-nitls [*options*] FILE...
+nitls [*options*] [*FILE*]...
 
 # DESCRIPTION
 
@@ -14,11 +14,24 @@ nitls [*options*] FILE...
 
 It is basically a `ls` or a simple `find` specialized on `.nit` source files.
 
+By default `nitls` works with the current directory (`.`).
+
+Each file can then be:
+
+* A Nit module (file).
+  In this case, only this single module is considered
+* A Nit group (directory).
+  In this case, all the modules of the groups (and recursively the sub-groups) are considered
+* A normal directory.
+  In this case, all its entries are analysed.
+  Files that are Nit modules and directories that are Nit groups are considered.
+  Other files and directories are ignored.
+
 # EXAMPLES
 
-Show the tree of modules from the current directory and subdirectories.
+Show the tree of modules from the current directory.
 
-    $ nitls -t -r .
+    $ nitls -t
 
 Show the list of projects imported by the modules of the current directory.
 
@@ -26,25 +39,7 @@ Show the list of projects imported by the modules of the current directory.
 
 # OPTIONS
 
-## COLLECT
-
-`-r`, `--recursive`
-:   Process directories recursively.
-
-    All `.nit` files found in the specified directory and subdirectories are considered.
-
-`-d`, `--depends`
-:   List dependencies of given modules
-
-    All imported modules are also considered.
-
-`-k`, `--keep`
-:   Ignore errors and files that are not a Nit source file.
-
-    When a file that is not a valit Nit module is encoutered, it is ignored and the rest of the file are
-    processed.
-
-    Without this option, a error message is displayed and nitls terminates on such a case.
+Each combination of option
 
 ## PRESENTATION MODE
 
@@ -65,11 +60,39 @@ Three presentation modes are available.
 
     Each `.nit` file is presented indivitually.
 
+The three modes are exclusives.
+
+The default mode is `--project` unless one on the argument is a group, then it is `--group`.
+
+## COLLECT
+
+`-r`, `--recursive`
+:   Process directories recursively.
+
+    All `.nit` files found in the specified directory and subdirectories are considered.
+
+`-d`, `--depends`
+:   List dependencies of given modules
+
+    All imported modules are also considered.
+
+    In --tree and --source modes, the modules direclty imported are also displayed.
+
+`-k`, `--keep`
+:   Ignore errors and files that are not a Nit source file.
+
+    When a file that is not a valid Nit module is encoutered, it is ignored and the rest of the files are
+    processed.
+
+    Without this option, an error message is displayed and nitls terminates on such a case.
+
 ## PRESENTATION OPTIONS
 
 `-p`, `--path`
 :   List only path (instead of name + path).
 
+    Paths are displayed uncolored.
+
 `-M`
 :   List dependencies suitable for a rule in a Makefile.
 
index 5fac6a4..0864629 100644 (file)
@@ -25,6 +25,178 @@ nitpretty [*options*]... FILE
 `--check`
 :   Check format of Nit source files
 
+# SPECIFICATION
+
+The specification of the pretty printing is described here.
+
+* Default indentation level is one `'\t'` character and is increased by one for
+  each indentation level.
+* Default line max-size is 80.
+
+### COMMENTS
+
+There is many categories of comments:
+
+`Licence comments` are attached to the top of the file no blank line before,
+one after.
+
+~~~nitish
+# This is a licence comment
+
+# Documentation for module `foo`
+module foo
+~~~
+
+`ADoc` are documentation comments attached to a `AModule`, `AClassdef`, `APropdef`.
+
+They are printed before the definition with a blank line before and no after
+at the same indentation level than the definition.
+
+~~~nitish
+# Documentation for module `foo`
+module foo
+
+# Documentation for class `Bar`
+class Bar
+     # Documentation for method `baz`
+     fun baz do end
+end
+~~~
+
+`Block comments` are comments composed of one or more line rattached to nothing.
+They are displayed with one blank line before and after at current indent level.
+
+~~~nitish
+<blank>
+# block
+# comment
+<blank>
+~~~
+
+`Attached comments` are comments attached to a production.
+They are printed as this.
+
+~~~nitish
+fun foo do # attached comment
+end
+~~~
+
+`nitpretty` automatically remove multiple blanks between comments:
+
+~~~nitish
+# Licence
+# ...
+<blank>
+# Block comment
+~~~
+
+### INLINING
+
+Productions are automatically inlined when possible.
+
+Conditions:
+
+* The production must be syntactically inlinable
+* The inlined production length is less than `PrettyPrinterVisitor::max-size`
+* The production do not contains any comments
+
+### MODULES
+
+* There is a blank between the module declaration and its imports
+* There is no blank between imports and only one after
+* There is a blank between each extern block definition
+* There is a blank between each class definition
+* There is no blank line at the end of the module
+
+~~~nitish
+# Documentation for module `foo`
+module foo
+
+import a
+import b
+import c
+
+# Documentation for class `Bar`
+class Bar end
+
+class Baz end # not a `ADoc` comment
+~~~
+
+### CLASSES
+
+* There is no blank between the class definition and its super-classes declarations
+* There is no blank between two inlined property definition
+* There is a blank between each block definition
+* There no blank line at the end of the class definition
+
+~~~nitish
+# Documentation for class `Bar`
+class Bar end
+
+class Baz
+    super Bar
+
+    fun a is abstract
+    private fun b do end
+
+    fun c do
+        # ...
+    end
+end
+~~~
+
+Generic types have no space after or before brackets and are separated by a comma and a space:
+
+~~~nitish
+class A[E: Type1, F: Type1] end
+~~~
+
+### BLOCKS
+
+* Inlined productions have no blank lines between them
+* Block productions have a blank before and after
+
+~~~nitish
+var a = 10
+var b = 0
+
+if a > b then
+     is positive
+     print "positive"
+end
+
+print "end"
+~~~
+
+### CALLS AND BINARY OPS
+
+Arguments are always printed separated with a comma and a space:
+
+~~~nitish
+foo(a, b, c)
+~~~
+
+Binary ops are always printed wrapped with spaces:
+
+~~~nitish
+var c = 1 + 2
+~~~
+
+Calls and binary ops can be splitted to fit the `max-size` constraint.
+Breaking priority is given to arguments declaration after the comma.
+
+~~~nitish
+return foo("aaaaaaaaaaaaaaaaaaaaaaaaaa", "bbbbbbbbbbbbbbbbbbbbbbbbbbb",
+    "cccccccccccccccccccccccccc")
+~~~
+
+Binary ops can also be broken to fit the `max-size` limit:
+
+~~~nitish
+return "aaaaaaaaaaaaaaaaaaaaaaaaaa" + "bbbbbbbbbbbbbbbbbbbbbbbbbbb" +
+    "cccccccccccccccccccccccccc"
+~~~
+
 # SEE ALSO
 
 The Nit language documentation and the source code of its tools and libraries may be downloaded from <http://nitlanguage.org>
index 4737fa9..4f45562 100644 (file)
@@ -25,8 +25,8 @@ They contain a list of test methods called TestCase.
 
 ## Working with `DocUnits`
 
-With DocUnits, executable code can be placed in comments of modules, classes and properties.
-The execution can be verified using `assert`
+DocUnits are blocks of executable code placed in comments of modules, classes and properties.
+The execution can be verified using `assert`.
 
 Example with a class:
 
@@ -49,6 +49,59 @@ To test a method you have to instantiate its class:
         fun baz(a, b: Int) do return a + b
     end
 
+In a single piece of documentation, each docunit is considered a part of a single module, thus regrouped when
+tested.
+Therefore, it is possible (and recommended) to split docunits in small parts if it make the explanation easier.
+
+~~~~
+# Some example of grouped docunits
+#
+# Declare and initialize a variable `a`.
+#
+#     var a = 1
+#
+# So the value of `a` can be used
+#
+#     assert a == 1
+#
+# even in complex operations
+#
+#     assert a + 1 == 2
+fun foo do end
+~~~~
+
+Sometime, some blocks of code has to be included in documentation but not considered by `nitunit`.
+Those blocks are distinguished by their tagged fences (untagged fences or fences tagged `nit` are considered to be docunits).
+
+~~~~
+# Some ASCII drawing
+#
+# ~~~~raw
+#   @<
+# <__)
+# ~~~~
+fun foo do end
+~~~~
+
+The special fence-tag `nitish` could also be used to indicate pseudo-nit that will be ignored by nitunit but highlighted by nitdoc.
+Such `nitish` piece of code can be used to enclose examples that cannot compile or that one do not want to be automatically executed.
+
+~~~~
+# Some pseudo-nit
+#
+# ~~~~nitish
+# var a: Int = someting
+# # ...
+# if a == 1 then something else something-else
+# ~~~~
+#
+# Some code to not try to execute automatically
+#
+# ~~~~nitish
+# system("rm -rf /")
+# ~~~~
+~~~~
+
 The `nitunit` command is used to test Nit files:
 
     $ nitunit foo.nit
index 13f500c..df006f9 100644 (file)
@@ -52,17 +52,21 @@ define([
                },
 
                _create: function() {
-                       this.element
-                               .attr(this.options.fieldAttrs)
-                               .keydown($.proxy(this._doKeyDown, this))
-                               .keyup($.proxy(this._doKeyUp, this))
-
+                       // set widget options
+                       this.element.attr(this.options.fieldAttrs);
+                       // event dispatch
+                       this._on(this.element, {
+                               "keydown": this._doKeyDown,
+                               "keyup": this._doKeyUp,
+                               "input": this._doInput
+                       });
+                       // add result table element once
                        this._table = $("<table/>")
                                .attr("id", this.options.tableID)
                                .css(this.options.tableCSS)
                                .css("min-width", this.element.outerWidth());
                        $("body").append(this._table);
-
+                       // make table disappear when a click occurs outside
                        $(document).click($.proxy(this.closeTable, this));
                },
 
@@ -94,11 +98,14 @@ define([
                                        this.closeTable();
                                        return true;
                                default: // Other keys
-                                       utils.delayEvent($.proxy(this.search, this));
                                        return true;
                        }
                },
 
+               _doInput: function(event) {
+                       utils.delayEvent($.proxy(this.search, this));
+               },
+
                /* Result lookup */
 
                _getResults: function(query) {
index 620bf49..8aa0295 100644 (file)
@@ -134,11 +134,13 @@ redef class AExpr
        # To create the new node `n`, we need to attach the child to it.
        # But, to put `n` where `c` was in `p`, the place has to be remembered.
        #
-       #     var p: AExpr
-       #     var c = p.c
-       #     var h = c.detach_with_placeholder
-       #     var n = astbuilder.make_XXX(c)
-       #     h.replace_with(n)
+       # ~~~nitish
+       # var p: AExpr
+       # var c = p.c
+       # var h = c.detach_with_placeholder
+       # var n = astbuilder.make_XXX(c)
+       # h.replace_with(n)
+       # ~~~
        fun detach_with_placeholder: AExpr
        do
                var h = new APlaceholderExpr.make
index abfbf3f..6329dac 100644 (file)
@@ -914,12 +914,8 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref ) {
                var cds = mtype.collect_mclassdefs(self.mainmodule).to_a
                self.mainmodule.linearize_mclassdefs(cds)
                for cd in cds do
-                       if not self.modelbuilder.mclassdef2nclassdef.has_key(cd) then continue
-                       var n = self.modelbuilder.mclassdef2nclassdef[cd]
-                       for npropdef in n.n_propdefs do
-                               if npropdef isa AAttrPropdef then
-                                       npropdef.init_expr(v, recv)
-                               end
+                       for npropdef in modelbuilder.collect_attr_propdef(cd) do
+                               npropdef.init_expr(v, recv)
                        end
                end
        end
@@ -930,12 +926,8 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref ) {
                var cds = mtype.collect_mclassdefs(self.mainmodule).to_a
                self.mainmodule.linearize_mclassdefs(cds)
                for cd in cds do
-                       if not self.modelbuilder.mclassdef2nclassdef.has_key(cd) then continue
-                       var n = self.modelbuilder.mclassdef2nclassdef[cd]
-                       for npropdef in n.n_propdefs do
-                               if npropdef isa AAttrPropdef then
-                                       npropdef.check_expr(v, recv)
-                               end
+                       for npropdef in modelbuilder.collect_attr_propdef(cd) do
+                               npropdef.check_expr(v, recv)
                        end
                end
        end
@@ -1857,10 +1849,10 @@ redef class MMethodDef
        do
                if is_abstract then return true
                var modelbuilder = v.compiler.modelbuilder
-               if modelbuilder.mpropdef2npropdef.has_key(self) then
-                       var npropdef = modelbuilder.mpropdef2npropdef[self]
-                       return npropdef.can_inline
-               else if self.mproperty.is_root_init then
+               var node = modelbuilder.mpropdef2node(self)
+               if node isa APropdef then
+                       return node.can_inline
+               else if node isa AClassdef then
                        # Automatic free init is always inlined since it is empty or contains only attribtes assigments
                        return true
                else
@@ -1873,19 +1865,18 @@ redef class MMethodDef
        do
                var modelbuilder = v.compiler.modelbuilder
                var val = constant_value
-               if modelbuilder.mpropdef2npropdef.has_key(self) then
-                       var npropdef = modelbuilder.mpropdef2npropdef[self]
+               var node = modelbuilder.mpropdef2node(self)
+               if node isa APropdef then
                        var oldnode = v.current_node
-                       v.current_node = npropdef
+                       v.current_node = node
                        self.compile_parameter_check(v, arguments)
-                       npropdef.compile_to_c(v, self, arguments)
+                       node.compile_to_c(v, self, arguments)
                        v.current_node = oldnode
-               else if self.mproperty.is_root_init then
-                       var nclassdef = modelbuilder.mclassdef2nclassdef[self.mclassdef]
+               else if node isa AClassdef then
                        var oldnode = v.current_node
-                       v.current_node = nclassdef
+                       v.current_node = node
                        self.compile_parameter_check(v, arguments)
-                       nclassdef.compile_to_c(v, self, arguments)
+                       node.compile_to_c(v, self, arguments)
                        v.current_node = oldnode
                else if val != null then
                        v.ret(v.value_instance(val))
index cc24d6e..ad34b9a 100644 (file)
@@ -44,6 +44,9 @@ class AndroidProject
        # Custom lines to add to the AndroidManifest.xml in the <application> node
        var manifest_application_lines = new Array[String]
 
+       # Custom lines to add to AndroidManifest.xml as attributes inside the <activity> node
+       var manifest_activity_attributes = new Array[String]
+
        # Minimum API level required for the application to run
        var min_api: nullable Int = null
 
@@ -107,6 +110,9 @@ redef class ModelBuilder
                annots = collect_annotations_on_modules("android_manifest_application", mmodule)
                for an in annots do project.manifest_application_lines.add an.arg_as_string(self) or else ""
 
+               annots = collect_annotations_on_modules("android_manifest_activity", mmodule)
+               for an in annots do project.manifest_activity_attributes.add an.arg_as_string(self) or else ""
+
                # Get the date and time (down to the minute) as string
                var local_time = new Tm.localtime
                var local_time_s = local_time.strftime("%y%m%d%H%M")
index 55468fd..1cf6ba8 100644 (file)
@@ -124,10 +124,12 @@ class AndroidToolchain
 
                # Also copy over the java files
                dir = "{android_project_root}/src/"
-               var extra_java_files = compiler.mainmodule.extra_java_files
-               if extra_java_files != null then for file in extra_java_files do
-                       var path = file.filename
-                       path.file_copy_to("{dir}/{path.basename("")}")
+               for mmodule in compiler.mainmodule.in_importation.greaters do
+                       var extra_java_files = mmodule.extra_java_files
+                       if extra_java_files != null then for file in extra_java_files do
+                               var path = file.filename
+                               path.file_copy_to(dir/path.basename(""))
+                       end
                end
 
                ## Generate delagating makefile
@@ -178,13 +180,11 @@ $(call import-module,android/native_app_glue)
              This will take care of integrating with our NDK code. -->
         <activity android:name="android.app.NativeActivity"
                 android:label="@string/app_name"
-                android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
-                android:configChanges="orientation|keyboardHidden"
-                android:screenOrientation="portrait"
+                {{{project.manifest_activity_attributes.join("\n")}}}
                 {{{icon_declaration}}}>
-            <!-- Tell NativeActivity the name of or .so -->
-            <meta-data android:name=\"{{{app_package}}}\"
-                    android:value=\"{{{app_name}}}\" />
+            <!-- Tell NativeActivity the name of our .so -->
+            <meta-data android:name=\"android.app.lib_name\"
+                    android:value=\"main\" />
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
index bf8dc30..b2f4837 100644 (file)
@@ -124,6 +124,8 @@ end
 # Two elements from a POSet cannot have the same color if they share common subelements
 #
 # Example:
+#
+# ~~~raw
 #       A
 #     / | \
 #    /  |  \
@@ -134,22 +136,26 @@ end
 #   E   F   G
 #   |
 #   H
+# ~~~
+#
 # Conflicts:
-#   A: {B, C, D, E, F, G, H}
-#   B: {A, C, E, H}
-#   C: {A, E, H, F}
-#   D: {A, G}
-#   E: {A, B, C, H}
-#   F: {A, C}
-#   G: {A, D}
-#   H: {A, B, C, E}
+#
+# * A: {B, C, D, E, F, G, H}
+# * B: {A, C, E, H}
+# * C: {A, E, H, F}
+# * D: {A, G}
+# * E: {A, B, C, H}
+# * F: {A, C}
+# * G: {A, D}
+# * H: {A, B, C, E}
+#
 # Possible colors:
-#   A:0, B:1, C: 2, D: 1, E: 3, F:3, G:2, H:4
 #
-# see:
-#      Ducournau, R. (2011).
-#      Coloring, a versatile technique for implementing object-oriented languages.
-#      Software: Practice and Experience, 41(6), 627–659.
+# * A:0, B:1, C: 2, D: 1, E: 3, F:3, G:2, H:4
+#
+# see: Ducournau, R. (2011).
+# Coloring, a versatile technique for implementing object-oriented languages.
+# Software: Practice and Experience, 41(6), 627–659.
 class POSetColorer[E: Object]
 
        # Is the poset already colored?
index 491ebfe..13f0bd7 100644 (file)
@@ -418,13 +418,12 @@ class SeparateCompiler
                var live_cast_types = runtime_type_analysis.live_cast_types
                var mtypes = new HashSet[MType]
                mtypes.add_all(live_types)
-               mtypes.add_all(live_cast_types)
                for c in self.box_kinds.keys do
                        mtypes.add(c.mclass_type)
                end
 
                # Compute colors
-               var poset = poset_from_mtypes(mtypes)
+               var poset = poset_from_mtypes(mtypes, live_cast_types)
                var colorer = new POSetColorer[MType]
                colorer.colorize(poset)
                type_ids = colorer.ids
@@ -437,12 +436,13 @@ class SeparateCompiler
                return poset
        end
 
-       private fun poset_from_mtypes(mtypes: Set[MType]): POSet[MType] do
+       private fun poset_from_mtypes(mtypes, cast_types: Set[MType]): POSet[MType] do
                var poset = new POSet[MType]
                for e in mtypes do
                        poset.add_node(e)
-                       for o in mtypes do
+                       for o in cast_types do
                                if e == o then continue
+                               poset.add_node(o)
                                if e.is_subtype(mainmodule, null, o) then
                                        poset.add_edge(e, o)
                                end
index 4141f75..09883db 100644 (file)
@@ -16,7 +16,7 @@
 module doc_model
 
 import model_utils
-import markdown
+import docdown
 import doc_templates
 import ordered_tree
 import model_ext
@@ -172,6 +172,7 @@ redef class MProject
 
        redef fun tpl_definition do
                var tpl = new TplDefinition
+               var mdoc = mdoc_or_fallback
                if mdoc != null then
                        tpl.comment = mdoc.tpl_comment
                end
@@ -213,6 +214,7 @@ redef class MGroup
 
        redef fun tpl_definition do
                var tpl = new TplDefinition
+               var mdoc = mdoc_or_fallback
                if mdoc != null then
                        tpl.comment = mdoc.tpl_comment
                end
@@ -235,7 +237,7 @@ redef class MModule
        redef fun tpl_declaration do
                var tpl = new Template
                tpl.add "<span>module "
-               tpl.add tpl_link
+               tpl.add tpl_namespace
                tpl.add "</span>"
                return tpl
        end
@@ -610,6 +612,28 @@ redef class MVirtualTypeDef
        end
 end
 
+redef class MInnerClass
+       redef fun nitdoc_url do return inner.nitdoc_url
+       redef fun tpl_signature do return inner.tpl_signature
+end
+
+redef class MInnerClassDef
+       redef fun nitdoc_url do return inner.nitdoc_url
+
+       redef fun tpl_anchor do return inner.tpl_anchor
+       redef fun tpl_link do return inner.tpl_link
+       redef fun tpl_signature do return inner.tpl_signature
+
+       redef fun tpl_definition do
+               var tpl = new TplClassDefinition
+               tpl.namespace = mclassdef.tpl_namespace
+               if mdoc != null then
+                       tpl.comment = mdoc.tpl_comment
+               end
+               return tpl
+       end
+end
+
 redef class MType
        fun tpl_signature: Template is abstract
 end
index 78ccd7f..248a8ee 100644 (file)
@@ -163,6 +163,8 @@ class Nitdoc
        private fun properties do
                for mproperty in model.mproperties do
                        if mproperty.visibility <= ctx.min_visibility then continue
+                       if mproperty isa MInnerClass then continue
+                       if mproperty isa MAttribute then continue
                        var page = new NitdocProperty(ctx, model, mainmodule, mproperty)
                        page.render.write_to_file("{ctx.output_dir.to_s}/{page.page_url}")
                end
@@ -903,7 +905,7 @@ class NitdocModule
 
                # Graph
                var mmodules = new HashSet[MModule]
-               mmodules.add_all mmodule.in_nesting.direct_greaters
+               mmodules.add_all mmodule.nested_mmodules
                mmodules.add_all imports
                if clients.length < 10 then mmodules.add_all clients
                mmodules.add mmodule
@@ -1088,6 +1090,9 @@ class NitdocClass
                tpl_sidebar_list("Virtual types", kind_map["type"].to_a, summary)
                tpl_sidebar_list("Constructors", kind_map["init"].to_a, summary)
                tpl_sidebar_list("Methods", kind_map["fun"].to_a, summary)
+               if not kind_map["inner"].is_empty then
+                       tpl_sidebar_list("Inner classes", kind_map["inner"].to_a, summary)
+               end
                tpl_sidebar.boxes.add new TplSideBox.with_content("All properties", summary)
        end
 
@@ -1275,6 +1280,10 @@ class NitdocClass
                                for article in tpl_mproperty_articles(kind_map, "fun") do
                                        section.add_child article
                                end
+                               # inner classes
+                               for article in tpl_mproperty_articles(kind_map, "inner") do
+                                       section.add_child article
+                               end
                                parent.add_child section
                        end
                end
@@ -1342,6 +1351,7 @@ class NitdocClass
                map["type"] = new HashSet[MProperty]
                map["init"] = new HashSet[MProperty]
                map["fun"] = new HashSet[MProperty]
+               map["inner"] = new HashSet[MProperty]
                for mprop in mprops do
                        if mprop isa MVirtualTypeProp then
                                map["type"].add mprop
@@ -1351,6 +1361,8 @@ class NitdocClass
                                else
                                        map["fun"].add mprop
                                end
+                       else if mprop isa MInnerClass then
+                               map["inner"].add mprop
                        end
                end
                return map
@@ -1486,7 +1498,12 @@ class NitdocProperty
 
        private fun tpl_properties(parent: TplSection) do
                # intro title
-               var section = new TplSection.with_title("intro", "Introduction")
+               var ns = mproperty.intro.mclassdef.mmodule.tpl_namespace
+               var section = new TplSection("intro")
+               var title = new Template
+               title.add "Introduction in "
+               title.add ns
+               section.title = title
                section.summary_title = "Introduction"
                section.add_child tpl_mpropdef_article(mproperty.intro)
                parent.add_child section
@@ -1504,7 +1521,7 @@ class NitdocProperty
                                parent.add_child new TplSection(mentity.nitdoc_id)
                        else if mentity isa MModule then
                                var ssection = new TplSection(mentity.nitdoc_id)
-                               var title = new Template
+                               title = new Template
                                title.add "in "
                                title.add mentity.tpl_namespace
                                ssection.title = title
index 0e8f00b..7624626 100644 (file)
@@ -17,6 +17,7 @@
 module doc_templates
 
 import template
+import json::static
 
 # A documentation page
 class TplPage
@@ -56,28 +57,31 @@ class TplPage
 
        # Render the html header
        private fun render_head do
-               add "<!DOCTYPE html>"
-               add "<head>"
-               add " <meta charset='utf-8'/>"
-               add " <!--link rel='stylesheet' href='{shareurl}/css/Nitdoc.UI.css' type='text/css'/-->"
-               add " <link rel='stylesheet' href='{shareurl}/vendors/bootstrap/css/bootstrap.min.css'/>"
-               add " <link rel='stylesheet' href='{shareurl}/css/nitdoc.bootstrap.css'/>"
-               add " <link rel='stylesheet' href='{shareurl}/css/nitdoc.css'/>"
-               add " <link rel='stylesheet' href='{shareurl}/css/Nitdoc.QuickSearch.css'/>"
-               add " <link rel='stylesheet' href='{shareurl}/css/Nitdoc.ModalBox.css'/>"
-               add " <link rel='stylesheet' href='{shareurl}/css/Nitdoc.GitHub.css'/>"
-               add " <title>{title}</title>"
-               add "</head>"
+               var css = (self.shareurl / "css").html_escape
+               var vendors = (self.shareurl / "vendors").html_escape
+
+               addn "<!DOCTYPE html>"
+               addn "<head>"
+               addn " <meta charset='utf-8'/>"
+               addn " <!--link rel='stylesheet' href='{css}/Nitdoc.UI.css' type='text/css'/-->"
+               addn " <link rel='stylesheet' href='{vendors}/bootstrap/css/bootstrap.min.css'/>"
+               addn " <link rel='stylesheet' href='{css}/nitdoc.bootstrap.css'/>"
+               addn " <link rel='stylesheet' href='{css}/nitdoc.css'/>"
+               addn " <link rel='stylesheet' href='{css}/Nitdoc.QuickSearch.css'/>"
+               addn " <link rel='stylesheet' href='{css}/Nitdoc.ModalBox.css'/>"
+               addn " <link rel='stylesheet' href='{css}/Nitdoc.GitHub.css'/>"
+               addn " <title>{title}</title>"
+               addn "</head>"
                add "<body"
                for attr in body_attrs do add attr
-               add ">"
+               addn ">"
        end
 
        # Render the topmenu template
        private fun render_topmenu do
-               add " <div class='row'>"
+               addn " <div class='row'>"
                add topmenu
-               add " </div>"
+               addn " </div>"
        end
 
        # Render the sidebar
@@ -95,49 +99,52 @@ class TplPage
        private fun render_content do
                for section in sections do add section
                if footer != null then
-                       add "<div class='well footer'>"
+                       addn "<div class='well footer'>"
                        add footer.as(not null)
-                       add "</div>"
+                       addn "</div>"
                end
        end
 
        # Render JS scripts
        private fun render_footer do
-               add "<script src='{shareurl}/vendors/jquery/jquery-1.11.1.min.js'></script>"
-               add "<script src='{shareurl}/vendors/jquery/jquery-ui-1.10.4.custom.min.js'></script>"
-               add "<script src='{shareurl}/vendors/bootstrap/js/bootstrap.min.js'></script>"
-               add "<script data-main='{shareurl}/js/nitdoc' src='{shareurl}/js/lib/require.js'></script>"
+               var vendors = (self.shareurl / "vendors").html_escape
+               var js = (self.shareurl / "js").html_escape
+
+               addn "<script src='{vendors}/jquery/jquery-1.11.1.min.js'></script>"
+               addn "<script src='{vendors}/jquery/jquery-ui-1.10.4.custom.min.js'></script>"
+               addn "<script src='{vendors}/bootstrap/js/bootstrap.min.js'></script>"
+               addn "<script data-main='{js}/nitdoc' src='{js}/lib/require.js'></script>"
                for script in scripts do add script
-               add """<script>
+               addn """<script>
                        $(function () {
                                $("[data-toggle='tooltip']").tooltip();
                                $("[data-toggle='popover']").popover();
                        });
                </script>"""
-               add "</body>"
-               add "</html>"
+               addn "</body>"
+               addn "</html>"
        end
 
        # Render the whole page
        redef fun rendering do
                render_head
-               add "<div class='container-fluid'>"
+               addn "<div class='container-fluid'>"
                render_topmenu
-               add " <div class='row' id='content'>"
+               addn " <div class='row' id='content'>"
                if sidebar != null then
-                       add "<div class='col col-xs-3 col-lg-2'>"
+                       addn "<div class='col col-xs-3 col-lg-2'>"
                        render_sidebar
-                       add "</div>"
-                       add "<div class='col col-xs-9 col-lg-10' data-spy='scroll' data-target='.summary'>"
+                       addn "</div>"
+                       addn "<div class='col col-xs-9 col-lg-10' data-spy='scroll' data-target='.summary'>"
                        render_content
-                       add "</div>"
+                       addn "</div>"
                else
-                       add "<div class='col col-xs-12'>"
+                       addn "<div class='col col-xs-12'>"
                        render_content
-                       add "</div>"
+                       addn "</div>"
                end
-               add " </div>"
-               add "</div>"
+               addn " </div>"
+               addn "</div>"
                render_footer
        end
 end
@@ -175,7 +182,7 @@ class TplTopMenu
                end
                tpl.add ">"
                tpl.add content
-               tpl.add "</li>"
+               tpl.addn "</li>"
                add_raw(tpl)
        end
 
@@ -186,27 +193,27 @@ class TplTopMenu
 
        redef fun rendering do
                if brand == null and elts.is_empty then return
-               add "<nav id='topmenu' class='navbar navbar-default navbar-fixed-top' role='navigation'>"
-               add " <div class='container-fluid'>"
-               add "  <div class='navbar-header'>"
+               addn "<nav id='topmenu' class='navbar navbar-default navbar-fixed-top' role='navigation'>"
+               addn " <div class='container-fluid'>"
+               addn "  <div class='navbar-header'>"
                add "   <button type='button' class='navbar-toggle' "
-               add "       data-toggle='collapse' data-target='#topmenu-collapse'>"
-               add "    <span class='sr-only'>Toggle menu</span>"
-               add "    <span class='icon-bar'></span>"
-               add "    <span class='icon-bar'></span>"
-               add "    <span class='icon-bar'></span>"
-               add "   </button>"
+               addn "       data-toggle='collapse' data-target='#topmenu-collapse'>"
+               addn "    <span class='sr-only'>Toggle menu</span>"
+               addn "    <span class='icon-bar'></span>"
+               addn "    <span class='icon-bar'></span>"
+               addn "    <span class='icon-bar'></span>"
+               addn "   </button>"
                if brand != null then add brand.as(not null)
-               add "  </div>"
-               add "  <div class='collapse navbar-collapse' id='topmenu-collapse'>"
+               addn "  </div>"
+               addn "  <div class='collapse navbar-collapse' id='topmenu-collapse'>"
                if not elts.is_empty then
-                       add "<ul class='nav navbar-nav'>"
+                       addn "<ul class='nav navbar-nav'>"
                        for elt in elts do add elt
-                       add "</ul>"
+                       addn "</ul>"
                end
-               add "  </div>"
-               add " </div>"
-               add "</nav>"
+               addn "  </div>"
+               addn " </div>"
+               addn "</nav>"
        end
 end
 
@@ -226,9 +233,9 @@ class TplSidebar
        redef fun rendering do
                if boxes.is_empty then return
                order_boxes
-               add "<div id='sidebar'>"
+               addn "<div id='sidebar'>"
                for box in boxes do add box
-               add "</div>"
+               addn "</div>"
        end
 end
 
@@ -289,16 +296,16 @@ class TplSideBox
                if content == null then return
                var open = ""
                if is_open then open = "in"
-               add "<div class='panel'>"
-               add " <div class='panel-heading'>"
+               addn "<div class='panel'>"
+               addn " <div class='panel-heading'>"
                add "  <a data-toggle='collapse' data-parent='#sidebar' data-target='#box_{id}' href='#'>"
                add title
-               add "  </a>"
-               add " </div>"
-               add " <div id='box_{id}' class='panel-body collapse {open}'>"
+               addn "  </a>"
+               addn " </div>"
+               addn " <div id='box_{id}' class='panel-body collapse {open}'>"
                add content.as(not null)
-               add " </div>"
-               add "</div>"
+               addn " </div>"
+               addn "</div>"
        end
 end
 
@@ -325,18 +332,18 @@ class TplSummary
 
        redef fun rendering do
                if children.is_empty then return
-               add "<div class='panel'>"
-               add " <div class='panel-heading'>"
+               addn "<div class='panel'>"
+               addn " <div class='panel-heading'>"
                add "  <a data-toggle='collapse' data-parent='#sidebar' data-target='#box-sum' href='#'>"
                add "Summary"
-               add "  </a>"
-               add " </div>"
-               add " <div id='box-sum' class='summary collapse in'>"
-               add " <ul class='nav'>"
+               addn "  </a>"
+               addn " </div>"
+               addn " <div id='box-sum' class='summary collapse in'>"
+               addn " <ul class='nav'>"
                for entry in children do add entry
-               add " </ul>"
-               add " </div>"
-               add "</div>"
+               addn " </ul>"
+               addn " </div>"
+               addn "</div>"
        end
 end
 
@@ -357,11 +364,11 @@ class TplSummaryEntry
                add "<li>"
                add text
                if not children.is_empty then
-                       add "<ul class='nav'>"
+                       addn "\n<ul class='nav'>"
                        for entry in children do add entry
-                       add "</ul>"
+                       addn "</ul>"
                end
-               add "</li>"
+               addn  "</li>"
        end
 end
 
@@ -437,23 +444,23 @@ class TplSection
        super TplSectionElt
 
        redef fun rendering do
-               add "<section id='{id}' class='{css_classes.join(" ")}'>"
+               addn "<section id='{id}' class='{css_classes.join(" ")}'>"
                if title != null then
                        var lvl = hlvl
                        if lvl == 2 then title_classes.add "well well-sm"
-                       add "<h{lvl} class='{title_classes.join(" ")}'>"
-                       add title.as(not null)
-                       add "</h{lvl}>"
+                       addn "<h{lvl} class='{title_classes.join(" ")}'>"
+                       addn title.as(not null)
+                       addn "</h{lvl}>"
                end
                if subtitle != null then
-                       add "<div class='info subtitle'>"
-                       add subtitle.as(not null)
-                       add "</div>"
+                       addn "<div class='info subtitle'>"
+                       addn subtitle.as(not null)
+                       addn "</div>"
                end
                for child in children do
                        add child
                end
-               add "</section>"
+               addn "</section>"
        end
 end
 
@@ -481,23 +488,23 @@ class TplArticle
 
        redef fun rendering do
                if is_empty then return
-               add "<article id='{id}' class='{css_classes.join(" ")}'>"
+               addn "<article id='{id}' class='{css_classes.join(" ")}'>"
                if source_link != null then
                        add "<div class='source-link'>"
                        add source_link.as(not null)
-                       add "</div>"
+                       addn "</div>"
                end
                if title != null then
                        var lvl = hlvl
                        if lvl == 2 then title_classes.add "well well-sm"
                        add "<h{lvl} class='{title_classes.join(" ")}'>"
                        add title.as(not null)
-                       add "</h{lvl}>"
+                       addn "</h{lvl}>"
                end
                if subtitle != null then
                        add "<div class='info subtitle'>"
                        add subtitle.as(not null)
-                       add "</div>"
+                       addn "</div>"
                end
                if content != null then
                        add content.as(not null)
@@ -505,7 +512,7 @@ class TplArticle
                for child in children do
                        add child
                end
-               add """</article>"""
+               addn """</article>"""
        end
 
        redef fun is_empty: Bool do
@@ -527,7 +534,7 @@ class TplDefinition
        var location: nullable Streamable = null is writable
 
        private fun render_info do
-               add "<div class='info text-right'>"
+               addn "<div class='info text-right'>"
                if namespace != null then
                        if comment == null then
                                add "<span class=\"noComment\">no comment for </span>"
@@ -538,7 +545,7 @@ class TplDefinition
                        add " "
                        add location.as(not null)
                end
-               add "</div>"
+               addn "</div>"
        end
 
        private fun render_comment do
@@ -546,10 +553,10 @@ class TplDefinition
        end
 
        redef fun rendering do
-               add "<div class='definition'>"
+               addn "<div class='definition'>"
                render_comment
                render_info
-               add "</div>"
+               addn "</div>"
        end
 end
 
@@ -563,20 +570,20 @@ class TplClassDefinition
        init do end
 
        redef fun rendering do
-               add "<div class='definition'>"
+               addn "<div class='definition'>"
                render_comment
                render_info
                render_list("Introduces", intros)
                render_list("Redefines", redefs)
-               add "</div>"
+               addn "</div>"
        end
 
        private fun render_list(name: String, elts: Array[TplListElt]) do
                if elts.is_empty then return
-               add "<h5>{name}</h5>"
-               add "<ul class='list-unstyled list-definition'>"
+               addn "<h5>{name.html_escape}</h5>"
+               addn "<ul class='list-unstyled list-definition'>"
                for elt in elts do add elt
-               add "</ul>"
+               addn "</ul>"
        end
 end
 
@@ -590,47 +597,47 @@ class TplSearchPage
 
        redef fun rendering do
                var title = self.title
-               if title != null then add "<h1>{title}</h1>"
-               add "<div class='container-fluid'>"
-               add " <div class='row'>"
+               if title != null then addn "<h1>{title.to_s.html_escape}</h1>"
+               addn "<div class='container-fluid'>"
+               addn " <div class='row'>"
                if not modules.is_empty then
-                       add "<div class='col-xs-4'>"
-                       add "<h3>Modules</h3>"
-                       add "<ul>"
+                       addn "<div class='col-xs-4'>"
+                       addn "<h3>Modules</h3>"
+                       addn "<ul>"
                        for m in modules do
                                add "<li>"
                                add m
-                               add "</li>"
+                               addn "</li>"
                        end
-                       add "</ul>"
-                       add "</div>"
+                       addn "</ul>"
+                       addn "</div>"
                end
                if not classes.is_empty then
-                       add "<div class='col-xs-4'>"
-                       add "<h3>Classes</h3>"
-                       add "<ul>"
+                       addn "<div class='col-xs-4'>"
+                       addn "<h3>Classes</h3>"
+                       addn "<ul>"
                        for c in classes do
                                add "<li>"
                                add c
-                               add "</li>"
+                               addn "</li>"
                        end
-                       add "</ul>"
-                       add "</div>"
+                       addn "</ul>"
+                       addn "</div>"
                end
                if not props.is_empty then
-                       add "<div class='col-xs-4'>"
-                       add "<h3>Properties</h3>"
-                       add "<ul>"
+                       addn "<div class='col-xs-4'>"
+                       addn "<h3>Properties</h3>"
+                       addn "<ul>"
                        for p in props do
                                add "<li>"
                                add p
-                               add "</li>"
+                               addn "</li>"
                        end
-                       add "</ul>"
-                       add "</div>"
+                       addn "</ul>"
+                       addn "</div>"
                end
-               add " </div>"
-               add "</div>"
+               addn " </div>"
+               addn "</div>"
        end
 end
 
@@ -693,9 +700,9 @@ class TplList
 
        redef fun rendering do
                if elts.is_empty then return
-               add "<ul class='{css_classes.join(" ")}'>"
+               addn "<ul class='{css_classes.join(" ")}'>"
                for elt in elts do add elt
-               add "</ul>"
+               addn "</ul>"
        end
 end
 
@@ -730,7 +737,7 @@ class TplListItem
        redef fun rendering do
                add "<li class='{css_classes.join(" ")}'>"
                add content
-               add "</li>"
+               addn "</li>"
        end
 end
 
@@ -748,9 +755,9 @@ class TplTab
        var css_classes = new Array[String]
 
        redef fun rendering do
-               add "<div class='tab-content'>"
+               addn "<div class='tab-content'>"
                for panel in panels do add panel
-               add "</div>"
+               addn "</div>"
        end
 end
 
@@ -789,9 +796,9 @@ class TplTabPanel
        redef fun rendering do
                add "<div class='tab-pane {css_classes.join(" ")}"
                if is_active then add "active"
-               add "' id='{id}'>"
+               addn "' id='{id}'>"
                if content != null then add content.as(not null)
-               add "</div>"
+               addn "</div>"
        end
 end
 
@@ -834,6 +841,16 @@ end
 
 # A HTML tag attribute
 #  `<tag attr="value">`
+#
+# ~~~nit
+# var attr: TagAttribute
+#
+# attr = new TagAttribute("foo", null)
+# assert attr.write_to_string == " foo=\"\""
+#
+# attr = new TagAttribute("foo", "bar<>")
+# assert attr.write_to_string == " foo=\"bar&lt;&gt;\""
+# ~~~
 class TagAttribute
        super Template
 
@@ -843,9 +860,10 @@ class TagAttribute
        redef fun rendering do
                var value = self.value
                if value == null then
-                       add(" {name}")
+                       # SEE: http://www.w3.org/TR/html5/infrastructure.html#boolean-attributes
+                       add " {name.html_escape}=\"\""
                else
-                       add(" {name}=\"{value}\"")
+                       add " {name.html_escape}=\"{value.html_escape}\""
                end
        end
 end
@@ -868,9 +886,9 @@ class TplScript
        redef fun rendering do
                add "<script"
                for attr in attrs do add attr
-               add ">"
+               addn ">"
                render_content
-               add "</script>"
+               addn "</script>"
        end
 end
 
@@ -882,17 +900,22 @@ class TplPiwikScript
        var site_id: String
 
        redef fun render_content do
-               add "<!-- Piwik -->"
-               add "var _paq = _paq || [];"
-               add " _paq.push([\"trackPageView\"]);"
-               add " _paq.push([\"enableLinkTracking\"]);"
-               add "(function() \{"
-               add " var u=((\"https:\" == document.location.protocol) ? \"https\" : \"http\") + \"://{tracker_url}\";"
-               add " _paq.push([\"setTrackerUrl\", u+\"piwik.php\"]);"
-               add " _paq.push([\"setSiteId\", \"{site_id}\"]);"
-               add " var d=document, g=d.createElement(\"script\"), s=d.getElementsByTagName(\"script\")[0]; g.type=\"text/javascript\";"
-               add " g.defer=true; g.async=true; g.src=u+\"piwik.js\"; s.parentNode.insertBefore(g,s);"
-               add "\})();"
+               var site_id = self.site_id.to_json
+               var tracker_url = self.tracker_url.trim
+               if tracker_url.chars.last != '/' then tracker_url += "/"
+               tracker_url = "://{tracker_url}".to_json
+
+               addn "<!-- Piwik -->"
+               addn "var _paq = _paq || [];"
+               addn " _paq.push([\"trackPageView\"]);"
+               addn " _paq.push([\"enableLinkTracking\"]);"
+               addn "(function() \{"
+               addn " var u=((\"https:\" == document.location.protocol) ? \"https\" : \"http\") + {tracker_url};"
+               addn " _paq.push([\"setTrackerUrl\", u+\"piwik.php\"]);"
+               addn " _paq.push([\"setSiteId\", {site_id}]);"
+               addn " var d=document, g=d.createElement(\"script\"), s=d.getElementsByTagName(\"script\")[0]; g.type=\"text/javascript\";"
+               addn " g.defer=true; g.async=true; g.src=u+\"piwik.js\"; s.parentNode.insertBefore(g,s);"
+               addn "\})();"
        end
 end
 
index fe74325..2adc9fd 100644 (file)
@@ -88,6 +88,28 @@ class MTypePart
        end
 end
 
+# An inner class.
+class MInnerClass
+       super MProperty
+
+       redef type MPROPDEF: MInnerClassDef
+
+       # The actual class.
+       var inner: MClass
+end
+
+# An inner class definition.
+class MInnerClassDef
+       super MPropDef
+
+       redef type MPROPDEF: MInnerClassDef
+       redef type MPROPERTY: MInnerClass
+
+       # The actual class definition.
+       var inner: MClassDef
+end
+
+
 # The “package” visiblity.
 #
 # Any visibility roughly equivalent to the default visibility of Java, that is
similarity index 92%
rename from src/markdown.nit
rename to src/docdown.nit
index e254480..08a776e 100644 (file)
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 # Transform Nit verbatim documentation into HTML
-module markdown
+module docdown
 
 private import parser
 import html
@@ -30,6 +30,9 @@ private class Doc2Mdwn
        # Count empty lines between code blocks
        var empty_lines = 0
 
+       # Optional tag for a fence
+       var fence_tag = ""
+
        fun work(mdoc: MDoc): HTMLTag
        do
                var root = new HTMLTag("div")
@@ -77,6 +80,7 @@ private class Doc2Mdwn
                                empty_lines = 0
                                # to allows 4 spaces including the one that follows the #
                                curblock.add(text)
+                               fence_tag = ""
                                continue
                        end
 
@@ -88,6 +92,8 @@ private class Doc2Mdwn
                                var l = 3
                                while l < text.length and text.chars[l] == '~' do l += 1
                                in_fence = text.substring(0, l)
+                               while l < text.length and (text.chars[l] == '.' or text.chars[l] == ' ') do l += 1
+                               fence_tag = text.substring_from(l)
                                continue
                        end
 
@@ -187,7 +193,7 @@ private class Doc2Mdwn
                                # Code part
                                var n2 = new HTMLTag("code")
                                n.add(n2)
-                               process_code(n2, part)
+                               process_code(n2, part, null)
                        end
                        is_text = not is_text
                end
@@ -222,13 +228,20 @@ private class Doc2Mdwn
                        # add the node
                        var n = new HTMLTag("pre")
                        root.add(n)
-                       process_code(n, btext.to_s)
+                       process_code(n, btext.to_s, fence_tag)
                        curblock.clear
                end
        end
 
-       fun process_code(n: HTMLTag, text: String)
+       fun process_code(n: HTMLTag, text: String, tag: nullable String)
        do
+               # Do not try to highlight non-nit code.
+               if tag != null and tag != "" and tag != "nit" and tag != "nitish" then
+                       n.append text
+                       n.add_class("rawcode")
+                       return
+               end
+
                # Try to parse it
                var ast = toolcontext.parse_something(text)
 
index 6fba61a..8ae08b9 100644 (file)
@@ -68,7 +68,7 @@ redef class AExternCodeBlock
 end
 
 redef class Location
-       fun as_line_pragma: String do return "#line {line_start} \"{file.filename}\"\n"
+       fun as_line_pragma: String do return "#line {line_start-1} \"{file.filename}\"\n"
 end
 
 redef class MModule
index e1b8463..05d8fd5 100644 (file)
@@ -44,12 +44,12 @@ private class ExternClassesTypingPhaseAst
                end
 
                var ftype = code_block.language.get_ftype(code_block, nclassdef)
-               nclassdef.ftype_cache = ftype
-               nclassdef.ftype_computed = true
+               nclassdef.mclassdef.ftype_cache = ftype
+               nclassdef.mclassdef.ftype_computed = true
        end
 end
 
-redef class AClassdef
+redef class MClassDef
        private var ftype_cache: nullable ForeignType = null
        private var ftype_computed = false
 
@@ -103,8 +103,7 @@ redef class MClass
                        return ftype_cache
                end
 
-               var intro_nclassdef = v.toolcontext.modelbuilder.mclassdef2nclassdef[intro]
-               var ftype = intro_nclassdef.ftype
+               var ftype = intro.ftype
                if ftype == null then
                        var ftype_b: nullable ForeignType = null # FIXME hack to circumvent bug where ftype is typed null
 
index a2dda26..019d201 100644 (file)
@@ -32,6 +32,7 @@ import c
 import cpp
 import java
 import extra_java_files
+import objc
 
 redef class MModule
        # Does this module uses the FFI?
diff --git a/src/ffi/objc.nit b/src/ffi/objc.nit
new file mode 100644 (file)
index 0000000..9ab6f7f
--- /dev/null
@@ -0,0 +1,220 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# FFI support for Objective-C
+#
+# Compiles all Objective-C code with clang. The user module must define
+# the framework used.
+#
+# This module is heavily based on the C++ FFI.
+module objc
+
+import extern_classes
+import c
+
+redef class FFILanguageAssignationPhase
+       # The Objective-C language visitor
+       var objc_language: FFILanguage = new ObjCLanguage(self)
+end
+
+redef class MModule
+       private var objc_file: nullable ObjCCompilationUnit = null
+end
+
+# The Objective-C langugage visitor
+class ObjCLanguage
+       super FFILanguage
+
+       redef fun identify_language(n) do return n.is_objc
+
+       redef fun compile_module_block(block, ecc, mmodule)
+       do
+               if mmodule.objc_file == null then mmodule.objc_file = new ObjCCompilationUnit
+
+               if block.is_objc_header then
+                       mmodule.objc_file.header_custom.add block.location.as_line_pragma
+                       mmodule.objc_file.header_custom.add block.code
+               else if block.is_objc_body then
+                       mmodule.objc_file.body_custom.add block.location.as_line_pragma
+                       mmodule.objc_file.body_custom.add block.code
+               end
+       end
+
+       redef fun compile_extern_method(block, m, ecc, mmodule)
+       do
+               if mmodule.objc_file == null then mmodule.objc_file = new ObjCCompilationUnit
+
+               var mpropdef = m.mpropdef
+               var recv_mtype = mpropdef.mclassdef.bound_mtype
+               var csignature = mpropdef.mproperty.build_csignature(
+                       recv_mtype, mmodule, "___impl", long_signature, from_objc_call_context)
+
+               var fc = new CFunction(csignature)
+               fc.decls.add block.location.as_line_pragma
+               fc.exprs.add block.code
+               mmodule.objc_file.add_exported_function fc
+       end
+
+       redef fun compile_extern_class(block, m, ecc, mmodule) do end
+
+       redef fun get_ftype(block, m) do return new ForeignObjCType(block.code)
+
+       redef fun compile_to_files(mmodule, compdir)
+       do
+               var objc_file = mmodule.objc_file
+               assert objc_file != null
+
+               # write .m and _m.h file
+               mmodule.objc_file.header_c_types.add """
+       #include "{{{mmodule.cname}}}._ffi.h"
+"""
+
+               var file = objc_file.write_to_files(mmodule, compdir)
+
+               # add compilation to makefile
+               mmodule.ffi_files.add file
+       end
+
+       redef fun compile_callback(callback, mmodule, mainmodule, ecc)
+       do
+               callback.compile_callback_to_objc(mmodule, mainmodule)
+       end
+end
+
+redef class AExternCodeBlock
+       # Is this Objective-C code?
+       fun is_objc : Bool do return language_name != null and
+               (language_name_lowered == "objc" or language_name_lowered.has_prefix("objc "))
+
+       # Is this Objective-C code for the body file?
+       fun is_objc_body : Bool do return language_name != null and
+               (language_name_lowered == "objc" or language_name_lowered == "objc body")
+
+       # Is this Objective-C code for the header file?
+       fun is_objc_header : Bool do return language_name != null and
+               (language_name_lowered == "objc header")
+end
+
+private class ObjCCompilationUnit
+       super CCompilationUnit
+
+       # Write this compilation unit to Objective-C source files
+       fun write_to_files(mmodule: MModule, compdir: String): ExternObjCFile
+       do
+               var base_name = "{mmodule.cname}._ffi"
+
+               var h_file = "{base_name}_m.h"
+               var guard = "{mmodule.cname.to_s.to_upper}_NIT_OBJC_H"
+               write_header_to_file(mmodule, compdir/h_file, new Array[String], guard)
+
+               var c_file = "{base_name}.m"
+               write_body_to_file(mmodule, compdir/c_file, ["\"{h_file}\""])
+
+               files.add compdir/c_file
+
+               mmodule.c_linker_options = "{mmodule.c_linker_options} -lobjc"
+
+               return new ExternObjCFile(compdir/c_file, mmodule)
+       end
+end
+
+# A Objective-C file
+class ExternObjCFile
+       super ExternFile
+
+       # Associated `MModule`
+       var mmodule: MModule
+
+       redef fun makefile_rule_name do return "{filename.basename(".m")}_m.o"
+       redef fun makefile_rule_content do
+               return "clang $(CFLAGS) -c {filename.basename("")} -o {makefile_rule_name}"
+       end
+       redef fun compiles_to_o_file do return true
+end
+
+# An Objective-C type
+class ForeignObjCType
+       super ForeignType
+
+       # Type name
+       var objc_type: String
+end
+
+redef class NitniCallback
+       # Compile this callback to be callable from Objective-C
+       fun compile_callback_to_objc(mmodule: MModule, mainmodule: MModule) do end
+end
+
+redef class MExplicitCall
+       redef fun compile_callback_to_objc(mmodule, mainmodule)
+       do
+               var mproperty = mproperty
+               assert mproperty isa MMethod
+
+               var objc_signature = mproperty.build_csignature(recv_mtype, mainmodule, null, short_signature, from_objc_call_context)
+               var ccall = mproperty.build_ccall(recv_mtype, mainmodule, null, long_signature, from_objc_call_context, null)
+               var fc = new CFunction(objc_signature)
+               fc.exprs.add ccall
+               mmodule.objc_file.add_local_function fc
+       end
+end
+
+# Calls withing Objective-C code
+private fun objc_call_context: ObjCCallContext do return once new ObjCCallContext
+
+# Calls from C to Objective-C
+private fun to_objc_call_context: ToObjCCallContext do return once new ToObjCCallContext
+
+# Calls from Objective-C to C
+private fun from_objc_call_context: FromObjCCallContext do return once new FromObjCCallContext
+
+private class ObjCCallContext
+       super CallContext
+
+       redef fun name_mtype(mtype)
+       do
+               if mtype isa MClassType then
+                       var ftype = mtype.mclass.ftype
+                       if ftype isa ForeignObjCType then
+                               return ftype.objc_type
+                       end
+               end
+
+               return mtype.cname
+       end
+end
+
+private class ToObjCCallContext
+       super ObjCCallContext
+
+       redef fun cast_to(mtype, name)
+       do
+               if mtype isa MClassType and mtype.mclass.ftype isa ForeignObjCType then
+                       return "(void*)({name})"
+               else return name
+       end
+end
+
+private class FromObjCCallContext
+       super ObjCCallContext
+
+       redef fun cast_from(mtype, name)
+       do
+               if mtype isa MClassType and mtype.mclass.ftype isa ForeignObjCType then
+                       return "({name_mtype(mtype)})({name})"
+               else return name
+       end
+end
index cfdf85b..53c1a77 100644 (file)
@@ -23,6 +23,7 @@ import div_by_zero
 import cached
 import serialization_phase
 import check_annotation
+import glsl_validation
 
 redef class ToolContext
        # FIXME: there is conflict in linex in nitc, so use this trick to force invocation
diff --git a/src/frontend/glsl_validation.nit b/src/frontend/glsl_validation.nit
new file mode 100644 (file)
index 0000000..5dd6b79
--- /dev/null
@@ -0,0 +1,122 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Check shader code within Nit modules using the tool _glslangValidator_
+#
+# For this phase to work, _glslangValidator_ must be in PATH. It can be
+# downloaded from https://www.khronos.org/opengles/sdk/tools/Reference-Compiler/
+module glsl_validation
+
+import literal
+
+redef class ToolContext
+       # Shader code validation phase
+       var glsl_validation_phase: Phase = new GLSLValidationPhase(self, [literal_phase])
+end
+
+private class GLSLValidationPhase
+       super Phase
+
+       # Annotation names
+
+       fun annot_name_vertex: String do return "glsl_vertex_shader"
+       fun annot_name_fragment: String do return "glsl_fragment_shader"
+
+       # TODO support more shader types as needed
+
+       # Is the tool _glsllangValidator_ in path?
+       var tool_is_in_path: nullable Bool = null
+
+       redef fun process_annotated_node(nstring, nat)
+       do
+               var annot_name = nat.n_atid.n_id.text
+               var is_vertex = annot_name == annot_name_vertex
+               var is_fragment = annot_name == annot_name_fragment
+
+               # Skip if we are not interested
+               if not is_vertex and not is_fragment then return
+
+               # Only applicable on strings
+               if not nstring isa AStringFormExpr then
+                       toolcontext.error(nstring.location,
+                               "Syntax error: only a string literal can be annotated as \"{annot_name}\".")
+                       return
+               end
+
+               # Do not double check if tool is in path
+               var in_path = tool_is_in_path
+               if in_path != null then
+                       if not in_path then return
+               else
+                       # Is _glslangValidator_ installed?
+                       var proc_which = new IProcess("which", "glslangValidator")
+                       proc_which.wait
+                       proc_which.close
+                       var status = proc_which.status
+                       in_path = status == 0
+                       tool_is_in_path = in_path
+                       if not in_path then
+                               toolcontext.warning(nat.location, "glslvalidator",
+                                       "Warning: program \"glslangValidator\" not in PATH, cannot validate this shader.")
+                               return
+                       end
+               end
+
+               # Get the shader source
+               var shader = nstring.value
+               assert shader != null
+
+               # Copy the shader to a file
+               # TODO make it more portable
+               var tmp = "/tmp/"
+               var ext
+               if is_vertex then
+                       ext = "vert"
+               else ext = "frag"
+               var path = tmp / "nit_shader." + ext
+
+               shader.write_to_file path
+
+               # Execute the validator
+               var proc_validator = new IProcess("glslangValidator", path)
+               proc_validator.wait
+               var lines = proc_validator.read_all.split('\n')
+               proc_validator.close
+
+               # Parse errors
+               var regex = "[A-Z]+: ([0-9]+):([0-9]+): (.*)".to_re
+               for line in lines do
+                       var match = line.search(regex)
+
+                       # Does it match an error?
+                       # If not, then it should be the summary
+                       if match != null then
+                               var shader_line_no = match.subs[1].to_s.to_i
+                               var msg = match.subs[2].to_s
+
+                               var line_start = nstring.location.line_start + shader_line_no
+                               var char_start = 0
+                               var char_end = 0
+                               var loc = new Location(nat.location.file,
+                                       line_start, line_start,
+                                       char_start, char_end)
+
+                               toolcontext.warning(loc, "glslvalidator",
+                                       "Shader error on {msg}")
+                       end
+               end
+       end
+end
index 1165ac9..5e3acf1 100644 (file)
@@ -349,6 +349,8 @@ redef class MClassDef
                if mdoc == null then mdoc = mclass.intro.mdoc
                if mdoc != null then mdoc.fill_infobox(res)
 
+               if in_hierarchy == null then return res
+
                if in_hierarchy.greaters.length > 1 then
                        var c = res.new_dropdown("hier", "super-classes")
                        for x in in_hierarchy.greaters do
@@ -395,11 +397,11 @@ redef class MPropDef
                var res = new HInfoBox(v, to_s)
                res.href = href
                if self isa MMethodDef then
-                       res.new_field("fun").append(mproperty.name).add msignature.linkto
+                       if msignature != null then res.new_field("fun").append(mproperty.name).add msignature.linkto
                else if self isa MAttributeDef then
-                       res.new_field("fun").append(mproperty.name).add static_mtype.linkto
+                       if static_mtype != null then res.new_field("fun").append(mproperty.name).add static_mtype.linkto
                else if self isa MVirtualTypeDef then
-                       res.new_field("add").append(mproperty.name).add bound.linkto
+                       if bound != null then res.new_field("add").append(mproperty.name).add bound.linkto
                else
                        res.new_field("wat?").append(mproperty.name)
                end
index fc9ca2a..58a49d1 100644 (file)
@@ -103,7 +103,7 @@ redef class ToolContext
        redef fun check_errors
        do
                if dbg == null then
-                       super
+                       return super
                else
                        if messages.length > 0 then
                                message_sorter.sort(messages)
@@ -116,6 +116,7 @@ redef class ToolContext
 
                        messages.clear
                end
+               return not had_error
        end
 
        # -d
@@ -279,20 +280,13 @@ class Debugger
                assert args.length == mpropdef.msignature.arity + 1 else debug("Invalid arity for {mpropdef}. {args.length} arguments given.")
 
                # Look for the AST node that implements the property
-               var mproperty = mpropdef.mproperty
-               if self.modelbuilder.mpropdef2npropdef.has_key(mpropdef) then
-                       var npropdef = self.modelbuilder.mpropdef2npropdef[mpropdef]
-                       self.parameter_check(npropdef, mpropdef, args)
-                       if npropdef isa AMethPropdef then
-                               return npropdef.rt_call(self, mpropdef, args)
-                       else
-                               print "Error, invalid propdef to call at runtime !"
-                               return null
-                       end
-               else if mproperty.is_root_init then
-                       var nclassdef = self.modelbuilder.mclassdef2nclassdef[mpropdef.mclassdef]
-                       self.parameter_check(nclassdef, mpropdef, args)
-                       return nclassdef.call(self, mpropdef, args)
+               var node = modelbuilder.mpropdef2node(mpropdef)
+               if node isa AMethPropdef then
+                       self.parameter_check(node, mpropdef, args)
+                       return node.rt_call(self, mpropdef, args)
+               else if node isa AClassdef then
+                       self.parameter_check(node, mpropdef, args)
+                       return node.call(self, mpropdef, args)
                else
                        fatal("Fatal Error: method {mpropdef} not found in the AST")
                        abort
index 8e9ea77..064395d 100644 (file)
@@ -76,7 +76,7 @@ class NaiveInterpreter
                init_instance_primitive(self.true_instance)
                self.false_instance = new PrimitiveInstance[Bool](mainmodule.bool_type, false)
                init_instance_primitive(self.false_instance)
-               self.null_instance = new MutableInstance(mainmodule.model.null_type)
+               self.null_instance = new PrimitiveInstance[nullable Object](mainmodule.model.null_type, null)
        end
 
        # Starts the interpreter on the main module of a program
@@ -101,13 +101,14 @@ class NaiveInterpreter
        # Subtype test in the context of the mainmodule
        fun is_subtype(sub, sup: MType): Bool
        do
-               return sub.is_subtype(self.mainmodule, self.frame.arguments.first.mtype.as(MClassType), sup)
+               return sub.is_subtype(self.mainmodule, current_receiver_class, sup)
        end
 
+       # Get a primitive method in the context of the main module
        fun force_get_primitive_method(name: String, recv: MType): MMethod
        do
                assert recv isa MClassType
-               return self.modelbuilder.force_get_primitive_method(self.frame.current_node, name, recv.mclass, self.mainmodule)
+               return self.modelbuilder.force_get_primitive_method(current_node, name, recv.mclass, self.mainmodule)
        end
 
        # Is a return executed?
@@ -239,6 +240,8 @@ class NaiveInterpreter
                return res
        end
 
+       # Return a instance associated to a primitive class
+       # Current primitive classes are `Int`, `Bool`, and `String`
        fun value_instance(object: Object): Instance
        do
                if object isa Int then
@@ -290,13 +293,27 @@ class NaiveInterpreter
                return b.to_s
        end
 
+       # The current node, used to print errors, debug and stack-traces
+       fun current_node: nullable ANode
+       do
+               if frames.is_empty then return null
+               return frames.first.current_node
+       end
+
+       # The dynamic type of the current `self`
+       fun current_receiver_class: MClassType
+       do
+               return frames.first.arguments.first.mtype.as(MClassType)
+       end
+
        # Exit the program with a message
        fun fatal(message: String)
        do
-               if frames.is_empty then
+               var node = current_node
+               if node == null then
                        print message
                else
-                       self.frame.current_node.fatal(self, message)
+                       node.fatal(self, message)
                end
                exit(1)
        end
@@ -304,10 +321,11 @@ class NaiveInterpreter
        # Debug on the current node
        fun debug(message: String)
        do
-               if frames.is_empty then
+               var node = current_node
+               if node == null then
                        print message
                else
-                       self.frame.current_node.debug(message)
+                       node.debug(message)
                end
        end
 
@@ -384,16 +402,18 @@ class NaiveInterpreter
                assert args.length == mpropdef.msignature.arity + 1 else debug("Invalid arity for {mpropdef}. {args.length} arguments given.")
 
                # Look for the AST node that implements the property
-               var mproperty = mpropdef.mproperty
                var val = mpropdef.constant_value
-               if self.modelbuilder.mpropdef2npropdef.has_key(mpropdef) then
-                       var npropdef = self.modelbuilder.mpropdef2npropdef[mpropdef]
-                       self.parameter_check(npropdef, mpropdef, args)
-                       return npropdef.call(self, mpropdef, args)
-               else if mproperty.is_root_init then
-                       var nclassdef = self.modelbuilder.mclassdef2nclassdef[mpropdef.mclassdef]
-                       self.parameter_check(nclassdef, mpropdef, args)
-                       return nclassdef.call(self, mpropdef, args)
+
+               var node = modelbuilder.mpropdef2node(mpropdef)
+               if node isa APropdef then
+                       self.parameter_check(node, mpropdef, args)
+                       return node.call(self, mpropdef, args)
+               else if node isa AClassdef then
+                       self.parameter_check(node, mpropdef, args)
+                       return node.call(self, mpropdef, args)
+               else if node != null then
+                       fatal("Fatal Error: method {mpropdef} associated to unexpected AST node {node.location}")
+                       abort
                else if val != null then
                        return value_instance(val)
                else
@@ -402,7 +422,7 @@ class NaiveInterpreter
                end
        end
 
-       # Generate type checks in the C code to check covariant parameters
+       # Execute type checks of covariant parameters
        fun parameter_check(node: ANode, mpropdef: MMethodDef, args: Array[Instance])
        do
                var msignature = mpropdef.msignature
@@ -414,6 +434,8 @@ class NaiveInterpreter
                        var origmtype =  mpropdef.mproperty.intro.msignature.mparameters[i].mtype
                        if not origmtype.need_anchor then continue
 
+                       #print "{mpropdef}: {mpropdef.mproperty.intro.msignature.mparameters[i]}"
+
                        # get the parameter type
                        var mtype = msignature.mparameters[i].mtype
                        var anchor = args.first.mtype.as(MClassType)
@@ -457,7 +479,7 @@ class NaiveInterpreter
                                        self.send(p, args)
                                else if p isa MAttribute then
                                        assert recv isa MutableInstance
-                                       recv.attributes[p] = arguments[i]
+                                       write_attribute(p, recv, arguments[i])
                                        i += 1
                                else abort
                        end
@@ -517,13 +539,7 @@ class NaiveInterpreter
                var cds = mtype.collect_mclassdefs(self.mainmodule).to_a
                self.mainmodule.linearize_mclassdefs(cds)
                for cd in cds do
-                       if not self.modelbuilder.mclassdef2nclassdef.has_key(cd) then continue
-                       var n = self.modelbuilder.mclassdef2nclassdef[cd]
-                       for npropdef in n.n_propdefs do
-                               if npropdef isa AAttrPropdef then
-                                       res.add(npropdef)
-                               end
-                       end
+                       res.add_all(modelbuilder.collect_attr_propdef(cd))
                end
 
                cache[mtype] = res
@@ -551,10 +567,10 @@ class NaiveInterpreter
                return mainmodule.get_primitive_class(name)
        end
 
-       # This function determine the correct type according the reciever of the current definition (self).
+       # This function determines the correct type according to the receiver of the current propdef (self).
        fun unanchor_type(mtype: MType): MType
        do
-               return mtype.anchor_to(self.mainmodule, self.frame.arguments.first.mtype.as(MClassType))
+               return mtype.anchor_to(self.mainmodule, current_receiver_class)
        end
 
        # Placebo instance used to mark internal error result when `null` already have a meaning.
@@ -589,7 +605,7 @@ abstract class Instance
 
        # The real value encapsulated if the instance is primitive.
        # Else aborts.
-       fun val: Object do abort
+       fun val: nullable Object do abort
 end
 
 # A instance with attribute (standards objects)
@@ -602,7 +618,7 @@ end
 
 # Special instance to handle primitives values (int, bool, etc.)
 # The trick it just to encapsulate the <<real>> value
-class PrimitiveInstance[E: Object]
+class PrimitiveInstance[E]
        super Instance
 
        # The real value encapsulated
@@ -617,17 +633,17 @@ class PrimitiveInstance[E: Object]
 
        redef fun ==(o)
        do
-               if not o isa PrimitiveInstance[Object] then return false
+               if not o isa PrimitiveInstance[nullable Object] then return false
                return self.val == o.val
        end
 
        redef fun eq_is(o)
        do
-               if not o isa PrimitiveInstance[Object] then return false
+               if not o isa PrimitiveInstance[nullable Object] then return false
                return self.val.is_same_instance(o.val)
        end
 
-       redef fun to_s do return "{mtype}#{val.object_id}({val})"
+       redef fun to_s do return "{mtype}#{val.object_id}({val or else "null"})"
 
        redef fun to_i do return val.as(Int)
 
@@ -908,6 +924,8 @@ redef class AMethPropdef
                                return v.bool_instance(args[0].to_f.is_nan)
                        else if pname == "is_inf_extern" then
                                return v.bool_instance(args[0].to_f.is_inf != 0)
+                       else if pname == "round" then
+                               return v.float_instance(args[0].to_f.round)
                        end
                else if cname == "NativeString" then
                        if pname == "new" then
@@ -968,6 +986,14 @@ redef class AMethPropdef
                        else if pname == "atof" then
                                return v.float_instance(recvval.to_f)
                        end
+               else if cname == "String" then
+                       var cs = v.send(v.force_get_primitive_method("to_cstring", args.first.mtype), [args.first])
+                       var str = cs.val.to_s
+                       if pname == "files" then
+                               var res = new Array[Instance]
+                               for f in str.files do res.add v.string_instance(f)
+                               return v.array_instance(res, v.get_primitive_class("String").mclass_type)
+                       end
                else if pname == "calloc_string" then
                        return v.native_string_instance("!" * args[1].to_i)
                else if cname == "NativeArray" then
@@ -989,7 +1015,7 @@ redef class AMethPropdef
                        else if pname == "length" then
                                return v.int_instance(recvval.length)
                        else if pname == "copy_to" then
-                               recvval.copy(0, args[2].to_i, args[1].val.as(Array[Instance]), 0)
+                               recvval.copy_to(0, args[2].to_i, args[1].val.as(Array[Instance]), 0)
                                return null
                        end
                else if cname == "NativeFile" then
@@ -1094,13 +1120,6 @@ redef class AMethPropdef
        end
 end
 
-redef class AbstractArray[E]
-       fun copy(start: Int, len: Int, dest: AbstractArray[E], new_start: Int)
-       do
-               self.copy_to(start, len, dest, new_start)
-       end
-end
-
 redef class AAttrPropdef
        redef fun call(v, mpropdef, args)
        do
diff --git a/src/loader.nit b/src/loader.nit
new file mode 100644 (file)
index 0000000..14ec4fe
--- /dev/null
@@ -0,0 +1,607 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2012 Jean Privat <jean@pryen.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.
+
+# Loading of Nit source files
+module loader
+
+import modelbuilder_base
+
+redef class ToolContext
+       # Option --path
+       var opt_path = new OptionArray("Set include path for loaders (may be used more than once)", "-I", "--path")
+
+       # Option --only-metamodel
+       var opt_only_metamodel = new OptionBool("Stop after meta-model processing", "--only-metamodel")
+
+       # Option --only-parse
+       var opt_only_parse = new OptionBool("Only proceed to parse step of loaders", "--only-parse")
+
+       redef init
+       do
+               super
+               option_context.add_option(opt_path, opt_only_parse, opt_only_metamodel)
+       end
+end
+
+redef class ModelBuilder
+       redef init
+       do
+               super
+
+               # Setup the paths value
+               paths.append(toolcontext.opt_path.value)
+
+               var path_env = "NIT_PATH".environ
+               if not path_env.is_empty then
+                       paths.append(path_env.split_with(':'))
+               end
+
+               var nit_dir = toolcontext.nit_dir
+               var libname = "{nit_dir}/lib"
+               if libname.file_exists then paths.add(libname)
+       end
+
+       # Load a bunch of modules.
+       # `modules` can contains filenames or module names.
+       # Imported modules are automatically loaded and modelized.
+       # The result is the corresponding model elements.
+       # Errors and warnings are printed with the toolcontext.
+       #
+       # Note: class and property model elements are not analysed.
+       fun parse(modules: 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 modules do
+                       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:
+       #
+       #   * the toolcontext --path option
+       #   * the NIT_PATH environment variable
+       #   * `toolcontext.nit_dir`
+       # Path can be added (or removed) by the client
+       var paths = new Array[String]
+
+       # Like (and used by) `get_mmodule_by_name` but just return the ModulePath
+       fun search_mmodule_by_name(anode: nullable ANode, mgroup: nullable MGroup, name: String): nullable ModulePath
+       do
+               # First, look in groups
+               var c = mgroup
+               while c != null do
+                       var dirname = c.filepath
+                       if dirname == null then break # virtual group
+                       if dirname.has_suffix(".nit") then break # singleton project
+
+                       # Second, try the directory to find a file
+                       var try_file = dirname + "/" + name + ".nit"
+                       if try_file.file_exists then
+                               var res = self.identify_file(try_file.simplify_path)
+                               assert res != null
+                               return res
+                       end
+
+                       # Third, try if the requested module is itself a group
+                       try_file = dirname + "/" + name + "/" + name + ".nit"
+                       if try_file.file_exists then
+                               var res = self.identify_file(try_file.simplify_path)
+                               assert res != null
+                               return res
+                       end
+
+                       c = c.parent
+               end
+
+               # Look at some known directories
+               var lookpaths = self.paths
+
+               # Look in the directory of the group project also (even if not explicitly in the path)
+               if mgroup != null then
+                       # path of the root group
+                       var dirname = mgroup.mproject.root.filepath
+                       if dirname != null then
+                               dirname = dirname.join_path("..").simplify_path
+                               if not lookpaths.has(dirname) and dirname.file_exists then
+                                       lookpaths = lookpaths.to_a
+                                       lookpaths.add(dirname)
+                               end
+                       end
+               end
+
+               var candidate = search_module_in_paths(anode.hot_location, name, lookpaths)
+
+               if candidate == null then
+                       if mgroup != null then
+                               error(anode, "Error: cannot find module {name} from {mgroup.name}. tried {lookpaths.join(", ")}")
+                       else
+                               error(anode, "Error: cannot find module {name}. tried {lookpaths.join(", ")}")
+                       end
+                       return null
+               end
+               return candidate
+       end
+
+       # Get a module by its short name; if required, the module is loaded, parsed and its hierarchies computed.
+       # If `mgroup` is set, then the module search starts from it up to the top level (see `paths`);
+       # if `mgroup` is null then the module is searched in the top level only.
+       # If no module exists or there is a name conflict, then an error on `anode` is displayed and null is returned.
+       fun get_mmodule_by_name(anode: nullable ANode, mgroup: nullable MGroup, name: String): nullable MModule
+       do
+               var path = search_mmodule_by_name(anode, mgroup, name)
+               if path == null then return null # Forward error
+               var res = self.load_module(path.filepath)
+               if res == null then return null # Forward error
+               # Load imported module
+               build_module_importation(res)
+               return res.mmodule.as(not null)
+       end
+
+       # Search a module `name` from path `lookpaths`.
+       # If found, the path of the file is returned
+       private fun search_module_in_paths(location: nullable Location, name: String, lookpaths: Collection[String]): nullable ModulePath
+       do
+               var candidate: nullable String = null
+               for dirname in lookpaths do
+                       var try_file = (dirname + "/" + name + ".nit").simplify_path
+                       if try_file.file_exists then
+                               if candidate == null then
+                                       candidate = try_file
+                               else if candidate != try_file then
+                                       # try to disambiguate conflicting modules
+                                       var abs_candidate = module_absolute_path(candidate)
+                                       var abs_try_file = module_absolute_path(try_file)
+                                       if abs_candidate != abs_try_file then
+                                               toolcontext.error(location, "Error: conflicting module file for {name}: {candidate} {try_file}")
+                                       end
+                               end
+                       end
+                       try_file = (dirname + "/" + name + "/" + name + ".nit").simplify_path
+                       if try_file.file_exists then
+                               if candidate == null then
+                                       candidate = try_file
+                               else if candidate != try_file then
+                                       # try to disambiguate conflicting modules
+                                       var abs_candidate = module_absolute_path(candidate)
+                                       var abs_try_file = module_absolute_path(try_file)
+                                       if abs_candidate != abs_try_file then
+                                               toolcontext.error(location, "Error: conflicting module file for {name}: {candidate} {try_file}")
+                                       end
+                               end
+                       end
+               end
+               if candidate == null then return null
+               return identify_file(candidate)
+       end
+
+       # Cache for `identify_file` by realpath
+       private var identified_files_by_path = new HashMap[String, nullable ModulePath]
+
+       # All the currently identified modules.
+       # See `identify_file`.
+       var identified_files = new Array[ModulePath]
+
+       # Identify a source file
+       # Load the associated project and groups if required
+       #
+       # Silently return `null` if `path` is not a valid module path.
+       fun identify_file(path: String): nullable ModulePath
+       do
+               # special case for not a nit file
+               if path.file_extension != "nit" then
+                       # search dirless files in known -I paths
+                       if path.dirname == "" then
+                               var res = search_module_in_paths(null, path, self.paths)
+                               if res != null then return res
+                       end
+
+                       # Found nothing? maybe it is a group...
+                       var candidate = null
+                       if path.file_exists then
+                               var mgroup = get_mgroup(path)
+                               if mgroup != null then
+                                       var owner_path = mgroup.filepath.join_path(mgroup.name + ".nit")
+                                       if owner_path.file_exists then candidate = owner_path
+                               end
+                       end
+
+                       if candidate == null then
+                               return null
+                       end
+                       path = candidate
+               end
+
+               # Fast track, the path is already known
+               var pn = path.basename(".nit")
+               var rp = module_absolute_path(path)
+               if identified_files_by_path.has_key(rp) then return identified_files_by_path[rp]
+
+               # Search for a group
+               var mgrouppath = path.join_path("..").simplify_path
+               var mgroup = get_mgroup(mgrouppath)
+
+               if mgroup == null then
+                       # singleton project
+                       var mproject = new MProject(pn, model)
+                       mgroup = new MGroup(pn, mproject, null) # same name for the root group
+                       mgroup.filepath = path
+                       mproject.root = mgroup
+                       toolcontext.info("found project `{pn}` at {path}", 2)
+               end
+
+               var res = new ModulePath(pn, path, mgroup)
+               mgroup.module_paths.add(res)
+
+               identified_files_by_path[rp] = res
+               identified_files.add(res)
+               return res
+       end
+
+       # Groups by path
+       private var mgroups = new HashMap[String, nullable MGroup]
+
+       # Return the mgroup associated to a directory path.
+       # If the directory is not a group null is returned.
+       fun get_mgroup(dirpath: String): nullable MGroup
+       do
+               var rdp = module_absolute_path(dirpath)
+               if mgroups.has_key(rdp) then
+                       return mgroups[rdp]
+               end
+
+               # Hack, a group is determined by:
+               # * the presence of a honomymous nit file
+               # * the fact that the directory is named `src`
+               var pn = rdp.basename(".nit")
+               var mp = dirpath.join_path(pn + ".nit").simplify_path
+
+               var dirpath2 = dirpath
+               if not mp.file_exists then
+                       if pn == "src" then
+                               # With a src directory, the group name is the name of the parent directory
+                               dirpath2 = rdp.dirname
+                               pn = dirpath2.basename("")
+                       else
+                               return null
+                       end
+               end
+
+               # check parent directory
+               var parentpath = dirpath.join_path("..").simplify_path
+               var parent = get_mgroup(parentpath)
+
+               var mgroup
+               if parent == null then
+                       # no parent, thus new project
+                       var mproject = new MProject(pn, model)
+                       mgroup = new MGroup(pn, mproject, null) # same name for the root group
+                       mproject.root = mgroup
+                       toolcontext.info("found project `{mproject}` at {dirpath}", 2)
+               else
+                       mgroup = new MGroup(pn, parent.mproject, parent)
+                       toolcontext.info("found sub group `{mgroup.full_name}` at {dirpath}", 2)
+               end
+               var readme = dirpath2.join_path("README.md")
+               if not readme.file_exists then readme = dirpath2.join_path("README")
+               if readme.file_exists then
+                       var mdoc = new MDoc
+                       var s = new IFStream.open(readme)
+                       while not s.eof do
+                               mdoc.content.add(s.read_line)
+                       end
+                       mgroup.mdoc = mdoc
+                       mdoc.original_mentity = mgroup
+               end
+               mgroup.filepath = dirpath
+               mgroups[rdp] = mgroup
+               return mgroup
+       end
+
+       # Force the identification of all ModulePath of the group and sub-groups.
+       fun visit_group(mgroup: MGroup) do
+               var p = mgroup.filepath
+               for f in p.files do
+                       var fp = p/f
+                       var g = get_mgroup(fp)
+                       if g != null then visit_group(g)
+                       identify_file(fp)
+               end
+       end
+
+       # Transform relative paths (starting with '../') into absolute paths
+       private fun module_absolute_path(path: String): String do
+               return getcwd.join_path(path).simplify_path
+       end
+
+       # Try to load a module AST using a path.
+       # Display an error if there is a problem (IO / lexer / parser) and return null
+       fun load_module_ast(filename: String): nullable AModule
+       do
+               if filename.file_extension != "nit" then
+                       self.toolcontext.error(null, "Error: file {filename} is not a valid nit module.")
+                       return null
+               end
+               if not filename.file_exists then
+                       self.toolcontext.error(null, "Error: file {filename} not found.")
+                       return null
+               end
+
+               self.toolcontext.info("load module {filename}", 2)
+
+               # Load the file
+               var file = new IFStream.open(filename)
+               var lexer = new Lexer(new SourceFile(filename, file))
+               var parser = new Parser(lexer)
+               var tree = parser.parse
+               file.close
+
+               # Handle lexer and parser error
+               var nmodule = tree.n_base
+               if nmodule == null then
+                       var neof = tree.n_eof
+                       assert neof isa AError
+                       error(neof, neof.message)
+                       return null
+               end
+
+               return nmodule
+       end
+
+       # Try to load a module using a path.
+       # Display an error if there is a problem (IO / lexer / parser) and return null.
+       # Note: usually, you do not need this method, use `get_mmodule_by_name` instead.
+       #
+       # The MModule is created however, the importation is not performed,
+       # therefore you should call `build_module_importation`.
+       fun load_module(filename: String): nullable AModule
+       do
+               # Look for the module
+               var file = identify_file(filename)
+               if file == null then
+                       toolcontext.error(null, "Error: cannot find module `{filename}`.")
+                       return null
+               end
+
+               # Already known and loaded? then return it
+               var mmodule = file.mmodule
+               if mmodule != null then
+                       return mmodule2nmodule[mmodule]
+               end
+
+               # Load it manually
+               var nmodule = load_module_ast(file.filepath)
+               if nmodule == null then return null # forward error
+
+               # build the mmodule and load imported modules
+               mmodule = build_a_mmodule(file.mgroup, file.name, nmodule)
+
+               if mmodule == null then return null # forward error
+
+               # Update the file information
+               file.mmodule = mmodule
+
+               return nmodule
+       end
+
+       # Injection of a new module without source.
+       # Used by the interpreter.
+       fun load_rt_module(parent: nullable MModule, nmodule: AModule, mod_name: String): nullable AModule
+       do
+               # Create the module
+
+               var mgroup = null
+               if parent != null then mgroup = parent.mgroup
+               var mmodule = new MModule(model, mgroup, mod_name, nmodule.location)
+               nmodule.mmodule = mmodule
+               nmodules.add(nmodule)
+               self.mmodule2nmodule[mmodule] = nmodule
+
+               if parent!= null then
+                       var imported_modules = new Array[MModule]
+                       imported_modules.add(parent)
+                       mmodule.set_visibility_for(parent, intrude_visibility)
+                       mmodule.set_imported_mmodules(imported_modules)
+               else
+                       build_module_importation(nmodule)
+               end
+
+               return nmodule
+       end
+
+       # Visit the AST and create the `MModule` object
+       private fun build_a_mmodule(mgroup: nullable MGroup, mod_name: String, nmodule: AModule): nullable MModule
+       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
+                       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}")
+                       end
+               end
+
+               # Create the module
+               var mmodule = new MModule(model, mgroup, mod_name, nmodule.location)
+               nmodule.mmodule = mmodule
+               nmodules.add(nmodule)
+               self.mmodule2nmodule[mmodule] = nmodule
+
+               if decl != null then
+                       var ndoc = decl.n_doc
+                       if ndoc != null then
+                               var mdoc = ndoc.to_mdoc
+                               mmodule.mdoc = mdoc
+                               mdoc.original_mentity = mmodule
+                       else
+                               advice(decl, "missing-doc", "Documentation warning: Undocumented module `{mmodule}`")
+                       end
+               end
+
+               return mmodule
+       end
+
+       # Analyze the module importation and fill the module_importation_hierarchy
+       #
+       # Unless you used `load_module`, the importation is already done and this method does a no-op.
+       fun build_module_importation(nmodule: AModule)
+       do
+               if nmodule.is_importation_done then return
+               nmodule.is_importation_done = true
+               var mmodule = nmodule.mmodule.as(not null)
+               var stdimport = true
+               var imported_modules = new Array[MModule]
+               for aimport in nmodule.n_imports do
+                       stdimport = false
+                       if not aimport isa AStdImport then
+                               continue
+                       end
+                       var mgroup = mmodule.mgroup
+                       if aimport.n_name.n_quad != null then mgroup = null # Start from top level
+                       for grp in aimport.n_name.n_path do
+                               var path = search_mmodule_by_name(grp, mgroup, grp.text)
+                               if path == null then return # Skip error
+                               mgroup = path.mgroup
+                       end
+                       var mod_name = aimport.n_name.n_id.text
+                       var sup = self.get_mmodule_by_name(aimport.n_name, mgroup, mod_name)
+                       if sup == null then continue # Skip error
+                       aimport.mmodule = sup
+                       imported_modules.add(sup)
+                       var mvisibility = aimport.n_visibility.mvisibility
+                       if mvisibility == protected_visibility then
+                               error(aimport.n_visibility, "Error: only properties can be protected.")
+                               return
+                       end
+                       if sup == mmodule then
+                               error(aimport.n_name, "Error: Dependency loop in module {mmodule}.")
+                       end
+                       if sup.in_importation < mmodule then
+                               error(aimport.n_name, "Error: Dependency loop between modules {mmodule} and {sup}.")
+                               return
+                       end
+                       mmodule.set_visibility_for(sup, mvisibility)
+               end
+               if stdimport then
+                       var mod_name = "standard"
+                       var sup = self.get_mmodule_by_name(nmodule, null, mod_name)
+                       if sup != null then # Skip error
+                               imported_modules.add(sup)
+                               mmodule.set_visibility_for(sup, public_visibility)
+                       end
+               end
+               self.toolcontext.info("{mmodule} imports {imported_modules.join(", ")}", 3)
+               mmodule.set_imported_mmodules(imported_modules)
+
+               # Force standard to be public if imported
+               for sup in mmodule.in_importation.greaters do
+                       if sup.name == "standard" then
+                               mmodule.set_visibility_for(sup, public_visibility)
+                       end
+               end
+
+               # TODO: Correctly check for useless importation
+               # It is even doable?
+               var directs = mmodule.in_importation.direct_greaters
+               for nim in nmodule.n_imports do
+                       if not nim isa AStdImport then continue
+                       var im = nim.mmodule
+                       if im == null then continue
+                       if directs.has(im) then continue
+                       # This generates so much noise that it is simpler to just comment it
+                       #warning(nim, "Warning: possible useless importation of {im}")
+               end
+       end
+
+       # All the loaded modules
+       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]
+end
+
+# File-system location of a module (file) that is identified but not always loaded.
+class ModulePath
+       # The name of the module
+       # (it's the basename of the filepath)
+       var name: String
+
+       # The human path of the module
+       var filepath: String
+
+       # The group (and the project) of the possible module
+       var mgroup: MGroup
+
+       # The loaded module (if any)
+       var mmodule: nullable MModule = null
+
+       redef fun to_s do return filepath
+end
+
+redef class MGroup
+       # Modules paths associated with the group
+       var module_paths = new Array[ModulePath]
+
+       # Is the group interesting for a final user?
+       #
+       # Groups are mandatory in the model but for simple projects they are not
+       # always interesting.
+       #
+       # A interesting group has, at least, one of the following true:
+       #
+       # * it has 2 modules or more
+       # * it has a subgroup
+       # * it has a documentation
+       fun is_interesting: Bool
+       do
+               return module_paths.length > 1 or mmodules.length > 1 or not in_nesting.direct_smallers.is_empty or mdoc != null
+       end
+
+end
+
+redef class AStdImport
+       # The imported module once determined
+       var mmodule: nullable MModule = null
+end
+
+redef class AModule
+       # The associated MModule once build by a `ModelBuilder`
+       var mmodule: nullable MModule
+       # Flag that indicate if the importation is already completed
+       var is_importation_done: Bool = false
+end
index 993ce7d..e82775a 100644 (file)
@@ -54,7 +54,16 @@ class Location
        var file: nullable SourceFile
        var line_start: Int
        var line_end: Int
+
+       # Start of this location on `line_start`
+       #
+       # A `column_start` of 1 means the first column or character.
+       #
+       # If `column_start == 0` this location concerns the whole line.
+       #
+       # Require: `column_start >= 0`
        var column_start: Int
+
        var column_end: Int
 
        # The index in the start character in the source
@@ -174,7 +183,12 @@ class Location
                while line_end+1 < string.length and string.chars[line_end+1] != '\n' and string.chars[line_end+1] != '\r' do
                        line_end += 1
                end
-               var lstart = string.substring(line_start, l.column_start - 1)
+               var lstart
+               if l.column_start > 0 then
+                       lstart = string.substring(line_start, l.column_start - 1)
+               else
+                       lstart = ""
+               end
                var cend
                if i != l.line_end then
                        cend = line_end - line_start + 1
index 6c63925..1ee1db2 100644 (file)
@@ -102,7 +102,8 @@ private class MendelMetricsPhase
                end
 
                if csv then
-                       var csvh = new CSVDocument
+                       var csvh = new CsvDocument
+                       csvh.format = new CsvFormat('"', ';', "\n")
                        csvh.header = ["povr", "ovr", "pext", "ext", "pspe", "spe", "prep", "rep", "eq"]
                        for mclass in mclasses do
                                var povr = mclass.is_pure_overrider(vis).object_id
@@ -114,7 +115,7 @@ private class MendelMetricsPhase
                                var prep = mclass.is_pure_replacer(vis).object_id
                                var rep = mclass.is_replacer(vis).object_id
                                var eq = mclass.is_equal(vis).object_id
-                               csvh.add_line(povr, ovr, pext, ext, pspe, spe, prep, rep, eq)
+                               csvh.add_record(povr, ovr, pext, ext, pspe, spe, prep, rep, eq)
                        end
                        csvh.save("{out}/inheritance_behaviour.csv")
                end
index b55e1b8..c51e656 100644 (file)
@@ -367,8 +367,10 @@ class MetricSet
        end
 
        # Export the metric set in CSV format
-       fun to_csv: CSVDocument do
-               var csv = new CSVDocument
+       fun to_csv: CsvDocument do
+               var csv = new CsvDocument
+
+               csv.format = new CsvFormat('"', ';', "\n")
 
                # set csv headers
                csv.header.add("entry")
@@ -390,7 +392,7 @@ class MetricSet
                                        line.add("n/a")
                                end
                        end
-                       csv.lines.add(line)
+                       csv.records.add(line)
                end
                return csv
        end
index abc733a..2f8d045 100644 (file)
@@ -33,6 +33,16 @@ redef class MEntity
        # The documentation associated to the entity
        var mdoc: nullable MDoc is writable
 
+       # The documentation associated to the entity or their main nested entity.
+       #
+       # MProject fall-back to their root MGroup
+       # MGroup fall-back to their default_mmodule
+       # Other entities do not fall-back
+       #
+       # One may use `MDoc::original_mentity` to retrieve the original
+       # source of the documentation.
+       fun mdoc_or_fallback: nullable MDoc do return mdoc
+
        # Is the entity deprecated?
        #
        # Used for warnings and in documentation.
index f2c11a6..c634815 100644 (file)
@@ -27,12 +27,6 @@ redef class Model
        # All known modules
        var mmodules = new Array[MModule]
 
-       # placebo for old module nesting hierarchy.
-       # where mainmodule < mainmodule::nestedmodule
-       #
-       # TODO REMOVE, rely on mgroup instead
-       var mmodule_nesting_hierarchy = new POSet[MModule]
-
        # Full module importation hierarchy including private or nested links.
        var mmodule_importation_hierarchy = new POSet[MModule]
 
@@ -63,6 +57,13 @@ redef class MGroup
        # Return `null` if the group has no default module or if the default
        # module is not loaded.
        var default_mmodule: nullable MModule = null
+
+       redef fun mdoc_or_fallback
+       do
+               if mdoc != null then return mdoc
+               if default_mmodule == null then return null
+               return default_mmodule.mdoc_or_fallback
+       end
 end
 
 # A Nit module is usually associated with a Nit source file.
@@ -84,12 +85,6 @@ class MModule
        # Alias for `name`
        redef fun to_s do return self.name
 
-       # placebo for old module nesting hierarchy
-       # The view of the module in the `model.mmodule_nesting_hierarchy`
-       #
-       # TODO REMOVE, rely on mgroup instead
-       var in_nesting: POSetElement[MModule] is noinit
-
        # The view of the module in the `model.mmodule_importation_hierarchy`
        var in_importation: POSetElement[MModule] is noinit
 
@@ -110,7 +105,6 @@ class MModule
        do
                model.mmodules_by_name.add_one(name, self)
                model.mmodules.add(self)
-               self.in_nesting = model.mmodule_nesting_hierarchy.add_node(self)
                if mgroup != null then
                        mgroup.mmodules.add(self)
                        if mgroup.name == name then
@@ -120,17 +114,9 @@ class MModule
                        # placebo for old module nesting hierarchy
                        var direct_owner = mgroup.default_mmodule
                        if direct_owner == self then
-                               # The module is the new owner of its own group, thus adopt the other modules
-                               for m in mgroup.mmodules do
-                                       if m == self then continue
-                                       model.mmodule_nesting_hierarchy.add_edge(self, m)
-                               end
                                # The potential owner is the default_mmodule of the parent group
                                if mgroup.parent != null then direct_owner = mgroup.parent.default_mmodule
                        end
-                       if direct_owner != self and direct_owner != null then
-                               model.mmodule_nesting_hierarchy.add_edge(direct_owner, self)
-                       end
                end
                self.in_importation = model.mmodule_importation_hierarchy.add_node(self)
        end
index f5582d8..899f023 100644 (file)
@@ -263,7 +263,7 @@ redef class MModule
                        var msg = "Fatal Error: more than one primitive class {name}:"
                        for c in cla do msg += " {c.full_name}"
                        print msg
-                       exit(1)
+                       #exit(1)
                end
                return cla.first
        end
@@ -388,7 +388,7 @@ class MClass
                        self.mparameters = mparametertypes
                        var mclass_type = new MGenericType(self, mparametertypes)
                        self.mclass_type = mclass_type
-                       self.get_mtype_cache.add(mclass_type)
+                       self.get_mtype_cache[mparametertypes] = mclass_type
                else
                        self.mclass_type = new MClassType(self)
                end
@@ -458,17 +458,14 @@ class MClass
        do
                assert mtype_arguments.length == self.arity
                if self.arity == 0 then return self.mclass_type
-               for t in self.get_mtype_cache do
-                       if t.arguments == mtype_arguments then
-                               return t
-                       end
-               end
-               var res = new MGenericType(self, mtype_arguments)
-               self.get_mtype_cache.add res
+               var res = get_mtype_cache.get_or_null(mtype_arguments)
+               if res != null then return res
+               res = new MGenericType(self, mtype_arguments)
+               self.get_mtype_cache[mtype_arguments.to_a] = res
                return res
        end
 
-       private var get_mtype_cache = new Array[MGenericType]
+       private var get_mtype_cache = new HashMap[Array[MType], MGenericType]
 end
 
 
@@ -631,24 +628,18 @@ abstract class MType
        do
                var sub = self
                if sub == sup then return true
+
+               #print "1.is {sub} a {sup}? ===="
+
                if anchor == null then
                        assert not sub.need_anchor
                        assert not sup.need_anchor
                else
+                       # First, resolve the formal types to the simplest equivalent forms in the receiver
                        assert sub.can_resolve_for(anchor, null, mmodule)
+                       sub = sub.lookup_fixed(mmodule, anchor)
                        assert sup.can_resolve_for(anchor, null, mmodule)
-               end
-
-               # First, resolve the formal types to a common version in the receiver
-               # The trick here is that fixed formal type will be associated to the bound
-               # And unfixed formal types will be associated to a canonical formal type.
-               if sub isa MParameterType or sub isa MVirtualType then
-                       assert anchor != null
-                       sub = sub.resolve_for(anchor.mclass.mclass_type, anchor, mmodule, false)
-               end
-               if sup isa MParameterType or sup isa MVirtualType then
-                       assert anchor != null
-                       sup = sup.resolve_for(anchor.mclass.mclass_type, anchor, mmodule, false)
+                       sup = sup.lookup_fixed(mmodule, anchor)
                end
 
                # Does `sup` accept null or not?
@@ -672,15 +663,17 @@ abstract class MType
                end
                # Now the case of direct null and nullable is over.
 
-               # A unfixed formal type can only accept itself
-               if sup isa MParameterType or sup isa MVirtualType then
-                       return sub == sup
-               end
-
                # If `sub` is a formal type, then it is accepted if its bound is accepted
-               if sub isa MParameterType or sub isa MVirtualType then
+               while sub isa MParameterType or sub isa MVirtualType do
+                       #print "3.is {sub} a {sup}?"
+
+                       # A unfixed formal type can only accept itself
+                       if sub == sup then return true
+
                        assert anchor != null
-                       sub = sub.anchor_to(mmodule, anchor)
+                       sub = sub.lookup_bound(mmodule, anchor)
+
+                       #print "3.is {sub} a {sup}?"
 
                        # Manage the second layer of null/nullable
                        if sub isa MNullableType then
@@ -690,9 +683,15 @@ abstract class MType
                                return sup_accept_null
                        end
                end
+               #print "4.is {sub} a {sup}? <- no more resolution"
 
                assert sub isa MClassType # It is the only remaining type
 
+               # A unfixed formal type can only accept itself
+               if sup isa MParameterType or sup isa MVirtualType then
+                       return false
+               end
+
                if sup isa MNullType then
                        # `sup` accepts only null
                        return false
@@ -732,6 +731,7 @@ abstract class MType
        # types to their bounds.
        #
        # Example
+       #
        #     class A end
        #     class B super A end
        #     class X end
@@ -743,6 +743,7 @@ abstract class MType
        #       super G[B]
        #       redef type U: Y
        #     end
+       #
        # Map[T,U]  anchor_to  H  #->  Map[B,Y]
        #
        # Explanation of the example:
@@ -771,9 +772,13 @@ abstract class MType
        # In Nit, for each super-class of a type, there is a equivalent super-type.
        #
        # Example:
+       #
+       # ~~~nitish
        #     class G[T, U] end
        #     class H[V] super G[V, Bool] end
+       #
        # H[Int]  supertype_to  G  #->  G[Int, Bool]
+       # ~~~
        #
        # REQUIRE: `super_mclass` is a super-class of `self`
        # REQUIRE: `self.need_anchor implies anchor != null and self.can_resolve_for(anchor, null, mmodule)`
@@ -807,9 +812,11 @@ abstract class MType
        #
        # ## Example 1
        #
-       #     class G[E] end
-       #     class H[F] super G[F] end
-       #     class X[Z] end
+       # ~~~
+       # class G[E] end
+       # class H[F] super G[F] end
+       # class X[Z] end
+       # ~~~
        #
        #  * Array[E].resolve_for(H[Int])  #->  Array[Int]
        #  * Array[E].resolve_for(G[Z], X[Int]) #->  Array[Z]
@@ -827,30 +834,34 @@ abstract class MType
        #
        # ## Example 2
        #
-       #     class A[E]
-       #         fun foo(e:E):E is abstract
-       #     end
-       #     class B super A[Int] end
+       # ~~~
+       # class A[E]
+       #     fun foo(e:E):E is abstract
+       # end
+       # class B super A[Int] end
+       # ~~~
        #
        # The signature on foo is (e: E): E
        # If we resolve the signature for B, we get (e:Int):Int
        #
        # ## Example 3
        #
-       #     class A[E]
-       #         fun foo(e:E) is abstract
-       #     end
-       #     class B[F]
-       #         var a: A[Array[F]]
-       #         fun bar do a.foo(x) # <- x is here
-       #     end
+       # ~~~nitish
+       # class A[E]
+       #     fun foo(e:E):E is abstract
+       # end
+       # class C[F]
+       #     var a: A[Array[F]]
+       #     fun bar do a.foo(x) # <- x is here
+       # end
+       # ~~~
        #
        # The first question is: is foo available on `a`?
        #
        # The static type of a is `A[Array[F]]`, that is an open type.
        # in order to find a method `foo`, whe must look at a resolved type.
        #
-       #   A[Array[F]].anchor_to(B[nullable Object])  #->  A[Array[nullable Object]]
+       #   A[Array[F]].anchor_to(C[nullable Object])  #->  A[Array[nullable Object]]
        #
        # the method `foo` exists in `A[Array[nullable Object]]`, therefore `foo` exists for `a`.
        #
@@ -858,7 +869,7 @@ abstract class MType
        #
        # the signature of `foo` is `foo(e:E)`, thus we must resolve the type E
        #
-       #   E.resolve_for(A[Array[F]],B[nullable Object])  #->  Array[F]
+       #   E.resolve_for(A[Array[F]],C[nullable Object])  #->  Array[F]
        #
        # The resolution can be done because `E` make sense for the class A (see `can_resolve_for`)
        #
@@ -869,6 +880,28 @@ abstract class MType
        # ENSURE: `not self.need_anchor implies result == self`
        fun resolve_for(mtype: MType, anchor: nullable MClassType, mmodule: MModule, cleanup_virtual: Bool): MType is abstract
 
+       # Resolve formal type to its verbatim bound.
+       # If the type is not formal, just return self
+       #
+       # The result is returned exactly as declared in the "type" property (verbatim).
+       # So it could be another formal type.
+       #
+       # In case of conflict, the method aborts.
+       fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType do return self
+
+       # Resolve the formal type to its simplest equivalent form.
+       #
+       # Formal types are either free or fixed.
+       # When it is fixed, it means that it is equivalent with a simpler type.
+       # When a formal type is free, it means that it is only equivalent with itself.
+       # This method return the most simple equivalent type of `self`.
+       #
+       # This method is mainly used for subtype test in order to sanely compare fixed.
+       #
+       # By default, return self.
+       # See the redefinitions for specific behavior in each kind of type.
+       fun lookup_fixed(mmodule: MModule, resolved_receiver: MType): MType do return self
+
        # Can the type be resolved?
        #
        # In order to resolve open types, the formal types must make sence.
@@ -880,11 +913,15 @@ abstract class MType
        #     class B[F]
        #     end
        #
-       #  * E.can_resolve_for(A[Int])  #->  true, E make sense in A
-       #  * E.can_resolve_for(B[Int])  #->  false, E does not make sense in B
-       #  * B[E].can_resolve_for(A[F], B[Object])  #->  true,
-       #    B[E] is a red hearing only the E is important,
-       #    E make sense in A
+       # ~~~nitish
+       # E.can_resolve_for(A[Int])  #->  true, E make sense in A
+       #
+       # E.can_resolve_for(B[Int])  #->  false, E does not make sense in B
+       #
+       # B[E].can_resolve_for(A[F], B[Object])  #->  true,
+       # # B[E] is a red hearing only the E is important,
+       # # E make sense in A
+       # ~~~
        #
        # REQUIRE: `anchor != null implies not anchor.need_anchor`
        # REQUIRE: `mtype.need_anchor implies anchor != null and mtype.can_resolve_for(anchor, null, mmodule)`
@@ -1017,14 +1054,21 @@ class MClassType
 
        redef fun collect_mclasses(mmodule)
        do
+               if collect_mclasses_last_module == mmodule then return collect_mclasses_last_module_cache
                assert not self.need_anchor
                var cache = self.collect_mclasses_cache
                if not cache.has_key(mmodule) then
                        self.collect_things(mmodule)
                end
-               return cache[mmodule]
+               var res = cache[mmodule]
+               collect_mclasses_last_module = mmodule
+               collect_mclasses_last_module_cache = res
+               return res
        end
 
+       private var collect_mclasses_last_module: nullable MModule = null
+       private var collect_mclasses_last_module_cache: Set[MClass] is noinit
+
        redef fun collect_mtypes(mmodule)
        do
                assert not self.need_anchor
@@ -1148,86 +1192,85 @@ class MVirtualType
 
        # The property associated with the type.
        # Its the definitions of this property that determine the bound or the virtual type.
-       var mproperty: MProperty
+       var mproperty: MVirtualTypeProp
 
        redef fun model do return self.mproperty.intro_mclassdef.mmodule.model
 
-       # Lookup the bound for a given resolved_receiver
-       # The result may be a other virtual type (or a parameter type)
-       #
-       # The result is returned exactly as declared in the "type" property (verbatim).
-       #
-       # In case of conflict, the method aborts.
-       fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType
+       redef fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType
+       do
+               return lookup_single_definition(mmodule, resolved_receiver).bound.as(not null)
+       end
+
+       private fun lookup_single_definition(mmodule: MModule, resolved_receiver: MType): MVirtualTypeDef
        do
                assert not resolved_receiver.need_anchor
                var props = self.mproperty.lookup_definitions(mmodule, resolved_receiver)
                if props.is_empty then
                        abort
                else if props.length == 1 then
-                       return props.first.as(MVirtualTypeDef).bound.as(not null)
+                       return props.first
                end
                var types = new ArraySet[MType]
+               var res  = props.first
                for p in props do
-                       types.add(p.as(MVirtualTypeDef).bound.as(not null))
+                       types.add(p.bound.as(not null))
+                       if not res.is_fixed then res = p
                end
                if types.length == 1 then
-                       return types.first
+                       return res
                end
                abort
        end
 
-       # Is the virtual type fixed for a given resolved_receiver?
-       fun is_fixed(mmodule: MModule, resolved_receiver: MType): Bool
+       # A VT is fixed when:
+       # * the VT is (re-)defined with the annotation `is fixed`
+       # * the VT is (indirectly) bound to an enum class (see `enum_kind`) since there is no subtype possible
+       # * the receiver is an enum class since there is no subtype possible
+       redef fun lookup_fixed(mmodule: MModule, resolved_receiver: MType): MType
        do
                assert not resolved_receiver.need_anchor
-               var props = self.mproperty.lookup_definitions(mmodule, resolved_receiver)
-               if props.is_empty then
-                       abort
-               end
-               for p in props do
-                       if p.as(MVirtualTypeDef).is_fixed then return true
-               end
-               return false
+               resolved_receiver = resolved_receiver.as_notnullable
+               assert resolved_receiver isa MClassType # It is the only remaining type
+
+               var prop = lookup_single_definition(mmodule, resolved_receiver)
+               var res = prop.bound.as(not null)
+
+               # Recursively lookup the fixed result
+               res = res.lookup_fixed(mmodule, resolved_receiver)
+
+               # 1. For a fixed VT, return the resolved bound
+               if prop.is_fixed then return res
+
+               # 2. For a enum boud, return the bound
+               if res isa MClassType and res.mclass.kind == enum_kind then return res
+
+               # 3. for a enum receiver return the bound
+               if resolved_receiver.mclass.kind == enum_kind then return res
+
+               return self
        end
 
        redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual)
        do
+               if not cleanup_virtual then return self
                assert can_resolve_for(mtype, anchor, mmodule)
                # self is a virtual type declared (or inherited) in mtype
                # The point of the function it to get the bound of the virtual type that make sense for mtype
                # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
                #print "{class_name}: {self}/{mtype}/{anchor}?"
-               var resolved_reciever
+               var resolved_receiver
                if mtype.need_anchor then
                        assert anchor != null
-                       resolved_reciever = mtype.resolve_for(anchor, null, mmodule, true)
+                       resolved_receiver = mtype.resolve_for(anchor, null, mmodule, true)
                else
-                       resolved_reciever = mtype
+                       resolved_receiver = mtype
                end
                # Now, we can get the bound
-               var verbatim_bound = lookup_bound(mmodule, resolved_reciever)
+               var verbatim_bound = lookup_bound(mmodule, resolved_receiver)
                # The bound is exactly as declared in the "type" property, so we must resolve it again
                var res = verbatim_bound.resolve_for(mtype, anchor, mmodule, cleanup_virtual)
-               #print "{class_name}: {self}/{mtype}/{anchor} -> {self}/{resolved_receiver}/{anchor} -> {verbatim_bound}/{mtype}/{anchor} -> {res}"
-
-               # What to return here? There is a bunch a special cases:
-               # If 'cleanup_virtual' we must return the resolved type, since we cannot return self
-               if cleanup_virtual then return res
-               # If the receiver is a intern class, then the virtual type cannot be redefined since there is no possible subclass. self is just fixed. so simply return the resolution
-               if resolved_reciever isa MNullableType then resolved_reciever = resolved_reciever.mtype
-               if resolved_reciever.as(MClassType).mclass.kind == enum_kind then return res
-               # If the resolved type isa MVirtualType, it means that self was bound to it, and cannot be unbound. self is just fixed. so return the resolution.
-               if res isa MVirtualType then return res
-               # If we are final, just return the resolution
-               if is_fixed(mmodule, resolved_reciever) then return res
-               # If the resolved type isa intern class, then there is no possible valid redefinition in any potential subclass. self is just fixed. so simply return the resolution
-               if res isa MClassType and res.mclass.kind == enum_kind then return res
-               # TODO: What if bound to a MParameterType?
-               # Note that Nullable types can always be redefined by the non nullable version, so there is no specific case on it.
 
-               # If anything apply, then `self' cannot be resolved, so return self
-               return self
+               return res
        end
 
        redef fun can_resolve_for(mtype, anchor, mmodule)
@@ -1254,12 +1297,14 @@ end
 # directly to the parameter types of the super-classes.
 #
 # Example:
+#
 #     class A[E]
 #         fun e: E is abstract
 #     end
 #     class B[F]
 #         super A[Array[F]]
 #     end
+#
 # In the class definition B[F], `F` is a valid type but `E` is not.
 # However, `self.e` is a valid method call, and the signature of `e` is
 # declared `e: E`.
@@ -1282,12 +1327,15 @@ class MParameterType
 
        redef fun to_s do return name
 
-       # Resolve the bound for a given resolved_receiver
-       # The result may be a other virtual type (or a parameter type)
-       fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType
+       redef fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType
        do
                assert not resolved_receiver.need_anchor
+               resolved_receiver = resolved_receiver.as_notnullable
+               assert resolved_receiver isa MClassType # It is the only remaining type
                var goalclass = self.mclass
+               if resolved_receiver.mclass == goalclass then
+                       return resolved_receiver.arguments[self.rank]
+               end
                var supertypes = resolved_receiver.collect_mtypes(mmodule)
                for t in supertypes do
                        if t.mclass == goalclass then
@@ -1300,6 +1348,22 @@ class MParameterType
                abort
        end
 
+       # A PT is fixed when:
+       # * Its bound is a enum class (see `enum_kind`).
+       #   The PT is just useless, but it is still a case.
+       # * More usually, the `resolved_receiver` is a subclass of `self.mclass`,
+       #   so it is necessarily fixed in a `super` clause, either with a normal type
+       #   or with another PT.
+       #   See `resolve_for` for examples about related issues.
+       redef fun lookup_fixed(mmodule: MModule, resolved_receiver: MType): MType
+       do
+               assert not resolved_receiver.need_anchor
+               resolved_receiver = resolved_receiver.as_notnullable
+               assert resolved_receiver isa MClassType # It is the only remaining type
+               var res = self.resolve_for(resolved_receiver.mclass.mclass_type, resolved_receiver, mmodule, false)
+               return res
+       end
+
        redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual)
        do
                assert can_resolve_for(mtype, anchor, mmodule)
@@ -1332,7 +1396,7 @@ class MParameterType
                        resolved_receiver = anchor.arguments[resolved_receiver.rank]
                        if resolved_receiver isa MNullableType then resolved_receiver = resolved_receiver.mtype
                end
-               assert resolved_receiver isa MClassType
+               assert resolved_receiver isa MClassType # It is the only remaining type
 
                # Eh! The parameter is in the current class.
                # So we return the corresponding argument, no mater what!
@@ -1396,6 +1460,14 @@ class MNullableType
                return self.mtype.can_resolve_for(mtype, anchor, mmodule)
        end
 
+       # Efficiently returns `mtype.lookup_fixed(mmodule, resolved_receiver).as_nullable`
+       redef fun lookup_fixed(mmodule, resolved_receiver)
+       do
+               var t = mtype.lookup_fixed(mmodule, resolved_receiver)
+               if t == mtype then return self
+               return t.as_nullable
+       end
+
        redef fun depth do return self.mtype.depth
 
        redef fun length do return self.mtype.length
index c23e5cb..b89eced 100644 (file)
@@ -18,6 +18,7 @@ module mproject
 import model_base
 private import more_collections
 import poset
+import mdoc
 
 # A Nit project, that encompass a product
 class MProject
@@ -45,6 +46,12 @@ class MProject
 
        # MProject are always roots of the concerns hierarchy
        redef fun parent_concern do return null
+
+       redef fun mdoc_or_fallback
+       do
+               if mdoc != null then return mdoc
+               return root.mdoc_or_fallback
+       end
 end
 
 # A group of modules in a project
index 9297793..7302619 100644 (file)
@@ -163,44 +163,6 @@ redef class MModule
                return mclasses
        end
 
-       fun in_nesting_intro_mclasses(min_visibility: MVisibility): Set[MClass] do
-               var res = new HashSet[MClass]
-               for mmodule in in_nesting.greaters do
-                       for mclass in mmodule.filter_intro_mclasses(min_visibility) do
-                               if mclass.visibility < min_visibility then continue
-                               res.add mclass
-                       end
-               end
-               return res
-       end
-
-       fun in_nesting_redef_mclasses(min_visibility: MVisibility): Set[MClass] do
-               var res = new HashSet[MClass]
-               for mmodule in self.in_nesting.greaters do
-                       for mclass in mmodule.filter_redef_mclasses(min_visibility) do
-                               if mclass.visibility < min_visibility then continue
-                               res.add mclass
-                       end
-               end
-               return res
-       end
-
-       fun in_nesting_intro_mclassdefs(min_visibility: MVisibility): Set[MClassDef] do
-               var res = new HashSet[MClassDef]
-               for mmodule in in_nesting.greaters do
-                       res.add_all mmodule.intro_mclassdefs(min_visibility)
-               end
-               return res
-       end
-
-       fun in_nesting_redef_mclassdefs(min_visibility: MVisibility): Set[MClassDef] do
-               var res = new HashSet[MClassDef]
-               for mmodule in self.in_nesting.greaters do
-                       res.add_all mmodule.redef_mclassdefs(min_visibility)
-               end
-               return res
-       end
-
        redef fun concern_rank is cached do
                var max = 0
                for p in in_importation.direct_greaters do
@@ -209,6 +171,23 @@ redef class MModule
                end
                return max + 1
        end
+
+       # Find all mmodules nested in `self` if `self` is the default module of a `MGroup`.
+       fun nested_mmodules: Array[MModule] do
+               var res = new Array[MModule]
+               var mgroup = mgroup
+               if mgroup == null or self != mgroup.default_mmodule then return res
+               for mmodule in mgroup.mmodules do
+                       if mmodule == self then continue
+                       res.add mmodule
+               end
+               for nested in mgroup.in_nesting.direct_smallers do
+                       var default = nested.default_mmodule
+                       if default == null then continue
+                       res.add default
+               end
+               return res
+       end
 end
 
 redef class MClass
@@ -535,7 +514,9 @@ end
 #
 # Comparison is made with the formula:
 #
-#     a.concern_rank + a.booster_rank <=> b.concern_rank + b.booster_ran
+# ~~~nitish
+# a.concern_rank + a.booster_rank <=> b.concern_rank + b.booster_ran
+# ~~~
 #
 # If both `a` and `b` have the same ranking,
 # ordering is based on lexicographic comparison of `a.name` and `b.name`
index 1ae7e45..b38bdac 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Load nit source files and build the associated model
-#
-# FIXME better doc
-#
-# FIXME split this module into submodules
-# FIXME add missing error checks
 module modelbuilder
 
-import model
+import loader
 import phase
 
 private import more_collections
@@ -30,29 +24,15 @@ private import more_collections
 ###
 
 redef class ToolContext
-       # Option --path
-       var opt_path = new OptionArray("Set include path for loaders (may be used more than once)", "-I", "--path")
-
-       # Option --only-metamodel
-       var opt_only_metamodel = new OptionBool("Stop after meta-model processing", "--only-metamodel")
-
-       # Option --only-parse
-       var opt_only_parse = new OptionBool("Only proceed to parse step of loaders", "--only-parse")
-
        # Option --ignore-visibility
        var opt_ignore_visibility = new OptionBool("Do not check, and produce errors, on visibility issues.", "--ignore-visibility")
 
        redef init
        do
                super
-               option_context.add_option(opt_path, opt_only_parse, opt_only_metamodel, opt_ignore_visibility)
+               option_context.add_option(opt_ignore_visibility)
        end
 
-       # The modelbuilder 1-to-1 associated with the toolcontext
-       fun modelbuilder: ModelBuilder do return modelbuilder_real.as(not null)
-
-       private var modelbuilder_real: nullable ModelBuilder = null
-
        # Combine module to make a single one if required.
        fun make_main_module(mmodules: Array[MModule]): MModule
        do
@@ -98,14 +78,7 @@ redef class Phase
 end
 
 
-# A model builder knows how to load nit source files and build the associated model
-class ModelBuilder
-       # The model where new modules, classes and properties are added
-       var model: Model
-
-       # The toolcontext used to control the interaction with the user (getting options and displaying messages)
-       var toolcontext: ToolContext
-
+redef class ModelBuilder
        # Run phases on all loaded modules
        fun run_phases
        do
@@ -123,725 +96,4 @@ class ModelBuilder
                end
        end
 
-       # Instantiate a modelbuilder for a model and a toolcontext
-       # Important, the options of the toolcontext must be correctly set (parse_option already called)
-       init
-       do
-               assert toolcontext.modelbuilder_real == null
-               toolcontext.modelbuilder_real = self
-
-               # Setup the paths value
-               paths.append(toolcontext.opt_path.value)
-
-               var path_env = "NIT_PATH".environ
-               if not path_env.is_empty then
-                       paths.append(path_env.split_with(':'))
-               end
-
-               var nit_dir = toolcontext.nit_dir
-               var libname = "{nit_dir}/lib"
-               if libname.file_exists then paths.add(libname)
-       end
-
-       # Load a bunch of modules.
-       # `modules` can contains filenames or module names.
-       # Imported modules are automatically loaded and modelized.
-       # The result is the corresponding model elements.
-       # Errors and warnings are printed with the toolcontext.
-       #
-       # Note: class and property model element are not analysed.
-       fun parse(modules: 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 modules do
-                       var nmodule = self.load_module(a)
-                       if nmodule == null then continue # Skip error
-                       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
-
-       # Return a class named `name` visible by the module `mmodule`.
-       # Visibility in modules is correctly handled.
-       # If no such a class exists, then null is returned.
-       # If more than one class exists, then an error on `anode` is displayed and null is returned.
-       # FIXME: add a way to handle class name conflict
-       fun try_get_mclass_by_name(anode: ANode, mmodule: MModule, name: String): nullable MClass
-       do
-               var classes = model.get_mclasses_by_name(name)
-               if classes == null then
-                       return null
-               end
-
-               var res: nullable MClass = null
-               for mclass in classes do
-                       if not mmodule.in_importation <= mclass.intro_mmodule then continue
-                       if not mmodule.is_visible(mclass.intro_mmodule, mclass.visibility) then continue
-                       if res == null then
-                               res = mclass
-                       else
-                               error(anode, "Ambigous class name '{name}'; conflict between {mclass.full_name} and {res.full_name}")
-                               return null
-                       end
-               end
-               return res
-       end
-
-       # Return a property named `name` on the type `mtype` visible in the module `mmodule`.
-       # Visibility in modules is correctly handled.
-       # Protected properties are returned (it is up to the caller to check and reject protected properties).
-       # If no such a property exists, then null is returned.
-       # If more than one property exists, then an error on `anode` is displayed and null is returned.
-       # FIXME: add a way to handle property name conflict
-       fun try_get_mproperty_by_name2(anode: ANode, mmodule: MModule, mtype: MType, name: String): nullable MProperty
-       do
-               var props = self.model.get_mproperties_by_name(name)
-               if props == null then
-                       return null
-               end
-
-               var cache = self.try_get_mproperty_by_name2_cache[mmodule, mtype, name]
-               if cache != null then return cache
-
-               var res: nullable MProperty = null
-               var ress: nullable Array[MProperty] = null
-               for mprop in props do
-                       if not mtype.has_mproperty(mmodule, mprop) then continue
-                       if not mmodule.is_visible(mprop.intro_mclassdef.mmodule, mprop.visibility) then continue
-
-                       # new-factories are invisible outside of the class
-                       if mprop isa MMethod and mprop.is_new and (not mtype isa MClassType or mprop.intro_mclassdef.mclass != mtype.mclass) then
-                               continue
-                       end
-
-                       if res == null then
-                               res = mprop
-                               continue
-                       end
-
-                       # Two global properties?
-                       # First, special case for init, keep the most specific ones
-                       if res isa MMethod and mprop isa MMethod and res.is_init and mprop.is_init then
-                               var restype = res.intro_mclassdef.bound_mtype
-                               var mproptype = mprop.intro_mclassdef.bound_mtype
-                               if mproptype.is_subtype(mmodule, null, restype) then
-                                       # found a most specific constructor, so keep it
-                                       res = mprop
-                                       continue
-                               end
-                       end
-
-                       # Ok, just keep all prop in the ress table
-                       if ress == null then
-                               ress = new Array[MProperty]
-                               ress.add(res)
-                       end
-                       ress.add(mprop)
-               end
-
-               # There is conflict?
-               if ress != null and res isa MMethod and res.is_init then
-                       # special case forinit again
-                       var restype = res.intro_mclassdef.bound_mtype
-                       var ress2 = new Array[MProperty]
-                       for mprop in ress do
-                               var mproptype = mprop.intro_mclassdef.bound_mtype
-                               if not restype.is_subtype(mmodule, null, mproptype) then
-                                       ress2.add(mprop)
-                               else if not mprop isa MMethod or not mprop.is_init then
-                                       ress2.add(mprop)
-                               end
-                       end
-                       if ress2.is_empty then
-                               ress = null
-                       else
-                               ress = ress2
-                               ress.add(res)
-                       end
-               end
-
-               if ress != null then
-                       assert ress.length > 1
-                       var s = new Array[String]
-                       for mprop in ress do s.add mprop.full_name
-                       self.error(anode, "Ambigous property name '{name}' for {mtype}; conflict between {s.join(" and ")}")
-               end
-
-               self.try_get_mproperty_by_name2_cache[mmodule, mtype, name] = res
-               return res
-       end
-
-       private var try_get_mproperty_by_name2_cache = new HashMap3[MModule, MType, String, nullable MProperty]
-
-
-       # Alias for try_get_mproperty_by_name2(anode, mclassdef.mmodule, mclassdef.mtype, name)
-       fun try_get_mproperty_by_name(anode: ANode, mclassdef: MClassDef, name: String): nullable MProperty
-       do
-               return try_get_mproperty_by_name2(anode, mclassdef.mmodule, mclassdef.bound_mtype, name)
-       end
-
-       # The list of directories to search for top level modules
-       # The list is initially set with :
-       #   * the toolcontext --path option
-       #   * the NIT_PATH environment variable
-       #   * `toolcontext.nit_dir`
-       # Path can be added (or removed) by the client
-       var paths = new Array[String]
-
-       # Like (an used by) `get_mmodule_by_name` but just return the ModulePath
-       private fun search_mmodule_by_name(anode: ANode, mgroup: nullable MGroup, name: String): nullable ModulePath
-       do
-               # First, look in groups
-               var c = mgroup
-               while c != null do
-                       var dirname = c.filepath
-                       if dirname == null then break # virtual group
-                       if dirname.has_suffix(".nit") then break # singleton project
-
-                       # Second, try the directory to find a file
-                       var try_file = dirname + "/" + name + ".nit"
-                       if try_file.file_exists then
-                               var res = self.identify_file(try_file.simplify_path)
-                               assert res != null
-                               return res
-                       end
-
-                       # Third, try if the requested module is itself a group
-                       try_file = dirname + "/" + name + "/" + name + ".nit"
-                       if try_file.file_exists then
-                               var res = self.identify_file(try_file.simplify_path)
-                               assert res != null
-                               return res
-                       end
-
-                       c = c.parent
-               end
-
-               # Look at some known directories
-               var lookpaths = self.paths
-
-               # Look in the directory of the group project also (even if not explicitely in the path)
-               if mgroup != null then
-                       # path of the root group
-                       var dirname = mgroup.mproject.root.filepath
-                       if dirname != null then
-                               dirname = dirname.join_path("..").simplify_path
-                               if not lookpaths.has(dirname) and dirname.file_exists then
-                                       lookpaths = lookpaths.to_a
-                                       lookpaths.add(dirname)
-                               end
-                       end
-               end
-
-               var candidate = search_module_in_paths(anode.hot_location, name, lookpaths)
-
-               if candidate == null then
-                       if mgroup != null then
-                               error(anode, "Error: cannot find module {name} from {mgroup.name}. tried {lookpaths.join(", ")}")
-                       else
-                               error(anode, "Error: cannot find module {name}. tried {lookpaths.join(", ")}")
-                       end
-                       return null
-               end
-               return candidate
-       end
-
-       # Get a module by its short name; if required, the module is loaded, parsed and its hierarchies computed.
-       # If `mgroup` is set, then the module search starts from it up to the top level (see `paths`);
-       # if `mgroup` is null then the module is searched in the top level only.
-       # If no module exists or there is a name conflict, then an error on `anode` is displayed and null is returned.
-       fun get_mmodule_by_name(anode: ANode, mgroup: nullable MGroup, name: String): nullable MModule
-       do
-               var path = search_mmodule_by_name(anode, mgroup, name)
-               if path == null then return null # Forward error
-               var res = self.load_module(path.filepath)
-               if res == null then return null # Forward error
-               return res.mmodule.as(not null)
-       end
-
-       # Search a module `name` from path `lookpaths`.
-       # If found, the path of the file is returned
-       private fun search_module_in_paths(location: nullable Location, name: String, lookpaths: Collection[String]): nullable ModulePath
-       do
-               var candidate: nullable String = null
-               for dirname in lookpaths do
-                       var try_file = (dirname + "/" + name + ".nit").simplify_path
-                       if try_file.file_exists then
-                               if candidate == null then
-                                       candidate = try_file
-                               else if candidate != try_file then
-                                       # try to disambiguate conflicting modules
-                                       var abs_candidate = module_absolute_path(candidate)
-                                       var abs_try_file = module_absolute_path(try_file)
-                                       if abs_candidate != abs_try_file then
-                                               toolcontext.error(location, "Error: conflicting module file for {name}: {candidate} {try_file}")
-                                       end
-                               end
-                       end
-                       try_file = (dirname + "/" + name + "/" + name + ".nit").simplify_path
-                       if try_file.file_exists then
-                               if candidate == null then
-                                       candidate = try_file
-                               else if candidate != try_file then
-                                       # try to disambiguate conflicting modules
-                                       var abs_candidate = module_absolute_path(candidate)
-                                       var abs_try_file = module_absolute_path(try_file)
-                                       if abs_candidate != abs_try_file then
-                                               toolcontext.error(location, "Error: conflicting module file for {name}: {candidate} {try_file}")
-                                       end
-                               end
-                       end
-               end
-               if candidate == null then return null
-               return identify_file(candidate)
-       end
-
-       # cache for `identify_file` by realpath
-       private var identified_files = new HashMap[String, nullable ModulePath]
-
-       # Identify a source file
-       # Load the associated project and groups if required
-       private fun identify_file(path: String): nullable ModulePath
-       do
-               # special case for not a nit file
-               if path.file_extension != "nit" then
-                       # search in known -I paths
-                       var res = search_module_in_paths(null, path, self.paths)
-                       if res != null then return res
-
-                       # Found nothins? maybe it is a group...
-                       var candidate = null
-                       if path.file_exists then
-                               var mgroup = get_mgroup(path)
-                               if mgroup != null then
-                                       var owner_path = mgroup.filepath.join_path(mgroup.name + ".nit")
-                                       if owner_path.file_exists then candidate = owner_path
-                               end
-                       end
-
-                       if candidate == null then
-                               toolcontext.error(null, "Error: cannot find module `{path}`.")
-                               return null
-                       end
-                       path = candidate
-               end
-
-               # Fast track, the path is already known
-               var pn = path.basename(".nit")
-               var rp = module_absolute_path(path)
-               if identified_files.has_key(rp) then return identified_files[rp]
-
-               # Search for a group
-               var mgrouppath = path.join_path("..").simplify_path
-               var mgroup = get_mgroup(mgrouppath)
-
-               if mgroup == null then
-                       # singleton project
-                       var mproject = new MProject(pn, model)
-                       mgroup = new MGroup(pn, mproject, null) # same name for the root group
-                       mgroup.filepath = path
-                       mproject.root = mgroup
-                       toolcontext.info("found project `{pn}` at {path}", 2)
-               end
-
-               var res = new ModulePath(pn, path, mgroup)
-               mgroup.module_paths.add(res)
-
-               identified_files[rp] = res
-               return res
-       end
-
-       # groups by path
-       private var mgroups = new HashMap[String, nullable MGroup]
-
-       # return the mgroup associated to a directory path
-       # if the directory is not a group null is returned
-       private fun get_mgroup(dirpath: String): nullable MGroup
-       do
-               var rdp = module_absolute_path(dirpath)
-               if mgroups.has_key(rdp) then
-                       return mgroups[rdp]
-               end
-
-               # Hack, a group is determined by:
-               # * the presence of a honomymous nit file
-               # * the fact that the directory is named `src`
-               var pn = rdp.basename(".nit")
-               var mp = dirpath.join_path(pn + ".nit").simplify_path
-
-               var dirpath2 = dirpath
-               if not mp.file_exists then
-                       if pn == "src" then
-                               # With a src directory, the group name is the name of the parent directory
-                               dirpath2 = rdp.dirname
-                               pn = dirpath2.basename("")
-                       else
-                               return null
-                       end
-               end
-
-               # check parent directory
-               var parentpath = dirpath.join_path("..").simplify_path
-               var parent = get_mgroup(parentpath)
-
-               var mgroup
-               if parent == null then
-                       # no parent, thus new project
-                       var mproject = new MProject(pn, model)
-                       mgroup = new MGroup(pn, mproject, null) # same name for the root group
-                       mproject.root = mgroup
-                       toolcontext.info("found project `{mproject}` at {dirpath}", 2)
-               else
-                       mgroup = new MGroup(pn, parent.mproject, parent)
-                       toolcontext.info("found sub group `{mgroup.full_name}` at {dirpath}", 2)
-               end
-               var readme = dirpath2.join_path("README.md")
-               if not readme.file_exists then readme = dirpath2.join_path("README")
-               if readme.file_exists then
-                       var mdoc = new MDoc
-                       var s = new IFStream.open(readme)
-                       while not s.eof do
-                               mdoc.content.add(s.read_line)
-                       end
-                       mgroup.mdoc = mdoc
-                       mdoc.original_mentity = mgroup
-               end
-               mgroup.filepath = dirpath
-               mgroups[rdp] = mgroup
-               return mgroup
-       end
-
-       # Transform relative paths (starting with '../') into absolute paths
-       private fun module_absolute_path(path: String): String do
-               return getcwd.join_path(path).simplify_path
-       end
-
-       # Try to load a module AST using a path.
-       # Display an error if there is a problem (IO / lexer / parser) and return null
-       fun load_module_ast(filename: String): nullable AModule
-       do
-               if filename.file_extension != "nit" then
-                       self.toolcontext.error(null, "Error: file {filename} is not a valid nit module.")
-                       return null
-               end
-               if not filename.file_exists then
-                       self.toolcontext.error(null, "Error: file {filename} not found.")
-                       return null
-               end
-
-               self.toolcontext.info("load module {filename}", 2)
-
-               # Load the file
-               var file = new IFStream.open(filename)
-               var lexer = new Lexer(new SourceFile(filename, file))
-               var parser = new Parser(lexer)
-               var tree = parser.parse
-               file.close
-
-               # Handle lexer and parser error
-               var nmodule = tree.n_base
-               if nmodule == null then
-                       var neof = tree.n_eof
-                       assert neof isa AError
-                       error(neof, neof.message)
-                       return null
-               end
-
-               return nmodule
-       end
-
-       # Try to load a module and its imported modules using a path.
-       # Display an error if there is a problem (IO / lexer / parser / importation) and return null
-       # Note: usually, you do not need this method, use `get_mmodule_by_name` instead.
-       fun load_module(filename: String): nullable AModule
-       do
-               # Look for the module
-               var file = identify_file(filename)
-               if file == null then return null # forward error
-
-               # Already known and loaded? then return it
-               var mmodule = file.mmodule
-               if mmodule != null then
-                       return mmodule2nmodule[mmodule]
-               end
-
-               # Load it manually
-               var nmodule = load_module_ast(file.filepath)
-               if nmodule == null then return null # forward error
-
-               # build the mmodule and load imported modules
-               mmodule = build_a_mmodule(file.mgroup, file.name, nmodule)
-
-               if mmodule == null then return null # forward error
-
-               # Update the file information
-               file.mmodule = mmodule
-
-               # Load imported module
-               build_module_importation(nmodule)
-
-               return nmodule
-       end
-
-       # Injection of a new module without source.
-       # Used by the interpreted
-       fun load_rt_module(parent: nullable MModule, nmodule: AModule, mod_name: String): nullable AModule
-       do
-               # Create the module
-
-               var mgroup = null
-               if parent != null then mgroup = parent.mgroup
-               var mmodule = new MModule(model, mgroup, mod_name, nmodule.location)
-               nmodule.mmodule = mmodule
-               nmodules.add(nmodule)
-               self.mmodule2nmodule[mmodule] = nmodule
-
-               if parent!= null then
-                       var imported_modules = new Array[MModule]
-                       imported_modules.add(parent)
-                       mmodule.set_visibility_for(parent, intrude_visibility)
-                       mmodule.set_imported_mmodules(imported_modules)
-               else
-                       build_module_importation(nmodule)
-               end
-
-               return nmodule
-       end
-
-       # Visit the AST and create the `MModule` object
-       private fun build_a_mmodule(mgroup: nullable MGroup, mod_name: String, nmodule: AModule): nullable MModule
-       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
-                       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}")
-                       end
-               end
-
-               # Create the module
-               var mmodule = new MModule(model, mgroup, mod_name, nmodule.location)
-               nmodule.mmodule = mmodule
-               nmodules.add(nmodule)
-               self.mmodule2nmodule[mmodule] = nmodule
-
-               if decl != null then
-                       var ndoc = decl.n_doc
-                       if ndoc != null then
-                               var mdoc = ndoc.to_mdoc
-                               mmodule.mdoc = mdoc
-                               mdoc.original_mentity = mmodule
-                       else
-                               advice(decl, "missing-doc", "Documentation warning: Undocumented module `{mmodule}`")
-                       end
-               end
-
-               return mmodule
-       end
-
-       # Analysis the module importation and fill the module_importation_hierarchy
-       private fun build_module_importation(nmodule: AModule)
-       do
-               if nmodule.is_importation_done then return
-               nmodule.is_importation_done = true
-               var mmodule = nmodule.mmodule.as(not null)
-               var stdimport = true
-               var imported_modules = new Array[MModule]
-               for aimport in nmodule.n_imports do
-                       stdimport = false
-                       if not aimport isa AStdImport then
-                               continue
-                       end
-                       var mgroup = mmodule.mgroup
-                       if aimport.n_name.n_quad != null then mgroup = null # Start from top level
-                       for grp in aimport.n_name.n_path do
-                               var path = search_mmodule_by_name(grp, mgroup, grp.text)
-                               if path == null then return # Skip error
-                               mgroup = path.mgroup
-                       end
-                       var mod_name = aimport.n_name.n_id.text
-                       var sup = self.get_mmodule_by_name(aimport.n_name, mgroup, mod_name)
-                       if sup == null then continue # Skip error
-                       aimport.mmodule = sup
-                       imported_modules.add(sup)
-                       var mvisibility = aimport.n_visibility.mvisibility
-                       if mvisibility == protected_visibility then
-                               error(aimport.n_visibility, "Error: only properties can be protected.")
-                               return
-                       end
-                       if sup == mmodule then
-                               error(aimport.n_name, "Error: Dependency loop in module {mmodule}.")
-                       end
-                       if sup.in_importation < mmodule then
-                               error(aimport.n_name, "Error: Dependency loop between modules {mmodule} and {sup}.")
-                               return
-                       end
-                       mmodule.set_visibility_for(sup, mvisibility)
-               end
-               if stdimport then
-                       var mod_name = "standard"
-                       var sup = self.get_mmodule_by_name(nmodule, null, mod_name)
-                       if sup != null then # Skip error
-                               imported_modules.add(sup)
-                               mmodule.set_visibility_for(sup, public_visibility)
-                       end
-               end
-               self.toolcontext.info("{mmodule} imports {imported_modules.join(", ")}", 3)
-               mmodule.set_imported_mmodules(imported_modules)
-
-               # Force standard to be public if imported
-               for sup in mmodule.in_importation.greaters do
-                       if sup.name == "standard" then
-                               mmodule.set_visibility_for(sup, public_visibility)
-                       end
-               end
-
-               # TODO: Correctly check for useless importation
-               # It is even doable?
-               var directs = mmodule.in_importation.direct_greaters
-               for nim in nmodule.n_imports do
-                       if not nim isa AStdImport then continue
-                       var im = nim.mmodule
-                       if im == null then continue
-                       if directs.has(im) then continue
-                       # This generates so much noise that it is simpler to just comment it
-                       #warning(nim, "Warning: possible useless importation of {im}")
-               end
-       end
-
-       # All the loaded modules
-       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]
-
-       # Helper function to display an error on a node.
-       # Alias for `self.toolcontext.error(n.hot_location, text)`
-       fun error(n: ANode, text: String)
-       do
-               self.toolcontext.error(n.hot_location, text)
-       end
-
-       # Helper function to display a warning on a node.
-       # Alias for: `self.toolcontext.warning(n.hot_location, text)`
-       fun warning(n: ANode, tag, text: String)
-       do
-               self.toolcontext.warning(n.hot_location, tag, text)
-       end
-
-       # Helper function to display an advice on a node.
-       # Alias for: `self.toolcontext.advice(n.hot_location, text)`
-       fun advice(n: ANode, tag, text: String)
-       do
-               self.toolcontext.advice(n.hot_location, tag, text)
-       end
-
-       # Force to get the primitive method named `name` on the type `recv` or do a fatal error on `n`
-       fun force_get_primitive_method(n: nullable ANode, name: String, recv: MClass, mmodule: MModule): MMethod
-       do
-               var res = mmodule.try_get_primitive_method(name, recv)
-               if res == null then
-                       var l = null
-                       if n != null then l = n.hot_location
-                       self.toolcontext.fatal_error(l, "Fatal Error: {recv} must have a property named {name}.")
-                       abort
-               end
-               return res
-       end
-end
-
-# placeholder to a module file identified but not always loaded in a project
-private class ModulePath
-       # The name of the module
-       # (it's the basename of the filepath)
-       var name: String
-
-       # The human path of the module
-       var filepath: String
-
-       # The group (and the project) of the possible module
-       var mgroup: MGroup
-
-       # The loaded module (if any)
-       var mmodule: nullable MModule = null
-
-       redef fun to_s do return filepath
-end
-
-redef class MGroup
-       # modules paths associated with the group
-       private var module_paths = new Array[ModulePath]
-end
-
-redef class AStdImport
-       # The imported module once determined
-       var mmodule: nullable MModule = null
-end
-
-redef class AModule
-       # The associated MModule once build by a `ModelBuilder`
-       var mmodule: nullable MModule
-       # Flag that indicate if the importation is already completed
-       var is_importation_done: Bool = false
-end
-
-redef class AVisibility
-       # The visibility level associated with the AST node class
-       fun mvisibility: MVisibility is abstract
-end
-redef class AIntrudeVisibility
-       redef fun mvisibility do return intrude_visibility
-end
-redef class APublicVisibility
-       redef fun mvisibility do return public_visibility
-end
-redef class AProtectedVisibility
-       redef fun mvisibility do return protected_visibility
-end
-redef class APrivateVisibility
-       redef fun mvisibility do return private_visibility
-end
-
-redef class ADoc
-       private var mdoc_cache: nullable MDoc
-       fun to_mdoc: MDoc
-       do
-               var res = mdoc_cache
-               if res != null then return res
-               res = new MDoc
-               for c in n_comment do
-                       var text = c.text
-                       if text.length < 2 then
-                               res.content.add ""
-                               continue
-                       end
-                       assert text.chars[0] == '#'
-                       if text.chars[1] == ' ' then
-                               text = text.substring_from(2) # eat starting `#` and space
-                       else
-                               text = text.substring_from(1) # eat atarting `#` only
-                       end
-                       if text.chars.last == '\n' then text = text.substring(0, text.length-1) # drop \n
-                       res.content.add(text)
-               end
-               mdoc_cache = res
-               return res
-       end
 end
diff --git a/src/modelbuilder_base.nit b/src/modelbuilder_base.nit
new file mode 100644 (file)
index 0000000..d09b717
--- /dev/null
@@ -0,0 +1,260 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2012 Jean Privat <jean@pryen.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.
+
+# Load nit source files and build the associated model
+#
+# FIXME better doc
+#
+# FIXME split this module into submodules
+# FIXME add missing error checks
+module modelbuilder_base
+
+import model
+import toolcontext
+import parser
+
+private import more_collections
+
+###
+
+redef class ToolContext
+
+       # The modelbuilder 1-to-1 associated with the toolcontext
+       fun modelbuilder: ModelBuilder do return modelbuilder_real.as(not null)
+
+       private var modelbuilder_real: nullable ModelBuilder = null
+
+end
+
+# A model builder knows how to load nit source files and build the associated model
+class ModelBuilder
+       # The model where new modules, classes and properties are added
+       var model: Model
+
+       # The toolcontext used to control the interaction with the user (getting options and displaying messages)
+       var toolcontext: ToolContext
+
+       # Instantiate a modelbuilder for a model and a toolcontext
+       # Important, the options of the toolcontext must be correctly set (parse_option already called)
+       init
+       do
+               assert toolcontext.modelbuilder_real == null
+               toolcontext.modelbuilder_real = self
+       end
+
+       # Return a class named `name` visible by the module `mmodule`.
+       # Visibility in modules is correctly handled.
+       # If no such a class exists, then null is returned.
+       # If more than one class exists, then an error on `anode` is displayed and null is returned.
+       # FIXME: add a way to handle class name conflict
+       fun try_get_mclass_by_name(anode: ANode, mmodule: MModule, name: String): nullable MClass
+       do
+               var classes = model.get_mclasses_by_name(name)
+               if classes == null then
+                       return null
+               end
+
+               var res: nullable MClass = null
+               for mclass in classes do
+                       if not mmodule.in_importation <= mclass.intro_mmodule then continue
+                       if not mmodule.is_visible(mclass.intro_mmodule, mclass.visibility) then continue
+                       if res == null then
+                               res = mclass
+                       else
+                               error(anode, "Ambigous class name '{name}'; conflict between {mclass.full_name} and {res.full_name}")
+                               return null
+                       end
+               end
+               return res
+       end
+
+       # Return a property named `name` on the type `mtype` visible in the module `mmodule`.
+       # Visibility in modules is correctly handled.
+       # Protected properties are returned (it is up to the caller to check and reject protected properties).
+       # If no such a property exists, then null is returned.
+       # If more than one property exists, then an error on `anode` is displayed and null is returned.
+       # FIXME: add a way to handle property name conflict
+       fun try_get_mproperty_by_name2(anode: ANode, mmodule: MModule, mtype: MType, name: String): nullable MProperty
+       do
+               var props = self.model.get_mproperties_by_name(name)
+               if props == null then
+                       return null
+               end
+
+               var cache = self.try_get_mproperty_by_name2_cache[mmodule, mtype, name]
+               if cache != null then return cache
+
+               var res: nullable MProperty = null
+               var ress: nullable Array[MProperty] = null
+               for mprop in props do
+                       if not mtype.has_mproperty(mmodule, mprop) then continue
+                       if not mmodule.is_visible(mprop.intro_mclassdef.mmodule, mprop.visibility) then continue
+
+                       # new-factories are invisible outside of the class
+                       if mprop isa MMethod and mprop.is_new and (not mtype isa MClassType or mprop.intro_mclassdef.mclass != mtype.mclass) then
+                               continue
+                       end
+
+                       if res == null then
+                               res = mprop
+                               continue
+                       end
+
+                       # Two global properties?
+                       # First, special case for init, keep the most specific ones
+                       if res isa MMethod and mprop isa MMethod and res.is_init and mprop.is_init then
+                               var restype = res.intro_mclassdef.bound_mtype
+                               var mproptype = mprop.intro_mclassdef.bound_mtype
+                               if mproptype.is_subtype(mmodule, null, restype) then
+                                       # found a most specific constructor, so keep it
+                                       res = mprop
+                                       continue
+                               end
+                       end
+
+                       # Ok, just keep all prop in the ress table
+                       if ress == null then
+                               ress = new Array[MProperty]
+                               ress.add(res)
+                       end
+                       ress.add(mprop)
+               end
+
+               # There is conflict?
+               if ress != null and res isa MMethod and res.is_init then
+                       # special case forinit again
+                       var restype = res.intro_mclassdef.bound_mtype
+                       var ress2 = new Array[MProperty]
+                       for mprop in ress do
+                               var mproptype = mprop.intro_mclassdef.bound_mtype
+                               if not restype.is_subtype(mmodule, null, mproptype) then
+                                       ress2.add(mprop)
+                               else if not mprop isa MMethod or not mprop.is_init then
+                                       ress2.add(mprop)
+                               end
+                       end
+                       if ress2.is_empty then
+                               ress = null
+                       else
+                               ress = ress2
+                               ress.add(res)
+                       end
+               end
+
+               if ress != null then
+                       assert ress.length > 1
+                       var s = new Array[String]
+                       for mprop in ress do s.add mprop.full_name
+                       self.error(anode, "Ambigous property name '{name}' for {mtype}; conflict between {s.join(" and ")}")
+               end
+
+               self.try_get_mproperty_by_name2_cache[mmodule, mtype, name] = res
+               return res
+       end
+
+       private var try_get_mproperty_by_name2_cache = new HashMap3[MModule, MType, String, nullable MProperty]
+
+
+       # Alias for try_get_mproperty_by_name2(anode, mclassdef.mmodule, mclassdef.mtype, name)
+       fun try_get_mproperty_by_name(anode: ANode, mclassdef: MClassDef, name: String): nullable MProperty
+       do
+               return try_get_mproperty_by_name2(anode, mclassdef.mmodule, mclassdef.bound_mtype, name)
+       end
+
+       # Helper function to display an error on a node.
+       # Alias for `self.toolcontext.error(n.hot_location, text)`
+       fun error(n: nullable ANode, text: String)
+       do
+               var l = null
+               if n != null then l = n.hot_location
+               self.toolcontext.error(l, text)
+       end
+
+       # Helper function to display a warning on a node.
+       # Alias for: `self.toolcontext.warning(n.hot_location, text)`
+       fun warning(n: nullable ANode, tag, text: String)
+       do
+               var l = null
+               if n != null then l = n.hot_location
+               self.toolcontext.warning(l, tag, text)
+       end
+
+       # Helper function to display an advice on a node.
+       # Alias for: `self.toolcontext.advice(n.hot_location, text)`
+       fun advice(n: nullable ANode, tag, text: String)
+       do
+               var l = null
+               if n != null then l = n.hot_location
+               self.toolcontext.advice(l, tag, text)
+       end
+
+       # Force to get the primitive method named `name` on the type `recv` or do a fatal error on `n`
+       fun force_get_primitive_method(n: nullable ANode, name: String, recv: MClass, mmodule: MModule): MMethod
+       do
+               var res = mmodule.try_get_primitive_method(name, recv)
+               if res == null then
+                       var l = null
+                       if n != null then l = n.hot_location
+                       self.toolcontext.fatal_error(l, "Fatal Error: {recv} must have a property named {name}.")
+                       abort
+               end
+               return res
+       end
+end
+
+redef class AVisibility
+       # The visibility level associated with the AST node class
+       fun mvisibility: MVisibility is abstract
+end
+redef class AIntrudeVisibility
+       redef fun mvisibility do return intrude_visibility
+end
+redef class APublicVisibility
+       redef fun mvisibility do return public_visibility
+end
+redef class AProtectedVisibility
+       redef fun mvisibility do return protected_visibility
+end
+redef class APrivateVisibility
+       redef fun mvisibility do return private_visibility
+end
+
+redef class ADoc
+       private var mdoc_cache: nullable MDoc
+       fun to_mdoc: MDoc
+       do
+               var res = mdoc_cache
+               if res != null then return res
+               res = new MDoc
+               for c in n_comment do
+                       var text = c.text
+                       if text.length < 2 then
+                               res.content.add ""
+                               continue
+                       end
+                       assert text.chars[0] == '#'
+                       if text.chars[1] == ' ' then
+                               text = text.substring_from(2) # eat starting `#` and space
+                       else
+                               text = text.substring_from(1) # eat atarting `#` only
+                       end
+                       if text.chars.last == '\n' then text = text.substring(0, text.length-1) # drop \n
+                       res.content.add(text)
+               end
+               mdoc_cache = res
+               return res
+       end
+end
index 441a6c2..ae9da02 100644 (file)
@@ -168,6 +168,10 @@ redef class ModelBuilder
                                                warning(nfdt, "useless-bound", "Warning: Useless formal parameter type since `{bound}` cannnot have subclasses.")
                                        end
                                else if mclass.mclassdefs.is_empty then
+                                       if objectclass == null then
+                                               error(nfd, "Error: Formal parameter type `{pname}' unbounded but no Object class exist.")
+                                               return
+                                       end
                                        # No bound, then implicitely bound by nullable Object
                                        var bound = objectclass.mclass_type.as_nullable
                                        bounds.add(bound)
@@ -407,9 +411,8 @@ redef class ModelBuilder
                end
        end
 
-       # Register the nclassdef associated to each mclassdef
-       # FIXME: why not refine the `MClassDef` class with a nullable attribute?
-       var mclassdef2nclassdef = new HashMap[MClassDef, AClassdef]
+       # Registration of the nclassdef associated to each mclassdef
+       private var mclassdef2nclassdef = new HashMap[MClassDef, AClassdef]
 
        # Return the static type associated to the node `ntype`.
        # `mmodule` and `mclassdef` is the context where the call is made (used to understand formal types)
index cb56d38..c996a0c 100644 (file)
@@ -17,7 +17,7 @@
 # Analysis and verification of property definitions to instantiate model element
 module modelize_property
 
-import modelize_class
+intrude import modelize_class
 private import annotation
 
 redef class ToolContext
@@ -36,9 +36,40 @@ private class ModelizePropertyPhase
 end
 
 redef class ModelBuilder
-       # Register the npropdef associated to each mpropdef
-       # FIXME: why not refine the `MPropDef` class with a nullable attribute?
-       var mpropdef2npropdef = new HashMap[MPropDef, APropdef]
+       # Registration of the npropdef associated to each mpropdef.
+       #
+       # Public clients need to use `mpropdef2node` to access stuff.
+       private var mpropdef2npropdef = new HashMap[MPropDef, APropdef]
+
+       # 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.
+       fun mpropdef2node(mpropdef: MPropDef): nullable ANode
+       do
+               var res: nullable ANode = mpropdef2npropdef.get_or_null(mpropdef)
+               if res != null then return res
+               if mpropdef isa MMethodDef and mpropdef.mproperty.is_root_init then
+                       res = mclassdef2nclassdef.get_or_null(mpropdef.mclassdef)
+                       if res != null then return res
+               end
+               return null
+       end
+
+       # Retrieve all the attributes nodes localy definied
+       # FIXME think more about this method and how the separations separate/global and ast/model should be done.
+       fun collect_attr_propdef(mclassdef: MClassDef): Array[AAttrPropdef]
+       do
+               var res = new Array[AAttrPropdef]
+               var n = mclassdef2nclassdef.get_or_null(mclassdef)
+               if n == null then return res
+               for npropdef in n.n_propdefs do
+                       if npropdef isa AAttrPropdef then
+                               res.add(npropdef)
+                       end
+               end
+               return res
+       end
 
        # Build the properties of `nclassdef`.
        # REQUIRE: all superclasses are built.
@@ -54,6 +85,7 @@ redef class ModelBuilder
                        build_properties(mclassdef2nclassdef[superclassdef])
                end
 
+               mclassdef.build_self_type(self, nclassdef)
                for nclassdef2 in nclassdef.all_defs do
                        for npropdef in nclassdef2.n_propdefs do
                                npropdef.build_property(self, mclassdef)
@@ -174,7 +206,8 @@ redef class ModelBuilder
                # Look for most-specific new-stype init definitions
                var spropdefs = the_root_init_mmethod.lookup_super_definitions(mclassdef.mmodule, mclassdef.bound_mtype)
                if spropdefs.is_empty then
-                       toolcontext.fatal_error(nclassdef.location, "Fatal error: {mclassdef} does not specialize {the_root_init_mmethod.intro_mclassdef}. Possible duplication of the root class `Object`?")
+                       toolcontext.error(nclassdef.location, "Error: {mclassdef} does not specialize {the_root_init_mmethod.intro_mclassdef}. Possible duplication of the root class `Object`?")
+                       return
                end
 
                # Search the longest-one and checks for conflict
@@ -310,6 +343,50 @@ redef class MClassDef
        # What is the `APropdef` associated to a `MProperty`?
        # Used to check multiple definition of a property.
        var mprop2npropdef: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef]
+
+       # Build the virtual type `SELF` only for introduction `MClassDef`
+       fun build_self_type(modelbuilder: ModelBuilder, nclassdef: AClassdef)
+       do
+               if not is_intro then return
+
+               var name = "SELF"
+               var mprop = modelbuilder.try_get_mproperty_by_name(nclassdef, self, name)
+
+               # If SELF type is declared nowherer?
+               if mprop == null then return
+
+               # SELF is not a virtual type? it is weird but we ignore it
+               if not mprop isa MVirtualTypeProp then return
+
+               # Is this the intro of SELF in the library?
+               var intro = mprop.intro
+               var intro_mclassdef = intro.mclassdef
+               if intro_mclassdef == self then
+                       var nintro = modelbuilder.mpropdef2npropdef[intro]
+
+                       # SELF must be declared in Object, otherwise this will create conflicts
+                       if intro_mclassdef.mclass.name != "Object" then
+                               modelbuilder.error(nintro, "Error: the virtual type SELF must be declared in Object.")
+                       end
+
+                       # SELF must be public
+                       if mprop.visibility != public_visibility then
+                               modelbuilder.error(nintro, "Error: the virtual type SELF must be public.")
+                       end
+
+                       # SELF must not be fixed
+                       if intro.is_fixed then
+                               modelbuilder.error(nintro, "Error: the virtual type SELF cannot be fixed.")
+                       end
+
+                       return
+               end
+
+               # This class introduction inherits a SELF
+               # We insert an artificial property to update it
+               var mpropdef = new MVirtualTypeDef(self, mprop, self.location)
+               mpropdef.bound = mclass.mclass_type
+       end
 end
 
 redef class APropdef
@@ -573,7 +650,7 @@ redef class AMethPropdef
                        mprop.is_init = is_init
                        mprop.is_new = n_kwnew != null
                        if parent isa ATopClassdef then mprop.is_toplevel = true
-                       if not self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, mprop) then return
+                       self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, mprop)
                else
                        if not mprop.is_root_init and not self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, not self isa AMainMethPropdef, mprop) then return
                        check_redef_property_visibility(modelbuilder, self.n_visibility, mprop)
@@ -631,6 +708,9 @@ redef class AMethPropdef
                        msignature = mpropdef.mproperty.intro.msignature
                        if msignature == null then return # Skip error
 
+                       # The local signature is adapted to use the local formal types, if any.
+                       msignature = msignature.resolve_for(mclassdef.mclass.mclass_type, mclassdef.bound_mtype, mmodule, false)
+
                        # Check inherited signature arity
                        if param_names.length != msignature.arity then
                                var node: ANode
@@ -900,11 +980,17 @@ redef class AAttrPropdef
                        if mtype == null then return
                end
 
+               var inherited_type: nullable MType = null
                # Inherit the type from the getter (usually an abstract getter)
-               if mtype == null and mreadpropdef != null and not mreadpropdef.is_intro then
+               if mreadpropdef != null and not mreadpropdef.is_intro then
                        var msignature = mreadpropdef.mproperty.intro.msignature
                        if msignature == null then return # Error, thus skipped
-                       mtype = msignature.return_mtype
+                       inherited_type = msignature.return_mtype
+                       if inherited_type != null then
+                               # The inherited type is adapted to use the local formal types, if any.
+                               inherited_type = inherited_type.resolve_for(mclassdef.mclass.mclass_type, mclassdef.bound_mtype, mmodule, false)
+                               if mtype == null then mtype = inherited_type
+                       end
                end
 
                var nexpr = self.n_expr
@@ -936,7 +1022,7 @@ redef class AAttrPropdef
 
                                if mtype == null then return
                        end
-               else if ntype != null then
+               else if ntype != null and inherited_type == mtype then
                        if nexpr isa ANewExpr then
                                var xmtype = modelbuilder.resolve_mtype(mmodule, mclassdef, nexpr.n_type)
                                if xmtype == mtype then
@@ -1090,6 +1176,11 @@ redef class ATypePropdef
                var mpropdef = new MVirtualTypeDef(mclassdef, mprop, self.location)
                self.mpropdef = mpropdef
                modelbuilder.mpropdef2npropdef[mpropdef] = self
+               if mpropdef.is_intro then
+                       modelbuilder.toolcontext.info("{mpropdef} introduces new type {mprop.full_name}", 4)
+               else
+                       modelbuilder.toolcontext.info("{mpropdef} redefines type {mprop.full_name}", 4)
+               end
                set_doc(mpropdef, modelbuilder)
 
                var atfixed = get_single_annotation("fixed", modelbuilder)
@@ -1148,7 +1239,8 @@ redef class ATypePropdef
                # Check redefinitions
                bound = mpropdef.bound.as(not null)
                for p in mpropdef.mproperty.lookup_super_definitions(mmodule, anchor) do
-                       var supbound = p.bound.as(not null)
+                       var supbound = p.bound
+                       if supbound == null then break # broken super bound, skip error
                        if p.is_fixed then
                                modelbuilder.error(self, "Redef Error: Virtual type {mpropdef.mproperty} is fixed in super-class {p.mclassdef.mclass}")
                                break
index a566f31..1bed82a 100644 (file)
@@ -94,8 +94,8 @@
 # `MProperty`
 #
 # * labels: `MProperty`, `model_name` and `MEntity`. Must also have `MMethod`,
-# `MAttribute` or `MVirtualTypeProp`, depending on the class of the represented
-# entity.
+# `MAttribute` `MVirtualTypeProp` or `MInnerClass`, depending on the class of
+# the represented entity.
 # * `full_name`: fully qualified name.
 # * `visibility`: visibility of the property.
 # * `is_init`: Indicates if the property is a constructor. Exists only if the
 # * `(:MProperty)-[:INTRO_CLASSDEF]->(:MClassDef)`: classdef that introduces
 # the property.
 #
+# Additional relationship for `MInnerClass`:
+#
+# * `(:MInnerClassDef)-[:NESTS]->(:MClass)`: actual inner class.
+#
 # `MPropDef`
 #
 # * labels: `MPropDef`, `model_name` and `MEntity`. Must also have `MMethodDef`,
-# `MAttributeDef` or `MVirtualTypeDef`, depending on the class of the
-# represented entity.
+# `MAttributeDef`, `MVirtualTypeDef` or `MInnerClassDef`, depending on the
+# class of the represented entity.
 # * `location`: origin of the definition. SEE: `Location.to_s`.
 # * `(:MPropDef)-[:DEFINES]->(:MProperty)`: associated property.
 #
 # is bound in this definition. Exists only if this definition bound the virtual
 # type to an effective type.
 #
+# Additional relationship for `MInnerClassDef`:
+#
+# * `(:MInnerClassDef)-[:NESTS]->(:MClassDef)`: actual inner class'
+# definition.
+#
 # `MType`
 #
 # * labels: `MType`, `model_name` and `MEntity`. Must also have `MClassType`,
 #
 # For example, if the source code contains:
 #
+# ~~~nitish
 #     fun foo(a: A, b: B, c: C)
+# ~~~
 #
 # The `MSignature` node will contain a property
 # `parameter_names = ["a", "b", "c"]` so the MSignature can be reconstructed
@@ -566,6 +577,9 @@ class NeoModel
                        node.labels.add "MAttribute"
                else if mproperty isa MVirtualTypeProp then
                        node.labels.add "MVirtualTypeProp"
+               else if mproperty isa MInnerClass then
+                       node.labels.add "MInnerClass"
+                       node.out_edges.add(new NeoEdge(node, "NESTS", to_node(mproperty.inner)))
                end
                node.out_edges.add(new NeoEdge(node, "INTRO_CLASSDEF", to_node(mproperty.intro_mclassdef)))
                return node
@@ -590,6 +604,9 @@ class NeoModel
                        mprop = new MAttribute(intro_mclassdef, name, visibility)
                else if node.labels.has("MVirtualTypeProp") then
                        mprop = new MVirtualTypeProp(intro_mclassdef, name, visibility)
+               else if node.labels.has("MInnerClass") then
+                       var inner = to_mclass(model, node.out_nodes("NESTS").first)
+                       mprop = new MInnerClass(intro_mclassdef, name, visibility, inner)
                end
                if mprop == null then
                        print "not yet implemented to_mproperty for {node.labels.join(",")}"
@@ -627,6 +644,9 @@ class NeoModel
                        if bound != null then
                                node.out_edges.add(new NeoEdge(node, "BOUND", to_node(bound)))
                        end
+               else if mpropdef isa MInnerClassDef then
+                       node.labels.add "MInnerClassDef"
+                       node.out_edges.add(new NeoEdge(node, "NESTS", to_node(mpropdef.inner)))
                end
                return node
        end
@@ -660,6 +680,11 @@ class NeoModel
                        mentities[node.id.as(Int)] = mpropdef
                        var bound = node.out_nodes("BOUND")
                        if not bound.is_empty then mpropdef.bound = to_mtype(model, bound.first)
+               else if node.labels.has("MInnerClassDef") then
+                       var inner = to_mclassdef(model, node.out_nodes("NESTS").first)
+                       mpropdef = new MInnerClassDef(mclassdef,
+                                       mproperty.as(MInnerClass), location, inner)
+                       mentities[node.id.as(Int)] = mpropdef
                end
                if mpropdef == null then
                        print "not yet implemented to_mpropdef for {node.labels.join(",")}"
index 3785ff5..5e8697d 100644 (file)
@@ -51,12 +51,11 @@ if opt_eval.value then
 
        var parent = null
        if opt_loop.value then
-               var nruntime = modelbuilder.load_module("niti_runtime")
-               if nruntime == null then
+               parent = modelbuilder.get_mmodule_by_name(null, null, "niti_runtime")
+               if parent == null then
                        toolcontext.check_errors
                        abort
                end
-               parent = nruntime.mmodule
        end
 
        modelbuilder.load_rt_module(parent, amodule, "-")
index e466f74..4c8cf9c 100644 (file)
@@ -22,6 +22,9 @@ var toolcontext = new ToolContext
 # Disable `cached` because it causes issues when printing transformed AST. FIXME
 toolcontext.cached_phase.disabled = true
 
+# Try to colorize, even if programs are non valid
+toolcontext.keep_going = true
+
 var opt_fragment = new OptionBool("Omit document header and footer", "-f", "--fragment")
 var opt_first_line = new OptionInt("Start the source file at this line (default: 1)", 0, "--first-line")
 var opt_last_line = new OptionInt("End the source file at this line (default: to the end)", 0, "--last-line")
index 54320cc..f78024b 100644 (file)
 # Simple tool to list Nit source files
 module nitls
 
-intrude import modelbuilder
+import modelbuilder
 import ordered_tree
+import console
 
 class ProjTree
        super OrderedTree[Object]
 
        var opt_paths = false
+       var tc: ToolContext
 
        redef fun display(o)
        do
@@ -31,13 +33,53 @@ class ProjTree
                        if opt_paths then
                                return o.filepath.as(not null)
                        else
-                               return "{o.name} ({o.filepath.to_s})"
+                               var d = ""
+                               if o.mdoc != null then
+                                       if tc.opt_no_color.value then
+                                               d = ": {o.mdoc.content.first}"
+                                       else
+                                               d = ": {o.mdoc.content.first.green}"
+                                       end
+                               end
+                               if tc.opt_no_color.value then
+                                       return "{o.name}{d} ({o.filepath.to_s})"
+                               else
+                                       return "{o.name}{d} ({o.filepath.yellow})"
+                               end
                        end
                else if o isa ModulePath then
                        if opt_paths then
                                return o.filepath
                        else
-                               return "{o.name} ({o.filepath})"
+                               var d = ""
+                               var dd = ""
+                               if o.mmodule != null and o.mmodule.mdoc != null then
+                                       if tc.opt_no_color.value then
+                                               d = ": {o.mmodule.mdoc.content.first}"
+                                       else
+                                               d = ": {o.mmodule.mdoc.content.first.green}"
+                                       end
+                               end
+                               if o.mmodule != null and not o.mmodule.in_importation.direct_greaters.is_empty then
+                                       var ms = new Array[String]
+                                       for m in o.mmodule.in_importation.direct_greaters do
+                                               if m.mgroup.mproject == o.mmodule.mgroup.mproject then
+                                                       ms.add m.name
+                                               else
+                                                       ms.add m.full_name
+                                               end
+                                       end
+                                       if tc.opt_no_color.value then
+                                               dd = " ({ms.join(" ")})"
+                                       else
+                                               dd = " ({ms.join(" ")})".light_gray
+                                       end
+                               end
+                               if tc.opt_no_color.value then
+                                       return "{o.name.bold}{d} ({o.filepath.to_s}){dd}"
+                               else
+                                       return "{o.name.bold}{d} ({o.filepath.yellow}){dd}"
+                               end
                        end
                else
                        abort
@@ -45,6 +87,24 @@ class ProjTree
        end
 end
 
+class AlphaEntityComparator
+       super Comparator
+       fun nameof(a: COMPARED): String
+       do
+               if a isa MGroup then
+                       return a.name
+               else if a isa ModulePath then
+                       return a.name
+               else
+                       abort
+               end
+       end
+       redef fun compare(a,b)
+       do
+               return nameof(a) <=> nameof(b)
+       end
+end
+
 var tc = new ToolContext
 
 var opt_keep = new OptionBool("Ignore errors and files that are not a Nit source file", "-k", "--keep")
@@ -58,6 +118,7 @@ var opt_paths = new OptionBool("List only path (instead of name + path)", "-p",
 
 tc.option_context.add_option(opt_keep, opt_recursive, opt_tree, opt_source, opt_project, opt_depends, opt_paths, opt_make)
 tc.tooldescription = "Usage: nitls [OPTION]... <file.nit|directory>...\nLists the projects and/or paths of Nit sources files."
+tc.accept_no_arguments = true
 tc.process_options(args)
 
 if opt_make.value then
@@ -72,89 +133,141 @@ if sum > 1 then
        print tc.tooldescription
        exit 1
 end
+if sum == 0 then opt_project.value = true
+tc.keep_going = opt_keep.value
 
 var model = new Model
 var mb = new ModelBuilder(model, tc)
 
-if opt_depends.value then
-       if opt_recursive.value then
-               print "-M incompatible with -r"
-               exit 1
+if tc.option_context.rest.is_empty then tc.option_context.rest.add "."
+var files
+if opt_recursive.value then
+       files = new Array[String]
+       for d in tc.option_context.rest do
+               var pipe = new IProcess("find", d, "-name", "*.nit")
+               while not pipe.eof do
+                       var l = pipe.read_line
+                       if l == "" then break # last line
+                       l = l.substring(0,l.length-1) # strip last oef
+                       files.add l
+               end
+               pipe.close
+               pipe.wait
+               if pipe.status != 0 and not opt_keep.value then exit 1
        end
-
-       mb.parse(tc.option_context.rest)
 else
-       var files
-       if opt_recursive.value then
-               files = new Array[String]
-               for d in tc.option_context.rest do
-                       var pipe = new IProcess("find", d, "-name", "*.nit")
-                       while not pipe.eof do
-                               var l = pipe.read_line
-                               if l == "" then break # last line
-                               l = l.substring(0,l.length-1) # strip last oef
-                               files.add l
+       files = tc.option_context.rest
+end
+
+if sum == 0 then
+       # If one of the file is a group, default is `opt_tree` instead of `opt_project`
+       for a in files do
+               var g = mb.get_mgroup(a)
+               if g != null then
+                       opt_tree.value = true
+                       opt_project.value = false
+                       break
+               end
+       end
+end
+
+# Identify all relevant files
+for a in files do
+       var g = mb.get_mgroup(a)
+       var mp = mb.identify_file(a)
+       if g != null and not opt_project.value then
+               mb.visit_group(g)
+       end
+       if g == null and mp == null then
+               # not a group not a module, then look at files in the directory
+               var fs = a.files
+               for f in fs do
+                       g = mb.get_mgroup(a/f)
+                       if g != null and not opt_project.value then
+                               mb.visit_group(g)
                        end
-                       pipe.close
-                       pipe.wait
-                       if pipe.status != 0 and not opt_keep.value then exit 1
+                       mp = mb.identify_file(a/f)
+                       #print "{a/f}: {mp or else "?"}"
                end
-       else
-               files = tc.option_context.rest
        end
+end
 
-       for a in files do
-               var mp = mb.identify_file(a)
-               if mp == null then
-                       if not opt_keep.value then tc.check_errors
+# Load modules to get more informations
+for mp in mb.identified_files do
+       if not opt_paths.value or opt_depends.value then
+               var mm = mb.load_module(mp.filepath)
+               if mm != null and opt_depends.value then
+                       mb.build_module_importation(mm)
                end
        end
 end
+#tc.check_errors
 
-if sum == 0 then opt_project.value = true
 
+var ot = new ProjTree(tc)
+var sorter = new AlphaEntityComparator
 if opt_tree.value then
-       var ot = new ProjTree
        ot.opt_paths = opt_paths.value
        for p in model.mprojects do
                for g in p.mgroups do
-                       ot.add(g.parent, g)
+                       var pa = g.parent
+                       if g.is_interesting then
+                               ot.add(pa, g)
+                               pa = g
+                       end
                        for mp in g.module_paths do
-                               ot.add(g, mp)
+                               ot.add(pa, mp)
                        end
                end
        end
-       ot.sort_with(new CachedAlphaComparator)
+       ot.sort_with(sorter)
        ot.write_to(stdout)
 end
 
 if opt_source.value then
-       var list = new Array[String]
+       var list = new Array[ModulePath]
        for p in model.mprojects do
                for g in p.mgroups do
                        for mp in g.module_paths do
-                               if opt_paths.value then
-                                       list.add(mp.filepath)
-                               else
-                                       list.add("{g.full_name}/{mp.name} ({mp.filepath})")
-                               end
+                               list.add mp
                        end
                end
        end
-       alpha_comparator.sort(list)
-       for l in list do print l
+       sorter.sort(list)
+       for mp in list do
+               if opt_paths.value then
+                       print mp.filepath
+               else
+                       print "{mp.mgroup.full_name}/{ot.display(mp)}"
+               end
+       end
 end
 
 if opt_project.value then
-       var list = new Array[String]
+       var list = new Array[MGroup]
        for p in model.mprojects do
-               var path = p.root.filepath.as(not null)
+               list.add p.root.as(not null)
+       end
+       sorter.sort(list)
+       for g in list do
+               var path = g.filepath.as(not null)
                if opt_paths.value then
-                       list.add(path)
+                       print path
                else
-                       list.add("{p.name} ({path})")
+                       var d = ""
+                       var md = g.mdoc_or_fallback
+                       if md != null then
+                               if tc.opt_no_color.value then
+                                       d = ": {md.content.first}"
+                               else
+                                       d = ": {md.content.first.green}"
+                               end
+                       end
+                       if tc.opt_no_color.value then
+                               print "{g.name}{d} ({path})"
+                       else
+                               print "{g.name}{d} ({path.yellow})"
+                       end
                end
        end
-       alpha_comparator.sort(list)
-       for l in list do print l
 end
index cc0ffa2..4f31aaf 100644 (file)
@@ -22,6 +22,7 @@ module nitni_base
 
 import parser
 import modelbuilder # builder only for externcalls
+private import compiler::abstract_compiler
 
 redef class MMethod
        # Short name of this method in C (without the class name)
@@ -53,7 +54,8 @@ end
 
 redef class MModule
        # Mangled name of this module in C
-       fun cname: String do return name
+       fun cname: String do return c_name # FIXME this is a hack to keep the internal FFI
+       # API independent of the compilers while still using the `MModule::c_name` service.
 end
 
 redef class MMethodDef
index 32294c2..7ff0b16 100644 (file)
 
 # `nitpretty` is a tool able to pretty print Nit files.
 #
-# Usage:
-#
-#      nitpretty source.nit
-#
-# Main options:
-#
-# * `-o res.nit` output result into `res.nit`
-# * `--diff` show diff between `source` and `res`
-# * `--meld` open diff with `meld`
-# * `--check` check the format of multiple source files
-# * `--check --meld` perform `--check` and open `meld` for each difference
-#
-# ## Specification
-#
-# The specification of the pretty printing is described here.
-#
-# * Default indentation level is one `'\t'` character and
-# is increased by one for each indentation level.
-# * Default line max-size is 80.
-#
-# ### Comments
-#
-# There is many categories of comments:
-#
-# `Licence comments` are attached to the top of the file
-# no blank line before, one after.
-#
-#     # This is a licence comment
-#
-#     # Documentation for module `foo`
-#     module foo
-#
-# `ADoc` are documentation comments attached to a `AModule`, `AClassdef`, `APropdef`.
-#
-# They are printed before the definition with a blank line before and no after
-# at the same indentation level than the definition.
-#
-#     # Documentation for module `foo`
-#     module foo
-#
-#     # Documentation for class `Bar`
-#     class Bar
-#          # Documentation for method `baz`
-#          fun baz do end
-#     end
-#
-# `Block comments` are comments composed of one or more line rattached to nothing.
-# They are displayed with one blank line before and after at current indent level.
-#
-#     <blank>
-#     # block
-#     # comment
-#     <blank>
-#
-# `Attached comments` are comments attached to a production.
-# They are printed as this.
-#
-#     fun foo do # attached comment
-#     end
-#
-# `nitpretty` automatically remove multiple blanks between comments:
-#
-#     # Licence
-#     # ...
-#     <blank>
-#     # Block comment
-#
-# ### Inlining
-#
-# Productions are automatically inlined when possible.
-#
-# Conditions:
-#
-# * the production must be syntactically inlinable
-# * the inlined production length is less than `PrettyPrinterVisitor::max-size`
-# * the production do not contains any comments
-#
-# ### Modules
-#
-# * There is a blank between the module declaration and its imports
-# * There is no blank between imports and only one after
-# * There is a blank between each extern block definition
-# * There is a blank between each class definition
-# * There is no blank line at the end of the module
-#
-#     # Documentation for module `foo`
-#     module foo
-#
-#     import a
-#     # import b
-#     import c
-#
-#     # Documentation for class `Bar`
-#     class Bar end
-#
-#     class Baz end # not a `ADoc` comment
-#
-#
-# ### Classes
-#
-# * There is no blank between the class definition and its super-classes declarations
-# * There is no blank between two inlined property definition
-# * There is a blank between each block definition
-# * There no blank line at the end of the class definition
-#
-#     # Documentation for class `Bar`
-#     class Bar end
-#
-#     class Baz
-#          super Bar
-#
-#          fun a is abstract
-#          private fun b do end
-#
-#          fun c do
-#               # ...
-#          end
-#     end
-#
-# Generic types have no espace after or before brackets and are separated by a comma and a space:
-#
-#     class A[E: Type1, F: Type1] do end
-#
-# ### Blocks
-#
-# * Inlined productions have no blank lines between them
-# * Block productions have a blank before and after
-#
-#     var a = 10
-#     var b = 0
-#
-#     if a > b then
-#          # is positive
-#          print "positive"
-#     end
-#
-#     print "end"
-#
-# ### Calls and Binary Ops
-#
-# Arguments are always printed separated with a comma and a space:
-#
-#     foo(a, b, c)
-#
-# Binary ops are always printed wrapped with spaces:
-#
-#     var c = 1 + 2
-#
-# Calls and binary ops can be splitted to fit the `max-size` constraint.
-# Breaking priority is given to arguments declaration after the comma.
-#
-#     return foo("aaaaaaaaaaaaaaaaaaaaaaaaaa", "bbbbbbbbbbbbbbbbbbbbbbbbbbb",
-#        "cccccccccccccccccccccccccc")
-#
-# Binary ops can also be broken to fit the `max-size` limit:
-#
-#     return "aaaaaaaaaaaaaaaaaaaaaaaaaa" + "bbbbbbbbbbbbbbbbbbbbbbbbbbb" +
-#        "cccccccccccccccccccccccccc"
-#
-module nitpretty
-
-import template
-import toolcontext
-import modelbuilder
-import astutil
-
-# The `PrettyPrinterVisitor` is used to visit a node and pretty print it.
-#
-# The main method here is `visit` that performs the pretty printing of a `ANode`.
-#
-# Because some tokens like `TComment` are not stored in the AST,
-# we visit the AST like traditionnal visitor and also maintain a
-# pointer to the `current_token` (actually the next one to be printed).
-#
-# Visited productions are in charges to move the token pointer using methods such as:
-#
-# * `consume`: print `current_token` and move to the next one
-# * `skip`: move to the next token without printing the current one
-# * `skip_to`: move to a specified token skipping all the tokens before
-# * `catch_up`: consume all the tokens between `current_token` and a specified token
-# * `finish_line`: consume all the tokens between `current_token` and the end of line
-class PrettyPrinterVisitor
-       # Pretty print `n`.
-       fun pretty(n: ANode): Template do
-               clear
-               n.parentize_tokens
-
-               if n isa Prod then
-                       current_token = n.first_token
-                       visit n
-               else if n isa Token then
-                       var p = n.parent
-
-                       while p != null and not p isa Prod do
-                               p = p.parent
-                       end
-
-                       current_token = p.first_token
-                       visit p
-               end
-
-               return tpl.as(not null)
-       end
-
-       # Pretty print the whole `nmodule` with comments before and after.
-       fun pretty_nmodule(nmodule: AModule): Template do
-               clear
-               nmodule.parentize_tokens
-               current_token = nmodule.location.file.first_token
-               visit nmodule
-               catch_up nmodule.location.file.last_token
-               tpl.add "\n"
-               return tpl.as(not null)
-       end
-
-       # Prepare `self` for a new visit.
-       private fun clear do
-               tpl = new Template
-               current_token = null
-               indent = 0
-               current_length = 0
-               previous_length = 0
-               wait_addn = 0
-       end
-
-       # Visit `n` if not null.
-       fun visit(n: nullable ANode) do
-               if n == null then return
-               n.accept_pretty_printer self
-       end
-
-       # Visit a list of `Anode`.
-       fun visit_list(n: nullable ANodes[ANode]) do
-               if n == null then return
-               n.accept_pretty_printer self
-       end
-
-       # Is the node inlinable and can fit on the line.
-       fun can_inline(n: nullable ANode): Bool do
-               if n == null then return true
-               if n.must_be_inline then return true
-               if n.must_be_block then return false
-               # check length
-               if n.collect_length + current_length > max_size then return false
-               # check block is inlinable
-               return n.is_inlinable
-       end
-
-       # Collect all `TComment` between `from` and `to`.
-       fun collect_comments(from: nullable ANode, to: nullable ANode): Array[TComment] do
-               var res = new Array[TComment]
-               if from isa Prod then from = from.first_token
-               if to isa Prod then to = to.first_token
-               if from == null or to == null then return res
-
-               while from != to do
-                       if from isa TComment then res.add from
-                       from = from.as(Token).next_token
-               end
-
-               return res
-       end
-
-       # Token under cursor.
-       #
-       # This is the next token to visit.
-       var current_token: nullable Token = null
-
-       # Skip the `current_token`.
-       fun skip do current_token = current_token.next_token
-
-       # Skip `current_token` until the end of line.
-       fun skip_line do current_token = current_token.last_real_token_in_line
-
-       # Skip `current_token` until `target` is reached.
-       fun skip_to(target: nullable Token) do
-               if target == null then return
-               while current_token != target do skip
-       end
-
-       # Visit `current_token`.
-       fun consume(token: String) do
-               assert current_token.text == token
-               visit current_token
-       end
-
-       # Is there token to visit between `current_token` and `target`?
-       fun need_catch_up(target: nullable Token): Bool do
-               if target == null then return false
-               return current_token != target
-       end
-
-       # Visit all tokens between `current_token` and `target`.
-       fun catch_up(target: nullable ANode) do
-               if target == null then return
-               if current_token == null then return
-               var token: Token
-               if target isa Token then
-                       token = target
-               else if target isa Prod then
-                       token = target.first_token.as(not null)
-               else
-                       abort
-               end
-               assert current_token.location <= token.location
-               while current_token != token do visit current_token
-       end
-
-       # Visit all tokens between `current_token` and the end of line.
-       fun finish_line do
-               if current_token isa TComment then
-                       adds
-                       visit current_token
-               end
-
-               while current_token isa TEol do skip
-       end
-
-       # The template under construction.
-       private var tpl: nullable Template = null
-
-       # Current indent level.
-       var indent = 0
-
-       # Size of a tabulation in spaces.
-       var tab_size = 8
-
-       # Max line size.
-       var max_size = 80
-
-       # Length of the current line.
-       var current_length = 0
-
-       # Length of the previous line.
-       var previous_length = 0
-
-       # Is the last line a blank line?
-       fun last_line_is_blank: Bool do return previous_length == 0
-
-       # Add `t` to current template.
-       fun add(t: String) do
-               if t.is_empty then return
-               while wait_addn > 0 do
-                       tpl.add "\n"
-                       wait_addn -= 1
-               end
-               tpl.add t
-               current_length += t.length
-       end
-
-       # Add a `'\n'`.
-       fun addn do
-               if current_length == 0 and last_line_is_blank then return
-               previous_length = current_length
-               current_length = 0
-               wait_addn += 1
-       end
-
-       # End of line chars are stored until another char is added.
-       # This avoid empty files with only a '`\n`'.
-       private var wait_addn = 0
-
-       # Add `'\t' * indent`.
-       fun addt do add "\t" * indent
-
-       # Add a space.
-       fun adds do add " "
-
-       fun visit_recv(n_expr: AExpr) do
-               if not n_expr isa AImplicitSelfExpr then
-                       visit n_expr
-                       consume "."
-               end
-       end
-end
-
-# Base framework redefs
-
-redef class ANodes[E]
-       private fun accept_pretty_printer(v: PrettyPrinterVisitor) do
-               for e in self do
-                       var e_can_inline = v.can_inline(e)
-
-                       if e != first then
-                               if not e_can_inline then
-                                       v.add ","
-                                       v.addn
-                                       v.addt
-                                       v.addt
-                               else
-                                       v.add ", "
-                               end
-                       end
-
-                       v.visit e
-               end
-       end
-end
-
-redef class ANode
-       # Start visit of `self` using a `PrettyPrinterVisitor`
-       private fun accept_pretty_printer(v: PrettyPrinterVisitor) is abstract
-
-       # Collect the length (in `Char`) of the node.
-       private fun collect_length: Int is abstract
-
-       # Is `self` printable in one line?
-       private fun is_inlinable: Bool do return true
-
-       # Force `self` to be rendered as a block.
-       private var force_block = false
-
-       # Does `self` have to be rendered as a block?
-       private fun must_be_block: Bool do return force_block
-
-       # Force `self` to be rendered as a line.
-       private var force_inline = false
-
-       # Does `self` have be rendered as a line?
-       private fun must_be_inline: Bool do
-               if parent != null and parent.must_be_inline then return true
-               return force_inline
-       end
-
-       # Does `self` was written in one line before transformation?
-       private fun was_inline: Bool is abstract
-end
-
-redef class Token
-       redef fun accept_pretty_printer(v) do
-               v.add text.trim
-               v.current_token = next_token
-       end
-
-       redef fun collect_length do return text.length
-       redef fun is_inlinable do return true
-       redef fun was_inline do return true
-end
-
-redef class Prod
-       redef fun accept_pretty_printer(v) do v.visit first_token
-
-       # The token where the production really start (skipping ADoc).
-       private fun start_token: nullable Token do return first_token
-
-       # Collect all `TComment` contained in the production
-       # (between `start_token` and `end_token`).
-       private fun collect_comments: Array[TComment] do
-               var res = new Array[TComment]
-               if start_token == null or last_token == null then return res
-               var token = start_token
-
-               while token != last_token do
-                       if token isa TComment then res.add token
-                       token = token.next_token
-               end
-
-               return res
-       end
-
-       redef fun collect_length do
-               var res = 0
-               if start_token == null or last_token == null then return res
-               var token = start_token
-
-               while token != last_token do
-                       res += token.text.length
-                       token = token.next_token
-               end
-
-               res += token.text.length
-               return res
-       end
-
-       redef fun was_inline do
-               return first_token.location.line_start == last_token.location.line_end
-       end
-end
-
-# Comments
-
-redef class TComment
-       redef fun accept_pretty_printer(v) do
-               if is_adoc then
-                       v.addt
-                       super
-                       v.addn
-                       return
-               end
-
-               if is_licence then
-                       super
-                       v.addn
-                       if is_last_in_group then v.addn
-                       return
-               end
-
-               if is_orphan then
-                       v.addn
-                       v.addt
-                       super
-                       v.addn
-                       v.addn
-                       return
-               end
-
-               if is_inline then
-                       if next_token isa TComment and is_first_in_group then v.addn
-                       v.addt
-                       super
-                       v.addn
-                       var prev_token = self.prev_token
-                       if prev_token isa TComment and prev_token.is_inline and is_last_in_group then v.addn
-                       return
-               end
-
-               super
-       end
-
-       # Is `self` part of an `ADoc`?
-       private fun is_adoc: Bool do return parent isa ADoc and parent.parent != null
-
-       # Is `self` part of a licence?
-       private fun is_licence: Bool do
-               var prev_token = self.prev_token
-
-               if prev_token == null then
-                       return true
-               else if prev_token isa TComment then
-                       return prev_token.is_licence
-               else
-                       return false
-               end
-       end
-
-       # Is `self` starts and ends its line?
-       private fun is_inline: Bool do
-               return self == first_real_token_in_line and self == last_real_token_in_line
-       end
-
-       # Is `self` an orphan line (blank before and after)?
-       private fun is_orphan: Bool do
-               return prev_token isa TEol and
-                  (prev_token.prev_token isa TEol or prev_token.prev_token isa TComment) and
-                  next_token isa TEol
-       end
-
-       # Is `self` the first comment of a group of comment?
-       private fun is_first_in_group: Bool do return not prev_token isa TComment
-
-       # Is `self` the last comment of a group of comments?
-       private fun is_last_in_group: Bool do return not next_token isa TComment
-end
-
-redef class ADoc
-       redef fun accept_pretty_printer(v) do for comment in n_comment do v.visit comment
-       redef fun is_inlinable do return n_comment.length <= 1
-end
-
-# Annotations
-
-redef class AAnnotations
-       redef fun accept_pretty_printer(v) do
-               v.adds
-               v.consume "is"
-
-               if v.can_inline(self) then
-                       v.adds
-                       for n_item in n_items do
-                               v.visit n_item
-                               if n_item != n_items.last then
-                                       v.add ", "
-                               end
-                       end
-                       v.finish_line
-               else if n_items.length > 1 then
-                       v.addn
-                       v.indent += 1
-
-                       for n_item in n_items do
-                               v.addt
-                               v.visit n_item
-                               v.finish_line
-                               v.addn
-                       end
-
-                       v.indent -= 1
-               end
-               if not was_inline and v.current_token isa TKwend then v.skip
-       end
-
-       redef fun is_inlinable do
-               if not super then return false
-               for annot in n_items do if not annot.is_inlinable then return false
-               return true
-       end
-end
-
-redef class AAnnotation
-       redef fun accept_pretty_printer(v) do
-               v.visit n_atid
-               if not n_args.is_empty then
-                       if n_opar == null then
-                               v.adds
-                       else
-                               v.visit n_opar
-                       end
-                       v.visit_list n_args
-                       v.visit n_cpar
-               end
-       end
-end
-
-redef class ATypeExpr
-       redef fun accept_pretty_printer(v) do v.visit n_type
-end
-
-# Modules
-
-redef class AModule
-       redef fun accept_pretty_printer(v) do
-               v.catch_up start_token
-               v.visit n_moduledecl
-
-               if not n_imports.is_empty then
-                       v.addn
-
-                       for n_import in n_imports do
-                               v.catch_up n_import
-                               v.visit n_import
-                       end
-               end
-
-               if not n_extern_code_blocks.is_empty then
-                       v.addn
-
-                       for n_extern_block in n_extern_code_blocks do
-                               v.catch_up n_extern_block
-                               v.visit n_extern_block
-                               v.addn
-                               if n_extern_block != n_extern_code_blocks.last then v.addn
-                       end
-
-                       if not n_classdefs.is_empty then v.addn
-               end
-
-               if not n_classdefs.is_empty then
-                       v.addn
-
-                       for n_classdef in n_classdefs do
-                               v.catch_up n_classdef
-                               v.visit n_classdef
-                               if n_classdef != n_classdefs.last then v.addn
-                       end
-               end
-
-               assert v.indent == 0
-       end
-
-       # Skip doc if any.
-       redef fun start_token do
-               if n_moduledecl != null then return n_moduledecl.first_token
-               if not n_imports.is_empty then return n_imports.first.first_token
-               if not n_classdefs.is_empty then return n_classdefs.first.first_token
-               return first_token
-       end
-
-       redef fun is_inlinable do return false
-end
-
-redef class AModuledecl
-       redef fun accept_pretty_printer(v) do
-               v.visit n_doc
-               v.visit n_kwmodule
-               v.adds
-               v.visit n_name
-
-               if n_annotations != null then
-                       var annot_inline = v.can_inline(n_annotations)
-                       v.visit n_annotations
-
-                       if not annot_inline then
-                               if v.current_token isa TKwend then
-                                       v.consume "end"
-                                       v.finish_line
-                               else
-                                       v.add "end"
-                               end
-                       end
-               end
-
-               v.finish_line
-               v.addn
-       end
-end
-
-redef class AModuleName
-       redef fun accept_pretty_printer(v) do
-               for path in n_path do
-                       v.visit path
-                       v.add "::"
-               end
-
-               v.visit n_id
-       end
-end
-
-redef class ANoImport
-       redef fun accept_pretty_printer(v) do
-               v.visit n_kwimport
-               v.adds
-               v.visit n_kwend
-               v.finish_line
-               v.addn
-       end
-end
-
-redef class AStdImport
-       redef fun accept_pretty_printer(v) do
-               if not n_visibility isa APublicVisibility then
-                       v.visit n_visibility
-                       v.adds
-               end
-
-               v.visit n_kwimport
-               v.adds
-               v.visit n_name
-               v.finish_line
-               v.addn
-       end
-end
-
-# Classes
-
-redef class AClassdef
-       redef fun accept_pretty_printer(v) do
-               for n_propdef in n_propdefs do
-                       v.catch_up n_propdef
-
-                       if n_propdef.n_doc != null or not v.can_inline(n_propdef) then
-                               if n_propdef != n_propdefs.first then v.addn
-                               v.visit n_propdef
-                               if n_propdef != n_propdefs.last then v.addn
-                       else
-                               v.visit n_propdef
-                       end
-               end
-       end
-end
-
-redef class AStdClassdef
-       redef fun accept_pretty_printer(v) do
-               v.visit n_doc
-               var can_inline = v.can_inline(self)
-
-               if not n_visibility isa APublicVisibility then
-                       v.visit n_visibility
-                       v.adds
-               end
-
-               if n_kwredef != null then
-                       v.visit n_kwredef
-                       v.adds
-               end
-
-               v.visit n_classkind
-               v.adds
-               v.visit n_id
-
-               if not n_formaldefs.is_empty then
-                       v.consume "["
-                       v.visit_list n_formaldefs
-                       v.consume "]"
-               end
-
-               if n_extern_code_block != null then
-                       v.adds
-                       v.visit n_extern_code_block
-               end
-
-               if can_inline then
-                       v.adds
-
-                       if not n_superclasses.is_empty then
-                               for n_superclass in n_superclasses do
-                                       v.visit n_superclass
-                                       v.adds
-                               end
-                       end
-               else
-                       v.finish_line
-                       v.addn
-                       v.indent += 1
-
-                       for n_superclass in n_superclasses do
-                               v.catch_up n_superclass
-                               v.addt
-                               v.visit n_superclass
-                               v.finish_line
-                               v.addn
-                       end
-
-                       if not n_superclasses.is_empty and not n_propdefs.is_empty then
-                               v.addn
-                       end
-
-                       super
-                       v.catch_up n_kwend
-                       v.indent -= 1
-               end
-
-               v.visit n_kwend
-               v.finish_line
-               v.addn
-               assert v.indent == 0
-       end
-
-       redef fun is_inlinable do
-               if not super then return false
-               if not n_propdefs.is_empty then return false
-               if n_superclasses.length > 1 then return false
-               if not collect_comments.is_empty then return false
-               return true
-       end
-
-       redef fun start_token do
-               if not n_visibility isa APublicVisibility then return n_visibility.first_token
-               if n_kwredef != null then return n_kwredef
-               return n_classkind.first_token
-       end
-end
-
-redef class AAbstractClasskind
-       redef fun accept_pretty_printer(v) do
-               v.visit n_kwabstract
-               v.adds
-               v.visit n_kwclass
-       end
-end
-
-redef class AExternClasskind
-       redef fun accept_pretty_printer(v) do
-               v.visit n_kwextern
-               v.adds
-               v.visit n_kwclass
-       end
-end
-
-redef class AFormaldef
-       redef fun accept_pretty_printer(v) do
-               v.visit n_id
-
-               if n_type != null then
-                       v.consume ":"
-                       v.adds
-                       v.visit n_type
-               end
-       end
-end
-
-redef class AType
-       redef fun accept_pretty_printer(v) do
-               if n_kwnullable != null then
-                       v.visit n_kwnullable
-                       v.adds
-               end
-
-               v.visit n_id
-
-               if not n_types.is_empty then
-                       v.consume "["
-                       v.visit_list n_types
-                       v.consume "]"
-               end
-       end
-end
-
-redef class ASuperclass
-       redef fun accept_pretty_printer(v) do
-               v.visit n_kwsuper
-               v.adds
-               v.visit n_type
-       end
-end
-
-# Properties
-
-redef class APropdef
-       redef fun accept_pretty_printer(v) do
-               v.visit n_doc
-               v.addt
-
-               if not n_visibility isa APublicVisibility then
-                       v.visit n_visibility
-                       v.adds
-               end
-
-               if n_kwredef != null then
-                       v.visit n_kwredef
-                       v.adds
-               end
-       end
-
-       redef fun start_token do
-               if n_doc == null then return super
-               return n_doc.last_token.next_token
-       end
-end
-
-redef class AAttrPropdef
-       redef fun accept_pretty_printer(v) do
-               super
-               v.visit n_kwvar
-               v.adds
-               v.visit n_id2
-
-               if n_type != null then
-                       v.consume ":"
-                       v.adds
-                       v.visit n_type
-               end
-
-               if n_expr != null then
-                       v.adds
-                       v.consume "="
-                       v.adds
-                       v.visit n_expr
-               end
-
-               if n_annotations != null then v.visit n_annotations
-               v.finish_line
-               v.addn
-       end
-
-       redef fun first_token do
-               if n_doc != null then return n_doc.first_token
-               if not n_visibility isa APublicVisibility then return n_visibility.first_token
-               if n_kwredef != null then return n_kwredef
-               return n_kwvar
-       end
-
-       redef fun is_inlinable do return true
-end
-
-redef class ATypePropdef
-       redef fun accept_pretty_printer(v) do
-               super
-               v.visit n_kwtype
-               v.adds
-               v.visit n_id
-               v.consume ":"
-               v.adds
-               v.visit n_type
-               v.finish_line
-               v.addn
-       end
-
-       redef fun is_inlinable do return true
-end
-
-redef class AMethPropdef
-       redef fun accept_pretty_printer(v) do
-               #  TODO: Handle extern annotations
-
-               var before = v.indent
-               var can_inline = v.can_inline(self)
-               super
-               if n_kwinit != null then v.visit n_kwinit
-               if n_kwmeth != null then v.visit n_kwmeth
-               if n_kwnew != null then v.visit n_kwnew
-
-               if not n_methid == null then
-                       v.adds
-                       v.visit n_methid
-               end
-
-               v.visit n_signature
-
-               if n_annotations != null then
-                       v.visit n_annotations
-               else
-                       v.adds
-               end
-
-               if n_extern_calls != null or n_extern_code_block != null then
-                       if n_annotations != null then v.adds
-                       if n_extern_calls != null then v.visit n_extern_calls
-                       if n_extern_code_block != null then v.visit n_extern_code_block
-               end
-
-               var n_block = self.n_block
-
-               if n_block != null then
-                       while not v.current_token isa TKwdo do v.skip
-                       if n_annotations != null then
-                               if v.can_inline(n_annotations) then
-                                       v.adds
-                               else
-                                       v.addt
-                               end
-                       end
-                       v.consume "do"
-
-                       if can_inline then
-                               v.adds
-
-                               if n_block isa ABlockExpr then
-                                       if n_block.n_expr.is_empty then
-                                               v.visit n_block.n_kwend
-                                       else
-                                               v.visit n_block.n_expr.first
-                                               v.current_token = n_block.n_kwend
-                                               v.skip
-                                       end
-                               else
-                                       v.visit n_block
-                                       if v.current_token isa TKwend then v.skip
-                               end
-                       else
-                               v.finish_line
-                               v.addn
-                               v.indent += 1
-
-                               if n_block isa ABlockExpr then
-                                       n_block.force_block = true
-                                       v.visit n_block
-                                       v.catch_up n_block.n_kwend
-                               else
-                                       v.addt
-                                       v.visit n_block
-                                       v.addn
-                               end
-
-                               v.indent -= 1
-                               v.addt
-                               if n_block isa ABlockExpr then
-                                       v.visit n_block.n_kwend
-                               else
-                                       v.add "end"
-                               end
-                       end
-               end
-
-               v.finish_line
-               v.addn
-               assert v.indent == before
-       end
-
-       # Can be inlined if:
-       # * block is empty or can be inlined
-       # * contains no comments
-       redef fun is_inlinable do
-               if not super then return false
-               if n_annotations != null and not n_annotations.is_inlinable then return false
-               if n_block != null and not n_block.is_inlinable then return false
-               if n_extern_calls != null and not n_extern_calls.is_inlinable then return false
-               if n_extern_code_block != null and not n_extern_code_block.is_inlinable then return false
-               if not collect_comments.is_empty then return false
-               return true
-       end
-end
-
-redef class AMainMethPropdef
-       redef fun accept_pretty_printer(v) do
-               v.visit n_block
-               v.addn
-       end
-end
-
-redef class ASignature
-       redef fun accept_pretty_printer(v) do
-               if not n_params.is_empty then
-                       v.consume "("
-                       v.visit_list n_params
-                       v.consume ")"
-               end
-
-               if n_type != null then
-                       v.consume ":"
-                       v.adds
-                       v.visit n_type
-               end
-       end
-end
-
-redef class AParam
-       redef fun accept_pretty_printer(v) do
-               v.visit n_id
-
-               if n_type != null then
-                       v.consume ":"
-                       v.adds
-                       v.visit n_type
-               end
-
-               if n_dotdotdot != null then v.visit n_dotdotdot
-       end
-end
-
-# Extern
-
-redef class AExternCalls
-       redef fun accept_pretty_printer(v) do
-               var can_inline = v.can_inline(self)
-               v.visit n_kwimport
-
-               if can_inline then
-                       v.adds
-                       v.visit_list n_extern_calls
-               else
-                       v.addn
-                       v.addt
-                       v.addt
-                       v.visit_list n_extern_calls
-               end
-
-               v.adds
-       end
-end
-
-redef class AFullPropExternCall
-       redef fun accept_pretty_printer(v) do
-               v.visit n_type
-               v.visit n_dot
-               v.visit n_methid
-       end
-end
-
-redef class ALocalPropExternCall
-       redef fun accept_pretty_printer(v) do v.visit n_methid
-end
-
-redef class AInitPropExternCall
-       redef fun accept_pretty_printer(v) do v.visit n_type
-end
-
-redef class ACastAsExternCall
-       redef fun accept_pretty_printer(v) do
-               v.visit n_from_type
-               v.visit n_dot
-               v.visit n_kwas
-               v.consume "("
-               v.visit n_to_type
-               v.consume ")"
-       end
-end
-
-redef class AAsNullableExternCall
-       redef fun accept_pretty_printer(v) do
-               v.visit n_type
-               v.consume "."
-               v.visit n_kwas
-               v.adds
-               v.visit n_kwnullable
-       end
-end
-
-redef class AAsNotNullableExternCall
-       redef fun accept_pretty_printer(v) do
-               v.visit n_type
-               v.consume "."
-               v.visit n_kwas
-               v.adds
-               v.visit n_kwnot
-               v.adds
-               v.visit n_kwnullable
-       end
-end
-
-redef class AExternCodeBlock
-       redef fun accept_pretty_printer(v) do
-               if n_in_language != null then
-                       v.visit n_in_language
-                       v.adds
-               end
-
-               v.visit n_extern_code_segment
-       end
-
-       redef fun is_inlinable do
-               if not super then return false
-               return n_extern_code_segment.is_inlinable
-       end
-end
-
-redef class AInLanguage
-       redef fun accept_pretty_printer(v) do
-               v.visit n_kwin
-               v.adds
-               v.visit n_string
-       end
-end
-
-redef class TExternCodeSegment
-       redef fun accept_pretty_printer(v) do
-               var can_inline = v.can_inline(self)
-
-               if can_inline then
-                       super
-               else
-                       var text = text.substring(2, text.length - 4)
-                       var lines = text.r_trim.split("\n")
-
-                       if text.is_empty then
-                               v.add "`\{`\}"
-                       else
-                               v.add "`\{"
-
-                               if not lines.first.trim.is_empty then
-                                       v.addn
-                                       lines.first.l_trim
-                                       v.indent += 1
-                                       v.addt
-                                       v.indent -= 1
-                               end
-
-                               for line in lines do
-                                       v.add line.r_trim
-                                       v.addn
-                               end
-
-                               v.addt
-                               v.add "`\}"
-                       end
-
-                       v.current_token = next_token
-               end
-       end
-
-       redef fun is_inlinable do
-               if not super then return false
-               return location.line_start == location.line_end
-       end
-end
-
-# Blocks
-
-redef class ABlockExpr
-       redef fun accept_pretty_printer(v) do
-               var before = v.indent
-               var can_inline = v.can_inline(self)
-
-               if can_inline and not n_expr.is_empty then
-                       v.visit n_expr.first
-                       v.finish_line
-               else
-                       for nexpr in n_expr do
-                               var expr_inline = v.can_inline(nexpr)
-                               if not expr_inline and nexpr != n_expr.first then v.addn
-                               v.catch_up nexpr
-                               v.addt
-                               v.visit nexpr
-                               v.finish_line
-                               v.addn
-                               if not expr_inline and nexpr != n_expr.last then v.addn
-                       end
-               end
-
-               assert v.indent == before
-       end
-
-       redef fun is_inlinable do
-               if not super then return false
-               if not collect_comments.is_empty then return false
-
-               if not n_expr.is_empty then
-                       if n_expr.length > 1 then return false
-                       if not n_expr.first.is_inlinable then return false
-               end
-
-               return true
-       end
-end
-
-redef class AIfExpr
-       redef fun accept_pretty_printer(v) do
-               var before = v.indent
-               var can_inline = v.can_inline(self)
-               v.visit n_kwif
-               v.adds
-
-               if v.can_inline(n_expr) then
-                       v.visit n_expr
-                       v.adds
-               else
-                       v.visit n_expr
-                       v.addn
-                       v.addt
-               end
-
-               # skip comments before `then` token
-               while not v.current_token isa TKwthen do v.skip
-               v.consume "then"
-               var n_else = self.n_else
-
-               if can_inline then
-                       v.adds
-                       if n_then != null then v.visit n_then
-
-                       if has_else(v) then
-                               n_else.force_inline = true
-                               v.adds
-                               v.consume "else"
-                               v.adds
-                               v.visit n_else
-                       else if n_then == null then
-                               v.add "end"
-                       end
-
-                       v.skip_to last_token.last_real_token_in_line
-               else
-                       v.finish_line
-                       v.addn
-                       v.indent += 1
-
-                       if n_then != null then
-                               if n_then isa ABlockExpr then
-                                       n_then.force_block = true
-                                       v.visit n_then
-                               else
-                                       v.addt
-                                       v.visit n_then
-                                       v.addn
-                               end
-                       end
-
-                       if has_else(v) then
-                               while not v.current_token isa TKwelse do
-                                       v.consume v.current_token.text
-                               end
-
-                               v.indent -= 1
-                               v.addt
-                               v.consume "else"
-
-                               if n_else isa AIfExpr then
-                                       n_else.force_block = true
-                                       v.adds
-                                       v.visit n_else
-                               else
-                                       v.finish_line
-                                       v.addn
-                                       v.indent += 1
-
-                                       if n_else isa ABlockExpr then
-                                               n_else.force_block = true
-                                               v.visit n_else
-                                       else
-                                               v.addt
-                                               v.visit n_else
-                                               v.addn
-                                       end
-
-                                       if last_token isa TKwend then
-                                               v.catch_up last_token
-                                               v.indent -= 1
-                                               v.addt
-                                               v.consume "end"
-                                       else
-                                               v.indent -= 1
-                                               v.addt
-                                               v.add "end"
-                                       end
-                               end
-                       else
-                               if last_token.location >= v.current_token.location then v.catch_up last_token
-                               v.indent -= 1
-                               v.addt
-                               v.add "end"
-                               if v.current_token isa TKwend then v.skip
-                       end
-               end
-
-               assert v.indent == before
-       end
-
-       redef fun is_inlinable do
-               if not super then return false
-               if n_then != null and not n_then.is_inlinable then return false
-               var n_else = self.n_else
-               if (n_else isa ABlockExpr and not n_else.n_expr.is_empty) or
-                  (not n_else isa ABlockExpr and n_else != null) then
-                       return false
-               end
-               if not collect_comments.is_empty then return false
-               return true
-       end
-
-       # Does this `if` statement contains a `else` part?
-       private fun has_else(v: PrettyPrinterVisitor): Bool do
-               var n_else = n_else
-               if n_else == null then return false
-               var n_kwelse = collect_kwelse
-               if n_kwelse == null then return false
-
-               if n_else isa ABlockExpr then
-                       var comments: Array[TComment]
-
-                       if n_then == null then
-                               comments = v.collect_comments(n_expr.last_token, n_else.last_token)
-                       else
-                               comments = v.collect_comments(n_then.last_token, n_else.last_token)
-                       end
-
-                       if not comments.is_empty then return true
-                       return not n_else.n_expr.is_empty
-               end
-
-               return true
-       end
-
-       # Lookup for `else` token in `self`.
-       private fun collect_kwelse: nullable TKwelse do
-               var token = first_token
-
-               while token != last_token do
-                       if token isa TKwelse then return token
-                       token = token.next_token
-               end
-
-               return null
-       end
-end
-
-# Used to factorize work on loops.
-private class ALoopHelper
-       super AExpr
-
-       fun loop_block: nullable ANode is abstract
-       fun loop_label: nullable ANode is abstract
-
-       fun visit_loop_block(v: PrettyPrinterVisitor) do
-               var n_block = loop_block
-               v.finish_line
-               v.addn
-               v.indent += 1
-
-               if n_block isa ABlockExpr then
-                       n_block.force_block = true
-                       v.visit n_block
-                       v.catch_up n_block.n_kwend
-                       v.indent -= 1
-                       v.addt
-                       v.visit n_block.n_kwend
-               else
-                       v.addt
-                       v.visit n_block
-                       v.addn
-                       v.indent -= 1
-                       v.addt
-                       v.add "end"
-               end
-
-               if loop_label != null then
-                       v.adds
-                       v.visit loop_label
-               end
-       end
-
-       fun visit_loop_inline(v: PrettyPrinterVisitor) do
-               var n_block = loop_block
-               v.adds
-
-               if n_block isa ABlockExpr then
-                       if n_block.n_expr.is_empty then
-                               v.visit n_block.n_kwend
-                       else
-                               v.visit n_block.n_expr.first
-                               v.current_token = n_block.n_kwend
-                               v.skip
-                       end
-               else
-                       v.visit n_block
-                       if v.current_token isa TKwend then v.skip
-               end
-
-               if loop_label != null then
-                       v.adds
-                       v.visit loop_label
-               end
-       end
-
-       redef fun is_inlinable do
-               var n_block = loop_block
-               if not super then return false
-               if n_block isa ABlockExpr and not n_block.is_inlinable then return false
-               if not collect_comments.is_empty then return false
-               return true
-       end
-end
-
-redef class ALoopExpr
-       super ALoopHelper
-
-       redef fun loop_block do return n_block
-       redef fun loop_label do return n_label
-
-       redef fun accept_pretty_printer(v) do
-               var can_inline = v.can_inline(self)
-               v.visit n_kwloop
-               if can_inline then visit_loop_inline v else visit_loop_block v
-       end
-end
-
-redef class AWhileExpr
-       super ALoopHelper
-
-       redef fun loop_block do return n_block
-       redef fun loop_label do return n_label
-
-       redef fun accept_pretty_printer(v) do
-               var can_inline = v.can_inline(self)
-               v.visit n_kwwhile
-               v.adds
-               v.visit n_expr
-               v.adds
-               v.visit n_kwdo
-               if can_inline then visit_loop_inline v else visit_loop_block v
-       end
-end
-
-redef class ADoExpr
-       super ALoopHelper
-
-       redef fun loop_block do return n_block
-       redef fun loop_label do return n_label
-
-       redef fun accept_pretty_printer(v) do
-               var can_inline = v.can_inline(self)
-               v.visit n_kwdo
-               if can_inline then visit_loop_inline v else visit_loop_block v
-       end
-end
-
-redef class AForExpr
-       super ALoopHelper
-
-       redef fun loop_block do return n_block
-       redef fun loop_label do return n_label
-
-       redef fun accept_pretty_printer(v) do
-               var can_inline = v.can_inline(self)
-               v.visit n_kwfor
-               v.adds
-
-               for n_id in n_ids do
-                       v.visit n_id
-                       if n_id != n_ids.last then v.add ", "
-               end
-
-               v.adds
-               v.consume "in"
-               v.adds
-               v.visit n_expr
-               v.adds
-               v.visit n_kwdo
-               if can_inline then visit_loop_inline v else visit_loop_block v
-       end
-end
-
-redef class ABreakExpr
-       redef fun accept_pretty_printer(v) do
-               v.visit n_kwbreak
-
-               if n_expr != null then
-                       v.adds
-                       v.visit n_expr
-               end
-
-               if n_label != null then
-                       v.adds
-                       v.visit n_label
-               end
-       end
-
-       redef fun is_inlinable do return true
-end
-
-redef class AContinueExpr
-       redef fun accept_pretty_printer(v) do
-               v.visit n_kwcontinue
-
-               if n_expr != null then
-                       v.adds
-                       v.visit n_expr
-               end
-
-               if n_label != null then
-                       v.adds
-                       v.visit n_label
-               end
-       end
-
-       redef fun is_inlinable do return true
-end
-
-# Calls
-
-redef class ASendExpr
-       redef fun is_inlinable do return true
-end
-
-redef class ACallExpr
-       redef fun accept_pretty_printer(v) do
-               var can_inline = v.can_inline(self)
-               v.visit_recv n_expr
-
-               if not n_expr isa AImplicitSelfExpr and not can_inline then
-                       v.addn
-                       v.addt
-                       v.addt
-               end
-
-               v.visit n_id
-
-               if not n_args.n_exprs.is_empty then
-                       if is_stmt and n_args.n_exprs.length == 1 then
-                               v.adds
-                               if v.current_token isa TOpar then v.skip
-                               v.visit n_args.n_exprs.first
-                               if v.current_token isa TCpar then v.skip
-                       else
-                               if v.current_token isa TOpar then
-                                       v.consume "("
-                               else
-                                       v.adds
-                               end
-
-                               v.visit_list n_args.n_exprs
-                               if v.current_token isa TCpar then v.consume ")"
-                       end
-               end
-       end
-
-       # Is the call alone on its line?
-       fun is_stmt: Bool do return parent isa ABlockExpr
-end
-
-redef class ACallAssignExpr
-       redef fun accept_pretty_printer(v) do
-               v.visit_recv n_expr
-               v.visit n_id
-
-               if not n_args.n_exprs.is_empty then
-                       v.consume "("
-                       v.visit_list n_args.n_exprs
-                       v.consume ")"
-               end
-
-               v.adds
-               v.consume "="
-               v.adds
-               v.visit n_value
-       end
-end
-
-redef class ACallReassignExpr
-       redef fun accept_pretty_printer(v) do
-               v.visit_recv n_expr
-               v.visit n_id
-
-               if not n_args.n_exprs.is_empty then
-                       v.consume "("
-                       v.visit_list n_args.n_exprs
-                       v.consume ")"
-               end
-
-               v.adds
-               v.visit n_assign_op
-               v.adds
-               v.visit n_value
-       end
-end
-
-redef class ABraExpr
-       redef fun accept_pretty_printer(v) do
-               v.visit n_expr
-
-               if not n_args.n_exprs.is_empty then
-                       v.consume "["
-                       v.visit_list n_args.n_exprs
-                       v.consume "]"
-               end
-       end
-end
-
-redef class ABraAssignExpr
-       redef fun accept_pretty_printer(v) do
-               v.visit n_expr
-
-               if not n_args.n_exprs.is_empty then
-                       v.consume "["
-                       v.visit_list n_args.n_exprs
-                       v.consume "]"
-               end
-
-               v.adds
-               v.visit n_assign
-               v.adds
-               v.visit n_value
-       end
-end
-
-redef class ABraReassignExpr
-       redef fun accept_pretty_printer(v) do
-               v.visit n_expr
-
-               if not n_args.n_exprs.is_empty then
-                       v.consume "["
-                       v.visit_list n_args.n_exprs
-                       v.consume "]"
-               end
-
-               v.adds
-               v.visit n_assign_op
-               v.adds
-               v.visit n_value
-       end
-end
-
-redef class AAssignMethid
-       redef fun accept_pretty_printer(v) do
-               v.visit n_id
-               v.visit n_assign
-       end
-end
-
-redef class ABraMethid
-       redef fun accept_pretty_printer(v) do
-               v.visit n_obra
-               v.visit n_cbra
-       end
-end
-
-redef class ABraassignMethid
-       redef fun accept_pretty_printer(v) do
-               v.visit n_obra
-               v.visit n_cbra
-               v.visit n_assign
-       end
-end
-
-redef class AInitExpr
-       redef fun accept_pretty_printer(v) do
-               if not n_expr isa AImplicitSelfExpr then
-                       v.visit n_expr
-                       v.consume "."
-               end
-
-               v.visit n_kwinit
-
-               if not n_args.n_exprs.is_empty then
-                       v.consume "("
-                       v.visit_list n_args.n_exprs
-                       v.consume ")"
-               end
-       end
-end
-
-redef class ANewExpr
-       redef fun accept_pretty_printer(v) do
-               var can_inline = v.can_inline(self)
-               v.visit n_kwnew
-               v.adds
-               v.visit n_type
-
-               if n_id != null then
-                       v.consume "."
-
-                       if not can_inline then
-                               v.addn
-                               v.addt
-                               v.addt
-                       end
-
-                       v.visit n_id
-               end
-
-               if not n_args.n_exprs.is_empty then
-                       v.consume "("
-                       v.visit_list n_args.n_exprs
-                       v.consume ")"
-               end
-       end
-
-       redef fun is_inlinable do return true
-end
-
-# Attributes
-
-redef class AAttrExpr
-       redef fun accept_pretty_printer(v) do
-               v.visit_recv n_expr
-               v.visit n_id
-       end
-
-       redef fun is_inlinable do return true
-end
-
-redef class AAttrAssignExpr
-       redef fun accept_pretty_printer(v) do
-               v.visit_recv n_expr
-               v.visit n_id
-               v.adds
-               v.visit n_assign
-               v.adds
-               v.visit n_value
-       end
-end
-
-redef class AAttrReassignExpr
-       redef fun accept_pretty_printer(v) do
-               v.visit_recv n_expr
-               v.visit n_id
-               v.adds
-               v.visit n_assign_op
-               v.adds
-               v.visit n_value
-       end
-end
-
-# Exprs
-
-redef class AVardeclExpr
-       redef fun accept_pretty_printer(v) do
-               v.visit n_kwvar
-               v.adds
-               v.visit n_id
-
-               if n_type != null then
-                       v.consume ":"
-                       v.adds
-                       v.visit n_type
-               end
-
-               if n_expr != null then
-                       v.adds
-                       v.consume "="
-                       v.adds
-                       v.visit n_expr
-               end
-       end
-
-       redef fun is_inlinable do return true
-end
-
-redef class AVarAssignExpr
-       redef fun accept_pretty_printer(v) do
-               v.visit n_id
-               v.adds
-               v.visit n_assign
-               v.adds
-               v.visit n_value
-       end
-end
-
-redef class AAssertExpr
-       redef fun accept_pretty_printer(v) do
-               var can_inline = v.can_inline(self)
-               v.visit n_kwassert
-
-               if n_id != null then
-                       v.adds
-                       v.visit n_id
-                       v.consume ":"
-               end
-
-               v.adds
-               v.visit n_expr
-               var n_else = self.n_else
-
-               if n_else != null then
-                       v.adds
-                       v.consume "else"
-
-                       if can_inline then
-                               v.adds
-                               v.visit n_else
-                       else
-                               v.addn
-
-                               if n_else isa ABlockExpr then
-                                       v.indent += 1
-                                       n_else.force_block = true
-                                       v.visit n_else
-                                       v.indent -= 1
-                                       v.addt
-                                       v.visit n_else.n_kwend
-                               else
-                                       v.indent += 1
-                                       v.addt
-                                       v.visit n_else
-                                       v.addn
-                                       v.indent -= 1
-                                       v.addt
-                                       v.add "end"
-                               end
-                       end
-               end
-       end
-
-       redef fun is_inlinable do
-               if not super then return false
-               if n_else != null and not n_else.is_inlinable then return false
-               return true
-       end
-end
-
-redef class AReturnExpr
-       redef fun accept_pretty_printer(v) do
-               v.visit n_kwreturn
-
-               if n_expr != null then
-                       v.adds
-                       v.visit n_expr
-               end
-       end
-end
-
-redef class ASuperExpr
-       redef fun accept_pretty_printer(v) do
-               v.visit n_kwsuper
-
-               if not n_args.n_exprs.is_empty then
-                       if is_stmt and n_args.n_exprs.length == 1 then
-                               v.adds
-                               if v.current_token isa TOpar then v.skip
-                               v.visit n_args.n_exprs.first
-                               if v.current_token isa TCpar then v.skip
-                       else
-                               if v.current_token isa TOpar then
-                                       v.consume "("
-                               else
-                                       v.adds
-                               end
-
-                               v.visit_list n_args.n_exprs
-                               if v.current_token isa TCpar then v.consume ")"
-                       end
-               end
-       end
-
-       # Is the call alone on its line?
-       fun is_stmt: Bool do return self.first_token.is_starting_line
-
-       redef fun is_inlinable do return true
-end
-
-redef class AOnceExpr
-       redef fun accept_pretty_printer(v) do
-               v.visit n_kwonce
-               v.adds
-               v.visit n_expr
-       end
-
-       redef fun is_inlinable do return true
-end
-
-redef class AAbortExpr
-       redef fun accept_pretty_printer(v) do v.visit n_kwabort
-       redef fun is_inlinable do return true
-end
-
-redef class ANotExpr
-       redef fun accept_pretty_printer(v) do
-               v.visit n_kwnot
-               v.adds
-               v.visit n_expr
-       end
-end
-
-redef class AAsCastExpr
-       redef fun accept_pretty_printer(v) do
-               v.visit n_expr
-               v.consume "."
-               v.visit n_kwas
-               v.visit n_opar
-               v.visit n_type
-               v.visit n_cpar
-       end
-end
-
-redef class AAsNotnullExpr
-       redef fun accept_pretty_printer(v) do
-               v.visit n_expr
-               v.consume "."
-               v.visit n_kwas
-               v.visit n_opar
-               v.visit n_kwnot
-               v.adds
-               v.visit n_kwnull
-               v.visit n_cpar
-       end
-end
-
-# Binops
-
-# Used to factorize work on Or, And, Implies and Binop expressions.
-private class ABinOpHelper
-       super AExpr
-
-       fun bin_expr1: AExpr is abstract
-       fun bin_expr2: AExpr is abstract
-
-       # Operator string
-       fun bin_op: String is abstract
-
-       redef fun accept_pretty_printer(v) do
-               var can_inline = v.can_inline(self)
-
-               if not can_inline then
-                       if (self isa ABinopExpr and bin_expr1 isa ABinopExpr) or
-                          (self isa AAndExpr and (bin_expr1 isa AAndExpr or bin_expr1 isa AOrExpr)) or
-                          (self isa AOrExpr and (bin_expr1 isa AAndExpr or bin_expr1 isa AOrExpr))
-                       then
-                               bin_expr1.force_block = true
-                       end
-               end
-
-               v.visit bin_expr1
-               v.adds
-               v.consume bin_op
-
-               if can_inline then
-                       v.adds
-                       v.visit bin_expr2
-               else
-                       v.addn
-                       v.addt
-                       v.addt
-                       v.visit bin_expr2
-               end
-       end
-end
-
-redef class AAndExpr
-       super ABinOpHelper
-
-       redef fun bin_expr1 do return n_expr
-       redef fun bin_expr2 do return n_expr2
-       redef fun bin_op do return "and"
-end
-
-redef class AOrExpr
-       super ABinOpHelper
-
-       redef fun bin_expr1 do return n_expr
-       redef fun bin_expr2 do return n_expr2
-       redef fun bin_op do return "or"
-end
-
-redef class AImpliesExpr
-       super ABinOpHelper
-
-       redef fun bin_expr1 do return n_expr
-       redef fun bin_expr2 do return n_expr2
-       redef fun bin_op do return "implies"
-end
-
-redef class ABinopExpr
-       super ABinOpHelper
-
-       redef fun bin_expr1 do return n_expr
-       redef fun bin_expr2 do return n_expr2
-end
-
-redef class AEqExpr
-       redef fun bin_op do return "=="
-end
-
-redef class AGeExpr
-       redef fun bin_op do return ">="
-end
-
-redef class AGgExpr
-       redef fun bin_op do return ">>"
-end
-
-redef class AGtExpr
-       redef fun bin_op do return ">"
-end
-
-redef class ALeExpr
-       redef fun bin_op do return "<="
-end
-
-redef class ALlExpr
-       redef fun bin_op do return "<<"
-end
-
-redef class ALtExpr
-       redef fun bin_op do return "<"
-end
-
-redef class AMinusExpr
-       redef fun bin_op do return "-"
-end
-
-redef class ANeExpr
-       redef fun bin_op do return "!="
-end
-
-redef class APercentExpr
-       redef fun bin_op do return "%"
-end
-
-redef class APlusExpr
-       redef fun bin_op do return "+"
-end
-
-redef class ASlashExpr
-       redef fun bin_op do return "/"
-end
-
-redef class AStarExpr
-       redef fun bin_op do return "*"
-end
-
-redef class AStarstarExpr
-       redef fun bin_op do return "**"
-end
-
-redef class AStarshipExpr
-       redef fun bin_op do return "<=>"
-end
-
-redef class AIsaExpr
-       redef fun accept_pretty_printer(v) do
-               v.visit n_expr
-               v.adds
-               v.consume "isa"
-               v.adds
-               v.visit n_type
-       end
-end
-
-redef class AOrElseExpr
-       redef fun accept_pretty_printer(v) do
-               v.visit n_expr
-               v.adds
-               v.consume "or"
-               v.adds
-               v.consume "else"
-               v.adds
-               v.visit n_expr2
-       end
-
-       redef fun is_inlinable do return true
-end
-
-# Syntax
-
-redef class AUminusExpr
-       redef fun accept_pretty_printer(v) do
-               v.consume "-"
-               v.visit n_expr
-       end
-end
-
-redef class ANullExpr
-       redef fun accept_pretty_printer(v) do v.visit n_kwnull
-       redef fun is_inlinable do return true
-end
-
-redef class AParExpr
-       redef fun accept_pretty_printer(v) do
-               v.visit n_opar
-               v.visit n_expr
-               v.visit n_cpar
-       end
-end
-
-redef class AArrayExpr
-       redef fun accept_pretty_printer(v) do
-               v.consume "["
-               v.visit_list n_exprs.n_exprs
-               v.consume "]"
-       end
-end
-
-redef class ACrangeExpr
-       redef fun accept_pretty_printer(v) do
-               v.visit n_obra
-               v.visit n_expr
-               v.consume ".."
-               v.visit n_expr2
-               v.visit n_cbra
-       end
-end
-
-redef class AOrangeExpr
-       redef fun accept_pretty_printer(v) do
-               v.visit n_obra
-               v.visit n_expr
-               v.consume ".."
-               v.visit n_expr2
-               v.visit n_cbra
-       end
-end
-
-# Strings
-
-redef class AStringFormExpr
-       redef fun accept_pretty_printer(v) do
-               var can_inline = v.can_inline(self)
-
-               if can_inline then
-                       v.visit n_string
-               else
-                       var text = n_string.text
-                       var i = 0
-
-                       while i < text.length do
-                               v.add text[i].to_s
-
-                               if v.current_length >= v.max_size and i <= text.length - 3 then
-                                       v.add "\" +"
-                                       v.addn
-                                       v.indent += 1
-                                       v.addt
-                                       v.indent -= 1
-                                       v.add "\""
-                               end
-
-                               i += 1
-                       end
-
-                       v.current_token = n_string.next_token
-               end
-       end
-end
-
-redef class ASuperstringExpr
-       redef fun accept_pretty_printer(v) do
-               for n_expr in n_exprs do v.visit n_expr
-       end
-
-       redef fun must_be_inline do
-               if super then return true
-
-               if not n_exprs.is_empty then
-                       var first = n_exprs.first
-                       return first isa AStringFormExpr and first.n_string.text.has_prefix("\"\"\"")
-               end
-
-               return false
-       end
-end
+# See `man nitpretty` for more infos.
+import pretty
 
 redef class ToolContext
+       # The working directory used to store temp files.
        var opt_dir = new OptionString("Working directory (default is '.nitpretty')", "--dir")
 
+       # Output pretty printed code with this filename.
        var opt_output = new OptionString("Output name (default is pretty.nit)", "-o",
           "--output")
 
+       # Show diff between source and pretty printed code.
        var opt_diff = new OptionBool("Show diff between source and output", "--diff")
 
+       # Show diff between source and pretty printed code using meld.
        var opt_meld = new OptionBool("Show diff between source and output using meld",
           "--meld")
 
+       # Check formatting instead of pretty printing.
+       #
+       # This option create a tempory pretty printed file then check if
+       # the output of the diff command on the source file and the pretty
+       # printed one is empty.
        var opt_check = new OptionBool("Check format of Nit source files", "--check")
 end
 
diff --git a/src/pretty.nit b/src/pretty.nit
new file mode 100644 (file)
index 0000000..75d9879
--- /dev/null
@@ -0,0 +1,2119 @@
+# 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.
+
+# Library used to pretty print Nit code.
+#
+# Usage:
+#
+#     import parser_util
+#     var tc = new ToolContext
+#     var nmodule = tc.parse_something("class A\nfun   toto :  Int  do   return   5\nend")
+#     var ppv = new PrettyPrinterVisitor
+#     var pmodule = ppv.pretty(nmodule)
+#     assert pmodule.write_to_string == """
+#     class A
+#     \tfun toto: Int do return 5
+#     end"""
+#
+# See `nitpretty` tool for more documentation.
+module pretty
+
+import template
+import toolcontext
+import modelbuilder
+import astutil
+
+# The `PrettyPrinterVisitor` is used to visit a node and pretty print it.
+#
+# The main method here is `visit` that performs the pretty printing of a `ANode`.
+#
+# Because some tokens like `TComment` are not stored in the AST,
+# we visit the AST like traditionnal visitor and also maintain a
+# pointer to the `current_token` (actually the next one to be printed).
+#
+# Visited productions are in charges to move the token pointer using methods such as:
+#
+# * `consume`: print `current_token` and move to the next one
+# * `skip`: move to the next token without printing the current one
+# * `skip_to`: move to a specified token skipping all the tokens before
+# * `catch_up`: consume all the tokens between `current_token` and a specified token
+# * `finish_line`: consume all the tokens between `current_token` and the end of line
+class PrettyPrinterVisitor
+       # Pretty print `n`.
+       fun pretty(n: ANode): Template do
+               clear
+               n.parentize_tokens
+
+               if n isa Prod then
+                       current_token = n.first_token
+                       visit n
+               else if n isa Token then
+                       var p = n.parent
+
+                       while p != null and not p isa Prod do
+                               p = p.parent
+                       end
+
+                       current_token = p.first_token
+                       visit p
+               end
+
+               return tpl.as(not null)
+       end
+
+       # Pretty print the whole `nmodule` with comments before and after.
+       fun pretty_nmodule(nmodule: AModule): Template do
+               clear
+               nmodule.parentize_tokens
+               current_token = nmodule.location.file.first_token
+               visit nmodule
+               catch_up nmodule.location.file.last_token
+               tpl.add "\n"
+               return tpl.as(not null)
+       end
+
+       # Prepare `self` for a new visit.
+       private fun clear do
+               tpl = new Template
+               current_token = null
+               indent = 0
+               current_length = 0
+               previous_length = 0
+               wait_addn = 0
+       end
+
+       # Visit `n` if not null.
+       fun visit(n: nullable ANode) do
+               if n == null then return
+               n.accept_pretty_printer self
+       end
+
+       # Visit a list of `Anode`.
+       fun visit_list(n: nullable ANodes[ANode]) do
+               if n == null then return
+               n.accept_pretty_printer self
+       end
+
+       # Is the node inlinable and can fit on the line.
+       fun can_inline(n: nullable ANode): Bool do
+               if n == null then return true
+               if n.must_be_inline then return true
+               if n.must_be_block then return false
+               # check length
+               if n.collect_length + current_length > max_size then return false
+               # check block is inlinable
+               return n.is_inlinable
+       end
+
+       # Collect all `TComment` between `from` and `to`.
+       fun collect_comments(from: nullable ANode, to: nullable ANode): Array[TComment] do
+               var res = new Array[TComment]
+               if from isa Prod then from = from.first_token
+               if to isa Prod then to = to.first_token
+               if from == null or to == null then return res
+
+               while from != to do
+                       if from isa TComment then res.add from
+                       from = from.as(Token).next_token
+               end
+
+               return res
+       end
+
+       # Token under cursor.
+       #
+       # This is the next token to visit.
+       var current_token: nullable Token = null
+
+       # Skip the `current_token`.
+       fun skip do current_token = current_token.next_token
+
+       # Skip `current_token` until the end of line.
+       fun skip_line do current_token = current_token.last_real_token_in_line
+
+       # Skip `current_token` until `target` is reached.
+       fun skip_to(target: nullable Token) do
+               if target == null then return
+               while current_token != target do skip
+       end
+
+       # Visit `current_token`.
+       fun consume(token: String) do
+               assert current_token.text == token
+               visit current_token
+       end
+
+       # Is there token to visit between `current_token` and `target`?
+       fun need_catch_up(target: nullable Token): Bool do
+               if target == null then return false
+               return current_token != target
+       end
+
+       # Visit all tokens between `current_token` and `target`.
+       fun catch_up(target: nullable ANode) do
+               if target == null then return
+               if current_token == null then return
+               var token: Token
+               if target isa Token then
+                       token = target
+               else if target isa Prod then
+                       token = target.first_token.as(not null)
+               else
+                       abort
+               end
+               assert current_token.location <= token.location
+               while current_token != token do visit current_token
+       end
+
+       # Visit all tokens between `current_token` and the end of line.
+       fun finish_line do
+               if current_token isa TComment then
+                       adds
+                       visit current_token
+               end
+
+               while current_token isa TEol do skip
+       end
+
+       # The template under construction.
+       private var tpl: nullable Template = null
+
+       # Current indent level.
+       var indent = 0
+
+       # Size of a tabulation in spaces.
+       var tab_size = 8
+
+       # Max line size.
+       var max_size = 80
+
+       # Length of the current line.
+       var current_length = 0
+
+       # Length of the previous line.
+       var previous_length = 0
+
+       # Is the last line a blank line?
+       fun last_line_is_blank: Bool do return previous_length == 0
+
+       # Add `t` to current template.
+       fun add(t: String) do
+               if t.is_empty then return
+               while wait_addn > 0 do
+                       tpl.add "\n"
+                       wait_addn -= 1
+               end
+               tpl.add t
+               current_length += t.length
+       end
+
+       # Add a `'\n'`.
+       fun addn do
+               if current_length == 0 and last_line_is_blank then return
+               previous_length = current_length
+               current_length = 0
+               wait_addn += 1
+       end
+
+       # End of line chars are stored until another char is added.
+       # This avoid empty files with only a '`\n`'.
+       private var wait_addn = 0
+
+       # Add `'\t' * indent`.
+       fun addt do add "\t" * indent
+
+       # Add a space.
+       fun adds do add " "
+
+       # Visit explicit receiver, implicit self will be ignored.
+       fun visit_recv(n_expr: AExpr) do
+               if not n_expr isa AImplicitSelfExpr then
+                       visit n_expr
+                       consume "."
+               end
+       end
+end
+
+# Base framework redefs
+
+redef class ANodes[E]
+       private fun accept_pretty_printer(v: PrettyPrinterVisitor) do
+               for e in self do
+                       var e_can_inline = v.can_inline(e)
+
+                       if e != first then
+                               if not e_can_inline then
+                                       v.add ","
+                                       v.addn
+                                       v.addt
+                                       v.addt
+                               else
+                                       v.add ", "
+                               end
+                       end
+
+                       v.visit e
+               end
+       end
+end
+
+redef class ANode
+       # Start visit of `self` using a `PrettyPrinterVisitor`
+       private fun accept_pretty_printer(v: PrettyPrinterVisitor) is abstract
+
+       # Collect the length (in `Char`) of the node.
+       private fun collect_length: Int is abstract
+
+       # Is `self` printable in one line?
+       private fun is_inlinable: Bool do return true
+
+       # Force `self` to be rendered as a block.
+       private var force_block = false
+
+       # Does `self` have to be rendered as a block?
+       private fun must_be_block: Bool do return force_block
+
+       # Force `self` to be rendered as a line.
+       private var force_inline = false
+
+       # Does `self` have be rendered as a line?
+       private fun must_be_inline: Bool do
+               if parent != null and parent.must_be_inline then return true
+               return force_inline
+       end
+
+       # Does `self` was written in one line before transformation?
+       private fun was_inline: Bool is abstract
+end
+
+redef class Token
+       redef fun accept_pretty_printer(v) do
+               v.add text.trim
+               v.current_token = next_token
+       end
+
+       redef fun collect_length do return text.length
+       redef fun is_inlinable do return true
+       redef fun was_inline do return true
+end
+
+redef class Prod
+       redef fun accept_pretty_printer(v) do v.visit first_token
+
+       # The token where the production really start (skipping ADoc).
+       private fun start_token: nullable Token do return first_token
+
+       # Collect all `TComment` contained in the production
+       # (between `start_token` and `end_token`).
+       private fun collect_comments: Array[TComment] do
+               var res = new Array[TComment]
+               if start_token == null or last_token == null then return res
+               var token = start_token
+
+               while token != last_token do
+                       if token isa TComment then res.add token
+                       token = token.next_token
+               end
+
+               return res
+       end
+
+       redef fun collect_length do
+               var res = 0
+               if start_token == null or last_token == null then return res
+               var token = start_token
+
+               while token != last_token do
+                       res += token.text.length
+                       token = token.next_token
+               end
+
+               res += token.text.length
+               return res
+       end
+
+       redef fun was_inline do
+               return first_token.location.line_start == last_token.location.line_end
+       end
+end
+
+# Comments
+
+redef class TComment
+       redef fun accept_pretty_printer(v) do
+               if is_adoc then
+                       v.addt
+                       super
+                       v.addn
+                       return
+               end
+
+               if is_licence then
+                       super
+                       v.addn
+                       if is_last_in_group then v.addn
+                       return
+               end
+
+               if is_orphan then
+                       v.addn
+                       v.addt
+                       super
+                       v.addn
+                       v.addn
+                       return
+               end
+
+               if is_inline then
+                       if next_token isa TComment and is_first_in_group then v.addn
+                       v.addt
+                       super
+                       v.addn
+                       var prev_token = self.prev_token
+                       if prev_token isa TComment and prev_token.is_inline and is_last_in_group then v.addn
+                       return
+               end
+
+               super
+       end
+
+       # Is `self` part of an `ADoc`?
+       private fun is_adoc: Bool do return parent isa ADoc and parent.parent != null
+
+       # Is `self` part of a licence?
+       private fun is_licence: Bool do
+               var prev_token = self.prev_token
+
+               if prev_token == null then
+                       return true
+               else if prev_token isa TComment then
+                       return prev_token.is_licence
+               else
+                       return false
+               end
+       end
+
+       # Is `self` starts and ends its line?
+       private fun is_inline: Bool do
+               return self == first_real_token_in_line and self == last_real_token_in_line
+       end
+
+       # Is `self` an orphan line (blank before and after)?
+       private fun is_orphan: Bool do
+               return prev_token isa TEol and
+                  (prev_token.prev_token isa TEol or prev_token.prev_token isa TComment) and
+                  next_token isa TEol
+       end
+
+       # Is `self` the first comment of a group of comment?
+       private fun is_first_in_group: Bool do return not prev_token isa TComment
+
+       # Is `self` the last comment of a group of comments?
+       private fun is_last_in_group: Bool do return not next_token isa TComment
+end
+
+redef class ADoc
+       redef fun accept_pretty_printer(v) do for comment in n_comment do v.visit comment
+       redef fun is_inlinable do return n_comment.length <= 1
+end
+
+# Annotations
+
+redef class AAnnotations
+       redef fun accept_pretty_printer(v) do
+               v.adds
+               v.consume "is"
+
+               if v.can_inline(self) then
+                       v.adds
+                       for n_item in n_items do
+                               v.visit n_item
+                               if n_item != n_items.last then
+                                       v.add ", "
+                               end
+                       end
+                       v.finish_line
+               else if n_items.length > 1 then
+                       v.addn
+                       v.indent += 1
+
+                       for n_item in n_items do
+                               v.addt
+                               v.visit n_item
+                               v.finish_line
+                               v.addn
+                       end
+
+                       v.indent -= 1
+               end
+               if not was_inline and v.current_token isa TKwend then v.skip
+       end
+
+       redef fun is_inlinable do
+               if not super then return false
+               for annot in n_items do if not annot.is_inlinable then return false
+               return true
+       end
+end
+
+redef class AAnnotation
+       redef fun accept_pretty_printer(v) do
+               v.visit n_atid
+               if not n_args.is_empty then
+                       if n_opar == null then
+                               v.adds
+                       else
+                               v.visit n_opar
+                       end
+                       v.visit_list n_args
+                       v.visit n_cpar
+               end
+       end
+end
+
+redef class ATypeExpr
+       redef fun accept_pretty_printer(v) do v.visit n_type
+end
+
+# Modules
+
+redef class AModule
+       redef fun accept_pretty_printer(v) do
+               v.catch_up start_token
+               v.visit n_moduledecl
+
+               if not n_imports.is_empty then
+                       v.addn
+
+                       for n_import in n_imports do
+                               v.catch_up n_import
+                               v.visit n_import
+                       end
+               end
+
+               if not n_extern_code_blocks.is_empty then
+                       v.addn
+
+                       for n_extern_block in n_extern_code_blocks do
+                               v.catch_up n_extern_block
+                               v.visit n_extern_block
+                               v.addn
+                               if n_extern_block != n_extern_code_blocks.last then v.addn
+                       end
+
+                       if not n_classdefs.is_empty then v.addn
+               end
+
+               if not n_classdefs.is_empty then
+                       v.addn
+
+                       for n_classdef in n_classdefs do
+                               v.catch_up n_classdef
+                               v.visit n_classdef
+                               if n_classdef != n_classdefs.last then v.addn
+                       end
+               end
+
+               assert v.indent == 0
+       end
+
+       # Skip doc if any.
+       redef fun start_token do
+               if n_moduledecl != null then return n_moduledecl.first_token
+               if not n_imports.is_empty then return n_imports.first.first_token
+               if not n_classdefs.is_empty then return n_classdefs.first.first_token
+               return first_token
+       end
+
+       redef fun is_inlinable do return false
+end
+
+redef class AModuledecl
+       redef fun accept_pretty_printer(v) do
+               v.visit n_doc
+               v.visit n_kwmodule
+               v.adds
+               v.visit n_name
+
+               if n_annotations != null then
+                       var annot_inline = v.can_inline(n_annotations)
+                       v.visit n_annotations
+
+                       if not annot_inline then
+                               if v.current_token isa TKwend then
+                                       v.consume "end"
+                                       v.finish_line
+                               else
+                                       v.add "end"
+                               end
+                       end
+               end
+
+               v.finish_line
+               v.addn
+       end
+end
+
+redef class AModuleName
+       redef fun accept_pretty_printer(v) do
+               for path in n_path do
+                       v.visit path
+                       v.add "::"
+               end
+
+               v.visit n_id
+       end
+end
+
+redef class ANoImport
+       redef fun accept_pretty_printer(v) do
+               v.visit n_kwimport
+               v.adds
+               v.visit n_kwend
+               v.finish_line
+               v.addn
+       end
+end
+
+redef class AStdImport
+       redef fun accept_pretty_printer(v) do
+               if not n_visibility isa APublicVisibility then
+                       v.visit n_visibility
+                       v.adds
+               end
+
+               v.visit n_kwimport
+               v.adds
+               v.visit n_name
+               v.finish_line
+               v.addn
+       end
+end
+
+# Classes
+
+redef class AClassdef
+       redef fun accept_pretty_printer(v) do
+               for n_propdef in n_propdefs do
+                       v.catch_up n_propdef
+
+                       if n_propdef.n_doc != null or not v.can_inline(n_propdef) then
+                               if n_propdef != n_propdefs.first then v.addn
+                               v.visit n_propdef
+                               if n_propdef != n_propdefs.last then v.addn
+                       else
+                               v.visit n_propdef
+                       end
+               end
+       end
+end
+
+redef class AStdClassdef
+       redef fun accept_pretty_printer(v) do
+               v.visit n_doc
+               var can_inline = v.can_inline(self)
+
+               if not n_visibility isa APublicVisibility then
+                       v.visit n_visibility
+                       v.adds
+               end
+
+               if n_kwredef != null then
+                       v.visit n_kwredef
+                       v.adds
+               end
+
+               v.visit n_classkind
+               v.adds
+               v.visit n_id
+
+               if not n_formaldefs.is_empty then
+                       v.consume "["
+                       v.visit_list n_formaldefs
+                       v.consume "]"
+               end
+
+               if n_extern_code_block != null then
+                       v.adds
+                       v.visit n_extern_code_block
+               end
+
+               if can_inline then
+                       v.adds
+
+                       if not n_superclasses.is_empty then
+                               for n_superclass in n_superclasses do
+                                       v.visit n_superclass
+                                       v.adds
+                               end
+                       end
+               else
+                       v.finish_line
+                       v.addn
+                       v.indent += 1
+
+                       for n_superclass in n_superclasses do
+                               v.catch_up n_superclass
+                               v.addt
+                               v.visit n_superclass
+                               v.finish_line
+                               v.addn
+                       end
+
+                       if not n_superclasses.is_empty and not n_propdefs.is_empty then
+                               v.addn
+                       end
+
+                       super
+                       v.catch_up n_kwend
+                       v.indent -= 1
+               end
+
+               v.visit n_kwend
+               v.finish_line
+               v.addn
+               assert v.indent == 0
+       end
+
+       redef fun is_inlinable do
+               if not super then return false
+               if not n_propdefs.is_empty then return false
+               if n_superclasses.length > 1 then return false
+               if not collect_comments.is_empty then return false
+               return true
+       end
+
+       redef fun start_token do
+               if not n_visibility isa APublicVisibility then return n_visibility.first_token
+               if n_kwredef != null then return n_kwredef
+               return n_classkind.first_token
+       end
+end
+
+redef class AAbstractClasskind
+       redef fun accept_pretty_printer(v) do
+               v.visit n_kwabstract
+               v.adds
+               v.visit n_kwclass
+       end
+end
+
+redef class AExternClasskind
+       redef fun accept_pretty_printer(v) do
+               v.visit n_kwextern
+               v.adds
+               v.visit n_kwclass
+       end
+end
+
+redef class AFormaldef
+       redef fun accept_pretty_printer(v) do
+               v.visit n_id
+
+               if n_type != null then
+                       v.consume ":"
+                       v.adds
+                       v.visit n_type
+               end
+       end
+end
+
+redef class AType
+       redef fun accept_pretty_printer(v) do
+               if n_kwnullable != null then
+                       v.visit n_kwnullable
+                       v.adds
+               end
+
+               v.visit n_id
+
+               if not n_types.is_empty then
+                       v.consume "["
+                       v.visit_list n_types
+                       v.consume "]"
+               end
+       end
+end
+
+redef class ASuperclass
+       redef fun accept_pretty_printer(v) do
+               v.visit n_kwsuper
+               v.adds
+               v.visit n_type
+       end
+end
+
+# Properties
+
+redef class APropdef
+       redef fun accept_pretty_printer(v) do
+               v.visit n_doc
+               v.addt
+
+               if not n_visibility isa APublicVisibility then
+                       v.visit n_visibility
+                       v.adds
+               end
+
+               if n_kwredef != null then
+                       v.visit n_kwredef
+                       v.adds
+               end
+       end
+
+       redef fun start_token do
+               if n_doc == null then return super
+               return n_doc.last_token.next_token
+       end
+end
+
+redef class AAttrPropdef
+       redef fun accept_pretty_printer(v) do
+               super
+               v.visit n_kwvar
+               v.adds
+               v.visit n_id2
+
+               if n_type != null then
+                       v.consume ":"
+                       v.adds
+                       v.visit n_type
+               end
+
+               if n_expr != null then
+                       v.adds
+                       v.consume "="
+                       v.adds
+                       v.visit n_expr
+               end
+
+               if n_annotations != null then v.visit n_annotations
+               v.finish_line
+               v.addn
+       end
+
+       redef fun first_token do
+               if n_doc != null then return n_doc.first_token
+               if not n_visibility isa APublicVisibility then return n_visibility.first_token
+               if n_kwredef != null then return n_kwredef
+               return n_kwvar
+       end
+
+       redef fun is_inlinable do return true
+end
+
+redef class ATypePropdef
+       redef fun accept_pretty_printer(v) do
+               super
+               v.visit n_kwtype
+               v.adds
+               v.visit n_id
+               v.consume ":"
+               v.adds
+               v.visit n_type
+               v.finish_line
+               v.addn
+       end
+
+       redef fun is_inlinable do return true
+end
+
+redef class AMethPropdef
+       redef fun accept_pretty_printer(v) do
+               #  TODO: Handle extern annotations
+
+               var before = v.indent
+               var can_inline = v.can_inline(self)
+               super
+               if n_kwinit != null then v.visit n_kwinit
+               if n_kwmeth != null then v.visit n_kwmeth
+               if n_kwnew != null then v.visit n_kwnew
+
+               if not n_methid == null then
+                       v.adds
+                       v.visit n_methid
+               end
+
+               v.visit n_signature
+
+               if n_annotations != null then
+                       v.visit n_annotations
+               else
+                       v.adds
+               end
+
+               if n_extern_calls != null or n_extern_code_block != null then
+                       if n_annotations != null then v.adds
+                       if n_extern_calls != null then v.visit n_extern_calls
+                       if n_extern_code_block != null then v.visit n_extern_code_block
+               end
+
+               var n_block = self.n_block
+
+               if n_block != null then
+                       while not v.current_token isa TKwdo do v.skip
+                       if n_annotations != null then
+                               if v.can_inline(n_annotations) then
+                                       v.adds
+                               else
+                                       v.addt
+                               end
+                       end
+                       v.consume "do"
+
+                       if can_inline then
+                               v.adds
+
+                               if n_block isa ABlockExpr then
+                                       if n_block.n_expr.is_empty then
+                                               v.visit n_block.n_kwend
+                                       else
+                                               v.visit n_block.n_expr.first
+                                               v.current_token = n_block.n_kwend
+                                               v.skip
+                                       end
+                               else
+                                       v.visit n_block
+                                       if v.current_token isa TKwend then v.skip
+                               end
+                       else
+                               v.finish_line
+                               v.addn
+                               v.indent += 1
+
+                               if n_block isa ABlockExpr then
+                                       n_block.force_block = true
+                                       v.visit n_block
+                                       v.catch_up n_block.n_kwend
+                               else
+                                       v.addt
+                                       v.visit n_block
+                                       v.addn
+                               end
+
+                               v.indent -= 1
+                               v.addt
+                               if n_block isa ABlockExpr then
+                                       v.visit n_block.n_kwend
+                               else
+                                       v.add "end"
+                               end
+                       end
+               end
+
+               v.finish_line
+               v.addn
+               assert v.indent == before
+       end
+
+       # Can be inlined if:
+       # * block is empty or can be inlined
+       # * contains no comments
+       redef fun is_inlinable do
+               if not super then return false
+               if n_annotations != null and not n_annotations.is_inlinable then return false
+               if n_block != null and not n_block.is_inlinable then return false
+               if n_extern_calls != null and not n_extern_calls.is_inlinable then return false
+               if n_extern_code_block != null and not n_extern_code_block.is_inlinable then return false
+               if not collect_comments.is_empty then return false
+               return true
+       end
+end
+
+redef class AMainMethPropdef
+       redef fun accept_pretty_printer(v) do
+               v.visit n_block
+               v.addn
+       end
+end
+
+redef class ASignature
+       redef fun accept_pretty_printer(v) do
+               if not n_params.is_empty then
+                       v.consume "("
+                       v.visit_list n_params
+                       v.consume ")"
+               end
+
+               if n_type != null then
+                       v.consume ":"
+                       v.adds
+                       v.visit n_type
+               end
+       end
+end
+
+redef class AParam
+       redef fun accept_pretty_printer(v) do
+               v.visit n_id
+
+               if n_type != null then
+                       v.consume ":"
+                       v.adds
+                       v.visit n_type
+               end
+
+               if n_dotdotdot != null then v.visit n_dotdotdot
+       end
+end
+
+# Extern
+
+redef class AExternCalls
+       redef fun accept_pretty_printer(v) do
+               var can_inline = v.can_inline(self)
+               v.visit n_kwimport
+
+               if can_inline then
+                       v.adds
+                       v.visit_list n_extern_calls
+               else
+                       v.addn
+                       v.addt
+                       v.addt
+                       v.visit_list n_extern_calls
+               end
+
+               v.adds
+       end
+end
+
+redef class AFullPropExternCall
+       redef fun accept_pretty_printer(v) do
+               v.visit n_type
+               v.visit n_dot
+               v.visit n_methid
+       end
+end
+
+redef class ALocalPropExternCall
+       redef fun accept_pretty_printer(v) do v.visit n_methid
+end
+
+redef class AInitPropExternCall
+       redef fun accept_pretty_printer(v) do v.visit n_type
+end
+
+redef class ACastAsExternCall
+       redef fun accept_pretty_printer(v) do
+               v.visit n_from_type
+               v.visit n_dot
+               v.visit n_kwas
+               v.consume "("
+               v.visit n_to_type
+               v.consume ")"
+       end
+end
+
+redef class AAsNullableExternCall
+       redef fun accept_pretty_printer(v) do
+               v.visit n_type
+               v.consume "."
+               v.visit n_kwas
+               v.adds
+               v.visit n_kwnullable
+       end
+end
+
+redef class AAsNotNullableExternCall
+       redef fun accept_pretty_printer(v) do
+               v.visit n_type
+               v.consume "."
+               v.visit n_kwas
+               v.adds
+               v.visit n_kwnot
+               v.adds
+               v.visit n_kwnullable
+       end
+end
+
+redef class AExternCodeBlock
+       redef fun accept_pretty_printer(v) do
+               if n_in_language != null then
+                       v.visit n_in_language
+                       v.adds
+               end
+
+               v.visit n_extern_code_segment
+       end
+
+       redef fun is_inlinable do
+               if not super then return false
+               return n_extern_code_segment.is_inlinable
+       end
+end
+
+redef class AInLanguage
+       redef fun accept_pretty_printer(v) do
+               v.visit n_kwin
+               v.adds
+               v.visit n_string
+       end
+end
+
+redef class TExternCodeSegment
+       redef fun accept_pretty_printer(v) do
+               var can_inline = v.can_inline(self)
+
+               if can_inline then
+                       super
+               else
+                       var text = text.substring(2, text.length - 4)
+                       var lines = text.r_trim.split("\n")
+
+                       if text.is_empty then
+                               v.add "`\{`\}"
+                       else
+                               v.add "`\{"
+
+                               if not lines.first.trim.is_empty then
+                                       v.addn
+                                       lines.first.l_trim
+                                       v.indent += 1
+                                       v.addt
+                                       v.indent -= 1
+                               end
+
+                               for line in lines do
+                                       v.add line.r_trim
+                                       v.addn
+                               end
+
+                               v.addt
+                               v.add "`\}"
+                       end
+
+                       v.current_token = next_token
+               end
+       end
+
+       redef fun is_inlinable do
+               if not super then return false
+               return location.line_start == location.line_end
+       end
+end
+
+# Blocks
+
+redef class ABlockExpr
+       redef fun accept_pretty_printer(v) do
+               var before = v.indent
+               var can_inline = v.can_inline(self)
+
+               if can_inline and not n_expr.is_empty then
+                       v.visit n_expr.first
+                       v.finish_line
+               else
+                       for nexpr in n_expr do
+                               var expr_inline = v.can_inline(nexpr)
+                               if not expr_inline and nexpr != n_expr.first then v.addn
+                               v.catch_up nexpr
+                               v.addt
+                               v.visit nexpr
+                               v.finish_line
+                               v.addn
+                               if not expr_inline and nexpr != n_expr.last then v.addn
+                       end
+               end
+
+               assert v.indent == before
+       end
+
+       redef fun is_inlinable do
+               if not super then return false
+               if not collect_comments.is_empty then return false
+
+               if not n_expr.is_empty then
+                       if n_expr.length > 1 then return false
+                       if not n_expr.first.is_inlinable then return false
+               end
+
+               return true
+       end
+end
+
+redef class AIfExpr
+       redef fun accept_pretty_printer(v) do
+               var before = v.indent
+               var can_inline = v.can_inline(self)
+               v.visit n_kwif
+               v.adds
+
+               if v.can_inline(n_expr) then
+                       v.visit n_expr
+                       v.adds
+               else
+                       v.visit n_expr
+                       v.addn
+                       v.addt
+               end
+
+               # skip comments before `then` token
+               while not v.current_token isa TKwthen do v.skip
+               v.consume "then"
+               var n_else = self.n_else
+
+               if can_inline then
+                       v.adds
+                       if n_then != null then v.visit n_then
+
+                       if has_else(v) then
+                               n_else.force_inline = true
+                               v.adds
+                               v.consume "else"
+                               v.adds
+                               v.visit n_else
+                       else if n_then == null then
+                               v.add "end"
+                       end
+
+                       v.skip_to last_token.last_real_token_in_line
+               else
+                       v.finish_line
+                       v.addn
+                       v.indent += 1
+
+                       if n_then != null then
+                               if n_then isa ABlockExpr then
+                                       n_then.force_block = true
+                                       v.visit n_then
+                               else
+                                       v.addt
+                                       v.visit n_then
+                                       v.addn
+                               end
+                       end
+
+                       if has_else(v) then
+                               while not v.current_token isa TKwelse do
+                                       v.consume v.current_token.text
+                               end
+
+                               v.indent -= 1
+                               v.addt
+                               v.consume "else"
+
+                               if n_else isa AIfExpr then
+                                       n_else.force_block = true
+                                       v.adds
+                                       v.visit n_else
+                               else
+                                       v.finish_line
+                                       v.addn
+                                       v.indent += 1
+
+                                       if n_else isa ABlockExpr then
+                                               n_else.force_block = true
+                                               v.visit n_else
+                                       else
+                                               v.addt
+                                               v.visit n_else
+                                               v.addn
+                                       end
+
+                                       if last_token isa TKwend then
+                                               v.catch_up last_token
+                                               v.indent -= 1
+                                               v.addt
+                                               v.consume "end"
+                                       else
+                                               v.indent -= 1
+                                               v.addt
+                                               v.add "end"
+                                       end
+                               end
+                       else
+                               if last_token.location >= v.current_token.location then v.catch_up last_token
+                               v.indent -= 1
+                               v.addt
+                               v.add "end"
+                               if v.current_token isa TKwend then v.skip
+                       end
+               end
+
+               assert v.indent == before
+       end
+
+       redef fun is_inlinable do
+               if not super then return false
+               if n_then != null and not n_then.is_inlinable then return false
+               var n_else = self.n_else
+               if (n_else isa ABlockExpr and not n_else.n_expr.is_empty) or
+                  (not n_else isa ABlockExpr and n_else != null) then
+                       return false
+               end
+               if not collect_comments.is_empty then return false
+               return true
+       end
+
+       # Does this `if` statement contains a `else` part?
+       private fun has_else(v: PrettyPrinterVisitor): Bool do
+               var n_else = n_else
+               if n_else == null then return false
+               var n_kwelse = collect_kwelse
+               if n_kwelse == null then return false
+
+               if n_else isa ABlockExpr then
+                       var comments: Array[TComment]
+
+                       if n_then == null then
+                               comments = v.collect_comments(n_expr.last_token, n_else.last_token)
+                       else
+                               comments = v.collect_comments(n_then.last_token, n_else.last_token)
+                       end
+
+                       if not comments.is_empty then return true
+                       return not n_else.n_expr.is_empty
+               end
+
+               return true
+       end
+
+       # Lookup for `else` token in `self`.
+       private fun collect_kwelse: nullable TKwelse do
+               var token = first_token
+
+               while token != last_token do
+                       if token isa TKwelse then return token
+                       token = token.next_token
+               end
+
+               return null
+       end
+end
+
+# Used to factorize work on loops.
+private class ALoopHelper
+       super AExpr
+
+       fun loop_block: nullable ANode is abstract
+       fun loop_label: nullable ANode is abstract
+
+       fun visit_loop_block(v: PrettyPrinterVisitor) do
+               var n_block = loop_block
+               v.finish_line
+               v.addn
+               v.indent += 1
+
+               if n_block isa ABlockExpr then
+                       n_block.force_block = true
+                       v.visit n_block
+                       v.catch_up n_block.n_kwend
+                       v.indent -= 1
+                       v.addt
+                       v.visit n_block.n_kwend
+               else
+                       v.addt
+                       v.visit n_block
+                       v.addn
+                       v.indent -= 1
+                       v.addt
+                       v.add "end"
+               end
+
+               if loop_label != null then
+                       v.adds
+                       v.visit loop_label
+               end
+       end
+
+       fun visit_loop_inline(v: PrettyPrinterVisitor) do
+               var n_block = loop_block
+               v.adds
+
+               if n_block isa ABlockExpr then
+                       if n_block.n_expr.is_empty then
+                               v.visit n_block.n_kwend
+                       else
+                               v.visit n_block.n_expr.first
+                               v.current_token = n_block.n_kwend
+                               v.skip
+                       end
+               else
+                       v.visit n_block
+                       if v.current_token isa TKwend then v.skip
+               end
+
+               if loop_label != null then
+                       v.adds
+                       v.visit loop_label
+               end
+       end
+
+       redef fun is_inlinable do
+               var n_block = loop_block
+               if not super then return false
+               if n_block isa ABlockExpr and not n_block.is_inlinable then return false
+               if not collect_comments.is_empty then return false
+               return true
+       end
+end
+
+redef class ALoopExpr
+       super ALoopHelper
+
+       redef fun loop_block do return n_block
+       redef fun loop_label do return n_label
+
+       redef fun accept_pretty_printer(v) do
+               var can_inline = v.can_inline(self)
+               v.visit n_kwloop
+               if can_inline then visit_loop_inline v else visit_loop_block v
+       end
+end
+
+redef class AWhileExpr
+       super ALoopHelper
+
+       redef fun loop_block do return n_block
+       redef fun loop_label do return n_label
+
+       redef fun accept_pretty_printer(v) do
+               var can_inline = v.can_inline(self)
+               v.visit n_kwwhile
+               v.adds
+               v.visit n_expr
+               v.adds
+               v.visit n_kwdo
+               if can_inline then visit_loop_inline v else visit_loop_block v
+       end
+end
+
+redef class ADoExpr
+       super ALoopHelper
+
+       redef fun loop_block do return n_block
+       redef fun loop_label do return n_label
+
+       redef fun accept_pretty_printer(v) do
+               var can_inline = v.can_inline(self)
+               v.visit n_kwdo
+               if can_inline then visit_loop_inline v else visit_loop_block v
+       end
+end
+
+redef class AForExpr
+       super ALoopHelper
+
+       redef fun loop_block do return n_block
+       redef fun loop_label do return n_label
+
+       redef fun accept_pretty_printer(v) do
+               var can_inline = v.can_inline(self)
+               v.visit n_kwfor
+               v.adds
+
+               for n_id in n_ids do
+                       v.visit n_id
+                       if n_id != n_ids.last then v.add ", "
+               end
+
+               v.adds
+               v.consume "in"
+               v.adds
+               v.visit n_expr
+               v.adds
+               v.visit n_kwdo
+               if can_inline then visit_loop_inline v else visit_loop_block v
+       end
+end
+
+redef class ABreakExpr
+       redef fun accept_pretty_printer(v) do
+               v.visit n_kwbreak
+
+               if n_expr != null then
+                       v.adds
+                       v.visit n_expr
+               end
+
+               if n_label != null then
+                       v.adds
+                       v.visit n_label
+               end
+       end
+
+       redef fun is_inlinable do return true
+end
+
+redef class AContinueExpr
+       redef fun accept_pretty_printer(v) do
+               v.visit n_kwcontinue
+
+               if n_expr != null then
+                       v.adds
+                       v.visit n_expr
+               end
+
+               if n_label != null then
+                       v.adds
+                       v.visit n_label
+               end
+       end
+
+       redef fun is_inlinable do return true
+end
+
+# Calls
+
+redef class ASendExpr
+       redef fun is_inlinable do return true
+end
+
+redef class ACallExpr
+       redef fun accept_pretty_printer(v) do
+               var can_inline = v.can_inline(self)
+               v.visit_recv n_expr
+
+               if not n_expr isa AImplicitSelfExpr and not can_inline then
+                       v.addn
+                       v.addt
+                       v.addt
+               end
+
+               v.visit n_id
+
+               if not n_args.n_exprs.is_empty then
+                       if is_stmt and n_args.n_exprs.length == 1 then
+                               v.adds
+                               if v.current_token isa TOpar then v.skip
+                               v.visit n_args.n_exprs.first
+                               if v.current_token isa TCpar then v.skip
+                       else
+                               if v.current_token isa TOpar then
+                                       v.consume "("
+                               else
+                                       v.adds
+                               end
+
+                               v.visit_list n_args.n_exprs
+                               if v.current_token isa TCpar then v.consume ")"
+                       end
+               end
+       end
+
+       # Is the call alone on its line?
+       fun is_stmt: Bool do return parent isa ABlockExpr
+end
+
+redef class ACallAssignExpr
+       redef fun accept_pretty_printer(v) do
+               v.visit_recv n_expr
+               v.visit n_id
+
+               if not n_args.n_exprs.is_empty then
+                       v.consume "("
+                       v.visit_list n_args.n_exprs
+                       v.consume ")"
+               end
+
+               v.adds
+               v.consume "="
+               v.adds
+               v.visit n_value
+       end
+end
+
+redef class ACallReassignExpr
+       redef fun accept_pretty_printer(v) do
+               v.visit_recv n_expr
+               v.visit n_id
+
+               if not n_args.n_exprs.is_empty then
+                       v.consume "("
+                       v.visit_list n_args.n_exprs
+                       v.consume ")"
+               end
+
+               v.adds
+               v.visit n_assign_op
+               v.adds
+               v.visit n_value
+       end
+end
+
+redef class ABraExpr
+       redef fun accept_pretty_printer(v) do
+               v.visit n_expr
+
+               if not n_args.n_exprs.is_empty then
+                       v.consume "["
+                       v.visit_list n_args.n_exprs
+                       v.consume "]"
+               end
+       end
+end
+
+redef class ABraAssignExpr
+       redef fun accept_pretty_printer(v) do
+               v.visit n_expr
+
+               if not n_args.n_exprs.is_empty then
+                       v.consume "["
+                       v.visit_list n_args.n_exprs
+                       v.consume "]"
+               end
+
+               v.adds
+               v.visit n_assign
+               v.adds
+               v.visit n_value
+       end
+end
+
+redef class ABraReassignExpr
+       redef fun accept_pretty_printer(v) do
+               v.visit n_expr
+
+               if not n_args.n_exprs.is_empty then
+                       v.consume "["
+                       v.visit_list n_args.n_exprs
+                       v.consume "]"
+               end
+
+               v.adds
+               v.visit n_assign_op
+               v.adds
+               v.visit n_value
+       end
+end
+
+redef class AAssignMethid
+       redef fun accept_pretty_printer(v) do
+               v.visit n_id
+               v.visit n_assign
+       end
+end
+
+redef class ABraMethid
+       redef fun accept_pretty_printer(v) do
+               v.visit n_obra
+               v.visit n_cbra
+       end
+end
+
+redef class ABraassignMethid
+       redef fun accept_pretty_printer(v) do
+               v.visit n_obra
+               v.visit n_cbra
+               v.visit n_assign
+       end
+end
+
+redef class AInitExpr
+       redef fun accept_pretty_printer(v) do
+               if not n_expr isa AImplicitSelfExpr then
+                       v.visit n_expr
+                       v.consume "."
+               end
+
+               v.visit n_kwinit
+
+               if not n_args.n_exprs.is_empty then
+                       v.consume "("
+                       v.visit_list n_args.n_exprs
+                       v.consume ")"
+               end
+       end
+end
+
+redef class ANewExpr
+       redef fun accept_pretty_printer(v) do
+               var can_inline = v.can_inline(self)
+               v.visit n_kwnew
+               v.adds
+               v.visit n_type
+
+               if n_id != null then
+                       v.consume "."
+
+                       if not can_inline then
+                               v.addn
+                               v.addt
+                               v.addt
+                       end
+
+                       v.visit n_id
+               end
+
+               if not n_args.n_exprs.is_empty then
+                       v.consume "("
+                       v.visit_list n_args.n_exprs
+                       v.consume ")"
+               end
+       end
+
+       redef fun is_inlinable do return true
+end
+
+# Attributes
+
+redef class AAttrExpr
+       redef fun accept_pretty_printer(v) do
+               v.visit_recv n_expr
+               v.visit n_id
+       end
+
+       redef fun is_inlinable do return true
+end
+
+redef class AAttrAssignExpr
+       redef fun accept_pretty_printer(v) do
+               v.visit_recv n_expr
+               v.visit n_id
+               v.adds
+               v.visit n_assign
+               v.adds
+               v.visit n_value
+       end
+end
+
+redef class AAttrReassignExpr
+       redef fun accept_pretty_printer(v) do
+               v.visit_recv n_expr
+               v.visit n_id
+               v.adds
+               v.visit n_assign_op
+               v.adds
+               v.visit n_value
+       end
+end
+
+# Exprs
+
+redef class AVardeclExpr
+       redef fun accept_pretty_printer(v) do
+               v.visit n_kwvar
+               v.adds
+               v.visit n_id
+
+               if n_type != null then
+                       v.consume ":"
+                       v.adds
+                       v.visit n_type
+               end
+
+               if n_expr != null then
+                       v.adds
+                       v.consume "="
+                       v.adds
+                       v.visit n_expr
+               end
+       end
+
+       redef fun is_inlinable do return true
+end
+
+redef class AVarAssignExpr
+       redef fun accept_pretty_printer(v) do
+               v.visit n_id
+               v.adds
+               v.visit n_assign
+               v.adds
+               v.visit n_value
+       end
+end
+
+redef class AAssertExpr
+       redef fun accept_pretty_printer(v) do
+               var can_inline = v.can_inline(self)
+               v.visit n_kwassert
+
+               if n_id != null then
+                       v.adds
+                       v.visit n_id
+                       v.consume ":"
+               end
+
+               v.adds
+               v.visit n_expr
+               var n_else = self.n_else
+
+               if n_else != null then
+                       v.adds
+                       v.consume "else"
+
+                       if can_inline then
+                               v.adds
+                               v.visit n_else
+                       else
+                               v.addn
+
+                               if n_else isa ABlockExpr then
+                                       v.indent += 1
+                                       n_else.force_block = true
+                                       v.visit n_else
+                                       v.indent -= 1
+                                       v.addt
+                                       v.visit n_else.n_kwend
+                               else
+                                       v.indent += 1
+                                       v.addt
+                                       v.visit n_else
+                                       v.addn
+                                       v.indent -= 1
+                                       v.addt
+                                       v.add "end"
+                               end
+                       end
+               end
+       end
+
+       redef fun is_inlinable do
+               if not super then return false
+               if n_else != null and not n_else.is_inlinable then return false
+               return true
+       end
+end
+
+redef class AReturnExpr
+       redef fun accept_pretty_printer(v) do
+               v.visit n_kwreturn
+
+               if n_expr != null then
+                       v.adds
+                       v.visit n_expr
+               end
+       end
+end
+
+redef class ASuperExpr
+       redef fun accept_pretty_printer(v) do
+               v.visit n_kwsuper
+
+               if not n_args.n_exprs.is_empty then
+                       if is_stmt and n_args.n_exprs.length == 1 then
+                               v.adds
+                               if v.current_token isa TOpar then v.skip
+                               v.visit n_args.n_exprs.first
+                               if v.current_token isa TCpar then v.skip
+                       else
+                               if v.current_token isa TOpar then
+                                       v.consume "("
+                               else
+                                       v.adds
+                               end
+
+                               v.visit_list n_args.n_exprs
+                               if v.current_token isa TCpar then v.consume ")"
+                       end
+               end
+       end
+
+       # Is the call alone on its line?
+       fun is_stmt: Bool do return self.first_token.is_starting_line
+
+       redef fun is_inlinable do return true
+end
+
+redef class AOnceExpr
+       redef fun accept_pretty_printer(v) do
+               v.visit n_kwonce
+               v.adds
+               v.visit n_expr
+       end
+
+       redef fun is_inlinable do return true
+end
+
+redef class AAbortExpr
+       redef fun accept_pretty_printer(v) do v.visit n_kwabort
+       redef fun is_inlinable do return true
+end
+
+redef class ANotExpr
+       redef fun accept_pretty_printer(v) do
+               v.visit n_kwnot
+               v.adds
+               v.visit n_expr
+       end
+end
+
+redef class AAsCastExpr
+       redef fun accept_pretty_printer(v) do
+               v.visit n_expr
+               v.consume "."
+               v.visit n_kwas
+               v.visit n_opar
+               v.visit n_type
+               v.visit n_cpar
+       end
+end
+
+redef class AAsNotnullExpr
+       redef fun accept_pretty_printer(v) do
+               v.visit n_expr
+               v.consume "."
+               v.visit n_kwas
+               v.visit n_opar
+               v.visit n_kwnot
+               v.adds
+               v.visit n_kwnull
+               v.visit n_cpar
+       end
+end
+
+# Binops
+
+# Used to factorize work on Or, And, Implies and Binop expressions.
+private class ABinOpHelper
+       super AExpr
+
+       fun bin_expr1: AExpr is abstract
+       fun bin_expr2: AExpr is abstract
+
+       # Operator string
+       fun bin_op: String is abstract
+
+       redef fun accept_pretty_printer(v) do
+               var can_inline = v.can_inline(self)
+
+               if not can_inline then
+                       if (self isa ABinopExpr and bin_expr1 isa ABinopExpr) or
+                          (self isa AAndExpr and (bin_expr1 isa AAndExpr or bin_expr1 isa AOrExpr)) or
+                          (self isa AOrExpr and (bin_expr1 isa AAndExpr or bin_expr1 isa AOrExpr))
+                       then
+                               bin_expr1.force_block = true
+                       end
+               end
+
+               v.visit bin_expr1
+               v.adds
+               v.consume bin_op
+
+               if can_inline then
+                       v.adds
+                       v.visit bin_expr2
+               else
+                       v.addn
+                       v.addt
+                       v.addt
+                       v.visit bin_expr2
+               end
+       end
+end
+
+redef class AAndExpr
+       super ABinOpHelper
+
+       redef fun bin_expr1 do return n_expr
+       redef fun bin_expr2 do return n_expr2
+       redef fun bin_op do return "and"
+end
+
+redef class AOrExpr
+       super ABinOpHelper
+
+       redef fun bin_expr1 do return n_expr
+       redef fun bin_expr2 do return n_expr2
+       redef fun bin_op do return "or"
+end
+
+redef class AImpliesExpr
+       super ABinOpHelper
+
+       redef fun bin_expr1 do return n_expr
+       redef fun bin_expr2 do return n_expr2
+       redef fun bin_op do return "implies"
+end
+
+redef class ABinopExpr
+       super ABinOpHelper
+
+       redef fun bin_expr1 do return n_expr
+       redef fun bin_expr2 do return n_expr2
+end
+
+redef class AEqExpr
+       redef fun bin_op do return "=="
+end
+
+redef class AGeExpr
+       redef fun bin_op do return ">="
+end
+
+redef class AGgExpr
+       redef fun bin_op do return ">>"
+end
+
+redef class AGtExpr
+       redef fun bin_op do return ">"
+end
+
+redef class ALeExpr
+       redef fun bin_op do return "<="
+end
+
+redef class ALlExpr
+       redef fun bin_op do return "<<"
+end
+
+redef class ALtExpr
+       redef fun bin_op do return "<"
+end
+
+redef class AMinusExpr
+       redef fun bin_op do return "-"
+end
+
+redef class ANeExpr
+       redef fun bin_op do return "!="
+end
+
+redef class APercentExpr
+       redef fun bin_op do return "%"
+end
+
+redef class APlusExpr
+       redef fun bin_op do return "+"
+end
+
+redef class ASlashExpr
+       redef fun bin_op do return "/"
+end
+
+redef class AStarExpr
+       redef fun bin_op do return "*"
+end
+
+redef class AStarstarExpr
+       redef fun bin_op do return "**"
+end
+
+redef class AStarshipExpr
+       redef fun bin_op do return "<=>"
+end
+
+redef class AIsaExpr
+       redef fun accept_pretty_printer(v) do
+               v.visit n_expr
+               v.adds
+               v.consume "isa"
+               v.adds
+               v.visit n_type
+       end
+end
+
+redef class AOrElseExpr
+       redef fun accept_pretty_printer(v) do
+               v.visit n_expr
+               v.adds
+               v.consume "or"
+               v.adds
+               v.consume "else"
+               v.adds
+               v.visit n_expr2
+       end
+
+       redef fun is_inlinable do return true
+end
+
+# Syntax
+
+redef class AUminusExpr
+       redef fun accept_pretty_printer(v) do
+               v.consume "-"
+               v.visit n_expr
+       end
+end
+
+redef class ANullExpr
+       redef fun accept_pretty_printer(v) do v.visit n_kwnull
+       redef fun is_inlinable do return true
+end
+
+redef class AParExpr
+       redef fun accept_pretty_printer(v) do
+               v.visit n_opar
+               v.visit n_expr
+               v.visit n_cpar
+       end
+end
+
+redef class AArrayExpr
+       redef fun accept_pretty_printer(v) do
+               v.consume "["
+               v.visit_list n_exprs.n_exprs
+               v.consume "]"
+       end
+end
+
+redef class ACrangeExpr
+       redef fun accept_pretty_printer(v) do
+               v.visit n_obra
+               v.visit n_expr
+               v.consume ".."
+               v.visit n_expr2
+               v.visit n_cbra
+       end
+end
+
+redef class AOrangeExpr
+       redef fun accept_pretty_printer(v) do
+               v.visit n_obra
+               v.visit n_expr
+               v.consume ".."
+               v.visit n_expr2
+               v.visit n_cbra
+       end
+end
+
+# Strings
+
+redef class AStringFormExpr
+       redef fun accept_pretty_printer(v) do
+               var can_inline = v.can_inline(self)
+
+               if can_inline then
+                       v.visit n_string
+               else
+                       var text = n_string.text
+                       var i = 0
+
+                       while i < text.length do
+                               v.add text[i].to_s
+
+                               if v.current_length >= v.max_size and i <= text.length - 3 then
+                                       v.add "\" +"
+                                       v.addn
+                                       v.indent += 1
+                                       v.addt
+                                       v.indent -= 1
+                                       v.add "\""
+                               end
+
+                               i += 1
+                       end
+
+                       v.current_token = n_string.next_token
+               end
+       end
+end
+
+redef class ASuperstringExpr
+       redef fun accept_pretty_printer(v) do
+               for n_expr in n_exprs do v.visit n_expr
+       end
+
+       redef fun must_be_inline do
+               if super then return true
+
+               if not n_exprs.is_empty then
+                       var first = n_exprs.first
+                       return first isa AStringFormExpr and first.n_string.text.has_prefix("\"\"\"")
+               end
+
+               return false
+       end
+end
index 9f97e45..7881db0 100644 (file)
@@ -111,7 +111,7 @@ class RapidTypeAnalysis
        # Return a ready-to-save CSV document objet that agregates informations about live types.
        # Each discovered type is listed in a line, with its status: resolution, liveness, cast-liveness.
        # Note: types are listed in an alphanumeric order to improve human reading.
-       fun live_types_to_csv: CSVDocument
+       fun live_types_to_csv: CsvDocument
        do
                # Gather all kind of type
                var typeset = new HashSet[MType]
@@ -121,7 +121,8 @@ class RapidTypeAnalysis
                typeset.add_all(live_open_cast_types)
                var types = typeset.to_a
                (new CachedAlphaComparator).sort(types)
-               var res = new CSVDocument
+               var res = new CsvDocument
+               res.format = new CsvFormat('"', ';', "\n")
                res.header = ["Type", "Resolution", "Liveness", "Cast-liveness"]
                for t in types do
                        var reso
@@ -130,7 +131,7 @@ class RapidTypeAnalysis
                        if t isa MClassType and (live_types.has(t) or live_open_types.has(t)) then live = "LIVE" else live = "DEAD"
                        var cast
                        if live_cast_types.has(t) or live_open_cast_types.has(t) then cast = "CAST LIVE" else cast = "CAST DEAD"
-                       res.add_line(t, reso, live, cast)
+                       res.add_record(t, reso, live, cast)
                end
                return res
        end
@@ -215,7 +216,7 @@ class RapidTypeAnalysis
 
                        var vararg_rank = mmethoddef.msignature.vararg_rank
                        if vararg_rank > -1 then
-                               var node = self.modelbuilder.mpropdef2npropdef[mmethoddef]
+                               var node = self.modelbuilder.mpropdef2node(mmethoddef)
                                var elttype = mmethoddef.msignature.mparameters[vararg_rank].mtype
                                #elttype = elttype.anchor_to(self.mainmodule, v.receiver)
                                var vararg = self.mainmodule.get_primitive_class("Array").get_mtype([elttype])
@@ -235,27 +236,25 @@ class RapidTypeAnalysis
                                add_cast(paramtype)
                        end
 
-                       if not modelbuilder.mpropdef2npropdef.has_key(mmethoddef) then
-                               # It is an init for a class?
-                               if mmeth.is_root_init then
-                                       var nclassdef = self.modelbuilder.mclassdef2nclassdef[mmethoddef.mclassdef]
-                                       assert mmethoddef == nclassdef.mfree_init
+                       var npropdef = modelbuilder.mpropdef2node(mmethoddef)
 
-                                       if mmethoddef.mproperty.is_root_init and not mmethoddef.is_intro then
-                                               self.add_super_send(v.receiver, mmethoddef)
-                                       end
-                               else if mmethoddef.constant_value != null then
-                                       # Make the return type live
-                                       v.add_type(mmethoddef.msignature.return_mtype.as(MClassType))
-                               else
-                                       abort
+                       if npropdef isa AClassdef then
+                               # It is an init for a class
+                               assert mmethoddef == npropdef.mfree_init
+
+                               if mmethoddef.mproperty.is_root_init and not mmethoddef.is_intro then
+                                       self.add_super_send(v.receiver, mmethoddef)
                                end
                                continue
+                       else if mmethoddef.constant_value != null then
+                               # Make the return type live
+                               v.add_type(mmethoddef.msignature.return_mtype.as(MClassType))
+                               continue
+                       else if npropdef == null then
+                               abort
                        end
 
-                       var npropdef = modelbuilder.mpropdef2npropdef[mmethoddef]
-
-                       if npropdef isa AMethPropdef  then
+                       if npropdef isa AMethPropdef then
                                var auto_super_inits = npropdef.auto_super_inits
                                if auto_super_inits != null then
                                        for auto_super_init in auto_super_inits do
@@ -345,10 +344,7 @@ class RapidTypeAnalysis
                var bound_mtype = mtype.anchor_to(mainmodule, recv)
                for cd in bound_mtype.collect_mclassdefs(mainmodule)
                do
-                       if not self.modelbuilder.mclassdef2nclassdef.has_key(cd) then continue
-                       var nclassdef = self.modelbuilder.mclassdef2nclassdef[cd]
-                       for npropdef in nclassdef.n_propdefs do
-                               if not npropdef isa AAttrPropdef then continue
+                       for npropdef in modelbuilder.collect_attr_propdef(cd) do
                                if not npropdef.has_value then continue
 
                                var mpropdef = npropdef.mpropdef.as(not null)
index 3140de5..cdb8ae8 100644 (file)
@@ -668,7 +668,11 @@ redef class AVardeclExpr
                var nexpr = self.n_expr
                if nexpr != null then
                        if mtype != null then
-                               v.visit_expr_subtype(nexpr, mtype)
+                               var etype = v.visit_expr_subtype(nexpr, mtype)
+                               if etype == mtype then
+                                       assert ntype != null
+                                       v.modelbuilder.advice(ntype, "useless-type", "Warning: useless type definition for variable `{variable.name}`")
+                               end
                        else
                                mtype = v.visit_expr(nexpr)
                                if mtype == null then return # Skip error
index c546c2e..71a8669 100644 (file)
@@ -17,7 +17,7 @@ module test_docdown
 
 import modelize
 import highlight
-import markdown
+import docdown
 
 redef class ModelBuilder
        fun test_markdown(page: HTMLTag, mmodule: MModule)
index 7bb39ca..27e6fac 100644 (file)
@@ -16,7 +16,7 @@
 module testing_doc
 
 import testing_base
-intrude import markdown
+intrude import docdown
 
 # Extractor, Executor and Reporter for the tests in a module
 class NitUnitExecutor
@@ -34,32 +34,31 @@ class NitUnitExecutor
        # All blocks of code from a same `ADoc`
        var blocks = new Array[Array[String]]
 
-       redef fun process_code(n: HTMLTag, text: String)
+       # All failures from a same `ADoc`
+       var failures = new Array[String]
+
+       redef fun process_code(n: HTMLTag, text: String, tag: nullable String)
        do
                # Skip non-blocks
                if n.tag != "pre" then return
 
+               # Skip strict non-nit
+               if tag != null and tag != "nit" and tag != "" then
+                       return
+               end
+
                # Try to parse it
                var ast = toolcontext.parse_something(text)
 
+               # Skip pure comments
+               if ast isa TComment then return
+
                # We want executable code
                if not (ast isa AModule or ast isa ABlockExpr or ast isa AExpr) then
-                       if ndoc != null and n.tag == "pre" and toolcontext.opt_warn.value > 1 then
-                               toolcontext.warning(ndoc.location, "invalid-block", "Warning: There is a block of code that is not valid Nit, thus not considered a nitunit")
-                               if ast isa AError then toolcontext.warning(ast.location, "syntax-error", ast.message)
-                               ndoc = null # To avoid multiple warning in the same node
-                       end
-                       return
-               end
-
-               # Search `assert` in the AST
-               var v = new SearchAssertVisitor
-               v.enter_visit(ast)
-               if not v.foundit then
-                       if ndoc != null and n.tag == "pre" and toolcontext.opt_warn.value > 1 then
-                               toolcontext.warning(ndoc.location, "invalid-block", "Warning: There is a block of Nit code without `assert`, thus not considered a nitunit")
-                               ndoc = null # To avoid multiple warning in the same node
-                       end
+                       var message = ""
+                       if ast isa AError then message = " At {ast.location}: {ast.message}."
+                       toolcontext.warning(ndoc.location, "invalid-block", "Error: There is a block of code that is not valid Nit, thus not considered a nitunit. To suppress this warning, enclose the block with a fence tagged `nitish` or `raw` (see `man nitdoc`).{message}")
+                       failures.add("{ndoc.location}: Invalid block of code.{message}")
                        return
                end
 
@@ -84,12 +83,24 @@ class NitUnitExecutor
        fun extract(ndoc: ADoc, tc: HTMLTag)
        do
                blocks.clear
+               failures.clear
 
                self.ndoc = ndoc
 
                work(ndoc.to_mdoc)
+
                toolcontext.check_errors
 
+               if not failures.is_empty then
+                       for msg in failures do
+                               var ne = new HTMLTag("failure")
+                               ne.attr("message", msg)
+                               tc.add ne
+                               toolcontext.modelbuilder.failed_entities += 1
+                       end
+                       if blocks.is_empty then testsuite.add(tc)
+               end
+
                if blocks.is_empty then return
 
                for block in blocks do test_block(ndoc, tc, block)
index 1a3006d..37f5c74 100644 (file)
@@ -141,19 +141,26 @@ class TestSuite
                if not toolcontext.test_dir.file_exists then
                        toolcontext.test_dir.mkdir
                end
+               write_to_nit
+               compile
                toolcontext.info("Execute test-suite {mmodule.name}", 1)
                var before_module = self.before_module
-               if not before_module == null then run_case(before_module)
-               for case in test_cases do run_case(case)
+               if not before_module == null then before_module.run
+               for case in test_cases do case.run
                var after_module = self.after_module
-               if not after_module == null then run_case(after_module)
+               if not after_module == null then after_module.run
        end
 
-       # Execute a test case
-       fun run_case(test_case: TestCase) do
-               test_case.write_to_nit
-               test_case.compile
-               test_case.run
+       # Write the test unit for `self` in a nit compilable file.
+       fun write_to_nit do
+               var file = new Template
+               file.addn "intrude import test_suite"
+               file.addn "import {mmodule.name}\n"
+               file.addn "var name = args.first"
+               for case in test_cases do
+                       case.write_to_nit(file)
+               end
+               file.write_to_file("{test_file}.nit")
        end
 
        # Return the test suite in XML format compatible with Jenkins.
@@ -161,56 +168,22 @@ class TestSuite
        fun to_xml: HTMLTag do
                var n = new HTMLTag("testsuite")
                n.attr("package", mmodule.name)
-               for test in test_cases do n.add test.to_xml
+               if failure != null then
+                       var f = new HTMLTag("failure")
+                       f.attr("message", failure.to_s)
+                       n.add f
+               else
+                       for test in test_cases do n.add test.to_xml
+               end
                return n
        end
-end
-
-# A test case is a unit test considering only a `MMethodDef`.
-class TestCase
-
-       # Test suite wich `self` belongs to.
-       var test_suite: TestSuite
-
-       # Test method to be compiled and tested.
-       var test_method: MMethodDef
-
-       # `ToolContext` to use to display messages and find `nitg` bin.
-       var toolcontext: ToolContext
-
-       # `MMethodDef` to call before the test case.
-       var before_test: nullable MMethodDef = null
-
-       # `MMethodDef` to call after the test case.
-       var after_test: nullable MMethodDef = null
 
        # Generated test file name.
        fun test_file: String do
-               var dir = toolcontext.test_dir
-               var mod = test_method.mclassdef.mmodule.name
-               var cls = test_method.mclassdef.name
-               var name = test_method.name
-               return "{dir}/{mod}_{cls}_{name}"
-       end
-
-       # Generate the test unit in a nit file.
-       fun write_to_nit do
-               var name = test_method.name
-               var file = new Template
-               file.addn "intrude import test_suite"
-               file.addn "import {test_method.mclassdef.mmodule.name}\n"
-               if test_method.mproperty.is_toplevel then
-                       file.addn name
-               else
-                       file.addn "var subject = new {test_method.mclassdef.name}.nitunit"
-                       if before_test != null then file.addn "subject.{before_test.name}"
-                       file.addn "subject.{name}"
-                       if after_test != null then file.addn "subject.{after_test.name}"
-               end
-               file.write_to_file("{test_file}.nit")
+               return toolcontext.test_dir / "gen_{mmodule.name.escape_to_c}"
        end
 
-       # Compile all test cases in once.
+       # Compile all `test_cases` cases in one file.
        fun compile do
                # find nitg
                var nit_dir = toolcontext.nit_dir
@@ -221,49 +194,86 @@ class TestCase
                end
                # compile test suite
                var file = test_file
-               var include_dir = test_method.mclassdef.mmodule.location.file.filename.dirname
+               var include_dir = mmodule.location.file.filename.dirname
                var cmd = "{nitg} --no-color '{file}.nit' -I {include_dir} -o '{file}.bin' > '{file}.out' 2>&1 </dev/null"
                var res = sys.system(cmd)
                var f = new IFStream.open("{file}.out")
                var msg = f.read_all
                f.close
                # set test case result
-               var loc = test_method.location
+               var loc = mmodule.location
                if res != 0 then
                        failure = msg
-                       toolcontext.warning(loc, "failure", "FAILURE: {test_method.name} (in file {file}.nit): {msg}")
+                       toolcontext.warning(loc, "failure", "FAILURE: {mmodule.name} (in file {file}.nit): {msg}")
                        toolcontext.modelbuilder.failed_tests += 1
                end
                toolcontext.check_errors
        end
 
+       # Error occured during test-suite compilation.
+       var failure: nullable String = null
+end
+
+# A test case is a unit test considering only a `MMethodDef`.
+class TestCase
+
+       # Test suite wich `self` belongs to.
+       var test_suite: TestSuite
+
+       # Test method to be compiled and tested.
+       var test_method: MMethodDef
+
+       # `ToolContext` to use to display messages and find `nitg` bin.
+       var toolcontext: ToolContext
+
+       # `MMethodDef` to call before the test case.
+       var before_test: nullable MMethodDef = null
+
+       # `MMethodDef` to call after the test case.
+       var after_test: nullable MMethodDef = null
+
+       # Generate the test unit for `self` in `file`.
+       fun write_to_nit(file: Template) do
+               var name = test_method.name
+               file.addn "if name == \"{name}\" then"
+               if test_method.mproperty.is_toplevel then
+                       file.addn "\t{name}"
+               else
+                       file.addn "\tvar subject = new {test_method.mclassdef.name}.nitunit"
+                       if before_test != null then file.addn "\tsubject.{before_test.name}"
+                       file.addn "\tsubject.{name}"
+                       if after_test != null then file.addn "\tsubject.{after_test.name}"
+               end
+               file.addn "end"
+       end
+
        # Execute the test case.
        fun run do
                toolcontext.info("Execute test-case {test_method.name}", 1)
                was_exec = true
                if toolcontext.opt_noact.value then return
                # execute
-               var file = test_file
-               var res = sys.system("{file.to_program_name}.bin > '{file}.out1' 2>&1 </dev/null")
-               var f = new IFStream.open("{file}.out1")
+               var method_name = test_method.name
+               var test_file = test_suite.test_file
+               var res_name = "{test_file}_{method_name.escape_to_c}"
+               var res = sys.system("{test_file}.bin {method_name} > '{res_name}.out1' 2>&1 </dev/null")
+               var f = new IFStream.open("{res_name}.out1")
                var msg = f.read_all
                f.close
                # set test case result
                var loc = test_method.location
                if res != 0 then
                        error = msg
-                       toolcontext.warning(loc, "failure", "ERROR: {test_method.name} (in file {file}.nit): {msg}")
+                       toolcontext.warning(loc, "failure",
+                          "ERROR: {method_name} (in file {test_file}.nit): {msg}")
                        toolcontext.modelbuilder.failed_tests += 1
                end
                toolcontext.check_errors
        end
 
-       # Error occured during execution.
+       # Error occured during test-case execution.
        var error: nullable String = null
 
-       # Error occured during compilation.
-       var failure: nullable String = null
-
        # Was the test case executed at least one?
        var was_exec = false
 
@@ -284,11 +294,6 @@ class TestCase
                                n.attr("message", error.to_s)
                                tc.add n
                        end
-                       if failure != null then
-                               n = new HTMLTag("failure")
-                               n.attr("message", failure.to_s)
-                               tc.add n
-                       end
                end
                return tc
        end
@@ -366,8 +371,13 @@ redef class MModule
 end
 
 redef class ModelBuilder
+       # Number of test classes generated.
        var total_classes = 0
+
+       # Number of tests generated.
        var total_tests = 0
+
+       # Number of failed tests.
        var failed_tests = 0
 
        # Run NitUnit test file for mmodule (if exists).
@@ -383,13 +393,13 @@ redef class ModelBuilder
                        test_file = "{include_dir}/{test_file}"
                end
                if not test_file.file_exists then
-                       toolcontext.info("Skip test for {mmodule}, no file {test_file} found", 1)
+                       toolcontext.info("Skip test for {mmodule}, no file {test_file} found", 2)
                        return ts
                end
                var tester = new NitUnitTester(self)
                var res = tester.test_module_unit(test_file)
                if res == null then
-                       toolcontext.info("Skip test for {mmodule}, no test suite found", 1)
+                       toolcontext.info("Skip test for {mmodule}, no test suite found", 2)
                        return ts
                end
                return res.to_xml
index ec91130..4547fb7 100644 (file)
@@ -105,9 +105,20 @@ class ToolContext
        private var messages = new Array[Message]
        private var message_sorter: Comparator = default_comparator
 
-       # Output all current stacked messages.
-       # If some errors occurred, exits the program.
-       fun check_errors
+       # Does an error prevent the program to stop at `check_errors`?
+       #
+       # Default to false.
+       # Set this value to `true` if you need to keep the program going in case of error.
+       var keep_going = false is writable
+
+       # Output all current stacked messages and display total error informations
+       #
+       # Return true if no errors occurred.
+       #
+       # If some errors occurred, the behavior depends on the value of `keep_going`.
+       # If `keep_going` is false, then the program exits.
+       # Else, the error count and the warning count are reset and false is returned.
+       fun check_errors: Bool
        do
                if messages.length > 0 then
                        message_sorter.sort(messages)
@@ -125,16 +136,20 @@ class ToolContext
 
                if error_count > 0 then
                        errors_info
-                       exit(1)
+                       if not keep_going then exit(1)
+                       return false
                end
+               return true
        end
 
-       # Display total error informations
+       # Display (and reset) total error informations
        fun errors_info
        do
                if error_count == 0 and warning_count == 0 then return
                if opt_no_color.value then return
                sys.stderr.write "Errors: {error_count}. Warnings: {warning_count}.\n"
+               error_count = 0
+               warning_count = 0
        end
 
        # Display an error
index 2212380..07acefb 100644 (file)
@@ -272,10 +272,12 @@ end
 redef class AArrayExpr
        # `[x,y]` is replaced with
        #
-       #     var t = new Array[X].with_capacity(2)
-       #     t.add(x)
-       #     t.add(y)
-       #     t
+       # ~~~nitish
+       # var t = new Array[X].with_capacity(2)
+       # t.add(x)
+       # t.add(y)
+       # t
+       # ~~~
        redef fun accept_transform_visitor(v)
        do
                var nblock = v.builder.make_block
@@ -323,11 +325,15 @@ end
 redef class ASendReassignFormExpr
        # `x.foo(y)+=z` is replaced with
        #
-       #     x.foo(y) = x.foo(y) + z
+       # ~~~nitish
+       # x.foo(y) = x.foo(y) + z
+       # ~~~
        #
        # witch is, in reality:
        #
-       #     x."foo="(y, x.foo(y)."+"(z))
+       # ~~~nitish
+       # x."foo="(y, x.foo(y)."+"(z))
+       # ~~~
        redef fun accept_transform_visitor(v)
        do
                var nblock = v.builder.make_block
index 9e9c778..53a99fa 100644 (file)
@@ -41,23 +41,34 @@ class VirtualMachine super NaiveInterpreter
        # Perfect hashing and perfect numbering
        var ph: Perfecthashing = new Perfecthashing
 
-       # Handles memory and garbage collection
+       # Handles memory allocated in C
        var memory_manager: MemoryManager = new MemoryManager
 
        # The unique instance of the `MInit` value
-       var initialization_value: Instance
+       var initialization_value: Instance is noinit
 
-       init(modelbuilder: ModelBuilder, mainmodule: MModule, arguments: Array[String])
+       init
        do
                var init_type = new MInitType(mainmodule.model)
                initialization_value = new MutableInstance(init_type)
                super
        end
 
-       # Subtyping test for the virtual machine
+       # Runtime subtyping test
        redef fun is_subtype(sub, sup: MType): Bool
        do
+               if sub == sup then return true
+
                var anchor = self.frame.arguments.first.mtype.as(MClassType)
+
+               # `sub` or `sup` are formal or virtual types, resolve them to concrete types
+               if sub isa MParameterType or sub isa MVirtualType then
+                       sub = sub.resolve_for(anchor.mclass.mclass_type, anchor, mainmodule, false)
+               end
+               if sup isa MParameterType or sup isa MVirtualType then
+                       sup = sup.resolve_for(anchor.mclass.mclass_type, anchor, mainmodule, false)
+               end
+
                var sup_accept_null = false
                if sup isa MNullableType then
                        sup_accept_null = true
@@ -77,11 +88,6 @@ class VirtualMachine super NaiveInterpreter
                end
                # Now the case of direct null and nullable is over
 
-               # An unfixed formal type can only accept itself
-               if sup isa MParameterType or sup isa MVirtualType then
-                       return sub == sup
-               end
-
                if sub isa MParameterType or sub isa MVirtualType then
                        sub = sub.anchor_to(mainmodule, anchor)
                        # Manage the second layer of null/nullable
@@ -100,34 +106,33 @@ class VirtualMachine super NaiveInterpreter
 
                assert sup isa MClassType
 
-               # Create the sup vtable if not create
+               # `sub` and `sup` can be discovered inside a Generic type during the subtyping test
                if not sup.mclass.loaded then create_class(sup.mclass)
-
-               # Sub can be discovered inside a Generic type during the subtyping test
                if not sub.mclass.loaded then create_class(sub.mclass)
 
-               if sup isa MGenericType then
-                       var sub2 = sub.supertype_to(mainmodule, anchor, sup.mclass)
-                       assert sub2.mclass == sup.mclass
-
-                       for i in [0..sup.mclass.arity[ do
-                               var sub_arg = sub2.arguments[i]
-                               var sup_arg = sup.arguments[i]
-                               var res = is_subtype(sub_arg, sup_arg)
-
-                               if res == false then return false
-                       end
-                       return true
-               end
-
+               # For now, always use perfect hashing for subtyping test
                var super_id = sup.mclass.vtable.id
                var mask = sub.mclass.vtable.mask
 
-               return inter_is_subtype(super_id, mask, sub.mclass.vtable.internal_vtable)
+               var res = inter_is_subtype_ph(super_id, mask, sub.mclass.vtable.internal_vtable)
+               if res == false then return false
+               # sub and sup can be generic types, each argument of generics has to be tested
+
+               if not sup isa MGenericType then return true
+               var sub2 = sub.supertype_to(mainmodule, anchor, sup.mclass)
+
+               # Test each argument of a generic by recursive calls
+               for i in [0..sup.mclass.arity[ do
+                       var sub_arg = sub2.arguments[i]
+                       var sup_arg = sup.arguments[i]
+                       var res2 = is_subtype(sub_arg, sup_arg)
+                       if res2 == false then return false
+               end
+               return true
        end
 
        # Subtyping test with perfect hashing
-       private fun inter_is_subtype(id: Int, mask:Int, vtable: Pointer): Bool `{
+       private fun inter_is_subtype_ph(id: Int, mask:Int, vtable: Pointer): Bool `{
                // hv is the position in hashtable
                int hv = id & mask;
 
@@ -138,6 +143,14 @@ class VirtualMachine super NaiveInterpreter
                return *offset == id;
        `}
 
+       # Subtyping test with Cohen test (direct access)
+       private fun inter_is_subtype_sst(id: Int, position: Int, vtable: Pointer): Bool `{
+               // Direct access to the position given in parameter
+               int tableid = (long unsigned int)((long int *)vtable)[position];
+
+               return id == tableid;
+       `}
+
        # Redef init_instance to simulate the loading of a class
        redef fun init_instance(recv: Instance)
        do
@@ -195,17 +208,21 @@ class VirtualMachine super NaiveInterpreter
                var ret = send_commons(mproperty, args, mtype)
                if ret != null then return ret
 
-               var propdef = method_dispatch(mproperty, recv.vtable.as(not null))
+               var propdef = method_dispatch(mproperty, recv.vtable.as(not null), recv)
 
                return self.call(propdef, args)
        end
 
        # Method dispatch, for a given global method `mproperty`
        # returns the most specific local method in the class corresponding to `vtable`
-       private fun method_dispatch(mproperty: MMethod, vtable: VTable): MMethodDef
+       private fun method_dispatch(mproperty: MMethod, vtable: VTable, recv: Instance): MMethodDef
        do
-               return method_dispatch_ph(vtable.internal_vtable, vtable.mask,
+               if mproperty.intro_mclassdef.mclass.positions_methods[recv.mtype.as(MClassType).mclass] != -1 then
+                       return method_dispatch_sst(vtable.internal_vtable, mproperty.absolute_offset)
+               else
+                       return method_dispatch_ph(vtable.internal_vtable, vtable.mask,
                                mproperty.intro_mclassdef.mclass.vtable.id, mproperty.offset)
+               end
        end
 
        # Execute a method dispatch with perfect hashing
@@ -221,16 +238,34 @@ class VirtualMachine super NaiveInterpreter
                return propdef;
        `}
 
+       # Execute a method dispatch with direct access and return the appropriate `MMethodDef`
+       # `vtable` : Pointer to the internal pointer of the class
+       # `absolute_offset` : Absolute offset from the beginning of the virtual table
+       private fun method_dispatch_sst(vtable: Pointer, absolute_offset: Int): MMethodDef `{
+               // pointer+2 is the position where methods are
+               // Add the offset of property and get the method implementation
+               MMethodDef propdef = (MMethodDef)((long int *)vtable)[absolute_offset];
+
+               return propdef;
+       `}
+
        # Return the value of the attribute `mproperty` for the object `recv`
        redef fun read_attribute(mproperty: MAttribute, recv: Instance): Instance
        do
                assert recv isa MutableInstance
 
-               # Read the attribute value with perfect hashing
-               var id = mproperty.intro_mclassdef.mclass.vtable.id
+               var i: Instance
 
-               var i = read_attribute_ph(recv.internal_attributes, recv.vtable.internal_vtable,
+               if mproperty.intro_mclassdef.mclass.positions_attributes[recv.mtype.as(MClassType).mclass] != -1 then
+                       # if this attribute class has an unique position for this receiver, then use direct access
+                       i = read_attribute_sst(recv.internal_attributes, mproperty.absolute_offset)
+               else
+                       # Otherwise, read the attribute value with perfect hashing
+                       var id = mproperty.intro_mclassdef.mclass.vtable.id
+
+                       i = read_attribute_ph(recv.internal_attributes, recv.vtable.internal_vtable,
                                        recv.vtable.mask, id, mproperty.offset)
+               end
 
                # If we get a `MInit` value, throw an error
                if i == initialization_value then
@@ -242,11 +277,11 @@ class VirtualMachine super NaiveInterpreter
        end
 
        # Return the attribute value in `instance` with a sequence of perfect_hashing
-       #     `instance` is the attributes array of the receiver
-       #     `vtable` is the pointer to the virtual table of the class (of the receiver)
-       #     `mask` is the perfect hashing mask of the class
-       #     `id` is the identifier of the class
-       #     `offset` is the relative offset of this attribute
+       # * `instance` is the attributes array of the receiver
+       # * `vtable` is the pointer to the virtual table of the class (of the receiver)
+       # * `mask` is the perfect hashing mask of the class
+       # * `id` is the identifier of the class
+       # * `offset` is the relative offset of this attribute
        private fun read_attribute_ph(instance: Pointer, vtable: Pointer, mask: Int, id: Int, offset: Int): Instance `{
                // Perfect hashing position
                int hv = mask & id;
@@ -260,25 +295,43 @@ class VirtualMachine super NaiveInterpreter
                return res;
        `}
 
+       # Return the attribute value in `instance` with a direct access (SST)
+       # * `instance` is the attributes array of the receiver
+       # * `offset` is the absolute offset of this attribute
+       private fun read_attribute_sst(instance: Pointer, offset: Int): Instance `{
+               /* We can make a direct access to the attribute value
+                  because this attribute is always at the same position
+                  for the class of this receiver */
+               Instance res = ((Instance *)instance)[offset];
+
+               return res;
+       `}
+
        # Replace in `recv` the value of the attribute `mproperty` by `value`
        redef fun write_attribute(mproperty: MAttribute, recv: Instance, value: Instance)
        do
                assert recv isa MutableInstance
 
-               var id = mproperty.intro_mclassdef.mclass.vtable.id
-
                # Replace the old value of mproperty in recv
-               write_attribute_ph(recv.internal_attributes, recv.vtable.internal_vtable,
+               if mproperty.intro_mclassdef.mclass.positions_attributes[recv.mtype.as(MClassType).mclass] != -1 then
+                       # if this attribute class has an unique position for this receiver, then use direct access
+                       write_attribute_sst(recv.internal_attributes, mproperty.absolute_offset, value)
+               else
+                       # Otherwise, use perfect hashing to replace the old value
+                       var id = mproperty.intro_mclassdef.mclass.vtable.id
+
+                       write_attribute_ph(recv.internal_attributes, recv.vtable.internal_vtable,
                                        recv.vtable.mask, id, mproperty.offset, value)
+               end
        end
 
        # Replace the value of an attribute in an instance
-       #     `instance` is the attributes array of the receiver
-       #     `vtable` is the pointer to the virtual table of the class (of the receiver)
-       #     `mask` is the perfect hashing mask of the class
-       #     `id` is the identifier of the class
-       #     `offset` is the relative offset of this attribute
-       #     `value` is the new value for this attribute
+       # * `instance` is the attributes array of the receiver
+       # * `vtable` is the pointer to the virtual table of the class (of the receiver)
+       # * `mask` is the perfect hashing mask of the class
+       # * `id` is the identifier of the class
+       # * `offset` is the relative offset of this attribute
+       # * `value` is the new value for this attribute
        private fun write_attribute_ph(instance: Pointer, vtable: Pointer, mask: Int, id: Int, offset: Int, value: Instance) `{
                // Perfect hashing position
                int hv = mask & id;
@@ -291,6 +344,16 @@ class VirtualMachine super NaiveInterpreter
                Instance_incr_ref(value);
        `}
 
+       # Replace the value of an attribute in an instance with direct access
+       # * `instance` is the attributes array of the receiver
+       # * `offset` is the absolute offset of this attribute
+       # * `value` is the new value for this attribute
+       private fun write_attribute_sst(instance: Pointer, offset: Int, value: Instance) `{
+               // Direct access to the position with the absolute offset
+               ((Instance *)instance)[offset] = value;
+               Instance_incr_ref(value);
+       `}
+
        # Is the attribute `mproperty` initialized in the instance `recv`?
        redef fun isset_attribute(mproperty: MAttribute, recv: Instance): Bool
        do
@@ -314,6 +377,10 @@ redef class MClass
        # True when the class is effectively loaded by the vm, false otherwise
        var loaded: Bool = false
 
+       # Color for Cohen subtyping test : the absolute position of the id
+       # of this class in virtual tables
+       var color: Int
+
        # For each loaded subclass, keep the position of the group of attributes
        # introduced by self class in the object
        var positions_attributes: HashMap[MClass, Int] = new HashMap[MClass, Int]
@@ -336,11 +403,17 @@ redef class MClass
                var nb_methods = new Array[Int]
                var nb_attributes = new Array[Int]
 
-               # Absolute offset of the beginning of the attributes table
+               # Absolute offset of attribute from the beginning of the attributes table
                var offset_attributes = 0
-               # Absolute offset of the beginning of the methods table
-               var offset_methods = 0
 
+               # Absolute offset of method from the beginning of the methods table,
+               # is initialize to 3 because the first position is empty in the virtual table
+               # and the second and third are respectively class id and delta
+               var offset_methods = 3
+
+               # The previous element in `superclasses`
+               var previous_parent: nullable MClass = null
+               if superclasses.length > 0 then previous_parent = superclasses[0]
                for parent in superclasses do
                        if not parent.loaded then parent.make_vt(v)
 
@@ -350,26 +423,36 @@ redef class MClass
 
                        for p in parent.intro_mproperties(none_visibility) do
                                if p isa MMethod then methods += 1
-                               if p isa MAttribute then
-                                       attributes += 1
-                               end
+                               if p isa MAttribute then attributes += 1
                        end
 
                        ids.push(parent.vtable.id)
                        nb_methods.push(methods)
                        nb_attributes.push(attributes)
 
-                       # Update `positions_attributes` and `positions_methods` in `parent`
-                       update_positions(offset_attributes, offset_methods, parent)
+                       # Update `positions_attributes` and `positions_methods` in `parent`.
+                       # If the position is invariant for this parent, store this position
+                       # else store a special value (-1)
+                       var pos_attr = -1
+                       var pos_meth = -1
+
+                       if previous_parent.as(not null).positions_attributes[parent] == offset_attributes then pos_attr = offset_attributes
+                       if previous_parent.as(not null).positions_methods[parent] == offset_methods then pos_meth = offset_methods
+
+                       parent.update_positions(pos_attr, pos_meth, self)
 
                        offset_attributes += attributes
                        offset_methods += methods
+                       offset_methods += 2 # Because each block starts with an id and the delta
                end
 
                # When all super-classes have their identifiers and vtables, allocate current one
                allocate_vtable(v, ids, nb_methods, nb_attributes, offset_attributes, offset_methods)
                loaded = true
 
+               # Set the absolute position of the identifier of this class in the virtual table
+               color = offset_methods - 2
+
                # The virtual table now needs to be filled with pointer to methods
                superclasses.add(self)
                for cl in superclasses do
@@ -378,11 +461,11 @@ redef class MClass
        end
 
        # Allocate a single vtable
-       #     `ids : Array of superclasses identifiers
-       #     `nb_methods : Array which contain the number of introduced methods for each class in ids
-       #     `nb_attributes : Array which contain the number of introduced attributes for each class in ids
-       #     `offset_attributes : Offset from the beginning of the table of the group of attributes
-       #     `offset_methods : Offset from the beginning of the table of the group of methods
+       # * `ids : Array of superclasses identifiers
+       # * `nb_methods : Array which contain the number of introduced methods for each class in ids
+       # * `nb_attributes : Array which contain the number of introduced attributes for each class in ids
+       # * `offset_attributes : Offset from the beginning of the table of the group of attributes
+       # * `offset_methods : Offset from the beginning of the table of the group of methods
        private fun allocate_vtable(v: VirtualMachine, ids: Array[Int], nb_methods: Array[Int], nb_attributes: Array[Int],
                        offset_attributes: Int, offset_methods: Int)
        do
@@ -411,11 +494,13 @@ redef class MClass
                        if p isa MMethod then
                                self_methods += 1
                                p.offset = relative_offset_meth
+                               p.absolute_offset = offset_methods + relative_offset_meth
                                relative_offset_meth += 1
                        end
                        if p isa MAttribute then
                                nb_introduced_attributes += 1
                                p.offset = relative_offset_attr
+                               p.absolute_offset = offset_attributes + relative_offset_attr
                                relative_offset_attr += 1
                        end
                end
@@ -427,18 +512,16 @@ redef class MClass
                nb_attributes_total.push(nb_introduced_attributes)
 
                # Save the offsets of self class
-               offset_attributes += nb_introduced_attributes
-               offset_methods += self_methods
                update_positions(offset_attributes, offset_methods, self)
 
                # Since we have the number of attributes for each class, calculate the delta
-               var d = calculate_delta(nb_attributes_total)
-               vtable.internal_vtable = v.memory_manager.init_vtable(ids_total, nb_methods_total, d, vtable.mask)
+               var deltas = calculate_delta(nb_attributes_total)
+               vtable.internal_vtable = v.memory_manager.init_vtable(ids_total, nb_methods_total, deltas, vtable.mask)
        end
 
        # Fill the vtable with methods of `self` class
-       #     `v` : Current instance of the VirtualMachine
-       #     `table` : the table of self class, will be filled with its methods
+       # * `v` : Current instance of the VirtualMachine
+       # * `table` : the table of self class, will be filled with its methods
        private fun fill_vtable(v:VirtualMachine, table: VTable, cl: MClass)
        do
                var methods = new Array[MMethodDef]
@@ -456,8 +539,8 @@ redef class MClass
 
        # Computes delta for each class
        # A delta represents the offset for this group of attributes in the object
-       #     `nb_attributes` : number of attributes for each class (classes are linearized from Object to current)
-       #     return deltas for each class
+       # *`nb_attributes` : number of attributes for each class (classes are linearized from Object to current)
+       # * return deltas for each class
        private fun calculate_delta(nb_attributes: Array[Int]): Array[Int]
        do
                var deltas = new Array[Int]
@@ -476,7 +559,9 @@ redef class MClass
        private fun superclasses_ordering(v: VirtualMachine): Array[MClass]
        do
                var superclasses = new Array[MClass]
-               superclasses.add_all(ancestors)
+
+               # Add all superclasses of `self`
+               superclasses.add_all(self.in_hierarchy(v.mainmodule).greaters)
 
                var res = new Array[MClass]
                if superclasses.length > 1 then
@@ -491,8 +576,8 @@ redef class MClass
        end
 
        # A kind of Depth-First-Search for superclasses ordering
-       #     `v` : the current executed instance of VirtualMachine
-       #     `res` : Result Array, ie current superclasses ordering
+       # *`v` : the current executed instance of VirtualMachine
+       # * `res` : Result Array, ie current superclasses ordering
        private fun dfs(v: VirtualMachine, res: Array[MClass]): Array[MClass]
        do
                # Add this class at the beginning
@@ -547,24 +632,31 @@ redef class MClass
                return res
        end
 
-       # Update positions of self class in `parent`
-       #     `attributes_offset`: absolute offset of introduced attributes
-       #     `methods_offset`: absolute offset of introduced methods
-       private fun update_positions(attributes_offsets: Int, methods_offset:Int, parent: MClass)
+       # Update positions of the class `cl`
+       # * `attributes_offset`: absolute offset of introduced attributes
+       # * `methods_offset`: absolute offset of introduced methods
+       private fun update_positions(attributes_offsets: Int, methods_offset:Int, cl: MClass)
        do
-               parent.positions_attributes[self] = attributes_offsets
-               parent.positions_methods[self] = methods_offset
+               positions_attributes[cl] = attributes_offsets
+               positions_methods[cl] = methods_offset
        end
 end
 
 redef class MAttribute
-       # Represents the relative offset of this attribute in the runtime instance
+       # Relative offset of this attribute in the runtime instance
+       # (beginning of the block of its introducing class)
        var offset: Int
+
+       # Absolute offset of this attribute in the runtime instance (beginning of the attribute table)
+       var absolute_offset: Int
 end
 
 redef class MMethod
-       # Represents the relative offset of this attribute in the runtime instance
+       # Relative offset of this method in the virtual table (from the beginning of the block)
        var offset: Int
+
+       # Absolute offset of this method in the virtual table (from the beginning of the vtable)
+       var absolute_offset: Int
 end
 
 # Redef MutableInstance to improve implementation of attributes in objects
@@ -576,6 +668,8 @@ end
 
 # Redef to associate an `Instance` to its `VTable`
 redef class Instance
+
+       # Associate a runtime instance to its virtual table which contains methods, types etc.
        var vtable: nullable VTable
 end
 
@@ -584,10 +678,6 @@ class MInitType
        super MType
 
        redef var model: Model
-       protected init(model: Model)
-       do
-               self.model = model
-       end
 
        redef fun to_s do return "InitType"
        redef fun as_nullable do return self
@@ -682,10 +772,10 @@ class MemoryManager
        `}
 
        # Put implementation of methods of a class in `vtable`
-       # `vtable` : Pointer to the C-virtual table
-       # `mask` : perfect-hashing mask of the class corresponding to the vtable
-       # `id` : id of the target class
-       # `methods` : array of MMethodDef of the target class
+       # * `vtable` : Pointer to the C-virtual table
+       # * `mask` : perfect-hashing mask of the class corresponding to the vtable
+       # * `id` : id of the target class
+       # * `methods` : array of MMethodDef of the target class
        fun put_methods(vtable: Pointer, mask: Int, id: Int, methods: Array[MMethodDef])
                import Array[MMethodDef].length, Array[MMethodDef].[] `{
 
diff --git a/tests/Linux.skip b/tests/Linux.skip
new file mode 100644 (file)
index 0000000..609105e
--- /dev/null
@@ -0,0 +1,3 @@
+cocoa_extern_types
+cocoa_message_box
+hello_cocoa
index 24c0604..cdd5559 100644 (file)
@@ -1,5 +1,5 @@
 
-PROGS=*.nit ../examples/*.nit ../examples/leapfrog/leapfrog.nit ../examples/shoot/shoot_logic.nit ../contrib/pep8analysis/src/pep8analysis ../lib/*.nit ../src/nitdoc.nit ../src/test_parser.nit ../src/nit.nit ../src/nitmetrics.nit ../src/nitg.nit
+PROGS=*.nit ../examples/*.nit ../examples/leapfrog/leapfrog.nit ../examples/shoot/shoot_logic.nit ../contrib/pep8analysis/src/pep8analysis ../contrib/nitiwiki/src/nitiwiki ../lib/*.nit ../src/nitdoc.nit ../src/test_parser.nit ../src/nit.nit ../src/nitmetrics.nit ../src/nitg.nit
 
 all: niti nitg-g nitg-s
 
index c1b4cff..cbf966b 100644 (file)
@@ -170,12 +170,15 @@ It is a success.
 The `$engine.skip` files (where `$engine` is an engine name, see below) describe tests that are skipped completely on a given engine.
 Usually it used with then engine `niti` because tests are too long.
 
-The `cc.skip` file describes tests that are analysed but no executable is generated.
-Usually it is because expected CC errors or missing C libraries.
+The `cc.skip` file describes tests that are analyzed but no executable is generated.
+Usually it is because of expected CC errors or missing C libraries.
 
 The `exec.skip` file describes tests that compiled but not executed.
 Usually it is because the programs are interactive or run some kind of server.
 
+The `$os.skip` file describes tests that are to be skipped completely on the given OS.
+Usually it is because of OS specific libraries.
+
 These `*.skip` files contain a list of patterns that will be used against test names.
 A single substring can thus be used to skip a full family of tests.
 
diff --git a/tests/base_formal_subtype.nit b/tests/base_formal_subtype.nit
new file mode 100644 (file)
index 0000000..9487b53
--- /dev/null
@@ -0,0 +1,164 @@
+# 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 end
+
+interface Object end
+
+enum Bool end
+
+class A[E: Object]
+       var o: Object
+
+       var e: E
+
+       type VE: E
+       var ve: VE
+
+       type VVE: VE
+       var vve: VVE
+
+       type VGE: G[E]
+       var vge: VGE
+
+       type VVGE: VGE
+       var vvge: VVGE
+
+       type VGVE: G[VE]
+       var vgve: VGVE
+
+       type VGVVE: G[VVE]
+       var vgvve: VGVVE
+
+       fun foo
+       do
+               # In order to check type relations, this test looks for the warnings about useless cast
+               # The following should produce a warning
+               assert o isa Object
+
+               assert e isa E
+               assert e isa Object
+
+               assert ve isa VE
+               assert ve isa E
+               assert ve isa Object
+
+               assert vve isa VVE
+               assert vve isa VE
+               assert vve isa E
+               assert vve isa Object
+
+               assert vge isa VGE
+               assert vge isa G[E]
+               assert vge isa G[Object]
+               assert vge isa Object
+
+               assert vvge isa VVGE
+               assert vvge isa VGE
+               assert vvge isa G[E]
+               assert vvge isa G[Object]
+               assert vvge isa Object
+
+               assert vgve isa VGVE
+               assert vgve isa G[VE]
+               assert vgve isa G[E]
+               assert vgve isa G[Object]
+               assert vgve isa Object
+
+               assert vgvve isa VGVVE
+               assert vgvve isa G[VVE]
+               assert vgvve isa G[VE]
+               assert vgvve isa G[E]
+               assert vgvve isa G[Object]
+               assert vgvve isa Object
+
+               # The following should not
+               assert o isa VGVVE
+               assert o isa G[VVE]
+               assert o isa VVGE
+               assert o isa VGVE
+               assert o isa G[VE]
+               assert o isa VGE
+               assert o isa G[E]
+               assert o isa G[Object]
+               assert o isa VVE
+               assert o isa VE
+               assert o isa E
+
+               assert e isa VGVVE
+               assert e isa G[VVE]
+               assert e isa VVGE
+               assert e isa VGVE
+               assert e isa G[VE]
+               assert e isa VGE
+               assert e isa G[E]
+               assert e isa G[Object]
+               assert e isa VVE
+               assert e isa VE
+
+               assert ve isa VGVVE
+               assert ve isa G[VVE]
+               assert ve isa VVGE
+               assert ve isa VGVE
+               assert ve isa G[VE]
+               assert ve isa VGE
+               assert ve isa G[E]
+               assert ve isa G[Object]
+               assert ve isa VVE
+
+               assert vve isa VGVVE
+               assert vve isa G[VVE]
+               assert vve isa VVGE
+               assert vve isa VGVE
+               assert vve isa G[VE]
+               assert vve isa VGE
+               assert vve isa G[E]
+               assert vve isa G[Object]
+
+               assert vge isa VGVVE
+               assert vge isa G[VVE]
+               assert vge isa VVGE
+               assert vge isa VGVE
+               assert vge isa G[VE]
+               assert vge isa VVE
+               assert vge isa VE
+               assert vge isa E
+
+               assert vvge isa VGVVE
+               assert vvge isa G[VVE]
+               assert vvge isa VGVE
+               assert vvge isa G[VE]
+               assert vvge isa VVE
+               assert vvge isa VE
+               assert vvge isa E
+
+               assert vgve isa VGVVE
+               assert vgve isa G[VVE]
+               assert vgve isa VGE
+               assert vgve isa VVGE
+               assert vgve isa VVE
+               assert vgve isa VE
+               assert vgve isa E
+
+               assert vgvve isa VGE
+               assert vgvve isa VVGE
+               assert vgvve isa VGVE
+               assert vgvve isa VVE
+               assert vgvve isa VE
+               assert vgvve isa E
+       end
+end
+
+class G[E]
+end
diff --git a/tests/base_self_type.nit b/tests/base_self_type.nit
new file mode 100644 (file)
index 0000000..7c5d204
--- /dev/null
@@ -0,0 +1,58 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import kernel
+
+class X
+       fun foo: SELF do return self
+       fun bar(o: SELF) do o.output_class_name
+end
+
+class Y
+       super X
+
+#alt1# redef fun foo do return new X
+#alt2# redef fun foo do return new Y
+end
+
+class A[E]
+       fun foo: Object do return new G[SELF]
+end
+
+class B[F]
+       super A[F]
+end
+
+class G[E:A[nullable Object]]
+end
+
+var x = new X
+x.output_class_name
+x.foo.output_class_name
+x.bar x
+
+var y = new Y
+y.output_class_name
+y.foo.output_class_name
+x.bar y
+y.bar y
+#alt3# y.bar x
+
+var a = new A[Int]
+a.output_class_name
+a.foo.output_class_name
+
+var b = new B[Bool]
+b.output_class_name
+b.foo.output_class_name
index 778d0d3..6dafd08 100755 (executable)
@@ -13,5 +13,7 @@ printf "%s\n" "$@" \
        ../examples/mpi/src/*.nit \
        ../lib/*/examples/*.nit \
        ../contrib/friendz/src/solver_cmd.nit \
+       ../contrib/neo_doxygen/src/tests/neo_doxygen_*.nit \
        ../contrib/pep8analysis/src/pep8analysis.nit \
+       ../contrib/nitiwiki/src/nitiwiki.nit \
        *.nit
diff --git a/tests/neo_doxygen_dump.args b/tests/neo_doxygen_dump.args
new file mode 100644 (file)
index 0000000..4046c7f
--- /dev/null
@@ -0,0 +1,7 @@
+'empty project with default settings' ../contrib/neo_doxygen/tests/empty-project/xml
+--src-lang any -- empty-project ../contrib/neo_doxygen/tests/empty-project/xml
+--src-lang java empty-project ../contrib/neo_doxygen/tests/empty-project/xml
+--src-lang any -- foo ../contrib/neo_doxygen/tests/java-project/xml
+--src-lang java -- foo ../contrib/neo_doxygen/tests/java-project/xml
+--src-lang java -- root-namespace ../contrib/neo_doxygen/tests/root-namespace/xml
+--src-lang java -- inner-class ../contrib/neo_doxygen/tests/inner-class/xml
index 7175bb7..f99ea03 100644 (file)
@@ -1,2 +1,7 @@
 nitg
 nitdoc
+nitlight
+neo_doxygen_dump
+neo_doxygen_file_compound
+neo_doxygen_graph_empty_project
+neo_doxygen_member_resolve_introducer
index 1fec913..c2c24ff 100644 (file)
@@ -12,9 +12,12 @@ nitg_args3
 nitg_args5
 nitg_args6
 nitg_args8
-test_markdown_args1
+nitunit_args
+test_docdown_args
 pep8analysis
 emscripten
 nitserial_args
 nitunit_args
 nitpretty_args
+hamming_number
+hailstone
diff --git a/tests/nitiwiki.args b/tests/nitiwiki.args
new file mode 100644 (file)
index 0000000..ae082af
--- /dev/null
@@ -0,0 +1,2 @@
+nitiwiki --config ../contrib/nitiwiki/tests/wiki1/config2.ini --clean --status
+nitiwiki --config ../contrib/nitiwiki/tests/wiki1/config2.ini --clean --render -v
index 70d5027..f93e9d7 100644 (file)
@@ -2,3 +2,4 @@ test_nitunit.nit --no-color -o $WRITE
 test_nitunit.nit --gen-suite --only-show
 test_nitunit.nit --gen-suite --only-show --private
 test_nitunit2.nit -o $WRITE
+test_doc2.nit --no-color -o $WRITE
index a64bbf0..b0818df 100644 (file)
@@ -1,5 +1,5 @@
-base_as_notnull2.nit:30,12--25: Warning: expression is already not null, since it is a `E: Object`.
-base_as_notnull2.nit:50,12--25: Warning: expression is already not null, since it is a `E: Object`.
+base_as_notnull2.nit:30,12--25: Warning: expression is already not null, since it is a `Object`.
+base_as_notnull2.nit:50,12--25: Warning: expression is already not null, since it is a `F: Object`.
 1
 1
 2
index a28e2e1..01ee624 100644 (file)
@@ -1,3 +1,3 @@
-alt/base_as_notnull2_alt1.nit:30,12--25: Warning: expression is already not null, since it is a `E: Object`.
-alt/base_as_notnull2_alt1.nit:50,12--25: Warning: expression is already not null, since it is a `E: Object`.
+alt/base_as_notnull2_alt1.nit:30,12--25: Warning: expression is already not null, since it is a `Object`.
+alt/base_as_notnull2_alt1.nit:50,12--25: Warning: expression is already not null, since it is a `F: Object`.
 alt/base_as_notnull2_alt1.nit:58,7--10: Type error: expected Object, got null
index ccaa594..e6335c5 100644 (file)
@@ -1,5 +1,5 @@
-alt/base_as_notnull2_alt2.nit:30,12--25: Warning: expression is already not null, since it is a `E: Object`.
-alt/base_as_notnull2_alt2.nit:50,12--25: Warning: expression is already not null, since it is a `E: Object`.
+alt/base_as_notnull2_alt2.nit:30,12--25: Warning: expression is already not null, since it is a `Object`.
+alt/base_as_notnull2_alt2.nit:50,12--25: Warning: expression is already not null, since it is a `F: Object`.
 Runtime error: Cast failed (alt/base_as_notnull2_alt2.nit:40)
 1
 1
index 7ce3a5b..4fb6e73 100644 (file)
@@ -1,3 +1,3 @@
-alt/base_as_notnull2_alt3.nit:30,12--25: Warning: expression is already not null, since it is a `E: Object`.
-alt/base_as_notnull2_alt3.nit:50,12--25: Warning: expression is already not null, since it is a `E: Object`.
+alt/base_as_notnull2_alt3.nit:30,12--25: Warning: expression is already not null, since it is a `Object`.
+alt/base_as_notnull2_alt3.nit:50,12--25: Warning: expression is already not null, since it is a `F: Object`.
 alt/base_as_notnull2_alt3.nit:64,7--10: Type error: expected Int, got null
diff --git a/tests/sav/base_formal_subtype.res b/tests/sav/base_formal_subtype.res
new file mode 100644 (file)
index 0000000..445a4fa
--- /dev/null
@@ -0,0 +1,30 @@
+base_formal_subtype.nit:48,10--21: Warning: Expression is already a Object.
+base_formal_subtype.nit:50,10--16: Warning: Expression is already a E.
+base_formal_subtype.nit:51,10--21: Warning: Expression is already a Object since it is a E.
+base_formal_subtype.nit:53,10--18: Warning: Expression is already a VE.
+base_formal_subtype.nit:54,10--17: Warning: Expression is already a E since it is a VE.
+base_formal_subtype.nit:55,10--22: Warning: Expression is already a Object since it is a VE.
+base_formal_subtype.nit:57,10--20: Warning: Expression is already a VVE.
+base_formal_subtype.nit:58,10--19: Warning: Expression is already a VE since it is a VVE.
+base_formal_subtype.nit:59,10--18: Warning: Expression is already a E since it is a VVE.
+base_formal_subtype.nit:60,10--23: Warning: Expression is already a Object since it is a VVE.
+base_formal_subtype.nit:62,10--20: Warning: Expression is already a VGE.
+base_formal_subtype.nit:63,10--20: Warning: Expression is already a G[E] since it is a VGE.
+base_formal_subtype.nit:64,10--25: Warning: Expression is already a G[Object] since it is a VGE.
+base_formal_subtype.nit:65,10--23: Warning: Expression is already a Object since it is a VGE.
+base_formal_subtype.nit:67,10--22: Warning: Expression is already a VVGE.
+base_formal_subtype.nit:68,10--21: Warning: Expression is already a VGE since it is a VVGE.
+base_formal_subtype.nit:69,10--21: Warning: Expression is already a G[E] since it is a VVGE.
+base_formal_subtype.nit:70,10--26: Warning: Expression is already a G[Object] since it is a VVGE.
+base_formal_subtype.nit:71,10--24: Warning: Expression is already a Object since it is a VVGE.
+base_formal_subtype.nit:73,10--22: Warning: Expression is already a VGVE.
+base_formal_subtype.nit:74,10--22: Warning: Expression is already a G[VE] since it is a VGVE.
+base_formal_subtype.nit:75,10--21: Warning: Expression is already a G[E] since it is a VGVE.
+base_formal_subtype.nit:76,10--26: Warning: Expression is already a G[Object] since it is a VGVE.
+base_formal_subtype.nit:77,10--24: Warning: Expression is already a Object since it is a VGVE.
+base_formal_subtype.nit:79,10--24: Warning: Expression is already a VGVVE.
+base_formal_subtype.nit:80,10--24: Warning: Expression is already a G[VVE] since it is a VGVVE.
+base_formal_subtype.nit:81,10--23: Warning: Expression is already a G[VE] since it is a VGVVE.
+base_formal_subtype.nit:82,10--22: Warning: Expression is already a G[E] since it is a VGVVE.
+base_formal_subtype.nit:83,10--27: Warning: Expression is already a G[Object] since it is a VGVVE.
+base_formal_subtype.nit:84,10--25: Warning: Expression is already a Object since it is a VGVVE.
index 4b49330..9ac131b 100644 (file)
@@ -1,2 +1,2 @@
-Runtime error: Cast failed. Expected `E`, got `B` (alt/base_gen_variance2_alt1.nit:27)
+Runtime error: Cast failed. Expected `F`, got `B` (alt/base_gen_variance2_alt1.nit:27)
 3
index 10f4ba7..27315ba 100644 (file)
@@ -1,2 +1,2 @@
-Runtime error: Cast failed. Expected `E`, got `D` (alt/base_gen_variance2_alt2.nit:27)
+Runtime error: Cast failed. Expected `F`, got `D` (alt/base_gen_variance2_alt2.nit:27)
 3
index f450e1f..c6eef59 100644 (file)
@@ -1,2 +1,2 @@
-Runtime error: Cast failed. Expected `E`, got `D` (alt/base_gen_variance3_alt1.nit:27)
+Runtime error: Cast failed. Expected `B`, got `D` (alt/base_gen_variance3_alt1.nit:27)
 2
index f912514..3c8702a 100644 (file)
@@ -1,2 +1,2 @@
-Runtime error: Cast failed. Expected `E`, got `Char` (alt/base_gen_variance_int_alt1.nit:27)
+Runtime error: Cast failed. Expected `Int`, got `Char` (alt/base_gen_variance_int_alt1.nit:27)
 2
diff --git a/tests/sav/base_self_type.res b/tests/sav/base_self_type.res
new file mode 100644 (file)
index 0000000..4c75853
--- /dev/null
@@ -0,0 +1,11 @@
+X
+X
+X
+Y
+Y
+Y
+Y
+A[Int]
+G[A[Int]]
+B[Bool]
+G[B[Bool]]
diff --git a/tests/sav/base_self_type_alt1.res b/tests/sav/base_self_type_alt1.res
new file mode 100644 (file)
index 0000000..467d315
--- /dev/null
@@ -0,0 +1 @@
+alt/base_self_type_alt1.nit:25,25--29: Type error: expected SELF, got X
diff --git a/tests/sav/base_self_type_alt2.res b/tests/sav/base_self_type_alt2.res
new file mode 100644 (file)
index 0000000..4c75853
--- /dev/null
@@ -0,0 +1,11 @@
+X
+X
+X
+Y
+Y
+Y
+Y
+A[Int]
+G[A[Int]]
+B[Bool]
+G[B[Bool]]
diff --git a/tests/sav/base_self_type_alt3.res b/tests/sav/base_self_type_alt3.res
new file mode 100644 (file)
index 0000000..78888be
--- /dev/null
@@ -0,0 +1 @@
+alt/base_self_type_alt3.nit:50,7: Type error: expected Y, got X
diff --git a/tests/sav/cocoa_extern_types.res b/tests/sav/cocoa_extern_types.res
new file mode 100644 (file)
index 0000000..4ad3dc3
--- /dev/null
@@ -0,0 +1 @@
+UNDEFINED
diff --git a/tests/sav/cocoa_message_box.res b/tests/sav/cocoa_message_box.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/sav/empty_program.res b/tests/sav/empty_program.res
new file mode 100644 (file)
index 0000000..e69de29
index 30a32a5..2a02c5e 100644 (file)
@@ -1 +1 @@
-../lib/standard/kernel.nit:79,1--95,3: Fatal error: kernel#Sys does not specialize module_0#Object. Possible duplication of the root class `Object`?
+../lib/standard/kernel.nit:101,1--117,3: Error: kernel#Sys does not specialize module_0#Object. Possible duplication of the root class `Object`?
index 6119ead..6c61f9f 100644 (file)
@@ -1 +1,2 @@
 alt/error_redef_alt3.nit:28,12--13: Error: No property B::f1 is inherited. Remove the redef keyword to define a new property.
+alt/error_redef_alt3.nit:28,15: Error: Untyped parameter `i'.
index 7c48f44..e509e47 100644 (file)
@@ -1 +1,2 @@
 alt/error_redef_alt6.nit:31,12--13: Error: No property B::f1 is inherited. Remove the redef keyword to define a new property.
+alt/error_redef_alt6.nit:31,15: Error: Untyped parameter `i'.
index 57dc2d2..ebb4401 100644 (file)
@@ -1 +1,2 @@
 alt/error_redef_alt9.nit:34,12--13: Error: No property B::f1 is inherited. Remove the redef keyword to define a new property.
+alt/error_redef_alt9.nit:34,15: Error: Untyped parameter `i'.
diff --git a/tests/sav/hailstone.res b/tests/sav/hailstone.res
new file mode 100644 (file)
index 0000000..0fb3d98
--- /dev/null
@@ -0,0 +1,2 @@
+Sequence for 27 has 112 begin with: 27, 82, 41, 124 and end with: 8, 4, 2, 1
+The number with longest sequence is 77031 with length of 351
diff --git a/tests/sav/hamming_number.res b/tests/sav/hamming_number.res
new file mode 100644 (file)
index 0000000..72c05b7
--- /dev/null
@@ -0,0 +1,21 @@
+1: 1
+2: 2
+3: 3
+4: 4
+5: 5
+6: 6
+7: 8
+8: 9
+9: 10
+10: 12
+11: 15
+12: 16
+13: 18
+14: 20
+15: 24
+16: 25
+17: 27
+18: 30
+19: 32
+20: 36
+1691: 2125764000
diff --git a/tests/sav/hello_cocoa.res b/tests/sav/hello_cocoa.res
new file mode 100644 (file)
index 0000000..4ad3dc3
--- /dev/null
@@ -0,0 +1 @@
+UNDEFINED
diff --git a/tests/sav/hello_world_text.res b/tests/sav/hello_world_text.res
new file mode 100644 (file)
index 0000000..f06c489
--- /dev/null
@@ -0,0 +1 @@
+Goodbye, World!
index 079146d..84ba2b7 100644 (file)
@@ -1,2 +1,2 @@
-<!DOCTYPE html><html><head><meta charset="utf-8"/><title>Nit</title><link rel="icon" href="http://nitlanguage.org/favicon.ico" type="image/x-icon"/><link rel="stylesheet" href="http://nitlanguage.org/style.css" type="text/css"/><link rel="stylesheet" href="http://nitlanguage.org/local.css" type="text/css"/></head><body><article class="page"><section class="pageheader"><a id='toptitle_first' class='toptitle'>the</a><a id='toptitle_second' class='toptitle' href=''>Nit</a><a id='toptitle_third' class='toptitle' href=''>Programming Language</a><header class="header"><div class="topsubtitle"><p>A Fun Language for Serious Programming</p></div></header></section><div id="pagebody"><section id="content"><h1># What is Nit?</h1><p>Nit is an object-oriented programming language. The goal of Nit is to propose a robust statically typed programming language where structure is not a pain.</p><p>So, what does the famous hello world program look like, in Nit?</p><pre><tt><span class='normal'>print </span><span class='string'>'Hello, World!'</span></tt></pre><h1># Feature Highlights</h1><h2>Usability</h2><p>Nit's goal is to be usable by real programmers for real projects</p><ul><li><a href="http://en.wikipedia.org/wiki/KISS_principle">KISS principle</a></li><li>Script-like language without verbosity nor cryptic statements</li><li>Painless static types: static typing should help programmers</li><li>Efficient development, efficient execution, efficient evolution.</li></ul><h2>Robustness</h2><p>Nit will help you to write bug-free programs</p><ul><li>Strong static typing</li><li>No more NullPointerException</li></ul><h2>Object-Oriented</h2><p>Nit's guideline is to follow the most powerful OO principles</p><ul><li><a href="./everything_is_an_object/">Everything is an object</a></li><li><a href="./multiple_inheritance/">Multiple inheritance</a></li><li><a href="./refinement/">Open classes</a></li><li><a href="./virtual_types/">Virtual types</a></li></ul><h1># Getting Started</h1><p>Get Nit from its Git repository:</p><pre><code>$ git clone http://nitlanguage.org/nit.git</code></pre><p>Build the compiler (may be long):</p><pre><code>$ cd nit
+<!DOCTYPE html><html><head><meta charset="utf-8"/><title>Nit</title><link rel="icon" href="http:&#47;&#47;nitlanguage.org&#47;favicon.ico" type="image&#47;x-icon"/><link rel="stylesheet" href="http:&#47;&#47;nitlanguage.org&#47;style.css" type="text&#47;css"/><link rel="stylesheet" href="http:&#47;&#47;nitlanguage.org&#47;local.css" type="text&#47;css"/></head><body><article class="page"><section class="pageheader"><a id='toptitle_first' class='toptitle'>the</a><a id='toptitle_second' class='toptitle' href=''>Nit</a><a id='toptitle_third' class='toptitle' href=''>Programming Language</a><header class="header"><div class="topsubtitle"><p>A Fun Language for Serious Programming</p></div></header></section><div id="pagebody"><section id="content"><h1># What is Nit?</h1><p>Nit is an object-oriented programming language. The goal of Nit is to propose a robust statically typed programming language where structure is not a pain.</p><p>So, what does the famous hello world program look like, in Nit?</p><pre><tt><span class='normal'>print </span><span class='string'>'Hello, World!'</span></tt></pre><h1># Feature Highlights</h1><h2>Usability</h2><p>Nit&#39;s goal is to be usable by real programmers for real projects</p><ul><li><a href="http:&#47;&#47;en.wikipedia.org&#47;wiki&#47;KISS_principle">KISS principle</a></li><li>Script-like language without verbosity nor cryptic statements</li><li>Painless static types: static typing should help programmers</li><li>Efficient development, efficient execution, efficient evolution.</li></ul><h2>Robustness</h2><p>Nit will help you to write bug-free programs</p><ul><li>Strong static typing</li><li>No more NullPointerException</li></ul><h2>Object-Oriented</h2><p>Nit&#39;s guideline is to follow the most powerful OO principles</p><ul><li><a href=".&#47;everything_is_an_object&#47;">Everything is an object</a></li><li><a href=".&#47;multiple_inheritance&#47;">Multiple inheritance</a></li><li><a href=".&#47;refinement&#47;">Open classes</a></li><li><a href=".&#47;virtual_types&#47;">Virtual types</a></li></ul><h1># Getting Started</h1><p>Get Nit from its Git repository:</p><pre><code>$ git clone http://nitlanguage.org/nit.git</code></pre><p>Build the compiler (may be long):</p><pre><code>$ cd nit
 $ make</code></pre><p>Compile a program:</p><pre><code>$ bin/nitc examples/hello_world.nit</code></pre><p>Execute the program:</p><pre><code>$ ./hello_world</code></pre></section></div></article></body></html>
\ No newline at end of file
diff --git a/tests/sav/neo_doxygen_dump.res b/tests/sav/neo_doxygen_dump.res
new file mode 100644 (file)
index 0000000..e043e01
--- /dev/null
@@ -0,0 +1,31 @@
+\e[1mNAME\e[m
+  %PROGRAM_NAME% — Doxygen XML to Neo4j.
+
+\e[1mSYNOPSIS\e[m
+  %PROGRAM_NAME% [--dest <url>] [--src-lang <lang>]
+    [--] <project_name> <doxml_dir>
+  %PROGRAM_NAME% [-h|--help]
+
+\e[1mDESCRIPTION\e[m
+  Convert a Doxygen XML output into a model in Neo4j that is readable by the
+  `nx` tool.
+
+\e[1mARGUMENTS\e[m
+  <project_name>  The internal name of the project. Must the same name as the
+                  one specified to the `nx` tool. Must not begin by an upper
+                  case letter.
+
+  <doxml_dir>     The directory where the XML documents generated by Doxygen are
+                  located.
+
+\e[1mOPTIONS\e[m
+
+  --dest       The URL of the destination graph. `http://localhost:7474` by
+               default.
+
+  -h, --help   Show the help (this page).
+
+  --src-lang   The programming language to assume when processing chunk in the
+               declarations left as-is by Doxygen. Use `any` (the default) to
+               disable any language-specific processing. <any, java>
+
diff --git a/tests/sav/neo_doxygen_dump_args1.res b/tests/sav/neo_doxygen_dump_args1.res
new file mode 100644 (file)
index 0000000..743b9a2
--- /dev/null
@@ -0,0 +1,51 @@
+Reading ../contrib/neo_doxygen/tests/empty-project/xml... Done.
+0 file read.
+Linking nodes...\e[s \e[u\e[J Done.
+Saving 2 nodes...
+---===DONE===---
+Saving 2 edges...
+Edge
+=type=4:ROOT
+=properties=JsonObject(0):
+{}
+----
+=from=Node
+=labels=Array(3):
+35:empty project with default settings
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"empty project with default settings"}
+----
+=to=Entity#0:
+=labels=Array(3):
+35:empty project with default settings
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"empty project with default settings"}
+
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+35:empty project with default settings
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"empty project with default settings"}
+----
+=to=Node
+=labels=Array(3):
+35:empty project with default settings
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"empty project with default settings"}
+
+
+---===DONE===---
diff --git a/tests/sav/neo_doxygen_dump_args2.res b/tests/sav/neo_doxygen_dump_args2.res
new file mode 100644 (file)
index 0000000..724e242
--- /dev/null
@@ -0,0 +1,51 @@
+Reading ../contrib/neo_doxygen/tests/empty-project/xml... Done.
+0 file read.
+Linking nodes...\e[s \e[u\e[J Done.
+Saving 2 nodes...
+---===DONE===---
+Saving 2 edges...
+Edge
+=type=4:ROOT
+=properties=JsonObject(0):
+{}
+----
+=from=Node
+=labels=Array(3):
+13:empty-project
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"empty-project"}
+----
+=to=Entity#0:
+=labels=Array(3):
+13:empty-project
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"empty-project"}
+
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+13:empty-project
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"empty-project"}
+----
+=to=Node
+=labels=Array(3):
+13:empty-project
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"empty-project"}
+
+
+---===DONE===---
diff --git a/tests/sav/neo_doxygen_dump_args3.res b/tests/sav/neo_doxygen_dump_args3.res
new file mode 100644 (file)
index 0000000..724e242
--- /dev/null
@@ -0,0 +1,51 @@
+Reading ../contrib/neo_doxygen/tests/empty-project/xml... Done.
+0 file read.
+Linking nodes...\e[s \e[u\e[J Done.
+Saving 2 nodes...
+---===DONE===---
+Saving 2 edges...
+Edge
+=type=4:ROOT
+=properties=JsonObject(0):
+{}
+----
+=from=Node
+=labels=Array(3):
+13:empty-project
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"empty-project"}
+----
+=to=Entity#0:
+=labels=Array(3):
+13:empty-project
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"empty-project"}
+
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+13:empty-project
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"empty-project"}
+----
+=to=Node
+=labels=Array(3):
+13:empty-project
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"empty-project"}
+
+
+---===DONE===---
diff --git a/tests/sav/neo_doxygen_dump_args4.res b/tests/sav/neo_doxygen_dump_args4.res
new file mode 100644 (file)
index 0000000..f44e8ea
--- /dev/null
@@ -0,0 +1,1951 @@
+Reading ../contrib/neo_doxygen/tests/java-project/xml... Done.
+15 files read.
+Linking nodes...\e[s \e[u\e[J Done.
+Saving 58 nodes...
+---===DONE===---
+Saving 85 edges...
+Edge
+=type=4:ROOT
+=properties=JsonObject(0):
+{}
+----
+=from=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#30:namespaceorg_1_1example_1_1foo
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example::foo","name":"foo","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:16,1--1,1"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:1,1--1,1","name":"A","full_name":"org::example::foo::A"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:1,1--1,1","name":"A","full_name":"org::example::foo::A"}
+----
+=to=Entity#32:classorg_1_1example_1_1foo_1_1_a
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(5):
+{"kind":"abstract class","visibility":"public","full_name":"org::example::foo::A","name":"A","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1"}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:1,1--1,1","name":"A","full_name":"org::example::foo::A"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1","is_intro":true,"name":"A","full_name":"org::example::foo::A"}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#30:namespaceorg_1_1example_1_1foo
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example::foo","name":"foo","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:16,1--1,1"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:1,1--1,1","name":"B","full_name":"org::example::foo::B"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:1,1--1,1","name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#32:classorg_1_1example_1_1foo_1_1_b
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(5):
+{"kind":"class","visibility":"public","full_name":"org::example::foo::B","name":"B","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1"}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:1,1--1,1","name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#30:namespaceorg_1_1example_1_1foo
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example::foo","name":"foo","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:16,1--1,1"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:1,1--1,1","name":"C","full_name":"org::example::foo::C"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:1,1--1,1","name":"C","full_name":"org::example::foo::C"}
+----
+=to=Entity#36:interfaceorg_1_1example_1_1foo_1_1_c
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"interface","visibility":"public","full_name":"org::example::foo::C","name":"C","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","mdoc":["An interface"]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:1,1--1,1","name":"C","full_name":"org::example::foo::C"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#30:namespaceorg_1_1example_1_1foo
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example::foo","name":"foo","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:16,1--1,1"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:1,1--1,1","name":"EmptyClass","full_name":"org::example::foo::EmptyClass"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:1,1--1,1","name":"EmptyClass","full_name":"org::example::foo::EmptyClass"}
+----
+=to=Entity#42:classorg_1_1example_1_1foo_1_1_empty_class
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"package","full_name":"org::example::foo::EmptyClass","name":"EmptyClass","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:21,1--21,1","mdoc":["This class is empty and is only visible in this package."]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:1,1--1,1","name":"EmptyClass","full_name":"org::example::foo::EmptyClass"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:21,1--21,1","is_intro":true,"name":"EmptyClass","full_name":"org::example::foo::EmptyClass","mdoc":["This class is empty and is only visible in this package."]}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":0,"name":"x"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["int"]}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":1,"name":"y"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["EmptyClass"]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#67:classorg_1_1example_1_1foo_1_1_a_1add415ae4129969055d678c7e7e048852
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:22,1--1,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"bar","mdoc":["Does something..."],"is_intro":true,"full_name":"org::example::foo::A::bar"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"bar","full_name":"org::example::foo::A::bar"}
+
+
+Edge
+=type=9:SIGNATURE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#67:classorg_1_1example_1_1foo_1_1_a_1add415ae4129969055d678c7e7e048852
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:22,1--1,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"bar","mdoc":["Does something..."],"is_intro":true,"full_name":"org::example::foo::A::bar"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(1):
+{"parameter_names":["x","y"]}
+
+
+Edge
+=type=9:PARAMETER
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(1):
+{"parameter_names":["x","y"]}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":0,"name":"x"}
+
+
+Edge
+=type=9:PARAMETER
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(1):
+{"parameter_names":["x","y"]}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":1,"name":"y"}
+
+
+Edge
+=type=10:RETURNTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(1):
+{"parameter_names":["x","y"]}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["abstract boolean"]}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":0,"name":"x"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["int"]}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":1,"name":"y"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["EmptyClass"]}
+
+
+Edge
+=type=9:CLASSTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#32:classorg_1_1example_1_1foo_1_1_a
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(5):
+{"kind":"abstract class","visibility":"public","full_name":"org::example::foo::A","name":"A","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"A","full_name":"org::example::foo::A"}
+
+
+Edge
+=type=5:CLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"A","full_name":"org::example::foo::A"}
+----
+=to=Entity#32:classorg_1_1example_1_1foo_1_1_a
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(5):
+{"kind":"abstract class","visibility":"public","full_name":"org::example::foo::A","name":"A","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1"}
+
+
+Edge
+=type=9:BOUNDTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1","is_intro":true,"name":"A","full_name":"org::example::foo::A"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"A","full_name":"org::example::foo::A"}
+
+
+Edge
+=type=6:MCLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1","is_intro":true,"name":"A","full_name":"org::example::foo::A"}
+----
+=to=Entity#32:classorg_1_1example_1_1foo_1_1_a
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(5):
+{"kind":"abstract class","visibility":"public","full_name":"org::example::foo::A","name":"A","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1","is_intro":true,"name":"A","full_name":"org::example::foo::A"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"bar","full_name":"org::example::foo::A::bar"}
+
+
+Edge
+=type=14:INTRO_CLASSDEF
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"bar","full_name":"org::example::foo::A::bar"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1","is_intro":true,"name":"A","full_name":"org::example::foo::A"}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1","is_intro":true,"name":"A","full_name":"org::example::foo::A"}
+----
+=to=Entity#67:classorg_1_1example_1_1foo_1_1_a_1add415ae4129969055d678c7e7e048852
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:22,1--1,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"bar","mdoc":["Does something..."],"is_intro":true,"full_name":"org::example::foo::A::bar"}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#67:classorg_1_1example_1_1foo_1_1_b_1ac6b627949b10b9357eefc0cafcae1d87
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+13:MAttributeDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:19,1---1,1","visibility":"protected","name":"qux","is_intro":true,"full_name":"org::example::foo::B::qux"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+10:MAttribute
+=properties=JsonObject(3):
+{"visibility":"protected","name":"qux","full_name":"org::example::foo::B::qux"}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#67:classorg_1_1example_1_1foo_1_1_b_1ac6b627949b10b9357eefc0cafcae1d87
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+13:MAttributeDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:19,1---1,1","visibility":"protected","name":"qux","is_intro":true,"full_name":"org::example::foo::B::qux"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["String"]}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":0,"name":"x"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["int"]}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":1,"name":"y"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["EmptyClass"]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#67:classorg_1_1example_1_1foo_1_1_b_1a11e157943665cc9e3a9be1502ebeb3b5
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(8):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:21,1--23,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"bar","is_intro":true,"full_name":"org::example::foo::B::bar"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"bar","full_name":"org::example::foo::B::bar"}
+
+
+Edge
+=type=9:SIGNATURE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#67:classorg_1_1example_1_1foo_1_1_b_1a11e157943665cc9e3a9be1502ebeb3b5
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(8):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:21,1--23,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"bar","is_intro":true,"full_name":"org::example::foo::B::bar"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(1):
+{"parameter_names":["x","y"]}
+
+
+Edge
+=type=9:PARAMETER
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(1):
+{"parameter_names":["x","y"]}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":0,"name":"x"}
+
+
+Edge
+=type=9:PARAMETER
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(1):
+{"parameter_names":["x","y"]}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":1,"name":"y"}
+
+
+Edge
+=type=10:RETURNTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(1):
+{"parameter_names":["x","y"]}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["boolean"]}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":0,"name":"x"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["int"]}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":1,"name":"y"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["EmptyClass"]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#67:classorg_1_1example_1_1foo_1_1_b_1a733f4e076f29c7d0c41ed258199ea1d9
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:28,1--28,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"baz","mdoc":["Some overriden documentation."],"is_intro":false,"full_name":"org::example::foo::B::baz"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"baz","full_name":"org::example::foo::C::baz"}
+
+
+Edge
+=type=9:SIGNATURE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#67:classorg_1_1example_1_1foo_1_1_b_1a733f4e076f29c7d0c41ed258199ea1d9
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:28,1--28,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"baz","mdoc":["Some overriden documentation."],"is_intro":false,"full_name":"org::example::foo::B::baz"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(0):
+{}
+
+
+Edge
+=type=10:RETURNTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(0):
+{}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["void"]}
+
+
+Edge
+=type=9:CLASSTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#32:classorg_1_1example_1_1foo_1_1_b
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(5):
+{"kind":"class","visibility":"public","full_name":"org::example::foo::B","name":"B","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"B","full_name":"org::example::foo::B"}
+
+
+Edge
+=type=5:CLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#32:classorg_1_1example_1_1foo_1_1_b
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(5):
+{"kind":"class","visibility":"public","full_name":"org::example::foo::B","name":"B","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1"}
+
+
+Edge
+=type=9:BOUNDTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"B","full_name":"org::example::foo::B"}
+
+
+Edge
+=type=6:MCLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#32:classorg_1_1example_1_1foo_1_1_b
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(5):
+{"kind":"class","visibility":"public","full_name":"org::example::foo::B","name":"B","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1"}
+
+
+Edge
+=type=8:INHERITS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"A","full_name":"org::example::foo::A"}
+
+
+Edge
+=type=8:INHERITS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"C","full_name":"org::example::foo::C"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+10:MAttribute
+=properties=JsonObject(3):
+{"visibility":"protected","name":"qux","full_name":"org::example::foo::B::qux"}
+
+
+Edge
+=type=14:INTRO_CLASSDEF
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+10:MAttribute
+=properties=JsonObject(3):
+{"visibility":"protected","name":"qux","full_name":"org::example::foo::B::qux"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#67:classorg_1_1example_1_1foo_1_1_b_1ac6b627949b10b9357eefc0cafcae1d87
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+13:MAttributeDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:19,1---1,1","visibility":"protected","name":"qux","is_intro":true,"full_name":"org::example::foo::B::qux"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"bar","full_name":"org::example::foo::B::bar"}
+
+
+Edge
+=type=14:INTRO_CLASSDEF
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"bar","full_name":"org::example::foo::B::bar"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#67:classorg_1_1example_1_1foo_1_1_b_1a11e157943665cc9e3a9be1502ebeb3b5
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(8):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:21,1--23,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"bar","is_intro":true,"full_name":"org::example::foo::B::bar"}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#67:classorg_1_1example_1_1foo_1_1_b_1a733f4e076f29c7d0c41ed258199ea1d9
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:28,1--28,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"baz","mdoc":["Some overriden documentation."],"is_intro":false,"full_name":"org::example::foo::B::baz"}
+
+
+Edge
+=type=9:CLASSTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#42:classorg_1_1example_1_1foo_1_1_empty_class
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"package","full_name":"org::example::foo::EmptyClass","name":"EmptyClass","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:21,1--21,1","mdoc":["This class is empty and is only visible in this package."]}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"EmptyClass","full_name":"org::example::foo::EmptyClass"}
+
+
+Edge
+=type=5:CLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"EmptyClass","full_name":"org::example::foo::EmptyClass"}
+----
+=to=Entity#42:classorg_1_1example_1_1foo_1_1_empty_class
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"package","full_name":"org::example::foo::EmptyClass","name":"EmptyClass","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:21,1--21,1","mdoc":["This class is empty and is only visible in this package."]}
+
+
+Edge
+=type=9:BOUNDTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:21,1--21,1","is_intro":true,"name":"EmptyClass","full_name":"org::example::foo::EmptyClass","mdoc":["This class is empty and is only visible in this package."]}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"EmptyClass","full_name":"org::example::foo::EmptyClass"}
+
+
+Edge
+=type=6:MCLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:21,1--21,1","is_intro":true,"name":"EmptyClass","full_name":"org::example::foo::EmptyClass","mdoc":["This class is empty and is only visible in this package."]}
+----
+=to=Entity#42:classorg_1_1example_1_1foo_1_1_empty_class
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"package","full_name":"org::example::foo::EmptyClass","name":"EmptyClass","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:21,1--21,1","mdoc":["This class is empty and is only visible in this package."]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#71:interfaceorg_1_1example_1_1foo_1_1_c_1a4e97061eb40b045e820de05b33c43d21
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+13:MAttributeDef
+=properties=JsonObject(6):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["\u000e2\u00080\u0009cAnswer to the Ultimate Question of Life, the Universe, and Everything.\u000e2\u00080\u0009c"],"is_intro":true,"full_name":"org::example::foo::C::THE_ANSWER"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+10:MAttribute
+=properties=JsonObject(3):
+{"visibility":"public","name":"THE_ANSWER","full_name":"org::example::foo::C::THE_ANSWER"}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#71:interfaceorg_1_1example_1_1foo_1_1_c_1a4e97061eb40b045e820de05b33c43d21
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+13:MAttributeDef
+=properties=JsonObject(6):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["\u000e2\u00080\u0009cAnswer to the Ultimate Question of Life, the Universe, and Everything.\u000e2\u00080\u0009c"],"is_intro":true,"full_name":"org::example::foo::C::THE_ANSWER"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["final long"]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#71:interfaceorg_1_1example_1_1foo_1_1_c_1a28ac7ce349ebb3e4a7747a8dd951582b
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:30,1--1,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"baz","mdoc":["A function with implicit modifiers."],"is_intro":true,"full_name":"org::example::foo::C::baz"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"baz","full_name":"org::example::foo::C::baz"}
+
+
+Edge
+=type=9:SIGNATURE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#71:interfaceorg_1_1example_1_1foo_1_1_c_1a28ac7ce349ebb3e4a7747a8dd951582b
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:30,1--1,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"baz","mdoc":["A function with implicit modifiers."],"is_intro":true,"full_name":"org::example::foo::C::baz"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(0):
+{}
+
+
+Edge
+=type=10:RETURNTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(0):
+{}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["void"]}
+
+
+Edge
+=type=9:CLASSTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#36:interfaceorg_1_1example_1_1foo_1_1_c
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"interface","visibility":"public","full_name":"org::example::foo::C","name":"C","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","mdoc":["An interface"]}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"C","full_name":"org::example::foo::C"}
+
+
+Edge
+=type=5:CLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"C","full_name":"org::example::foo::C"}
+----
+=to=Entity#36:interfaceorg_1_1example_1_1foo_1_1_c
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"interface","visibility":"public","full_name":"org::example::foo::C","name":"C","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","mdoc":["An interface"]}
+
+
+Edge
+=type=9:BOUNDTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"C","full_name":"org::example::foo::C"}
+
+
+Edge
+=type=6:MCLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+----
+=to=Entity#36:interfaceorg_1_1example_1_1foo_1_1_c
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"interface","visibility":"public","full_name":"org::example::foo::C","name":"C","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","mdoc":["An interface"]}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+10:MAttribute
+=properties=JsonObject(3):
+{"visibility":"public","name":"THE_ANSWER","full_name":"org::example::foo::C::THE_ANSWER"}
+
+
+Edge
+=type=14:INTRO_CLASSDEF
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+10:MAttribute
+=properties=JsonObject(3):
+{"visibility":"public","name":"THE_ANSWER","full_name":"org::example::foo::C::THE_ANSWER"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+----
+=to=Entity#71:interfaceorg_1_1example_1_1foo_1_1_c_1a4e97061eb40b045e820de05b33c43d21
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+13:MAttributeDef
+=properties=JsonObject(6):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["\u000e2\u00080\u0009cAnswer to the Ultimate Question of Life, the Universe, and Everything.\u000e2\u00080\u0009c"],"is_intro":true,"full_name":"org::example::foo::C::THE_ANSWER"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"baz","full_name":"org::example::foo::C::baz"}
+
+
+Edge
+=type=14:INTRO_CLASSDEF
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"baz","full_name":"org::example::foo::C::baz"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+----
+=to=Entity#71:interfaceorg_1_1example_1_1foo_1_1_c_1a28ac7ce349ebb3e4a7747a8dd951582b
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:30,1--1,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"baz","mdoc":["A function with implicit modifiers."],"is_intro":true,"full_name":"org::example::foo::C::baz"}
+
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#12:namespaceorg
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org","name":"org","location":"\/dev\/null:1,1--1,1"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+
+Edge
+=type=6:PARENT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#12:namespaceorg
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org","name":"org","location":"\/dev\/null:1,1--1,1"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+
+
+Edge
+=type=5:NESTS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+----
+=to=Entity#12:namespaceorg
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org","name":"org","location":"\/dev\/null:1,1--1,1"}
+
+
+Edge
+=type=6:PARENT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#23:namespaceorg_1_1example
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example","name":"example","location":"\/dev\/null:1,1--1,1"}
+----
+=to=Entity#12:namespaceorg
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org","name":"org","location":"\/dev\/null:1,1--1,1"}
+
+
+Edge
+=type=5:NESTS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#12:namespaceorg
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org","name":"org","location":"\/dev\/null:1,1--1,1"}
+----
+=to=Entity#23:namespaceorg_1_1example
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example","name":"example","location":"\/dev\/null:1,1--1,1"}
+
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#23:namespaceorg_1_1example
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example","name":"example","location":"\/dev\/null:1,1--1,1"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+
+Edge
+=type=6:PARENT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#30:namespaceorg_1_1example_1_1foo
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example::foo","name":"foo","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:16,1--1,1"}
+----
+=to=Entity#23:namespaceorg_1_1example
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example","name":"example","location":"\/dev\/null:1,1--1,1"}
+
+
+Edge
+=type=5:NESTS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#23:namespaceorg_1_1example
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example","name":"example","location":"\/dev\/null:1,1--1,1"}
+----
+=to=Entity#30:namespaceorg_1_1example_1_1foo
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example::foo","name":"foo","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:16,1--1,1"}
+
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#30:namespaceorg_1_1example_1_1foo
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example::foo","name":"foo","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:16,1--1,1"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+
+---===DONE===---
diff --git a/tests/sav/neo_doxygen_dump_args5.res b/tests/sav/neo_doxygen_dump_args5.res
new file mode 100644 (file)
index 0000000..ae6cb05
--- /dev/null
@@ -0,0 +1,1951 @@
+Reading ../contrib/neo_doxygen/tests/java-project/xml... Done.
+15 files read.
+Linking nodes...\e[s \e[u\e[J Done.
+Saving 58 nodes...
+---===DONE===---
+Saving 85 edges...
+Edge
+=type=4:ROOT
+=properties=JsonObject(0):
+{}
+----
+=from=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#30:namespaceorg_1_1example_1_1foo
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example::foo","name":"foo","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:16,1--1,1"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:1,1--1,1","name":"A","full_name":"org::example::foo::A"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:1,1--1,1","name":"A","full_name":"org::example::foo::A"}
+----
+=to=Entity#32:classorg_1_1example_1_1foo_1_1_a
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(5):
+{"kind":"abstract class","visibility":"public","full_name":"org::example::foo::A","name":"A","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1"}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:1,1--1,1","name":"A","full_name":"org::example::foo::A"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1","is_intro":true,"name":"A","full_name":"org::example::foo::A"}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#30:namespaceorg_1_1example_1_1foo
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example::foo","name":"foo","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:16,1--1,1"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:1,1--1,1","name":"B","full_name":"org::example::foo::B"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:1,1--1,1","name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#32:classorg_1_1example_1_1foo_1_1_b
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(5):
+{"kind":"class","visibility":"public","full_name":"org::example::foo::B","name":"B","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1"}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:1,1--1,1","name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#30:namespaceorg_1_1example_1_1foo
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example::foo","name":"foo","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:16,1--1,1"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:1,1--1,1","name":"C","full_name":"org::example::foo::C"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:1,1--1,1","name":"C","full_name":"org::example::foo::C"}
+----
+=to=Entity#36:interfaceorg_1_1example_1_1foo_1_1_c
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"interface","visibility":"public","full_name":"org::example::foo::C","name":"C","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","mdoc":["An interface"]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:1,1--1,1","name":"C","full_name":"org::example::foo::C"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#30:namespaceorg_1_1example_1_1foo
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example::foo","name":"foo","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:16,1--1,1"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:1,1--1,1","name":"EmptyClass","full_name":"org::example::foo::EmptyClass"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:1,1--1,1","name":"EmptyClass","full_name":"org::example::foo::EmptyClass"}
+----
+=to=Entity#42:classorg_1_1example_1_1foo_1_1_empty_class
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"package","full_name":"org::example::foo::EmptyClass","name":"EmptyClass","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:21,1--21,1","mdoc":["This class is empty and is only visible in this package."]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:1,1--1,1","name":"EmptyClass","full_name":"org::example::foo::EmptyClass"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:21,1--21,1","is_intro":true,"name":"EmptyClass","full_name":"org::example::foo::EmptyClass","mdoc":["This class is empty and is only visible in this package."]}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":0,"name":"x"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["int"]}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":1,"name":"y"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["EmptyClass"]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#67:classorg_1_1example_1_1foo_1_1_a_1add415ae4129969055d678c7e7e048852
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:22,1--1,1","is_intern":false,"is_extern":false,"is_abstract":true,"visibility":"public","name":"bar","mdoc":["Does something..."],"is_intro":true,"full_name":"org::example::foo::A::bar"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"bar","full_name":"org::example::foo::A::bar"}
+
+
+Edge
+=type=9:SIGNATURE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#67:classorg_1_1example_1_1foo_1_1_a_1add415ae4129969055d678c7e7e048852
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:22,1--1,1","is_intern":false,"is_extern":false,"is_abstract":true,"visibility":"public","name":"bar","mdoc":["Does something..."],"is_intro":true,"full_name":"org::example::foo::A::bar"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(1):
+{"parameter_names":["x","y"]}
+
+
+Edge
+=type=9:PARAMETER
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(1):
+{"parameter_names":["x","y"]}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":0,"name":"x"}
+
+
+Edge
+=type=9:PARAMETER
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(1):
+{"parameter_names":["x","y"]}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":1,"name":"y"}
+
+
+Edge
+=type=10:RETURNTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(1):
+{"parameter_names":["x","y"]}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["boolean"]}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":0,"name":"x"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["int"]}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":1,"name":"y"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["EmptyClass"]}
+
+
+Edge
+=type=9:CLASSTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#32:classorg_1_1example_1_1foo_1_1_a
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(5):
+{"kind":"abstract class","visibility":"public","full_name":"org::example::foo::A","name":"A","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"A","full_name":"org::example::foo::A"}
+
+
+Edge
+=type=5:CLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"A","full_name":"org::example::foo::A"}
+----
+=to=Entity#32:classorg_1_1example_1_1foo_1_1_a
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(5):
+{"kind":"abstract class","visibility":"public","full_name":"org::example::foo::A","name":"A","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1"}
+
+
+Edge
+=type=9:BOUNDTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1","is_intro":true,"name":"A","full_name":"org::example::foo::A"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"A","full_name":"org::example::foo::A"}
+
+
+Edge
+=type=6:MCLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1","is_intro":true,"name":"A","full_name":"org::example::foo::A"}
+----
+=to=Entity#32:classorg_1_1example_1_1foo_1_1_a
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(5):
+{"kind":"abstract class","visibility":"public","full_name":"org::example::foo::A","name":"A","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1","is_intro":true,"name":"A","full_name":"org::example::foo::A"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"bar","full_name":"org::example::foo::A::bar"}
+
+
+Edge
+=type=14:INTRO_CLASSDEF
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"bar","full_name":"org::example::foo::A::bar"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1","is_intro":true,"name":"A","full_name":"org::example::foo::A"}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1","is_intro":true,"name":"A","full_name":"org::example::foo::A"}
+----
+=to=Entity#67:classorg_1_1example_1_1foo_1_1_a_1add415ae4129969055d678c7e7e048852
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:22,1--1,1","is_intern":false,"is_extern":false,"is_abstract":true,"visibility":"public","name":"bar","mdoc":["Does something..."],"is_intro":true,"full_name":"org::example::foo::A::bar"}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#67:classorg_1_1example_1_1foo_1_1_b_1ac6b627949b10b9357eefc0cafcae1d87
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+13:MAttributeDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:19,1---1,1","visibility":"protected","name":"qux","is_intro":true,"full_name":"org::example::foo::B::qux"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+10:MAttribute
+=properties=JsonObject(3):
+{"visibility":"protected","name":"qux","full_name":"org::example::foo::B::qux"}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#67:classorg_1_1example_1_1foo_1_1_b_1ac6b627949b10b9357eefc0cafcae1d87
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+13:MAttributeDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:19,1---1,1","visibility":"protected","name":"qux","is_intro":true,"full_name":"org::example::foo::B::qux"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["String"]}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":0,"name":"x"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["int"]}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":1,"name":"y"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["EmptyClass"]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#67:classorg_1_1example_1_1foo_1_1_b_1a11e157943665cc9e3a9be1502ebeb3b5
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(8):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:21,1--23,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"bar","is_intro":true,"full_name":"org::example::foo::B::bar"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"bar","full_name":"org::example::foo::B::bar"}
+
+
+Edge
+=type=9:SIGNATURE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#67:classorg_1_1example_1_1foo_1_1_b_1a11e157943665cc9e3a9be1502ebeb3b5
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(8):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:21,1--23,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"bar","is_intro":true,"full_name":"org::example::foo::B::bar"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(1):
+{"parameter_names":["x","y"]}
+
+
+Edge
+=type=9:PARAMETER
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(1):
+{"parameter_names":["x","y"]}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":0,"name":"x"}
+
+
+Edge
+=type=9:PARAMETER
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(1):
+{"parameter_names":["x","y"]}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":1,"name":"y"}
+
+
+Edge
+=type=10:RETURNTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(1):
+{"parameter_names":["x","y"]}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["boolean"]}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":0,"name":"x"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["int"]}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":1,"name":"y"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["EmptyClass"]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#67:classorg_1_1example_1_1foo_1_1_b_1a733f4e076f29c7d0c41ed258199ea1d9
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:28,1--28,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"baz","mdoc":["Some overriden documentation."],"is_intro":false,"full_name":"org::example::foo::B::baz"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"baz","full_name":"org::example::foo::C::baz"}
+
+
+Edge
+=type=9:SIGNATURE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#67:classorg_1_1example_1_1foo_1_1_b_1a733f4e076f29c7d0c41ed258199ea1d9
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:28,1--28,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"baz","mdoc":["Some overriden documentation."],"is_intro":false,"full_name":"org::example::foo::B::baz"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(0):
+{}
+
+
+Edge
+=type=10:RETURNTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(0):
+{}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["void"]}
+
+
+Edge
+=type=9:CLASSTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#32:classorg_1_1example_1_1foo_1_1_b
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(5):
+{"kind":"class","visibility":"public","full_name":"org::example::foo::B","name":"B","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"B","full_name":"org::example::foo::B"}
+
+
+Edge
+=type=5:CLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#32:classorg_1_1example_1_1foo_1_1_b
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(5):
+{"kind":"class","visibility":"public","full_name":"org::example::foo::B","name":"B","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1"}
+
+
+Edge
+=type=9:BOUNDTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"B","full_name":"org::example::foo::B"}
+
+
+Edge
+=type=6:MCLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#32:classorg_1_1example_1_1foo_1_1_b
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(5):
+{"kind":"class","visibility":"public","full_name":"org::example::foo::B","name":"B","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1"}
+
+
+Edge
+=type=8:INHERITS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"A","full_name":"org::example::foo::A"}
+
+
+Edge
+=type=8:INHERITS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"C","full_name":"org::example::foo::C"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+10:MAttribute
+=properties=JsonObject(3):
+{"visibility":"protected","name":"qux","full_name":"org::example::foo::B::qux"}
+
+
+Edge
+=type=14:INTRO_CLASSDEF
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+10:MAttribute
+=properties=JsonObject(3):
+{"visibility":"protected","name":"qux","full_name":"org::example::foo::B::qux"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#67:classorg_1_1example_1_1foo_1_1_b_1ac6b627949b10b9357eefc0cafcae1d87
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+13:MAttributeDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:19,1---1,1","visibility":"protected","name":"qux","is_intro":true,"full_name":"org::example::foo::B::qux"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"bar","full_name":"org::example::foo::B::bar"}
+
+
+Edge
+=type=14:INTRO_CLASSDEF
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"bar","full_name":"org::example::foo::B::bar"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#67:classorg_1_1example_1_1foo_1_1_b_1a11e157943665cc9e3a9be1502ebeb3b5
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(8):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:21,1--23,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"bar","is_intro":true,"full_name":"org::example::foo::B::bar"}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#67:classorg_1_1example_1_1foo_1_1_b_1a733f4e076f29c7d0c41ed258199ea1d9
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:28,1--28,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"baz","mdoc":["Some overriden documentation."],"is_intro":false,"full_name":"org::example::foo::B::baz"}
+
+
+Edge
+=type=9:CLASSTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#42:classorg_1_1example_1_1foo_1_1_empty_class
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"package","full_name":"org::example::foo::EmptyClass","name":"EmptyClass","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:21,1--21,1","mdoc":["This class is empty and is only visible in this package."]}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"EmptyClass","full_name":"org::example::foo::EmptyClass"}
+
+
+Edge
+=type=5:CLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"EmptyClass","full_name":"org::example::foo::EmptyClass"}
+----
+=to=Entity#42:classorg_1_1example_1_1foo_1_1_empty_class
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"package","full_name":"org::example::foo::EmptyClass","name":"EmptyClass","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:21,1--21,1","mdoc":["This class is empty and is only visible in this package."]}
+
+
+Edge
+=type=9:BOUNDTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:21,1--21,1","is_intro":true,"name":"EmptyClass","full_name":"org::example::foo::EmptyClass","mdoc":["This class is empty and is only visible in this package."]}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"EmptyClass","full_name":"org::example::foo::EmptyClass"}
+
+
+Edge
+=type=6:MCLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:21,1--21,1","is_intro":true,"name":"EmptyClass","full_name":"org::example::foo::EmptyClass","mdoc":["This class is empty and is only visible in this package."]}
+----
+=to=Entity#42:classorg_1_1example_1_1foo_1_1_empty_class
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"package","full_name":"org::example::foo::EmptyClass","name":"EmptyClass","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:21,1--21,1","mdoc":["This class is empty and is only visible in this package."]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#71:interfaceorg_1_1example_1_1foo_1_1_c_1a4e97061eb40b045e820de05b33c43d21
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+13:MAttributeDef
+=properties=JsonObject(6):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["\u000e2\u00080\u0009cAnswer to the Ultimate Question of Life, the Universe, and Everything.\u000e2\u00080\u0009c"],"is_intro":true,"full_name":"org::example::foo::C::THE_ANSWER"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+10:MAttribute
+=properties=JsonObject(3):
+{"visibility":"public","name":"THE_ANSWER","full_name":"org::example::foo::C::THE_ANSWER"}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#71:interfaceorg_1_1example_1_1foo_1_1_c_1a4e97061eb40b045e820de05b33c43d21
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+13:MAttributeDef
+=properties=JsonObject(6):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["\u000e2\u00080\u0009cAnswer to the Ultimate Question of Life, the Universe, and Everything.\u000e2\u00080\u0009c"],"is_intro":true,"full_name":"org::example::foo::C::THE_ANSWER"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["final long"]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#71:interfaceorg_1_1example_1_1foo_1_1_c_1a28ac7ce349ebb3e4a7747a8dd951582b
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:30,1--1,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"baz","mdoc":["A function with implicit modifiers."],"is_intro":true,"full_name":"org::example::foo::C::baz"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"baz","full_name":"org::example::foo::C::baz"}
+
+
+Edge
+=type=9:SIGNATURE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#71:interfaceorg_1_1example_1_1foo_1_1_c_1a28ac7ce349ebb3e4a7747a8dd951582b
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:30,1--1,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"baz","mdoc":["A function with implicit modifiers."],"is_intro":true,"full_name":"org::example::foo::C::baz"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(0):
+{}
+
+
+Edge
+=type=10:RETURNTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(0):
+{}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["void"]}
+
+
+Edge
+=type=9:CLASSTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#36:interfaceorg_1_1example_1_1foo_1_1_c
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"interface","visibility":"public","full_name":"org::example::foo::C","name":"C","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","mdoc":["An interface"]}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"C","full_name":"org::example::foo::C"}
+
+
+Edge
+=type=5:CLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"C","full_name":"org::example::foo::C"}
+----
+=to=Entity#36:interfaceorg_1_1example_1_1foo_1_1_c
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"interface","visibility":"public","full_name":"org::example::foo::C","name":"C","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","mdoc":["An interface"]}
+
+
+Edge
+=type=9:BOUNDTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"C","full_name":"org::example::foo::C"}
+
+
+Edge
+=type=6:MCLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+----
+=to=Entity#36:interfaceorg_1_1example_1_1foo_1_1_c
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"interface","visibility":"public","full_name":"org::example::foo::C","name":"C","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","mdoc":["An interface"]}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+10:MAttribute
+=properties=JsonObject(3):
+{"visibility":"public","name":"THE_ANSWER","full_name":"org::example::foo::C::THE_ANSWER"}
+
+
+Edge
+=type=14:INTRO_CLASSDEF
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+10:MAttribute
+=properties=JsonObject(3):
+{"visibility":"public","name":"THE_ANSWER","full_name":"org::example::foo::C::THE_ANSWER"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+----
+=to=Entity#71:interfaceorg_1_1example_1_1foo_1_1_c_1a4e97061eb40b045e820de05b33c43d21
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+13:MAttributeDef
+=properties=JsonObject(6):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["\u000e2\u00080\u0009cAnswer to the Ultimate Question of Life, the Universe, and Everything.\u000e2\u00080\u0009c"],"is_intro":true,"full_name":"org::example::foo::C::THE_ANSWER"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"baz","full_name":"org::example::foo::C::baz"}
+
+
+Edge
+=type=14:INTRO_CLASSDEF
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"baz","full_name":"org::example::foo::C::baz"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+----
+=to=Entity#71:interfaceorg_1_1example_1_1foo_1_1_c_1a28ac7ce349ebb3e4a7747a8dd951582b
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:30,1--1,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"baz","mdoc":["A function with implicit modifiers."],"is_intro":true,"full_name":"org::example::foo::C::baz"}
+
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#12:namespaceorg
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org","name":"org","location":"\/dev\/null:1,1--1,1"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+
+Edge
+=type=6:PARENT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#12:namespaceorg
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org","name":"org","location":"\/dev\/null:1,1--1,1"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+
+
+Edge
+=type=5:NESTS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+----
+=to=Entity#12:namespaceorg
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org","name":"org","location":"\/dev\/null:1,1--1,1"}
+
+
+Edge
+=type=6:PARENT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#23:namespaceorg_1_1example
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example","name":"example","location":"\/dev\/null:1,1--1,1"}
+----
+=to=Entity#12:namespaceorg
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org","name":"org","location":"\/dev\/null:1,1--1,1"}
+
+
+Edge
+=type=5:NESTS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#12:namespaceorg
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org","name":"org","location":"\/dev\/null:1,1--1,1"}
+----
+=to=Entity#23:namespaceorg_1_1example
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example","name":"example","location":"\/dev\/null:1,1--1,1"}
+
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#23:namespaceorg_1_1example
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example","name":"example","location":"\/dev\/null:1,1--1,1"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+
+Edge
+=type=6:PARENT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#30:namespaceorg_1_1example_1_1foo
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example::foo","name":"foo","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:16,1--1,1"}
+----
+=to=Entity#23:namespaceorg_1_1example
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example","name":"example","location":"\/dev\/null:1,1--1,1"}
+
+
+Edge
+=type=5:NESTS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#23:namespaceorg_1_1example
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example","name":"example","location":"\/dev\/null:1,1--1,1"}
+----
+=to=Entity#30:namespaceorg_1_1example_1_1foo
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example::foo","name":"foo","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:16,1--1,1"}
+
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#30:namespaceorg_1_1example_1_1foo
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example::foo","name":"foo","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:16,1--1,1"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+
+---===DONE===---
diff --git a/tests/sav/neo_doxygen_dump_args6.res b/tests/sav/neo_doxygen_dump_args6.res
new file mode 100644 (file)
index 0000000..65d20ff
--- /dev/null
@@ -0,0 +1,208 @@
+Reading ../contrib/neo_doxygen/tests/root-namespace/xml... Done.
+3 files read.
+Linking nodes...\e[s \e[u\e[J Done.
+Saving 6 nodes...
+---===DONE===---
+Saving 9 edges...
+Edge
+=type=4:ROOT
+=properties=JsonObject(0):
+{}
+----
+=from=Node
+=labels=Array(3):
+14:root-namespace
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"root-namespace"}
+----
+=to=Entity#0:
+=labels=Array(3):
+14:root-namespace
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"root-namespace"}
+
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+14:root-namespace
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"root-namespace"}
+----
+=to=Node
+=labels=Array(3):
+14:root-namespace
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"root-namespace"}
+
+
+Edge
+=type=9:CLASSTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#9:class_foo
+=labels=Array(3):
+14:root-namespace
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"package","full_name":"Foo","name":"Foo","location":"%SOURCE_DIRECTORY%\/Foo.java:19,1--19,1","mdoc":["A class in the root namespace"]}
+----
+=to=Entity#0:
+=labels=Array(4):
+14:root-namespace
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"Foo","full_name":"Foo"}
+
+
+Edge
+=type=5:CLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+14:root-namespace
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"Foo","full_name":"Foo"}
+----
+=to=Entity#9:class_foo
+=labels=Array(3):
+14:root-namespace
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"package","full_name":"Foo","name":"Foo","location":"%SOURCE_DIRECTORY%\/Foo.java:19,1--19,1","mdoc":["A class in the root namespace"]}
+
+
+Edge
+=type=9:BOUNDTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+14:root-namespace
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/Foo.java:19,1--19,1","is_intro":true,"name":"Foo","full_name":"Foo","mdoc":["A class in the root namespace"]}
+----
+=to=Entity#0:
+=labels=Array(4):
+14:root-namespace
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"Foo","full_name":"Foo"}
+
+
+Edge
+=type=6:MCLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+14:root-namespace
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/Foo.java:19,1--19,1","is_intro":true,"name":"Foo","full_name":"Foo","mdoc":["A class in the root namespace"]}
+----
+=to=Entity#9:class_foo
+=labels=Array(3):
+14:root-namespace
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"package","full_name":"Foo","name":"Foo","location":"%SOURCE_DIRECTORY%\/Foo.java:19,1--19,1","mdoc":["A class in the root namespace"]}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+14:root-namespace
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"root-namespace"}
+----
+=to=Entity#0:
+=labels=Array(3):
+14:root-namespace
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/Foo.java:1,1--1,1","name":"Foo","full_name":"Foo"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+14:root-namespace
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/Foo.java:1,1--1,1","name":"Foo","full_name":"Foo"}
+----
+=to=Entity#9:class_foo
+=labels=Array(3):
+14:root-namespace
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"package","full_name":"Foo","name":"Foo","location":"%SOURCE_DIRECTORY%\/Foo.java:19,1--19,1","mdoc":["A class in the root namespace"]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+14:root-namespace
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/Foo.java:1,1--1,1","name":"Foo","full_name":"Foo"}
+----
+=to=Entity#0:
+=labels=Array(3):
+14:root-namespace
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/Foo.java:19,1--19,1","is_intro":true,"name":"Foo","full_name":"Foo","mdoc":["A class in the root namespace"]}
+
+
+---===DONE===---
diff --git a/tests/sav/neo_doxygen_dump_args7.res b/tests/sav/neo_doxygen_dump_args7.res
new file mode 100644 (file)
index 0000000..308f58a
--- /dev/null
@@ -0,0 +1,482 @@
+Reading ../contrib/neo_doxygen/tests/inner-class/xml... Done.
+4 files read.
+Linking nodes...\e[s \e[u\e[J Done.
+Saving 11 nodes...
+---===DONE===---
+Saving 21 edges...
+Edge
+=type=4:ROOT
+=properties=JsonObject(0):
+{}
+----
+=from=Node
+=labels=Array(3):
+11:inner-class
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"inner-class"}
+----
+=to=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"inner-class"}
+
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"inner-class"}
+----
+=to=Node
+=labels=Array(3):
+11:inner-class
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"inner-class"}
+
+
+Edge
+=type=9:CLASSTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#17:class_outer_class
+=labels=Array(3):
+11:inner-class
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"public","full_name":"OuterClass","name":"OuterClass","location":"%SOURCE_DIRECTORY%\/OuterClass.java:19,1--24,1","mdoc":["A class with an inner class."]}
+----
+=to=Entity#0:
+=labels=Array(4):
+11:inner-class
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"OuterClass","full_name":"OuterClass"}
+
+
+Edge
+=type=5:CLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+11:inner-class
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"OuterClass","full_name":"OuterClass"}
+----
+=to=Entity#17:class_outer_class
+=labels=Array(3):
+11:inner-class
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"public","full_name":"OuterClass","name":"OuterClass","location":"%SOURCE_DIRECTORY%\/OuterClass.java:19,1--24,1","mdoc":["A class with an inner class."]}
+
+
+Edge
+=type=9:BOUNDTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/OuterClass.java:19,1--24,1","is_intro":true,"name":"OuterClass","full_name":"OuterClass","mdoc":["A class with an inner class."]}
+----
+=to=Entity#0:
+=labels=Array(4):
+11:inner-class
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"OuterClass","full_name":"OuterClass"}
+
+
+Edge
+=type=6:MCLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/OuterClass.java:19,1--24,1","is_intro":true,"name":"OuterClass","full_name":"OuterClass","mdoc":["A class with an inner class."]}
+----
+=to=Entity#17:class_outer_class
+=labels=Array(3):
+11:inner-class
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"public","full_name":"OuterClass","name":"OuterClass","location":"%SOURCE_DIRECTORY%\/OuterClass.java:19,1--24,1","mdoc":["A class with an inner class."]}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/OuterClass.java:19,1--24,1","is_intro":true,"name":"OuterClass","full_name":"OuterClass","mdoc":["A class with an inner class."]}
+----
+=to=Entity#0:
+=labels=Array(4):
+11:inner-class
+7:MEntity
+9:MProperty
+11:MInnerClass
+=properties=JsonObject(3):
+{"visibility":"public","full_name":"OuterClass::InnerClass","name":"InnerClass"}
+
+
+Edge
+=type=14:INTRO_CLASSDEF
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+11:inner-class
+7:MEntity
+9:MProperty
+11:MInnerClass
+=properties=JsonObject(3):
+{"visibility":"public","full_name":"OuterClass::InnerClass","name":"InnerClass"}
+----
+=to=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/OuterClass.java:19,1--24,1","is_intro":true,"name":"OuterClass","full_name":"OuterClass","mdoc":["A class with an inner class."]}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/OuterClass.java:19,1--24,1","is_intro":true,"name":"OuterClass","full_name":"OuterClass","mdoc":["A class with an inner class."]}
+----
+=to=Entity#0:
+=labels=Array(4):
+11:inner-class
+7:MEntity
+8:MPropDef
+14:MInnerClassDef
+=properties=JsonObject(5):
+{"location":"\/dev\/null:1,1--1,1","full_name":"OuterClass::InnerClass","name":"InnerClass","visibility":"public","is_intro":true}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+11:inner-class
+7:MEntity
+8:MPropDef
+14:MInnerClassDef
+=properties=JsonObject(5):
+{"location":"\/dev\/null:1,1--1,1","full_name":"OuterClass::InnerClass","name":"InnerClass","visibility":"public","is_intro":true}
+----
+=to=Entity#0:
+=labels=Array(4):
+11:inner-class
+7:MEntity
+9:MProperty
+11:MInnerClass
+=properties=JsonObject(3):
+{"visibility":"public","full_name":"OuterClass::InnerClass","name":"InnerClass"}
+
+
+Edge
+=type=5:NESTS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+11:inner-class
+7:MEntity
+8:MPropDef
+14:MInnerClassDef
+=properties=JsonObject(5):
+{"location":"\/dev\/null:1,1--1,1","full_name":"OuterClass::InnerClass","name":"InnerClass","visibility":"public","is_intro":true}
+----
+=to=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/OuterClass.java:23,1--23,1","is_intro":true,"name":"OuterClass::InnerClass","full_name":"OuterClass::InnerClass","mdoc":["An instance (non-static) inner class."]}
+
+
+Edge
+=type=5:NESTS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+11:inner-class
+7:MEntity
+9:MProperty
+11:MInnerClass
+=properties=JsonObject(3):
+{"visibility":"public","full_name":"OuterClass::InnerClass","name":"InnerClass"}
+----
+=to=Entity#33:class_outer_class_1_1_inner_class
+=labels=Array(3):
+11:inner-class
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"public","full_name":"OuterClass::InnerClass","name":"OuterClass::InnerClass","location":"%SOURCE_DIRECTORY%\/OuterClass.java:23,1--23,1","mdoc":["An instance (non-static) inner class."]}
+
+
+Edge
+=type=9:CLASSTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#33:class_outer_class_1_1_inner_class
+=labels=Array(3):
+11:inner-class
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"public","full_name":"OuterClass::InnerClass","name":"OuterClass::InnerClass","location":"%SOURCE_DIRECTORY%\/OuterClass.java:23,1--23,1","mdoc":["An instance (non-static) inner class."]}
+----
+=to=Entity#0:
+=labels=Array(4):
+11:inner-class
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"OuterClass::InnerClass","full_name":"OuterClass::InnerClass"}
+
+
+Edge
+=type=5:CLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+11:inner-class
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"OuterClass::InnerClass","full_name":"OuterClass::InnerClass"}
+----
+=to=Entity#33:class_outer_class_1_1_inner_class
+=labels=Array(3):
+11:inner-class
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"public","full_name":"OuterClass::InnerClass","name":"OuterClass::InnerClass","location":"%SOURCE_DIRECTORY%\/OuterClass.java:23,1--23,1","mdoc":["An instance (non-static) inner class."]}
+
+
+Edge
+=type=9:BOUNDTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/OuterClass.java:23,1--23,1","is_intro":true,"name":"OuterClass::InnerClass","full_name":"OuterClass::InnerClass","mdoc":["An instance (non-static) inner class."]}
+----
+=to=Entity#0:
+=labels=Array(4):
+11:inner-class
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"OuterClass::InnerClass","full_name":"OuterClass::InnerClass"}
+
+
+Edge
+=type=6:MCLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/OuterClass.java:23,1--23,1","is_intro":true,"name":"OuterClass::InnerClass","full_name":"OuterClass::InnerClass","mdoc":["An instance (non-static) inner class."]}
+----
+=to=Entity#33:class_outer_class_1_1_inner_class
+=labels=Array(3):
+11:inner-class
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"public","full_name":"OuterClass::InnerClass","name":"OuterClass::InnerClass","location":"%SOURCE_DIRECTORY%\/OuterClass.java:23,1--23,1","mdoc":["An instance (non-static) inner class."]}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"inner-class"}
+----
+=to=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/OuterClass.java:1,1--1,1","name":"OuterClass","full_name":"OuterClass"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/OuterClass.java:1,1--1,1","name":"OuterClass","full_name":"OuterClass"}
+----
+=to=Entity#17:class_outer_class
+=labels=Array(3):
+11:inner-class
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"public","full_name":"OuterClass","name":"OuterClass","location":"%SOURCE_DIRECTORY%\/OuterClass.java:19,1--24,1","mdoc":["A class with an inner class."]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/OuterClass.java:1,1--1,1","name":"OuterClass","full_name":"OuterClass"}
+----
+=to=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/OuterClass.java:19,1--24,1","is_intro":true,"name":"OuterClass","full_name":"OuterClass","mdoc":["A class with an inner class."]}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/OuterClass.java:1,1--1,1","name":"OuterClass","full_name":"OuterClass"}
+----
+=to=Entity#33:class_outer_class_1_1_inner_class
+=labels=Array(3):
+11:inner-class
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"public","full_name":"OuterClass::InnerClass","name":"OuterClass::InnerClass","location":"%SOURCE_DIRECTORY%\/OuterClass.java:23,1--23,1","mdoc":["An instance (non-static) inner class."]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/OuterClass.java:1,1--1,1","name":"OuterClass","full_name":"OuterClass"}
+----
+=to=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/OuterClass.java:23,1--23,1","is_intro":true,"name":"OuterClass::InnerClass","full_name":"OuterClass::InnerClass","mdoc":["An instance (non-static) inner class."]}
+
+
+---===DONE===---
diff --git a/tests/sav/neo_doxygen_file_compound.res b/tests/sav/neo_doxygen_file_compound.res
new file mode 100644 (file)
index 0000000..ab885c0
--- /dev/null
@@ -0,0 +1,1215 @@
+---===WITHOUT GLOBALS===---
+# Graph
+Edge
+=type=4:ROOT
+=properties=JsonObject(0):
+{}
+----
+=from=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a::b","name":"b"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"\/dev\/null:1,1--1,1","name":"Bar","full_name":"a::b::Bar"}
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"\/dev\/null:1,1--1,1","name":"Bar","full_name":"a::b::Bar"}
+----
+=to=Entity#12:classa_b_bar
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(4):
+{"kind":"class","visibility":"public","full_name":"a::b::Bar","name":"Bar"}
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"\/dev\/null:1,1--1,1","name":"Bar","full_name":"a::b::Bar"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"\/dev\/null:1,1--1,1","is_intro":true,"name":"Bar","full_name":"a::b::Bar"}
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#10:namespacec
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"c","name":"c"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"\/dev\/null:1,1--1,1","name":"Bar","full_name":"c::Bar"}
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#10:namespaced
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"d","name":"d"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"\/dev\/null:1,1--1,1","name":"Bar","full_name":"d::Bar"}
+
+Edge
+=type=9:CLASSTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#12:classa_b_bar
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(4):
+{"kind":"class","visibility":"public","full_name":"a::b::Bar","name":"Bar"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"Bar","full_name":"a::b::Bar"}
+
+Edge
+=type=5:CLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"Bar","full_name":"a::b::Bar"}
+----
+=to=Entity#12:classa_b_bar
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(4):
+{"kind":"class","visibility":"public","full_name":"a::b::Bar","name":"Bar"}
+
+Edge
+=type=9:BOUNDTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"\/dev\/null:1,1--1,1","is_intro":true,"name":"Bar","full_name":"a::b::Bar"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"Bar","full_name":"a::b::Bar"}
+
+Edge
+=type=6:MCLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"\/dev\/null:1,1--1,1","is_intro":true,"name":"Bar","full_name":"a::b::Bar"}
+----
+=to=Entity#12:classa_b_bar
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(4):
+{"kind":"class","visibility":"public","full_name":"a::b::Bar","name":"Bar"}
+
+Edge
+=type=9:CLASSTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#8:classbaz
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(4):
+{"kind":"class","visibility":"public","full_name":"Baz","name":"Baz"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"Baz","full_name":"Baz"}
+
+Edge
+=type=5:CLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"Baz","full_name":"Baz"}
+----
+=to=Entity#8:classbaz
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(4):
+{"kind":"class","visibility":"public","full_name":"Baz","name":"Baz"}
+
+Edge
+=type=9:BOUNDTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"\/dev\/null:1,1--1,1","is_intro":true,"name":"Baz","full_name":"Baz"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"Baz","full_name":"Baz"}
+
+Edge
+=type=6:MCLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"\/dev\/null:1,1--1,1","is_intro":true,"name":"Baz","full_name":"Baz"}
+----
+=to=Entity#8:classbaz
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(4):
+{"kind":"class","visibility":"public","full_name":"Baz","name":"Baz"}
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a","name":"a"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+Edge
+=type=6:PARENT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a","name":"a"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+
+Edge
+=type=5:NESTS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a","name":"a"}
+
+Edge
+=type=6:PARENT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a::b","name":"b"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a","name":"a"}
+
+Edge
+=type=5:NESTS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a","name":"a"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a::b","name":"b"}
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a::b","name":"b"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#10:namespacec
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"c","name":"c"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+Edge
+=type=6:PARENT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#10:namespacec
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"c","name":"c"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+
+Edge
+=type=5:NESTS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+----
+=to=Entity#10:namespacec
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"c","name":"c"}
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#10:namespaced
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"d","name":"d"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+Edge
+=type=6:PARENT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#10:namespaced
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"d","name":"d"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+
+Edge
+=type=5:NESTS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+----
+=to=Entity#10:namespaced
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"d","name":"d"}
+
+
+---===WITH GLOBALS===---
+# Graph
+Edge
+=type=4:ROOT
+=properties=JsonObject(0):
+{}
+----
+=from=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a::b","name":"b"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"\/dev\/null:1,1--1,1","name":"Bar","full_name":"a::b::Bar"}
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"\/dev\/null:1,1--1,1","name":"Bar","full_name":"a::b::Bar"}
+----
+=to=Entity#12:classa_b_bar
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(4):
+{"kind":"class","visibility":"public","full_name":"a::b::Bar","name":"Bar"}
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"\/dev\/null:1,1--1,1","name":"Bar","full_name":"a::b::Bar"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"\/dev\/null:1,1--1,1","is_intro":true,"name":"Bar","full_name":"a::b::Bar"}
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#10:namespacec
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"c","name":"c"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"\/dev\/null:1,1--1,1","name":"Bar","full_name":"c::Bar"}
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#10:namespaced
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"d","name":"d"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"\/dev\/null:1,1--1,1","name":"Bar","full_name":"d::Bar"}
+
+Edge
+=type=9:CLASSTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#12:classa_b_bar
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(4):
+{"kind":"class","visibility":"public","full_name":"a::b::Bar","name":"Bar"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"Bar","full_name":"a::b::Bar"}
+
+Edge
+=type=5:CLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"Bar","full_name":"a::b::Bar"}
+----
+=to=Entity#12:classa_b_bar
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(4):
+{"kind":"class","visibility":"public","full_name":"a::b::Bar","name":"Bar"}
+
+Edge
+=type=9:BOUNDTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"\/dev\/null:1,1--1,1","is_intro":true,"name":"Bar","full_name":"a::b::Bar"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"Bar","full_name":"a::b::Bar"}
+
+Edge
+=type=6:MCLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"\/dev\/null:1,1--1,1","is_intro":true,"name":"Bar","full_name":"a::b::Bar"}
+----
+=to=Entity#12:classa_b_bar
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(4):
+{"kind":"class","visibility":"public","full_name":"a::b::Bar","name":"Bar"}
+
+Edge
+=type=9:CLASSTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#8:classbaz
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(4):
+{"kind":"class","visibility":"public","full_name":"Baz","name":"Baz"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"Baz","full_name":"Baz"}
+
+Edge
+=type=5:CLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"Baz","full_name":"Baz"}
+----
+=to=Entity#8:classbaz
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(4):
+{"kind":"class","visibility":"public","full_name":"Baz","name":"Baz"}
+
+Edge
+=type=9:BOUNDTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"\/dev\/null:1,1--1,1","is_intro":true,"name":"Baz","full_name":"Baz"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"Baz","full_name":"Baz"}
+
+Edge
+=type=6:MCLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"\/dev\/null:1,1--1,1","is_intro":true,"name":"Baz","full_name":"Baz"}
+----
+=to=Entity#8:classbaz
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(4):
+{"kind":"class","visibility":"public","full_name":"Baz","name":"Baz"}
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a","name":"a"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+Edge
+=type=6:PARENT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a","name":"a"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+
+Edge
+=type=5:NESTS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a","name":"a"}
+
+Edge
+=type=6:PARENT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a::b","name":"b"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a","name":"a"}
+
+Edge
+=type=5:NESTS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a","name":"a"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a::b","name":"b"}
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a::b","name":"b"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#10:namespacec
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"c","name":"c"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+Edge
+=type=6:PARENT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#10:namespacec
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"c","name":"c"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+
+Edge
+=type=5:NESTS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+----
+=to=Entity#10:namespacec
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"c","name":"c"}
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#10:namespaced
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"d","name":"d"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+Edge
+=type=6:PARENT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#10:namespaced
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"d","name":"d"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+
+Edge
+=type=5:NESTS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+----
+=to=Entity#10:namespaced
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"d","name":"d"}
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"\/dev\/null:1,1--1,1","name":"Bar","full_name":"Bar"}
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"\/dev\/null:1,1--1,1","name":"Bar","full_name":"Bar"}
+----
+=to=Entity#8:classbaz
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(4):
+{"kind":"class","visibility":"public","full_name":"Baz","name":"Baz"}
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"\/dev\/null:1,1--1,1","name":"Bar","full_name":"Bar"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"\/dev\/null:1,1--1,1","is_intro":true,"name":"Baz","full_name":"Baz"}
+
+
diff --git a/tests/sav/neo_doxygen_graph_empty_project.res b/tests/sav/neo_doxygen_graph_empty_project.res
new file mode 100644 (file)
index 0000000..d57edd6
--- /dev/null
@@ -0,0 +1,44 @@
+# Graph
+Edge
+=type=4:ROOT
+=properties=JsonObject(0):
+{}
+----
+=from=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+
diff --git a/tests/sav/neo_doxygen_member_resolve_introducer.res b/tests/sav/neo_doxygen_member_resolve_introducer.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/sav/nitg-e/base_self_type.res b/tests/sav/nitg-e/base_self_type.res
new file mode 100644 (file)
index 0000000..3c20b42
--- /dev/null
@@ -0,0 +1,11 @@
+X
+X
+X
+Y
+Y
+Y
+Y
+A
+G
+B
+G
diff --git a/tests/sav/nitg-e/base_self_type_alt2.res b/tests/sav/nitg-e/base_self_type_alt2.res
new file mode 100644 (file)
index 0000000..3c20b42
--- /dev/null
@@ -0,0 +1,11 @@
+X
+X
+X
+Y
+Y
+Y
+Y
+A
+G
+B
+G
index 56621b6..980ce17 100644 (file)
@@ -1,4 +1,4 @@
-Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/standard/kernel.nit:374)
+Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/standard/kernel.nit:411)
 11
 21
 31
index 56621b6..980ce17 100644 (file)
@@ -1,4 +1,4 @@
-Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/standard/kernel.nit:374)
+Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/standard/kernel.nit:411)
 11
 21
 31
index 56621b6..980ce17 100644 (file)
@@ -1,4 +1,4 @@
-Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/standard/kernel.nit:374)
+Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/standard/kernel.nit:411)
 11
 21
 31
diff --git a/tests/sav/nitiwiki.res b/tests/sav/nitiwiki.res
new file mode 100644 (file)
index 0000000..232b5ef
--- /dev/null
@@ -0,0 +1,2 @@
+Not in a nitiwiki directory.
+Use --init to initialize one here.
diff --git a/tests/sav/nitiwiki_args1.res b/tests/sav/nitiwiki_args1.res
new file mode 100644 (file)
index 0000000..3f5641d
--- /dev/null
@@ -0,0 +1,10 @@
+nitiWiki
+name: wiki2
+config: ../contrib/nitiwiki/tests/wiki1/config2.ini
+url: http://localhost/
+
+There is modified files:
+ + pages
+ + /pages/index.md
+
+Use nitiwiki --render to render modified files
diff --git a/tests/sav/nitiwiki_args2.res b/tests/sav/nitiwiki_args2.res
new file mode 100644 (file)
index 0000000..adf25a7
--- /dev/null
@@ -0,0 +1 @@
+Render section out
index 33325f6..547af57 100644 (file)
@@ -1,67 +1,67 @@
-<span class="nitcode"><span class="line" id="L1"><span class="nc_c"># This file is part of NIT ( http://www.nitlanguage.org ).
+<span class="nitcode"><span class="line" id="L1"><span class="nc_c"># This file is part of NIT ( http:&#47;&#47;www.nitlanguage.org ).
 </span></span><span class="line" id="L2"><span class="nc_c">#
 </span></span><span class="line" id="L3"><span class="nc_c"># Copyright 2006-2008 Jean Privat &lt;jean@pryen.org&gt;
 </span></span><span class="line" id="L4"><span class="nc_c">#
-</span></span><span class="line" id="L5"><span class="nc_c"># Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
+</span></span><span class="line" id="L5"><span class="nc_c"># Licensed under the Apache License, Version 2.0 (the &#34;License&#34;);
 </span></span><span class="line" id="L6"><span class="nc_c"># you may not use this file except in compliance with the License.
 </span></span><span class="line" id="L7"><span class="nc_c"># You may obtain a copy of the License at
 </span></span><span class="line" id="L8"><span class="nc_c">#
-</span></span><span class="line" id="L9"><span class="nc_c">#     http://www.apache.org/licenses/LICENSE-2.0
+</span></span><span class="line" id="L9"><span class="nc_c">#     http:&#47;&#47;www.apache.org&#47;licenses&#47;LICENSE-2.0
 </span></span><span class="line" id="L10"><span class="nc_c">#
 </span></span><span class="line" id="L11"><span class="nc_c"># Unless required by applicable law or agreed to in writing, software
-</span></span><span class="line" id="L12"><span class="nc_c"># distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
+</span></span><span class="line" id="L12"><span class="nc_c"># distributed under the License is distributed on an &#34;AS IS&#34; BASIS,
 </span></span><span class="line" id="L13"><span class="nc_c"># WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 </span></span><span class="line" id="L14"><span class="nc_c"># See the License for the specific language governing permissions and
 </span></span><span class="line" id="L15"><span class="nc_c"># limitations under the License.
 </span></span><span class="line" id="L16">
 </span><span class="line" id="L17"><span class="nc_k">import</span> <span class="nc_k">end</span>
 </span><span class="line" id="L18">
-</span><span class="nc_cdef foldable" id="base_simple3#Object"><span class="line" id="L19"><span class="nc_k">interface</span> <span class="nc_def nc_t popupable" title="class Object" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Object&quot;&gt;class Object&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;/b&gt; &lt;span&gt;Object&lt;/span&gt;&lt;br/&gt;&lt;div class=&quot;dropdown&quot;&gt; &lt;a data-toggle=&quot;dropdown&quot; href=&quot;#&quot;&gt;&lt;b&gt;hier&lt;/b&gt; sub-classes&lt;span class=&quot;caret&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;ul class=&quot;dropdown-menu&quot; role=&quot;menu&quot; aria-labelledby=&quot;dLabel&quot;&gt;&lt;li&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Bool&quot;&gt;Bool&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;base_simple3.html#base_simple3#A&quot;&gt;A&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;base_simple3.html#base_simple3#B&quot;&gt;B&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;base_simple3.html#base_simple3#C&quot;&gt;C&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Sys&quot;&gt;Sys&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;" data-toggle="popover">Object</span>
+</span><span class="nc_cdef foldable" id="base_simple3#Object"><span class="line" id="L19"><span class="nc_k">interface</span> <span class="nc_def nc_t popupable" title="class Object" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Object&#34;&gt;class Object&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;&#47;b&gt; &lt;span&gt;Object&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;div class=&#34;dropdown&#34;&gt; &lt;a data-toggle=&#34;dropdown&#34; href=&#34;#&#34;&gt;&lt;b&gt;hier&lt;&#47;b&gt; sub-classes&lt;span class=&#34;caret&#34;&gt;&lt;&#47;span&gt;&lt;&#47;a&gt;&lt;ul class=&#34;dropdown-menu&#34; role=&#34;menu&#34; aria-labelledby=&#34;dLabel&#34;&gt;&lt;li&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Bool&#34;&gt;Bool&lt;&#47;a&gt;&lt;&#47;li&gt;&lt;li&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;&lt;&#47;li&gt;&lt;li&gt;&lt;a href=&#34;base_simple3.html#base_simple3#A&#34;&gt;A&lt;&#47;a&gt;&lt;&#47;li&gt;&lt;li&gt;&lt;a href=&#34;base_simple3.html#base_simple3#B&#34;&gt;B&lt;&#47;a&gt;&lt;&#47;li&gt;&lt;li&gt;&lt;a href=&#34;base_simple3.html#base_simple3#C&#34;&gt;C&lt;&#47;a&gt;&lt;&#47;li&gt;&lt;li&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Sys&#34;&gt;Sys&lt;&#47;a&gt;&lt;&#47;li&gt;&lt;&#47;ul&gt;&lt;&#47;div&gt;&lt;&#47;div&gt;" data-toggle="popover">Object</span>
 </span><span class="line" id="L20"><span class="nc_k">end</span>
 </span></span><span class="line" id="L21">
-</span><span class="nc_cdef foldable" id="base_simple3#Bool"><span class="line" id="L22"><span class="nc_k">enum</span> <span class="nc_def nc_t popupable" title="class Bool" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Bool&quot;&gt;class Bool&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;/b&gt; &lt;span&gt;Bool&lt;/span&gt;&lt;br/&gt;&lt;div class=&quot;dropdown&quot;&gt; &lt;a data-toggle=&quot;dropdown&quot; href=&quot;#&quot;&gt;&lt;b&gt;hier&lt;/b&gt; super-classes&lt;span class=&quot;caret&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;ul class=&quot;dropdown-menu&quot; role=&quot;menu&quot; aria-labelledby=&quot;dLabel&quot;&gt;&lt;li&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Object&quot;&gt;Object&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;" data-toggle="popover">Bool</span>
+</span><span class="nc_cdef foldable" id="base_simple3#Bool"><span class="line" id="L22"><span class="nc_k">enum</span> <span class="nc_def nc_t popupable" title="class Bool" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Bool&#34;&gt;class Bool&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;&#47;b&gt; &lt;span&gt;Bool&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;div class=&#34;dropdown&#34;&gt; &lt;a data-toggle=&#34;dropdown&#34; href=&#34;#&#34;&gt;&lt;b&gt;hier&lt;&#47;b&gt; super-classes&lt;span class=&#34;caret&#34;&gt;&lt;&#47;span&gt;&lt;&#47;a&gt;&lt;ul class=&#34;dropdown-menu&#34; role=&#34;menu&#34; aria-labelledby=&#34;dLabel&#34;&gt;&lt;li&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Object&#34;&gt;Object&lt;&#47;a&gt;&lt;&#47;li&gt;&lt;&#47;ul&gt;&lt;&#47;div&gt;&lt;&#47;div&gt;" data-toggle="popover">Bool</span>
 </span><span class="line" id="L23"><span class="nc_k">end</span>
 </span></span><span class="line" id="L24">
-</span><span class="nc_cdef foldable" id="base_simple3#Int"><span class="line" id="L25"><span class="nc_k">enum</span> <span class="nc_def nc_t popupable" title="class Int" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;class Int&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;/b&gt; &lt;span&gt;Int&lt;/span&gt;&lt;br/&gt;&lt;div class=&quot;dropdown&quot;&gt; &lt;a data-toggle=&quot;dropdown&quot; href=&quot;#&quot;&gt;&lt;b&gt;hier&lt;/b&gt; super-classes&lt;span class=&quot;caret&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;ul class=&quot;dropdown-menu&quot; role=&quot;menu&quot; aria-labelledby=&quot;dLabel&quot;&gt;&lt;li&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Object&quot;&gt;Object&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;" data-toggle="popover">Int</span>
-</span><span class="nc_pdef foldable" id="base_simple3#Int#output"><span class="line" id="L26">        <span class="nc_k">fun</span> <span class="nc_def popupable" title="base_simple3#Int#output" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Int#output&quot;&gt;base_simple3#Int#output&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;fun&lt;/b&gt; &lt;span&gt;output&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover"><span class="nc_i">output</span></span> <span class="nc_k">is</span> <span class="nc_i">intern</span>
+</span><span class="nc_cdef foldable" id="base_simple3#Int"><span class="line" id="L25"><span class="nc_k">enum</span> <span class="nc_def nc_t popupable" title="class Int" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;class Int&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;&#47;b&gt; &lt;span&gt;Int&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;div class=&#34;dropdown&#34;&gt; &lt;a data-toggle=&#34;dropdown&#34; href=&#34;#&#34;&gt;&lt;b&gt;hier&lt;&#47;b&gt; super-classes&lt;span class=&#34;caret&#34;&gt;&lt;&#47;span&gt;&lt;&#47;a&gt;&lt;ul class=&#34;dropdown-menu&#34; role=&#34;menu&#34; aria-labelledby=&#34;dLabel&#34;&gt;&lt;li&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Object&#34;&gt;Object&lt;&#47;a&gt;&lt;&#47;li&gt;&lt;&#47;ul&gt;&lt;&#47;div&gt;&lt;&#47;div&gt;" data-toggle="popover">Int</span>
+</span><span class="nc_pdef foldable" id="base_simple3#Int#output"><span class="line" id="L26">        <span class="nc_k">fun</span> <span class="nc_def popupable" title="base_simple3#Int#output" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Int#output&#34;&gt;base_simple3#Int#output&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;fun&lt;&#47;b&gt; &lt;span&gt;output&lt;span&gt;&lt;&#47;span&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover"><span class="nc_i">output</span></span> <span class="nc_k">is</span> <span class="nc_i">intern</span>
 </span></span><span class="line" id="L27"><span class="nc_k">end</span>
 </span></span><span class="line" id="L28">
-</span><span class="nc_cdef foldable" id="base_simple3#A"><span class="line" id="L29"><span class="nc_k">class</span> <span class="nc_def nc_t popupable" title="class A" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#A&quot;&gt;class A&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;/b&gt; &lt;span&gt;A&lt;/span&gt;&lt;br/&gt;&lt;div class=&quot;dropdown&quot;&gt; &lt;a data-toggle=&quot;dropdown&quot; href=&quot;#&quot;&gt;&lt;b&gt;hier&lt;/b&gt; super-classes&lt;span class=&quot;caret&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;ul class=&quot;dropdown-menu&quot; role=&quot;menu&quot; aria-labelledby=&quot;dLabel&quot;&gt;&lt;li&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Object&quot;&gt;Object&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;" data-toggle="popover">A</span>
-</span><span class="nc_pdef foldable" id="base_simple3#A#init"><span class="line" id="L30">    <span class="nc_k">init</span> <span class="nc_k">do</span> <span class="nc_l popupable" title="Int" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">5</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Int#output&quot;&gt;call base_simple3#Int#output&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Int#output&quot;&gt;output&lt;/a&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">output</span>
-</span></span><span class="nc_pdef foldable" id="base_simple3#A#run"><span class="line" id="L31">      <span class="nc_k">fun</span> <span class="nc_def popupable" title="base_simple3#A#run" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#A#run&quot;&gt;base_simple3#A#run&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;fun&lt;/b&gt; &lt;span&gt;run&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover"><span class="nc_i">run</span></span> <span class="nc_k">do</span> <span class="nc_l popupable" title="Int" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">6</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Int#output&quot;&gt;call base_simple3#Int#output&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Int#output&quot;&gt;output&lt;/a&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">output</span>
+</span><span class="nc_cdef foldable" id="base_simple3#A"><span class="line" id="L29"><span class="nc_k">class</span> <span class="nc_def nc_t popupable" title="class A" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#A&#34;&gt;class A&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;&#47;b&gt; &lt;span&gt;A&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;div class=&#34;dropdown&#34;&gt; &lt;a data-toggle=&#34;dropdown&#34; href=&#34;#&#34;&gt;&lt;b&gt;hier&lt;&#47;b&gt; super-classes&lt;span class=&#34;caret&#34;&gt;&lt;&#47;span&gt;&lt;&#47;a&gt;&lt;ul class=&#34;dropdown-menu&#34; role=&#34;menu&#34; aria-labelledby=&#34;dLabel&#34;&gt;&lt;li&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Object&#34;&gt;Object&lt;&#47;a&gt;&lt;&#47;li&gt;&lt;&#47;ul&gt;&lt;&#47;div&gt;&lt;&#47;div&gt;" data-toggle="popover">A</span>
+</span><span class="nc_pdef foldable" id="base_simple3#A#init"><span class="line" id="L30">    <span class="nc_k">init</span> <span class="nc_k">do</span> <span class="nc_l popupable" title="Int" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">5</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Int#output&#34;&gt;call base_simple3#Int#output&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Int#output&#34;&gt;output&lt;&#47;a&gt;&lt;span&gt;&lt;&#47;span&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">output</span>
+</span></span><span class="nc_pdef foldable" id="base_simple3#A#run"><span class="line" id="L31">      <span class="nc_k">fun</span> <span class="nc_def popupable" title="base_simple3#A#run" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#A#run&#34;&gt;base_simple3#A#run&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;fun&lt;&#47;b&gt; &lt;span&gt;run&lt;span&gt;&lt;&#47;span&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover"><span class="nc_i">run</span></span> <span class="nc_k">do</span> <span class="nc_l popupable" title="Int" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">6</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Int#output&#34;&gt;call base_simple3#Int#output&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Int#output&#34;&gt;output&lt;&#47;a&gt;&lt;span&gt;&lt;&#47;span&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">output</span>
 </span></span><span class="line" id="L32"><span class="nc_k">end</span>
 </span></span><span class="line" id="L33">
-</span><span class="nc_cdef foldable" id="base_simple3#B"><span class="line" id="L34"><span class="nc_k">class</span> <span class="nc_def nc_t popupable" title="class B" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#B&quot;&gt;class B&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;/b&gt; &lt;span&gt;B&lt;/span&gt;&lt;br/&gt;&lt;div class=&quot;dropdown&quot;&gt; &lt;a data-toggle=&quot;dropdown&quot; href=&quot;#&quot;&gt;&lt;b&gt;hier&lt;/b&gt; super-classes&lt;span class=&quot;caret&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;ul class=&quot;dropdown-menu&quot; role=&quot;menu&quot; aria-labelledby=&quot;dLabel&quot;&gt;&lt;li&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Object&quot;&gt;Object&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;" data-toggle="popover">B</span>
-</span><span class="nc_pdef foldable" id="base_simple3#B#_val"><a id="base_simple3#B#val"></a><a id="base_simple3#B#val="></a><span class="line" id="L35">     <span class="nc_k">var</span> <span class="nc_def nc_i popupable" title="base_simple3#B#val" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#B#val&quot;&gt;base_simple3#B#val&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;fun&lt;/b&gt; &lt;span&gt;val&lt;span&gt;: &lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">val</span><span>:</span> <span class="nc_t popupable" title="Int" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">Int</span>
-</span></span><span class="nc_pdef foldable" id="base_simple3#B#init"><span class="line" id="L36">     <span class="nc_k">init</span><span>(</span><span class="nc_v nc_i popupable" title="v: Int" data-content="&lt;div&gt;&lt;b&gt;local var&lt;/b&gt; &lt;span&gt;v:&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">v</span><span>:</span> <span class="nc_t popupable" title="Int" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">Int</span><span>)</span>
+</span><span class="nc_cdef foldable" id="base_simple3#B"><span class="line" id="L34"><span class="nc_k">class</span> <span class="nc_def nc_t popupable" title="class B" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#B&#34;&gt;class B&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;&#47;b&gt; &lt;span&gt;B&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;div class=&#34;dropdown&#34;&gt; &lt;a data-toggle=&#34;dropdown&#34; href=&#34;#&#34;&gt;&lt;b&gt;hier&lt;&#47;b&gt; super-classes&lt;span class=&#34;caret&#34;&gt;&lt;&#47;span&gt;&lt;&#47;a&gt;&lt;ul class=&#34;dropdown-menu&#34; role=&#34;menu&#34; aria-labelledby=&#34;dLabel&#34;&gt;&lt;li&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Object&#34;&gt;Object&lt;&#47;a&gt;&lt;&#47;li&gt;&lt;&#47;ul&gt;&lt;&#47;div&gt;&lt;&#47;div&gt;" data-toggle="popover">B</span>
+</span><span class="nc_pdef foldable" id="base_simple3#B#_val"><a id="base_simple3#B#val"></a><a id="base_simple3#B#val="></a><span class="line" id="L35">     <span class="nc_k">var</span> <span class="nc_def nc_i popupable" title="base_simple3#B#val" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#B#val&#34;&gt;base_simple3#B#val&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;fun&lt;&#47;b&gt; &lt;span&gt;val&lt;span&gt;: &lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">val</span><span>:</span> <span class="nc_t popupable" title="Int" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">Int</span>
+</span></span><span class="nc_pdef foldable" id="base_simple3#B#init"><span class="line" id="L36">     <span class="nc_k">init</span><span>(</span><span class="nc_v nc_i popupable" title="v: Int" data-content="&lt;div&gt;&lt;b&gt;local var&lt;&#47;b&gt; &lt;span&gt;v:&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">v</span><span>:</span> <span class="nc_t popupable" title="Int" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">Int</span><span>)</span>
 </span><span class="line" id="L37">    <span class="nc_k">do</span>
-</span><span class="line" id="L38">            <span class="nc_l popupable" title="Int" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">7</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Int#output&quot;&gt;call base_simple3#Int#output&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Int#output&quot;&gt;output&lt;/a&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">output</span>
-</span><span class="line" id="L39">            <span class="nc_k">self</span><span>.</span><span class="nc_i popupable" title="call base_simple3#B#val=" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#B#val=&quot;&gt;call base_simple3#B#val=&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#B#val=&quot;&gt;val=&lt;/a&gt;&lt;span&gt;(val: &lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">val</span> <span>=</span> <span class="nc_v nc_i popupable" title="v: Int" data-content="&lt;div&gt;&lt;b&gt;local var&lt;/b&gt; &lt;span&gt;v:&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">v</span>
+</span><span class="line" id="L38">            <span class="nc_l popupable" title="Int" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">7</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Int#output&#34;&gt;call base_simple3#Int#output&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Int#output&#34;&gt;output&lt;&#47;a&gt;&lt;span&gt;&lt;&#47;span&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">output</span>
+</span><span class="line" id="L39">            <span class="nc_k">self</span><span>.</span><span class="nc_i popupable" title="call base_simple3#B#val=" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#B#val=&#34;&gt;call base_simple3#B#val=&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#B#val=&#34;&gt;val=&lt;&#47;a&gt;&lt;span&gt;(val: &lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;)&lt;&#47;span&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">val</span> <span>=</span> <span class="nc_v nc_i popupable" title="v: Int" data-content="&lt;div&gt;&lt;b&gt;local var&lt;&#47;b&gt; &lt;span&gt;v:&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">v</span>
 </span><span class="line" id="L40">    <span class="nc_k">end</span>
-</span></span><span class="nc_pdef foldable" id="base_simple3#B#run"><span class="line" id="L41">      <span class="nc_k">fun</span> <span class="nc_def popupable" title="base_simple3#B#run" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#B#run&quot;&gt;base_simple3#B#run&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;fun&lt;/b&gt; &lt;span&gt;run&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover"><span class="nc_i">run</span></span> <span class="nc_k">do</span> <span class="nc_i popupable" title="call base_simple3#B#val" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#B#val&quot;&gt;call base_simple3#B#val&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#B#val&quot;&gt;val&lt;/a&gt;&lt;span&gt;: &lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">val</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Int#output&quot;&gt;call base_simple3#Int#output&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Int#output&quot;&gt;output&lt;/a&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">output</span>
+</span></span><span class="nc_pdef foldable" id="base_simple3#B#run"><span class="line" id="L41">      <span class="nc_k">fun</span> <span class="nc_def popupable" title="base_simple3#B#run" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#B#run&#34;&gt;base_simple3#B#run&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;fun&lt;&#47;b&gt; &lt;span&gt;run&lt;span&gt;&lt;&#47;span&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover"><span class="nc_i">run</span></span> <span class="nc_k">do</span> <span class="nc_i popupable" title="call base_simple3#B#val" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#B#val&#34;&gt;call base_simple3#B#val&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#B#val&#34;&gt;val&lt;&#47;a&gt;&lt;span&gt;: &lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">val</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Int#output&#34;&gt;call base_simple3#Int#output&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Int#output&#34;&gt;output&lt;&#47;a&gt;&lt;span&gt;&lt;&#47;span&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">output</span>
 </span></span><span class="line" id="L42"><span class="nc_k">end</span>
 </span></span><span class="line" id="L43">
-</span><span class="nc_cdef foldable" id="base_simple3#C"><span class="line" id="L44"><span class="nc_k">class</span> <span class="nc_def nc_t popupable" title="class C" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#C&quot;&gt;class C&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;/b&gt; &lt;span&gt;C&lt;/span&gt;&lt;br/&gt;&lt;div class=&quot;dropdown&quot;&gt; &lt;a data-toggle=&quot;dropdown&quot; href=&quot;#&quot;&gt;&lt;b&gt;hier&lt;/b&gt; super-classes&lt;span class=&quot;caret&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;ul class=&quot;dropdown-menu&quot; role=&quot;menu&quot; aria-labelledby=&quot;dLabel&quot;&gt;&lt;li&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Object&quot;&gt;Object&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;" data-toggle="popover">C</span>
-</span><span class="nc_pdef foldable" id="base_simple3#C#_val1"><a id="base_simple3#C#val1"></a><a id="base_simple3#C#val1="></a><span class="line" id="L45">  <span class="nc_k">var</span> <span class="nc_def nc_i popupable" title="base_simple3#C#val1" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#C#val1&quot;&gt;base_simple3#C#val1&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;fun&lt;/b&gt; &lt;span&gt;val1&lt;span&gt;: &lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">val1</span><span>:</span> <span class="nc_t popupable" title="Int" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">Int</span>
-</span></span><span class="nc_pdef foldable" id="base_simple3#C#_val2"><a id="base_simple3#C#val2"></a><a id="base_simple3#C#val2="></a><span class="line" id="L46">   <span class="nc_k">var</span> <span class="nc_def nc_i popupable" title="base_simple3#C#val2" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#C#val2&quot;&gt;base_simple3#C#val2&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;fun&lt;/b&gt; &lt;span&gt;val2&lt;span&gt;: &lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">val2</span><span>:</span> <span class="nc_t popupable" title="Int" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">Int</span> <span>=</span> <span class="nc_l popupable" title="Int" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">10</span>
+</span><span class="nc_cdef foldable" id="base_simple3#C"><span class="line" id="L44"><span class="nc_k">class</span> <span class="nc_def nc_t popupable" title="class C" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#C&#34;&gt;class C&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;&#47;b&gt; &lt;span&gt;C&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;div class=&#34;dropdown&#34;&gt; &lt;a data-toggle=&#34;dropdown&#34; href=&#34;#&#34;&gt;&lt;b&gt;hier&lt;&#47;b&gt; super-classes&lt;span class=&#34;caret&#34;&gt;&lt;&#47;span&gt;&lt;&#47;a&gt;&lt;ul class=&#34;dropdown-menu&#34; role=&#34;menu&#34; aria-labelledby=&#34;dLabel&#34;&gt;&lt;li&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Object&#34;&gt;Object&lt;&#47;a&gt;&lt;&#47;li&gt;&lt;&#47;ul&gt;&lt;&#47;div&gt;&lt;&#47;div&gt;" data-toggle="popover">C</span>
+</span><span class="nc_pdef foldable" id="base_simple3#C#_val1"><a id="base_simple3#C#val1"></a><a id="base_simple3#C#val1="></a><span class="line" id="L45">  <span class="nc_k">var</span> <span class="nc_def nc_i popupable" title="base_simple3#C#val1" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#C#val1&#34;&gt;base_simple3#C#val1&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;fun&lt;&#47;b&gt; &lt;span&gt;val1&lt;span&gt;: &lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">val1</span><span>:</span> <span class="nc_t popupable" title="Int" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">Int</span>
+</span></span><span class="nc_pdef foldable" id="base_simple3#C#_val2"><a id="base_simple3#C#val2"></a><a id="base_simple3#C#val2="></a><span class="line" id="L46">   <span class="nc_k">var</span> <span class="nc_def nc_i popupable" title="base_simple3#C#val2" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#C#val2&#34;&gt;base_simple3#C#val2&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;fun&lt;&#47;b&gt; &lt;span&gt;val2&lt;span&gt;: &lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">val2</span><span>:</span> <span class="nc_t popupable" title="Int" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">Int</span> <span>=</span> <span class="nc_l popupable" title="Int" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">10</span>
 </span></span><span class="line" id="L47"><span class="nc_k">end</span>
 </span></span><span class="line" id="L48">
-</span><span class="nc_pdef foldable" id="base_simple3#Object#foo"><span class="line" id="L49"><span class="nc_k">fun</span> <span class="nc_def popupable" title="base_simple3#Object#foo" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Object#foo&quot;&gt;base_simple3#Object#foo&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;fun&lt;/b&gt; &lt;span&gt;foo&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover"><span class="nc_i">foo</span></span> <span class="nc_k">do</span> <span class="nc_l popupable" title="Int" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">2</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Int#output&quot;&gt;call base_simple3#Int#output&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Int#output&quot;&gt;output&lt;/a&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">output</span>
-</span></span><span class="nc_pdef foldable" id="base_simple3#Object#bar"><span class="line" id="L50"><span class="nc_k">fun</span> <span class="nc_def popupable" title="base_simple3#Object#bar" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Object#bar&quot;&gt;base_simple3#Object#bar&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;fun&lt;/b&gt; &lt;span&gt;bar&lt;span&gt;(i: &lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover"><span class="nc_i">bar</span></span><span>(</span><span class="nc_v nc_i popupable" title="i: Int" data-content="&lt;div&gt;&lt;b&gt;local var&lt;/b&gt; &lt;span&gt;i:&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">i</span><span>:</span> <span class="nc_t popupable" title="Int" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">Int</span><span>)</span> <span class="nc_k">do</span> <span class="nc_v nc_i popupable" title="i: Int" data-content="&lt;div&gt;&lt;b&gt;local var&lt;/b&gt; &lt;span&gt;i:&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">i</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Int#output&quot;&gt;call base_simple3#Int#output&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Int#output&quot;&gt;output&lt;/a&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">output</span>
-</span></span><span class="nc_pdef foldable" id="base_simple3#Object#baz"><span class="line" id="L51"><span class="nc_k">fun</span> <span class="nc_def popupable" title="base_simple3#Object#baz" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Object#baz&quot;&gt;base_simple3#Object#baz&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;fun&lt;/b&gt; &lt;span&gt;baz&lt;span&gt;: &lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover"><span class="nc_i">baz</span></span><span>:</span> <span class="nc_t popupable" title="Int" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">Int</span> <span class="nc_k">do</span> <span class="nc_k">return</span> <span class="nc_l popupable" title="Int" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">4</span>
+</span><span class="nc_pdef foldable" id="base_simple3#Object#foo"><span class="line" id="L49"><span class="nc_k">fun</span> <span class="nc_def popupable" title="base_simple3#Object#foo" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Object#foo&#34;&gt;base_simple3#Object#foo&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;fun&lt;&#47;b&gt; &lt;span&gt;foo&lt;span&gt;&lt;&#47;span&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover"><span class="nc_i">foo</span></span> <span class="nc_k">do</span> <span class="nc_l popupable" title="Int" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">2</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Int#output&#34;&gt;call base_simple3#Int#output&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Int#output&#34;&gt;output&lt;&#47;a&gt;&lt;span&gt;&lt;&#47;span&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">output</span>
+</span></span><span class="nc_pdef foldable" id="base_simple3#Object#bar"><span class="line" id="L50"><span class="nc_k">fun</span> <span class="nc_def popupable" title="base_simple3#Object#bar" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Object#bar&#34;&gt;base_simple3#Object#bar&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;fun&lt;&#47;b&gt; &lt;span&gt;bar&lt;span&gt;(i: &lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;)&lt;&#47;span&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover"><span class="nc_i">bar</span></span><span>(</span><span class="nc_v nc_i popupable" title="i: Int" data-content="&lt;div&gt;&lt;b&gt;local var&lt;&#47;b&gt; &lt;span&gt;i:&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">i</span><span>:</span> <span class="nc_t popupable" title="Int" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">Int</span><span>)</span> <span class="nc_k">do</span> <span class="nc_v nc_i popupable" title="i: Int" data-content="&lt;div&gt;&lt;b&gt;local var&lt;&#47;b&gt; &lt;span&gt;i:&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">i</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Int#output&#34;&gt;call base_simple3#Int#output&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Int#output&#34;&gt;output&lt;&#47;a&gt;&lt;span&gt;&lt;&#47;span&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">output</span>
+</span></span><span class="nc_pdef foldable" id="base_simple3#Object#baz"><span class="line" id="L51"><span class="nc_k">fun</span> <span class="nc_def popupable" title="base_simple3#Object#baz" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Object#baz&#34;&gt;base_simple3#Object#baz&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;fun&lt;&#47;b&gt; &lt;span&gt;baz&lt;span&gt;: &lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover"><span class="nc_i">baz</span></span><span>:</span> <span class="nc_t popupable" title="Int" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">Int</span> <span class="nc_k">do</span> <span class="nc_k">return</span> <span class="nc_l popupable" title="Int" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">4</span>
 </span></span><span class="line" id="L52">
-</span><span class="nc_pdef foldable" id="base_simple3#Sys#main"><span class="line" id="L53"><span class="nc_l popupable" title="Int" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">1</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Int#output&quot;&gt;call base_simple3#Int#output&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Int#output&quot;&gt;output&lt;/a&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">output</span>
-</span><span class="line" id="L54"><span class="nc_i popupable" title="call base_simple3#Object#foo" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Object#foo&quot;&gt;call base_simple3#Object#foo&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Object#foo&quot;&gt;foo&lt;/a&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">foo</span>
-</span><span class="line" id="L55"><span class="nc_i popupable" title="call base_simple3#Object#bar" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Object#bar&quot;&gt;call base_simple3#Object#bar&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Object#bar&quot;&gt;bar&lt;/a&gt;&lt;span&gt;(i: &lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">bar</span><span>(</span><span class="nc_l popupable" title="Int" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">3</span><span>)</span>
-</span><span class="line" id="L56"><span class="nc_i popupable" title="call base_simple3#Object#baz" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Object#baz&quot;&gt;call base_simple3#Object#baz&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Object#baz&quot;&gt;baz&lt;/a&gt;&lt;span&gt;: &lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">baz</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Int#output&quot;&gt;call base_simple3#Int#output&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Int#output&quot;&gt;output&lt;/a&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">output</span>
+</span><span class="nc_pdef foldable" id="base_simple3#Sys#main"><span class="line" id="L53"><span class="nc_l popupable" title="Int" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">1</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Int#output&#34;&gt;call base_simple3#Int#output&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Int#output&#34;&gt;output&lt;&#47;a&gt;&lt;span&gt;&lt;&#47;span&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">output</span>
+</span><span class="line" id="L54"><span class="nc_i popupable" title="call base_simple3#Object#foo" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Object#foo&#34;&gt;call base_simple3#Object#foo&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Object#foo&#34;&gt;foo&lt;&#47;a&gt;&lt;span&gt;&lt;&#47;span&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">foo</span>
+</span><span class="line" id="L55"><span class="nc_i popupable" title="call base_simple3#Object#bar" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Object#bar&#34;&gt;call base_simple3#Object#bar&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Object#bar&#34;&gt;bar&lt;&#47;a&gt;&lt;span&gt;(i: &lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;)&lt;&#47;span&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">bar</span><span>(</span><span class="nc_l popupable" title="Int" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">3</span><span>)</span>
+</span><span class="line" id="L56"><span class="nc_i popupable" title="call base_simple3#Object#baz" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Object#baz&#34;&gt;call base_simple3#Object#baz&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Object#baz&#34;&gt;baz&lt;&#47;a&gt;&lt;span&gt;: &lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">baz</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Int#output&#34;&gt;call base_simple3#Int#output&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Int#output&#34;&gt;output&lt;&#47;a&gt;&lt;span&gt;&lt;&#47;span&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">output</span>
 </span><span class="line" id="L57">
-</span><span class="line" id="L58"><span class="nc_k">var</span> <span class="nc_v nc_i popupable" title="a: A" data-content="&lt;div&gt;&lt;b&gt;local var&lt;/b&gt; &lt;span&gt;a:&lt;a href=&quot;base_simple3.html#base_simple3#A&quot;&gt;A&lt;/a&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">a</span> <span>=</span> <span class="nc_k">new</span> <span class="nc_t popupable" title="A" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#A&quot;&gt;A&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#A&quot;&gt;A&lt;/a&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">A</span>
-</span><span class="line" id="L59"><span class="nc_v nc_i popupable" title="a: A" data-content="&lt;div&gt;&lt;b&gt;local var&lt;/b&gt; &lt;span&gt;a:&lt;a href=&quot;base_simple3.html#base_simple3#A&quot;&gt;A&lt;/a&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">a</span><span>.</span><span class="nc_i popupable" title="call base_simple3#A#run" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#A#run&quot;&gt;call base_simple3#A#run&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#A#run&quot;&gt;run&lt;/a&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">run</span>
+</span><span class="line" id="L58"><span class="nc_k">var</span> <span class="nc_v nc_i popupable" title="a: A" data-content="&lt;div&gt;&lt;b&gt;local var&lt;&#47;b&gt; &lt;span&gt;a:&lt;a href=&#34;base_simple3.html#base_simple3#A&#34;&gt;A&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">a</span> <span>=</span> <span class="nc_k">new</span> <span class="nc_t popupable" title="A" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#A&#34;&gt;A&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#A&#34;&gt;A&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">A</span>
+</span><span class="line" id="L59"><span class="nc_v nc_i popupable" title="a: A" data-content="&lt;div&gt;&lt;b&gt;local var&lt;&#47;b&gt; &lt;span&gt;a:&lt;a href=&#34;base_simple3.html#base_simple3#A&#34;&gt;A&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">a</span><span>.</span><span class="nc_i popupable" title="call base_simple3#A#run" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#A#run&#34;&gt;call base_simple3#A#run&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#A#run&#34;&gt;run&lt;&#47;a&gt;&lt;span&gt;&lt;&#47;span&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">run</span>
 </span><span class="line" id="L60">
-</span><span class="line" id="L61"><span class="nc_k">var</span> <span class="nc_v nc_i popupable" title="b: B" data-content="&lt;div&gt;&lt;b&gt;local var&lt;/b&gt; &lt;span&gt;b:&lt;a href=&quot;base_simple3.html#base_simple3#B&quot;&gt;B&lt;/a&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">b</span> <span>=</span> <span class="nc_k">new</span> <span class="nc_t popupable" title="B" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#B&quot;&gt;B&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#B&quot;&gt;B&lt;/a&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">B</span><span>(</span><span class="nc_l popupable" title="Int" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">8</span><span>)</span>
-</span><span class="line" id="L62"><span class="nc_v nc_i popupable" title="b: B" data-content="&lt;div&gt;&lt;b&gt;local var&lt;/b&gt; &lt;span&gt;b:&lt;a href=&quot;base_simple3.html#base_simple3#B&quot;&gt;B&lt;/a&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">b</span><span>.</span><span class="nc_i popupable" title="call base_simple3#B#run" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#B#run&quot;&gt;call base_simple3#B#run&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#B#run&quot;&gt;run&lt;/a&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">run</span>
+</span><span class="line" id="L61"><span class="nc_k">var</span> <span class="nc_v nc_i popupable" title="b: B" data-content="&lt;div&gt;&lt;b&gt;local var&lt;&#47;b&gt; &lt;span&gt;b:&lt;a href=&#34;base_simple3.html#base_simple3#B&#34;&gt;B&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">b</span> <span>=</span> <span class="nc_k">new</span> <span class="nc_t popupable" title="B" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#B&#34;&gt;B&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#B&#34;&gt;B&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">B</span><span>(</span><span class="nc_l popupable" title="Int" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">8</span><span>)</span>
+</span><span class="line" id="L62"><span class="nc_v nc_i popupable" title="b: B" data-content="&lt;div&gt;&lt;b&gt;local var&lt;&#47;b&gt; &lt;span&gt;b:&lt;a href=&#34;base_simple3.html#base_simple3#B&#34;&gt;B&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">b</span><span>.</span><span class="nc_i popupable" title="call base_simple3#B#run" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#B#run&#34;&gt;call base_simple3#B#run&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#B#run&#34;&gt;run&lt;&#47;a&gt;&lt;span&gt;&lt;&#47;span&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">run</span>
 </span><span class="line" id="L63">
-</span><span class="line" id="L64"><span class="nc_k">var</span> <span class="nc_v nc_i popupable" title="c: C" data-content="&lt;div&gt;&lt;b&gt;local var&lt;/b&gt; &lt;span&gt;c:&lt;a href=&quot;base_simple3.html#base_simple3#C&quot;&gt;C&lt;/a&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">c</span> <span>=</span> <span class="nc_k">new</span> <span class="nc_t popupable" title="C" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#C&quot;&gt;C&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#C&quot;&gt;C&lt;/a&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">C</span><span>(</span><span class="nc_l popupable" title="Int" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">9</span><span>)</span>
-</span><span class="line" id="L65"><span class="nc_v nc_i popupable" title="c: C" data-content="&lt;div&gt;&lt;b&gt;local var&lt;/b&gt; &lt;span&gt;c:&lt;a href=&quot;base_simple3.html#base_simple3#C&quot;&gt;C&lt;/a&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">c</span><span>.</span><span class="nc_i popupable" title="call base_simple3#C#val1" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#C#val1&quot;&gt;call base_simple3#C#val1&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#C#val1&quot;&gt;val1&lt;/a&gt;&lt;span&gt;: &lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">val1</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Int#output&quot;&gt;call base_simple3#Int#output&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Int#output&quot;&gt;output&lt;/a&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">output</span>
-</span><span class="line" id="L66"><span class="nc_v nc_i popupable" title="c: C" data-content="&lt;div&gt;&lt;b&gt;local var&lt;/b&gt; &lt;span&gt;c:&lt;a href=&quot;base_simple3.html#base_simple3#C&quot;&gt;C&lt;/a&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">c</span><span>.</span><span class="nc_i popupable" title="call base_simple3#C#val2" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#C#val2&quot;&gt;call base_simple3#C#val2&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#C#val2&quot;&gt;val2&lt;/a&gt;&lt;span&gt;: &lt;a href=&quot;base_simple3.html#base_simple3#Int&quot;&gt;Int&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">val2</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="&lt;a href=&quot;base_simple3.html#base_simple3#Int#output&quot;&gt;call base_simple3#Int#output&lt;/a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;/b&gt; &lt;span&gt;&lt;a href=&quot;base_simple3.html#base_simple3#Int#output&quot;&gt;output&lt;/a&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;" data-toggle="popover">output</span>
+</span><span class="line" id="L64"><span class="nc_k">var</span> <span class="nc_v nc_i popupable" title="c: C" data-content="&lt;div&gt;&lt;b&gt;local var&lt;&#47;b&gt; &lt;span&gt;c:&lt;a href=&#34;base_simple3.html#base_simple3#C&#34;&gt;C&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">c</span> <span>=</span> <span class="nc_k">new</span> <span class="nc_t popupable" title="C" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#C&#34;&gt;C&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#C&#34;&gt;C&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">C</span><span>(</span><span class="nc_l popupable" title="Int" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;class&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">9</span><span>)</span>
+</span><span class="line" id="L65"><span class="nc_v nc_i popupable" title="c: C" data-content="&lt;div&gt;&lt;b&gt;local var&lt;&#47;b&gt; &lt;span&gt;c:&lt;a href=&#34;base_simple3.html#base_simple3#C&#34;&gt;C&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">c</span><span>.</span><span class="nc_i popupable" title="call base_simple3#C#val1" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#C#val1&#34;&gt;call base_simple3#C#val1&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#C#val1&#34;&gt;val1&lt;&#47;a&gt;&lt;span&gt;: &lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">val1</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Int#output&#34;&gt;call base_simple3#Int#output&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Int#output&#34;&gt;output&lt;&#47;a&gt;&lt;span&gt;&lt;&#47;span&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">output</span>
+</span><span class="line" id="L66"><span class="nc_v nc_i popupable" title="c: C" data-content="&lt;div&gt;&lt;b&gt;local var&lt;&#47;b&gt; &lt;span&gt;c:&lt;a href=&#34;base_simple3.html#base_simple3#C&#34;&gt;C&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">c</span><span>.</span><span class="nc_i popupable" title="call base_simple3#C#val2" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#C#val2&#34;&gt;call base_simple3#C#val2&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#C#val2&#34;&gt;val2&lt;&#47;a&gt;&lt;span&gt;: &lt;a href=&#34;base_simple3.html#base_simple3#Int&#34;&gt;Int&lt;&#47;a&gt;&lt;&#47;span&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">val2</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="&lt;a href=&#34;base_simple3.html#base_simple3#Int#output&#34;&gt;call base_simple3#Int#output&lt;&#47;a&gt;" data-content="&lt;div&gt;&lt;b&gt;call&lt;&#47;b&gt; &lt;span&gt;&lt;a href=&#34;base_simple3.html#base_simple3#Int#output&#34;&gt;output&lt;&#47;a&gt;&lt;span&gt;&lt;&#47;span&gt;&lt;&#47;span&gt;&lt;br&#47;&gt;&lt;&#47;div&gt;" data-toggle="popover">output</span>
 </span></span><span class="line" id="L67"><span></span></span></span>
\ No newline at end of file
index 3fd326a..4ad3dc3 100644 (file)
@@ -1,3 +1 @@
-Usage: nitls [OPTION]... <file.nit|directory>...
-Lists the projects and/or paths of Nit sources files.
-Use --help for help
+UNDEFINED
index 435add1..accb0d6 100644 (file)
@@ -1,2 +1,5 @@
-base_simple3 (base_simple3.nit)
-project1 (project1)
+\e[1mbase_simple3\e[m (\e[33mbase_simple3.nit\e[m)
+project1 (\e[33mproject1\e[m)
+|--\e[1mmodule1\e[m (\e[33mproject1/module1.nit\e[m)
+|--\e[1mmodule2\e[m (\e[33mproject1/module2.nit\e[m)
+`--\e[1mproject1\e[m (\e[33mproject1/project1.nit\e[m)
index 813821d..accb0d6 100644 (file)
@@ -1,4 +1,5 @@
-base_simple3 (base_simple3.nit)
-`--base_simple3 (base_simple3.nit)
-project1 (project1)
-`--project1 (project1/project1.nit)
+\e[1mbase_simple3\e[m (\e[33mbase_simple3.nit\e[m)
+project1 (\e[33mproject1\e[m)
+|--\e[1mmodule1\e[m (\e[33mproject1/module1.nit\e[m)
+|--\e[1mmodule2\e[m (\e[33mproject1/module2.nit\e[m)
+`--\e[1mproject1\e[m (\e[33mproject1/project1.nit\e[m)
index d1705b7..accb0d6 100644 (file)
@@ -1,6 +1,5 @@
-base_simple3 (base_simple3.nit)
-`--base_simple3 (base_simple3.nit)
-project1 (project1)
-|--module1 (project1/module1.nit)
-|--module2 (project1/module2.nit)
-`--project1 (project1/project1.nit)
+\e[1mbase_simple3\e[m (\e[33mbase_simple3.nit\e[m)
+project1 (\e[33mproject1\e[m)
+|--\e[1mmodule1\e[m (\e[33mproject1/module1.nit\e[m)
+|--\e[1mmodule2\e[m (\e[33mproject1/module2.nit\e[m)
+`--\e[1mproject1\e[m (\e[33mproject1/project1.nit\e[m)
index eb37699..f54c342 100644 (file)
@@ -1,2 +1,4 @@
-base_simple3/base_simple3 (base_simple3.nit)
-project1/project1 (project1/project1.nit)
+base_simple3/\e[1mbase_simple3\e[m (\e[33mbase_simple3.nit\e[m)
+project1/\e[1mmodule1\e[m (\e[33mproject1/module1.nit\e[m)
+project1/\e[1mmodule2\e[m (\e[33mproject1/module2.nit\e[m)
+project1/\e[1mproject1\e[m (\e[33mproject1/project1.nit\e[m)
index af28f14..e248df6 100644 (file)
@@ -41,7 +41,7 @@ Bool [
 Object -> Bool [dir=back arrowtail=open style=dashed];
 
 Float [
- label = "{Float||}"
+ label = "{Float||+ is_approx(other: Float, precision: Float): Bool\l}"
 ]
 Numeric -> Float [dir=back arrowtail=open style=dashed];
 
index 6189897..9a7b30f 100644 (file)
@@ -41,7 +41,7 @@ Bool [
 Object -> Bool [dir=back arrowtail=open style=dashed];
 
 Float [
- label = "{Float||}"
+ label = "{Float||+ is_approx(other: Float, precision: Float): Bool\l}"
 ]
 Numeric -> Float [dir=back arrowtail=open style=dashed];
 
index 12b7181..b00e342 100644 (file)
@@ -2,7 +2,7 @@ test_nitunit.nit:20,1--22,0: ERROR: nitunit.test_nitunit.test_nitunit::X.<class>
 
 test_nitunit.nit:23,2--25,0: FAILURE: nitunit.test_nitunit.test_nitunit::X.test_nitunit::X::foo (in .nitunit/test_nitunit-3.nit): .nitunit/test_nitunit-3.nit:5,8--27: Error: Method or variable 'undefined_identifier' unknown in Sys.
 
-test_test_nitunit.nit:36,2--40,4: ERROR: test_foo1 (in file .nitunit/test_test_nitunit_TestX_test_foo1.nit): Runtime error: Assert failed (test_test_nitunit.nit:39)
+test_test_nitunit.nit:36,2--40,4: ERROR: test_foo1 (in file .nitunit/gen_test_test_nitunit.nit): Runtime error: Assert failed (test_test_nitunit.nit:39)
 
 DocUnits:
 Entities: 27; Documented ones: 3; With nitunits: 3; Failures: 2
@@ -11,8 +11,8 @@ TestSuites:
 Class suites: 1; Test Cases: 3; Failures: 1
 <testsuites><testsuite package="test_nitunit"><testcase classname="nitunit.test_nitunit.&lt;module&gt;" name="&lt;module&gt;"><system-err></system-err><system-out>assert true
 </system-out></testcase><testcase classname="nitunit.test_nitunit.test_nitunit::X" name="&lt;class&gt;"><system-err></system-err><system-out>assert false
-</system-out><error message="Runtime error: Assert failed (.nitunit/test_nitunit-2.nit:5)
+</system-out><error message="Runtime error: Assert failed (.nitunit&#47;test_nitunit-2.nit:5)
 "></error></testcase><testcase classname="nitunit.test_nitunit.test_nitunit::X" name="test_nitunit::X::foo"><system-err></system-err><system-out>assert undefined_identifier
-</system-out><failure message=".nitunit/test_nitunit-3.nit:5,8--27: Error: Method or variable 'undefined_identifier' unknown in Sys.
+</system-out><failure message=".nitunit&#47;test_nitunit-3.nit:5,8--27: Error: Method or variable &#39;undefined_identifier&#39; unknown in Sys.
 "></failure></testcase></testsuite><testsuite package="test_test_nitunit"><testcase classname="nitunit.test_test_nitunit.test_test_nitunit::TestX" name="test_test_nitunit::TestX::test_foo"><system-err></system-err><system-out>out</system-out></testcase><testcase classname="nitunit.test_test_nitunit.test_test_nitunit::TestX" name="test_test_nitunit::TestX::test_foo1"><system-err></system-err><system-out>out</system-out><error message="Runtime error: Assert failed (test_test_nitunit.nit:39)
 "></error></testcase><testcase classname="nitunit.test_test_nitunit.test_test_nitunit::TestX" name="test_test_nitunit::TestX::test_foo2"><system-err></system-err><system-out>out</system-out></testcase></testsuite></testsuites>
\ No newline at end of file
diff --git a/tests/sav/nitunit_args5.res b/tests/sav/nitunit_args5.res
new file mode 100644 (file)
index 0000000..7019ad0
--- /dev/null
@@ -0,0 +1,11 @@
+DocUnits:
+DocUnits Success
+Entities: 6; Documented ones: 5; With nitunits: 3; Failures: 0
+
+TestSuites:
+No test cases found
+Class suites: 0; Test Cases: 0; Failures: 0
+<testsuites><testsuite package="test_doc2"><testcase classname="nitunit.test_doc2.standard::kernel::Object" name="test_doc2::Object::foo1"><system-err></system-err><system-out>assert true # tested
+</system-out></testcase><testcase classname="nitunit.test_doc2.standard::kernel::Object" name="test_doc2::Object::foo2"><system-err></system-err><system-out>assert true # tested
+</system-out></testcase><testcase classname="nitunit.test_doc2.standard::kernel::Object" name="test_doc2::Object::foo3"><system-err></system-err><system-out>assert true # tested
+</system-out></testcase></testsuite><testsuite></testsuite></testsuites>
\ No newline at end of file
index aa38be4..9ce343f 100644 (file)
@@ -1 +1 @@
-Runtime error: Assert failed (../lib/c.nit:64)
+Runtime error: Assert failed (../lib/c.nit:45)
index 95d7a74..79d181f 100644 (file)
@@ -1,2 +1,2 @@
-Runtime error: Assert failed (../lib/c.nit:57)
+Runtime error: Assert failed (../lib/c.nit:37)
 0
index 95d7a74..79d181f 100644 (file)
@@ -1,2 +1,2 @@
-Runtime error: Assert failed (../lib/c.nit:57)
+Runtime error: Assert failed (../lib/c.nit:37)
 0
index 3bb984c..47d5416 100644 (file)
@@ -1,4 +1,4 @@
-Runtime error: Assert failed (../lib/c.nit:56)
+Runtime error: Assert failed (../lib/c.nit:36)
 0
 0
 1
index 23ae886..593a60f 100644 (file)
@@ -22,9 +22,9 @@ border-color: red;
 h5 {font-weight:bold;}
 .nitcode a { color: inherit; cursor:pointer; }
 .nitcode .popupable:hover { text-decoration: underline; cursor:help; } /* underline titles */
-pre.nitcode .foldable { display: block } /* for block productions*/
-pre.nitcode .line{ display: block } /* for lines */
-pre.nitcode .line:hover{ background-color: #FFFFE0; } /* current line */
+.nitcode .foldable { display: block } /* for block productions*/
+.nitcode .line{ display: block } /* for lines */
+.nitcode .line:hover{ background-color: #FFFFE0; } /* current line */
 .nitcode :target { background-color: #FFF3C2 } /* target highlight*/
 /* lexical raw tokens. independent of usage or semantic: */
 .nitcode .nc_c { color: gray; font-style: italic; } /* comment */
@@ -62,7 +62,7 @@ bullet</li></ul><pre class="nitcode"><span class="nitcode"><span class="line" id
 </span><span class="line" id="L2"><span class="nc_i">block</span>
 </span><span class="line" id="L3"><span></span></span></span></pre><p>a first example</p><pre class="nitcode"><span class="nitcode"><span class="line" id="L1"><span class="nc_k">assert</span> <span class="nc_l">1</span> <span class="nc_o">+</span> <span class="nc_l">1</span> <span class="nc_o">==</span> <span class="nc_l">2</span>
 </span><span class="line" id="L2"><span></span></span></span></pre><p>and a last example to illustrate the <code class="nitcode"><span class="nitcode"><span class="line" id="L1"><span class="nc_i">to_s</span><span></span></span></span></code> method on <code class="nitcode"><span class="nitcode"><span class="line" id="L1"><span class="nc_t">A</span><span></span></span></span></code>.</p><pre class="nitcode"><span class="nitcode"><span class="line" id="L1"><span class="nc_k">var</span> <span class="nc_i">a</span> <span>=</span> <span class="nc_k">new</span> <span class="nc_t">A</span>
-</span><span class="line" id="L2"><span class="nc_k">assert</span> <span class="nc_i">a</span><span>.</span><span class="nc_i">to_s</span> <span class="nc_o">==</span> <span class="nc_s">&quot;A&quot;</span>
+</span><span class="line" id="L2"><span class="nc_k">assert</span> <span class="nc_i">a</span><span>.</span><span class="nc_i">to_s</span> <span class="nc_o">==</span> <span class="nc_s">&#34;A&#34;</span>
 </span><span class="line" id="L3"><span></span></span></span></pre></div><script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
 <script src="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
 <script>$(".popupable").popover({html:true, placement:'top'})/*initialize bootstrap popover*/</script></body></html>
\ No newline at end of file
diff --git a/tests/sav/test_docdown_args2.res b/tests/sav/test_docdown_args2.res
new file mode 100644 (file)
index 0000000..51196e3
--- /dev/null
@@ -0,0 +1,65 @@
+<html><head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
+<style type="text/css">
+code {margin: 0 2px;
+padding: 0px 5px;
+border: 1px solid #ddd;
+background-color: #f8f8f8;
+border-radius: 3px;}
+pre {
+background-color: #f8f8f8;
+border: 1px solid #ddd;
+font-size: 13px;
+line-height: 19px;
+overflow: auto;
+padding: 6px 6px;
+border-radius: 3px;
+}
+.rawcode[title] {
+border-color: red;
+}
+h5 {font-weight:bold;}
+.nitcode a { color: inherit; cursor:pointer; }
+.nitcode .popupable:hover { text-decoration: underline; cursor:help; } /* underline titles */
+.nitcode .foldable { display: block } /* for block productions*/
+.nitcode .line{ display: block } /* for lines */
+.nitcode .line:hover{ background-color: #FFFFE0; } /* current line */
+.nitcode :target { background-color: #FFF3C2 } /* target highlight*/
+/* lexical raw tokens. independent of usage or semantic: */
+.nitcode .nc_c { color: gray; font-style: italic; } /* comment */
+.nitcode .nc_d { color: #3D8127; font-style: italic; } /* documentation comments */
+.nitcode .nc_k { font-weight: bold; } /* keyword */
+.nitcode .nc_o {} /* operator */
+.nitcode .nc_i {} /* standard identifier */
+.nitcode .nc_t { color: #445588; font-weight: bold; } /* type/class identifier */
+.nitcode .nc_a { color: #445588; font-style: italic; } /* old style attribute identifier */
+.nitcode .nc_l { color: #009999; } /* char and number literal */
+.nitcode .nc_s { color: #8F1546; } /* string literal */
+/* syntactic token usage. added because of their position in the AST */
+.nitcode .nc_ast { color: blue; } /* assert label */
+.nitcode .nc_la { color: blue; } /* break/continue label */
+.nitcode .nc_m { color: #445588; } /* module name */
+/* syntactic groups */
+.nitcode .nc_def { font-weight: bold; color: blue; } /* name used in a definition */
+  .nitcode .nc_def.nc_a { color: blue; } /* name used in a attribute definition */
+  .nitcode .nc_def.nc_t { color: blue; } /* name used in a class or vt definition */
+.nitcode .nc_ss { color: #9E6BEB; } /* superstrings */
+.nitcode .nc_cdef {} /* A whole class definition */
+.nitcode .nc_pdef {} /* A whole property definition */
+/* semantic token usage */
+.nitcode .nc_v { font-style: italic; } /* local variable or parameter */
+.nitcode .nc_vt { font-style: italic; } /* virtual type or formal type */
+
+.nitcode .nc_error { border: 1px red solid;} /* not used */
+.popover { max-width: 800px !important; }
+
+</style>
+</head><body><h3 id='test_doc2'>module test_doc2</h1><h5 id='test_doc2#Object#foo1'>prop test_doc2#Object#foo1</h3><div class="nitdoc"><p class="synopsys">Test code</p><pre class="nitcode"><span class="nitcode"><span class="line" id="L1"><span class="nc_k">assert</span> <span class="nc_k">true</span> <span># tested
+</span></span><span class="line" id="L2"><span></span></span></span></pre></div><h5 id='test_doc2#Object#foo2'>prop test_doc2#Object#foo2</h3><div class="nitdoc"><p class="synopsys">Test code</p><pre class="nitcode"><span class="nitcode"><span class="line" id="L1"><span class="nc_k">assert</span> <span class="nc_k">true</span> <span># tested
+</span></span><span class="line" id="L2"><span></span></span></span></pre></div><h5 id='test_doc2#Object#foo3'>prop test_doc2#Object#foo3</h3><div class="nitdoc"><p class="synopsys">Test code</p><pre class="nitcode"><span class="nitcode"><span class="line" id="L1"><span class="nc_k">assert</span> <span class="nc_k">true</span> <span># tested
+</span></span><span class="line" id="L2"><span></span></span></span></pre></div><h5 id='test_doc2#Object#foo4'>prop test_doc2#Object#foo4</h3><div class="nitdoc"><p class="synopsys">Test code</p><pre class="rawcode">assert false # not tested (and not highlighted)
+</pre></div><h5 id='test_doc2#Object#foo5'>prop test_doc2#Object#foo5</h3><div class="nitdoc"><p class="synopsys">Test code</p><pre class="nitcode"><span class="nitcode"><span class="line" id="L1"><span class="nc_k">assert</span> <span class="nc_k">false</span> <span># not tested (but highlighted)
+</span></span><span class="line" id="L2"><span></span></span></span></pre></div><script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
+<script src="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
+<script>$(".popupable").popover({html:true, placement:'top'})/*initialize bootstrap popover*/</script></body></html>
\ No newline at end of file
diff --git a/tests/sav/test_ffi_objc_types_and_callbacks.res b/tests/sav/test_ffi_objc_types_and_callbacks.res
new file mode 100644 (file)
index 0000000..9eb68aa
--- /dev/null
@@ -0,0 +1,2 @@
+From Objective-C: 2468 12.340000 1234
+From Nit: 2468 12.34 1234
diff --git a/tests/sav/test_glsl_validation.res b/tests/sav/test_glsl_validation.res
new file mode 100644 (file)
index 0000000..7cb202c
--- /dev/null
@@ -0,0 +1,6 @@
+test_glsl_validation.nit:24,0: Shader error on 'binding' : not supported for this version or the enabled extensions 
+test_glsl_validation.nit:24,0: Shader error on 'binding' : requires uniform or buffer storage qualifier 
+test_glsl_validation.nit:24,0: Shader error on 'binding' : requires block, or sampler/image, or atomic-counter type 
+test_glsl_validation.nit:28,0: Shader error on 'gl_FragColor' : undeclared identifier 
+test_glsl_validation.nit:28,0: Shader error on 'assign' :  cannot convert from 'mediump 4-component vector of float' to 'float'
+test_glsl_validation.nit:29,0: Shader error on 'b' : undeclared identifier 
index ba6c5fe..b05a1b7 100644 (file)
@@ -1,4 +1,4 @@
-Runtime error: Cast failed. Expected `E`, got `Bool` (../lib/standard/collection/array.nit:782)
+Runtime error: Cast failed. Expected `E`, got `Bool` (../lib/standard/collection/array.nit:785)
 NativeString
 N
 Nit
diff --git a/tests/sav/test_ropes_buffer_add_overflow.res b/tests/sav/test_ropes_buffer_add_overflow.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/sav/test_ropes_buffer_clear.res b/tests/sav/test_ropes_buffer_clear.res
new file mode 100644 (file)
index 0000000..951dbb9
--- /dev/null
@@ -0,0 +1,2 @@
+23
+3
diff --git a/tests/sav/test_ropes_buffer_reverse.res b/tests/sav/test_ropes_buffer_reverse.res
new file mode 100644 (file)
index 0000000..eb577ea
--- /dev/null
@@ -0,0 +1,2 @@
+//
+yxxxx
diff --git a/tests/sav/test_ropes_buffer_to_s.res b/tests/sav/test_ropes_buffer_to_s.res
new file mode 100644 (file)
index 0000000..5bff6e1
--- /dev/null
@@ -0,0 +1,7 @@
+`clear` and `append`: abcd
+`clear` and `add`: ab
+`add` at `maxlen + 1`: c
+`append` up to `maxlen + 1`: ab
+`reverse`: xyz
+`upper`: foo
+`lower`: BAR
diff --git a/tests/test_doc2.nit b/tests/test_doc2.nit
new file mode 100644 (file)
index 0000000..70e266c
--- /dev/null
@@ -0,0 +1,46 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Test code
+#
+#     assert true # tested
+fun foo1 do end
+
+# Test code
+#
+# ~~~~
+# assert true # tested
+# ~~~~
+fun foo2 do end
+
+# Test code
+#
+# ~~~~nit
+# assert true # tested
+# ~~~~
+fun foo3 do end
+
+# Test code
+#
+# ~~~~raw
+# assert false # not tested (and not highlighted)
+# ~~~~
+fun foo4 do end
+
+# Test code
+#
+# ~~~~nitish
+# assert false # not tested (but highlighted)
+# ~~~~
+fun foo5 do end
diff --git a/tests/test_docdown.args b/tests/test_docdown.args
new file mode 100644 (file)
index 0000000..b10baba
--- /dev/null
@@ -0,0 +1,2 @@
+test_doc.nit
+test_doc2.nit
diff --git a/tests/test_ffi_objc_types_and_callbacks.nit b/tests/test_ffi_objc_types_and_callbacks.nit
new file mode 100644 (file)
index 0000000..9b0cd1c
--- /dev/null
@@ -0,0 +1,35 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+module test_ffi_objc_types_and_callbacks
+
+fun foo(i: Int, f: Float, s: String)
+import bar, String.to_cstring, Int.+ in "ObjC" `{
+       char *cstr = String_to_cstring(s);
+
+       long ii = Int__plus(i, i);
+
+       printf("From Objective-C: %ld %f %s\n", ii, f, cstr);
+
+       Object_bar(recv, ii, f, s);
+`}
+
+fun bar(i: Int, f: Float, s: String)
+do
+       print "From Nit: {i} {f} {s}"
+end
+
+foo(1234, 12.34, "1234")
diff --git a/tests/test_glsl_validation.nit b/tests/test_glsl_validation.nit
new file mode 100644 (file)
index 0000000..950ef7b
--- /dev/null
@@ -0,0 +1,33 @@
+# 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 glesv2
+
+var shader = """
+#version 300 es
+precision mediump float;
+
+in vec4 v_color;
+in vec2 v_texCoord;
+uniform sampler2D vTex;
+layout(binding = 0) out vec4 outColor;
+
+void main()
+{
+       gl_FragColor = v_color * texture(vTex, v_texCoord);
+       b;
+}
+""" @ glsl_fragment_shader
+
+shader.to_s # silences the "never read warning"
diff --git a/tests/test_markdown.args b/tests/test_markdown.args
deleted file mode 100644 (file)
index 79d2034..0000000
+++ /dev/null
@@ -1 +0,0 @@
-test_doc.nit
index 7ee824c..5575949 100644 (file)
@@ -83,7 +83,7 @@ print "{kate["name"].to_s} IS LOVED BY {kate.in_nodes("LOVES").first["name"].to_
 
 print "\n# Test lazy\n"
 
-client = new Neo4jClient("http://localhost:7474")
+client = new Neo4jClient("http://localhost:7474/")
 assert client.is_ok
 
 # Read Andres
diff --git a/tests/test_ropes_buffer_add_overflow.nit b/tests/test_ropes_buffer_add_overflow.nit
new file mode 100644 (file)
index 0000000..6482b0e
--- /dev/null
@@ -0,0 +1,28 @@
+# 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.
+
+# Checks that `RopeBuffer.add` does not makes the internal buffer overflow.
+#
+# Note: In order to help repoducibility, this test read an private attribute of
+# the buffer.
+module test_ropes_buffer_add_overflow
+
+import standard
+intrude import ropes
+
+var buffer = new RopeBuffer
+
+buffer.append("x" * maxlen)
+buffer.add 'y'
+assert buffer.rpos <= maxlen else print "{buffer.rpos} > {maxlen}"
diff --git a/tests/test_ropes_buffer_clear.nit b/tests/test_ropes_buffer_clear.nit
new file mode 100644 (file)
index 0000000..eba364e
--- /dev/null
@@ -0,0 +1,37 @@
+# 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.
+
+# Checks if `RopeBuffer.clear` actually reset everything.
+module test_ropes_buffer_clear
+
+import standard
+
+var buffer = new RopeBuffer
+
+buffer.append "1"
+# Force to flush the internal buffer, so that all the internal positions will be
+# set to a non-zero value.
+buffer.append("?" * (maxlen + 1))
+buffer.clear
+buffer.append "23"
+print buffer
+
+buffer = new RopeBuffer
+buffer.append "12"
+# Force to flush the internal buffer, so that all the internal positions will be
+# set to a non-zero value.
+buffer.append("?" * (maxlen + 1))
+buffer.clear
+buffer.append "3"
+print buffer
diff --git a/tests/test_ropes_buffer_reverse.nit b/tests/test_ropes_buffer_reverse.nit
new file mode 100644 (file)
index 0000000..e4a0170
--- /dev/null
@@ -0,0 +1,29 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+module test_ropes_buffer_reverse
+
+import standard
+
+redef fun maxlen do return 3
+
+var buffer = new RopeBuffer
+
+buffer.reverse
+print "/{buffer}/"
+
+buffer.append("x" * (maxlen + 1))
+buffer.add 'y'
+buffer.reverse
+print buffer.to_s
diff --git a/tests/test_ropes_buffer_to_s.nit b/tests/test_ropes_buffer_to_s.nit
new file mode 100644 (file)
index 0000000..cc8eb4f
--- /dev/null
@@ -0,0 +1,79 @@
+# 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.
+
+# Checks the immutability of the strings returned by `RopeBuffer.to_s`.
+module test_ropes_buffer_to_s
+
+import standard
+
+# Note: In this sort of test, never print the string more than once: the string
+# itself may cache an flatten representation of itself when `print` calls `to_s`
+# on it. For example, the original bug that motivated the writting of the
+# present test got unoticed until we tried to edit the buffer **before**
+# outputting `s`.
+
+var buffer = new RopeBuffer
+var s: String
+
+sys.stdout.write "`clear` and `append`: "
+buffer.append "abcd"
+s = buffer.to_s
+buffer.clear
+buffer.append "ef"
+print s
+
+sys.stdout.write "`clear` and `add`: "
+buffer.clear
+buffer.add 'a'
+buffer.add 'b'
+s = buffer.to_s
+buffer.clear
+buffer.add 'c'
+print s
+
+sys.stdout.write "`add` at `maxlen + 1`: "
+buffer.clear
+buffer.add 'c'
+s = buffer.to_s
+buffer.append("*" * (maxlen -1))
+buffer.add 'x'
+print s
+
+sys.stdout.write "`append` up to `maxlen + 1`: "
+buffer.clear
+buffer.append "ab"
+s = buffer.to_s
+buffer.append("*" * (maxlen -1))
+print s
+
+sys.stdout.write "`reverse`: "
+buffer.clear
+buffer.append "xyz"
+s = buffer.to_s
+buffer.reverse
+print s
+
+sys.stdout.write "`upper`: "
+buffer.clear
+buffer.append "foo"
+s = buffer.to_s
+buffer.upper
+print s
+
+sys.stdout.write "`lower`: "
+buffer.clear
+buffer.append "BAR"
+s = buffer.to_s
+buffer.lower
+print s
index 8720ca3..fb3eb86 100755 (executable)
@@ -32,8 +32,6 @@ JAVA_HOME=$(dirname $(dirname $(readlink -f $(which javac))))
 paths=`echo $JAVA_HOME/jre/lib/*/{client,server}/`
 paths=($paths) 
 JNI_LIB_PATH=${paths[0]}
-echo $JAVA_HOME
-echo $JNI_LIB_PATH
 shopt -u nullglob
 
 outdir="out"
@@ -318,6 +316,14 @@ need_skip()
                echo >>$xml "<testcase classname='`xmlesc "$3"`' name='`xmlesc "$2"`' `timestamp`><skipped/></testcase>"
                return 0
        fi
+
+       # Skip by OS
+       os_skip_file=`uname`.skip
+       if test -e $os_skip_file && echo "$1" | grep -f "$os_skip_file"; then
+               echo "=> $2: [skip os]"
+               echo >>$xml "<testcase classname='`xmlesc "$3"`' name='`xmlesc "$2"`' `timestamp`><skipped/></testcase>"
+               return 0
+       fi
        return 1
 }