From: Jean Privat Date: Thu, 6 Nov 2014 01:02:17 +0000 (-0500) Subject: Merge: Use new constructors X-Git-Tag: v0.6.11~54 X-Git-Url: http://nitlanguage.org?hp=23f2216f93cdc233c6dc1d396967f1cc9a046e78 Merge: Use new constructors Since c_src is regenerated, new-style-constructors are available in lib and tools. Most of the job was to just to remove useless `init` and sometime adding a `noinit` or a default value to attributes. Pull-Request: #866 Reviewed-by: Lucas Bajolet Reviewed-by: Alexis Laferrière --- diff --git a/Makefile b/Makefile index 636e0ce..326d49b 100644 --- a/Makefile +++ b/Makefile @@ -66,12 +66,16 @@ doc/nitc/index.html: bin/nitdoc bin/nitls --piwik-tracker "pratchett.info.uqam.ca/piwik/" \ --piwik-site-id "3" +man: + $(MAKE) -C share/man + clean: rm -rf -- .nit_compile 2> /dev/null || true rm -rf -- doc/stdlib doc/nitc || true cd c_src; make clean cd src; make clean cd tests; make clean + cd share/man; make clean for m in $(PROGS); do \ $(MAKE) clean -C "$$m"; \ test -d $$m/.nit_compile && rm -r $$m/.nit_compile; \ diff --git a/README b/README index 2b4e22e..adb80ee 100644 --- a/README +++ b/README @@ -17,6 +17,7 @@ Some Nit features: Requirement: * gcc http://gcc.gnu.org/ + * pkg-config http://www.freedesktop.org/wiki/Software/pkg-config/ * ccache http://ccache.samba.org/ to improve recompilation * libgc-dev http://www.hpl.hp.com/personal/Hans_Boehm/gc/ * graphviz http://www.graphviz.org/ to enable graphes with the nitdoc tool @@ -24,7 +25,7 @@ Requirement: Those are available in most linux distributions - # sudo apt-get install build-essential ccache libgc-dev graphviz libunwind + # sudo apt-get install build-essential ccache libgc-dev graphviz libunwind pkg-config Important files and directory: diff --git a/bin/nitc b/bin/nitc index cd4c670..42b4e3a 100755 --- a/bin/nitc +++ b/bin/nitc @@ -1,4 +1,3 @@ #!/bin/bash -self=`readlink /proc/$$/fd/255` -dir=`dirname "$self"` +dir=`dirname "$BASH_SOURCE"` exec "$dir/nitg" "$@" diff --git a/c_src/Makefile b/c_src/Makefile index db97fe4..b7e5ab8 100644 --- a/c_src/Makefile +++ b/c_src/Makefile @@ -3,7 +3,7 @@ CXX = ccache c++ CFLAGS = -g -O2 -Wno-unused-value -Wno-switch CINCL = LDFLAGS ?= -LDLIBS ?= -lm -lgc +LDLIBS ?= -lm NEED_LIBUNWIND := YesPlease uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') @@ -296,41 +296,49 @@ nith.types.4.o: nith.types.4.c nith.types.5.o: nith.types.5.c $(CC) $(CFLAGS) $(CINCL) -c -o nith.types.5.o nith.types.5.c +# does pkg-config exists? +ifneq ($(shell which pkg-config >/dev/null; echo $$?), 0) +$(error "Command `pkg-config` not found. Please install it") +endif +# Check for library bdw-gc +ifneq ($(shell pkg-config --exists 'bdw-gc'; echo $$?), 0) +$(error "pkg-config: package bdw-gc is not found.") +endif time_nit.extern.o: time_nit.c - $(CC) $(CFLAGS) -c -o time_nit.extern.o time_nit.c + $(CC) $(CFLAGS) -c -o time_nit.extern.o time_nit.c string_nit.extern.o: string_nit.c - $(CC) $(CFLAGS) -c -o string_nit.extern.o string_nit.c + $(CC) $(CFLAGS) -c -o string_nit.extern.o string_nit.c file_nit.extern.o: file_nit.c - $(CC) $(CFLAGS) -c -o file_nit.extern.o file_nit.c + $(CC) $(CFLAGS) -c -o file_nit.extern.o file_nit.c exec_nit.extern.o: exec_nit.c - $(CC) $(CFLAGS) -c -o exec_nit.extern.o exec_nit.c + $(CC) $(CFLAGS) -c -o exec_nit.extern.o exec_nit.c tables_nit.extern.o: tables_nit.c - $(CC) $(CFLAGS) -c -o tables_nit.extern.o tables_nit.c + $(CC) $(CFLAGS) -c -o tables_nit.extern.o tables_nit.c c_functions_hash.extern.o: c_functions_hash.c - $(CC) $(CFLAGS) -c -o c_functions_hash.extern.o c_functions_hash.c + $(CC) $(CFLAGS) -c -o c_functions_hash.extern.o c_functions_hash.c gc_chooser.extern.o: gc_chooser.c - $(CC) $(CFLAGS) -DWITH_LIBGC -c -o gc_chooser.extern.o gc_chooser.c + $(CC) $(CFLAGS) -DWITH_LIBGC `pkg-config --cflags bdw-gc` -c -o gc_chooser.extern.o gc_chooser.c string._ffi.extern.o: string._ffi.c - $(CC) $(CFLAGS) -c -o string._ffi.extern.o string._ffi.c + $(CC) $(CFLAGS) -c -o string._ffi.extern.o string._ffi.c string._nitni.extern.o: string._nitni.c - $(CC) $(CFLAGS) -c -o string._nitni.extern.o string._nitni.c + $(CC) $(CFLAGS) -c -o string._nitni.extern.o string._nitni.c kernel._ffi.extern.o: kernel._ffi.c - $(CC) $(CFLAGS) -c -o kernel._ffi.extern.o kernel._ffi.c + $(CC) $(CFLAGS) -c -o kernel._ffi.extern.o kernel._ffi.c kernel._nitni.extern.o: kernel._nitni.c - $(CC) $(CFLAGS) -c -o kernel._nitni.extern.o kernel._nitni.c + $(CC) $(CFLAGS) -c -o kernel._nitni.extern.o kernel._nitni.c nitg: nith.classes.1.o nith.classes.2.o nith.classes.3.o nith.classes.4.o nith.classes.5.o nith.classes.6.o nith.classes.7.o nith.main.1.o nith.sep.1.o modelize_property.sep.1.o modelize_property.sep.2.o modelize_class.sep.1.o modelbuilder.sep.1.o model.sep.1.o model.sep.2.o mmodule.sep.1.o location.sep.1.o string.sep.1.o string.sep.2.o math.sep.1.o kernel.sep.1.o abstract_collection.sep.1.o list.sep.1.o array.sep.1.o sorter.sep.1.o hash_collection.sep.1.o environ.sep.1.o file.sep.1.o stream.sep.1.o string_search.sep.1.o time.sep.1.o exec.sep.1.o mproject.sep.1.o model_base.sep.1.o more_collections.sep.1.o poset.sep.1.o mdoc.sep.1.o phase.sep.1.o toolcontext.sep.1.o opts.sep.1.o version.sep.1.o template.sep.1.o parser.sep.1.o parser.sep.2.o parser.sep.3.o parser.sep.4.o parser.sep.5.o parser.sep.6.o parser_prod.sep.1.o parser_prod.sep.2.o parser_prod.sep.3.o parser_prod.sep.4.o parser_prod.sep.5.o lexer.sep.1.o parser_nodes.sep.1.o lexer_work.sep.1.o tables.sep.1.o parser_work.sep.1.o annotation.sep.1.o literal.sep.1.o transform.sep.1.o astbuilder.sep.1.o typing.sep.1.o typing.sep.2.o typing.sep.3.o local_var_init.sep.1.o flow.sep.1.o scope.sep.1.o astvalidation.sep.1.o auto_super_init.sep.1.o rapid_type_analysis.sep.1.o separate_erasure_compiler.sep.1.o separate_erasure_compiler.sep.2.o separate_compiler.sep.1.o separate_compiler.sep.2.o separate_compiler.sep.3.o separate_compiler.sep.4.o separate_compiler.sep.5.o abstract_compiler.sep.1.o abstract_compiler.sep.2.o abstract_compiler.sep.3.o abstract_compiler.sep.4.o abstract_compiler.sep.5.o platform.sep.1.o c_tools.sep.1.o mixin.sep.1.o coloring.sep.1.o nith.types.1.o nith.types.2.o nith.types.3.o nith.types.4.o nith.types.5.o time_nit.extern.o string_nit.extern.o file_nit.extern.o exec_nit.extern.o tables_nit.extern.o c_functions_hash.extern.o gc_chooser.extern.o string._ffi.extern.o string._nitni.extern.o kernel._ffi.extern.o kernel._nitni.extern.o - $(CC) $(LDFLAGS) -o nitg nith.classes.1.o nith.classes.2.o nith.classes.3.o nith.classes.4.o nith.classes.5.o nith.classes.6.o nith.classes.7.o nith.main.1.o nith.sep.1.o modelize_property.sep.1.o modelize_property.sep.2.o modelize_class.sep.1.o modelbuilder.sep.1.o model.sep.1.o model.sep.2.o mmodule.sep.1.o location.sep.1.o string.sep.1.o string.sep.2.o math.sep.1.o kernel.sep.1.o abstract_collection.sep.1.o list.sep.1.o array.sep.1.o sorter.sep.1.o hash_collection.sep.1.o environ.sep.1.o file.sep.1.o stream.sep.1.o string_search.sep.1.o time.sep.1.o exec.sep.1.o mproject.sep.1.o model_base.sep.1.o more_collections.sep.1.o poset.sep.1.o mdoc.sep.1.o phase.sep.1.o toolcontext.sep.1.o opts.sep.1.o version.sep.1.o template.sep.1.o parser.sep.1.o parser.sep.2.o parser.sep.3.o parser.sep.4.o parser.sep.5.o parser.sep.6.o parser_prod.sep.1.o parser_prod.sep.2.o parser_prod.sep.3.o parser_prod.sep.4.o parser_prod.sep.5.o lexer.sep.1.o parser_nodes.sep.1.o lexer_work.sep.1.o tables.sep.1.o parser_work.sep.1.o annotation.sep.1.o literal.sep.1.o transform.sep.1.o astbuilder.sep.1.o typing.sep.1.o typing.sep.2.o typing.sep.3.o local_var_init.sep.1.o flow.sep.1.o scope.sep.1.o astvalidation.sep.1.o auto_super_init.sep.1.o rapid_type_analysis.sep.1.o separate_erasure_compiler.sep.1.o separate_erasure_compiler.sep.2.o separate_compiler.sep.1.o separate_compiler.sep.2.o separate_compiler.sep.3.o separate_compiler.sep.4.o separate_compiler.sep.5.o abstract_compiler.sep.1.o abstract_compiler.sep.2.o abstract_compiler.sep.3.o abstract_compiler.sep.4.o abstract_compiler.sep.5.o platform.sep.1.o c_tools.sep.1.o mixin.sep.1.o coloring.sep.1.o nith.types.1.o nith.types.2.o nith.types.3.o nith.types.4.o nith.types.5.o time_nit.extern.o string_nit.extern.o file_nit.extern.o exec_nit.extern.o tables_nit.extern.o c_functions_hash.extern.o gc_chooser.extern.o string._ffi.extern.o string._nitni.extern.o kernel._ffi.extern.o kernel._nitni.extern.o $(LDLIBS) + $(CC) $(LDFLAGS) -o nitg nith.classes.1.o nith.classes.2.o nith.classes.3.o nith.classes.4.o nith.classes.5.o nith.classes.6.o nith.classes.7.o nith.main.1.o nith.sep.1.o modelize_property.sep.1.o modelize_property.sep.2.o modelize_class.sep.1.o modelbuilder.sep.1.o model.sep.1.o model.sep.2.o mmodule.sep.1.o location.sep.1.o string.sep.1.o string.sep.2.o math.sep.1.o kernel.sep.1.o abstract_collection.sep.1.o list.sep.1.o array.sep.1.o sorter.sep.1.o hash_collection.sep.1.o environ.sep.1.o file.sep.1.o stream.sep.1.o string_search.sep.1.o time.sep.1.o exec.sep.1.o mproject.sep.1.o model_base.sep.1.o more_collections.sep.1.o poset.sep.1.o mdoc.sep.1.o phase.sep.1.o toolcontext.sep.1.o opts.sep.1.o version.sep.1.o template.sep.1.o parser.sep.1.o parser.sep.2.o parser.sep.3.o parser.sep.4.o parser.sep.5.o parser.sep.6.o parser_prod.sep.1.o parser_prod.sep.2.o parser_prod.sep.3.o parser_prod.sep.4.o parser_prod.sep.5.o lexer.sep.1.o parser_nodes.sep.1.o lexer_work.sep.1.o tables.sep.1.o parser_work.sep.1.o annotation.sep.1.o literal.sep.1.o transform.sep.1.o astbuilder.sep.1.o typing.sep.1.o typing.sep.2.o typing.sep.3.o local_var_init.sep.1.o flow.sep.1.o scope.sep.1.o astvalidation.sep.1.o auto_super_init.sep.1.o rapid_type_analysis.sep.1.o separate_erasure_compiler.sep.1.o separate_erasure_compiler.sep.2.o separate_compiler.sep.1.o separate_compiler.sep.2.o separate_compiler.sep.3.o separate_compiler.sep.4.o separate_compiler.sep.5.o abstract_compiler.sep.1.o abstract_compiler.sep.2.o abstract_compiler.sep.3.o abstract_compiler.sep.4.o abstract_compiler.sep.5.o platform.sep.1.o c_tools.sep.1.o mixin.sep.1.o coloring.sep.1.o nith.types.1.o nith.types.2.o nith.types.3.o nith.types.4.o nith.types.5.o time_nit.extern.o string_nit.extern.o file_nit.extern.o exec_nit.extern.o tables_nit.extern.o c_functions_hash.extern.o gc_chooser.extern.o string._ffi.extern.o string._nitni.extern.o kernel._ffi.extern.o kernel._nitni.extern.o $(LDLIBS) `pkg-config --libs bdw-gc` clean: rm nith.classes.1.o nith.classes.2.o nith.classes.3.o nith.classes.4.o nith.classes.5.o nith.classes.6.o nith.classes.7.o nith.main.1.o nith.sep.1.o modelize_property.sep.1.o modelize_property.sep.2.o modelize_class.sep.1.o modelbuilder.sep.1.o model.sep.1.o model.sep.2.o mmodule.sep.1.o location.sep.1.o string.sep.1.o string.sep.2.o math.sep.1.o kernel.sep.1.o abstract_collection.sep.1.o list.sep.1.o array.sep.1.o sorter.sep.1.o hash_collection.sep.1.o environ.sep.1.o file.sep.1.o stream.sep.1.o string_search.sep.1.o time.sep.1.o exec.sep.1.o mproject.sep.1.o model_base.sep.1.o more_collections.sep.1.o poset.sep.1.o mdoc.sep.1.o phase.sep.1.o toolcontext.sep.1.o opts.sep.1.o version.sep.1.o template.sep.1.o parser.sep.1.o parser.sep.2.o parser.sep.3.o parser.sep.4.o parser.sep.5.o parser.sep.6.o parser_prod.sep.1.o parser_prod.sep.2.o parser_prod.sep.3.o parser_prod.sep.4.o parser_prod.sep.5.o lexer.sep.1.o parser_nodes.sep.1.o lexer_work.sep.1.o tables.sep.1.o parser_work.sep.1.o annotation.sep.1.o literal.sep.1.o transform.sep.1.o astbuilder.sep.1.o typing.sep.1.o typing.sep.2.o typing.sep.3.o local_var_init.sep.1.o flow.sep.1.o scope.sep.1.o astvalidation.sep.1.o auto_super_init.sep.1.o rapid_type_analysis.sep.1.o separate_erasure_compiler.sep.1.o separate_erasure_compiler.sep.2.o separate_compiler.sep.1.o separate_compiler.sep.2.o separate_compiler.sep.3.o separate_compiler.sep.4.o separate_compiler.sep.5.o abstract_compiler.sep.1.o abstract_compiler.sep.2.o abstract_compiler.sep.3.o abstract_compiler.sep.4.o abstract_compiler.sep.5.o platform.sep.1.o c_tools.sep.1.o mixin.sep.1.o coloring.sep.1.o nith.types.1.o nith.types.2.o nith.types.3.o nith.types.4.o nith.types.5.o time_nit.extern.o string_nit.extern.o file_nit.extern.o exec_nit.extern.o tables_nit.extern.o c_functions_hash.extern.o gc_chooser.extern.o string._ffi.extern.o string._nitni.extern.o kernel._ffi.extern.o kernel._nitni.extern.o 2>/dev/null diff --git a/c_src/abstract_compiler.sep.1.c b/c_src/abstract_compiler.sep.1.c index da573c6..e9e6534 100644 --- a/c_src/abstract_compiler.sep.1.c +++ b/c_src/abstract_compiler.sep.1.c @@ -3498,8 +3498,8 @@ abstract_compiler__AbstractCompiler__build_c_to_nit_bindings(var_compiler); /* D if (varonce26) { var27 = varonce26; } else { -var28 = "-DWITH_LIBGC"; -var29 = 12; +var28 = "-DWITH_LIBGC `pkg-config --cflags bdw-gc` "; +var29 = 42; var30 = string__NativeString__to_s_with_length(var28, var29); var27 = var30; varonce26 = var27; @@ -5985,8 +5985,8 @@ varonce65 = var66; if (varonce70) { var71 = varonce70; } else { -var72 = "\nLDFLAGS ?= \nLDLIBS ?= -lm -lgc "; -var73 = 33; +var72 = "\nLDFLAGS ?= \nLDLIBS ?= -lm `pkg-config --libs bdw-gc`"; +var73 = 55; var74 = string__NativeString__to_s_with_length(var72, var73); var71 = var74; varonce70 = var71; diff --git a/c_src/nith.mk b/c_src/nith.mk index db97fe4..b7e5ab8 100644 --- a/c_src/nith.mk +++ b/c_src/nith.mk @@ -3,7 +3,7 @@ CXX = ccache c++ CFLAGS = -g -O2 -Wno-unused-value -Wno-switch CINCL = LDFLAGS ?= -LDLIBS ?= -lm -lgc +LDLIBS ?= -lm NEED_LIBUNWIND := YesPlease uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') @@ -296,41 +296,49 @@ nith.types.4.o: nith.types.4.c nith.types.5.o: nith.types.5.c $(CC) $(CFLAGS) $(CINCL) -c -o nith.types.5.o nith.types.5.c +# does pkg-config exists? +ifneq ($(shell which pkg-config >/dev/null; echo $$?), 0) +$(error "Command `pkg-config` not found. Please install it") +endif +# Check for library bdw-gc +ifneq ($(shell pkg-config --exists 'bdw-gc'; echo $$?), 0) +$(error "pkg-config: package bdw-gc is not found.") +endif time_nit.extern.o: time_nit.c - $(CC) $(CFLAGS) -c -o time_nit.extern.o time_nit.c + $(CC) $(CFLAGS) -c -o time_nit.extern.o time_nit.c string_nit.extern.o: string_nit.c - $(CC) $(CFLAGS) -c -o string_nit.extern.o string_nit.c + $(CC) $(CFLAGS) -c -o string_nit.extern.o string_nit.c file_nit.extern.o: file_nit.c - $(CC) $(CFLAGS) -c -o file_nit.extern.o file_nit.c + $(CC) $(CFLAGS) -c -o file_nit.extern.o file_nit.c exec_nit.extern.o: exec_nit.c - $(CC) $(CFLAGS) -c -o exec_nit.extern.o exec_nit.c + $(CC) $(CFLAGS) -c -o exec_nit.extern.o exec_nit.c tables_nit.extern.o: tables_nit.c - $(CC) $(CFLAGS) -c -o tables_nit.extern.o tables_nit.c + $(CC) $(CFLAGS) -c -o tables_nit.extern.o tables_nit.c c_functions_hash.extern.o: c_functions_hash.c - $(CC) $(CFLAGS) -c -o c_functions_hash.extern.o c_functions_hash.c + $(CC) $(CFLAGS) -c -o c_functions_hash.extern.o c_functions_hash.c gc_chooser.extern.o: gc_chooser.c - $(CC) $(CFLAGS) -DWITH_LIBGC -c -o gc_chooser.extern.o gc_chooser.c + $(CC) $(CFLAGS) -DWITH_LIBGC `pkg-config --cflags bdw-gc` -c -o gc_chooser.extern.o gc_chooser.c string._ffi.extern.o: string._ffi.c - $(CC) $(CFLAGS) -c -o string._ffi.extern.o string._ffi.c + $(CC) $(CFLAGS) -c -o string._ffi.extern.o string._ffi.c string._nitni.extern.o: string._nitni.c - $(CC) $(CFLAGS) -c -o string._nitni.extern.o string._nitni.c + $(CC) $(CFLAGS) -c -o string._nitni.extern.o string._nitni.c kernel._ffi.extern.o: kernel._ffi.c - $(CC) $(CFLAGS) -c -o kernel._ffi.extern.o kernel._ffi.c + $(CC) $(CFLAGS) -c -o kernel._ffi.extern.o kernel._ffi.c kernel._nitni.extern.o: kernel._nitni.c - $(CC) $(CFLAGS) -c -o kernel._nitni.extern.o kernel._nitni.c + $(CC) $(CFLAGS) -c -o kernel._nitni.extern.o kernel._nitni.c nitg: nith.classes.1.o nith.classes.2.o nith.classes.3.o nith.classes.4.o nith.classes.5.o nith.classes.6.o nith.classes.7.o nith.main.1.o nith.sep.1.o modelize_property.sep.1.o modelize_property.sep.2.o modelize_class.sep.1.o modelbuilder.sep.1.o model.sep.1.o model.sep.2.o mmodule.sep.1.o location.sep.1.o string.sep.1.o string.sep.2.o math.sep.1.o kernel.sep.1.o abstract_collection.sep.1.o list.sep.1.o array.sep.1.o sorter.sep.1.o hash_collection.sep.1.o environ.sep.1.o file.sep.1.o stream.sep.1.o string_search.sep.1.o time.sep.1.o exec.sep.1.o mproject.sep.1.o model_base.sep.1.o more_collections.sep.1.o poset.sep.1.o mdoc.sep.1.o phase.sep.1.o toolcontext.sep.1.o opts.sep.1.o version.sep.1.o template.sep.1.o parser.sep.1.o parser.sep.2.o parser.sep.3.o parser.sep.4.o parser.sep.5.o parser.sep.6.o parser_prod.sep.1.o parser_prod.sep.2.o parser_prod.sep.3.o parser_prod.sep.4.o parser_prod.sep.5.o lexer.sep.1.o parser_nodes.sep.1.o lexer_work.sep.1.o tables.sep.1.o parser_work.sep.1.o annotation.sep.1.o literal.sep.1.o transform.sep.1.o astbuilder.sep.1.o typing.sep.1.o typing.sep.2.o typing.sep.3.o local_var_init.sep.1.o flow.sep.1.o scope.sep.1.o astvalidation.sep.1.o auto_super_init.sep.1.o rapid_type_analysis.sep.1.o separate_erasure_compiler.sep.1.o separate_erasure_compiler.sep.2.o separate_compiler.sep.1.o separate_compiler.sep.2.o separate_compiler.sep.3.o separate_compiler.sep.4.o separate_compiler.sep.5.o abstract_compiler.sep.1.o abstract_compiler.sep.2.o abstract_compiler.sep.3.o abstract_compiler.sep.4.o abstract_compiler.sep.5.o platform.sep.1.o c_tools.sep.1.o mixin.sep.1.o coloring.sep.1.o nith.types.1.o nith.types.2.o nith.types.3.o nith.types.4.o nith.types.5.o time_nit.extern.o string_nit.extern.o file_nit.extern.o exec_nit.extern.o tables_nit.extern.o c_functions_hash.extern.o gc_chooser.extern.o string._ffi.extern.o string._nitni.extern.o kernel._ffi.extern.o kernel._nitni.extern.o - $(CC) $(LDFLAGS) -o nitg nith.classes.1.o nith.classes.2.o nith.classes.3.o nith.classes.4.o nith.classes.5.o nith.classes.6.o nith.classes.7.o nith.main.1.o nith.sep.1.o modelize_property.sep.1.o modelize_property.sep.2.o modelize_class.sep.1.o modelbuilder.sep.1.o model.sep.1.o model.sep.2.o mmodule.sep.1.o location.sep.1.o string.sep.1.o string.sep.2.o math.sep.1.o kernel.sep.1.o abstract_collection.sep.1.o list.sep.1.o array.sep.1.o sorter.sep.1.o hash_collection.sep.1.o environ.sep.1.o file.sep.1.o stream.sep.1.o string_search.sep.1.o time.sep.1.o exec.sep.1.o mproject.sep.1.o model_base.sep.1.o more_collections.sep.1.o poset.sep.1.o mdoc.sep.1.o phase.sep.1.o toolcontext.sep.1.o opts.sep.1.o version.sep.1.o template.sep.1.o parser.sep.1.o parser.sep.2.o parser.sep.3.o parser.sep.4.o parser.sep.5.o parser.sep.6.o parser_prod.sep.1.o parser_prod.sep.2.o parser_prod.sep.3.o parser_prod.sep.4.o parser_prod.sep.5.o lexer.sep.1.o parser_nodes.sep.1.o lexer_work.sep.1.o tables.sep.1.o parser_work.sep.1.o annotation.sep.1.o literal.sep.1.o transform.sep.1.o astbuilder.sep.1.o typing.sep.1.o typing.sep.2.o typing.sep.3.o local_var_init.sep.1.o flow.sep.1.o scope.sep.1.o astvalidation.sep.1.o auto_super_init.sep.1.o rapid_type_analysis.sep.1.o separate_erasure_compiler.sep.1.o separate_erasure_compiler.sep.2.o separate_compiler.sep.1.o separate_compiler.sep.2.o separate_compiler.sep.3.o separate_compiler.sep.4.o separate_compiler.sep.5.o abstract_compiler.sep.1.o abstract_compiler.sep.2.o abstract_compiler.sep.3.o abstract_compiler.sep.4.o abstract_compiler.sep.5.o platform.sep.1.o c_tools.sep.1.o mixin.sep.1.o coloring.sep.1.o nith.types.1.o nith.types.2.o nith.types.3.o nith.types.4.o nith.types.5.o time_nit.extern.o string_nit.extern.o file_nit.extern.o exec_nit.extern.o tables_nit.extern.o c_functions_hash.extern.o gc_chooser.extern.o string._ffi.extern.o string._nitni.extern.o kernel._ffi.extern.o kernel._nitni.extern.o $(LDLIBS) + $(CC) $(LDFLAGS) -o nitg nith.classes.1.o nith.classes.2.o nith.classes.3.o nith.classes.4.o nith.classes.5.o nith.classes.6.o nith.classes.7.o nith.main.1.o nith.sep.1.o modelize_property.sep.1.o modelize_property.sep.2.o modelize_class.sep.1.o modelbuilder.sep.1.o model.sep.1.o model.sep.2.o mmodule.sep.1.o location.sep.1.o string.sep.1.o string.sep.2.o math.sep.1.o kernel.sep.1.o abstract_collection.sep.1.o list.sep.1.o array.sep.1.o sorter.sep.1.o hash_collection.sep.1.o environ.sep.1.o file.sep.1.o stream.sep.1.o string_search.sep.1.o time.sep.1.o exec.sep.1.o mproject.sep.1.o model_base.sep.1.o more_collections.sep.1.o poset.sep.1.o mdoc.sep.1.o phase.sep.1.o toolcontext.sep.1.o opts.sep.1.o version.sep.1.o template.sep.1.o parser.sep.1.o parser.sep.2.o parser.sep.3.o parser.sep.4.o parser.sep.5.o parser.sep.6.o parser_prod.sep.1.o parser_prod.sep.2.o parser_prod.sep.3.o parser_prod.sep.4.o parser_prod.sep.5.o lexer.sep.1.o parser_nodes.sep.1.o lexer_work.sep.1.o tables.sep.1.o parser_work.sep.1.o annotation.sep.1.o literal.sep.1.o transform.sep.1.o astbuilder.sep.1.o typing.sep.1.o typing.sep.2.o typing.sep.3.o local_var_init.sep.1.o flow.sep.1.o scope.sep.1.o astvalidation.sep.1.o auto_super_init.sep.1.o rapid_type_analysis.sep.1.o separate_erasure_compiler.sep.1.o separate_erasure_compiler.sep.2.o separate_compiler.sep.1.o separate_compiler.sep.2.o separate_compiler.sep.3.o separate_compiler.sep.4.o separate_compiler.sep.5.o abstract_compiler.sep.1.o abstract_compiler.sep.2.o abstract_compiler.sep.3.o abstract_compiler.sep.4.o abstract_compiler.sep.5.o platform.sep.1.o c_tools.sep.1.o mixin.sep.1.o coloring.sep.1.o nith.types.1.o nith.types.2.o nith.types.3.o nith.types.4.o nith.types.5.o time_nit.extern.o string_nit.extern.o file_nit.extern.o exec_nit.extern.o tables_nit.extern.o c_functions_hash.extern.o gc_chooser.extern.o string._ffi.extern.o string._nitni.extern.o kernel._ffi.extern.o kernel._nitni.extern.o $(LDLIBS) `pkg-config --libs bdw-gc` clean: rm nith.classes.1.o nith.classes.2.o nith.classes.3.o nith.classes.4.o nith.classes.5.o nith.classes.6.o nith.classes.7.o nith.main.1.o nith.sep.1.o modelize_property.sep.1.o modelize_property.sep.2.o modelize_class.sep.1.o modelbuilder.sep.1.o model.sep.1.o model.sep.2.o mmodule.sep.1.o location.sep.1.o string.sep.1.o string.sep.2.o math.sep.1.o kernel.sep.1.o abstract_collection.sep.1.o list.sep.1.o array.sep.1.o sorter.sep.1.o hash_collection.sep.1.o environ.sep.1.o file.sep.1.o stream.sep.1.o string_search.sep.1.o time.sep.1.o exec.sep.1.o mproject.sep.1.o model_base.sep.1.o more_collections.sep.1.o poset.sep.1.o mdoc.sep.1.o phase.sep.1.o toolcontext.sep.1.o opts.sep.1.o version.sep.1.o template.sep.1.o parser.sep.1.o parser.sep.2.o parser.sep.3.o parser.sep.4.o parser.sep.5.o parser.sep.6.o parser_prod.sep.1.o parser_prod.sep.2.o parser_prod.sep.3.o parser_prod.sep.4.o parser_prod.sep.5.o lexer.sep.1.o parser_nodes.sep.1.o lexer_work.sep.1.o tables.sep.1.o parser_work.sep.1.o annotation.sep.1.o literal.sep.1.o transform.sep.1.o astbuilder.sep.1.o typing.sep.1.o typing.sep.2.o typing.sep.3.o local_var_init.sep.1.o flow.sep.1.o scope.sep.1.o astvalidation.sep.1.o auto_super_init.sep.1.o rapid_type_analysis.sep.1.o separate_erasure_compiler.sep.1.o separate_erasure_compiler.sep.2.o separate_compiler.sep.1.o separate_compiler.sep.2.o separate_compiler.sep.3.o separate_compiler.sep.4.o separate_compiler.sep.5.o abstract_compiler.sep.1.o abstract_compiler.sep.2.o abstract_compiler.sep.3.o abstract_compiler.sep.4.o abstract_compiler.sep.5.o platform.sep.1.o c_tools.sep.1.o mixin.sep.1.o coloring.sep.1.o nith.types.1.o nith.types.2.o nith.types.3.o nith.types.4.o nith.types.5.o time_nit.extern.o string_nit.extern.o file_nit.extern.o exec_nit.extern.o tables_nit.extern.o c_functions_hash.extern.o gc_chooser.extern.o string._ffi.extern.o string._nitni.extern.o kernel._ffi.extern.o kernel._nitni.extern.o 2>/dev/null diff --git a/contrib/neo_doxygen/Makefile b/contrib/neo_doxygen/Makefile new file mode 100644 index 0000000..ed82923 --- /dev/null +++ b/contrib/neo_doxygen/Makefile @@ -0,0 +1,30 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +NITG=../../bin/nitg +NITG_FLAGS=--dir bin +NEO4J_DIR=/var/lib/neo4j + +.PHONY: bin reset-neo + +# Compile the tool. +bin: + mkdir -p bin + ../../bin/nitg --dir bin 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 diff --git a/contrib/neo_doxygen/gen-all.sh b/contrib/neo_doxygen/gen-all.sh new file mode 100755 index 0000000..b43ceab --- /dev/null +++ b/contrib/neo_doxygen/gen-all.sh @@ -0,0 +1,36 @@ +#! /bin/bash + +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# ./gen-all.sh +# +# Document all projects in the specified directory. +# +# Projects are direct sub-directories of the specified directory. +# Every project directory must contain a `.nx_config` file. +# 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 + # Note: gen-one.sh already prints errors. + ./gen-one.sh "$1" "$dir" || exit + fi + fi +done diff --git a/contrib/neo_doxygen/gen-one.sh b/contrib/neo_doxygen/gen-one.sh new file mode 100755 index 0000000..2621c8d --- /dev/null +++ b/contrib/neo_doxygen/gen-one.sh @@ -0,0 +1,38 @@ +#! /bin/bash + +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# ./gen-one.sh +# +# Document the project in the specified directory. +# +# The project name is the basename of the specified directory. +# The project directory must contain a `.nx_config` file. +# Also, the directory must include the Doxygen XML output in its `doxygen/xml` +# subdirectory. + +NEO_DOXYGEN="${PWD}/bin/neo_doxygen" +NX="${PWD}/../../bin/nx" +dir=$2 + +. sh-lib/errors.sh + +echo "$0: Documenting \"${dir##*/}\"..." +pushd "$dir" +try "$NEO_DOXYGEN" --src-lang "$1" --dest http://localhost:7474 -- "${dir##*/}" "$dir/doxygen/xml" +try echo "$0: [done] neo_doxygen" +try "$NX" neo doc "${dir##*/}" +try echo "$0: [done] nx" +popd diff --git a/contrib/neo_doxygen/sh-lib/errors.sh b/contrib/neo_doxygen/sh-lib/errors.sh new file mode 100644 index 0000000..dc5335b --- /dev/null +++ b/contrib/neo_doxygen/sh-lib/errors.sh @@ -0,0 +1,46 @@ +#! /bin/bash + +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Error handling. + +# The program’s name. +prog_name=$0 + +# Run the specified command and exit in case of error. +function try { + "$@" + local status=$? + if [ $status -ne 0 ]; then + >&2 echo "${prog_name}: Error: \`$1\` failed with exit status ${status}." + trace + exit "$status" + fi + return 0 +} + +# Print the stack trace. +function trace { + local frame=0 + >&2 caller $frame + local has_next=$? + while [ $has_next = 0 ]; do + ((frame++)); + >&2 caller $frame + has_next=$? + done + >&2 echo "---" + return 0 +} diff --git a/contrib/neo_doxygen/src/doxml/compounddef.nit b/contrib/neo_doxygen/src/doxml/compounddef.nit new file mode 100644 index 0000000..4cd42ca --- /dev/null +++ b/contrib/neo_doxygen/src/doxml/compounddef.nit @@ -0,0 +1,167 @@ +# 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. + +# `compounddef` element reading. +module doxml::compounddef + +import memberdef +import more_collections + +# Processes the content of a `compounddef` element. +class CompoundDefListener + super EntityDefListener + + var compound: Compound is writable, noinit + private var memberdef: MemberDefListener is noinit + private var param_listener: TypeParamListener is noinit + + # Default attributes for members in the current section. + private var member_defaults: MemberDefaults is noinit + + # For each section kind, default attributes for member in that section. + private var section_kinds: DefaultMap[String, MemberDefaults] is noinit + + + # Attributes of the current `` element. + + private var refid = "" + private var prot = "" + private var virt = "" + + + init do + super + var defaults = new MemberDefaults("public", false, false) + + memberdef = new MemberDefListener(reader, self) + param_listener = new TypeParamListener(reader, self) + + member_defaults = defaults + section_kinds = new DefaultMap[String, MemberDefaults](defaults) + + section_kinds["public-type"] = defaults + section_kinds["public-func"] = defaults + section_kinds["public-attrib"] = defaults + section_kinds["public-slot"] = defaults + defaults = new MemberDefaults("public", true, false) + section_kinds["public-static-func"] = defaults + section_kinds["public-static-attrib"] = defaults + + defaults = new MemberDefaults("protected", false, false) + section_kinds["protected-type"] = defaults + section_kinds["protected-func"] = defaults + section_kinds["protected-attrib"] = defaults + section_kinds["protected-slot"] = defaults + defaults = new MemberDefaults("protected", true, false) + section_kinds["protected-static-func"] = defaults + section_kinds["protected-static-attrib"] = defaults + + defaults = new MemberDefaults("package", false, false) + section_kinds["package-type"] = defaults + section_kinds["package-func"] = defaults + section_kinds["package-attrib"] = defaults + defaults = new MemberDefaults("package", true, false) + section_kinds["package-static-func"] = defaults + section_kinds["package-static-attrib"] = defaults + + defaults = new MemberDefaults("private", false, false) + section_kinds["private-type"] = defaults + section_kinds["private-func"] = defaults + section_kinds["private-attrib"] = defaults + section_kinds["private-slot"] = defaults + defaults = new MemberDefaults("private", true, false) + section_kinds["private-static-func"] = defaults + section_kinds["private-static-attrib"] = defaults + + defaults = new MemberDefaults("public", true, true) + section_kinds["related"] = defaults + section_kinds["user-defined"] = defaults + end + + 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 + 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", "") + prot = get_optional(atts, "prot", "") + virt = get_optional(atts, "virt", "") + text.listen_until(dox_uri, local_name) + else if "memberdef" == local_name then + read_member(atts) + else if local_name == "sectiondef" then + member_defaults = section_kinds[get_required(atts, "kind")] + if member_defaults.is_special then + super # TODO + end + else if "param" == local_name then + param_listener.listen_until(dox_uri, local_name) + else if "templateparamlist" != local_name then + super + end + end + + redef fun end_dox_element(local_name: String) do + if local_name == "compoundname" 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 + 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 + 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) + else + super + end + end + + private fun read_member(atts: Attributes) do + var kind = get_required(atts, "kind") + + create_member(kind) + memberdef.member.model_id = get_required(atts, "id") + memberdef.member.visibility = get_optional(atts, "prot", + member_defaults.visibility) + end + + private fun create_member(kind: String) do + if kind == "variable" then + memberdef.member = new Attribute(compound.graph) + else if kind == "function" then + memberdef.member = new Method(compound.graph) + else + memberdef.member = new UnknownMember(compound.graph) + noop.listen_until(dox_uri, "memberdef") + return + end + memberdef.listen_until(dox_uri, "memberdef") + end +end + +# Default attributes for members in the current section. +private class MemberDefaults + var visibility: String + var is_static: Bool + var is_special: Bool +end diff --git a/contrib/neo_doxygen/src/doxml/doc.nit b/contrib/neo_doxygen/src/doxml/doc.nit new file mode 100644 index 0000000..84a880d --- /dev/null +++ b/contrib/neo_doxygen/src/doxml/doc.nit @@ -0,0 +1,30 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Documentation reading. +module doxml::doc + +import listener + +# Processes documentation. +class DocListener + super TextListener + + var doc: JsonArray = new JsonArray is writable + + redef fun end_listening do + super + doc.add(to_s) + end +end diff --git a/contrib/neo_doxygen/src/doxml/doxml.nit b/contrib/neo_doxygen/src/doxml/doxml.nit new file mode 100644 index 0000000..280334a --- /dev/null +++ b/contrib/neo_doxygen/src/doxml/doxml.nit @@ -0,0 +1,89 @@ +# 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. + +# Doxygen’s XML documents reading. +module doxml + +import compounddef + +# Reader for XML documents whose the schema is `compound.xsd`. +class CompoundFileReader + super DoxmlListener + + # The project graph. + var model: ProjectGraph + + # The language-specific strategies to use. + redef var source_language: SourceLanguage + + private var reader: XMLReader = new XophonReader + private var compounddef: CompoundDefListener is noinit + private var noop: NoopListener is noinit + + init do + compounddef = new CompoundDefListener(reader, self) + noop = new NoopListener(reader, self) + end + + redef fun graph do return model + + # Read the document at the specified path. + fun read(path: String) do + reader.content_handler = self + reader.parse_file(path) + compounddef.compound = new UnknownCompound(model) + end + + redef fun start_dox_element(local_name: String, atts: Attributes) do + if local_name == "compounddef" then + read_compound(atts) + else if "doxygen" != local_name then + noop.listen_until(dox_uri, local_name) + end + end + + private fun read_compound(atts: Attributes) do + var kind = get_required(atts, "kind") + + create_compound(kind) + # TODO Make all values of `kind` and `visibility` compatible with the Nit meta-model. + if get_bool(atts, "final") then + kind = "final {kind}" + end + if get_bool(atts, "sealed") then + kind = "sealed {kind}" + end + if get_bool(atts, "abstract") then + kind = "abstract {kind}" + end + compounddef.compound.kind = kind + compounddef.compound.model_id = get_required(atts, "id") + compounddef.compound.visibility = get_optional(atts, "prot", "") + end + + private fun create_compound(kind: String) do + if kind == "file" then + compounddef.compound = new FileCompound(model) + else if kind == "namespace" then + compounddef.compound = new Namespace(model) + else if kind == "class" or kind == "interface" or kind == "enum" then + compounddef.compound = new ClassCompound(model) + else + compounddef.compound = new UnknownCompound(model) + noop.listen_until(dox_uri, "compounddef") + return + end + compounddef.listen_until(dox_uri, "compounddef") + end +end diff --git a/contrib/neo_doxygen/src/doxml/entitydef.nit b/contrib/neo_doxygen/src/doxml/entitydef.nit new file mode 100644 index 0000000..6c11a6c --- /dev/null +++ b/contrib/neo_doxygen/src/doxml/entitydef.nit @@ -0,0 +1,129 @@ +# 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. + +# Common SAX listeners for entity definitions. +module doxml::entitydef + +import doc + +# Processes the content of an entity definition. +abstract class EntityDefListener + super StackableListener + + # The inner `TextListener`. + protected var text: TextListener is noinit + + # The inner `DocListener`. + protected var doc: DocListener is noinit + + # The inner `NoopListener`. + protected var noop: NoopListener is noinit + + init do + super + text = new TextListener(reader, self) + doc = new DocListener(reader, self) + noop = new NoopListener(reader, self) + end + + # The current entity. + protected fun entity: Entity is abstract + + redef fun start_dox_element(local_name: String, atts: Attributes) do + if ["briefdescription", "detaileddescription", "inbodydescription"].has(local_name) then + doc.doc = entity.doc + doc.listen_until(dox_uri, local_name) + else if "location" == local_name then + entity.location = get_location(atts) + else + noop.listen_until(dox_uri, local_name) + end + end + + redef fun end_listening do + super + entity.put_in_graph + end + + # Parse the attributes of a `location` element. + protected fun get_location(atts: Attributes): Location do + var location = new Location + + location.path = atts.value_ns("", "bodyfile") or else atts.value_ns("", "file") + # Doxygen may indicate `[generated]`. + if "[generated]" == location.path then location.path = null + var line_start = atts.value_ns("", "bodystart") or else atts.value_ns("", "line") or else null + if line_start != null then location.line_start = line_start.to_i + var line_end = atts.value_ns("", "bodyend") + if line_end != null then location.line_end = line_end.to_i + var column_start = atts.value_ns("", "column") + if column_start != null then location.column_start = column_start.to_i + if location.line_start == location.line_end then + location.column_end = location.column_start + end + return location + end +end + +# Processes the content of a `` element. +abstract class ParamListener[T: Parameter] + super EntityDefListener + + # The current parameter. + var parameter: T is noinit + + private var type_listener: TypeListener is noinit + + init do + super + type_listener = new TypeListener(reader, self) + end + + redef fun entity do return parameter + + redef fun listen_until(uri, local_name) do + super + parameter = create_parameter + end + + # Create a new parameter. + protected fun create_parameter: T is abstract + + redef fun start_dox_element(local_name: String, atts: Attributes) do + if "declname" == local_name then + text.listen_until(dox_uri, local_name) + else if "type" == local_name then + type_listener.listen_until(dox_uri, local_name) + else + super + end + end + + redef fun end_dox_element(local_name: String) do + if "declname" == local_name then + parameter.name = text.to_s + else if "type" == local_name then + source_language.apply_parameter_type(parameter, type_listener.linked_text) + else + super + end + end +end + +# Processes the content of a `` element in a `` element. +class TypeParamListener + super ParamListener[TypeParameter] + + redef fun create_parameter do return new TypeParameter(graph) +end diff --git a/contrib/neo_doxygen/src/doxml/language_specific.nit b/contrib/neo_doxygen/src/doxml/language_specific.nit new file mode 100644 index 0000000..bbc6410 --- /dev/null +++ b/contrib/neo_doxygen/src/doxml/language_specific.nit @@ -0,0 +1,180 @@ +# 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. + +# Handle language-specific parts of the importation. +module doxml::language_specific + +import model + +# Various importation logics that depend on the project’s language. +abstract class SourceLanguage + + # Apply the information deduced from `type_text` to `member`. + # + # `type_text` is the content of the `` element. + fun apply_member_type(member: Member, type_text: RawType) do + if type_text["text"] != null then + member.static_type = type_text + end + end + + # Apply the information deduced from `type_text` to `parameter`. + # + # `type_text` is the content of the `` element. + fun apply_parameter_type(parameter: Parameter, type_text: RawType) do + if type_text["text"] != null then + parameter.static_type = type_text + end + end + + # Extract the specified keyword at the beginning of the specified text. + # + # If the keyword is at the beginning of the specified text, return `true` + # and remove the keyword. Else, return false. + # + # Used to extract some keywords that Doxygen puts in the type. + # + # class DummySource + # super JavaSource + # # + # fun test(text: LinkedText, keyword: String): Bool do + # return extract_keyword(text, keyword) + # end + # end + # # + # var text = new RawType(new ProjectGraph("")) + # var dummy = new DummySource + # var res: Bool + # # + # text.add_part("abstract final", "") + # res = dummy.test(text, "static") + # assert not res + # res = dummy.test(text, "abstract") + # assert res + # assert "final" == text["text"].as(JsonArray).first + # res = dummy.test(text, "final") + # assert res + # assert text["text"] == null + # res = dummy.test(text, "abstract") + # assert not res + protected fun extract_keyword(text: LinkedText, keyword: String): Bool do + var text_array = text["text"] + if text_array == null then return false + assert text_array isa JsonArray + if text_array.is_empty then return false + + var content = text_array.first.as(String).l_trim + var link = text.links.first + var found = false + + if link == null and content.has_prefix(keyword) then + if keyword.length == content.length then + content = "" + found = true + else if content.chars[keyword.length] <= ' ' then + content = content.substring_from(keyword.length).l_trim + found = true + end + if "" == content then + text.shift_part + else if found then + text.set_part(0, content, "") + end + end + return found + end + + # Extract the specified suffix in the specified text. + # + # If the suffix is at the end of the specified text, return `true` + # and remove the suffix. Else, return false. + # + # Used to extract stuff like `...` that Doxygen puts in the type. + # + # class DummySource + # super JavaSource + # # + # fun test(text: LinkedText, s: String): Bool do + # return extract_suffix(text, s) + # end + # end + # # + # var text = new RawType(new ProjectGraph("")) + # var dummy = new DummySource + # var res: Bool + # # + # text.add_part("Object...+++", "") + # res = dummy.test(text, "...") + # assert not res + # res = dummy.test(text, "+++") + # assert res + # assert "Object..." == text["text"].as(JsonArray).first + # res = dummy.test(text, "...") + # assert res + # assert "Object" == text["text"].as(JsonArray).first + protected fun extract_suffix(text: LinkedText, suffix: String): Bool do + var text_array = text["text"] + if text_array == null then return false + assert text_array isa JsonArray + if text_array.is_empty then return false + + 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 + if "" == content then + text.pop_part + else + text.set_part(0, content, "") + end + return true + else + return false + end + end +end + +# The default importation logics. +# +# Do nothing special. +class DefaultSource + super SourceLanguage +end + +# Importation logics for Java. +class JavaSource + super SourceLanguage + + redef fun apply_member_type(member, type_text) do + # 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") + # TODO final + # TODO void + # TODO Avoid using `RawType` when possible. Only use `RawType` as a fallback. + super + end + + redef fun apply_parameter_type(parmeter, type_text) do + # We assume that Doxygen do not put annotations in the type (it seems to + # be the case). + # TODO final + # TODO Avoid using `RawType` when possible. Only use `RawType` as a fallback. + parmeter.is_vararg = extract_suffix(type_text, "...") + super + end +end diff --git a/contrib/neo_doxygen/src/doxml/listener.nit b/contrib/neo_doxygen/src/doxml/listener.nit new file mode 100644 index 0000000..26de0d2 --- /dev/null +++ b/contrib/neo_doxygen/src/doxml/listener.nit @@ -0,0 +1,281 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Basic SAX listeners. +module doxml::listener + +import saxophonit +import model +import language_specific + +# Common abstractions for SAX listeners reading XML documents generated by Doxygen. +abstract class DoxmlListener + super ContentHandler + + # The locator setted by calling `document_locator=`. + protected var locator: nullable SAXLocator = null + + # The project graph. + fun graph: ProjectGraph is abstract + + # The language-specific strategies to use. + fun source_language: SourceLanguage is abstract + + redef fun document_locator=(locator: SAXLocator) do + self.locator = locator + end + + protected fun dox_uri: String do return "" + + redef fun start_element(uri: String, local_name: String, qname: String, + atts: Attributes) do + super + if uri != dox_uri then return # None of our business. + start_dox_element(local_name, atts) + end + + # Process the start of an element in the Doxygen’s namespace. + # + # See `ContentHandler.start_element` for the description of the parameters. + protected fun start_dox_element(local_name: String, atts: Attributes) do end + + redef fun end_element(uri: String, local_name: String, qname: String) do + super + if uri != dox_uri then return # None of our business. + end_dox_element(local_name) + end + + # Process the end of an element in the Doxygen’s namespace. + # + # See `ContentHandler.start_element` for the description of the parameters. + protected fun end_dox_element(local_name: String) do end + + protected fun get_bool(atts: Attributes, local_name: String): Bool do + return get_optional(atts, local_name, "no") == "yes" + end + + # Get the value of an optional attribute. + # + # Parameters: + # + # * `atts`: attribute list. + # * `local_name`: local name of the attribute. + # * `default`: value to return when the specified attribute is not found. + protected fun get_optional(atts: Attributes, local_name: String, + default: String): String do + return atts.value_ns(dox_uri, local_name) or else default + end + + # Get the value of an required attribute. + # + # Parameters: + # + # * `atts`: attribute list. + # * `local_name`: local name of the attribute. + protected fun get_required(atts: Attributes, local_name: String): String do + var value = atts.value_ns(dox_uri, local_name) + if value == null then + throw_error("The `{local_name}` attribute is required.") + return "" + else + return value + end + end + + redef fun end_document do + locator = null + end + + # Throw an error with the specified message by prepending the current location. + protected fun throw_error(message: String) do + var e: SAXParseException + + if locator != null then + e = new SAXParseException.with_locator(message, locator.as(not null)) + else + e = new SAXParseException(message) + end + e.throw + end +end + +# A `DoxmlListener` that read only a part of a document. +# +# Temporary redirect events to itself until it ends processing its part. +abstract class StackableListener + super DoxmlListener + + # The associated reader. + var reader: XMLReader + + # The parent listener. + var parent: DoxmlListener + + # Namespace’s IRI of the element at the root of the part to process. + private var root_uri: String = "" + + # Local name of the element at the root of the part to process. + private var root_local_name: String = "" + + # The number of open element of the same type than the root of the part to process. + private var depth = 0 + + # The project graph. + private var p_graph: ProjectGraph is noinit + + # The language-specific strategies to use. + private var p_source: SourceLanguage is noinit + + + init do + super + p_graph = parent.graph + p_source = parent.source_language + end + + redef fun graph do return p_graph + redef fun source_language do return p_source + + # Temporary redirect events to itself until the end of the specified element. + fun listen_until(uri: String, local_name: String) do + root_uri = uri + root_local_name = local_name + depth = 1 + reader.content_handler = self + locator = parent.locator + end + + redef fun start_element(uri: String, local_name: String, qname: String, + atts: Attributes) do + super + if uri == root_uri and local_name == root_local_name then + depth += 1 + end + end + + redef fun end_element(uri: String, local_name: String, qname: String) do + super + if uri == root_uri and local_name == root_local_name then + depth -= 1 + if depth <= 0 then + end_listening + parent.end_element(uri, local_name, qname) + end + end + end + + # Reset the reader’s listener to the parent. + fun end_listening do + reader.content_handler = parent + locator = null + end + + redef fun end_document do + end_listening + end +end + +# A SAX listener that skips any event except the end of the part to process. +# +# Used to skip an entire element. +class NoopListener + super StackableListener +end + +# Concatenates any text node found. +class TextListener + super StackableListener + + protected var buffer: Buffer = new FlatBuffer + private var sp: Bool = false + + redef fun listen_until(uri: String, local_name: String) do + buffer.clear + sp = false + super + end + + redef fun characters(str: String) do + if sp then + if buffer.length > 0 then buffer.append(" ") + sp = false + end + buffer.append(str) + end + + redef fun ignorable_whitespace(str: String) do + sp = true + end + + # Flush the buffer. + protected fun flush_buffer: String do + var s = buffer.to_s + + buffer.clear + sp = false + return s + end + + redef fun to_s do return buffer.to_s +end + +# Processes a content of type `linkedTextType`. +abstract class LinkedTextListener[T: LinkedText] + super TextListener + + # The read text. + var linked_text: T is noinit + + private var refid = "" + + # Create a new instance of `T`. + protected fun create_linked_text: T is abstract + + redef fun listen_until(uri: String, local_name: String) do + linked_text = create_linked_text + refid = "" + super + end + + redef fun start_dox_element(local_name: String, atts: Attributes) do + super + push_part + if "ref" == local_name then refid = get_required(atts, "refid") + end + + redef fun end_dox_element(local_name: String) do + super + push_part + if "ref" == local_name then refid = "" + end + + private fun push_part do + var s = flush_buffer + + if not s.is_empty then + linked_text.add_part(s, refid) + end + end + + redef fun to_s do return linked_text.to_s +end + +# Processes the content of a `` element. +class TypeListener + super LinkedTextListener[RawType] + + private var raw_type: RawType is noinit + + redef fun create_linked_text do return new RawType(graph) +end diff --git a/contrib/neo_doxygen/src/doxml/memberdef.nit b/contrib/neo_doxygen/src/doxml/memberdef.nit new file mode 100644 index 0000000..5249404 --- /dev/null +++ b/contrib/neo_doxygen/src/doxml/memberdef.nit @@ -0,0 +1,70 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# `memberdef` element reading. +module doxml::memberdef + +import entitydef + +# Processes the content of a `` element. +class MemberDefListener + super EntityDefListener + + # The current member. + var member: Member is writable, noinit + + private var type_listener: TypeListener is noinit + private var param_listener: MemberParamListener is noinit + + init do + super + type_listener = new TypeListener(reader, self) + param_listener = new MemberParamListener(reader, self) + end + + redef fun entity do return member + + redef fun start_dox_element(local_name: String, atts: Attributes) do + if "name" == local_name then + text.listen_until(dox_uri, local_name) + else if "reimplements" == local_name then + member.reimplement(get_required(atts, "refid")) + else if "type" == local_name then + type_listener.listen_until(dox_uri, local_name) + else if "param" == local_name then + param_listener.listen_until(dox_uri, local_name) + else + super + end + end + + redef fun end_dox_element(local_name: String) do + if "name" == local_name then + member.name = text.to_s + else if "type" == local_name then + source_language.apply_member_type(member, type_listener.linked_text) + else if "param" == local_name then + member.add_parameter(param_listener.parameter) + else + super + end + end +end + +# Processes the content of a `` element in a `` element. +class MemberParamListener + super ParamListener[MemberParameter] + + redef fun create_parameter do return new MemberParameter(graph) +end diff --git a/contrib/neo_doxygen/src/model/class_compound.nit b/contrib/neo_doxygen/src/model/class_compound.nit new file mode 100644 index 0000000..7663c0a --- /dev/null +++ b/contrib/neo_doxygen/src/model/class_compound.nit @@ -0,0 +1,230 @@ +# 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. + +# Nodes for classes. +module model::class_compound + +import graph +import member +import type_entity + +# A class. +class ClassCompound + super Compound + + # The corresponding type. + # + # In the case of a generic class, defines bounds for type parameters. + var class_type: ClassType is noinit + + # The definition. + var class_def: ClassDef is noinit + + init do + super + class_type = new ClassType(graph) + class_type.class_compound = self + class_def = new ClassDef(graph, self) + self.labels.add("MClass") + kind = "class" + visibility = "public" + end + + # Return the number of type parameters. + fun arity: Int do return class_type.arity + + redef fun name=(name: String) do + super + class_type.name = name + class_def.name = name + end + + redef fun full_name=(full_name: String) do + super + class_type.full_name = full_name + class_def.full_name = full_name + end + + redef fun parent_name=(parent_name: String) do + super + class_type.parent_name = parent_name + class_def.parent_name = parent_name + end + + redef fun location=(location: nullable Location) do + super + class_def.location = location + end + + redef fun set_mdoc do + super + 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) + end + + redef fun declare_member(member: Member) do + class_def.declare_member(member) + end + + # Append the specified type parameter. + fun add_type_parameter(parameter: TypeParameter) do + class_type.arguments.add(parameter) + end + + redef fun put_in_graph do + super + class_type.put_in_graph + class_def.put_in_graph + end + + redef fun put_edges do + super + graph.add_edge(self, "CLASSTYPE", class_type) + if arity > 0 then + var names = new JsonArray + + for p in class_type.arguments do + names.add(p.name) + end + self["parameter_names"] = names + end + end +end + +# The `MClassDef` node of a class. +class ClassDef + super CodeBlock + + var class_compound: ClassCompound + var supers: SimpleCollection[String] = new Array[String] + var members: SimpleCollection[Member] = new Array[Member] + + init do + super + self.labels.add("MClassDef") + self["is_intro"] = true + end + + fun declare_super(id: String, name: String, prot: String, virt: String) do + # TODO prot, virt, name + if "" != id then + supers.add(id) + end + end + + fun declare_member(member: Member) do + var full_name = self["full_name"] + + if full_name != null then + member.parent_name = full_name.to_s + end + members.add(member) + end + + redef fun full_name=(full_name: String) do + super + for m in members do + m.parent_name = full_name + end + end + + redef fun parent_name=(parent_name: String) do + super + for m in members do + m.parent_name = full_name + end + end + + redef fun put_edges do + super + graph.add_edge(self, "BOUNDTYPE", class_compound.class_type) + graph.add_edge(self, "MCLASS", class_compound) + for s in supers do + graph.add_edge(self, "INHERITS", graph.by_id[s].as(ClassCompound).class_type) + end + for m in members do + if m.is_intro then + var intro = m.introducer.as(not null) + graph.add_edge(self, "INTRODUCES", intro) + graph.add_edge(intro, "INTRO_CLASSDEF", self) + end + graph.add_edge(self, "DECLARES", m) + end + end +end + +# A type defined by a class. +class ClassType + super TypeEntity + + # The associated class. + # + # You may use this attribute or `class_compound_id` to specify the class. + var class_compound: nullable ClassCompound = null is writable + + # The `model_id` of the associated class. + # + # You may use this attribute or `class_compound` to specify the class. + var class_compound_id: String = "" is writable + + # The type arguments or the type parameters. + var arguments = new Array[TypeEntity] + + init do + super + self.labels.add("MClassType") + end + + # Return the number of arguments. + fun arity: Int do return arguments.length + + fun is_generic: Bool do return arity > 0 + + redef fun put_in_graph do + super + if is_generic then + self.labels.add("MGenericType") + else + var i = self.labels.index_of("MGenericType") + if i >= 0 then self.labels.remove_at(i) + end + end + + redef fun put_edges do + var cls = class_compound + + if cls == null and class_compound_id != "" then + cls = graph.by_id[class_compound_id].as(ClassCompound) + end + assert cls != null + + super + graph.add_edge(self, "CLASS", cls) + assert cls.arity == self.arity + for i in [0..arguments.length[ do + var a = arguments[i] + if cls.class_type != self then + a.name = cls.class_type.arguments[i].name + end + if a isa TypeParameter then + a.rank = i + graph.add_edge(a, "CLASS", cls) + end + graph.add_edge(self, "ARGUMENT", a) + end + end +end diff --git a/contrib/neo_doxygen/src/model/graph.nit b/contrib/neo_doxygen/src/model/graph.nit new file mode 100644 index 0000000..e14d817 --- /dev/null +++ b/contrib/neo_doxygen/src/model/graph.nit @@ -0,0 +1,293 @@ +# 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. + +# Graphs and basic entities. +module model::graph + +import neo4j +import location + +# A Neo4j graph. +class NeoGraph + var all_nodes: SimpleCollection[NeoNode] = new Array[NeoNode] + var all_edges: SimpleCollection[NeoEdge] = new Array[NeoEdge] + + # Add a relationship between two nodes. + # + # Parameters are the same than for the constructor of `NeoEdge`. + fun add_edge(from: NeoNode, rel_type: String, to: NeoNode) do + all_edges.add(new NeoEdge(from, rel_type, to)) + end +end + +# The project’s graph. +class ProjectGraph + super NeoGraph + + # The node reperesenting the project. + # + # Once the project’s graph is initialized, this node must not be edited. + var project: NeoNode = new NeoNode + + # Entities by `model_id`. + var by_id: Map[String, Entity] = new HashMap[String, Entity] + + # 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) + project.labels.add("MEntity") + project.labels.add("MProject") + project["name"] = name + all_nodes.add(project) + + var root = new RootNamespace(self) + root.put_in_graph + by_id[""] = root + end + + # Request to all nodes in the graph to add their related edges. + fun put_edges do + add_edge(project, "ROOT", by_id[""]) + for n in all_nodes do + if n isa Entity then + n.put_edges + end + end + end +end + +# A model’s entity. +# +# In practice, this is the base class of every node in a `ProjectGraph`. +abstract class Entity + super NeoNode + + # Graph that will embed the entity. + var graph: ProjectGraph + + # ID of the entity in the model. + # + # Is empty for entities without an ID. + var model_id: String = "" is writable + + # Associated documentation. + var doc: JsonArray = new JsonArray is writable + + init do + self.labels.add(graph.project["name"].to_s) + self.labels.add("MEntity") + end + + # The short (unqualified) name. + # + # May be also set by `full_name=`. + fun name=(name: String) do + self["name"] = name + end + + # The short (unqualified) name. + fun name: String do + var name = self["name"] + assert name isa String + return name + end + + # Include the documentation of `self` in the graph. + protected fun set_mdoc do + self["mdoc"] = doc + end + + # The namespace separator of Nit/C++. + fun ns_separator: String do return "::" + + # The name separator used when calling `full_name=`. + fun name_separator: String do return ns_separator + + # The full (qualified) name. + # + # Also set `name` using `name_separator`. + fun full_name=(full_name: String) do + var m: nullable Match = full_name.search_last(name_separator) + + self["full_name"] = full_name + if m == null then + name = full_name + else + name = full_name.substring_from(m.after) + end + end + + # The full (qualified) name. + fun full_name: String do + var full_name = self["full_name"] + assert full_name isa String + return full_name + end + + # 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 + end + + # Set the location of the entity in the source code. + fun location=(location: nullable Location) do + self["location"] = location + end + + # Put the entity in the graph. + # + # Called by the loader when it has finished to read the entity. + fun put_in_graph do + if doc.length > 0 then + set_mdoc + end + graph.all_nodes.add(self) + if model_id != "" then graph.by_id[model_id] = self + end + + # Put the related edges in the graph. + # + # This method is called on each node by `ProjectGraph.put_edges`. + # + # Note: Even at this step, the entity may modify its own attributes and + # inner entities’ ones because some values are only known once the entity + # know its relationships with the rest of the graph. + fun put_edges do end +end + +# An entity whose the location is mandatory. +abstract class CodeBlock + super Entity + + init do + self["location"] = new Location + end + + redef fun location=(location: nullable Location) do + if location == null then + super(new Location) + else + super + end + end +end + +# A compound. +# +# Usually corresponds to a `` element in of the XML output of +# Doxygen. +abstract class Compound + super Entity + + # Set the declared visibility (the proctection) of the compound. + fun visibility=(visibility: String) do + self["visibility"] = visibility + end + + # Set the specific kind of the compound. + fun kind=(kind: String) do + self["kind"] = kind + end + + # Declare an inner namespace. + # + # 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 + + # Declare an inner class. + # + # 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 + + # 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. + # * `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 +end + +# An unrecognized compound. +# +# Used to simplify the handling of ignored entities. +class UnknownCompound + super Compound + + redef fun put_in_graph do end + redef fun put_edges do end +end + +# A namespace. +# +# Corresponds to a group in Nit. +class Namespace + super Compound + + # Inner namespaces (IDs). + # + # Left empty for the root namespace. + var inner_namespaces: SimpleCollection[String] = new Array[String] + + init do + super + self.labels.add("MGroup") + end + + redef fun declare_namespace(id: String, name: String) do + inner_namespaces.add(id) + end + + redef fun put_edges do + super + graph.add_edge(self, "PROJECT", graph.project) + if self["name"] == self["full_name"] and self["full_name"] != "" then + # The root namespace does not know its children. + var root = graph.by_id[""] + graph.add_edge(self, "PARENT", root) + graph.add_edge(root, "NESTS", self) + end + for ns in inner_namespaces do + var node = graph.by_id[ns] + graph.add_edge(node, "PARENT", self) + graph.add_edge(self, "NESTS", node) + end + end +end + +# The root namespace of a `ProjectGraph`. +# +# This the only entity in the graph whose `model_id` is really `""`. +# Added automatically at the initialization of a `ProjectGraph`. +class RootNamespace + super Namespace + + init do + super + self["full_name"] = "" + self["name"] = graph.project["name"] + end + + redef fun declare_namespace(id: String, name: String) do end +end diff --git a/contrib/neo_doxygen/src/model/linked_text.nit b/contrib/neo_doxygen/src/model/linked_text.nit new file mode 100644 index 0000000..bfdf6a5 --- /dev/null +++ b/contrib/neo_doxygen/src/model/linked_text.nit @@ -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. + +# A text with links. +module model::linked_text + +import graph + +# A text with links. +abstract class LinkedText + super Entity + + # All link in the text. + # + # Do not edit directly. + var links: Sequence[nullable Link] = new Array[nullable Link] + + # Remove all the parts. + fun clear_parts do + self["text"] = null + links.clear + end + + # Remove the first part. + fun shift_part do + var text = self["text"] + assert text isa JsonArray + text.shift + links.shift + if text.is_empty then + self["text"] = null + end + end + + # Remove the last part. + fun pop_part do + var text = self["text"] + assert text isa JsonArray + text.pop + links.pop + if text.is_empty then + self["text"] = null + end + end + + # Remove the part at the specified index. + fun remove_part_at(index: Int) do + var text = self["text"] + assert text isa JsonArray + text.remove_at(index) + links.remove_at(index) + if text.is_empty then + self["text"] = null + end + end + + # Change a part of text. + # + # Parameters: + # + # * `index` : the index of the part. + # * `content` : textual content. + # * `refid` : `model_id` of the linked entity or `""`. + fun set_part(index: Int, content: String, refid: String) do + var text = self["text"] + assert text isa JsonArray + text[index] = content + if not refid.is_empty then + links[index] = create_link(links.length, refid) + else + links[index] = null + end + end + + # Append a part of text. + # + # Parameters: + # + # * `content` : textual content. + # * `refid` : `model_id` of the linked entity or `""`. + fun add_part(content: String, refid: String) do + var text = self["text"] + + if text == null then + text = new JsonArray + self["text"] = text + end + assert text isa JsonArray + text.add(content) + if not refid.is_empty then + links.add(create_link(links.length, refid)) + else + links.add(null) + end + end + + # Create a link to the specified entity. + protected fun create_link(rank:Int, refid: String): Link is abstract + + redef fun to_s do + var text = self["text"] + + if text isa JsonArray then + return text.join("") + else + return "UNDEFINED" + end + end + + redef fun put_in_graph do + super + for link in links do + if link isa Link then + link.put_in_graph + end + end + end + + redef fun put_edges do + super + for i in [0..links.length[ do + var link = links[i] + if link isa Link then + link["rank"] = i + graph.add_edge(self, "LINK", link) + end + end + end +end + +# A link. +abstract class Link + super Entity + + # * `refid` : `model_id` of the linked entity. + var refid: String + + init do + super + self["rank"] = -1 + end + + redef fun put_edges do + graph.add_edge(self, "TARGET", graph.by_id[refid]) + end + + # Specify the rank (index) of the parameter in the signature. + # + # Called by `LinkedText.put_edges`. + private fun rank=(rank: Int) do + self["rank"] = rank + end +end diff --git a/contrib/neo_doxygen/src/model/location.nit b/contrib/neo_doxygen/src/model/location.nit new file mode 100644 index 0000000..8652577 --- /dev/null +++ b/contrib/neo_doxygen/src/model/location.nit @@ -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. + +# This module is used to model locations in source files. +module location + +import neo4j + +# A location inside a source file. +class Location + super Jsonable + + var path: nullable String = null is writable + var line_start: Int = 1 is writable + var line_end: Int = 1 is writable + var column_start: Int = 1 is writable + var column_end: Int = 1 is writable + + redef fun to_s: String do + var file_part = "/dev/null:" + if path != null and path.length > 0 then file_part = "{path.as(not null)}:" + return "{file_part}{line_start},{column_start}--{line_end},{column_end}" + end + + redef fun to_json do return to_s.to_json +end diff --git a/contrib/neo_doxygen/src/model/member.nit b/contrib/neo_doxygen/src/model/member.nit new file mode 100644 index 0000000..f29892e --- /dev/null +++ b/contrib/neo_doxygen/src/model/member.nit @@ -0,0 +1,288 @@ +# 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. + +# Members. +module model::member + +import graph +import type_entity + +# A member. +abstract class Member + super CodeBlock + + # 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] + + 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 + + redef fun put_in_graph do + super + self["is_intro"] = is_intro + if is_intro then + var visibility = self["visibility"] + var full_name = self["full_name"] + var name = self["name"] + + introducer = create_introducer + if full_name isa String then + introducer.full_name = full_name + else if name isa String then + introducer.name = name + end + if visibility isa String then + introducer.visibility = visibility + end + introducer.put_in_graph + end + end + + redef fun put_edges do + super + var intro = resolve_introducer + + assert intro != null + graph.add_edge(self, "DEFINES", intro) + end + + # Set the visibility. + fun visibility=(visibility: String) do + self["visibility"] = visibility + if introducer != null then + introducer.as(not null).visibility = visibility + end + end + + redef fun name=(name: String) do + super + if introducer != null then + introducer.as(not null).name = name + end + end + + redef fun full_name=(full_name: String) do + super + if introducer != null then + introducer.as(not null).full_name = full_name + end + end + + redef fun parent_name=(parent_name: String) do + super + if introducer != null then + introducer.as(not null).parent_name = parent_name + end + end + + # 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") + # 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 + fun resolve_introducer: nullable MemberIntroducer do + if introducer == null then + var member_queue = new List[String] + var visited = new HashSet[Member] + var member: Member + + member_queue.add_all(reimplemented) + while not member_queue.is_empty do + member = graph.by_id[member_queue.shift].as(Member) + if visited.has(member) then + return null + else if member.is_intro then + return member.introducer + else + visited.add(member) + member_queue.add_all(member.reimplemented) + end + end + return null + else + return introducer + end + end +end + +# An unrecognized member. +# +# Used to simplify the handling of ignored entities. +class UnknownMember + super Member + + redef fun put_in_graph do end + redef fun put_edges do end +end + +class Method + super Member + + # The method’s signature. + var signature: Signature is noinit, writable + + init do + super + self.labels.add("MMethodDef") + self["is_intern"] = false # TODO + self["is_extern"] = false # TODO + signature = new Signature(graph) + is_abstract = false + end + + # Set the return type. + redef fun static_type=(static_type: nullable TypeEntity) do + signature.return_type = static_type + end + + # Get the return type. + redef fun static_type: nullable TypeEntity do return signature.return_type + + redef fun add_parameter(parameter: MemberParameter) do + signature.parameters.add(parameter) + end + + redef fun create_introducer: MemberIntroducer do + return new MethodIntroducer(graph) + end + + redef fun put_in_graph do + super + signature.put_in_graph + end + + redef fun put_edges do + super + graph.add_edge(self, "SIGNATURE", signature) + end +end + +class Attribute + super Member + + # The declared type. + redef var static_type: nullable TypeEntity = null is writable + + init do + super + self.labels.add("MAttributeDef") + end + + redef fun create_introducer: MemberIntroducer do + return new AttributeIntroducer(graph) + end + + redef fun put_in_graph do + super + if static_type != null then + static_type.as(not null).put_in_graph + end + end + + redef fun put_edges do + super + if static_type != null then + graph.add_edge(self, "TYPE", static_type.as(not null)) + end + end +end + +# The `MProperty` node of a root of a reimplementation graph. +abstract class MemberIntroducer + super Entity + + init do + super + self.labels.add("MProperty") + self["visibility"] = "public" + end + + fun visibility=(visibility: String) do + self["visibility"] = visibility + end +end + +# A `MProperty` node for a method. +class MethodIntroducer + super MemberIntroducer + + init do + super + self.labels.add("MMethod") + self["is_init"] = false # TODO + end +end + +# A `MProperty` node for an attribute. +class AttributeIntroducer + super MemberIntroducer + + init do + super + self.labels.add("MAttribute") + end +end + +redef class Compound + # Append the specified member. + fun declare_member(member: Member) do end +end diff --git a/contrib/neo_doxygen/src/model/model.nit b/contrib/neo_doxygen/src/model/model.nit new file mode 100644 index 0000000..d3c2af9 --- /dev/null +++ b/contrib/neo_doxygen/src/model/model.nit @@ -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. + +# The model used to populate the Neo4j graph. +module model + +import location +import linked_text +import graph +import class_compound +import module_compound +import member diff --git a/contrib/neo_doxygen/src/model/module_compound.nit b/contrib/neo_doxygen/src/model/module_compound.nit new file mode 100644 index 0000000..6629cc7 --- /dev/null +++ b/contrib/neo_doxygen/src/model/module_compound.nit @@ -0,0 +1,139 @@ +# 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. + +# Nodes for modules and files. +module model::module_compound + +import graph +import class_compound + +# A source file. +# +# 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. +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] + + # The last component of the path, without the extension. + # + # Used as the unqualified name of the modules. + private var basename: String = "" + + init do + super + end + + redef fun name_separator: String do return "/" + + redef fun location=(location: nullable Location) do + super + 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 + end + + redef fun name=(name: String) do + # Example: `MyClass.java` + super + var match = name.search_last(".") + + if match == null then + basename = name + else + 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 + end + + redef fun declare_namespace(id: String, 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 + end + 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] + end + m.declare_class(id, name) + 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. + if model_id != "" then graph.by_id[model_id] = self + end +end + +# A module. +class Module + super Compound + super CodeBlock + + # The `model_id` of the parent namespace. + var parent: String = "" is writable + + # The classes defined in the module. + var inner_classes: SimpleCollection[String] = new Array[String] + + init do + super + self.labels.add("MModule") + end + + redef fun declare_class(id: String, name: String) do + inner_classes.add(id) + 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) + end + end +end diff --git a/contrib/neo_doxygen/src/model/type_entity.nit b/contrib/neo_doxygen/src/model/type_entity.nit new file mode 100644 index 0000000..d8ea8c0 --- /dev/null +++ b/contrib/neo_doxygen/src/model/type_entity.nit @@ -0,0 +1,166 @@ +# 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. + +# Typing and parameters. +module model::type_entity + +import graph +import linked_text + +# Base class of all types and signatures. +abstract class TypeEntity + super Entity + + init do + super + self.labels.add("MType") + end +end + +# A type parameter or a type argument. +# +# Note : The class relationship and the rank are set by `MClassType.put_edges`. +class TypeParameter + super TypeEntity + super Parameter + + init do + super + self.labels.add("MParameterType") + end +end + + +# A type described by a text. +class RawType + super TypeEntity + super LinkedText + + init do + super + self.labels.add("MRawType") + end + + redef fun create_link(rank, refid) do return new TypeLink(graph, refid) +end + +# A link in a `RawType`. +class TypeLink + super Link + + init do + super + self.labels.add("MTypePart") + end +end + + +# A signature of a method. +class Signature + super TypeEntity + + # The parameters. + var parameters = new Array[MemberParameter] + + # The static type of the returned value. + var return_type: nullable TypeEntity = null is writable + + init do + super + self.labels.add("MSignature") + end + + redef fun put_in_graph do + super + if return_type isa TypeEntity then + return_type.as(TypeEntity).put_in_graph + end + for p in parameters do + p.put_in_graph + end + end + + redef fun put_edges do + super + if parameters.length > 0 then + var names = new JsonArray + + for i in [0..parameters.length[ do + var p = parameters[i] + p.rank = i + names.add(p.name) + graph.add_edge(self, "PARAMETER", p) + end + self["parameter_names"] = names + end + if return_type != null then + graph.add_edge(self, "RETURNTYPE", return_type.as(not null)) + end + end +end + +# A parameter or an argument. +abstract class Parameter + super Entity + + # The static type of the parameter. + var static_type: nullable TypeEntity = null is writable + + init do + super + self["is_vararg"] = false + self["rank"] = -1 + end + + # Is the parameter a “vararg”? + fun is_vararg=(is_vararg: Bool) do + self["is_vararg"] = is_vararg + end + + # Is the parameter a “vararg”? + fun is_vararg: Bool do + var value = self["is_vararg"] + assert value isa Bool + return value + end + + # Set the rank (index) of the parameter in the signature. + fun rank=(rank: Int) do + self["rank"] = rank + end + + redef fun put_in_graph do + super + if static_type != null then + static_type.as(not null).put_in_graph + end + end + + redef fun put_edges do + super + graph.add_edge(self, "TYPE", static_type.as(not null)) + end +end + +# A parameter of a member. +# +# Note : The rank are set by `Signature.put_edges`. +class MemberParameter + super Parameter + + init do + super + self.labels.add("MParameter") + end +end diff --git a/contrib/neo_doxygen/src/neo_doxygen.nit b/contrib/neo_doxygen/src/neo_doxygen.nit new file mode 100644 index 0000000..f26dfc2 --- /dev/null +++ b/contrib/neo_doxygen/src/neo_doxygen.nit @@ -0,0 +1,306 @@ +# 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. + +# Doxygen XML to Neo4j. +# +# Converts a Doxygen XML output into a model in Neo4j that is readable by the +# `nx` tool. +module neo_doxygen + +import model +import doxml +import console +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 + + private var save_cursor: String = (new TermSaveCursor).to_s + + # Escape control sequence to reset the current line. + private var reset_line: String = "{new TermRestoreCursor}{new TermEraseDisplayDown}" + + # Generate a graph from the specified project model. + # + # Parameters: + # + # * `name`: project name. + # * `dir`: Doxygen XML output directory path. + # * `source`: The language-specific logics to use. + 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] + + if dir.length > 1 and dir.chars.last == "/" then + dir = dir.substring(0, dir.length - 1) + end + sys.stdout.write save_cursor + loop + for f in dir.files 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) + end + end + if directories.length <= 0 then break + dir = directories.pop + end + print "{reset_line}Reading... Done." + end + + # Check the project’s name. + private fun check_name(name: String) do + assert name_valid: not name.chars.first.is_upper else + 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 + sys.stderr.write("{sys.program_name}: The label `{name}` is already" + + " used in the specified graph.\n") + end + end + + # Save the graph. + fun save do + print "Linking nodes...{save_cursor}" + model.put_edges + print "{reset_line} Done." + var nodes = model.all_nodes + print "Saving {nodes.length} nodes...{save_cursor}" + push_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 + end +end + +# The main class. +class NeoDoxygenCommand + + # Invalid arguments + var e_usage = 64 + + # Available options for `--src-lang`. + var sources = new HashMap[String, SourceLanguage] + + # The synopsis. + var synopsis: String = "[--dest ] [--src-lang ]\n" + + " [--] " + + # The synopsis for the help page. + var help_synopsis = "[-h|--help]" + + # The default destination. + var default_dest = "http://localhost:7474" + + # Processes the options. + var option_context = new OptionContext + + # The `--src-lang` option. + var opt_src_lang: OptionEnum is noinit + + # The `--dest` option. + var opt_dest: OptionString is noinit + + # The `-h|--help` option. + var opt_help: OptionBool is noinit + + init do + sources["any"] = new DefaultSource + sources["java"] = new JavaSource + + var prefix = new OptionText(""" +{{{"NAME".bold}}} + {{{sys.program_name}}} — Doxygen XML to Neo4j. + +{{{"SYNOPSIS".bold}}} + {{{sys.program_name}}} {{{synopsis}}} + {{{sys.program_name}}} {{{help_synopsis}}} + +{{{"DESCRIPTION".bold}}} + Convert a Doxygen XML output into a model in Neo4j that is readable by the + `nx` tool. + +{{{"ARGUMENTS".bold}}} + 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. + + The directory where the XML documents generated by Doxygen are + located. + +{{{"OPTIONS".bold}}} +""") + option_context.add_option(prefix) + + opt_dest = new OptionString("The URL of the destination graph. `{default_dest}` by default.", + "--dest") + opt_dest.default_value = default_dest + option_context.add_option(opt_dest) + + 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. + fun main: Int do + if args.is_empty then + show_help + return e_usage + end + option_context.parse(args) + + var errors = option_context.get_errors + var rest = option_context.rest + + if errors.is_empty and not opt_help.value and rest.length != 2 then + errors.add "Unexpected number of additional arguments. Expecting 2; got {rest.length}." + end + if not errors.is_empty then + for e in errors do print_error(e) + show_usage + return e_usage + end + if opt_help.value then + show_help + return 0 + end + + var source = sources[opt_src_lang.value_name] + 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)) + + neo.load_project(project_name, dir, source) + neo.save + return 0 + end + + # Show the help. + fun show_help do + option_context.usage + end + + # Show the usage. + fun show_usage do + sys.stderr.write "Usage: {sys.program_name} {synopsis}\n" + sys.stderr.write "For details, run `{sys.program_name} --help`.\n" + end + + # Print an error. + fun print_error(e: String) do + sys.stderr.write "{sys.program_name}: {e}\n" + end +end + +# Add handling of multi-line descriptions. +# +# Note: The algorithm is naive and do not handle internationalisation and +# escape sequences. +redef class Option + + redef fun pretty(off) do + var s = super + + if s.length > 80 and off < 80 then + var column_length = 80 - off + var left = 0 + var right = 80 + var buf = new FlatBuffer + var prefix = "\n{" " * off}" + + loop + while right > left and s.chars[right] != ' ' do + right -= 1 + end + if left == right then + buf.append s.substring(left, column_length) + right += column_length + else + buf.append s.substring(left, right - left) + right += 1 + end + buf.append prefix + left = right + right += column_length + if right >= s.length then break + end + buf.append s.substring_from(left) + buf.append "\n" + return buf.to_s + else + return "{s}\n" + end + end +end + +exit((new NeoDoxygenCommand).main) diff --git a/contrib/online_ide/sources/nit/pnacl_nit.nit b/contrib/online_ide/sources/nit/pnacl_nit.nit index 477c79f..d50b84a 100644 --- a/contrib/online_ide/sources/nit/pnacl_nit.nit +++ b/contrib/online_ide/sources/nit/pnacl_nit.nit @@ -57,7 +57,7 @@ end redef class ToolContext # We don't need 'the compute_nit_dir'. - redef fun compute_nit_dir: nullable String + redef fun compute_nit_dir do return "/pnacl" end diff --git a/doc/advanced_options b/doc/advanced_options deleted file mode 100644 index 814f81b..0000000 --- a/doc/advanced_options +++ /dev/null @@ -1,5 +0,0 @@ -* GC ************************************************************************** - -Nit programs can dynamically select a GC at runtime. Just set NIT_GC_OPTION envvar. -Set it to "help" to list available GC at the begin of the program. - diff --git a/lib/console.nit b/lib/console.nit index 04dcb6e..e922a84 100644 --- a/lib/console.nit +++ b/lib/console.nit @@ -19,9 +19,162 @@ module console abstract class TermEscape # The US-ASCII ESC character. protected fun esc: Char do return 27.ascii + + # The Control Sequence Introducer (CSI). + protected fun csi: String do return "{esc}[" +end + +# Abstract class of the ANSI/VT100 escape sequences for directional moves. +abstract class TermDirectionalMove + super TermEscape + + # The length of the move. + var magnitude: Int = 1 is protected writable + + redef fun to_s do + if magnitude == 1 then return "{csi}{code}" + return "{csi}{magnitude}{code}" + end + + # The code of the command. + protected fun code: String is abstract +end + +# ANSI/VT100 code to move the cursor up by `magnitude` rows (CUU). +class TermMoveUp + super TermDirectionalMove + + init do end + + # Move by the specified number of cells. + init by(magnitude: Int) do self.magnitude = magnitude + + redef fun code do return "A" +end + +# ANSI/VT100 code to move the cursor down by `magnitude` rows (CUD). +class TermMoveDown + super TermDirectionalMove + + init do end + + # Move by the specified number of cells. + init by(magnitude: Int) do self.magnitude = magnitude + + redef fun code do return "B" +end + +# ANSI/VT100 code to move the cursor foward by `magnitude` columns (CUF). +class TermMoveFoward + super TermDirectionalMove + + init do end + + # Move by the specified number of cells. + init by(magnitude: Int) do self.magnitude = magnitude + + redef fun code do return "C" +end + +# ANSI/VT100 code to move the cursor backward by `magnitude` columns (CUB). +class TermMoveBackward + super TermDirectionalMove + + init do end + + # Move by the specified number of cells. + init by(magnitude: Int) do self.magnitude = magnitude + + redef fun code do return "D" +end + +# ANSI/VT100 code to move the cursor at the specified position (CUP). +class TermMove + super TermEscape + + # Vertical position. + # + # 1 is the top. + var row: Int = 1 + + # Horizontal position. + # + # 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. + init at(row: Int, column: Int) do + self.row = row + self.column = column + end + + redef fun to_s do + if row == 1 then + if column == 1 then return "{csi}H" + return "{csi};{column}H" + else + if column == 1 then return "{csi}{row}H" + return "{csi}{row};{column}H" + end + end +end + +# ANSI/VT100 code to clear from the cursor to the end of the screen (ED 0). +class TermEraseDisplayDown + super TermEscape + redef fun to_s do return "{csi}J" +end + +# ANSI/VT100 code to clear from the cursor to the beginning of the screen (ED 1). +class TermEraseDisplayUp + super TermEscape + redef fun to_s do return "{csi}1J" +end + +# ANSI/VT100 code to clear the entire display and move the cursor to the top left of screen (ED 2). +# +# Note: Some terminals always move the cursor when the screen is cleared. So we +# force this behaviour to ensure interoperability of the code. +class TermClearDisplay + super TermEscape + redef fun to_s do return "{csi}2J{csi}H" +end + +# ANSI/VT100 code to erase anything after the cursor in the line (EL 0). +class TermEraseLineFoward + super TermEscape + redef fun to_s do return "{csi}K" +end + +# ANSI/VT100 code to erase anything before the cursor in the line (EL 1). +class TermEraseLineBackward + super TermEscape + redef fun to_s do return "{csi}1K" +end + +# ANSI/VT100 code to clear everything in the current line (EL 2). +class TermClearLine + super TermEscape + redef fun to_s do return "{csi}2K" +end + +# ANSI/VT100 code to save the current cursor position (SCP). +class TermSaveCursor + super TermEscape + redef fun to_s do return "{csi}s" +end + +# ANSI/VT100 code to restore the current cursor position (RCP). +class TermRestoreCursor + super TermEscape + redef fun to_s do return "{csi}u" end -# ANSI/VT100 code to switch character attributes (SGR). +# ANSI/VT100 code to change character look (SGR). # # By default, resets everything to the terminal’s defaults. # @@ -46,7 +199,7 @@ class TermCharFormat attributes.add_all(format.attributes) end - redef fun to_s: String do return "{esc}[{attributes.join(";")}m" + redef fun to_s: String do return "{csi}{attributes.join(";")}m" # Apply the specified SGR and return `self`. private fun apply(sgr: String): TermCharFormat do diff --git a/lib/more_collections.nit b/lib/more_collections.nit index 50117cf..bd441a1 100644 --- a/lib/more_collections.nit +++ b/lib/more_collections.nit @@ -110,3 +110,13 @@ class HashMap3[K1: Object, K2: Object, K3: Object, V] level2[k2, k3] = v end end + +# A map with a default value. +class DefaultMap[K: Object, V] + super HashMap[K, V] + + # The default value. + var default: V + + redef fun provide_default_value(key) do return default +end diff --git a/lib/neo4j/curl_json.nit b/lib/neo4j/curl_json.nit index f1a1da8..dc5c8ac 100644 --- a/lib/neo4j/curl_json.nit +++ b/lib/neo4j/curl_json.nit @@ -50,6 +50,7 @@ abstract class JsonCurlRequest headers = new HeaderMap headers["Accept"] = "application/json; charset=UTF-8" headers["Transfer-Encoding"] = "chunked" + headers["X-Stream"] = "true" if auth != null then headers["Authorization"] = "token {auth.to_s}" end @@ -95,7 +96,7 @@ abstract class JsonCurlRequest end var err_hook = execute_hook - if err_hook != null then return err_hook + if err_hook != null then return err_hook var err_resp = perform if err_resp != null then return err_resp diff --git a/lib/opts.nit b/lib/opts.nit index c088325..5e36142 100644 --- a/lib/opts.nit +++ b/lib/opts.nit @@ -282,6 +282,14 @@ class OptionContext parse_intern(it) end + # Must all option be given before the first argument? + # + # When set to `false` (the default), options of the command line are + # all parsed until the end of the list of arguments or until "--" is met (in this case "--" is discarded). + # + # When set to `true` options are parsed until the first non-option is met. + var options_before_rest = false is writable + # Parse the command line protected fun parse_intern(it: Iterator[String]) do @@ -319,6 +327,10 @@ class OptionContext else rest.add(it.item) it.next + if options_before_rest then + rest.add_all(it.to_a) + parseargs = false + end end end end diff --git a/lib/standard/string_search.nit b/lib/standard/string_search.nit index fcf14c7..9b1fb8a 100644 --- a/lib/standard/string_search.nit +++ b/lib/standard/string_search.nit @@ -327,6 +327,37 @@ redef class Text # assert "I say hello to the world!".search_from("hello",7) == null fun search_from(p: Pattern, from: Int): nullable Match do return p.search_in(self, from) + # Search the last occurence of the text `t`. + # + # assert "bob".search_last("b").from == 2 + # assert "bob".search_last("bo").from == 0 + # assert "bob".search_last("ob").from == 1 + # assert "bobob".search_last("ob").from == 3 + # assert "bobbob".search_last("bb").from == 2 + # assert "bobbob".search_last("bob").from == 3 + # assert "bob".search_last("z") == null + # assert "".search_last("b") == null + fun search_last(t: Text): nullable Match do + return search_last_up_to(t, length) + end + + # Search the last occurence of the text `t` before `up_to`. + # + # assert "bobbob".search_last_up_to("b", 3).from == 2 + # assert "bobbob".search_last_up_to("b", 6).from == 5 + # assert "bobbob".search_last_up_to("b", 0) == null + fun search_last_up_to(t: Text, up_to: Int): nullable Match do + var i = up_to - t.length + + while i >= 0 do + if substring(i, t.length) == t then + return new Match(self.to_s, i, t.length) + end + i -= 1 + end + return null + end + # Search all occurrences of p into self. # # var a = new Array[Int] diff --git a/share/man/Makefile b/share/man/Makefile index 3eeeb03..c87e2fb 100644 --- a/share/man/Makefile +++ b/share/man/Makefile @@ -18,4 +18,7 @@ OUT=$(patsubst %.md,man1/%.1,$(IN)) all: $(OUT) man1/%.1: %.md + mkdir -p man1 pandoc $< -t man -s -o $@ + +clean: diff --git a/share/man/README.md b/share/man/README.md index a167029..71df3ee 100644 --- a/share/man/README.md +++ b/share/man/README.md @@ -13,9 +13,9 @@ man -l man1/nitg.1 ~~~ For global access, one can set the `MANPATH` environment variable to this `man` directory (not the `man1` subdirectory). -Do not forget to append a trailing column (`:`) to keep existing manpages accessible. +Do not forget to append `$MANPATH` to keep existing manpages accessible. ~~~ -export MANPATH=/path/to/nit/share/man: +export MANPATH=/path/to/nit/share/man:$MANPATH man nitg ~~~ diff --git a/share/man/man1/nitc.1 b/share/man/man1/nitc.1 new file mode 120000 index 0000000..e213084 --- /dev/null +++ b/share/man/man1/nitc.1 @@ -0,0 +1 @@ +nitg.1 \ No newline at end of file diff --git a/share/man/nitg.md b/share/man/nitg.md index 1c45f1d..9ff9963 100644 --- a/share/man/nitg.md +++ b/share/man/nitg.md @@ -2,175 +2,417 @@ # NAME -Compiles Nit programs. +nitg --- compiles Nit programs. + # SYNOPSYS -nitg [*options*]... +nitg [*options*] FILE... + + +# DESCRIPTION + +nitg is the current official Nit compiler. +It takes the main module of a Nit program as argument and produces an executable file. + +By default, the generated executables are produced in the current directory. +(see `--dir` for details.) + +Internally, nitg rely on the presence of a C compiler. Usually gcc (but nitg was successfully tested with clang). +A compilation directory is therefore created and (re-)used. +By default, the compilation directory is named `.nit_compile`. +(see `--compile-dir` for details.) + +Currently, because Nit is still in heavy development, the compilation directory is not cleaned after the compilation. + +By default, the compilation process tries to have a good trade-off between the compilation time and the performance of produced executables. +To produce more optimized executables, the current best option is `--semi-global`. + +To improve the compilation time and simplify the compilation of multiple programs, more than one file can be given. +Each one will be compiled into a distinct executable. + +To combine files into a single program, use the `-m` option. + +nitg can produces executables for various platforms when specific modules are used. +Currently, android, pnacl and emscripten are supported. +See the documentation of these specific modules for details. + # OPTIONS +## MESSAGES + `-W`, `--warn` -: Show more warnings +: Show additional warnings (advices). + + By default, only important warnings are displayed. + May be overridden by `-w`. + + Important warnings are displayed by default. A warning is considered important when: + + * There is a simple correction. + * There is no reason to let the code this way. + * There is always a real issue (no false positive). + + Other warnings, called advices, are not displayed by default to avoid filling the terminal with + unwanted information. + A warning is considered an advice when: + + * The correction could be complex. e.g. require a refactorisation or an API change. + * The correction cannot be done. e.g. Code that use a deprecated API for some compatibility reason. + * There is not a real issue (false positive). Note that this should be unlikely. + * Transitional: While a real important warning, it fires a lot in current code, so a transition is needed + in order to let people fix them before promoting the advice to an important warning. `-w`, `--warning` -: Show/hide a specific warning +: Show/hide a specific warning. + + Each type of warning can be individually displayed or hidden. + The `-w` option takes the name of a warning (displayed at the end of the warning message, between parentheses) to activate it; + and "no-{name}" to disable it. + It has precedence over -q and -W. + Multiple `-w` can be given. + + To show only `missing-doc` warnings in standard" + + $ nitg -q -w missing-doc standard + + To show all warnings and advices, except `missing-doc`: + + $ nitg -W -w no-missing-doc standard + + To show important warnings except `useless-type-test`, but not advice except `missing-doc`: + + $ nitg -w missing-doc -w no-useless-type-test standard `-q`, `--quiet` -: Do not show warnings +: Do not show warnings. + May be overridden by `-w` `--stop-on-first-error` -: Stop on first error +: Just display the first encountered error then stop. + + By default, nitg tries to detect and display more than one error before aborting the compilation. `--no-color` -: Do not use color to display errors and warnings +: Do not use color to display errors and warnings. + + Also, do not echo the line. + This options is mainly used by scripts and tools that need parsable error messages. + +`-v`, `--verbose` +: Additional messages from the tool. + Multiple `-v` can be given to improve the verbosity. + + With one `-v`, there is constant number of lines. + With two `-v`, the number of lines is proportional to the number of modules. + With three `-v`, the number of lines is proportional to the number of definition of properties. `--log` -: Generate various log files +: Generate various log files. + Currently unused. `--log-dir` -: Directory where to generate log files +: Directory where to generate log files. + Currently unused. + `-h`, `-?`, `--help` -: Show Help (This screen) +: Show Help (the list of options). `--version` -: Show version and exit +: Show version and exit. -`--set-dummy-tool` -: Set toolname and version to DUMMY. Useful for testing -`-v`, `--verbose` -: Verbose +## PATHS -`--bash-completion` -: Generate bash_completion file for this program +`-I`, `--path` +: Add an include path. -`--stub-man` -: Generate a stub manpage in pandoc markdown format + This option is used to indicate an additional path of a directory containing Nit libraries. -`--disable-phase` -: DEBUG: Disable a specific phase; use `list` to get the list. + The path added with `-I` are searched before those added by the environment variable `NIT_PATH`. -`-I`, `--path` -: Set include path for loaders (may be used more than once) + May be used more than once. -`--only-parse` -: Only proceed to parse step of loaders +`-o`, `--output` +: Output executable name. -`--only-metamodel` -: Stop after meta-model processing + Indicates the path and name of the produced executable. -`--ignore-visibility` -: Do not check, and produce errors, on visibility issues. + Note: it is better to use `--dir` if only the directory is important. + This way, the platform extension will be correctly set. -`-o`, `--output` -: Output file + `-o` is not available if multiple programs are compiled at once. `--dir` -: Output directory +: Output directory. -`--no-cc` -: Do not invoke C compiler + Produce the executables in the given directory instead of the current directory. -`--no-main` -: Do not generate main entry point -`--make-flags` -: Additional options to make +## COMPILATION `--compile-dir` -: Directory used to generate temporary files +: Directory used to generate temporary files. -`--hardening` -: Generate contracts in the C code against bugs in the compiler + By default, it is named `.nit_compile`. -`--no-shortcut-range` -: Always insantiate a range and its iterator on 'for' loops +`--no-cc` +: Do not invoke the C compiler. -`--no-check-covariance` -: Disable type tests of covariant parameters (dangerous) + Files in the compilation directory are generated but the C compiler is not invoked. -`--no-check-attr-isset` -: Disable isset tests before each attribute access (dangerous) + This option is mainly used to produce C files distributable then compilable on system that do not have a Nit compiler (e.g. embedded system). + In this case, it is suggested to also use the options `--dir`, `--compile-dir` and `--semi-global`. -`--no-check-assert` -: Disable the evaluation of explicit 'assert' and 'as' (dangerous) + $ nitg examples/hello_world.nit --no-cc --dir hello --compile-dir hello --semi-global -`--no-check-autocast` -: Disable implicit casts on unsafe expression usage (dangerous) + Will produce a `hello` directory that contains the required C files to finish the compilation. + Only the C files required for the program are generated. + The final binary will be generated in the same directory. -`--no-check-null` -: Disable tests of null receiver (dangerous) +`-m` +: Additional module to mix-in. -`--no-check-all` -: Disable all tests (dangerous) + Additional modules are imported and refine the main module of the program. + This has basically the same effect than implementing a specific module that imports the main module of the program then each one of the mix-in modules. + May be used more than once. -`--typing-test-metrics` -: Enable static and dynamic count of all type tests + This is option is used to weave additional behaviors to existing programs. + Modules designated to bring features to programs by refining basic or specialized services, without any intervention of the main program, are good candidates to be used with the `-m` option. + E.g. `hash_debug`. -`--invocation-metrics` -: Enable static and dynamic count of all method invocations + An other usage of the `-m` option is to compile program to a specific platform. E.g. `emscripten` or `android`. -`--isset-checks-metrics` -: Enable static and dynamic count of isset checks before attributes access + A last usage is to develop programs as product lines with a main basic module (vanilla) and specific distinct features as flavor modules, then to combine them at compile-time. -`--stacktrace` -: Control the generation of stack traces + $ nitg prog_vanilla.nit -m feature_chocolate.nit -m feature_cherry.nit -`--no-gcc-directive` -: Disable a advanced gcc directives for optimization +`-D`, `--define` +: Define a specific property. + + The `-D` option allows to refine a top-level method at compile-time. + This has basically the same effect than implementing a specific module that imports the main module of the program and refines the designated methods. + + The designated method must be top-level function with no parameters that returns a Bool, an Int or a String. + + The argument of the `-D` option is "{name}={value}". + For Bool, the argument can also be just "{name}", in this case, the value is considered to be `true`. + + $ nitg foo.nit -D prefix=/opt/foo -D port=8080 -D with_ssl `--release` -: Compile in release mode and finalize application +: Compile in release mode and finalize application. -`--global` -: Use global compilation + Currently, this only affect the android platform. + +## COMPILATION MODES + +`nitg` includes distinct compilation modes. `--separate` -: Use separate compilation +: Use separate compilation (default mode). -`--no-inline-intern` -: Do not inline call to intern methods + In separate compilation, modules are compiled independently of their programs. + This makes the recompilation of programs faster since only the modified files need to be recompiled. -`--no-union-attribute` -: Put primitive attibutes in a box instead of an union +`--global` +: Use global compilation. -`--no-shortcut-equal` -: Always call == in a polymorphic way + The produced executables may become huge and the compilation time is prohibitive. + But sometime, they are faster. + + In practice, `--semi-global` produces nearly as fast but smaller executables. + +`--erasure` +: Erase generic types. + + Like `--separate` but use an erasure dynamic typing policy for generics and virtual types. + Usually you do not need this, even if you understand the previous sentence. + + +## SEMI-GLOBAL OPTIMIZATIONS + +In `--separate` and in `--erasure` modes, some optimization can be gained by relaxing the constraint about +the independence on programs. + +Therefore, with these options, the produced executables may be faster and smaller but the recompilation time +will increase. + +`--semi-global` +: Enable all semi-global optimizations. + +`--rta` +: Activate RTA (Rapid Type Analysis). + + This option only make sense in `--erasure` to enable some semi-global optimizations. + + RTA is implicitly enabled in `--separate` and `--global`. `--inline-coloring-numbers` -: Inline colors and ids (semi-global) +: Inline colors and ids (semi-global). `--inline-some-methods` -: Allow the separate compiler to inline some methods (semi-global) +: Allow the separate compiler to inline some methods (semi-global). + Need `--rta`. `--direct-call-monomorph` -: Allow the separate compiler to direct call monomorph sites (semi-global) +: Allow the separate compiler to direct call monomorphic sites (semi-global). + Need `--rta`. `--skip-dead-methods` : Do not compile dead methods (semi-global) + Need `--rta`. -`--semi-global` -: Enable all semi-global optimizations + +## DANGEROUS OPTIMIZATIONS + +The following optimizations disable runtime checks. +It means that correct (non-buggy) programs may be slightly faster. +It also means that incorrect (buggy) programs may have unspecified behaviors +(e.g. formatting your hard drive or killing your cat). + +In fact, these options are mainly used to bench the compilation results. + +`--no-check-all` +: Disable all tests (dangerous). + +`--no-check-covariance` +: Disable type tests of covariant parameters (dangerous). + +`--no-check-attr-isset` +: Disable isset tests before each attribute access (dangerous). + +`--no-check-assert` +: Disable the evaluation of explicit `assert` and `as` (dangerous). + +`--no-check-autocast` +: Disable implicit casts on unsafe expression usage (dangerous). + +`--no-check-null` +: Disable tests of null receiver (dangerous). + +`--no-check-erasure-cast` +: Disable implicit casts on unsafe return with erasure-typing policy (dangerous). + + +## UNOPTIMIZATIONS + +These options are used to debug or to bench the compilation results. +Usually you do not need them since they make the generated code slower. + +`--hardening` +: Generate contracts in the C code against bugs in the compiler. + +`--no-shortcut-range` +: Always instantiate a range and its iterator on 'for' loops. + +`--no-union-attribute` +: Put primitive attributes in a box instead of an union. + +`--no-shortcut-equal` +: Always call == in a polymorphic way. + +`--no-inline-intern` +: Do not inline call to intern methods. `--colo-dead-methods` -: Force colorization of dead methods +: Force colorization of dead methods. + +`--no-gcc-directive` +: Disable advanced gcc directives for optimization. + + +## INTERNAL OPTIONS + +These options can be used to control the fine behavior of the tool. +They are useless for a normal user. + +`--disable-phase` +: Disable a specific phase; use `list` to get the list. + +`--only-parse` +: Only proceed to parse files. + +`--only-metamodel` +: Stop after meta-model processing. + +`--ignore-visibility` +: Do not check, and produce errors, on visibility issues. + +`--no-main` +: Do not generate main entry point. + +`--stacktrace` +: Control the generation of stack traces. + +`--max-c-lines` +: Maximum number of lines in generated C files. Use 0 for unlimited. + +`--group-c-files` +: Group all generated code in the same series of files. + +`--make-flags` +: Additional options to the `make` command. + + $ nitg foo.nit --make-flags 'CC=clang' --make-flags 'CFLAGS="-O0 -g"' + +`--typing-test-metrics` +: Enable static and dynamic count of all type tests. + +`--invocation-metrics` +: Enable static and dynamic count of all method invocations. + +`--isset-checks-metrics` +: Enable static and dynamic count of isset checks before attributes access. `--tables-metrics` -: Enable static size measuring of tables used for vft, typing and resolution +: Enable static size measuring of tables used for vft, typing and resolution. -`--erasure` -: Erase generic types +`--set-dummy-tool` +: Set toolname and version to DUMMY. Useful for testing. -`--no-check-erasure-cast` -: Disable implicit casts on unsafe return with erasure-typing policy (dangerous) +`--bash-completion` +: Generate bash_completion file for this program. -`--rta` -: Activate RTA (implicit with --global and --separate) +`--stub-man` +: Generate a stub manpage in pandoc markdown format. -`-m` -: Additionals module to min-in + +# ENVIRONMENT VARIABLES + +`NIT_DIR` +: Nit install directory. + + When the `NIT_DIR` environment variable is set then it specifies the path of the Nit install directory. + + This directory is used to locate binaries, shared files and the common libraries. + + When unset, the directory is guessed according to some heuristic. + +`NIT_PATH` +: Additional include paths. + + The `NIT_PATH` environment variable contains paths of directories containing Nit libraries. + Each path is separated with a column (`:`). + + The `-I` option also add additional paths. + +`NIT_GC_OPTION` +: Runtime control of the garbage collector. + + The behavior of the GC of the executables produced by nitg can be tuned with this environment variable. + + The environment variable is used when programs are executed, not when they are compiled. + Thus, you do not need to recompile programs in order to tweak their GC options. + + Available values are: + + * boehm: use the Boehm-Demers-Weiser's conservative garbage collector (default). + * malloc: disable the GC and just use `malloc` without doing any `free`. + * large: disable the GC and just allocate a large memory area to use for all instantiation. + * help: show the list of available options. # SEE ALSO diff --git a/src/c_tools.nit b/src/c_tools.nit index e265a2e..b56f947 100644 --- a/src/c_tools.nit +++ b/src/c_tools.nit @@ -115,13 +115,17 @@ class ExternFile fun compiles_to_o_file: Bool do return false fun add_to_jar: Bool do return false + + # Additional libraries needed for the compilation + # Will be used with pkg-config + var pkgconfigs = new Array[String] end # An extern C file to compile class ExternCFile super ExternFile - # Additionnal specific CC compiler -c flags + # Additional specific CC compiler -c flags var cflags: String redef fun hash do return filename.hash @@ -136,7 +140,11 @@ class ExternCFile redef fun makefile_rule_content do var ff = filename.basename("") var o = makefile_rule_name - return "$(CC) $(CFLAGS) {self.cflags} -c -o {o} {ff}" + var pkg = "" + if not pkgconfigs.is_empty then + pkg = "`pkg-config --cflags {pkgconfigs.join(" ")}`" + end + return "$(CC) $(CFLAGS) {self.cflags} {pkg} -c -o {o} {ff}" end redef fun compiles_to_o_file do return true diff --git a/src/compiler/abstract_compiler.nit b/src/compiler/abstract_compiler.nit index 62c0987..733a56e 100644 --- a/src/compiler/abstract_compiler.nit +++ b/src/compiler/abstract_compiler.nit @@ -34,8 +34,6 @@ redef class ToolContext var opt_no_cc = new OptionBool("Do not invoke C compiler", "--no-cc") # --no-main var opt_no_main = new OptionBool("Do not generate main entry point", "--no-main") - # --cc-paths - var opt_cc_path = new OptionArray("Set include path for C header files (may be used more than once)", "--cc-path") # --make-flags var opt_make_flags = new OptionString("Additional options to make", "--make-flags") # --max-c-lines @@ -81,6 +79,8 @@ redef class ToolContext self.option_context.add_option(self.opt_no_gcc_directive) self.option_context.add_option(self.opt_release) self.option_context.add_option(self.opt_max_c_lines, self.opt_group_c_files) + + opt_no_main.hidden = true end redef fun process_options(args) @@ -151,43 +151,9 @@ end class MakefileToolchain super Toolchain - # The list of directories to search for included C headers (-I for C compilers) - # The list is initially set with : - # * the toolcontext --cc-path option - # * the NIT_CC_PATH environment variable - # * `toolcontext.nit_dir` - # Path can be added (or removed) by the client - var cc_paths = new Array[String] - - # The clib directory of Nit - # Used to found some common runtime - var clib: String is noinit - - protected fun gather_cc_paths - do - # Look for the the Nit clib path - var path_env = toolcontext.nit_dir - if path_env != null then - var libname = "{path_env}/clib" - if not libname.file_exists then - toolcontext.fatal_error(null, "Cannot determine the nit clib path. define envvar NIT_DIR.") - end - clib = libname - end - - # Add user defined cc_paths - cc_paths.append(toolcontext.opt_cc_path.value) - - path_env = "NIT_CC_PATH".environ - if not path_env.is_empty then - cc_paths.append(path_env.split_with(':')) - end - end redef fun write_and_make(compiler) do - gather_cc_paths - var compile_dir = compile_dir # Generate the .h and .c files @@ -230,7 +196,9 @@ class MakefileToolchain # Add gc_choser.h to aditionnal bodies var gc_chooser = new ExternCFile("gc_chooser.c", cc_opt_with_libgc) + if cc_opt_with_libgc != "" then gc_chooser.pkgconfigs.add "bdw-gc" compiler.extern_bodies.add(gc_chooser) + var clib = toolcontext.nit_dir / "clib" compiler.files_to_copy.add "{clib}/gc_chooser.c" compiler.files_to_copy.add "{clib}/gc_chooser.h" @@ -352,18 +320,13 @@ class MakefileToolchain var makepath = "{compile_dir}/{makename}" var makefile = new OFStream.open(makepath) - var cc_includes = "" - for p in cc_paths do - cc_includes += " -I \"" + p + "\"" - end - var linker_options = new HashSet[String] for m in mainmodule.in_importation.greaters do var libs = m.collect_linker_libs if libs != null then linker_options.add_all(libs) end - makefile.write("CC = ccache cc\nCXX = ccache c++\nCFLAGS = -g -O2 -Wno-unused-value -Wno-switch\nCINCL = {cc_includes}\nLDFLAGS ?= \nLDLIBS ?= -lm -lgc {linker_options.join(" ")}\n\n") + makefile.write("CC = ccache cc\nCXX = ccache c++\nCFLAGS = -g -O2 -Wno-unused-value -Wno-switch\nCINCL =\nLDFLAGS ?= \nLDLIBS ?= -lm {linker_options.join(" ")}\n\n") var ost = toolcontext.opt_stacktrace.value if (ost == "libunwind" or ost == "nitstack") and (platform == null or platform.supports_libunwind) then makefile.write("NEED_LIBUNWIND := YesPlease\n") @@ -399,6 +362,28 @@ class MakefileToolchain var java_files = new Array[ExternFile] + var pkgconfigs = new Array[String] + for f in compiler.extern_bodies do + pkgconfigs.add_all f.pkgconfigs + end + # Protect pkg-config + if not pkgconfigs.is_empty then + makefile.write """ +# does pkg-config exists? +ifneq ($(shell which pkg-config >/dev/null; echo $$?), 0) +$(error "Command `pkg-config` not found. Please install it") +endif +""" + for p in pkgconfigs do + makefile.write """ +# Check for library {{{p}}} +ifneq ($(shell pkg-config --exists '{{{p}}}'; echo $$?), 0) +$(error "pkg-config: package {{{p}}} is not found.") +endif +""" + end + end + # Compile each required extern body into a specific .o for f in compiler.extern_bodies do var o = f.makefile_rule_name @@ -424,7 +409,11 @@ class MakefileToolchain end # Link edition - makefile.write("{outpath}: {dep_rules.join(" ")}\n\t$(CC) $(LDFLAGS) -o {outpath} {ofiles.join(" ")} $(LDLIBS)\n\n") + var pkg = "" + if not pkgconfigs.is_empty then + pkg = "`pkg-config --libs {pkgconfigs.join(" ")}`" + end + makefile.write("{outpath}: {dep_rules.join(" ")}\n\t$(CC) $(LDFLAGS) -o {outpath} {ofiles.join(" ")} $(LDLIBS) {pkg}\n\n") # Clean makefile.write("clean:\n\trm {ofiles.join(" ")} 2>/dev/null\n\n") makefile.close diff --git a/src/compiler/android_platform.nit b/src/compiler/android_platform.nit index 6fec966..55468fd 100644 --- a/src/compiler/android_platform.nit +++ b/src/compiler/android_platform.nit @@ -205,8 +205,8 @@ $(call import-module,android/native_app_glue) # libpng is not available on Android NDK # FIXME make obtionnal when we have alternatives to mnit var nit_dir = toolcontext.nit_dir - var share_dir = "{nit_dir or else ""}/share/" - if nit_dir == null or not share_dir.file_exists then + var share_dir = nit_dir/"share/" + if not share_dir.file_exists then print "Android project error: Nit share directory not found, please use the environment variable NIT_DIR" exit 1 end diff --git a/src/compiler/compiler_ffi.nit b/src/compiler/compiler_ffi.nit index e9c740a..6a36b2b 100644 --- a/src/compiler/compiler_ffi.nit +++ b/src/compiler/compiler_ffi.nit @@ -53,7 +53,9 @@ extern void nitni_global_ref_decr(void*); nitni_ccu.write_as_nitni(self, v.compiler.modelbuilder.compile_dir) for file in nitni_ccu.files do - v.compiler.extern_bodies.add(new ExternCFile(file, c_compiler_options)) + var f = new ExternCFile(file, c_compiler_options) + f.pkgconfigs.add_all pkgconfigs + v.compiler.extern_bodies.add(f) end # reset FFI things so the next compilation job, if any, starts with a clean context diff --git a/src/doc/doc_model.nit b/src/doc/doc_model.nit index 41386d2..4141f75 100644 --- a/src/doc/doc_model.nit +++ b/src/doc/doc_model.nit @@ -19,6 +19,11 @@ import model_utils import markdown import doc_templates import ordered_tree +import model_ext + + +################################################################################ +# Additions to Nit entities. redef class MDoc # Comment synopsys HTML escaped @@ -714,3 +719,22 @@ redef class ConcernsTree li.append lst end end + + +################################################################################ +# Additions to `model_ext`. + +redef class MRawType + redef fun tpl_signature do + var tpl = new Template + + for part in parts do + if part.target != null then + tpl.add part.target.as(not null).tpl_link + else + tpl.add part.text.html_escape + end + end + return tpl + end +end diff --git a/src/doc/doc_pages.nit b/src/doc/doc_pages.nit index 844e79e..78d42fb 100644 --- a/src/doc/doc_pages.nit +++ b/src/doc/doc_pages.nit @@ -109,11 +109,7 @@ class Nitdoc var sharedir = ctx.opt_sharedir.value if sharedir == null then var dir = ctx.nit_dir - if dir == null then - print "Error: Cannot locate nitdoc share files. Uses --sharedir or envvar NIT_DIR" - abort - end - sharedir = "{dir}/share/nitdoc" + sharedir = dir/"share/nitdoc" if not sharedir.file_exists then print "Error: Cannot locate nitdoc share files. Uses --sharedir or envvar NIT_DIR" abort diff --git a/src/doc/model_ext.nit b/src/doc/model_ext.nit new file mode 100644 index 0000000..fe74325 --- /dev/null +++ b/src/doc/model_ext.nit @@ -0,0 +1,98 @@ +# 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. + +# Extensions to the Nit model for foreign languages. +module doc::model_ext + +intrude import model +intrude import model::model_base + +# A type described by a text annoted with links. +# +# For use with Nitdoc only. +class MRawType + super MType + + redef var model: Model + + # The parts that contitute the description of the type. + var parts: Sequence[MTypePart] = new Array[MTypePart] + + redef fun as_nullable do + not_available + return self + end + redef fun need_anchor do + not_available + return false + end + redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual) do + not_available + return self + end + redef fun can_resolve_for(mtype, anchor, mmodule) do + not_available + return true + end + redef fun collect_mclassdefs(mmodule) do + not_available + return new HashSet[MClassDef] + end + redef fun collect_mclasses(mmodule) do + not_available + return new HashSet[MClass] + end + redef fun collect_mtypes(mmodule) do + not_available + return new HashSet[MClassType] + end + + redef fun to_s do return parts.to_s + + private fun not_available do + assert false else + sys.stderr.write "A `MRawType` is for documentation-purpose only so the requested operation is not available.\n" + end + end +end + +# A part of a `RawType`. +class MTypePart + super MEntity + + redef var model: Model + + # The textual content. + var text: String + + # If the part links to another entity, the targeted entity. + var target: nullable MEntity + + redef fun name do return text + redef fun to_s do return text + + # Return a version of `self` that links to the specified entity. + fun link_to(target: nullable MEntity): MTypePart do + return new MTypePart(model, text, target) + end +end + +# The “package” visiblity. +# +# Any visibility roughly equivalent to the default visibility of Java, that is +# private for a collection of modules. +fun package_visibility: MVisibility do return once new MVisibility("package", 2) + +# A class kind with no equivalent semantic in Nit. +fun raw_kind(s: String): MClassKind do return new MClassKind(s, false) diff --git a/src/ffi/c.nit b/src/ffi/c.nit index 48d4343..6fba61a 100644 --- a/src/ffi/c.nit +++ b/src/ffi/c.nit @@ -74,6 +74,10 @@ end redef class MModule var c_compiler_options = "" is writable var c_linker_options = "" is writable + + # Additional libraries needed for the compilation + # Will be used with pkg-config + var pkgconfigs = new Array[String] end class ForeignCType diff --git a/src/ffi/ffi.nit b/src/ffi/ffi.nit index a418616..a2dda26 100644 --- a/src/ffi/ffi.nit +++ b/src/ffi/ffi.nit @@ -60,7 +60,11 @@ redef class MModule end ffi_ccu.write_as_impl(self, compdir) - for filename in ffi_ccu.files do ffi_files.add(new ExternCFile(filename, c_compiler_options)) + for filename in ffi_ccu.files do + var f = new ExternCFile(filename, c_compiler_options) + f.pkgconfigs.add_all pkgconfigs + ffi_files.add(f) + end end # Avoid the compile a ffi propdef more than once diff --git a/src/ffi/pkgconfig.nit b/src/ffi/pkgconfig.nit index 335d8d1..dca4fab 100644 --- a/src/ffi/pkgconfig.nit +++ b/src/ffi/pkgconfig.nit @@ -87,15 +87,7 @@ class PkgconfigPhase return end - # compiler - var proc = new IProcess("pkg-config", "--cflags", pkg) - var compiler_opts = proc.read_all - mmodule.c_compiler_options = "{mmodule.c_compiler_options} {compiler_opts.replace("\n", " ")}" - - # linker - proc = new IProcess("pkg-config", "--libs", pkg) - var linker_opts = proc.read_all - mmodule.c_linker_options = "{mmodule.c_linker_options} {linker_opts.replace("\n", " ")}" + mmodule.pkgconfigs.add pkg end end diff --git a/src/modelbuilder.nit b/src/modelbuilder.nit index 76a6305..83f5e0e 100644 --- a/src/modelbuilder.nit +++ b/src/modelbuilder.nit @@ -139,10 +139,8 @@ class ModelBuilder end var nit_dir = toolcontext.nit_dir - if nit_dir != null then - var libname = "{nit_dir}/lib" - if libname.file_exists then paths.add(libname) - end + var libname = "{nit_dir}/lib" + if libname.file_exists then paths.add(libname) end # Load a bunch of modules. diff --git a/src/modelize/modelize_property.nit b/src/modelize/modelize_property.nit index dd9d06d..cb56d38 100644 --- a/src/modelize/modelize_property.nit +++ b/src/modelize/modelize_property.nit @@ -587,9 +587,9 @@ redef class AMethPropdef self.mpropdef = mpropdef modelbuilder.mpropdef2npropdef[mpropdef] = self if mpropdef.is_intro then - modelbuilder.toolcontext.info("{mpropdef} introduces new method {mprop.full_name}", 3) + modelbuilder.toolcontext.info("{mpropdef} introduces new method {mprop.full_name}", 4) else - modelbuilder.toolcontext.info("{mpropdef} redefines method {mprop.full_name}", 3) + modelbuilder.toolcontext.info("{mpropdef} redefines method {mprop.full_name}", 4) end end diff --git a/src/neo.nit b/src/neo.nit index df2792c..a566f31 100644 --- a/src/neo.nit +++ b/src/neo.nit @@ -133,8 +133,8 @@ # `MType` # # * labels: `MType`, `model_name` and `MEntity`. Must also have `MClassType`, -# `MNullableType`, `MVirtualType` or `MSignature`, depending on the class of -# the represented entity. +# `MNullableType`, `MVirtualType`, `MRawType` or `MSignature`, depending on the +# class of the represented entity. # # Additional label and relationships for `MClassType`: # @@ -160,6 +160,11 @@ # # * `(:MNullableType)-[:TYPE]->(:MType)`: base type of the nullable type. # +# Additional attribute and relationship for `MRawType`: +# +# * `text`: JSON array of the parts’ text. +# * `(:MRawType)-[:LINK]->(:MTypePart)`: the parts that link to another entity. +# # Additional attribute and relationships for `MSignature`: # # * `parameter_names`: JSON array representing the list of the parameter names. @@ -188,9 +193,15 @@ # # MParameters are also ranked by their position in the corresponding signature. # Rank 0 for the first parameter, 1 for the next one and etc. +# +# `MTypePart` +# +# * labels: `MTypePart`, `model_name` and `MEntity`. +# * `rank`: position in the `MRawType`. +# * `(:MTypePart)-[:TARGET]->(:MEntity)`: the target of the link. module neo -import model +import doc::model_ext import neo4j import toolcontext @@ -213,27 +224,27 @@ class NeoModel # Fill `model` using base pointed by `client`. fun load(model: Model): Model do - toolcontext.info("Locate all mentities...", 1) - var nodes = client.nodes_with_label(model_name) - - toolcontext.info("Preload nodes...", 1) - pull_all_nodes(nodes) - toolcontext.info("Preload edges...", 1) - pull_all_edges(nodes) + var nodes: Array[NeoNode] - toolcontext.info("Build model...", 1) + toolcontext.info("Loading project node...", 1) nodes = client.nodes_with_labels([model_name, "MProject"]) for node in nodes do to_mproject(model, node) + toolcontext.info("Loading groups...", 1) nodes = client.nodes_with_labels([model_name, "MGroup"]) for node in nodes do to_mgroup(model, node) + toolcontext.info("Loading modules...", 1) nodes = client.nodes_with_labels([model_name, "MModule"]) for node in nodes do to_mmodule(model, node) + toolcontext.info("Loading classes...", 1) nodes = client.nodes_with_labels([model_name, "MClass"]) for node in nodes do to_mclass(model, node) + toolcontext.info("Loading class definitions...", 1) nodes = client.nodes_with_labels([model_name, "MClassDef"]) for node in nodes do to_mclassdef(model, node) + toolcontext.info("Loading properties...", 1) nodes = client.nodes_with_labels([model_name, "MProperty"]) for node in nodes do to_mproperty(model, node) + toolcontext.info("Loading property definitions...", 1) nodes = client.nodes_with_labels([model_name, "MPropDef"]) for node in nodes do to_mpropdef(model, node) return model @@ -270,52 +281,6 @@ class NeoModel do_batch(batch) end - # Load content for all `nodes` from base. - # - # Content corresponds to properties and labels that are loaded in batch mode. - private fun pull_all_nodes(nodes: Collection[NeoNode]) do - var batch = new NeoBatch(client) - var len = nodes.length - var sum = 0 - var i = 1 - for node in nodes do - batch.load_node(node) - if i == batch_max_size then - do_batch(batch) - sum += batch_max_size - toolcontext.info(" {sum * 100 / len}% done", 1) - batch = new NeoBatch(client) - i = 1 - else - i += 1 - end - end - do_batch(batch) - end - - # Load all edges from base linked to `nodes`. - # - # Edges are loaded in batch mode. - private fun pull_all_edges(nodes: Collection[NeoNode]) do - var batch = new NeoBatch(client) - var len = nodes.length - var sum = 0 - var i = 1 - for node in nodes do - batch.load_node_edges(node) - if i == batch_max_size then - do_batch(batch) - sum += batch_max_size - toolcontext.info(" {sum * 100 / len}% done", 1) - batch = new NeoBatch(client) - i = 1 - else - i += 1 - end - end - do_batch(batch) - end - # How many operation can be executed in one batch? private var batch_max_size = 1000 @@ -349,7 +314,9 @@ class NeoModel end # Mentities associated to nodes. - private var mentities = new HashMap[NeoNode, MEntity] + # + # The key is the node’s id. + private var mentities = new HashMap[Int, MEntity] # Nodes associated with MEntities. private var nodes = new HashMap[MEntity, NeoNode] @@ -370,6 +337,20 @@ class NeoModel abort end + # Get the `MEntity` associated with `node`. + fun to_mentity(model: Model, node: NeoNode): MEntity do + if node.labels.has("MProject") then return to_mproject(model, node) + if node.labels.has("MGroup") then return to_mgroup(model, node) + if node.labels.has("MModule") then return to_mmodule(model, node) + if node.labels.has("MClass") then return to_mclass(model, node) + if node.labels.has("MClassDef") then return to_mclassdef(model, node) + if node.labels.has("MProperty") then return to_mproperty(model, node) + if node.labels.has("MPropDef") then return to_mpropdef(model, node) + if node.labels.has("MType") then return to_mtype(model, node) + if node.labels.has("MParameter") then return to_mparameter(model, node) + abort + end + # Make a new `NeoNode` based on `mentity`. private fun make_node(mentity: MEntity): NeoNode do var node = new NeoNode @@ -396,10 +377,12 @@ class NeoModel # # REQUIRE `node.labels.has("MProject")` private fun to_mproject(model: Model, node: NeoNode): MProject do - if mentities.has_key(node) then return mentities[node].as(MProject) + var m = mentities.get_or_null(node.id.as(Int)) + if m isa MProject then return m + assert node.labels.has("MProject") var mproject = new MProject(node["name"].to_s, model) - mentities[node] = mproject + mentities[node.id.as(Int)] = mproject set_doc(node, mproject) mproject.root = to_mgroup(model, node.out_nodes("ROOT").first) return mproject @@ -428,7 +411,9 @@ class NeoModel # # REQUIRE `node.labels.has("MGroup")` private fun to_mgroup(model: Model, node: NeoNode): MGroup do - if mentities.has_key(node) then return mentities[node].as(MGroup) + var m = mentities.get_or_null(node.id.as(Int)) + if m isa MGroup then return m + assert node.labels.has("MGroup") var mproject = to_mproject(model, node.out_nodes("PROJECT").first) var parent: nullable MGroup = null @@ -437,7 +422,7 @@ class NeoModel parent = to_mgroup(model, out.first) end var mgroup = new MGroup(node["name"].to_s, mproject, parent) - mentities[node] = mgroup + mentities[node.id.as(Int)] = mgroup set_doc(node, mgroup) return mgroup end @@ -464,7 +449,9 @@ class NeoModel # # REQUIRE `node.labels.has("MModule")` private fun to_mmodule(model: Model, node: NeoNode): MModule do - if mentities.has_key(node) then return mentities[node].as(MModule) + var m = mentities.get_or_null(node.id.as(Int)) + if m isa MModule then return m + assert node.labels.has("MModule") var ins = node.in_nodes("DECLARES") var mgroup: nullable MGroup = null @@ -474,7 +461,7 @@ class NeoModel var name = node["name"].to_s var location = to_location(node["location"].to_s) var mmodule = new MModule(model, mgroup, name, location) - mentities[node] = mmodule + mentities[node.id.as(Int)] = mmodule set_doc(node, mmodule) var imported_mmodules = new Array[MModule] for smod in node.out_nodes("IMPORTS") do @@ -504,7 +491,9 @@ class NeoModel # # REQUIRE `node.labels.has("MClass")` private fun to_mclass(model: Model, node: NeoNode): MClass do - if mentities.has_key(node) then return mentities[node].as(MClass) + var m = mentities.get_or_null(node.id.as(Int)) + if m isa MClass then return m + assert node.labels.has("MClass") var mmodule = to_mmodule(model, node.in_nodes("INTRODUCES").first) var name = node["name"].to_s @@ -517,7 +506,7 @@ class NeoModel end end var mclass = new MClass(mmodule, name, parameter_names, kind, visibility) - mentities[node] = mclass + mentities[node.id.as(Int)] = mclass set_doc(node, mclass) return mclass end @@ -545,13 +534,15 @@ class NeoModel # # REQUIRE `node.labels.has("MClassDef")` private fun to_mclassdef(model: Model, node: NeoNode): MClassDef do - if mentities.has_key(node) then return mentities[node].as(MClassDef) + var m = mentities.get_or_null(node.id.as(Int)) + if m isa MClassDef then return m + assert node.labels.has("MClassDef") var mmodule = to_mmodule(model, node.in_nodes("DEFINES").first) var mtype = to_mtype(model, node.out_nodes("BOUNDTYPE").first).as(MClassType) var location = to_location(node["location"].to_s) var mclassdef = new MClassDef(mmodule, mtype, location) - mentities[node] = mclassdef + mentities[node.id.as(Int)] = mclassdef set_doc(node, mclassdef) var supertypes = new Array[MClassType] for sup in node.out_nodes("INHERITS") do @@ -584,7 +575,9 @@ class NeoModel # # REQUIRE `node.labels.has("MProperty")` private fun to_mproperty(model: Model, node: NeoNode): MProperty do - if mentities.has_key(node) then return mentities[node].as(MProperty) + var m = mentities.get_or_null(node.id.as(Int)) + if m isa MProperty then return m + assert node.labels.has("MProperty") var intro_mclassdef = to_mclassdef(model, node.out_nodes("INTRO_CLASSDEF").first) var name = node["name"].to_s @@ -602,7 +595,7 @@ class NeoModel print "not yet implemented to_mproperty for {node.labels.join(",")}" abort end - mentities[node] = mprop + mentities[node.id.as(Int)] = mprop set_doc(node, mprop) return mprop end @@ -642,7 +635,9 @@ class NeoModel # # REQUIRE `node.labels.has("MPropDef")` private fun to_mpropdef(model: Model, node: NeoNode): MPropDef do - if mentities.has_key(node) then return mentities[node].as(MPropDef) + var m = mentities.get_or_null(node.id.as(Int)) + if m isa MPropDef then return m + assert node.labels.has("MPropDef") var mclassdef = to_mclassdef(model, node.in_nodes("DECLARES").first) var mproperty = to_mproperty(model, node.out_nodes("DEFINES").first) @@ -653,16 +648,16 @@ class NeoModel mpropdef.is_abstract = node["is_abstract"].as(Bool) mpropdef.is_intern = node["is_intern"].as(Bool) mpropdef.is_extern = node["is_extern"].as(Bool) - mentities[node] = mpropdef + mentities[node.id.as(Int)] = mpropdef mpropdef.msignature = to_mtype(model, node.out_nodes("SIGNATURE").first).as(MSignature) else if node.labels.has("MAttributeDef") then mpropdef = new MAttributeDef(mclassdef, mproperty.as(MAttribute), location) - mentities[node] = mpropdef + mentities[node.id.as(Int)] = mpropdef var static_mtype = node.out_nodes("TYPE") if not static_mtype.is_empty then mpropdef.static_mtype = to_mtype(model, static_mtype.first) else if node.labels.has("MVirtualTypeDef") then mpropdef = new MVirtualTypeDef(mclassdef, mproperty.as(MVirtualTypeProp), location) - mentities[node] = mpropdef + 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) end @@ -703,15 +698,41 @@ class NeoModel var rank = 0 for mparameter in mtype.mparameters do names.add mparameter.name - var pnode = to_node(mparameter) + var pnode = mparameter_node(mparameter) pnode["rank"] = rank node.out_edges.add(new NeoEdge(node, "PARAMETER", pnode)) + rank += 1 end if not names.is_empty then node["parameter_names"] = names var return_mtype = mtype.return_mtype if return_mtype != null then node.out_edges.add(new NeoEdge(node, "RETURNTYPE", to_node(return_mtype))) end + else if mtype isa MRawType then + node.labels.add "MRawType" + var text = new JsonArray + var rank = 0 + for part in mtype.parts do + text.add part.text + if part.target != null then + var pnode = mtypepart_node(part) + pnode["rank"] = rank + node.out_edges.add(new NeoEdge(node, "LINK", pnode)) + end + rank += 1 + end + if not text.is_empty then node["text"] = text + end + return node + end + + # Build a `NeoNode` representing `mtypepart`. + private fun mtypepart_node(mtypepart: MTypePart): NeoNode do + var node = make_node(mtypepart) + node.labels.add "MTypePart" + if mtypepart.target != null then + var target_node = to_node(mtypepart.target.as(not null)) + node.out_edges.add(new NeoEdge(node, "TARGET", target_node)) end return node end @@ -720,7 +741,9 @@ class NeoModel # # REQUIRE `node.labels.has("MType")` private fun to_mtype(model: Model, node: NeoNode): MType do - if mentities.has_key(node) then return mentities[node].as(MType) + var m = mentities.get_or_null(node.id.as(Int)) + if m isa MType then return m + assert node.labels.has("MType") if node.labels.has("MClassType") then var mclass = to_mclass(model, node.out_nodes("CLASS").first) @@ -729,24 +752,24 @@ class NeoModel args.add to_mtype(model, narg) end var mtype = mclass.get_mtype(args) - mentities[node] = mtype + mentities[node.id.as(Int)] = mtype return mtype else if node.labels.has("MParameterType") then var mclass = to_mclass(model, node.out_nodes("CLASS").first) var rank = node["rank"].to_s.to_i var mtype = mclass.mparameters[rank] - mentities[node] = mtype + mentities[node.id.as(Int)] = mtype return mtype else if node.labels.has("MNullableType") then var intype = to_mtype(model, node.out_nodes("TYPE").first) var mtype = intype.as_nullable - mentities[node] = mtype + mentities[node.id.as(Int)] = mtype return mtype else if node.labels.has("MVirtualType") then var mproperty = to_mproperty(model, node.out_nodes("PROPERTY").first) assert mproperty isa MVirtualTypeProp var mtype = mproperty.mvirtualtype - mentities[node] = mtype + mentities[node.id.as(Int)] = mtype return mtype else if node.labels.has("MSignature") then # Get all param nodes @@ -770,7 +793,26 @@ class NeoModel return_mtype = to_mtype(model, ret_nodes.first) end var mtype = new MSignature(mparameters, return_mtype) - mentities[node] = mtype + mentities[node.id.as(Int)] = mtype + return mtype + else if node.labels.has("MRawType") then + var mtype = new MRawType(model) + var parts = node["text"] + if parts isa JsonArray then + for p in parts do + mtype.parts.add(new MTypePart(model, p.to_s, null)) + end + for pnode in node.out_nodes("LINK") do + assert pnode.labels.has("MTypePart") + if not pnode.out_nodes("TARGET").is_empty then + var rank = pnode["rank"] + var target = to_mentity(model, pnode.out_nodes("TARGET").first) + assert rank isa Int + mtype.parts[rank] = mtype.parts[rank].link_to(target) + end + end + end + mentities[node.id.as(Int)] = mtype return mtype end print "not yet implemented to_mtype for {node.labels.join(",")}" @@ -791,13 +833,15 @@ class NeoModel # # REQUIRE `node.labels.has("MParameter")` private fun to_mparameter(model: Model, node: NeoNode): MParameter do - if mentities.has_key(node) then return mentities[node].as(MParameter) + var m = mentities.get_or_null(node.id.as(Int)) + if m isa MParameter then return m + assert node.labels.has("MParameter") var name = node["name"].to_s var mtype = to_mtype(model, node.out_nodes("TYPE").first) var is_vararg = node["is_vararg"].as(Bool) var mparameter = new MParameter(name, mtype, is_vararg) - mentities[node] = mparameter + mentities[node.id.as(Int)] = mparameter return mparameter end @@ -827,6 +871,8 @@ class NeoModel return protected_visibility else if vis == private_visibility.to_s then return private_visibility + else if vis == package_visibility.to_s then + return package_visibility else return none_visibility end @@ -844,8 +890,9 @@ class NeoModel return enum_kind else if kind == extern_kind.to_s then return extern_kind + else + return raw_kind(kind) end - abort end # Extract the `MDoc` from `node` and link it to `mentity`. diff --git a/src/nit.nit b/src/nit.nit index 9a95194..3785ff5 100644 --- a/src/nit.nit +++ b/src/nit.nit @@ -23,6 +23,7 @@ import parser_util # Create a tool context to handle options and paths var toolcontext = new ToolContext +toolcontext.option_context.options_before_rest = true toolcontext.tooldescription = "Usage: nit [OPTION]... ...\nInterprets and debugs Nit programs." # Add an option "-o" to enable compatibilit with the tests.sh script var opt = new OptionString("compatibility (does noting)", "-o") diff --git a/src/semantize/auto_super_init.nit b/src/semantize/auto_super_init.nit index 31a508a..ac7763e 100644 --- a/src/semantize/auto_super_init.nit +++ b/src/semantize/auto_super_init.nit @@ -65,7 +65,7 @@ redef class AMethPropdef var nosuper = get_single_annotation("nosuper", modelbuilder) # Collect only for constructors - if not mpropdef.mproperty.is_init then + if not mpropdef.mproperty.is_init or mpropdef.mproperty.is_new then if nosuper != null then modelbuilder.error(nosuper, "Error: nosuper only in `init`") return end diff --git a/src/semantize/typing.nit b/src/semantize/typing.nit index 0d9c296..3140de5 100644 --- a/src/semantize/typing.nit +++ b/src/semantize/typing.nit @@ -1724,7 +1724,7 @@ redef class ANewExpr if not callsite.mproperty.is_new then var kind = recvtype.mclass.kind if kind != concrete_kind then - v.error(self, "Cannot instantiate {kind} {recvtype}.") + v.error(self, "Type Error: Cannot instantiate {kind} {recvtype}.") return end self.mtype = recvtype diff --git a/src/testing/testing_doc.nit b/src/testing/testing_doc.nit index 42d2b0c..f393950 100644 --- a/src/testing/testing_doc.nit +++ b/src/testing/testing_doc.nit @@ -118,8 +118,8 @@ class NitUnitExecutor if toolcontext.opt_noact.value then return var nit_dir = toolcontext.nit_dir - var nitg = "{nit_dir or else ""}/bin/nitg" - if nit_dir == null or not nitg.file_exists then + var nitg = nit_dir/"bin/nitg" + if not nitg.file_exists then toolcontext.error(null, "Cannot find nitg. Set envvar NIT_DIR.") toolcontext.check_errors end diff --git a/src/testing/testing_suite.nit b/src/testing/testing_suite.nit index 5936038..1a3006d 100644 --- a/src/testing/testing_suite.nit +++ b/src/testing/testing_suite.nit @@ -214,8 +214,8 @@ class TestCase fun compile do # find nitg var nit_dir = toolcontext.nit_dir - var nitg = "{nit_dir or else ""}/bin/nitg" - if nit_dir == null or not nitg.file_exists then + var nitg = nit_dir/"bin/nitg" + if not nitg.file_exists then toolcontext.error(null, "Cannot find nitg. Set envvar NIT_DIR.") toolcontext.check_errors end diff --git a/src/toolcontext.nit b/src/toolcontext.nit index fb3aeaa..ec91130 100644 --- a/src/toolcontext.nit +++ b/src/toolcontext.nit @@ -246,6 +246,9 @@ class ToolContext # Option --log-dir var opt_log_dir = new OptionString("Directory where to generate log files", "--log-dir") + # Option --nit-dir + var opt_nit_dir = new OptionString("Base directory of the Nit installation", "--nit-dir") + # Option --help var opt_help = new OptionBool("Show Help (This screen)", "-h", "-?", "--help") @@ -275,7 +278,12 @@ class ToolContext init do - option_context.add_option(opt_warn, opt_warning, opt_quiet, opt_stop_on_first_error, opt_no_color, opt_log, opt_log_dir, opt_help, opt_version, opt_set_dummy_tool, opt_verbose, opt_bash_completion, opt_stub_man) + option_context.add_option(opt_warn, opt_warning, opt_quiet, opt_stop_on_first_error, opt_no_color, opt_log, opt_log_dir, opt_nit_dir, opt_help, opt_version, opt_set_dummy_tool, opt_verbose, opt_bash_completion, opt_stub_man) + + # Hide some internal options + opt_stub_man.hidden = true + opt_bash_completion.hidden = true + opt_set_dummy_tool.hidden = true end # Name, usage and synopsis of the tool. @@ -365,6 +373,8 @@ The Nit language documentation and the source code of its tools and libraries ma exit 1 end + nit_dir = compute_nit_dir + if option_context.rest.is_empty and not accept_no_arguments then print tooldescription print "Use --help for help" @@ -382,7 +392,6 @@ The Nit language documentation and the source code of its tools and libraries ma log_directory.mkdir end - nit_dir = compute_nit_dir end # Get the current `nit_version` or "DUMMY_VERSION" if `--set-dummy-tool` is set. @@ -402,27 +411,54 @@ The Nit language documentation and the source code of its tools and libraries ma end # The identified root directory of the Nit project - var nit_dir: nullable String = null + var nit_dir: String is noinit - private fun compute_nit_dir: nullable String + private fun compute_nit_dir: String do - # a environ variable has precedence - var res = "NIT_DIR".environ - if not res.is_empty then return res + # the option has precedence + var res = opt_nit_dir.value + if res != null then + if not check_nit_dir(res) then + fatal_error(null, "Fatal Error: the value of --nit-dir does not seem to be a valid base Nit directory: {res}") + 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 + fatal_error(null, "Fatal Error: the value of NIT_DIR does not seem to be a valid base Nit directory: {res}") + end + return res + end # find the runpath of the program from argv[0] res = "{sys.program_name.dirname}/.." - if res.file_exists and "{res}/src/nit.nit".file_exists then return res.simplify_path + 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 res.file_exists and "{res}/src/nit.nit".file_exists then return res.simplify_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 - return null + fatal_error(null, "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.") + abort + end + + private fun check_nit_dir(res: String): Bool + do + return res.file_exists and "{res}/src/nit.nit".file_exists end end diff --git a/tests/base_new.nit b/tests/base_new.nit index 8fdf39a..d36a68b 100644 --- a/tests/base_new.nit +++ b/tests/base_new.nit @@ -49,6 +49,11 @@ class C end end +class D + super C + new(z: Bool): B do return new C(1111) +end + redef class Int new z do return 0 new a: A do return new A @@ -79,6 +84,10 @@ end '\n'.output +(new D(true)).output + +'\n'.output + #alt8#(new Int).output (new Int.z).output (new Int.a).output diff --git a/tests/nit.args b/tests/nit.args index 0c14c1c..8a91562 100644 --- a/tests/nit.args +++ b/tests/nit.args @@ -1,4 +1,4 @@ --log --log-dir out/test_nitc_logs ../examples/hello_world.nit base_simple3.nit -m test_mixin.nit ../examples/hello_world.nit -test_define.nit -D text=hello -D num=42 -D flag +-D text=hello -D num=42 -D flag test_define.nit diff --git a/tests/sav/base_error_new_abstract.res b/tests/sav/base_error_new_abstract.res index e23154d..a3c8000 100644 --- a/tests/sav/base_error_new_abstract.res +++ b/tests/sav/base_error_new_abstract.res @@ -1 +1 @@ -base_error_new_abstract.nit:21,9--13: Cannot instantiate abstract class A. +base_error_new_abstract.nit:21,9--13: Type Error: Cannot instantiate abstract class A. diff --git a/tests/sav/base_error_new_interface.res b/tests/sav/base_error_new_interface.res index 0e64d98..c0c2c1b 100644 --- a/tests/sav/base_error_new_interface.res +++ b/tests/sav/base_error_new_interface.res @@ -1 +1 @@ -base_error_new_interface.nit:21,9--13: Cannot instantiate interface A. +base_error_new_interface.nit:21,9--13: Type Error: Cannot instantiate interface A. diff --git a/tests/sav/base_new.res b/tests/sav/base_new.res index fe346a1..510c2e4 100644 --- a/tests/sav/base_new.res +++ b/tests/sav/base_new.res @@ -13,5 +13,7 @@ B11 B111 +B1111 + 0 B1 diff --git a/tests/sav/base_new_alt5.res b/tests/sav/base_new_alt5.res index 15d625a..e9c98c9 100644 --- a/tests/sav/base_new_alt5.res +++ b/tests/sav/base_new_alt5.res @@ -1 +1 @@ -alt/base_new_alt5.nit:58,1--9: Error: Method 'i' doesn't exists in A. +alt/base_new_alt5.nit:63,1--9: Error: Method 'i' doesn't exists in A. diff --git a/tests/sav/base_new_alt6.res b/tests/sav/base_new_alt6.res index 53c4091..3ac7e2a 100644 --- a/tests/sav/base_new_alt6.res +++ b/tests/sav/base_new_alt6.res @@ -1 +1 @@ -alt/base_new_alt6.nit:60,1--12: Error: Method 'i' doesn't exists in A. +alt/base_new_alt6.nit:65,1--12: Error: Method 'i' doesn't exists in A. diff --git a/tests/sav/base_new_alt7.res b/tests/sav/base_new_alt7.res index 698bfbf..99ce3e1 100644 --- a/tests/sav/base_new_alt7.res +++ b/tests/sav/base_new_alt7.res @@ -1 +1 @@ -alt/base_new_alt7.nit:78,2--9: Error: Method 'n2' doesn't exists in C. +alt/base_new_alt7.nit:83,2--9: Error: Method 'n2' doesn't exists in C. diff --git a/tests/sav/base_new_alt8.res b/tests/sav/base_new_alt8.res index 1eed641..51ee855 100644 --- a/tests/sav/base_new_alt8.res +++ b/tests/sav/base_new_alt8.res @@ -1 +1 @@ -alt/base_new_alt8.nit:82,2--8: Cannot instantiate enum Int. +alt/base_new_alt8.nit:91,2--8: Type Error: Cannot instantiate enum Int. diff --git a/tests/sav/error_needed_method_alt2.res b/tests/sav/error_needed_method_alt2.res index e95a0c5..14ced87 100644 --- a/tests/sav/error_needed_method_alt2.res +++ b/tests/sav/error_needed_method_alt2.res @@ -1 +1 @@ -alt/error_needed_method_alt2.nit:47,10--27: Cannot instantiate interface Collection[Int]. +alt/error_needed_method_alt2.nit:47,10--27: Type Error: Cannot instantiate interface Collection[Int]. diff --git a/tests/sav/test_toolcontext_args1.res b/tests/sav/test_toolcontext_args1.res index 800327a..6e0ca35 100644 --- a/tests/sav/test_toolcontext_args1.res +++ b/tests/sav/test_toolcontext_args1.res @@ -5,7 +5,7 @@ _DUMMY_TOOL() COMPREPLY=() cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}" - opts="--warn --warning --quiet --stop-on-first-error --no-color --log --log-dir --help --version --set-dummy-tool --verbose --bash-completion --stub-man --option-a --option-b" + opts="--warn --warning --quiet --stop-on-first-error --no-color --log --log-dir --nit-dir --help --version --set-dummy-tool --verbose --bash-completion --stub-man --option-a --option-b" if [[ ${cur} == -* ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) return 0 diff --git a/tests/sav/test_toolcontext_args2.res b/tests/sav/test_toolcontext_args2.res index 91fa2fa..b14caf6 100644 --- a/tests/sav/test_toolcontext_args2.res +++ b/tests/sav/test_toolcontext_args2.res @@ -7,12 +7,10 @@ Test for ToolContext, try --bash-completion. --no-color Do not use color to display errors and warnings --log Generate various log files --log-dir Directory where to generate log files + --nit-dir Base directory of the Nit installation -h, -?, --help Show Help (This screen) --version Show version and exit - --set-dummy-tool Set toolname and version to DUMMY. Useful for testing -v, --verbose Verbose - --bash-completion Generate bash_completion file for this program - --stub-man Generate a stub manpage in pandoc markdown format -a, --option-a option a, do nothing -b, --option-b option b, do nothing -c option c, do nothing diff --git a/tests/tests.sh b/tests/tests.sh index 14be6d4..8179c9c 100755 --- a/tests/tests.sh +++ b/tests/tests.sh @@ -74,8 +74,8 @@ saferun() if test -n "$TIME"; then $TIME -o "$o" $a $TIMEOUT "$@" else - $TIMEOUT "$@" if test -n "$a"; then echo 0 >> "$o"; else echo 0 > "$o"; fi + $TIMEOUT "$@" fi } @@ -505,7 +505,7 @@ for ii in "$@"; do if [ -n "$isinterpret" ]; then cat > "$ff.bin" < "$ff.cmp.err" @@ -521,10 +521,10 @@ END # Compile if [ "x$verbose" = "xtrue" ]; then echo "" - echo $NITC --no-color $OPT -o "$ffout" "$i" "$includes" $nocc + echo $NITC --no-color $OPT -o "$ffout" "$includes" $nocc "$i" fi NIT_NO_STACK=1 JNI_LIB_PATH=$JNI_LIB_PATH JAVA_HOME=$JAVA_HOME \ - saferun -o "$ff.time.out" $NITC --no-color $OPT -o "$ffout" "$i" $includes $nocc 2> "$ff.cmp.err" > "$ff.compile.log" + saferun -o "$ff.time.out" $NITC --no-color $OPT -o "$ffout" $includes $nocc "$i" 2> "$ff.cmp.err" > "$ff.compile.log" ERR=$? if [ "x$verbose" = "xtrue" ]; then cat "$ff.compile.log"