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 <r4pass@hotmail.com>
Reviewed-by: Alexis Laferrière <alexis.laf@xymus.net>
--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; \
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
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:
#!/bin/bash
-self=`readlink /proc/$$/fd/255`
-dir=`dirname "$self"`
+dir=`dirname "$BASH_SOURCE"`
exec "$dir/nitg" "$@"
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')
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
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;
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;
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')
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
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+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
--- /dev/null
+#! /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 <source_language> <directory>
+#
+# 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
--- /dev/null
+#! /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 <source_language> <directory>
+#
+# 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
--- /dev/null
+#! /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
+}
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# `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 `<basecompoundref>` 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
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# 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
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# 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
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# 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 `<param>` 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 `<param>` element in a `<templateparamlist>` element.
+class TypeParamListener
+ super ParamListener[TypeParameter]
+
+ redef fun create_parameter do return new TypeParameter(graph)
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# 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 `<type>` 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 `<type>` 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
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Basic 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 `<type>` element.
+class TypeListener
+ super LinkedTextListener[RawType]
+
+ private var raw_type: RawType is noinit
+
+ redef fun create_linked_text do return new RawType(graph)
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# `memberdef` element reading.
+module doxml::memberdef
+
+import entitydef
+
+# Processes the content of a `<memberdef>` 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 `<param>` element in a `<memberdef>` element.
+class MemberParamListener
+ super ParamListener[MemberParameter]
+
+ redef fun create_parameter do return new MemberParameter(graph)
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# 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
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# 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 `<compounddef>` 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
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# A 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
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# 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
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# 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
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# 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
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# 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
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# 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
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# 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 <url>] [--src-lang <lang>]\n" +
+ " [--] <project_name> <doxml_dir>"
+
+ # 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}}}
+ <project_name> The internal name of the project. Must the same name as the
+ one specified to the `nx` tool. Must not begin by an upper
+ case letter.
+
+ <doxml_dir> The directory where the XML documents generated by Doxygen are
+ located.
+
+{{{"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)
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
+++ /dev/null
-* 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.
-
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.
#
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
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
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
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
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
else
rest.add(it.item)
it.next
+ if options_before_rest then
+ rest.add_all(it.to_a)
+ parseargs = false
+ end
end
end
end
# 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]
all: $(OUT)
man1/%.1: %.md
+ mkdir -p man1
pandoc $< -t man -s -o $@
+
+clean:
~~~
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
~~~
--- /dev/null
+nitg.1
\ No newline at end of file
# 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
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
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
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
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)
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
# 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"
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")
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
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
# 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
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
import markdown
import doc_templates
import ordered_tree
+import model_ext
+
+
+################################################################################
+# Additions to Nit entities.
redef class MDoc
# Comment synopsys HTML escaped
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
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
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# 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)
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
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
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
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.
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
# `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`:
#
#
# * `(: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.
#
# 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
# 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
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
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]
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
#
# 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
#
# 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
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
#
# 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
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
#
# 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
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
#
# 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
#
# 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
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
#
# 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)
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
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
#
# 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)
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
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(",")}"
#
# 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
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
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`.
# 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]... <file.nit>...\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")
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
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
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
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
# 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")
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.
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"
log_directory.mkdir
end
- nit_dir = compute_nit_dir
end
# Get the current `nit_version` or "DUMMY_VERSION" if `--set-dummy-tool` is set.
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
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
'\n'.output
+(new D(true)).output
+
+'\n'.output
+
#alt8#(new Int).output
(new Int.z).output
(new Int.a).output
--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
-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.
-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.
-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.
-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.
-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.
-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.
-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].
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
--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
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
}
if [ -n "$isinterpret" ]; then
cat > "$ff.bin" <<END
-exec $NITC --no-color $OPT "$i" $includes -- "\$@"
+exec $NITC --no-color $OPT $includes -- "$i" "\$@"
END
chmod +x "$ff.bin"
> "$ff.cmp.err"
# 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"