Added 2 features to Opportunity, namely the maybe option and the count for the answers, as well as a visual hint for the best answer.
Also fixed a few bugs, some Update statements were wrong.
Pull-Request: #885
Reviewed-by: Alexis Laferrière <alexis.laf@xymus.net>
Reviewed-by: Jean Privat <jean@pryen.org>
--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; \
echo "*** Benching Array.to_s performance ***"
fi
- ../bin/nitg --global ./strings/array_tos.nit -m ./strings/array_to_s_vars/array_to_s_rope.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
+ ../bin/nitg --global ./strings/array_tos.nit -m ./strings/array_to_s_vars/array_to_s_flatstr.nit -m ../lib/standard/ropes.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
prepare_res arr_tos_ropes.out arr_tos_ropes ropes
if $verbose; then
bench_command $i ropes$i ./array_tos --loops $2 --strlen $i --ccts $1 "NIT_GC_CHOOSER=large"
done
+ ../bin/nitg --global ./strings/array_tos.nit -m ./strings/array_to_s_vars/array_to_s_flatstr.nit -m ../lib/standard/ropes.nit -m ../lib/buffered_ropes.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
+
+ prepare_res arr_tos_buf_ropes.out arr_tos_buf_ropes buffered_ropes
+ if $verbose; then
+ echo "Buffered Ropes :"
+ fi
+ for i in `seq 1 "$3"`; do
+ if $verbose; then
+ echo "String length = $i, Concats/loop = $1, Loops = $2"
+ fi
+ bench_command $i buf_ropes$i ./array_tos --loops $2 --strlen $i --ccts $1 "NIT_GC_CHOOSER=large"
+ done
+
../bin/nitg --global ./strings/array_tos.nit -m ./strings/array_to_s_vars/array_to_s_flatstr.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
prepare_res arr_tos_flat.out arr_tos_flat flatstring
prepare_res arr_tos_man_buf.out arr_tos_man_buf flatbuf_with_capacity
if $verbose; then
- echo "Memmove :"
+ echo "FlatBuffer.with_capacity :"
fi
for i in `seq 1 "$3"`; do
if $verbose; then
bench_command $i flatbuf_with_capacity$i ./array_tos --loops $2 --strlen $i --ccts $1 "NIT_GC_CHOOSER=large"
done
+ ../bin/nitg --global ./strings/array_tos.nit -m ./strings/array_to_s_vars/array_to_s_rope_buf.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
+
+ prepare_res arr_tos_rope_buf.out arr_tos_rope_buf ropebuf
+ if $verbose; then
+ echo "RopeBuffer :"
+ fi
+ for i in `seq 1 "$3"`; do
+ if $verbose; then
+ echo "String length = $i, Concats/loop = $1, Loops = $2"
+ fi
+ bench_command $i ropebuf$i ./array_tos --loops $2 --strlen $i --ccts $1 "NIT_GC_CHOOSER=large"
+ done
+
plot array_tos.gnu
}
function bench_concat()
{
- if $verbose; then
- echo "*** Benching concat performance ***"
- fi
+ ../bin/nitg --global ./strings/chain_concat.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
+ ../bin/nitg --global ./strings/utf_chain_concat.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
- prepare_res concat_ropes.out concat_ropes ropes
if $verbose; then
- echo "Ropes :"
+ echo "*** Benching concat performance ***"
fi
- for i in `seq 1 "$1"`; do
- if $verbose; then
- echo "String length = $i, Concats/loop = $2, Loops = $3"
- fi
- bench_command $i ropes$i ./chain_concat -m rope --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
- done
prepare_res concat_flat.out concat_flat flatstring
if $verbose; then
bench_command $i flatstr_utf8_noindex$i ./utf_chain_concat -m flatstr_utf8_noindex --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
done
- plot concat.gnu
-}
+ ../bin/nitg --global ./strings/chain_concat.nit -m ../lib/standard/ropes.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
-function bench_iteration()
-{
+ prepare_res concat_ropes.out concat_ropes ropes
if $verbose; then
- echo "*** Benching iteration performance ***"
+ echo "Ropes :"
fi
+ for i in `seq 1 "$1"`; do
+ if $verbose; then
+ echo "String length = $i, Concats/loop = $2, Loops = $3"
+ fi
+ bench_command $i ropes$i ./chain_concat -m flatstr --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
+ done
- prepare_res iter_ropes_iter.out iter_ropes_iter ropes_iter
+ ../bin/nitg --global ./strings/chain_concat.nit -m ../lib/standard/ropes.nit -m ../lib/buffered_ropes.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
+
+ prepare_res concat_buf_ropes.out concat_buf_ropes buffered_ropes
if $verbose; then
- echo "Ropes by iterator :"
+ echo "buffered ropes :"
fi
for i in `seq 1 "$1"`; do
if $verbose; then
- echo "String base length = $1, Concats (depth of the rope) = $i, Loops = $3"
+ echo "string length = $i, concats/loop = $2, loops = $3"
fi
- bench_command $i ropes_iter$i ./iteration_bench -m rope --iter-mode iterator --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
+ bench_command $i buf_ropes$i ./chain_concat -m flatstr --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
done
- prepare_res iter_ropes_index.out iter_ropes_index ropes_index
+ ../bin/nitg --global ./strings/chain_cct_ropebuf.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
+
+ prepare_res cct_buf_ropes.out cct_buf_ropes cctbuf_ropes
if $verbose; then
- echo "Ropes by index :"
+ echo "buffered ropes :"
fi
for i in `seq 1 "$1"`; do
if $verbose; then
- echo "String base length = $1, Concats (depth of the rope) = $i, Loops = $3"
+ echo "string length = $i, concats/loop = $2, loops = $3"
fi
- bench_command $i ropes_index$i ./iteration_bench -m rope --iter-mode index --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
+ bench_command $i cctbuf_ropes$i ./chain_cct_ropebuf --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
done
+ plot concat.gnu
+}
+
+function bench_iteration()
+{
+ if $verbose; then
+ echo "*** Benching iteration performance ***"
+ fi
+
+ ../bin/nitg --global ./strings/iteration_bench.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
+ ../bin/nitg --global ./strings/utf_iteration_bench.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
+
prepare_res iter_flat_iter.out iter_flat_iter flatstring_iter
if $verbose; then
echo "FlatStrings by iterator :"
bench_command $i flatstr_index_utf8_noindex$i ./utf_iteration_bench -m flatstr_utf8_noindex --iter-mode index --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
done
- plot iter.gnu
-}
+ ../bin/nitg --global ./strings/iteration_bench.nit -m ../lib/standard/ropes.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
-function bench_substr()
-{
+ prepare_res iter_ropes_iter.out iter_ropes_iter ropes_iter
if $verbose; then
- echo "*** Benching substring performance ***"
+ echo "Ropes by iterator :"
fi
+ for i in `seq 1 "$1"`; do
+ if $verbose; then
+ echo "String base length = $1, Concats (depth of the rope) = $i, Loops = $3"
+ fi
+ bench_command $i ropes_iter$i ./iteration_bench -m flatstr --iter-mode iterator --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
+ done
- prepare_res substr_ropes.out substr_ropes ropes
+ prepare_res iter_ropes_index.out iter_ropes_index ropes_index
if $verbose; then
- echo "Ropes :"
+ echo "Ropes by index :"
fi
for i in `seq 1 "$1"`; do
if $verbose; then
- echo "String length = $i, loops = $2, Loops = $3"
+ echo "String base length = $1, Concats (depth of the rope) = $i, Loops = $3"
+ fi
+ bench_command $i ropes_index$i ./iteration_bench -m flatstr --iter-mode index --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
+ done
+
+ ../bin/nitg --global ./strings/iteration_bench.nit -m ../lib/standard/ropes.nit -m ../lib/buffered_ropes.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
+
+ prepare_res iter_buf_ropes_iter.out iter_buf_ropes_iter buf_ropes_iter
+ if $verbose; then
+ echo "Buffered Ropes by iterator :"
+ fi
+ for i in `seq 1 "$1"`; do
+ if $verbose; then
+ echo "String base length = $1, Concats (depth of the rope) = $i, Loops = $3"
+ fi
+ bench_command $i buf_ropes_iter$i ./iteration_bench -m flatstr --iter-mode iterator --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
+ done
+
+ prepare_res iter_buf_ropes_index.out iter_buf_ropes_index buf_ropes_index
+ if $verbose; then
+ echo "Buffered Ropes by index :"
+ fi
+ for i in `seq 1 "$1"`; do
+ if $verbose; then
+ echo "String base length = $1, Concats (depth of the rope) = $i, Loops = $3"
fi
- bench_command $i ropes$i ./substr_bench -m rope --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
+ bench_command $i buf_ropes_index$i ./iteration_bench -m flatstr --iter-mode index --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
done
+ plot iter.gnu
+}
+
+function bench_substr()
+{
+ if $verbose; then
+ echo "*** Benching substring performance ***"
+ fi
+
+ ../bin/nitg --global ./strings/substr_bench.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
+ ../bin/nitg --global ./strings/utf_substr_bench.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
+
prepare_res substr_flat.out substr_flat flatstring
if $verbose; then
echo "FlatStrings :"
bench_command $i flatstring_utf8_noindex$i ./utf_substr_bench -m flatstr_utf8_noindex --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
done
+ ../bin/nitg --global ./strings/substr_bench.nit -m ../lib/standard/ropes.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
+
+ prepare_res substr_ropes.out substr_ropes ropes
+ if $verbose; then
+ echo "Ropes :"
+ fi
+ for i in `seq 1 "$1"`; do
+ if $verbose; then
+ echo "String length = $i, loops = $2, Loops = $3"
+ fi
+ bench_command $i ropes$i ./substr_bench -m flatstr --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
+ done
+
+ ../bin/nitg --global ./strings/substr_bench.nit -m ../lib/standard/ropes.nit -m ../lib/buffered_ropes.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
+
+ prepare_res substr_buf_ropes.out substr_buf_ropes buf_ropes
+ if $verbose; then
+ echo "Buffered Ropes :"
+ fi
+ for i in `seq 1 "$1"`; do
+ if $verbose; then
+ echo "String length = $i, loops = $2, Loops = $3"
+ fi
+ bench_command $i buf_ropes$i ./substr_bench -m flatstr --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
+ done
plot substr.gnu
}
exit
fi
-if $verbose; then
- echo "Compiling"
-fi
-
-../bin/nitg --global ./strings/chain_concat.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
-../bin/nitg --global ./strings/utf_chain_concat.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
-../bin/nitg --global ./strings/iteration_bench.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
-../bin/nitg --global ./strings/utf_iteration_bench.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
-../bin/nitg --global ./strings/substr_bench.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
-../bin/nitg --global ./strings/utf_substr_bench.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
-
case "$1" in
iter) shift; bench_iteration $@ ;;
cct) shift; bench_concat $@ ;;
end
end
-fun bench_rope(str_size: Int, nb_ccts: Int, loops: Int)
-do
- var lft = "a" * str_size
-
- for i in [0..loops] do
- var str: String = new RopeString.from(lft)
- for j in [0..nb_ccts] do
- str += lft
- end
- end
-end
-
fun bench_flatbuf(str_size: Int, nb_ccts: Int, loops: Int)
do
var lft = "a" * str_size
end
var opts = new OptionContext
-var mode = new OptionEnum(["rope", "flatstr", "flatbuf"], "Mode", -1, "-m")
+var mode = new OptionEnum(["flatstr", "flatbuf"], "Mode", -1, "-m")
var nb_ccts = new OptionInt("Number of concatenations per loop", -1, "--ccts")
var loops = new OptionInt("Number of loops to be done", -1, "--loops")
var strlen = new OptionInt("Length of the base string", -1, "--strlen")
var modval = mode.value
if modval == 0 then
- bench_rope(strlen.value, nb_ccts.value, loops.value)
-else if modval == 1 then
bench_flatstr(strlen.value, nb_ccts.value, loops.value)
-else if modval == 2 then
+else if modval == 1 then
bench_flatbuf(strlen.value, nb_ccts.value, loops.value)
else
opts.usage
import opts
-fun bench_rope_iter(nb_cct: Int, loops: Int, strlen: Int)
-do
- var a = "a" * strlen
- var x:String = new RopeString.from(a)
- for i in [0 .. nb_cct] do x += a
- var cnt = 0
- var c: Char
- while cnt != loops do
- for i in x do
- c = i
- end
- cnt += 1
- end
-end
-
-fun bench_rope_index(nb_cct: Int, loops: Int, strlen: Int)
-do
- var a = "a" * strlen
- var x:String = new RopeString.from(a)
- for i in [0 .. nb_cct] do x += a
- var cnt = 0
- var c: Char
- var pos = 0
- while cnt != loops do
- pos = 0
- while pos < x.length do
- c = x[pos]
- pos += 1
- end
- cnt += 1
- end
-end
-
fun bench_flatstr_iter(nb_cct: Int, loops: Int, strlen: Int)
do
var a = "a" * strlen
end
var opts = new OptionContext
-var mode = new OptionEnum(["rope", "flatstr", "flatbuf"], "Mode", -1, "-m")
+var mode = new OptionEnum(["flatstr", "flatbuf"], "Mode", -1, "-m")
var access_mode = new OptionEnum(["iterator", "index"], "Iteration mode", -1, "--iter-mode")
var nb_ccts = new OptionInt("Number of concatenations done to the string (in the case of the rope, this will increase its depth)", -1, "--ccts")
var loops = new OptionInt("Number of loops to be done", -1, "--loops")
if modval == 0 then
if iterval == 0 then
- bench_rope_iter(nb_ccts.value, loops.value, strlen.value)
- else if iterval == 1 then
- bench_rope_index(nb_ccts.value, loops.value, strlen.value)
- else
- opts.usage
- exit(-1)
- end
-else if modval == 1 then
- if iterval == 0 then
bench_flatstr_iter(nb_ccts.value, loops.value, strlen.value)
else if iterval == 1 then
bench_flatstr_index(nb_ccts.value, loops.value, strlen.value)
opts.usage
exit(-1)
end
-else if modval == 2 then
+else if modval == 1 then
if iterval == 0 then
bench_flatbuf_iter(nb_ccts.value, loops.value, strlen.value)
else if iterval == 1 then
import opts
-fun bench_rope(nb_cct: Int, loops: Int, strlen: Int)
-do
- var a = "a" * strlen
- var x:String = new RopeString.from(a)
- for i in [0 .. nb_cct] do x += a
- var cnt = 0
- while cnt != loops do
- x.substring(0,5)
- cnt += 1
- end
-end
-
fun bench_flatstr(nb_cct: Int, loops: Int, strlen: Int)
do
var a = "a" * strlen
end
var opts = new OptionContext
-var mode = new OptionEnum(["rope", "flatstr", "flatbuf"], "Mode", -1, "-m")
+var mode = new OptionEnum(["flatstr", "flatbuf"], "Mode", -1, "-m")
var nb_ccts = new OptionInt("Number of concatenations done to the string (in the case of the rope, this will increase its depth)", -1, "--ccts")
var loops = new OptionInt("Number of loops to be done", -1, "--loops")
var strlen = new OptionInt("Length of the base string", -1, "--strlen")
var modval = mode.value
if modval == 0 then
- bench_rope(nb_ccts.value, loops.value, strlen.value)
-else if modval == 1 then
bench_flatstr(nb_ccts.value, loops.value, strlen.value)
-else if modval == 2 then
+else if modval == 1 then
bench_flatbuf(nb_ccts.value, loops.value, strlen.value)
else
opts.usage
CFLAGS = -g -O2 -Wno-unused-value -Wno-switch
CINCL =
LDFLAGS ?=
-LDLIBS ?= -lm `pkg-config --libs bdw-gc`
+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 `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
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)
var done_tag: Tag = 5.tag
# Number of tasks within each task assignation with `task_tag`
- var tasks_per_packet = 4
+ var tasks_per_packet = 1
# Run the main logic of this node
fun run is abstract
# Gather and registar all tasks
fun create_tasks
do
- var c = 0
- for engine in engines do for prog in test_programs do
+ for prog in test_programs do for engine in engines do
tasks.add new Task(engine, prog)
- c += 1
end
end
end
if res == 5 then result.fail = true
if res == 6 then result.soso = true
if res == 7 then result.skip = true
+ if res == 8 then result.todo = true
+ if res == 9 then result.skip_exec = true
if res == 0 then result.unknown = true
results.add result
print "* {results.fixmes.length} fixmes"
print "* {results.sosos.length} sosos"
print "* {results.skips.length} skips"
+ print "* {results.todos.length} todos"
+ print "* {results.skip_execs.length} skip execs"
print "* {results.unknowns.length} unknowns (bug in tests.sh or nitester)"
end
# Output file directory
var out_dir = "/dev/shm/nit_out{rank}" is lazy
+ # Directory to store the xml files produced for Jenkins
+ var xml_dir = "~/jenkins_xml/"
+
# Output file of the `tests.sh` script
var tests_sh_out = "/dev/shm/nit_local_out{rank}" is lazy
- # Path to the local copy of the Nit repository
- var nit_copy_dir = "/dev/shm/nit{rank}/" is lazy
-
# Source Nit repository, must be already updated and `make` before execution
var nit_source_dir = "~/nit"
fun setup
do
if verbose > 0 then sys.system "hostname"
- sys.system "git clone {nit_source_dir} {nit_copy_dir}"
end
# Clean up the testing environment
do
if comp_dir.file_exists then comp_dir.rmdir
if out_dir.file_exists then out_dir.rmdir
- if nit_copy_dir.file_exists then nit_copy_dir.rmdir
if tests_sh_out.file_exists then tests_sh_out.file_delete
end
# Receive tasks to execute
mpi.recv_into(task_buffer, 0, 1, status.source, status.tag, comm_world)
var first_id = task_buffer[0]
- for task_id in [first_id .. first_id + tasks_per_packet] do
+ for task_id in [first_id .. first_id + tasks_per_packet[ do
# If id is over all known tasks, stop right here
if task_id >= tasks.length then break
var task = tasks[task_id]
# Command line to execute test
- var cmd = "XMLDIR={out_dir} ERRLIST={out_dir}/errlist TMPDIR={out_dir} " +
+ var cmd = "XMLDIR={xml_dir} ERRLIST={out_dir}/errlist TMPDIR={out_dir} " +
"CCACHE_DIR={ccache_dir} CCACHE_TEMPDIR={ccache_dir} CCACHE_BASEDIR={comp_dir} " +
- "./tests.sh --compdir {comp_dir} --outdir {out_dir} -o \"--make-flags '-j1'\"" +
- " --node --engine {task.engine} {nit_copy_dir / "tests" / task.test_program} > {tests_sh_out}"
+ "./tests.sh --compdir {comp_dir} --outdir {out_dir} " +
+ " --node --engine {task.engine} {task.test_program} > {tests_sh_out}"
# Execute test
sys.system cmd
if line.has("[======= fail") then res = 5
if line.has("[======= soso") then res = 6
if line.has("[skip]") then res = 7
+ if line.has("[todo]") then res = 8
+ if line.has("[skip exec]") then res = 9
if res == null then
res = 0
# Is `self` result a _soso_?
var soso = false
- # Is `self` skipped test?
+ # Has `self` been skipped?
var skip = false
+ # Is `self` TODO?
+ var todo = false
+
+ # Has the execution of `self` been skipped?
+ var skip_exec = false
+
# Is `self` an unknown result, probably an error
var unknown = false
if ok_empty then err = "0k"
if fixme then err = "fixme"
if fail then err = "fail"
+ if soso then err = "soso"
+ if skip then err = "skip"
+ if todo then err = "todo"
+ if skip_exec then err = "skip_exec"
return "{task} arg{arg} alt{alt} => {err}"
end
var fails = new HashSet[Result]
var sosos = new HashSet[Result]
var skips = new HashSet[Result]
+ var todos = new HashSet[Result]
+ var skip_execs = new HashSet[Result]
var unknowns = new HashSet[Result]
# TODO remove
if result.fail then fails.add result
if result.soso then sosos.add result
if result.skip then skips.add result
+ if result.todo then todos.add result
+ if result.skip_exec then skip_execs.add result
if result.unknown then unknowns.add result
super
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
bin/pep8analysis:
mkdir -p bin
- ../../bin/nitg --global -o bin/pep8analysis src/pep8analysis.nit
+ ../../bin/nitg -o bin/pep8analysis src/pep8analysis.nit
doc/index.html:
../../bin/nitdoc src/pep8analysis.nit
class PatternWithDir
super BM_Pattern
- var dir: String
+ var dir: String is noinit
init with_dir(motif, dir: String)
do
+++ /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.
-
default:
- ../../../bin/nitg --global converter.nit
+ ../../../bin/nitg --semi-global converter.nit
HTTPD_PY := python $(NACL_SDK_ROOT)/tools/httpd.py
serve:
2. Declare the environment variable NACL_SDK_ROOT as the root of the target platform within the SDK (ex: ~/nacl_sdk/pepper_34/) :
$ export NACL_SDK_ROOT=/path/to/nacl_sdk/pepper_[your_version]
-3. Compile the Nit code with: `nitg --global converter.nit` or `make`.
+3. Compile the Nit code with: `nitg --semi-global converter.nit` or `make`.
-You must use the '--global' option. Some features in the standard library are not supported by the NaCL platform, the global compiler do not try to compile them.
+You must use the '--semi-global' (or `--global`) option. Some features in the standard library are not supported by the NaCL platform, the global compiler do not try to compile them.
4. Start a local server using: `make serve`.
break
end
- print "Solved, after looking at {r.steps} positions during {c.lapse}"
+ print "Solved, after looking at {r.steps} positions"
pb.print_plan(r.plan)
end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Ropes with a special kind of Leaves that act similar to a `Buffer`
+#
+# When using this module, re-allocations are limited by the introduction
+# of a larger-than-necessary buffered area for the native part of a `String`
+# in an append-only fashion.
+#
+# Concretely, when concatenating two small strings of length `n` + `m` < `maxlen`
+# What happens is that a `maxlen` byte buffer is allocated, ready to receive more
+# bytes a posteriori without necessarily reallocating a new byte array.
+#
+# Theoretically, this should lower the number of concatenations
+# and reallocations when concatenating `String` objects.
+module buffered_ropes
+
+intrude import standard::ropes
+
+# Hidden buffer, used to simulate a `FlatBuffer` on a short string.
+#
+# This is to be used by low-level APIs because of its lack of
+# safety, if you use it, make sure you know what you are doing !
+#
+# Practically, it is the underlying representation of a `Leaf` in
+# the `Rope` block, its advantage is that it saves a bit more space
+# for future concatenations, without risking to overwrite previously
+# used space, making it suitable for Strings.
+#
+# Note for future use : Should there be parallel capacity in Nit at
+# some point, this is NOT thread safe !
+private class ManualBuffer
+ var ns: NativeString is noinit
+ # Current position in the `NativeString`
+ #
+ # It is used by the clients of `ManualBuffer` as a guard
+ # to detect if the concatenation in the `ManualBuffer`
+ # is safe or not.
+ #
+ # i.e. :
+ # Say we have two strings `x` and `y` referencing the
+ # same `ManualBuffer` `b`, `y` is the concatenation of
+ # `x` and another string.
+ #
+ # If we try to concatenate a `String` `z` to `x`, a new
+ # `ManualBuffer` will be created since `pos` and `x.length`
+ # do not match.
+ #
+ # However, if we concatenate the same `String` to `y`,
+ # the contents of `z` will be copied to the `ManualBuffer`.
+ var pos = 0
+
+ init do ns = new NativeString(maxlen)
+
+ fun [](i: Int): Char do return ns[i]
+end
+
+# Simple implementation of the iterator on Substrings for `Leaf`
+#
+# Basically just returns `self` encapsulated in a `FlatString`.
+private class LeafSubstrings
+ super IndexedIterator[Text]
+
+ var str: String
+ var avail = true
+
+ init(l: Leaf) do str = new FlatString.with_infos(l.buf.ns, l.length, 0, l.length - 1)
+
+ redef fun is_ok do return avail
+
+ redef fun next do avail = false
+
+ redef fun index do return 0
+
+ redef fun item do return str
+end
+
+# Leaf of a `Rope`, used as a buffered area for speedy concatenation.
+private class Leaf
+ super RopeString
+
+ private var buf: ManualBuffer
+ private var bns: NativeString is noinit
+ redef var length: Int is noinit
+
+ redef fun empty do return new Leaf(new ManualBuffer)
+
+ redef fun to_cstring do
+ var len = length
+ var ns = new NativeString(len + 1)
+ ns[len] = '\0'
+ buf.ns.copy_to(ns, len, 0, 0)
+ return ns
+ end
+
+ redef fun substrings do return new LeafSubstrings(self)
+
+ redef fun [](i) do return buf[i]
+
+ init do
+ bns = buf.ns
+ length = buf.pos
+ end
+
+ redef fun output do new FlatString.with_infos(buf.ns, length, 0, length - 1).output
+
+ redef fun to_upper do
+ var x = new ManualBuffer
+ var nns = x.ns
+ var ns = bns
+ var mlen = length
+ for i in [0..mlen[ do
+ nns[i] = ns[i].to_upper
+ end
+ x.pos = mlen - 1
+ return new Leaf(x)
+ end
+
+ redef fun to_lower do
+ var x = new ManualBuffer
+ var nns = x.ns
+ var ns = bns
+ var mlen = length
+ for i in [0..mlen[ do
+ nns[i] = ns[i].to_lower
+ end
+ x.pos = mlen - 1
+ return new Leaf(x)
+ end
+
+ redef fun reversed do
+ var x = new ManualBuffer
+ var nns = x.ns
+ var ns = bns
+ var mlen = length
+ var j = mlen - 1
+ for i in [0 .. mlen[ do
+ nns[j] = ns[i]
+ j -= 1
+ end
+ x.pos = mlen - 1
+ return new Leaf(x)
+ end
+
+ redef fun substring(from, len) do
+ return new FlatString.with_infos(buf.ns, len, from, from + len - 1)
+ end
+
+ redef fun insert_at(s, pos) do
+ var l = substring(0, pos)
+ var r = substring_from(pos)
+ return l + s + r
+ end
+
+ redef fun +(o) do
+ var s = o.to_s
+ var slen = s.length
+ var mlen = length
+ if slen == 0 then return self
+ if mlen == 0 then return s
+ var nlen = mlen + slen
+ if nlen > maxlen then return new Concat(self, s)
+ if s isa FlatString then
+ var bpos = buf.pos
+ var sits = s.items
+ if bpos == mlen then
+ sits.copy_to(buf.ns, slen, s.index_from, bpos)
+ buf.pos = bpos + slen
+ return new Leaf(buf)
+ else
+ var b = new ManualBuffer
+ var nbns = b.ns
+ bns.copy_to(nbns, mlen, 0, 0)
+ sits.copy_to(nbns, slen, s.index_from, mlen)
+ b.pos = nlen
+ return new Leaf(b)
+ end
+ else if s isa Leaf then
+ var bpos = buf.pos
+ var sbns = s.bns
+ if bpos == mlen then
+ sbns.copy_to(bns, slen, 0, bpos)
+ buf.pos += slen
+ return new Leaf(buf)
+ else
+ var b = new ManualBuffer
+ var nbns = b.ns
+ bns.copy_to(nbns, mlen, 0, 0)
+ sbns.copy_to(nbns, slen, 0, mlen)
+ b.pos = nlen
+ return new Leaf(b)
+ end
+ else if s isa Concat then
+ if not s.left isa Concat then
+ return new Concat(self + s.left, s.right)
+ end
+ return new Concat(self, s)
+ else
+ var bpos = buf.pos
+ var b = buf
+ if bpos != mlen then
+ b = new ManualBuffer
+ bns.copy_to(b.ns, mlen, 0, 0)
+ end
+ for i in s.chars do
+ bns[bpos] = i
+ bpos += 1
+ end
+ return new Leaf(b)
+ end
+ end
+end
+
+redef class Concat
+ redef fun to_cstring do
+ var len = length
+ var ns = new NativeString(len + 1)
+ ns[len] = '\0'
+ var off = 0
+ for i in substrings do
+ var ilen = i.length
+ if i isa FlatString then
+ i.items.copy_to(ns, ilen, i.index_from, off)
+ else if i isa Leaf then
+ i.buf.ns.copy_to(ns, ilen, 0, off)
+ else
+ abort
+ end
+ off += ilen
+ end
+ return ns
+ end
+
+ redef fun +(o) do
+ var s = o.to_s
+ var mlen = length
+ var slen = s.length
+ if s isa FlatString then
+ var r = right
+ var rlen = r.length
+ if rlen + slen > maxlen then return new Concat(left, new Concat(r, s))
+ return new Concat(left, r + s)
+ else if s isa Concat then
+ return new Concat(self, s)
+ else if s isa Leaf then
+ var r = right
+ var rlen = r.length
+ if rlen + slen > maxlen then return new Concat(left, new Concat(r, s))
+ return new Concat(left, r + s)
+ else
+ abort
+ end
+ end
+end
+
+redef class FlatString
+ redef fun +(o) do
+ var s = o.to_s
+ var slen = s.length
+ var mlen = length
+ if slen == 0 then return self
+ if mlen == 0 then return s
+ if s isa FlatString then
+ if slen + mlen > maxlen then return new Concat(self, s)
+ var mits = items
+ var sifrom = s.index_from
+ var mifrom = index_from
+ var sits = s.items
+ var b = new ManualBuffer
+ var bns = b.ns
+ mits.copy_to(bns, mlen, mifrom, 0)
+ sits.copy_to(bns, slen, sifrom, mlen)
+ b.pos = mlen + slen
+ return new Leaf(b)
+ else if s isa Concat then
+ var sl = s.left
+ var sllen = sl.length
+ if sllen + mlen > maxlen then return new Concat(self, s)
+ return new Concat(sl + self, s.right)
+ else if s isa Leaf then
+ if slen + mlen > maxlen then return new Concat(self, s)
+ var mits = items
+ var mifrom = index_from
+ var sb = s.buf
+ var b = new ManualBuffer
+ var bns = b.ns
+ items.copy_to(bns, mlen, mifrom, 0)
+ sb.ns.copy_to(bns, slen, 0, mlen)
+ b.pos = mlen + slen
+ return new Leaf(b)
+ else
+ abort
+ end
+ end
+end
+
+redef class Array[E]
+
+ # Fast implementation
+ redef fun to_s do
+ var l = length
+ if l == 0 then return ""
+ if l == 1 then if self[0] == null then return "" else return self[0].to_s
+ var its = _items
+ var na = new NativeArray[String](l)
+ var i = 0
+ var sl = 0
+ var mypos = 0
+ while i < l do
+ var itsi = its[i]
+ if itsi == null then
+ i += 1
+ continue
+ end
+ var tmp = itsi.to_s
+ sl += tmp.length
+ na[mypos] = tmp
+ i += 1
+ mypos += 1
+ end
+ var ns = new NativeString(sl + 1)
+ ns[sl] = '\0'
+ i = 0
+ var off = 0
+ while i < mypos do
+ var tmp = na[i]
+ var tpl = tmp.length
+ if tmp isa FlatString then
+ tmp.items.copy_to(ns, tpl, tmp.index_from, off)
+ off += tpl
+ else
+ for j in tmp.substrings do
+ var slen = j.length
+ if j isa FlatString then
+ j.items.copy_to(ns, slen, j.index_from, off)
+ else if j isa Leaf then
+ j.buf.ns.copy_to(ns, slen, 0, off)
+ end
+ off += slen
+ end
+ end
+ i += 1
+ end
+ return ns.to_s_with_length(sl)
+ end
+end
+++ /dev/null
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# This file is free software, which comes along with NIT. This software is
-# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE. You can modify it if you want, provided this header
-# is kept unaltered, and a notification of the changes is added.
-# You are allowed to redistribute it and sell it, alone or as a part of
-# another product.
-
-# Introduces ropes with buffered leaves
-module bufferized_ropes
-
-import standard
-intrude import standard::ropes
-
-# Leaf containing a FlatBuffer to optimize concatenation operations
-private class BufferLeaf
- super Leaf
-
- init(val: FlatBuffer) do
- self.str = val
- length = str.length
- end
-
-end
-
-redef class Concat
- redef fun to_leaf
- do
- if left == null then
- if right == null then return new StringLeaf("".as(FlatString))
- return right.to_leaf
- end
- if right == null then return left.as(not null).to_leaf
- if left.length + right.length < buf_len then
- var b = new FlatBuffer.with_capacity(buf_len)
- b.append(left.to_leaf.str)
- b.append(right.to_leaf.str)
- return new BufferLeaf(b)
- else
- var b = new FlatBuffer.with_capacity(left.length + right.length)
- b.append(left.to_leaf.str)
- b.append(right.to_leaf.str)
- return new StringLeaf(b.lazy_to_s(b.length))
- end
- end
-end
-
-redef class FlatText
-
- # Creates a substring, only without any copy overhead for Buffers
- # The call to lazy_substring ensures the creation of a FlatString, which is required for Leaves.
- private fun lazy_substring(from: Int, length: Int): FlatString is abstract
-
- # Same as substring_from, but without copy of the data for Buffers.
- private fun lazy_substring_from(from: Int): FlatString is abstract
-end
-
-redef class FlatBuffer
-
- # Same as to_s, only will not copy self before returning a String.
- private fun lazy_to_s(len: Int): FlatString
- do
- return new FlatString.with_infos(items, len, 0, length - 1)
- end
-
- redef fun lazy_substring(from,length)
- do
- return new FlatString.with_infos(items, length, from, from + length - 1)
- end
-
- redef fun lazy_substring_from(from)
- do
- var newlen = length - from
- return new FlatString.with_infos(items, newlen, from, from + newlen - 1)
- end
-
-end
-
-redef class FlatString
-
- redef fun lazy_substring(from, len) do return substring(from,len).as(FlatString)
-
- redef fun lazy_substring_from(from) do return substring_from(from).as(FlatString)
-
-end
-
-redef class Rope
-
- # Empty Rope
- init do root = new BufferLeaf(new FlatBuffer.with_capacity(buf_len))
-
-end
-
-redef class RopeString
-
- init from(s: String) do
- if s.length < buf_len then
- var b = new FlatBuffer.with_capacity(buf_len)
- b.append(s)
- root = new BufferLeaf(b)
- else
- if s isa RopeString then root = s.root else root = new StringLeaf(s.as(FlatString))
- end
- end
-
- redef fun +(o) do return insert_at(o.to_s, length)
-
- # Inserts a String `str` at position `pos`
- redef fun insert_at(str, pos)
- do
- if str.length == 0 then return self
-
- assert pos >= 0 and pos <= length
-
- if pos == length then
- var r = root
- if r isa BufferLeaf then
- var b = r.str.as(FlatBuffer)
- if r.length + str.length < b.capacity then
- b.append(str)
- return new RopeString.from_root(new BufferLeaf(b))
- end
- end
- end
-
- var path = node_at(pos)
-
- var cct: RopeNode
-
- if path.offset == path.leaf.length then
- cct = build_node_len_offset(path, str)
- else if path.offset == 0 then
- cct = build_node_zero_offset(path, str)
- else
- cct = build_node_other(path,str)
- end
-
- if path.stack.is_empty then return new RopeString.from_root(cct)
-
- var tmp = path.stack.pop
- var last_concat: Concat
-
- if tmp.left then
- last_concat = new Concat(cct,tmp.node.right.as(not null))
- else
- last_concat = new Concat(tmp.node.left.as(not null), cct)
- end
-
- for i in path.stack.reverse_iterator do
- var nod: Concat
- if i.left then
- nod = new Concat(last_concat, i.node.right.as(not null))
- else
- nod = new Concat(i.node.left.as(not null), last_concat)
- end
- last_concat = nod
- end
-
- return new RopeString.from_root(last_concat)
- end
-
- redef fun substring(pos, len)
- do
- if pos < 0 then
- len += pos
- pos = 0
- end
-
- if pos + len > length then len = length - pos
-
- if len <= 0 then return new RopeString
-
- var path = node_at(pos)
-
- var lf = path.leaf
- var offset = path.offset
-
- var s: FlatString
- if lf isa StringLeaf then
- s = lf.str.as(FlatString)
- else
- s = lf.str.as(FlatBuffer).lazy_to_s(lf.length)
- end
-
- if path.leaf.str.length - offset > len then
- lf = new StringLeaf(s.substring(offset,len).as(FlatString))
- else
- lf = new StringLeaf(s.substring_from(offset).as(FlatString))
- end
-
- var nod: RopeNode = lf
-
- if lf.length == len then return new RopeString.from_root(lf)
-
- var lft: nullable RopeNode
- var rht: nullable RopeNode
-
- for i in path.stack.reverse_iterator do
- if i.right then continue
- lft = nod
- rht = i.node.right
- nod = new Concat(lft, rht)
- end
-
- var ret = new RopeString
- ret.root = nod
-
- path = ret.node_at(len-1)
-
- offset = path.offset
-
- lf = path.leaf
-
- if lf isa StringLeaf then
- s = lf.str.as(FlatString)
- else
- s = lf.str.as(FlatBuffer).lazy_to_s(lf.length)
- end
-
- nod = new StringLeaf(s.substring(0, offset+1).as(FlatString))
-
- for i in path.stack.reverse_iterator do
- if i.left then continue
- rht = nod
- lft = i.node.left
- nod = new Concat(lft, rht)
- end
-
- ret.root = nod
-
- return ret
- end
-
- private fun build_node_zero_offset(path: Path, s: String): RopeNode
- do
- var finlen = path.leaf.length + s.length
- if finlen <= buf_len then
- var b = new FlatBuffer.with_capacity(buf_len)
- b.append(s)
- b.append(path.leaf.str)
- if finlen == buf_len then return new StringLeaf(b.lazy_to_s(finlen))
- return new BufferLeaf(b)
- end
- var rht = path.leaf
- var lft: RopeNode
- if s isa FlatString then
- if s.length > buf_len then
- lft = new StringLeaf(s)
- else
- var b = new FlatBuffer
- b.append(s)
- lft = new BufferLeaf(b)
- end
- else
- lft = s.as(RopeString).root
- end
- return new Concat(lft, rht)
- end
-
- private fun build_node_len_offset(path: Path, s: String): RopeNode
- do
- var leaf = path.leaf
- if leaf isa BufferLeaf then
- if s.length > buf_len then
- if s isa FlatString then
- return new Concat(leaf, new StringLeaf(s))
- else
- return new Concat(leaf, s.as(Rope).root)
- end
- end
- var finlen = leaf.length + s.length
- var buf = leaf.str.as(FlatBuffer)
- var cap = buf.capacity
- # Meaning the buffer was modified elsewhere
- # Therefore, we create a new one
- if leaf.length != buf.length then
- var b = new FlatBuffer.with_capacity(buf_len)
- b.append(buf.lazy_to_s(leaf.length))
- buf = b
- end
- if finlen <= cap then
- buf.append(s)
- if finlen == buf_len then return new StringLeaf(buf.lazy_to_s(finlen))
- return new BufferLeaf(buf)
- else
- var l_len = finlen - cap
- buf.append(s.substring(0,l_len))
- var b2 = new FlatBuffer.with_capacity(buf_len)
- b2.append(s.substring_from(l_len))
- var left_leaf = new StringLeaf(buf.lazy_to_s(buf.length))
- var right_leaf = new BufferLeaf(b2)
- var cct = new Concat(left_leaf, right_leaf)
- return cct
- end
- else
- var lft = leaf
- var rht: RopeNode
- if s.length >= buf_len then
- if s isa FlatString then rht = new StringLeaf(s) else rht = s.as(Rope).root
- else
- var buf = new FlatBuffer.with_capacity(buf_len)
- buf.append(s)
- rht = new BufferLeaf(buf)
- end
- return new Concat(lft,rht)
- end
- end
-
- private fun build_node_other(path: Path,str: String): RopeNode
- do
- var lf = path.leaf
- var s: FlatString
- if lf isa BufferLeaf then
- var b = lf.str.as(FlatBuffer)
- s = b.lazy_to_s(lf.length)
- else
- s = lf.str.as(FlatString)
- end
- var l_str = s.lazy_substring(0, path.offset)
- var r_str = s.lazy_substring_from(path.offset)
- if s.length + str.length < buf_len then
- var buf = new FlatBuffer.with_capacity(buf_len)
- buf.append(l_str)
- buf.append(str)
- buf.append(r_str)
- return new BufferLeaf(buf)
- end
- var child: RopeNode
- if str isa FlatString then child = new StringLeaf(str) else child = str.as(Rope).root
- var l_cct = new Concat(new StringLeaf(l_str), child)
- var r_cct = new Concat(l_cct, new StringLeaf(r_str))
- return r_cct
- end
-
-end
-
-redef class SubstringsIterator
-
- # Compute the bounds of the current substring and makes the substring
- redef fun make_substring
- do
- var l = nodes.item
- var s = l.str
- var min = 0
- var length = l.length
- if nodes.index < pos then
- min = pos - nodes.index
- end
- substring = s.lazy_substring(min, length)
- end
-
-end
-
-redef class ReverseSubstringsIterator
-
- redef fun make_substring
- do
- var l = leaves.item
- var s = l.str
- if pos > (leaves.index + l.length - 1) then return
- str = s.lazy_substring(0, (pos - leaves.index + 1))
- end
-
-end
-
-# Default size of a buffer in a rope leaf.
-fun buf_len: Int do return 200
-
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Cartesian products on heterogeneous collections.
+#
+# This module is a proof-of-concept to propose memory-efficient views on collections.
+#
+# This is a specific alternative to `combinations`, that focuses only highly efficient
+# Cartesian products between collections of different types.
+#
+# Collection[Int] X Collection[String] -> Collection[(Int,String)]
+#
+# However, in Nit, there in no native *tuple* type.
+# So we need a first building block, a pair.
+
+# A simple read-only pair of two elements `e` and `f`.
+class Pair[E, F]
+ # The first element of the pair
+ var e: E
+
+ # The second element of the pair
+ var f: F
+
+ # The parenthesized notation.
+ #
+ # ~~~
+ # var p = new Pair[Int, String](1, "hello")
+ # assert p.to_s == "(1,hello)"
+ # ~~~
+ redef fun to_s
+ do
+ var es = e or else ""
+ var fs = f or else ""
+ return "({es},{fs})"
+ end
+
+ # Untyped pair equality.
+ #
+ # ~~~
+ # var p1 = new Pair[Object, Object](1, 2)
+ # var p2 = new Pair[Int, Int](1, 2)
+ # var p3 = new Pair[Int, Int](1, 3)
+ #
+ # assert p1 == p2
+ # assert p2 != p3
+ # ~~~
+ #
+ # Untyped because we want that `p1 == p2` above.
+ # So the method just ignores the real types of `E` and `F`.
+ redef fun ==(o) do return o isa Pair[nullable Object, nullable Object] and e == o.e and f == o.f
+
+ redef fun hash do return e.hash * 13 + f.hash * 27 # Magic numbers are magic!
+end
+
+# A view of a Cartesian-product collection over two collections.
+#
+# A Cartesian product over two collections is just a collection of pairs.
+# Therefore, this view *contains* all the pairs of elements constructed by associating each
+# element of the first collection to each element of the second collection.
+#
+# However the view is memory-efficient and the pairs are created only when needed.
+#
+# A simple Cartesian product
+# ~~~~
+# var c1 = [1,2]
+# var c2 = ["a","b","c"]
+# var c12 = new Cartesian[Int,String](c1, c2)
+# assert c12.length == 6
+# assert c12.join(";") == "(1,a);(1,b);(1,c);(2,a);(2,b);(2,c)" # All the 6 pairs
+# ~~~~
+#
+# Note: because it is a view, changes on the base collections are reflected on the view.
+#
+# E.g. c12 is a view on c1 and c2, so if c1 changes, then c12 "changes".
+# ~~~~
+# assert c2.pop == "c"
+# assert c12.length == 4
+# assert c12.join(";") == "(1,a);(1,b);(2,a);(2,b)" # All the 4 remaining pairs
+# ~~~~
+#
+# Cartesian objects are collections, so can be used to build another Cartesian object.
+# ~~~~
+# var c3 = [1000..2000[
+# var c123 = new Cartesian[Pair[Int,String],Int](c12, c3)
+# assert c123.length == 4000
+# ~~~~
+#
+# All methods of Collection are inherited, it is so great!
+#
+# E.g. search elements?
+# ~~~~
+# var p12 = new Pair[Int,String](2,"b")
+# assert c12.has(p12) == true
+# var p123 = new Pair[Pair[Int, String], Int](p12, 1500)
+# var p123bis = new Pair[Pair[Int, String], Int](p12, 0)
+# assert c123.has(p123) == true
+# assert c123.has(p123bis) == false
+# ~~~~
+class Cartesian[E, F]
+ super Collection[Pair[E,F]]
+
+ # The first collection
+ var ce: Collection[E]
+
+ # The second collection
+ var cf: Collection[F]
+
+ redef fun length do return ce.length * cf.length # optional, but so efficient...
+
+ redef fun iterator do return new CartesianIterator[E,F](self)
+
+ # Returns a new Cartesian where the first collection is the second.
+ # Because the full collection is virtual, the operation is cheap!
+ fun swap: Cartesian[F, E] do return new Cartesian[F, E](cf, ce)
+end
+
+# An iterator over a `Cartesian`-product collection.
+class CartesianIterator[E,F]
+ super Iterator[Pair[E,F]]
+
+ # The associated Cartesian-product collection.
+ var collection: Cartesian[E,F]
+
+ # The iterator over the first collection of the Cartesian product.
+ # Will be used only once.
+ private var ice: Iterator[E] is noinit
+
+ # The iterator over the second collection of the Cartesian product.
+ # Will be used once for each element of the first collection.
+ private var icf: Iterator[F] is noinit
+
+ init do
+ # Initialize each iterator
+ ice = collection.ce.iterator
+ icf = collection.cf.iterator
+ end
+
+ redef fun is_ok do return ice.is_ok and icf.is_ok
+
+ redef fun item do
+ # We lazily create the pair here
+ var res = item_cache
+ if res == null then
+ res = new Pair[E,F](ice.item, icf.item)
+ item_cache = res
+ end
+ return res
+ end
+
+ # Cached pair created by `item` and cleared by `next`.
+ private var item_cache: nullable Pair[E,F] = null
+
+ redef fun next do
+ # Next item in the second iterator
+ icf.next
+ if not icf.is_ok then
+ # If it is over, then reset it and advance the first iterator
+ icf = collection.cf.iterator
+ ice.next
+ end
+ # Reset the cache
+ item_cache = null
+ end
+
+ # First member of `item`.
+ #
+ # This method shortcut the allocation of a `Pair`, thus should be more time and memory efficient.
+ fun item_e: E do return ice.item
+
+ # Second member of `item`.
+ #
+ # This method shortcut the allocation of a `Pair`, thus should be more time and memory efficient.
+ fun item_f: E do return icf.item
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Cartesian products, combinations and permutation on collections.
+#
+# This module offers memory-efficient views on combinatoric collections.
+# Methods of the views create objects only when needed.
+# Moreover, produced objects during iterations are free to be collected and
+# their memory reused.
+#
+# This enable these views and method to works with very combinatoric large collections.
+#
+# When small combinatoric views need to be kept in memory (for fast access by example).
+# The `Collection::to_a` method and other related factories can be used to transform
+# the combinatoric views into extensive collections,
+module combinations
+
+redef class Collection[E]
+ # Cartesian product, over `r` times `self`.
+ #
+ # See `CartesianCollection` for details.
+ #
+ # FIXME: Cannot be used if RTA is enabled. So `niti` or `--erasure` only.
+ fun product(r: Int): Collection[SequenceRead[E]]
+ do
+ return new CartesianCollection[E]([self]*r)
+ end
+
+ # All `r`-length permutations on self (all possible ordering) without repeated elements.
+ #
+ # See `CartesianCollection` for details.
+ #
+ # FIXME: Cannot be used if RTA is enabled. So `niti` or `--erasure` only.
+ fun permutations(r: Int): Collection[SequenceRead[E]]
+ do
+ var res = new CombinationCollection[E](self, r)
+ res.are_sorted = false
+ res.are_unique = true
+ return res
+ end
+
+ # All `r`-length combinations on self (in same order) without repeated elements.
+ #
+ # See `CartesianCollection` for details.
+ #
+ # FIXME: Cannot be used if RTA is enabled. So `niti` or `--erasure` only.
+ fun combinations(r: Int): Collection[SequenceRead[E]]
+ do
+ var res = new CombinationCollection[E](self, r)
+ res.are_sorted = true
+ res.are_unique = true
+ return res
+ end
+
+ # All `r`-length combination on self (in same order) with repeated elements.
+ #
+ # See `CartesianCollection` for details.
+ #
+ # FIXME: Cannot be used if RTA is enabled. So `niti` or `--erasure` only.
+ fun combinations_with_replacement(r: Int): Collection[SequenceRead[E]]
+ do
+ var res = new CombinationCollection[E](self, r)
+ res.are_sorted = true
+ res.are_unique = false
+ return res
+ end
+end
+
+# A view of a Cartesian-product collection over homogeneous collections.
+#
+# Therefore, this view *generates* all the sequences of elements constructed by associating
+# en element for each one of the original collections.
+#
+# It is equivalent to doing nesting `for` for each collection.
+#
+# ~~~~
+# var xs = [1, 2, 3]
+# var ys = [8, 9]
+# var xys = new CartesianCollection[Int]([xs, ys])
+# assert xys.length == 6
+# assert xys.to_a == [[1,8], [1,9], [2,8], [2,9], [3,8], [3,9]]
+# ~~~~
+#
+# The pattern of the generate sequences produces a lexicographical order.
+#
+# Because it is a generator, it is memory-efficient and the sequences are created only when needed.
+#
+# Note: because it is a view, changes on the base collections are reflected on the view.
+#
+# ~~~~
+# assert xs.pop == 3
+# assert ys.pop == 9
+# assert xys.to_a == [[1,8], [2,8]]
+# ~~~~
+class CartesianCollection[E]
+ super Collection[SequenceRead[E]]
+
+ # The base collections used to generate the sequences.
+ var collections: SequenceRead[Collection[E]]
+
+ redef fun length
+ do
+ var res = 1
+ for c in collections do res = res * c.length
+ return res
+ end
+
+ redef fun iterator do return new CartesianIterator[E](self)
+end
+
+private class CartesianIterator[E]
+ super Iterator[SequenceRead[E]]
+ var collection: CartesianCollection[E]
+
+ # The array of iterations that will be increased in the lexicographic order.
+ private var iterators = new Array[Iterator[E]]
+
+ init
+ do
+ for c in collection.collections do
+ var it = c.iterator
+ iterators.add it
+ if not it.is_ok then is_ok = false
+ end
+ end
+
+ redef var is_ok = true
+
+ redef fun item
+ do
+ var len = iterators.length
+ var res = new Array[E].with_capacity(len)
+ for i in [0..len[ do
+ var it = iterators[i]
+ res.add(it.item)
+ end
+ return res
+ end
+
+ redef fun next
+ do
+ var rank = iterators.length - 1
+
+ # Odometer-like increment starting from the last iterator
+ loop
+ var it = iterators[rank]
+ it.next
+ if it.is_ok then return
+
+ # The iterator if over
+ if rank == 0 then
+ # It it is the first, then the whole thing is over
+ is_ok = false
+ return
+ end
+
+ # If not, restart the iterator and increment the previous one
+ # (like a carry)
+ iterators[rank] = collection.collections[rank].iterator
+ rank -= 1
+ end
+ end
+end
+
+# A view of some combinations over a base collections.
+#
+# This view *generates* some combinations and permutations on a collection.
+#
+# By default, the generated sequences are combinations:
+#
+# * each sequence has a length of `repeat`
+# * elements are in sorted order (see `are_sorted` for details)
+# * no repeated element (see `are_unique` for details)
+#
+# ~~~~
+# var xs = [1, 2, 3]
+# var cxs = new CombinationCollection[Int](xs, 2)
+# assert cxs.length == 3
+# assert cxs.to_a == [[1,2], [1,3], [2,3]]
+# ~~~~
+#
+# Other kind of combinations can be generated by tweaking the attributes `are_sorted` and `are_unique`.
+#
+# * for permutation:
+#
+# ~~~~
+# cxs.are_sorted = false
+# cxs.are_unique = true
+# assert cxs.length == 6
+# assert cxs.to_a == [[1,2], [1,3], [2,1], [2,3], [3,1], [3,2]]
+# ~~~~
+#
+# * for combinations with replacement:
+#
+# ~~~~
+# cxs.are_sorted = true
+# cxs.are_unique = false
+# assert cxs.length == 6
+# assert cxs.to_a == [[1,1], [1,2], [1,3], [2,2], [2,3], [3,3]]
+# ~~~~
+#
+# * for product:
+#
+# ~~~~
+# cxs.are_sorted = false
+# cxs.are_unique = false
+# assert cxs.length == 9
+# assert cxs.to_a == [[1,1], [1,2], [1,3], [2,1], [2,2], [2,3], [3,1], [3,2], [3,3]]
+# ~~~~
+#
+# However, in the last case, a faster alternative is to use `CartesianCollection`:
+#
+# ~~~~
+# var cp = new CartesianCollection[Int]([xs] * 2)
+# assert cp.to_a == cxs.to_a
+# ~~~~
+#
+# As seen in the examples, the patterns of the generated sequences produce a lexicographical order.
+#
+# Because it is a generator, it is memory-efficient and the sequences are created only when needed.
+#
+# Note: because it is a view, changes on the base collection are reflected on the view.
+#
+# ~~~~
+# assert xs.pop == 3
+# cxs.are_sorted = true
+# cxs.are_unique = true
+# assert cxs.to_a == [[1,2]]
+# ~~~~
+class CombinationCollection[E]
+ super Collection[SequenceRead[E]]
+
+ # The base collection used to generate the sequences.
+ var collection: Collection[E]
+
+ # The maximum length of each generated sequence.
+ var repeat: Int
+
+ init
+ do
+ assert repeat >= 0
+ end
+
+ # Are the elements in the generated sequences sorted?
+ # Default `true`.
+ #
+ # When `true`, the original order is preserved.
+ #
+ # Elements are compared by their order in the base collection,
+ # not by their intrinsic value or comparability.
+ #
+ # ~~~~
+ # var xs = [1, 1, 2]
+ # var cxs = new CombinationCollection[Int](xs, 2)
+ # cxs.are_sorted = true
+ # assert cxs.to_a == [[1,1], [1,2], [1, 2]]
+ # cxs.are_sorted = false
+ # assert cxs.to_a == [[1,1], [1,2], [1, 1], [1, 2], [2, 1], [2, 1]]
+ # ~~~~
+ var are_sorted = true is writable
+
+ # Are the element in the generated sequence unique?
+ # Default `true`.
+ #
+ # When `true`, an element cannot be reused in the same sequence (no replacement).
+ #
+ # Elements are distinguished by their order in the base collection,
+ # not by their intrinsic value or equality.
+ #
+ # ~~~~
+ # var xs = [1, 1, 2]
+ # var cxs = new CombinationCollection[Int](xs, 2)
+ # cxs.are_unique = true
+ # assert cxs.to_a == [[1,1], [1,2], [1, 2]]
+ # cxs.are_unique = false
+ # assert cxs.to_a == [[1,1], [1,1], [1,2], [1,1], [1,2], [2,2]]
+ # ~~~~
+ var are_unique = true is writable
+
+ redef fun length
+ do
+ var n = collection.length
+ if are_unique then
+ if repeat > n then
+ return 0
+ end
+ if are_sorted then
+ return n.factorial / repeat.factorial
+ else
+ return n.factorial / (n-repeat).factorial
+ end
+ else
+ if are_sorted then
+ return (n+repeat-1).factorial / repeat.factorial / (n-1).factorial
+ else
+ return n ** repeat
+ end
+ end
+ end
+
+ redef fun iterator do
+ return new CombinationIterator[E](self)
+ end
+end
+
+private class CombinationIterator[E]
+ super Iterator[SequenceRead[E]]
+ var product: CombinationCollection[E]
+
+ private var iterators = new Array[Iterator[E]]
+ private var indices = new Array[Int]
+
+ var are_sorted: Bool is noinit
+ var are_unique: Bool is noinit
+
+ init
+ do
+ are_sorted = product.are_sorted
+ are_unique = product.are_unique
+
+ for rank in [0..product.repeat[ do
+ reset_iterator(rank)
+ end
+ end
+
+ redef var is_ok = true
+
+ redef fun item
+ do
+ var len = product.repeat
+ var res = new Array[E].with_capacity(len)
+ for i in [0..len[ do
+ var it = iterators[i]
+ res.add(it.item)
+ end
+ return res
+ end
+
+ redef fun next
+ do
+ var rank = product.repeat - 1
+
+ loop
+ var it = iterators[rank]
+
+ if are_unique and not are_sorted then
+ var idx = indices[rank] + 1
+ it.next
+ var adv = next_free(rank, idx)
+ for i in [idx..adv[ do it.next
+ indices[rank] = adv
+ else
+ it.next
+ indices[rank] += 1
+ end
+
+ if it.is_ok then break
+ if rank == 0 then
+ is_ok = false
+ return
+ end
+ rank -= 1
+ end
+
+ for r in [rank+1..product.repeat[ do
+ reset_iterator(r)
+ end
+ end
+
+ private fun next_free(rank: Int, start: Int): Int
+ do
+ loop
+ for i in [0..rank[ do
+ if indices[i] == start then
+ start += 1
+ continue label
+ end
+ end
+ break label
+ end label
+ return start
+ end
+
+ private fun reset_iterator(rank: Int): Iterator[E]
+ do
+ var it = product.collection.iterator
+ iterators[rank] = it
+ var skip = 0
+
+ if (not are_sorted and not are_unique) or rank == 0 then
+ # DO NOTHING
+ else if are_sorted and are_unique then
+ skip = indices[rank-1] + 1
+ else if are_sorted then
+ skip = indices[rank-1]
+ else
+ skip = next_free(rank, 0)
+ end
+
+ for i in [0..skip[ do it.next
+ indices[rank] = skip
+ if not it.is_ok then is_ok = false
+ return it
+ end
+
+ fun need_skip: Bool
+ do
+ if not are_sorted and not are_unique then
+ return false
+ else if are_sorted and are_unique then
+ var max = -1
+ for i in indices do
+ if i <= max then return true
+ max = i
+ end
+ return false
+ else if are_sorted then
+ var max = -1
+ for i in indices do
+ if i < max then return true
+ max = i
+ end
+ return false
+ else
+ # are_unique
+ for i in indices do
+ if indices.count(i) > 1 then return true
+ end
+ return false
+ end
+ end
+end
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
# Add a raw html string
# add_html("<a href='#top'>top</a>")
- fun add_html(html: String) do current.add(new HTMLRaw(html))
+ fun add_html(html: String) do current.add(new HTMLRaw("", html))
# Open a html tag
# open("ul")
# HTML tagname: 'div' for <div></div>
var tag: String
- init(tag: String) do
- self.tag = tag
+ init do
self.is_void = (once ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr"]).has(tag)
end
#
# assert (new HTMLTag("img")).is_void == true
# assert (new HTMLTag("p")).is_void == false
- var is_void: Bool
+ var is_void: Bool is noinit
init with_attrs(tag: String, attrs: Map[String, String]) do
self.tag = tag
# assert p.write_to_string == "<p>Hello<br/>World!</p>"
# Text is escaped see: standard::String::html_escape
fun append(txt: String): HTMLTag do
- add(new HTMLRaw(txt.html_escape))
+ add(new HTMLRaw("", txt.html_escape))
return self
end
#
# Note: the HTML in insered as it, no verification is done.
fun add_raw_html(txt: String): HTMLTag do
- add(new HTMLRaw(txt))
+ add(new HTMLRaw("", txt))
return self
end
super HTMLTag
private var content: String
- init(content: String) do self.content = content
redef fun render_in(res) do res.add content
end
private var jvm_cache: nullable JavaVM = null
private var jni_env_cache: nullable JniEnv = null
- # Default Java Virtual Machine to use (will be instanciated using
+ # Default Java Virtual Machine to use (will be instantiated using
# `create_default_jvm` if not already set)
fun jvm: JavaVM
do
# Sets the current default JNI env (use with `jvm=`)
fun jni_env=(jni_env: JniEnv) do jni_env_cache = jni_env
- # Called by `jvm` and `jni_env` to instanciate a Java Virual Machine.
+ # Called by `jvm` and `jni_env` to instantiate a Java Virtual Machine.
# Used mostly for the FFI with Java.
protected fun create_default_jvm
do
var builder = new JavaVMBuilder
- # By default, look for Java classes in a jar file the same dir as the executable
+ # By default, look for Java classes in a jar file the same directory as the executable
builder.options.add "-Djava.class.path={sys.program_name}.jar"
var jvm = builder.create_jvm
fun load_jclass(name: NativeString): JClass import jni_env `{
JNIEnv *nit_ffi_jni_env = Sys_jni_env(recv);
- // retreive the implementation Java class
+ // retrieve the implementation Java class
jclass java_class = (*nit_ffi_jni_env)->FindClass(nit_ffi_jni_env, name);
if (java_class == NULL) {
fprintf(stderr, "Nit FFI with Java error: failed to load class.\\n");
end
redef class Text
+ # Get `self` as a `JavaString`
fun to_java_string: JavaString do return to_cstring.to_java_string
end
private fun pop_from_local_frame_with_env(jni_env: JniEnv): SELF `{
return (*jni_env)->PopLocalFrame(jni_env, recv);
`}
+
+ # Is `self` null in Java?
+ #
+ # Since Java type system doesn't have the same `nullable` concept as Nit's,
+ # the two systems are not directly compatible. Any Nit instances of
+ # `JavaObject` may hold a Java null.
+ #
+ # To benefit from the safer type system of Nit, it is recommended to check
+ # the return of all extern methods implemented in Java to ensure the value
+ # is not a Java null. In case it is, you should replace it by a normal Nit
+ # `null`.
+ fun is_java_null: Bool in "Java" `{ return recv == null; `}
+
+ # `JavaString` representation of `self` using Java's `toString`
+ fun to_java_string: JavaString in "Java" `{ return recv.toString(); `}
+
+ # Use Java's `toString` for any `JavaObject`
+ redef fun to_s
+ do
+ if is_java_null then return super
+ return to_java_string.to_s
+ end
end
#
# See: http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/jniTOC.html
module jvm is
- c_compiler_option("-I $(JAVA_HOME)/include/")
- c_linker_option("-L $(JNI_LIB_PATH) -ljvm")
+ c_compiler_option "-I $(JAVA_HOME)/include/ -I $(JAVA_HOME)/include/linux/"
+ c_linker_option "-L $(JNI_LIB_PATH) -ljvm"
end
in "C Header" `{
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
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Uses JSON as a storage medium for a Neo4j subgraph.
+module neo4j::json_store
+
+import neo4j
+private import template
+
+# A Neo4j graph that uses as a storage medium.
+#
+# The graph is stored as a JSON object with the following properties:
+#
+# * `"nodes"`: An array with all nodes. Each node is an object with the
+# following properties:
+# * `"id"`: The ID (`Int`) that uniquely identifies the node in the current
+# graph.
+# * `"labels"`: An array of all applied labels.
+# * `"properties"`: An object mapping each defined property to its value.
+# * `"links"`: An array with all relationships. Each relationship is an object
+# with the following properties:
+# * `"type"`: The type (`String`) of the relationship.
+# * `"properties"`: An object mapping each defined property to its value.
+# * `"from"`: The ID (`Int`) of the source node.
+# * `"to"`: The ID (`Int`) of the destination node.
+#
+# TODO Refine the graph API instead when it will be available.
+class JsonGraph
+ super Jsonable
+
+ # All nodes in the graph.
+ var nodes: SimpleCollection[NeoNode] = new Array[NeoNode]
+
+ # All relationships in the graph.
+ var links: SimpleCollection[NeoEdge] = new Array[NeoEdge]
+
+ # Create an empty graph.
+ init do end
+
+ # Retrieve the graph from the specified JSON value.
+ #
+ # var graph = new JsonGraph
+ # var a = new NeoNode
+ # a.labels.add "Foo"
+ # a["answer"] = 42
+ # a["Ultimate question of"] = new JsonArray.from(["life",
+ # "the Universe", "and Everything."])
+ # graph.nodes.add a
+ # var b = new NeoNode
+ # b.labels.add "Foo"
+ # b.labels.add "Bar"
+ # graph.nodes.add b
+ # graph.links.add new NeoEdge(a, "BAZ", b)
+ # #
+ # graph = new JsonGraph.from_json(graph.to_json)
+ # assert 1 == graph.links.length
+ # for link in graph.links do
+ # assert "BAZ" == link.rel_type
+ # assert a.labels == link.from.labels
+ # for k, v in a.properties do assert v == link.from.properties[k]
+ # assert b.labels == link.to.labels
+ # for k, v in b.properties do assert v == link.to.properties[k]
+ # end
+ # assert 2 == graph.nodes.length
+ init from_json(t: Text) do
+ from_json_object(t.to_jsonable.as(JsonObject))
+ end
+
+ # Retrieve the graph from the specified JSON object.
+ init from_json_object(o: JsonObject) do
+ var node_by_id = new HashMap[Int, NeoNode]
+ var nodes = o["nodes"].as(JsonArray)
+ for json_node in nodes do
+ assert json_node isa JsonObject
+ var node = new NeoNode.from_json_object(json_node)
+ node_by_id[json_node["id"].as(Int)] = node
+ self.nodes.add node
+ end
+ var links = o["links"].as(JsonArray)
+ for json_link in links do
+ assert json_link isa JsonObject
+ var from = node_by_id[json_link["from"].as(Int)]
+ var to = node_by_id[json_link["to"].as(Int)]
+ var rel_type = json_link["type"].as(String)
+ var json_properties = json_link["properties"].as(JsonObject)
+ var link = new NeoEdge(from, rel_type, to)
+ link.properties.recover_with(json_properties)
+ self.links.add link
+ end
+ end
+
+ redef fun to_json do
+ var t = new Template
+ t.add "\{\"nodes\":["
+ var i = 0
+ for n in nodes do
+ if i > 0 then t.add ","
+ t.add n.to_json
+ i += 1
+ end
+ t.add "],\"links\":["
+ i = 0
+ for link in links do
+ if i > 0 then t.add ","
+ t.add link.to_json
+ i += 1
+ end
+ t.add "]\}"
+ return t.write_to_string
+ end
+end
+
+# Make `NeoNode` `Jsonable`.
+redef class NeoNode
+ super Jsonable
+
+ # Retrieve the node from the specified JSON value.
+ #
+ # Note: Here, the `"id"` is optional and ignored.
+ #
+ # SEE: `JsonGraph`
+ #
+ # var node = new NeoNode.from_json("""
+ # {
+ # "labels": ["foo", "Bar"],
+ # "properties": {
+ # "baz": 42
+ # }
+ # }
+ # """)
+ # assert ["foo", "Bar"] == node.labels
+ # assert 42 == node["baz"]
+ init from_json(t: Text) do
+ from_json_object(t.to_jsonable.as(JsonObject))
+ end
+
+ # Retrieve the node from the specified JSON value.
+ #
+ # Note: Here, the `"id"` is optional and ignored.
+ #
+ # SEE: `JsonGraph`
+ init from_json_object(o: JsonObject) do
+ init
+ var labels = o["labels"].as(JsonArray)
+ for lab in labels do self.labels.add(lab.as(String))
+ var json_properties = o["properties"].as(JsonObject)
+ properties.recover_with(json_properties)
+ end
+
+ # Get the JSON representation of `self`.
+ #
+ # SEE: `JsonGraph`
+ redef fun to_json do
+ var t = new Template
+ t.add "\{\"id\":"
+ t.add object_id.to_json
+ t.add ",\"labels\":["
+ var i = 0
+ for lab in labels do
+ if i > 0 then t.add ","
+ t.add lab.to_json
+ i += 1
+ end
+ t.add "],\"properties\":"
+ t.add properties.to_json
+ t.add "}"
+ return t.write_to_string
+ end
+
+ redef fun to_s do return to_json
+end
+
+# Make `NeoEdge` `Jsonable`.
+redef class NeoEdge
+ super Jsonable
+
+ redef fun to_json do
+ var t = new Template
+ t.add "\{\"type\":"
+ t.add rel_type.to_json
+ t.add ",\"properties\":"
+ t.add properties.to_json
+ t.add ",\"from\":"
+ t.add from.object_id.to_json
+ t.add ",\"to\":"
+ t.add to.object_id.to_json
+ t.add "}"
+ return t.write_to_string
+ end
+
+ redef fun to_s do return to_json
+end
# Perform a `CypherQuery`
# see: CypherQuery
fun cypher(query: CypherQuery): Jsonable do
- return post("{cypher_url}", query.to_json)
+ return post("{cypher_url}", query.to_rest)
end
# GET JSON data from `url`
return self
end
- # Translate the query to JSON
- fun to_json: JsonObject do
+ # Translate the query to the body of a corresponding Neo4j REST request.
+ fun to_rest: JsonObject do
var obj = new JsonObject
obj["query"] = query
if not params.is_empty then
return obj
end
- redef fun to_s do return to_json.to_s
+ redef fun to_s do return to_rest.to_s
end
# The fundamental units that form a graph are nodes and relationships.
# Is the property `key` set?
fun has_key(key: String): Bool do return properties.has_key(key)
-
- # Translate `self` to JSON
- fun to_json: JsonObject do return properties
end
# Nodes are used to represent entities stored in base.
var tpl = new FlatBuffer
tpl.append "\{"
tpl.append "labels: [{labels.join(", ")}],"
- tpl.append "data: {to_json}"
+ tpl.append "data: {properties.to_json}"
tpl.append "\}"
return tpl.write_to_string
end
# Get edge type
fun rel_type: nullable String do return internal_type
- redef fun to_json do
+ # Get the JSON body of a REST request that create the relationship.
+ private fun to_rest: JsonObject do
var obj = new JsonObject
if to.is_linked then
obj["to"] = to.url
else
job.to = "\{{edge.from.batch_id.to_s}\}/relationships"
end
- job.body = edge.to_json
+ job.body = edge.to_rest
end
# Create multiple edges
var request = new JsonPOST(client.batch_url, client.curl)
# request.headers["X-Stream"] = "true"
var json_jobs = new JsonArray
- for job in jobs.values do json_jobs.add job.to_json
+ for job in jobs.values do json_jobs.add job.to_rest
request.data = json_jobs
var response = request.execute
var res = client.parse_response(response)
var body: nullable Jsonable = null
# JSON formated job
- fun to_json: JsonObject do
+ fun to_rest: JsonObject do
var job = new JsonObject
job["id"] = id
job["method"] = method
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
var iterators = new Array[Iterator[E]]
- init(tree: OrderedTree[E]) do
- self.tree = tree
-
+ init do
if not tree.is_empty then
iterators.add tree.roots.iterator
end
# A null value represents the upper bound of identifier
private var interval = new List[Couple[nullable Int, nullable Int]]
- # An array used as a temporary Hashtable for
+ # An array used as a temporary Hashtable for
# checking there is no collision between identifiers
private var tempht = new Array[nullable Int]
# By default, all identifiers are available
interval.push(new Couple[nullable Int, nullable Int](1, null))
end
-
+
# Returns a mask composed by discriminants bits
- # for these given identifiers
+ # for these given identifiers
# The mask + 1 value is the size of the hastable to create
fun phand(ids: Array[Int]): Int
do
mask = orMask.bin_xor(andMask)
# Re-initialize the hashtable with null values
- for i in [0..mask+1] do tempht[i] = null
+ for i in [0..(mask+1)] do tempht[i] = null
# Optimize the already computed mask
var newmask = 0
while i != 0 do
if mask.getbit(i) == 1 then
newmask = mask.bin_xor(1.lshift(i))
-
+
# If there is no collision, replace the old mask
if phandp(ids, newmask) then
mask = newmask
tempht[hv] = mask
end
end
-
+
return true
end
end
# Resetting hashtable
+ for j in [0..(mask+1)] do tempht[j] = null
+
+ # Set the temporary hashtable for `compute_least_free_ids`
phandp(ids, mask)
# Fill the given array with n free identifiers
# Tests if this id is free for this mask
var hv = i.bin_and(mask)
- # If the hashtable if full, push an empty item
+ # If the hashtable if full, push an empty item
if hv >= tempht.length then
tempht.push(null)
end
if tempht[hv] != mask then
found = true
id = i
- end
+ end
i = i + 1
end
else
inter.item.first += 1
end
- else
+ else
if id != inter.item.first and id != inter.item.second then
# We need to split in two this interval
var last = inter.item.second
return fe.dtos.has(t)
end
- # Display the POSet in a gaphical windows.
- # Graphviz with a working -Txlib is expected.
- # Used fo debugging.
- fun show_dot
+ # Write the POSet as a graphviz digraph.
+ #
+ # Nodes are identified with their `to_s`.
+ # Edges are unlabeled.
+ fun write_dot(f: OStream)
do
- var f = new OProcess("dot", "-Txlib")
- #var f = stdout
f.write "digraph \{\n"
for x in elements.keys do
- f.write "\"{x}\";\n"
+ var xstr = x.to_s.escape_to_dot
+ f.write "\"{xstr}\";\n"
var xe = self.elements[x]
for y in xe.dtos do
+ var ystr = y.to_s.escape_to_dot
if self.has_edge(y,x) then
- f.write "\"{x}\" -> \"{y}\"[dir=both];\n"
+ f.write "\"{xstr}\" -> \"{ystr}\"[dir=both];\n"
else
- f.write "\"{x}\" -> \"{y}\";\n"
+ f.write "\"{xstr}\" -> \"{ystr}\";\n"
end
end
end
f.write "\}\n"
- #f.close
- #f.wait
+ end
+
+ # Display the POSet in a graphical windows.
+ # Graphviz with a working -Txlib is expected.
+ #
+ # See `write_dot` for details.
+ fun show_dot
+ do
+ var f = new OProcess("dot", "-Txlib")
+ f.write "\}\n"
+ write_dot(f)
+ f.close
+ f.wait
end
# Compare two elements in an arbitrary total order.
# Exposes methods for debugging ropes when needed.
module ropes_debug
-intrude import ::standard::ropes
-import ::standard
+import standard
+intrude import standard::ropes
-redef class Rope
+redef class Text
# Writes self as a dot file on the hard drive
- fun to_dot(filepath: String): String is abstract
-end
+ private fun internal_to_dot: String is abstract
-redef class RopeNode
- # Generates a dot string
- fun to_dot(s: String): String is abstract
+ fun to_dot: String do
+ return "digraph g \{\n" + internal_to_dot + "\}\n"
+ end
end
-redef class Leaf
- redef fun to_dot(s): String
+redef class Concat
+ redef fun internal_to_dot: String
do
- s += "n{object_id} [label = \"{str}\" shape = rect];\n"
- s += "n{str.object_id} -> n{object_id} [label = \"contains\"];\n"
- s = str.to_dot(s)
+ var s = "n{object_id} [label = {length}];\n"
+ s += "n{object_id} -> n{left.object_id} [label = \"left\"];\n"
+ s += left.internal_to_dot
+ s += "n{object_id} -> n{right.object_id} [label = \"right\"];\n"
+ s += right.internal_to_dot
return s
end
end
-redef class Concat
- redef fun to_dot(s): String
+redef class RopeBuffer
+ redef fun internal_to_dot: String
do
- s += "n{object_id} [label = {length}];\n"
- if left != null then
- s += "n{object_id} -> n{left.object_id} [label = \"left\"];\n"
- s = left.to_dot(s)
- end
- if right != null then
- s += "n{object_id} -> n{right.object_id} [label = \"right\"];\n"
- s = right.to_dot(s)
- end
+ var s = "n{object_id} [label = {length}];\n"
+ s += "n{object_id} -> n{str.object_id} [label = \"str\"];\n"
+ s += str.internal_to_dot
+ s += "n{object_id} -> n{ns.object_id} [label = \"ns\"];\n"
+ s += "n{ns.object_id}[label = \"NativeString\", content=\"{ns.to_s_with_length(rpos)}\"];\n"
return s
end
end
-redef class FlatText
- fun to_dot(s: String): String is abstract
-end
-
redef class FlatString
- redef fun to_dot(s: String): String
+ redef fun internal_to_dot: String
do
- return s + "n{object_id} [label=\"FlatString\\nindex_from = {index_from}\\nindex_to = {index_to}\\nNativeString = {items.to_s_with_length(items.cstring_length)}\"];\n"
+ return "n{object_id} [label=\"FlatString\\nindex_from = {index_from}\\nindex_to = {index_to}\\nNativeString = {items.to_s_with_length(items.cstring_length)}\"];\n"
end
end
redef class FlatBuffer
- redef fun to_dot(s: String): String
+ redef fun internal_to_dot: String
do
- return s + "n{object_id} [label=\"FlatBuffer\\length = {length}\\ncapacity = {capacity}\\nitems = {items.to_s_with_length(items.cstring_length)}\"];\n"
+ return "n{object_id} [label=\"FlatBuffer\\length = {length}\\ncapacity = {capacity}\\nitems = {items.to_s_with_length(items.cstring_length)}\"];\n"
end
end
-redef class RopeString
- redef fun to_dot(filepath: String)
- do
- var of = new OFStream.open(filepath)
- var ret: String = new RopeString.from("digraph g \{\n")
- ret = root.to_dot(ret).as(RopeString)
- ret += "\}\n"
- ret.write_to(of)
- of.close
- return ret
- end
-end
-
-
+++ /dev/null
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# This file is free software, which comes along with NIT. This software is
-# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE. You can modify it is you want, provided this header
-# is kept unaltered, and a notification of the changes is added.
-# You are allowed to redistribute it and sell it, alone or is a part of
-# another product.
-
-# Introduces a self-balancing method on Rope, using a Splay Tree
-module splay_ropes
-
-import standard
-intrude import standard::ropes
-
-redef class Rope
-
- # Performs a Left rotation on node `x`
- # Since a Rope does not have any notion of parent in its node, they need to be passed as arguments if available.
- private fun left_rotate(r: Concat): Concat
- do
- var rr = r.right.as(Concat)
- var rl = r.left
- var pl = rr.left
- var pr = rr.right
- var nr = new Concat(rl, pl)
- var np = new Concat(nr, pr)
- return np
- end
-
- # Performs a Right rotation on node `r`
- # Since a Rope does not have any notion of parent in its node, they need to be passed as arguments if available.
- private fun right_rotate(r: Concat): Concat
- do
- var rl = r.left.as(Concat)
- var rr = r.right
- var pr = rl.right
- var pl = rl.left
- var nr = new Concat(pr, rr)
- var np = new Concat(pl, nr)
- return np
- end
-
- # Performs a Splay operation on a complete path
- # The last node of the path will become the root.
- private fun splay(path: Path): nullable Concat
- do
- var st = path.stack
- if st.is_empty then return null
- var cct = st.pop.node
- while not st.is_empty do
- var tmp = st.pop
- var nod: Concat
- if tmp.left then
- nod = new Concat(cct, tmp.node.right)
- cct = right_rotate(nod)
- else
- nod = new Concat(tmp.node.left, cct)
- cct = left_rotate(nod)
- end
- end
- return cct
- end
-end
-
-redef class RopeString
-
- # Inserts a String `str` at position `pos`
- redef fun insert_at(str, pos)
- do
- if str.length == 0 then return self
- if self.length == 0 then return new RopeString.from(str)
-
- assert pos >= 0 and pos <= length
-
- var path = node_at(pos)
-
- var last_concat: Concat
-
- if path.offset == 0 then
- if str isa FlatString then
- last_concat = new Concat(new StringLeaf(str), path.leaf)
- else
- last_concat = new Concat(str.as(RopeString).root, path.leaf)
- end
- else if path.offset == path.leaf.length then
- if str isa FlatString then
- last_concat = new Concat(path.leaf, new StringLeaf(str))
- else
- last_concat = new Concat(path.leaf, str.as(RopeString).root)
- end
- else
- var s = path.leaf.str
- var l_half = s.substring(0, s.length - path.offset)
- var r_half = s.substring_from(s.length - path.offset)
- var cct: Concat
- var ll = new StringLeaf(l_half.as(FlatString))
- if str isa FlatString then
- cct = new Concat(ll, new StringLeaf(str))
- else
- cct = new Concat(ll, str.as(RopeString).root)
- end
- last_concat = new Concat(cct, new StringLeaf(r_half.as(FlatString)))
- end
-
- var st = path.stack
-
- if st.is_empty then return new RopeString.from_root(last_concat)
-
- var tmp = st.pop
-
- if tmp.left then
- var n = tmp.node.right
- var r = new Concat(last_concat, n)
- st.push(new PathElement(r))
- else
- var n = tmp.node.left
- var r = new Concat(n, last_concat)
- st.push(new PathElement(r))
- end
-
- return new RopeString.from_root(splay(path).as(not null))
- end
-
-end
-
fun destroy do close
# Close this connection
- fun close `{ sqlite3_close_v2(recv); `}
+ fun close `{
+#if SQLITE_VERSION_NUMBER >= 3007014
+ sqlite3_close_v2(recv);
+#else
+ // A program using the older version should not rely on the garbage-collector
+ // to close its connections. They must be closed manually after the associated
+ // prepare statements have been finalized.
+ sqlite3_close(recv);
+#endif
+ `}
# Execute a SQL statement
fun exec(sql: String): Sqlite3Code import String.to_cstring `{
redef fun iterator do return new ContainerIterator[E](self)
- # Create a new instance with a given initial value.
- init(e: E) do item = e
-
# The stored item
var item: E is writable
end
redef fun next do is_ok = false
- init(c: Container[E]) do _container = c
-
redef var is_ok: Bool = true
private var container: Container[E]
end
private var iter: Iterator[Couple[K,V]]
-
- init(i: Iterator[Couple[K,V]]) do _iter = i
end
# Some tools ###################################################################
# The second element of the couple.
var second: S is writable
-
- # Create a new instance with a first and a second object.
- init(f: F, s: S)
- do
- first = f
- second = s
- end
end
res.append(other)
return res
end
+
+ # Repetition of arrays.
+ #
+ # returns a new array built by concatenating `self` `repeat` times.
+ #
+ # var a = [1,2,3]
+ # assert (a * 0).is_empty
+ # assert a * 1 == [1,2,3]
+ # assert a * 2 == [1,2,3,1,2,3]
+ # assert (a * 10).length == 30
+ fun *(repeat: Int): Array[E]
+ do
+ assert repeat >= 0
+ var res = new Array[E].with_capacity(length * repeat)
+ while repeat > 0 do
+ res.add_all(self)
+ repeat -= 1
+ end
+ return res
+ end
end
# An `Iterator` on `AbstractArray`
redef fun next do _index += 1
- init(a: AbstractArrayRead[E])
- do
- _array = a
- _index = 0
- end
-
redef var index = 0
private var array: AbstractArrayRead[E]
redef fun next do _index -= 1
- init(a: AbstractArrayRead[E])
+ init
do
- _array = a
- _index = a.length - 1
+ _index = _array.length - 1
end
end
redef fun item: E do return _iter.item
- init(iter: ArrayIterator[E]) do _iter = iter
-
private var iter: ArrayIterator[E]
end
private var prev_item: nullable N = null
private var prev_in_bucklet: nullable N = null
private var next_in_bucklet: nullable N = null
- init(k: K)
- do
- _key = k
- end
end
# A map implemented with a hash table.
super HashNode[K]
redef type N: HashMapNode[K, V]
private var value: V
-
- init(k: K, v: V)
- do
- super(k)
- _value = v
- end
end
class HashMapIterator[K: Object, V]
private var map: HashMap[K, V]
# The current node
- private var node: nullable HashMapNode[K, V]
+ private var node: nullable HashMapNode[K, V] = null
- init(map: HashMap[K, V])
+ init
do
_map = map
- _node = map._first_item
+ _node = _map._first_item
end
end
private class HashSetNode[E: Object]
super HashNode[E]
redef type N: HashSetNode[E]
-
- init(e: E)
- do
- _key = e
- end
end
private class HashSetIterator[E: Object]
private var set: HashSet[E]
# The position in the internal map storage
- private var node: nullable HashSetNode[E]
+ private var node: nullable HashSetNode[E] = null
- init(set: HashSet[E])
+ init
do
- _set = set
- _node = set._first_item
+ _node = _set._first_item
end
end
end
# Build a new iterator for `list`.
- private init(list: List[E])
+ init
do
- _list = list
- _node = list._head
- _index = 0
+ _node = _list._head
end
# The current list
private var list: List[E]
# The current node of the list
- private var node: nullable ListNode[E]
+ private var node: nullable ListNode[E] = null
# The index of the current node
- redef var index
+ redef var index = 0
# Remove the current item
fun delete
_index -= 1
end
- private init(list: List[E])
+ init
do
- _list = list
+ var list = _list
_node = list._tail
_index = list.length
end
# Linked nodes that constitute a linked list.
private class ListNode[E]
super Container[E]
- init(i: E)
- do
- item = i
- end
# The next node.
- var next: nullable ListNode[E]
+ var next: nullable ListNode[E] = null
# The previous node.
- var prev: nullable ListNode[E]
+ var prev: nullable ListNode[E] = null
end
# Iterator on ranges.
super Iterator[E]
private var range: Range[E]
- redef var item
+ redef var item is noinit
redef fun is_ok do return _item < _range.after
redef fun next do _item = _item.successor(1)
- init(r: Range[E])
+ init
do
- _range = r
- _item = r.first
+ _item = _range.first
end
end
end
end
- private init do end
- private init without_file do end
end
# File output stream
self.path = path
_is_writable = true
end
-
- private init do end
- private init without_file do end
end
###############################################################################
class Stdin
super IFStream
- private init do
+ init do
_file = new NativeFile.native_stdin
path = "/dev/stdin"
prepare_buffer(1)
class Stdout
super OFStream
- private init do
+ init do
_file = new NativeFile.native_stdout
path = "/dev/stdout"
_is_writable = true
class Stderr
super OFStream
- private init do
+ init do
_file = new NativeFile.native_stderr
path = "/dev/stderr"
_is_writable = true
#
# assert not 13.is_even
fun is_odd: Bool do return not is_even
+
+ # Returns the `self` raised to the power of `e`.
+ #
+ # assert 2 ** 3 == 8
+ fun **(e: Int): Int
+ do
+ return self.to_f.pow(e.to_f).to_i
+ end
+
+ # The factorial of `self` (aka `self!`)
+ #
+ # Returns `1 * 2 * 3 * ... * self-1 * self`
+ #
+ # assert 0.factorial == 1 # by convention for an empty product
+ # assert 1.factorial == 1
+ # assert 4.factorial == 24
+ # assert 9.factorial == 362880
+ fun factorial: Int
+ do
+ assert self >= 0
+ var res = 1
+ var n = self
+ while n > 0 do
+ res = res * n
+ n -= 1
+ end
+ return res
+ end
end
redef class Float
init(default_comparator)
end
- init(comparator: Comparator) do self.comparator = comparator
-
redef fun is_empty do return items.is_empty
redef fun length do return items.length
redef fun iterator do return items.iterator
-# This file is part of NIT ( http://www.nitlanguage.org ).
+# This file is part of NIT (http://www.nitlanguage.org).
#
-# This file is free software, which comes along with NIT. This software is
-# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE. You can modify it if you want, provided this header
-# is kept unaltered, and a notification of the changes is added.
-# You are allowed to redistribute it and sell it, alone or as a part of
-# another product.
-
-# Nit implementation of the Ropes (see Ropes : An Alternative to Strings,
-# SOFTWARE - PRACTICE AND EXPERIENCE, VOL. 25(12), 1315 - 1330 (DECEMBER 1995)
-# Hans. J Boehm, Russ Atkinson and Michael Plass)
+# 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
#
-# A rope is a kind of string but instead of being flat, it relies on a binary tree structure to store data.
+# 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.
+
+# Tree-based representation of a String.
+#
+# Ropes are a data structure introduced in a 1995 paper from
+# Hans J. Boehm, Russ Atkinson and Michael Plass.
+# See : `Ropes : an Alternative to Strings`, `Software - Practice and Experience,
+# Vol. 25(12), 1315-1330 (December 1995)`.
+#
+# The implementation developed here provides an automatic change
+# of data structure depending on the length of the leaves.
+#
+# The length from which a `Rope` is built from a `flat` string
+# if defined at top-level (see `maxlen`) and can be redefined by clients
+# depending on their needs (e.g. if you need to bench the speed of
+# the creation of concat nodes, lower the size of maxlen).
+#
+# A Rope as defined in the original paper is a Tree made of concatenation
+# nodes and containing `Flat` (that is Array-based) strings as Leaves.
+#
+# Example :
+#
+# ` Concat `
+# ` / \ `
+# ` Concat Concat `
+# ` / \ / \ `
+# `"My" " Name" " is" " Simon." `
+#
+# Note that the above example is not representative of the actual implementation
+# of `Ropes`, since short leaves are merged to keep the rope at an acceptable
+# height (hence, this rope here might actually be a `FlatString` !).
module ropes
intrude import string
-# Used when searching for a particular node
-# Returns the path to the node from the root of the rope
-# Also, the node and the offset for seeked position in the rope
-private class Path
- # Leaf found
- var leaf: Leaf
- # Offset in leaf
- var offset: Int
- # Stack of the nodes traversed, and the path used
- var stack: List[PathElement]
-end
+# Maxlen is the maximum length of a Leaf node
+#
+# When concatenating two leaves, if `new_length` > `maxlen`,
+# A `Concat` node is created instead
+#
+# Its purpose is to limit the depth of the `Rope` (this
+# improves performance when accessing/iterating).
+fun maxlen: Int do return 64
-# An element for a Path, has the concat node and whether or not
-# left or right child was visited.
-private class PathElement
- # Visited node
- var node: Concat
- # Was the left child visited ?
- var left = false
- # Was the right child visited ?
- var right = false
+# String using a tree-based representation with leaves as `FlatStrings`
+private abstract class Rope
+ super Text
end
-# A node for a Rope
-private abstract class RopeNode
- # Length of the node
- var length = 0
+private abstract class RopeString
+ super Rope
+ super String
- # Transforms the current node to a Leaf.
- # This might be costly to invoke since this produces a FlatString concatenation.
- # Can be used internally to limit the growth of the Rope when working with small leaves.
- fun to_leaf: Leaf is abstract
+ redef fun chars is cached do return new RopeChars(self)
end
-# Node that represents a concatenation between two nodes (of any RopeNode type)
+# Node that represents a concatenation between two `String`
private class Concat
- super RopeNode
+ super RopeString
+
+ redef var length: Int
+
+ redef fun substrings do return new RopeSubstrings(self)
+
+ redef fun empty do return ""
+
+ redef fun to_cstring is cached do
+ var len = length
+ var ns = new NativeString(len + 1)
+ ns[len] = '\0'
+ var off = 0
+ for i in substrings do
+ var ilen = i.length
+ i.as(FlatString).items.copy_to(ns, ilen, i.as(FlatString).index_from, off)
+ off += ilen
+ end
+ return ns
+ end
# Left child of the node
- var left: nullable RopeNode
+ var left: String
# Right child of the node
- var right: nullable RopeNode
+ var right: String
- init(l: nullable RopeNode, r: nullable RopeNode)
- do
+ init(l: String, r: String) do
left = l
right = r
- if l != null then length += l.length
- if r != null then length += r.length
+ length = l.length + r.length
end
- redef fun to_leaf
- do
- if left == null then
- if right == null then return new StringLeaf("".as(FlatString))
- return right.to_leaf
- end
- if right == null then return left.as(not null).to_leaf
- return new StringLeaf((left.to_leaf.str.as(FlatString) + right.to_leaf.str.as(FlatString)).as(FlatString))
+ redef fun output do
+ left.output
+ right.output
end
-end
-
-# Leaf of a Rope, contains a FlatString
-private abstract class Leaf
- super RopeNode
-
- # Encapsulated FlatString in the leaf node
- var str: FlatText
-
-end
-private class StringLeaf
- super Leaf
+ redef fun iterator do return new RopeIter(self)
- init(val: FlatString) do
- self.str = val
- length = str.length
+ redef fun *(i) do
+ var x: String = self
+ for j in [1 .. i[ do x += self
+ return x
end
- redef fun to_leaf do return self
-end
-
-# Used as a cache when using indexed access to a substring in the Rope
-private class LeafCache
- # Cached leaf
- var leaf: Leaf
- # Position in Rope
- var pos: Int
-end
-
-# Basic structure, binary tree with a root node.
-#
-# Also shared services by subsequent implementations.
-abstract class Rope
- super Text
-
- # Root node, entry point of a Rope.
- private var root: RopeNode is noinit
-
- # Cached version of self as a flat String
- private var str_representation: nullable NativeString = null
-
- private var leaf_cache: nullable LeafCache = null
-
- # Empty Rope
- init do root = new StringLeaf("".as(FlatString))
-
- # Creates a new Rope with `s` as root
- init from(s: String) do
- if s isa RopeString then root = s.root else root = new StringLeaf(s.as(FlatString))
+ redef fun [](i) do
+ var llen = left.length
+ if i >= llen then return right[i - llen]
+ return left[i]
end
- private init from_root(r: RopeNode)
- do
- root = r
+ redef fun substring(from, len) do
+ var llen = left.length
+ if from < llen then
+ if from + len < llen then return left.substring(from,len)
+ var lsublen = llen - from
+ return left.substring_from(from) + right.substring(0, len - lsublen)
+ else
+ return right.substring(from - llen, len)
+ end
end
- redef fun length do return root.length
-
- # Iterator on the nodes of the rope, in forward postfix order
- private fun postfix(from: Int): Postfix do return new Postfix.from(self, from)
-
- # Iterator on the leaves of the rope, forward order
- private fun leaves(from: Int): LeavesIterator do return new LeavesIterator(self, from)
+ redef fun reversed do return new Concat(right.reversed, left.reversed)
- # Iterator on the substrings from 0, in forward order
- redef fun substrings do return new SubstringsIterator(self, 0)
-
- # Iterator on the substrings, starting at position `from`, in forward order
- fun substrings_from(from: Int): IndexedIterator[Text] do return new SubstringsIterator(self, from)
-
- # Iterator on the nodes of the rope, in backwards postfix order
- private fun reverse_postfix(from: Int): ReversePostfix do return new ReversePostfix.from(self, from)
-
- # Iterator on the leaves of the rope, backwards order
- private fun reverse_leaves(from: Int): ReverseLeavesIterator do return new ReverseLeavesIterator(self,from)
+ redef fun insert_at(s, pos) do
+ if pos > left.length then
+ return left + right.insert_at(s, pos - left.length)
+ end
+ return left.insert_at(s, pos) + right
+ end
- # Iterator on the substrings, in reverse order
- fun reverse_substrings: IndexedIterator[Text] do return new ReverseSubstringsIterator(self, length-1)
+ redef fun to_upper do return new Concat(left.to_upper, right.to_upper)
- # Iterator on the substrings, in reverse order, starting iteration at position `from`
- fun reverse_substrings_from(from: Int): IndexedIterator[Text] do return new ReverseSubstringsIterator(self, from)
+ redef fun to_lower do return new Concat(left.to_lower, right.to_lower)
- redef fun output
- do
- for i in substrings do
- i.output
+ redef fun +(o) do
+ var s = o.to_s
+ var mlen = length
+ var slen = s.length
+ if s isa Concat then
+ return new Concat(self, s)
+ else
+ var r = right
+ var rlen = r.length
+ if rlen + slen > maxlen then return new Concat(left, new Concat(r, s))
+ return new Concat(left, r + s)
end
end
+end
- redef fun to_cstring
- do
- if str_representation != null then return str_representation.as(not null)
+# Mutable `Rope`, optimized for concatenation operations
+#
+# A `RopeBuffer` is an efficient way of building a `String` when
+# concatenating small strings.
+#
+# It does concatenations in an optimized way by having a
+# mutable part and an immutable part built by efficiently
+# concatenating strings in chain.
+#
+# Every concatenation operation is done by copying a string to
+# the mutable part and flushing it when full.
+#
+# However, when a long string is appended to the `Buffer`,
+# the concatenation is done at it would be in a `Rope`.
+class RopeBuffer
+ super Rope
+ super Buffer
- var native_final_str = calloc_string(length + 1)
+ redef fun chars: Sequence[Char] is cached do return new RopeBufferChars(self)
- native_final_str[length] = '\0'
+ # The final string being built on the fly
+ private var str: String is noinit
- if self.length == 0 then
- str_representation = native_final_str
- return native_final_str
- end
+ # Current concatenation buffer
+ private var ns: NativeString is noinit
- var offset = 0
+ # Next available (e.g. unset) character in the `Buffer`
+ private var rpos = 0
- for i in substrings do
- var str = i.flatten
- if str isa FlatString then str.items.copy_to(native_final_str, str.length, str.index_from, offset)
- offset += i.length
- end
+ # Keeps track of the buffer's currently dumped part
+ #
+ # This might happen if for instance, a String was being
+ # built by concatenating small parts of string and suddenly
+ # a long string (length > maxlen) is appended.
+ private var dumped: Int is noinit
- str_representation = native_final_str
+ # Length of the complete rope
+ redef var length = 0
- return native_final_str
- end
+ # Length of the mutable part
+ #
+ # Is also used as base to compute the size of the next
+ # mutable native string (`ns`)
+ private var buf_size: Int is noinit
- # Path to the Leaf for `position`
- private fun node_at(position: Int): Path
- do
- assert position >= 0 and position <= length
- if position == length then
- var st = new List[PathElement]
- stack_to_end(root,st)
- if not st.is_empty then
- var lst = st.last
- var lf = lst.node.right
- if lf != null then
- return new Path(lf.as(Leaf), lf.length, st)
- else
- lf = lst.node.left
- return new Path(lf.as(Leaf), lf.length, st)
- end
- else
- return new Path(root.as(Leaf), length, st)
- end
- end
- return get_node_from(root, 0, position, new List[PathElement])
- end
-
- # Special case for when the required pos is length
- private fun stack_to_end(nod: RopeNode, st: List[PathElement])
- do
- if nod isa Leaf then return
- var n = nod.as(Concat)
- var r = n.right
- var ele = new PathElement(n)
- ele.right = true
- st.push(ele)
- if r != null then
- stack_to_end(r, st)
- end
- return
- end
+ redef fun substrings: Iterator[String] do return new RopeBufSubstringIterator(self)
- # Builds the path to Leaf at position `seek_pos`
- private fun get_node_from(node: RopeNode, curr_pos: Int, seek_pos: Int, stack: List[PathElement]): Path
- do
- assert curr_pos >= 0
- if node isa Leaf then
- self.leaf_cache = new LeafCache(node, curr_pos)
- return new Path(node, seek_pos - curr_pos, stack)
- end
- node = node.as(Concat)
-
- if node.left != null then
- var next_pos = curr_pos + node.left.length
- stack.add(new PathElement(node))
- if next_pos > seek_pos then
- stack.last.left = true
- return get_node_from(node.left.as(not null), curr_pos, seek_pos, stack)
- end
- stack.last.right = true
- return get_node_from(node.right.as(not null), next_pos, seek_pos, stack)
- else
- var vis = new PathElement(node)
- vis.right = true
- stack.add(vis)
- return get_node_from(node.right.as(not null), curr_pos, seek_pos, stack)
- end
+ # Builds an empty `RopeBuffer`
+ init do
+ str = ""
+ ns = new NativeString(maxlen)
+ buf_size = maxlen
+ dumped = 0
end
- redef fun ==(o)
- do
- if not o isa Text then return false
- if o.length != self.length then return false
- var oit = o.chars.iterator
- for i in self.chars.iterator do
- if i != oit.item then return false
- oit.next
- end
- return true
+ # Builds a new `RopeBuffer` with `str` in it.
+ init from(str: String) do
+ self.str = str
+ ns = new NativeString(maxlen)
+ buf_size = maxlen
+ length = str.length
+ dumped = 0
end
-end
-# Rope that cannot be modified
-class RopeString
- super Rope
- super String
+ # Resets the informations of the `Buffer`
+ #
+ # This is called when doing in-place modifications
+ # on a previously to_s'd `RopeBuffer`
+ private fun reset do
+ var nns = new NativeString(buf_size)
+ var blen = rpos - dumped
+ ns.copy_to(nns, blen, dumped, 0)
+ dumped = 0
+ rpos = blen
+ written = false
+ end
- redef fun to_s do return self
+ redef fun empty do return new RopeBuffer
- redef fun empty do return once new RopeString.from("")
+ redef fun clear do
+ str = ""
+ length = 0
+ rpos = 0
+ end
- redef var chars: SequenceRead[Char] = new RopeStringChars(self)
+ redef fun substring(from, count) do
+ var strlen = str.length
- redef fun reversed
- do
- var ret = empty
- for i in substrings do
- ret = i.as(String).reversed + ret
+ if from < 0 then
+ count += from
+ if count < 0 then count = 0
+ from = 0
end
- return ret
- end
- redef fun to_upper
- do
- var ret = empty
- for i in substrings do
- ret += i.as(String).to_upper
- end
- return ret
- end
+ if count > length then count = length - from
- redef fun to_lower
- do
- var ret = empty
- for i in substrings do
- ret += i.as(String).to_lower
- end
- return ret
- end
+ if count == 0 then return empty
- redef fun +(o) do
- if self.length == 0 then return o.to_s
- if o.length == 0 then return self
- var str = o.to_s
- if str isa FlatString then
- return new RopeString.from_root(new Concat(root, new StringLeaf(str)))
- else if str isa RopeString then
- return new RopeString.from_root(new Concat(root, str.root))
+ if from < strlen then
+ var subpos = strlen - from
+ if count <= subpos then
+ return new RopeBuffer.from(str.substring(from, count))
+ else
+ var l = str.substring_from(from)
+ var rem = count - subpos
+ var nns = new NativeString(rem)
+ ns.copy_to(nns, rem, dumped, 0)
+ return new RopeBuffer.from(l + nns.to_s_with_length(rem))
+ end
else
- abort
- end
- end
-
- redef fun *(n)
- do
- var ret = new RopeString.from("")
- for i in [0..n[ do
- ret = (ret + self).as(RopeString)
+ var nns = new NativeString(count)
+ ns.copy_to(nns, count, dumped, 0)
+ return new RopeBuffer.from(nns.to_s_with_length(count))
end
- return ret
end
- # Inserts a String `str` at position `pos`
- redef fun insert_at(str, pos)
- do
- if str.length == 0 then return self
- if self.length == 0 then return new RopeString.from(str)
-
- assert pos >= 0 and pos <= length
-
- var path = node_at(pos)
-
- var last_concat: Concat
-
- if path.offset == 0 then
- if str isa FlatString then
- last_concat = new Concat(new StringLeaf(str), path.leaf)
- else
- last_concat = new Concat(str.as(RopeString).root, path.leaf)
+ redef fun append(s) do
+ var slen = s.length
+ length += slen
+ var rp = rpos
+ if s isa Rope then
+ if rp > 0 and dumped != rp then
+ str += new FlatString.with_infos(ns, rp - dumped, dumped, rp - 1)
+ dumped = rp
end
- else if path.offset == path.leaf.length then
- if str isa FlatString then
- last_concat = new Concat(path.leaf, new StringLeaf(str))
- else
- last_concat = new Concat(path.leaf, str.as(RopeString).root)
+ str = str + s
+ return
+ end
+ if slen > maxlen then
+ if rp > 0 and dumped != rp then
+ str += new FlatString.with_infos(ns, rp - dumped, dumped, rp - 1)
+ dumped = rp
end
+ str = str + s
+ return
+ end
+ var remsp = buf_size - rp
+ var sits: NativeString
+ var begin: Int
+ if s isa FlatString then
+ begin = s.index_from
+ sits = s.items
+ else if s isa FlatBuffer then
+ begin = 0
+ sits = s.items
else
- var s = path.leaf.str
- var l_half = s.substring(0, s.length - path.offset)
- var r_half = s.substring_from(s.length - path.offset)
- var cct: Concat
- var ll = new StringLeaf(l_half.as(FlatString))
- if str isa FlatString then
- cct = new Concat(ll, new StringLeaf(str))
+ if slen <= remsp then
+ for i in s.chars do
+ ns[rpos] = i
+ rpos += 1
+ end
else
- cct = new Concat(ll, str.as(RopeString).root)
+ var spos = 0
+ for i in [0..remsp[ do
+ ns[rpos] = s[spos]
+ rpos += 1
+ spos += 1
+ end
+ dump_buffer
+ while spos < slen do
+ ns[rpos] = s[spos]
+ spos += 1
+ rpos += 1
+ end
end
- last_concat = new Concat(cct, new StringLeaf(r_half.as(FlatString)))
+ return
end
-
- for i in path.stack.reverse_iterator do
- if i.left then
- last_concat = new Concat(last_concat, i.node.right)
+ if slen <= remsp then
+ sits.copy_to(ns, slen, begin, rp)
+ if rp == buf_size then
+ rpos = buf_size
+ dump_buffer
+ rpos = 0
else
- last_concat = new Concat(i.node.left, last_concat)
+ rpos += slen
end
+ else
+ sits.copy_to(ns, remsp, begin, rp)
+ rpos = buf_size
+ dump_buffer
+ var nlen = slen - remsp
+ sits.copy_to(ns, nlen, begin + remsp, 0)
+ rpos = nlen
end
-
- return new RopeString.from_root(last_concat)
end
- # O(log(n))
- #
- # var rope = new RopeString.from("abcd")
- # assert rope.substring(1, 2) == "bc"
- # assert rope.substring(-1, 2) == "a"
- # assert rope.substring(1, 0) == ""
- # assert rope.substring(2, 5) == "cd"
- #
- redef fun substring(pos, len)
- do
- if pos < 0 then
- len += pos
- pos = 0
+ redef fun add(c) do
+ var rp = rpos
+ length += 1
+ ns[rp] = c
+ rp += 1
+ if rp == buf_size then
+ rpos = rp
+ dump_buffer
+ rp = 0
end
+ rpos = rp
+ end
- if pos + len > length then len = length - pos
-
- if len <= 0 then return new RopeString.from("")
-
- var path = node_at(pos)
+ # Converts the Buffer to a FlatString, appends it to
+ # the final String and re-allocates a new larger Buffer.
+ private fun dump_buffer do
+ written = false
+ var nstr = new FlatString.with_infos(ns, rpos - dumped, dumped, rpos - 1)
+ str += nstr
+ var bs = buf_size
+ bs = bs * 2
+ ns = new NativeString(bs)
+ buf_size = bs
+ dumped = 0
+ end
- var lf = path.leaf
- var offset = path.offset
+ redef fun output do
+ str.output
+ new FlatString.with_infos(ns, rpos - dumped, dumped, rpos - 1).output
+ end
- if path.leaf.str.length - offset > len then lf = new StringLeaf(lf.str.substring(offset,len).as(FlatString)) else lf = new StringLeaf(lf.str.substring_from(offset).as(FlatString))
+ # Enlarge is useless here since the `Buffer`
+ # part is automatically dumped when necessary.
+ #
+ # Also, since the buffer can not be overused by a
+ # single string, there is no need for manual
+ # resizing.
+ #
+ # "You have no power here !"
+ redef fun enlarge(i) do end
- var nod: RopeNode = lf
+ redef fun to_s do
+ written = true
+ var nnslen = rpos - dumped
+ if nnslen == 0 then return str
+ return str + new FlatString.with_infos(ns, rpos - dumped, dumped, rpos - 1)
+ end
- for i in path.stack.reverse_iterator do
- if i.right then continue
- nod = new Concat(nod, i.node.right)
+ redef fun reverse do
+ str = str.reversed
+ var nns = new NativeString(buf_size)
+ var j = rpos
+ var mits = ns
+ for i in [0 .. rpos[ do
+ nns[i] = mits[j]
+ j -= 1
end
+ ns = nns
+ end
- var ret = new RopeString
- ret.root = nod
-
- path = ret.node_at(len-1)
-
- offset = path.offset
- nod = new StringLeaf(path.leaf.str.substring(0, offset+1).as(FlatString))
-
- for i in path.stack.reverse_iterator do
- if i.left then continue
- nod = new Concat(i.node.left, nod)
+ redef fun upper do
+ if written then reset
+ str = str.to_upper
+ var mits = ns
+ for i in [0 .. rpos[ do
+ mits[i] = mits[i].to_upper
end
+ end
- ret.root = nod
-
- return ret
+ redef fun lower do
+ if written then reset
+ str = str.to_lower
+ var mits = ns
+ for i in [0 .. rpos[ do
+ mits[i] = mits[i].to_lower
+ end
end
end
redef class FlatString
- redef fun insert_at(s, pos)
- do
+ redef fun insert_at(s, pos) do
+ var l = substring(0, pos)
+ var r = substring_from(pos)
+ return l + s + r
+ end
- if pos == 0 then
- var r = new RopeString.from(s)
- return r + self
- end
- if pos == length then
- var r = new RopeString.from(self)
- return r + s
+ redef fun +(o) do
+ var s = o.to_s
+ var slen = s.length
+ var mlen = length
+ if slen == 0 then return self
+ if mlen == 0 then return s
+ var nlen = slen + mlen
+ if s isa FlatString then
+ if nlen > maxlen then return new Concat(self, s)
+ var mits = items
+ var sifrom = s.index_from
+ var mifrom = index_from
+ var sits = s.items
+ var ns = new NativeString(nlen + 1)
+ mits.copy_to(ns, mlen, mifrom, 0)
+ sits.copy_to(ns, slen, sifrom, mlen)
+ return ns.to_s_with_length(nlen)
+ else if s isa Concat then
+ var sl = s.left
+ var sllen = sl.length
+ if sllen + mlen > maxlen then return new Concat(self, s)
+ return new Concat(self + sl, s.right)
+ else
+ abort
end
-
- var l = substring(0,pos)
- var r = substring_from(pos)
- var ret: String = new RopeString.from(l)
- ret += s
- return ret + r
end
+end
+# A simple linked list for use with iterators
+private class RopeIterPiece
+ # The encapsulated node of the `Rope`
+ var node: String
+ # Was its left child (if any) visited ?
+ var ldone: Bool
+ # Was its right child (if any) visited ?
+ var rdone: Bool
+ # The previous node in the list.
+ var prev: nullable RopeIterPiece
end
-private class RopeStringChars
- super SequenceRead[Char]
+# A reverse iterator capable of working with `Rope` objects
+private class RopeReviter
+ super IndexedIterator[Char]
- var tgt: Rope
+ # Current NativeString
+ var ns: String
+ # Current position in NativeString
+ var pns: Int
+ # Position in the Rope (0-indexed)
+ var pos: Int
+ # Iterator on the substrings, does the Postfix part of
+ # the Rope traversal.
+ var subs: IndexedIterator[String]
- redef fun [](pos)
- do
- assert pos < tgt.length
- if tgt.leaf_cache != null and pos >= tgt.leaf_cache.pos and (tgt.leaf_cache.pos + tgt.leaf_cache.leaf.length) > pos then return tgt.leaf_cache.leaf.str.chars[pos - tgt.leaf_cache.pos]
- var path = tgt.node_at(pos)
- return path.leaf.str.chars[path.offset]
+ init(root: RopeString) do
+ pos = root.length - 1
+ subs = new ReverseRopeSubstrings(root)
+ ns = subs.item
+ pns = ns.length - 1
end
- redef fun iterator do return iterator_from(0)
-
- redef fun iterator_from(pos) do return new RopeCharIterator(tgt, pos)
+ init from(root: RopeString, pos: Int) do
+ self.pos = pos
+ subs = new ReverseRopeSubstrings.from(root, pos)
+ ns = subs.item
+ pns = pos - subs.index
+ end
- redef fun reverse_iterator do return reverse_iterator_from(tgt.length-1)
+ redef fun index do return pos
- redef fun reverse_iterator_from(pos) do return new ReverseRopeCharIterator(tgt, pos)
-end
+ redef fun is_ok do return pos >= 0
-# Used to iterate on a Rope
-private class IteratorElement
+ redef fun item do return ns[pns]
- init(e: RopeNode)
- do
- if e isa Leaf then
- left = true
- right = true
- end
- node = e
+ redef fun next do
+ pns -= 1
+ pos -= 1
+ if pns >= 0 then return
+ if not subs.is_ok then return
+ subs.next
+ if not subs.is_ok then return
+ ns = subs.item
+ pns = ns.length - 1
end
-
- # The node being visited
- var node: RopeNode
- # If the node has a left child, was it visited ?
- var left = false
- # If the node has a right child, was it visited ?
- var right = false
- # Was the current node visited ?
- var done = false
end
-# Simple Postfix iterator on the nodes of a Rope
-private class Postfix
- super IndexedIterator[RopeNode]
-
- # Target Rope to iterate on
- var target: Rope
+# Forward iterator on the chars of a `Rope`
+private class RopeIter
+ super IndexedIterator[Char]
- # Current position in Rope
+ # Position in current `String`
+ var pns: Int
+ # Current `String` being iterated on
+ var str: String
+ # Substrings of the Rope
+ var subs: IndexedIterator[String]
+ # Maximum position to iterate on (e.g. Rope.length)
+ var max: Int
+ # Position (char) in the Rope (0-indexed)
var pos: Int
- # Visited nodes
- var stack = new List[IteratorElement]
+ init(root: RopeString) do
+ subs = new RopeSubstrings(root)
+ pns = 0
+ str = subs.item
+ max = root.length - 1
+ pos = 0
+ end
- init from(tgt: Rope, pos: Int)
- do
- self.target = tgt
+ init from(root: RopeString, pos: Int) do
+ subs = new RopeSubstrings.from(root, pos)
+ pns = pos - subs.index
self.pos = pos
- if pos < 0 or pos >= tgt.length then return
- var path = tgt.node_at(pos)
- self.pos -= path.offset
- for i in path.stack do
- var item = new IteratorElement(i.node)
- item.left = true
- if i.right then item.right = true
- stack.push item
- end
- var item = new IteratorElement(path.leaf)
- item.done = true
- stack.push item
+ str = subs.item
+ max = root.length - 1
end
- redef fun item
- do
- assert is_ok
- return stack.last.node
- end
+ redef fun item do return str[pns]
- redef fun is_ok do return not stack.is_empty
+ redef fun is_ok do return pos <= max
redef fun index do return pos
redef fun next do
- if stack.is_empty then return
- if pos > target.length-1 then
- stack.clear
- return
- end
- var lst = stack.last
- if lst.done then
- if lst.node isa Leaf then
- pos += lst.node.length
- end
- stack.pop
- next
- return
- end
- if not lst.left then
- lst.left = true
- var nod = lst.node
- if nod isa Concat and nod.left != null then
- stack.push(new IteratorElement(nod.left.as(not null)))
- next
- return
- end
- end
- if not lst.right then
- lst.right = true
- var nod = lst.node
- if nod isa Concat and nod.right != null then
- stack.push(new IteratorElement(nod.right.as(not null)))
- next
- return
- end
- end
- lst.done = true
+ pns += 1
+ pos += 1
+ if pns < subs.item.length then return
+ if not subs.is_ok then return
+ subs.next
+ if not subs.is_ok then return
+ str = subs.item
+ pns = 0
end
end
-# Iterates on the leaves (substrings) of the Rope
-class LeavesIterator
- super IndexedIterator[Leaf]
-
- private var nodes: Postfix
+# Substrings of a Rope (i.e. Reverse postfix iterator on leaves)
+private class ReverseRopeSubstrings
+ super IndexedIterator[String]
+
+ # Visit Stack
+ var iter: RopeIterPiece is noinit
+ # Position in `Rope`
+ var pos: Int is noinit
+
+ # Current leaf
+ var str: String is noinit
+
+ init(root: RopeString) do
+ var r = new RopeIterPiece(root, false, true, null)
+ pos = root.length - 1
+ var lnod: String = root
+ loop
+ if lnod isa Concat then
+ lnod = lnod.right
+ r = new RopeIterPiece(lnod, false, true, r)
+ else
+ str = lnod
+ iter = r
+ break
+ end
+ end
+ end
- init(tgt: Rope, pos: Int)
- do
- nodes = tgt.postfix(pos)
+ init from(root: RopeString, pos: Int) do
+ var r = new RopeIterPiece(root, false, true, null)
+ var rnod: String = root
+ var off = pos
+ loop
+ if rnod isa Concat then
+ if off >= rnod.left.length then
+ off -= rnod.left.length
+ rnod = rnod.right
+ r = new RopeIterPiece(rnod, false, true, r)
+ else
+ r.ldone = true
+ rnod = rnod.left
+ r = new RopeIterPiece(rnod, false, true, r)
+ end
+ else
+ str = rnod
+ r.ldone = true
+ iter = r
+ self.pos = pos - off
+ break
+ end
+ end
end
- redef fun is_ok do return nodes.is_ok
+ redef fun item do return str
- redef fun item
- do
- assert is_ok
- return nodes.item.as(Leaf)
- end
+ redef fun index do return pos
- redef fun index do return nodes.index
+ redef fun is_ok do return pos >= 0
- redef fun next
- do
- while nodes.is_ok do
- nodes.next
- if nodes.is_ok and nodes.item isa Leaf then break
+ redef fun next do
+ if pos < 0 then return
+ var curr: nullable RopeIterPiece = iter.prev
+ var currit = curr.node
+ while curr != null do
+ currit = curr.node
+ if not currit isa Concat then
+ str = currit
+ pos -= str.length
+ iter = curr
+ return
+ end
+ if not curr.rdone then
+ curr.rdone = true
+ curr = new RopeIterPiece(currit.right, false, false, curr)
+ continue
+ end
+ if not curr.ldone then
+ curr.ldone = true
+ curr = new RopeIterPiece(currit.left, false, false, curr)
+ continue
+ end
+ curr = curr.prev
end
+ pos = -1
end
end
-# Uses the leaves and calculates a new substring on each iteration
-class SubstringsIterator
- super IndexedIterator[Text]
-
- private var nodes: IndexedIterator[Leaf]
-
- # Current position in Rope
- var pos: Int
+private class RopeBufSubstringIterator
+ super Iterator[String]
- # Current substring, computed from the current Leaf and indexes
- var substring: Text
+ # Iterator on the substrings of the building string
+ var iter: Iterator[String]
+ # Makes a String out of the buffered part of the Ropebuffer
+ var nsstr: String
+ # Did we attain the buffered part ?
+ var nsstr_done = false
- init(tgt: Rope, pos: Int)
- do
- nodes = tgt.leaves(pos)
- self.pos = pos
- if pos < 0 or pos >= tgt.length then return
- make_substring
- end
-
- # Compute the bounds of the current substring and makes the substring
- private fun make_substring
- do
- substring = nodes.item.str
- var min = 0
- var length = substring.length
- if nodes.index < pos then
- min = pos - nodes.index
- end
- substring = substring.substring(min, length)
+ init(str: RopeBuffer) do
+ iter = str.str.substrings
+ nsstr = new FlatString.with_infos(str.ns, str.rpos - str.dumped, str.dumped, str.rpos - 1)
+ if str.length == 0 then nsstr_done = true
end
- redef fun is_ok do return nodes.is_ok
+ redef fun is_ok do return iter.is_ok or not nsstr_done
- redef fun item
- do
+ redef fun item do
assert is_ok
- return substring
+ if iter.is_ok then return iter.item
+ return nsstr
end
- redef fun index do return pos
-
- redef fun next
- do
- pos += substring.length
- nodes.next
- if nodes.is_ok then make_substring
+ redef fun next do
+ if iter.is_ok then
+ iter.next
+ return
+ end
+ nsstr_done = true
end
-
end
-class RopeCharIterator
- super IndexedIterator[Char]
-
- var substrings: IndexedIterator[Text]
-
- var pos: Int
-
- var max: Int
-
- var substr_iter: IndexedIterator[Char]
+# Substrings of a Rope (i.e. Postfix iterator on leaves)
+private class RopeSubstrings
+ super IndexedIterator[String]
+
+ # Visit Stack
+ var iter: RopeIterPiece is noinit
+ # Position in `Rope`
+ var pos: Int is noinit
+ # Maximum position in `Rope` (i.e. length - 1)
+ var max: Int is noinit
+
+ # Current leaf
+ var str: String is noinit
+
+ init(root: RopeString) do
+ var r = new RopeIterPiece(root, true, false, null)
+ pos = 0
+ max = root.length - 1
+ var rnod: String = root
+ loop
+ if rnod isa Concat then
+ rnod = rnod.left
+ r = new RopeIterPiece(rnod, true, false, r)
+ else
+ str = rnod
+ r.rdone = true
+ iter = r
+ break
+ end
+ end
+ end
- init(tgt: Rope, from: Int)
- do
- substrings = tgt.substrings_from(from)
- max = tgt.length - 1
- if not substrings.is_ok then
- pos = tgt.length
- return
+ init from(root: RopeString, pos: Int) do
+ var r = new RopeIterPiece(root, true, false, null)
+ max = root.length - 1
+ var rnod: String = root
+ var off = pos
+ loop
+ if rnod isa Concat then
+ if off >= rnod.left.length then
+ r.rdone = true
+ off -= rnod.left.length
+ rnod = rnod.right
+ r = new RopeIterPiece(rnod, true, false, r)
+ else
+ rnod = rnod.left
+ r = new RopeIterPiece(rnod, true, false, r)
+ end
+ else
+ str = rnod
+ r.rdone = true
+ iter = r
+ self.pos = pos - off
+ break
+ end
end
- pos = from
- substr_iter = substrings.item.chars.iterator
end
- redef fun item do return substr_iter.item
+ redef fun item do return str
redef fun is_ok do return pos <= max
redef fun index do return pos
- redef fun next
- do
- pos += 1
- if substr_iter.is_ok then
- substr_iter.next
- end
- if not substr_iter.is_ok then
- substrings.next
- if substrings.is_ok then
- substr_iter = substrings.item.chars.iterator
+ redef fun next do
+ pos += str.length
+ if pos > max then return
+ var it = iter.prev
+ var rnod: String = it.node
+ loop
+ if not rnod isa Concat then
+ it.ldone = true
+ it.rdone = true
+ str = rnod
+ iter = it.as(not null)
+ break
+ end
+ if not it.ldone then
+ rnod = rnod.left
+ it.ldone = true
+ it = new RopeIterPiece(rnod, false, false, it)
+ else if not it.rdone then
+ it.rdone = true
+ rnod = rnod.right
+ it = new RopeIterPiece(rnod, false, false, it)
+ else
+ it = it.prev
+ rnod = it.node
+ continue
end
end
end
end
-private class ReversePostfix
- super IndexedIterator[RopeNode]
+# Implementation of a `StringCharView` for `RopeString` objects
+private class RopeChars
+ super StringCharView
- var target: Rope
+ var tgt: RopeString
- var pos: Int
+ init(s: RopeString) do tgt = s
- var min = 0
+ redef fun [](i) do
+ return tgt[i]
+ end
- var stack = new List[IteratorElement]
+ redef fun iterator_from(i) do return new RopeIter.from(tgt, i)
- init from(tgt: Rope, pos: Int)
- do
- self.pos = pos
- target = tgt
- if pos < 0 or pos >= tgt.length then return
- var path = tgt.node_at(pos)
- self.pos -= path.offset
- for i in path.stack do
- var elemt = new IteratorElement(i.node)
- elemt.right = true
- if i.left then
- elemt.left = true
- end
- stack.push elemt
- end
- stack.push(new IteratorElement(path.leaf))
- stack.last.done = true
- end
+ redef fun reverse_iterator_from(i) do return new RopeReviter.from(tgt, i)
- redef fun item do
- assert is_ok
- return stack.last.node
- end
+end
- redef fun is_ok do return not stack.is_empty
+class RopeBufferIter
+ super IndexedIterator[Char]
- redef fun index do return pos
+ var sit: IndexedIterator[Char]
- redef fun next
- do
- if stack.is_empty then return
- if pos < min then
- stack.clear
- return
- end
- var lst = stack.last
- if lst.done then
- stack.pop
- next
- return
- end
- if not lst.right then
- var nod = lst.node.as(Concat)
- var rgt = nod.right
- lst.right = true
- if rgt != null then
- stack.push(new IteratorElement(rgt))
- next
- return
- end
- end
- if not lst.left then
- var nod = lst.node.as(Concat)
- var lft = nod.left
- lst.left = true
- if lft != null then
- stack.push(new IteratorElement(lft))
- next
- return
- end
- end
- if lst.node isa Leaf then pos -= lst.node.length
- lst.done = true
- end
-end
+ var ns: NativeString
+
+ var pns: Int
-private class ReverseLeavesIterator
- super IndexedIterator[Leaf]
+ var maxpos: Int
- var nodes: ReversePostfix
+ redef var index: Int
+
+ init(t: RopeBuffer) do
+ ns = t.ns
+ maxpos = t.rpos
+ sit = t.str.chars.iterator
+ pns = t.dumped
+ index = 0
+ end
- init(tgt: Rope, from: Int)
- do
- nodes = tgt.reverse_postfix(from)
+ init from(t: RopeBuffer, pos: Int) do
+ ns = t.ns
+ maxpos = t.length
+ sit = t.str.chars.iterator_from(pos)
+ pns = pos - t.str.length
+ index = pos
end
- redef fun is_ok do return nodes.is_ok
+ redef fun is_ok do return index < maxpos
redef fun item do
- assert is_ok
- return nodes.item.as(Leaf)
+ if sit.is_ok then return sit.item
+ return ns[pns]
end
redef fun next do
- while nodes.is_ok do
- nodes.next
- if nodes.is_ok then if nodes.item isa Leaf then break
+ index += 1
+ if sit.is_ok then
+ sit.next
+ else
+ pns += 1
end
end
-
- redef fun index do return nodes.index
-
end
-private class ReverseSubstringsIterator
- super IndexedIterator[Text]
+class RopeBufferReviter
+ super IndexedIterator[Char]
- var leaves: ReverseLeavesIterator
+ var sit: IndexedIterator[Char]
- var pos: Int
+ var ns: NativeString
+
+ var pns: Int
- var str: Text
+ redef var index: Int
- init(tgt: Rope, from: Int)
- do
- leaves = tgt.reverse_leaves(from)
- pos = from
- if not leaves.is_ok then return
- str = leaves.item.str
- make_substring
+ init(tgt: RopeBuffer) do
+ sit = tgt.str.chars.reverse_iterator
+ pns = tgt.rpos - 1
+ index = tgt.length - 1
+ ns = tgt.ns
end
- fun make_substring
- do
- if pos >= (leaves.index + str.length - 1) then return
- str = str.substring(0, (pos - leaves.index + 1))
+ init from(tgt: RopeBuffer, pos: Int) do
+ sit = tgt.str.chars.reverse_iterator_from(pos - tgt.rpos - tgt.dumped)
+ pns = pos - tgt.str.length
+ index = pos
+ ns = tgt.ns
end
- redef fun is_ok do return leaves.is_ok
+ redef fun is_ok do return index > 0
redef fun item do
- assert is_ok
- return str
+ if pns >= 0 then return ns[pns]
+ return sit.item
end
- redef fun index do return pos
-
redef fun next do
- pos -= str.length
- leaves.next
- if not leaves.is_ok then return
- str = leaves.item.str
- make_substring
+ index -= 1
+ if pns >= 0 then
+ pns -= 1
+ else
+ sit.next
+ end
end
end
-private class ReverseRopeCharIterator
- super IndexedIterator[Char]
+# View on the chars of a `RopeBuffer`
+class RopeBufferChars
+ super BufferCharView
- var substrs: IndexedIterator[Text]
+ redef type SELFTYPE: RopeBuffer
- var pos: Int
-
- var subiter: IndexedIterator[Char]
+ redef fun [](i) do
+ if i < target.str.length then
+ return target.str[i]
+ else
+ return target.ns[i - target.str.length]
+ end
+ end
- init(tgt: Rope, from: Int)
- do
- substrs = tgt.reverse_substrings_from(from)
- if not substrs.is_ok then
- pos = -1
- return
+ redef fun []=(i,c) do
+ if i == target.length then target.add c
+ if i < target.str.length then
+ var s = target.str
+ var l = s.substring(0, i)
+ var r = s.substring_from(i + 1)
+ target.str = l + c.to_s + r
+ else
+ target.ns[i - target.str.length] = c
end
- subiter = substrs.item.chars.reverse_iterator
- pos = from
end
- redef fun is_ok do return pos >= 0
+ redef fun add(c) do target.add c
- redef fun item do
- assert is_ok
- return subiter.item
- end
+ redef fun push(c) do target.add c
- redef fun index do return pos
+ redef fun iterator_from(i) do return new RopeBufferIter.from(target, i)
- redef fun next do
- pos -= 1
- if subiter.is_ok then subiter.next
- if not subiter.is_ok then
- if substrs.is_ok then substrs.next
- if substrs.is_ok then subiter = substrs.item.chars.reverse_iterator
- end
- end
+ redef fun reverse_iterator_from(i) do return new RopeBufferReviter.from(target, i)
end
-
import file
import exec
import stream
-import ropes
import collection
import math
+import ropes
import kernel
import gc
import bitset
redef fun write_to(stream) do stream.write(self)
end
-redef class RopeNode
- super Streamable
-end
-
-redef class Leaf
-
- redef fun write_to(s) do s.write(str)
-end
-
-redef class Concat
-
- redef fun write_to(s)
- do
- if left != null then left.write_to(s)
- if right != null then right.write_to(s)
- end
-end
-
-redef class RopeString
-
- redef fun write_to(s) do root.write_to(s)
-end
-
# Input streams with a buffer
abstract class BufferedIStream
super IStream
# assert "\n\"'\\\{\}".escape_to_nit == "\\n\\\"\\'\\\\\\\{\\\}"
fun escape_to_nit: String do return escape_more_to_c("\{\}")
+ # Escape to POSIX Shell (sh).
+ #
+ # Abort if the text contains a null byte.
+ #
+ # assert "\n\"'\\\{\}0".escape_to_sh == "'\n\"'\\''\\\{\}0'"
+ fun escape_to_sh: String do
+ var b = new FlatBuffer
+ b.chars.add '\''
+ for i in [0..length[ do
+ var c = chars[i]
+ if c == '\'' then
+ b.append("'\\''")
+ else
+ assert without_null_byte: c != '\0'
+ b.add(c)
+ end
+ end
+ b.chars.add '\''
+ return b.to_s
+ end
+
# Return a string where Nit escape sequences are transformed.
#
# var s = "\\n"
private var target: SELFTYPE
- private init(tgt: SELFTYPE)
- do
- target = tgt
- end
-
redef fun is_empty do return target.is_empty
redef fun length do return target.length
fun insert_at(s: String, pos: Int): SELFTYPE is abstract
+ redef fun substrings: Iterator[String] is abstract
+
# Returns a reversed version of self
#
# assert "hello".reversed == "olleh"
var tgt: nullable FlatText
- init(tgt: FlatText) do self.tgt = tgt
-
redef fun item do
assert is_ok
return tgt.as(not null)
do
assert length >= 0
var str = new FlatString.with_infos(self, length, 0, length - 1)
- str.real_items = self
return str
end
var new_self = calloc_string(length + 1)
copy_to(new_self, length, 0, 0)
var str = new FlatString.with_infos(new_self, length, 0, length - 1)
- str.real_items = self
+ new_self[length] = '\0'
+ str.real_items = new_self
return str
end
end
end
end
- # Compile a new motif
- init(motif: String)
+ init
do
- _motif = motif
_length = _motif.length
_gs = new Array[Int].with_capacity(_length)
- _bc_table = new ArrayMap[Char, Int]
compute_gs
compute_bc
end
private var motif: String
# length of the motif
- private var length: Int
+ private var length: Int is noinit
private fun bc(e: Char): Int
do
end
# good shifts
- private var gs: Array[Int]
+ private var gs: Array[Int] is noinit
# bad characters
- private var bc_table: Map[Char, Int]
+ private var bc_table = new ArrayMap[Char, Int]
private fun compute_bc
do
# The contents of the matching part
redef fun to_s do return string.substring(from,length)
- # Matches `len` characters of `s` from `f`.
- init(s: String, f: Int, len: Int)
+ init
do
- assert positive_length: len >= 0
- assert valid_from: f >= 0
- assert valid_after: f + len <= s.length
- string = s
- from = f
- length = len
+ assert positive_length: length >= 0
+ assert valid_from: from >= 0
+ assert valid_after: from + length <= string.length
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]
items.copy_to(new_str, bytelen, index_from, 0)
o.items.copy_to(new_str, o.bytelen, o.index_from, bytelen)
return new FlatString.full(new_str, 0, new_bytelen - 1, new_bytelen, newlen)
- else if o isa RopeString then
- return new RopeString.from(self) + o
+ else if o isa Concat then
+ return new Concat(self, o)
else
# If it goes to this point, that means another String implementation was concerned, therefore you need to support the + operation for this variant
abort
redef var bytelen: Int
redef init from(s) do
- if s isa RopeString then
+ if s isa Concat then
with_capacity(50)
for i in s.substrings do self.append(i)
end
end
redef fun append(s) do
- if s isa RopeString then
+ if s isa Concat then
for i in s.substrings do append i
end
var i = s.as(FlatString)
--- /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.
+
+# This script is a wrapper for `nitester` which also manages a local repo
+#
+# The first argument _must_ be the hash of the commit at the head of the
+# branch to test. The other arguments are passed on to `nitester`.
+
+hash=$1
+shift
+
+set +x
+
+local_repo=nit/
+remote_repo=privat
+
+tools_dir=misc/jenkins/
+
+cd $local_repo
+git clean -fdxq .
+
+git fetch $remote_repo
+git checkout $hash
+
+# Make nitg and tools
+$tools_dir/unitrun.sh "run-make-0initial_make" make
+
+# Make nitester
+$tools_dir/unitrun.sh "run-make-nitester" make -C contrib/nitester/
+
+# Run tests
+cd tests
+mkdir -p out
+rm ~/jenkins_xml/*.xml
+mpirun -np 30 ../contrib/nitester/bin/nitester $@
name=$1
shift
+# Detect a working time command
+if env time --quiet -f%U true 2>/dev/null; then
+ TIME="env time --quiet -f%U -o '${name}.t.out'"
+elif env time -f%U true 2>/dev/null; then
+ TIME="env time -f%U -o '${name}.t.out'"
+else
+ TIME=
+fi
+
# Magic here! This tee and save both stdout and stderr in distinct files without messing with them
# Time just get the user time
-/usr/bin/time -f%U --quiet -o "${name}.t.out" "$@" > >(tee "${name}.out") 2> >(tee "${name}.2.out" >&2)
+$TIME "$@" > >(tee "${name}.out") 2> >(tee "${name}.2.out" >&2)
res=$?
c=`echo "${name%-*}" | tr "-" "."`
--- /dev/null
+man1
+www
+pdf.out
all: $(OUT)
man1/%.1: %.md
+ mkdir -p man1
pandoc $< -t man -s -o $@
+
+# Rule to produce mdwn files for ikiwiki that will be used at http://nitlanguage.org/tools/
+web:
+ rm -r www 2>/dev/null || true
+ mkdir -p www
+ cp nit*.md www
+ rename '$$_ = "$${_}wn"' www/*.md
+ sed -i -e '1d;/SEE ALSO/,$$d' www/*.mdwn
+
+publish: web
+ rsync www/* asimov:wiki/nitlanguage/doc/tools/
+ ssh asimov make -C wiki/nitlanguage
+
+pdf:
+ mkdir -p pdf.out
+ for x in nit*.md; do echo $$x; pandoc -V header-includes='\usepackage{savetrees}' $$x -o pdf.out/$$x.pdf; done
+ pdfjoin pdf.out/*.pdf -o man.pdf
+
+clean:
+ rm -r www pdf.out || true
~~~
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
-Interprets and debugs Nit programs.
+nit - interprets and debugs Nit programs.
-# SYNOPSYS
+# SYNOPSIS
-nit [*options*]...
+nit [*options*] FILE [ARG]...
-# OPTIONS
+nit [*options*] -e COMMAND [ARG]...
+
+# DESCRIPTION
+
+`nit` is the current official interpreter.
+It takes the main module of a program as the first argument then the options and commands of the program.
+
+ $ nit examples/hello_world.nit
+ hello world
+
+The Nit interpreter is usable and valid as a *shebang* interpreted directive.
+It is however recommended to use with `/usr/bin/env` because the location of the executable is not standardized.
+
+ #!/usr/bin/env nit
+ print "hello world"
-`-W`, `--warn`
-: Show more warnings
+The interpreter includes an interactive debugger, it supports basic commands used for debugging a program much like GDB or such.
+See the `DEBUGGER` section for details.
-`-w`, `--warning`
-: Show/hide a specific warning
-`-q`, `--quiet`
-: Do not show warnings
+The behavior of the interpreter may differs slightly from the compiler.
-`--stop-on-first-error`
-: Stop on first error
+First, the interpreted is the reference implementation for the specification of the Nit language.
+That means if `nitg` and `nit` have a different behavior on a same program, it is likely that `nit` is right and `nitg` is wrong.
-`--no-color`
-: Do not use color to display errors and warnings
+Second, the FFI is not yet implemented in the interpreter.
+Only a subset of the standard methods are implemented with some hard-coded behaviors.
+While it is enough to use most of the standard library, a lot of additional libraries may not be usable by the interpreter.
-`--log`
-: Generate various log files
+Last, `nit` is the *Naive Interpretation Tool*, it means that it is slow and may take an average of 50.000% in overhead comparatively to `nitg`(it also means that `nitg` is fast).
+In practice, the slowness is not an issue for simple Nit scripts;
+it is not a big deal if `nit` takes millisecond to execute programs even if `nitg` only need microseconds.
-`--log-dir`
-: Directory where to generate log files
-`-h`, `-?`, `--help`
-: Show Help (This screen)
+# OPTIONS
+
+Most options are the same than `nitg(1)`.
+Here, only the specific one are indicated.
+
+Note that, unlike in other Nit tools, the options *MUST* be indicated before the main module of a program.
+Whatever follows it is used as arguments of the interpreted program.
-`--version`
-: Show version and exit
+ $ nit -e 'print args.first' -v
+ -v
-`--set-dummy-tool`
-: Set toolname and version to DUMMY. Useful for testing
+## COMMAND
-`-v`, `--verbose`
-: Verbose
+`-e`
+: Specifies the program from command-line.
-`--bash-completion`
-: Generate bash_completion file for this program
+ The `-e` option runs a program written on the command line.
+ Like with ruby, perl, bash and other script language.
-`--stub-man`
-: Generate a stub manpage in pandoc markdown format
+ $ nit -e 'print 5+5'
+ 10
-`--disable-phase`
-: DEBUG: Disable a specific phase; use `list` to get the list.
+`-n`
+: Repeatedly run the program for each line in file-name arguments.
-`-I`, `--path`
-: Set include path for loaders (may be used more than once)
+ If no arguments are given, then `nit` iterates over the lines of the standard input (stdin).
-`--only-parse`
-: Only proceed to parse step of loaders
+ $ echo "hello world" | nit -n -e 'print sys.line.capitalized'
+ Hello World
-`--only-metamodel`
-: Stop after meta-model processing
+ If some arguments are given, then `nit` considers that each argument is a filepath then it iterates on their lines.
-`--ignore-visibility`
-: Do not check, and produce errors, on visibility issues.
+## INTERPRETATION OPTIONS
`--discover-call-trace`
-: Trace calls of the first invocation of a method
+: Trace calls of the first invocation of methods.
+
+ Each time a method is invoked for the first time, its information is printed on the standard output for error (`stderr`).
+
+ This option helps the user to have a simplified but humanly readable overview of the behavior of a particular program execution.
+
+## DEBUGGER OPTIONS
`-d`
: Launches the target program with the debugger attached to it
`--port`
: Sets the debug port (Defaults to 22125) - Must be contained between 0 and 65535
+## OTHER OPTIONS
+
`-o`
-: compatibility (does noting)
+: Does nothing. Used for compatibility.
-`-m`
-: Additionals module to min-in
-`-e`
-: Specifies the program from command-line
+# DEBUGGER
+
+To use use the debugger, launch your program using the nit interpreter `nit` with `-d` option.
+
+It is also possible to execute the program normally until an error is encountered using the `-c` option.
+
+A remote debugger is also available, it can be used with the client-side executable `nitdbg_client`.
+
+On the client side, the debugger works like the previous one, input some commands when debugging a program, except you have to launch the server before trying to debug.
+
+## DEBUGGER FEATURES
+
+When using a debugger, a must-have is the possibility to control execution of your program by stepping over, in and out of a line/snippet of code. The nit debugger allows you to do that.
+
+You can add/remove breakpoints on instructions, so that the execution will stop when the execution reaches the specified line of the specified file.
+
+When an error is encountered, the debugger gives you the chance of inputting commands before exiting.
+
+The debugger also gives the possibility of printing the values of the requested variables.
+
+The modification of variables at runtime is possible too, but only if the variables are of primitive types (until it becomes possible).
+
+Also, you probably won't want to type a long variable name every time you wish to print its value, the debugger has the possibility of setting aliases to replace the awfully long and cryptic name of that variable you try to access by a beautiful alias.
+
+If you want to trace the modifications or uses of a variable of your choice, the trace command will be perfect for you as it will print or break when encountering the variable of your choice.
+
+## DEBUGGER COMMANDS
+
+`n`
+: Proceeds to the next instruction (step-over)
+
+`s`
+: Steps in an instruction
+
+`finish`
+: Steps out of an instruction
+
+`c`
+: Continues the execution until a breakpoint is encountered or until an error/end of program
+
+`b/break line_number`
+: Adds a breakpoint on line *line_number* for the current file
+
+`b/break file line_number`
+: Adds a breakpoint on line *line_number* for the file *file* (Don't forget to add the .nit extension to the command)
+
+`d/delete line_number`
+: Removes a breakpoint on line *line_number* for the current file
+
+`d/delete file line_number`
+: Removes a breakpoint on line *line_number* for the file *file*
+
+`kill`
+: Kills the current program (produces a stack trace)
+
+`variable = value`
+: Sets the value of *variable* to *value* (Only supports primitive types for now : Bool, Char, Int, Float)
+
+`p/print variable_name`
+: Prints the value of the variable *variable_name*
+
+`p/print stack`
+: Prints a stack trace starting with the current frame
+
+`p/print variable_name[index]`
+: Prints the value of the variable contained at the index *index* of variable *variable_name* (*variable_name* must be a subtype of SequenceRead)
+
+`p/print variable_name[index_from..index_to]`
+: Prints the values of all the variables contained from index *index_from* up to *index_to* in the variable *variable_name*
+
+All the print commands also work on any dimension SequenceRead collection.
+
+`variable_name as alias`
+: Sets an alias *alias* for the variable *variable_name*
+
+`trace variable_name [break/print]`
+: Traces the uses of the variable you chose to trace by printing the statement it appears in or by breaking on each use. (The [break/print] part is not mandatory, by default, the print option will be used)
+
+`untrace variable_name`
+: Removes the trace on the variable you chose to trace earlier in the program
-`-n`
-: Repeatedly run the program for each line in file-name arguments
# SEE ALSO
--- /dev/null
+% NITDBG_CLIENT(1)
+
+# NAME
+
+nitdbg_client - network client for remote debugging.
+
+# SYNOPSIS
+
+nitdbg_client [*options*]...
+
+# DESCRIPTION
+
+`nitdbg_client` connects to a `nit` debugger server and controls it.
+
+See the interpreter command `nit(1)` for details about remote debugging.
+
+# OPTIONS
+
+`--host`
+: Sets the host to debug from, use IPV4 only. (Defaults to 127.0.0.1).
+
+`--port`
+: Sets the debug port (Defaults to 22125).
+
+ Must be contained between 0 and 65535
+
+# SEE ALSO
+
+The Nit language documentation and the source code of its tools and libraries may be downloaded from <http://nitlanguage.org>
# NAME
-Generates HTML pages of API documentation from Nit source files.
+nitdoc - generates HTML pages of API documentation from Nit source files.
-# SYNOPSYS
+# SYNOPSIS
-nitdoc [*options*]...
+nitdoc [*options*]... FILE...
-# OPTIONS
+# DESCRIPTION
-`-W`, `--warn`
-: Show more warnings
+`nitdoc` takes one or more modules and generate HTML pages of API documentation for these modules and their imported modules.
-`-w`, `--warning`
-: Show/hide a specific warning
+The documentation is extracted from the comments found above the definition of modules, classes, and properties.
-`-q`, `--quiet`
-: Do not show warnings
+Internally, `nitdoc` relies on the presence of the `dot` command from the [graphviz] project.
+If the dot program is not present or not found, no image of hierarchies are generated.
+See option `--no-dot`.
-`--stop-on-first-error`
-: Stop on first error
+The documentation of the Nit [standard library] is generated with this tool.
-`--no-color`
-: Do not use color to display errors and warnings
+ [graphviz]: http://www.graphviz.org
+ [standard library]: http://nitlanguage.org/doc/stdlib
-`--log`
-: Generate various log files
+# DOCUMENTATION FORMAT
-`--log-dir`
-: Directory where to generate log files
+The format of the documentation is a dialect of [markdown] that allows GitHub fences (`~~~`).
-`-h`, `-?`, `--help`
-: Show Help (This screen)
+Code blocks are interpreted as snippets of Nit programs and intended to be used as examples of code.
+When these code snippets are valid, executable and contain at least and `assert` clause, they could be automatically executed and verified.
+See niunit(1) for details.
-`--version`
-: Show version and exit
+ [markdown]: http://daringfireball.net/projects/markdown
-`--set-dummy-tool`
-: Set toolname and version to DUMMY. Useful for testing
+# OPTIONS
-`-v`, `--verbose`
-: Verbose
+`-d`, `--dir`
+: output directory.
-`--bash-completion`
-: Generate bash_completion file for this program
+ Where the HTML files are generated.
-`--stub-man`
-: Generate a stub manpage in pandoc markdown format
+ By default, the directory is named `doc`.
-`--disable-phase`
-: DEBUG: Disable a specific phase; use `list` to get the list.
+`--source`
+: Format to link source code.
-`-I`, `--path`
-: Set include path for loaders (may be used more than once)
+ The format string is used to generated links to some parts of the source-code.
+ Use `%f` for filename, `%l` for first line, and `%L` for last line.
-`--only-parse`
-: Only proceed to parse step of loaders
+ For instance, the [standard library] use the following value to link to files in GitHub:
-`--only-metamodel`
-: Stop after meta-model processing
+ "https://github.com/privat/nit/blob/$(git rev-parse HEAD)/%f#L%l-%L"
-`--ignore-visibility`
-: Do not check, and produce errors, on visibility issues.
+ Here, the `git rev-parse HEAD` is used to link to the current snapshot revision of the file.
-`-d`, `--dir`
-: output directory
+`--no-dot`
+: do not generate graphs with graphviz.
-`--source`
-: link for source (%f for filename, %l for first line, %L for last line)
+`--private`
+: also generate private API.
+
+## CUSTOMIZATION
`--sharedir`
-: directory containing nitdoc assets
+: directory containing nitdoc assets.
-`--shareurl`
-: use shareurl instead of copy shared files
+ By default `$NIT_DIR/share/nitdoc/` is used.
-`--no-dot`
-: do not generate graphes with graphviz
+`--shareurl`
+: use shareurl instead of copy shared files.
-`--private`
-: also generate private API
+ By default, assets from the sharedir a copied into the output directory and refered with a relative path in the generated files.
+ Whith this option, the assets are not copied and the given URL of path is used in the generated files to locate assets.
`--custom-title`
-: custom title for homepage
+: custom title for homepage.
`--custom-footer-text`
-: custom footer text
+: custom footer text.
`--custom-overview-text`
: custom intro text for homepage
`--custom-brand`
: custom link to external site
+## SERVICES
+
`--github-upstream`
: Git branch where edited commits will be pulled into (ex: user:repo:branch)
: Git working directory used to resolve path name (ex: /home/me/myproject/)
`--piwik-tracker`
-: Piwik tracker URL (ex: nitlanguage.org/piwik/)
+: Piwik tracker URL (ex: `"nitlanguage.org/piwik/"`)
`--piwik-site-id`
: Piwik site ID
# NAME
-Compiles Nit programs.
+nitg - compiles Nit programs.
-# SYNOPSYS
-nitg [*options*]...
+# SYNOPSIS
+
+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.
+
+ $ nitg prog1.nit prog2.nit
+
+To combine files into a single program, use the `-m` option.
+
+ $ nitg prog1.nit -m other_module.nit
+
+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 classes.
+ With four `-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 additional 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 usable 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
+`--nit-dir`
+: Base directory of the Nit installation.
-`--make-flags`
-: Additional options to make
+ Has precedence over the environment variable `NIT_DIR`.
+
+## 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)
+: 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`
+: Base directory of the Nit installation.
+
+ 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.
+
+ The `--nit-dir` option also set the base directory of the Nit installation but has precedence.
+
+`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
# NAME
-Generates HTML of highlited code from Nit source files.
+nitlight - generates HTML of highlighted code from Nit source files.
-# SYNOPSYS
+# SYNOPSIS
-nitlight [*options*]...
+nitlight [*options*] FILE...
-# OPTIONS
-
-`-W`, `--warn`
-: Show more warnings
-
-`-w`, `--warning`
-: Show/hide a specific warning
-
-`-q`, `--quiet`
-: Do not show warnings
-
-`--stop-on-first-error`
-: Stop on first error
-
-`--no-color`
-: Do not use color to display errors and warnings
+# DESCRIPTION
-`--log`
-: Generate various log files
+Unlike generic lexical or syntactic highlighter, nitlight use semantic information on programs to improve the rendered result.
-`--log-dir`
-: Directory where to generate log files
-
-`-h`, `-?`, `--help`
-: Show Help (This screen)
-
-`--version`
-: Show version and exit
-
-`--set-dummy-tool`
-: Set toolname and version to DUMMY. Useful for testing
+# OPTIONS
-`-v`, `--verbose`
-: Verbose
+Common options of the Nit tools are understood.
+Here, only the specific one are indicated.
-`--bash-completion`
-: Generate bash_completion file for this program
+`-f`, `--fragment`
+: Omit document header and footer.
-`--stub-man`
-: Generate a stub manpage in pandoc markdown format
+ By default, a complete autonomous HTML document is generated.
+ If `-f` is given, only the inside of the body part is generated such that it could be integrated
+ into a HTML document.
-`--disable-phase`
-: DEBUG: Disable a specific phase; use `list` to get the list.
+`--first-line`
+: Start the source file at this line (default: 1).
-`-I`, `--path`
-: Set include path for loaders (may be used more than once)
+ The generated HTML will only contains lines bellow the specified one.
-`--only-parse`
-: Only proceed to parse step of loaders
+`--last-line`
+: End the source file at this line (default: to the end)
-`--only-metamodel`
-: Stop after meta-model processing
+ The generated HTML will only contains lines ebove the specified one.
-`--ignore-visibility`
-: Do not check, and produce errors, on visibility issues.
+`-d`, `--dir`
+: Output html files in a specific directory (required if more than one module).
-`-f`, `--fragment`
-: Omit document header and footer
+ By default the generated HTML is outputted on the screen.
+ If this option is used, then HTML files are generated in the specified directory.
-`--first-line`
-: Start the source file at this line (default: 1)
+ A basic `index.heml` and a `style.css` file are also generated in the directory.
-`--last-line`
-: End the source file at this line (default: to the end)
+`--full`
+: Process also imported modules.
-`-d`, `--dir`
-: Output html files in a specific directory (required if more than one module)
+ By default, only the modules indicated on the command line are highlighted.
-`--full`
-: Process also imported modules
+ With the `--full` option, all imported modules (even those in standard) are also precessed.
# SEE ALSO
# NAME
-Lists the projects and/or paths of Nit sources files.
+nitls - lists the projects, groups and paths of Nit sources files.
-# SYNOPSYS
+# SYNOPSIS
-nitls [*options*]...
+nitls [*options*] FILE...
-# OPTIONS
+# DESCRIPTION
-`-W`, `--warn`
-: Show more warnings
+`nitls` is used to list Nit files in directories and extract the module-group-project relation.
-`-w`, `--warning`
-: Show/hide a specific warning
+It is basically a `ls` or a simple `find` specialized on `.nit` source files.
-`-q`, `--quiet`
-: Do not show warnings
+# EXAMPLES
-`--stop-on-first-error`
-: Stop on first error
+Show the tree of modules from the current directory and subdirectories.
-`--no-color`
-: Do not use color to display errors and warnings
+ $ nitls -t -r .
-`--log`
-: Generate various log files
+Show the list of projects imported by the modules of the current directory.
-`--log-dir`
-: Directory where to generate log files
+ $ nitls -d -P *.nit
-`-h`, `-?`, `--help`
-: Show Help (This screen)
+# OPTIONS
-`--version`
-: Show version and exit
+## COLLECT
-`--set-dummy-tool`
-: Set toolname and version to DUMMY. Useful for testing
+`-r`, `--recursive`
+: Process directories recursively.
-`-v`, `--verbose`
-: Verbose
+ All `.nit` files found in the specified directory and subdirectories are considered.
-`--bash-completion`
-: Generate bash_completion file for this program
+`-d`, `--depends`
+: List dependencies of given modules
-`--stub-man`
-: Generate a stub manpage in pandoc markdown format
+ All imported modules are also considered.
-`--disable-phase`
-: DEBUG: Disable a specific phase; use `list` to get the list.
+`-k`, `--keep`
+: Ignore errors and files that are not a Nit source file.
-`-I`, `--path`
-: Set include path for loaders (may be used more than once)
+ When a file that is not a valit Nit module is encoutered, it is ignored and the rest of the file are
+ processed.
-`--only-parse`
-: Only proceed to parse step of loaders
+ Without this option, a error message is displayed and nitls terminates on such a case.
-`--only-metamodel`
-: Stop after meta-model processing
+## PRESENTATION MODE
-`--ignore-visibility`
-: Do not check, and produce errors, on visibility issues.
+Three presentation modes are available.
-`-k`, `--keep`
-: Ignore errors and files that are not a Nit source file
+`-P`, `--project`
+: List projects in a flat list (default).
-`-r`, `--recursive`
-: Process directories recussively
+ Only project are displayed (and not the individual files).
`-t`, `--tree`
-: List source files in their groups and projects
+: List source files in their groups and projects.
+
+ Each `.nit` file is presented in a tree of projects and groups.
`-s`, `--source`
-: List source files
+: List source files in a flat list.
-`-P`, `--project`
-: List projects paths (default)
+ Each `.nit` file is presented indivitually.
-`-d`, `--depends`
-: List dependencies of given modules
+## PRESENTATION OPTIONS
`-p`, `--path`
-: List only path (instead of name + path)
+: List only path (instead of name + path).
`-M`
-: List dependencies suitable for a rule in a Makefile. Alias for -d, -p and -s
+: List dependencies suitable for a rule in a Makefile.
+
+ Alias for `-d`, `-p` and `-s`.
# SEE ALSO
# NAME
-Computes various metrics on Nit programs.
+nitmetrics -- computes various metrics on Nit programs.
-# SYNOPSYS
+# SYNOPSIS
-nitmetrics [*options*]...
+nitmetrics [*options*]... FILE...
# OPTIONS
-`-W`, `--warn`
-: Show more warnings
-
-`-w`, `--warning`
-: Show/hide a specific warning
-
-`-q`, `--quiet`
-: Do not show warnings
-
-`--stop-on-first-error`
-: Stop on first error
-
-`--no-color`
-: Do not use color to display errors and warnings
-
-`--log`
-: Generate various log files
-
-`--log-dir`
-: Directory where to generate log files
-
-`-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
-
-`--disable-phase`
-: DEBUG: Disable a specific phase; use `list` to get the list.
-
-`-I`, `--path`
-: Set include path for loaders (may be used more than once)
-
-`--only-parse`
-: Only proceed to parse step of loaders
-
-`--only-metamodel`
-: Stop after meta-model processing
-
-`--ignore-visibility`
-: Do not check, and produce errors, on visibility issues.
+## METRICS
`--all`
: Compute all metrics
`--rta`
: Compute RTA metrics
-`--csv`
-: Export metrics in CSV format
-
`--generate_hyperdoc`
: Generate Hyperdoc
`--poset`
: Complete metrics on posets
+## OUTPUT
+
+`--csv`
+: Also export metrics in CSV format.
+
`-d`, `--dir`
-: Directory where some statistics files are generated
+: Directory where some statistics files are generated.
`--no-colors`
-: Disable colors in console outputs
+: Disable colors in console outputs.
# SEE ALSO
# NAME
-Collect potential style and code issues.
+nitpick - collect potential style and code issues.
-# SYNOPSYS
+# SYNOPSIS
-nitpick [*options*]...
+nitpick [*options*] FILE...
-# OPTIONS
-
-`-W`, `--warn`
-: Show more warnings
-
-`-w`, `--warning`
-: Show/hide a specific warning
-
-`-q`, `--quiet`
-: Do not show warnings
-
-`--stop-on-first-error`
-: Stop on first error
-
-`--no-color`
-: Do not use color to display errors and warnings
-
-`--log`
-: Generate various log files
-
-`--log-dir`
-: Directory where to generate log files
+# DESCRIPTION
-`-h`, `-?`, `--help`
-: Show Help (This screen)
+`nitpick` is a fast code checker.
-`--version`
-: Show version and exit
+It is currently used with the vim syntactic plugin.
-`--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
-
-`--disable-phase`
-: DEBUG: Disable a specific phase; use `list` to get the list.
-
-`-I`, `--path`
-: Set include path for loaders (may be used more than once)
-
-`--only-parse`
-: Only proceed to parse step of loaders
-
-`--only-metamodel`
-: Stop after meta-model processing
+# OPTIONS
-`--ignore-visibility`
-: Do not check, and produce errors, on visibility issues.
+Only common options of the Nit tools are understood.
# SEE ALSO
# NAME
-Pretty print Nit code from Nit source files.
+nitpretty - pretty print Nit code from Nit source files.
-# SYNOPSYS
+# SYNOPSIS
-nitpretty [*options*]...
+nitpretty [*options*]... FILE
# OPTIONS
-`-W`, `--warn`
-: Show more warnings
-
-`-w`, `--warning`
-: Show/hide a specific warning
-
-`-q`, `--quiet`
-: Do not show warnings
-
-`--stop-on-first-error`
-: Stop on first error
-
-`--no-color`
-: Do not use color to display errors and warnings
-
-`--log`
-: Generate various log files
-
-`--log-dir`
-: Directory where to generate log files
-
-`-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
-
-`--disable-phase`
-: DEBUG: Disable a specific phase; use `list` to get the list.
-
-`-I`, `--path`
-: Set include path for loaders (may be used more than once)
-
-`--only-parse`
-: Only proceed to parse step of loaders
-
-`--only-metamodel`
-: Stop after meta-model processing
-
-`--ignore-visibility`
-: Do not check, and produce errors, on visibility issues.
-
`--dir`
: Working directory (default is '.nitpretty')
# NAME
-Generates a serialization support module
+nitserial - generates a serialization support module
-# SYNOPSYS
+# SYNOPSIS
-nitserial [*options*]...
+nitserial [*options*]... FILE
# OPTIONS
`--dir`
: Output directory
-`-W`, `--warn`
-: Show more warnings
-
-`-w`, `--warning`
-: Show/hide a specific warning
-
-`-q`, `--quiet`
-: Do not show warnings
-
-`--stop-on-first-error`
-: Stop on first error
-
-`--no-color`
-: Do not use color to display errors and warnings
-
-`--log`
-: Generate various log files
-
-`--log-dir`
-: Directory where to generate log files
-
-`-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
-
-`--disable-phase`
-: DEBUG: Disable a specific phase; use `list` to get the list.
-
-`-I`, `--path`
-: Set include path for loaders (may be used more than once)
-
-`--only-parse`
-: Only proceed to parse step of loaders
-
-`--only-metamodel`
-: Stop after meta-model processing
-
-`--ignore-visibility`
-: Do not check, and produce errors, on visibility issues.
-
# SEE ALSO
The Nit language documentation and the source code of its tools and libraries may be downloaded from <http://nitlanguage.org>
# NAME
-Executes the unit tests from Nit source files.
+nitunit - executes the unit tests from Nit source files.
-# SYNOPSYS
+# SYNOPSIS
-nitunit [*options*]...
+nitunit [*options*] FILE...
-# OPTIONS
+# DESCRIPTION
+
+Unit testing in Nit can be achieved in two ways:
+
+* using `DocUnits` in code comments
+* using `TestSuites` with test unit files
+
+`DocUnits` are executable pieces of code found in the documentation of modules,
+classes and properties.
+They are used for documentation purpose, they should be kept simple and illustrative.
+More advanced unit testing can be done using TestSuites.
+
+`TestSuites` are test files coupled to a tested module.
+They contain a list of test methods called TestCase.
+
+## Working with `DocUnits`
+
+With DocUnits, executable code can be placed in comments of modules, classes and properties.
+The execution can be verified using `assert`
+
+Example with a class:
+
+ module foo
+ # var foo = new Foo
+ # assert foo.bar == 10
+ class Foo
+ var bar = 10
+ end
-`-W`, `--warn`
-: Show more warnings
+Everything used in the test must be declared.
+To test a method you have to instantiate its class:
-`-w`, `--warning`
-: Show/hide a specific warning
+ module foo
+ # var foo = new Foo
+ # assert foo.bar == 10
+ class Foo
+ # var foo = new Foo
+ # assert foo.baz(1, 2) == 3
+ fun baz(a, b: Int) do return a + b
+ end
-`-q`, `--quiet`
-: Do not show warnings
+The `nitunit` command is used to test Nit files:
-`--stop-on-first-error`
-: Stop on first error
+ $ nitunit foo.nit
-`--no-color`
-: Do not use color to display errors and warnings
+## Working with `TestSuites`
-`--log`
-: Generate various log files
+TestSuites are Nit files that define a set of TestCases for a particular module.
-`--log-dir`
-: Directory where to generate log files
+The test suite must be called `test_` followed by the name of the module to test.
+So for the module `foo.nit` the test suite will be called `test_foo.nit`.
-`-h`, `-?`, `--help`
-: Show Help (This screen)
+The structure of a test suite is the following:
-`--version`
-: Show version and exit
+ # test suite for module `foo`
+ module test_foo
+ import foo # can be intrude to test private things
+ class TestFoo
+ # test case for `foo::Foo::baz`
+ fun test_baz do
+ var subject = new Foo
+ assert subject.baz(1, 2) == 3
+ end
+ end
-`--set-dummy-tool`
-: Set toolname and version to DUMMY. Useful for testing
+Test suite can be executed using the same `nitunit` command:
-`-v`, `--verbose`
-: Verbose
+ $ nitunit foo.nit
-`--bash-completion`
-: Generate bash_completion file for this program
+`nitunit` will execute a test for each method named `test_*` in a class named `Test*`
+so multiple tests can be executed for a single method:
-`--stub-man`
-: Generate a stub manpage in pandoc markdown format
+ class TestFoo
+ fun test_baz_1 do
+ var subject = new Foo
+ assert subject.baz(1, 2) == 3
+ end
+ fun test_baz_2 do
+ var subject = new Foo
+ assert subject.baz(1, -2) == -1
+ end
+ end
-`--disable-phase`
-: DEBUG: Disable a specific phase; use `list` to get the list.
+`TestSuites` also provide methods to configure the test run:
-`-I`, `--path`
-: Set include path for loaders (may be used more than once)
+`before_test` and `after_test`: methods called before/after each test case.
+They can be used to factorize repetitive tasks:
-`--only-parse`
-: Only proceed to parse step of loaders
+ class TestFoo
+ var subject: Foo
+ # Mandatory empty init
+ init do end
+ # Method executed before each test
+ fun before_test do
+ subject = new Foo
+ end
+ fun test_baz_1 do
+ assert subject.baz(1, 2) == 3
+ end
+ fun test_baz_2 do
+ assert subject.baz(1, -2) == -1
+ end
+ end
+
+When using custom test attributes, an empty `init` must be declared to allow automatic test running.
+
+`before_module` and `after_module`: methods called before/after each test suite.
+They have to be declared at top level:
+
+ module test_bdd_connector
+ import bdd_connector
+ # Testing the bdd_connector
+ class TestConnector
+ # test cases using a server
+ end
+ # Method executed before testing the module
+ fun before_module do
+ # start server before all test cases
+ end
+ # Method executed after testing the module
+ fun after_module do
+ # stop server after all test cases
+ end
+
+## Generating test suites
+
+ Write test suites for big modules can be a repetitive and boring task...
+ To make it easier, `nitunit` can generate test skeletons for Nit modules:
+
+ $ nitunit --gen-suite foo.nit
+
+ This will generate the test suite `test_foo` containing test case stubs for all public
+ methods found in `foo.nit`.
-`--only-metamodel`
-: Stop after meta-model processing
-`--ignore-visibility`
-: Do not check, and produce errors, on visibility issues.
+# OPTIONS
`--full`
-: Process also imported modules
+: Process also imported modules.
+
+ By default, only the modules indicated on the command line are tested.
+
+ With the `--full` option, all imported modules (even those in standard) are also precessed.
`-o`, `--output`
: Output name (default is 'nitunit.xml')
+ `nitunit` produces a XML file comatible with JUnit.
+
`--dir`
: Working directory (default is '.nitunit')
+ In order to execute the tests, nit files are generated then compiled and executed in the giver working directory.
+
`--no-act`
-: Does not compile and run tests
+: Does not compile and run tests.
`-p`, `--pattern`
-: Only run test case with name that match pattern. Examples: 'TestFoo', 'TestFoo*', 'TestFoo::test_foo', 'TestFoo::test_foo*', 'test_foo', 'test_foo*'
+: Only run test case with name that match pattern. Examples: `TestFoo`, `TestFoo*`, `TestFoo::test_foo`, `TestFoo::test_foo*`, `test_foo`, `test_foo*`
`-t`, `--target-file`
: Specify test suite location.
+## SUITE GENERATION
+
`--gen-suite`
: Generate test suite skeleton for a module
`-f`, `--force`
-: Force test generation even if file exists
+: Force test generation even if file exists.
+
+ Any existing test suite will be overwritten.
`--private`
-: Also generate test case for private methods
+: Also generate test case for private methods.
`--only-show`
-: Only display skeleton, do not write file
+: Only display the skeleton, do not write any file.
# SEE ALSO
# NAME
-Displays specific pieces of API information from Nit source files.
+nitx - displays specific pieces of API information from Nit source files.
-# SYNOPSYS
+# SYNOPSIS
-nitx [*options*]...
+nitx [*options*] FILE [COMMAND]
-# OPTIONS
-
-`-W`, `--warn`
-: Show more warnings
-
-`-w`, `--warning`
-: Show/hide a specific warning
-
-`-q`, `--quiet`
-: Do not show warnings
+# DESCRIPTION
-`--stop-on-first-error`
-: Stop on first error
+`nitx` in an interactive tool that display information about programs and libraries.
-`--no-color`
-: Do not use color to display errors and warnings
+A command that query some information can be given as and argument.
+This will immediately displays the information then terminates the programs.
-`--log`
-: Generate various log files
+If no command are given, the program starts an interactive session where commands are entered until `:q` is given.
-`--log-dir`
-: Directory where to generate log files
+# COMMANDS
-`-h`, `-?`, `--help`
-: Show Help (This screen)
+`name`
+: lookup module, class and property with the corresponding 'name'.
-`--version`
-: Show version and exit
+`param: Type`
+: lookup methods using the corresponding 'Type' as parameter.
-`--set-dummy-tool`
-: Set toolname and version to DUMMY. Useful for testing
+`return: Type`
+: lookup methods returning the corresponding 'Type'.
-`-v`, `--verbose`
-: Verbose
+`new: Type`
+: lookup methods creating new instances of 'Type'.
-`--bash-completion`
-: Generate bash_completion file for this program
+`:h`
+: display an help message about the commands.
-`--stub-man`
-: Generate a stub manpage in pandoc markdown format
+`:q`
+: exit the tool.
-`--disable-phase`
-: DEBUG: Disable a specific phase; use `list` to get the list.
-
-`-I`, `--path`
-: Set include path for loaders (may be used more than once)
-
-`--only-parse`
-: Only proceed to parse step of loaders
-
-`--only-metamodel`
-: Stop after meta-model processing
+# OPTIONS
-`--ignore-visibility`
-: Do not check, and produce errors, on visibility issues.
+Only common options of the Nit tools are understood.
# SEE ALSO
fun add_local_function( efc : CFunction )
do
- body_decl.add( "{efc.signature};\n" )
- body_impl.add( "\n" )
- body_impl.add( efc.to_writer )
+ body_decl.add "static {efc.signature};\n"
+ body_impl.add "\n"
+ body_impl.add efc.to_writer
end
fun add_exported_function( efc : CFunction )
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
- init (filename, cflags: String)
- do
- super filename
-
- self.cflags = cflags
- end
-
- # 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
do
var platform = compiler.mainmodule.target_platform
if self.toolcontext.opt_stacktrace.value == "nitstack" and (platform == null or platform.supports_libunwind) then compiler.build_c_to_nit_bindings
- var cc_opt_with_libgc = "-DWITH_LIBGC `pkg-config --cflags bdw-gc`"
+ var cc_opt_with_libgc = "-DWITH_LIBGC"
if platform != null and not platform.supports_libgc then cc_opt_with_libgc = ""
# Add gc_choser.h to aditionnal bodies
var gc_chooser = new ExternCFile("gc_chooser.c", cc_opt_with_libgc)
+ 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"
self.toolcontext.info("Total C source files to compile: {cfiles.length}", 2)
end
- fun makefile_name(mainmodule: MModule): String do return "{mainmodule.name}.mk"
+ fun makefile_name(mainmodule: MModule): String do return "{mainmodule.c_name}.mk"
fun default_outname(mainmodule: MModule): String
do
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 `pkg-config --libs bdw-gc` {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
var mainmodule: MModule is writable
# The real main module of the program
- var realmainmodule: MModule
+ var realmainmodule: MModule is noinit
# The modelbuilder used to know the model and the AST
var modelbuilder: ModelBuilder is protected writable
# Is hardening asked? (see --hardening)
fun hardening: Bool do return self.modelbuilder.toolcontext.opt_hardening.value
- init(mainmodule: MModule, modelbuilder: ModelBuilder)
+ init
do
- self.mainmodule = mainmodule
self.realmainmodule = mainmodule
- self.modelbuilder = modelbuilder
end
# Force the creation of a new file
do
if modelbuilder.toolcontext.opt_group_c_files.value then
if self.files.is_empty then
- var f = new CodeFile(mainmodule.name)
+ var f = new CodeFile(mainmodule.c_name)
self.files.add(f)
end
return self.files.first
fun new_visitor: VISITOR is abstract
# Where global declaration are stored (the main .h)
- var header: CodeWriter is writable
+ var header: CodeWriter is writable, noinit
# Provide a declaration that can be requested (before or latter) by a visitor
fun provide_declaration(key: String, s: String)
# (used for local or global declaration)
fun add_decl(s: String) do self.decl_lines.add(s)
- init(file: CodeFile)
+ init
do
- self.file = file
file.writers.add(self)
end
end
var current_node: nullable ANode = null is writable
# The current `Frame`
- var frame: nullable Frame is writable
+ var frame: nullable Frame = null is writable
# Alias for self.compiler.mainmodule.object_type
fun object_type: MClassType do return self.compiler.mainmodule.object_type
# Alias for self.compiler.mainmodule.bool_type
fun bool_type: MClassType do return self.compiler.mainmodule.bool_type
- var writer: CodeWriter
+ var writer: CodeWriter is noinit
- init(compiler: COMPILER)
+ init
do
- self.compiler = compiler
self.writer = new CodeWriter(compiler.files.last)
end
# false (usual value) means that the variable is a mcasttype or a subtype.
var is_exact: Bool = false is writable
- init(name: String, mtype: MType, mcasttype: MType)
+ init
do
- self.name = name
- self.mtype = mtype
- self.mcasttype = mcasttype
assert not mtype.need_anchor
assert not mcasttype.need_anchor
end
do
var res = self.c_name_cache
if res != null then return res
- res = "{mclass.intro_mmodule.name.to_cmangle}__{mclass.name.to_cmangle}"
+ res = "{mclass.intro_mmodule.c_name}__{mclass.name.to_cmangle}"
self.c_name_cache = res
return res
end
fun c_name: String do
var res = self.c_name_cache
if res != null then return res
- res = "{intro_mmodule.name.to_cmangle}__{name.to_cmangle}"
+ res = "{intro_mmodule.c_name}__{name.to_cmangle}"
self.c_name_cache = res
return res
end
do
var res = self.c_name_cache
if res != null then return res
- res = "{self.mclassdef.mmodule.name.to_cmangle}__{self.mclassdef.mclass.name.to_cmangle}__{self.mproperty.name.to_cmangle}"
+ res = "{self.mclassdef.mmodule.c_name}__{self.mclassdef.mclass.name.to_cmangle}__{self.mproperty.name.to_cmangle}"
self.c_name_cache = res
return res
end
end
redef class MModule
+ # Return the name of the global C identifier associated to `self`.
+ # This name is used to prefix files and other C identifiers associated with `self`.
+ var c_name: String is lazy do
+ var g = mgroup
+ var res
+ if g != null and g.mproject.name != name then
+ res = g.mproject.name.to_cmangle + "__" + name.to_cmangle
+ else
+ res = name.to_cmangle
+ end
+ return res
+ end
+
# All `MProperty` associated to all `MClassDef` of `mclass`
fun properties(mclass: MClass): Set[MProperty] do
if not self.properties_cache.has_key(mclass) then
# 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
var poset: POSet[E]
- init(poset: POSet[E]) do
- self.poset = poset
+ init do
extract_core
extract_border
extract_crown
private var poset: POSet[H]
private var conflicts: Map[H, Set[H]]
- init(poset: POSet[H], conflicts: Map[H, Set[H]]) do
- self.poset = poset
- self.conflicts = conflicts
- end
-
# Colorize buckets using the POSet and conflict graph
fun colorize(buckets: Map[H, Set[E]]): Map[E, Int] do
colors.clear
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
mtype.compile_extern_type(v, ccu)
# has callbacks already been compiled? (this may very well happen with global compilation)
- if mmodule.check_callback_compilation(mtype) then mtype.compile_extern_helper_functions(v, ccu)
+ mtype.compile_extern_helper_functions(v, ccu, mmodule.check_callback_compilation(mtype))
end
end
# compile callbacks
- for cb in foreign_callbacks.callbacks do if mainmodule.check_callback_compilation(cb) then
- cb.compile_extern_callback(v, ccu)
+ for cb in foreign_callbacks.callbacks do
+ cb.compile_extern_callback(v, ccu, mainmodule.check_callback_compilation(cb))
end
- for cb in foreign_callbacks.supers do if mainmodule.check_callback_compilation(cb) then
- cb.compile_extern_callback(v, ccu)
+ for cb in foreign_callbacks.supers do
+ cb.compile_extern_callback(v, ccu, mainmodule.check_callback_compilation(cb))
end
- for cb in foreign_callbacks.casts do if mainmodule.check_callback_compilation(cb) then
- cb.compile_extern_callbacks(v, ccu)
+ for cb in foreign_callbacks.casts do
+ cb.compile_extern_callbacks(v, ccu, mainmodule.check_callback_compilation(cb))
end
# manage nitni callback set
ccu.header_c_types.add("#endif\n")
end
- private fun compile_extern_helper_functions(v: AbstractCompilerVisitor, ccu: CCompilationUnit)
+ private fun compile_extern_helper_functions(v: AbstractCompilerVisitor, ccu: CCompilationUnit, compile_implementation_too: Bool)
do
# actually, we do not need to do anything when using the bohem garbage collector
var call_context = from_c_call_context
end
redef class MNullableType
- redef fun compile_extern_helper_functions(v, ccu)
+ redef fun compile_extern_helper_functions(v, ccu, compile_implementation_too)
do
super
# In nitni files, #define friendly as extern
ccu.header_decl.add("#define {base_cname} {full_cname}\n")
+ if not compile_implementation_too then return
+
# FIXME: This is ugly an broke the separate compilation principle
# The real function MUST be compiled only once, #define pragma only protect the compiler, not the loader
# However, I am not sure of the right approach here (eg. week refs are ugly)
end
redef class MExplicitCall
- private fun compile_extern_callback(v: AbstractCompilerVisitor, ccu: CCompilationUnit)
+ private fun compile_extern_callback(v: AbstractCompilerVisitor, ccu: CCompilationUnit, compile_implementation_too: Bool)
do
var mproperty = mproperty
assert mproperty isa MMethod
var full_friendly_csignature = mproperty.build_csignature(recv_mtype, v.compiler.mainmodule, null, long_signature, internal_call_context)
ccu.header_decl.add("extern {full_friendly_csignature};\n")
+ if not compile_implementation_too then return
+
# Internally, implement internal function
var nitni_visitor = v.compiler.new_visitor
nitni_visitor.frame = v.frame
end
redef class MExplicitSuper
- private fun compile_extern_callback(v: AbstractCompilerVisitor, ccu: CCompilationUnit)
+ private fun compile_extern_callback(v: AbstractCompilerVisitor, ccu: CCompilationUnit, compile_implementation_too: Bool)
do
var mproperty = from.mproperty
assert mproperty isa MMethod
var internal_cname = mproperty.build_cname(mclass_type, v.compiler.mainmodule, "___super", long_signature)
ccu.header_decl.add("#define {friendly_cname} {internal_cname}\n")
+ if not compile_implementation_too then return
+
# Internally, implement internal function
var nitni_visitor = v.compiler.new_visitor
nitni_visitor.frame = v.frame
end
redef class MExplicitCast
- private fun compile_extern_callbacks(v: AbstractCompilerVisitor, ccu: CCompilationUnit)
+ private fun compile_extern_callbacks(v: AbstractCompilerVisitor, ccu: CCompilationUnit, compile_implementation_too: Bool)
do
var from = from
var to = to
# In nitni files, #define friendly as extern
ccu.header_decl.add("#define {check_cname} {v.compiler.mainmodule.name}___{check_cname}\n")
- # Internally, implement internal function
- var nitni_visitor = v.compiler.new_visitor
- nitni_visitor.frame = v.frame
+ if compile_implementation_too then
+ # Internally, implement internal function
+ var nitni_visitor = v.compiler.new_visitor
+ nitni_visitor.frame = v.frame
- var full_internal_csignature = "int {v.compiler.mainmodule.name }___{from.mangled_cname}_is_a_{to.mangled_cname}({internal_call_context.name_mtype(from)} from)"
+ var full_internal_csignature = "int {v.compiler.mainmodule.name }___{from.mangled_cname}_is_a_{to.mangled_cname}({internal_call_context.name_mtype(from)} from)"
- nitni_visitor.add_decl("/* nitni check for {from} to {to} */")
- nitni_visitor.add_decl("{full_internal_csignature} \{")
+ nitni_visitor.add_decl("/* nitni check for {from} to {to} */")
+ nitni_visitor.add_decl("{full_internal_csignature} \{")
- #var from_var = new RuntimeVariable("from->value", from, from)
- var from_var = nitni_visitor.var_from_c("from", from)
- from_var = nitni_visitor.box_extern(from_var, from)
- var recv_var = nitni_visitor.type_test(from_var, to, "FFI isa")
- nitni_visitor.add("return {recv_var};")
+ var from_var = nitni_visitor.var_from_c("from", from)
+ from_var = nitni_visitor.box_extern(from_var, from)
+ var recv_var = nitni_visitor.type_test(from_var, to, "FFI isa")
+ nitni_visitor.add("return {recv_var};")
- nitni_visitor.add("\}")
+ nitni_visitor.add("\}")
+ end
# special checks
if from == to.as_nullable then
# In nitni files, #define friendly as extern
ccu.header_decl.add("#define {cast_cname} {v.compiler.mainmodule.name}___{cast_cname}\n")
- # Internally, implement internal function
- nitni_visitor = v.compiler.new_visitor
- nitni_visitor.frame = v.frame
+ if compile_implementation_too then
+ # Internally, implement internal function
+ var nitni_visitor = v.compiler.new_visitor
+ nitni_visitor.frame = v.frame
- full_internal_csignature = "{to.cname_blind} {v.compiler.mainmodule.name }___{from.mangled_cname}_as_{to.mangled_cname}({internal_call_context.name_mtype(from)} from)"
- nitni_visitor.add_decl("/* nitni cast for {from} to {to} */")
- nitni_visitor.add_decl("{full_internal_csignature} \{")
+ var full_internal_csignature = "{to.cname_blind} {v.compiler.mainmodule.name }___{from.mangled_cname}_as_{to.mangled_cname}({internal_call_context.name_mtype(from)} from)"
+ nitni_visitor.add_decl("/* nitni cast for {from} to {to} */")
+ nitni_visitor.add_decl("{full_internal_csignature} \{")
- from_var = nitni_visitor.var_from_c("from", from)
- from_var = nitni_visitor.box_extern(from_var, from)
+ var from_var = nitni_visitor.var_from_c("from", from)
+ from_var = nitni_visitor.box_extern(from_var, from)
- ## test type
- var check = nitni_visitor.type_test(from_var, to, "FFI cast")
- nitni_visitor.add("if (!{check}) \{")
- nitni_visitor.add_abort("FFI cast failed")
- nitni_visitor.add("\}")
+ ## test type
+ var check = nitni_visitor.type_test(from_var, to, "FFI cast")
+ nitni_visitor.add("if (!{check}) \{")
+ nitni_visitor.add_abort("FFI cast failed")
+ nitni_visitor.add("\}")
- ## internal cast
- recv_var = nitni_visitor.autobox(from_var, to)
- recv_var = nitni_visitor.unbox_extern(recv_var, to)
+ ## internal cast
+ var recv_var = nitni_visitor.autobox(from_var, to)
+ recv_var = nitni_visitor.unbox_extern(recv_var, to)
- nitni_visitor.ret_to_c(recv_var, to)
+ nitni_visitor.ret_to_c(recv_var, to)
- nitni_visitor.add("\}")
+ nitni_visitor.add("\}")
+ end
# special casts
if from.as_nullable == to then
# The result of the RTA (used to know live types and methods)
var runtime_type_analysis: RapidTypeAnalysis
- init(mainmodule: MModule, modelbuilder: ModelBuilder, runtime_type_analysis: RapidTypeAnalysis)
+ init
do
- super(mainmodule, modelbuilder)
var file = new_file("{mainmodule.name}.nitgg")
self.header = new CodeWriter(file)
- self.runtime_type_analysis = runtime_type_analysis
self.live_primitive_types = new Array[MClassType]
for t in runtime_type_analysis.live_types do
if t.ctype != "val*" or t.mclass.name == "Pointer" then
# Subset of runtime_type_analysis.live_types that contains only primitive types
# Used to implement the equal test
- var live_primitive_types: Array[MClassType]
+ var live_primitive_types: Array[MClassType] is noinit
# Add a new todo task
fun todo(m: AbstractRuntimeFunction)
# (usually is a live type but no strong guarantee)
var recv: MClassType
- init(mmethoddef: MMethodDef, recv: MClassType)
- do
- super(mmethoddef)
- self.recv = recv
- end
-
redef fun build_c_name
do
var res = self.c_name_cache
var compiler = new SeparateCompiler(mainmodule, self, runtime_type_analysis)
compiler.compile_header
+ var c_name = mainmodule.c_name
+
# compile class structures
self.toolcontext.info("Property coloring", 2)
- compiler.new_file("{mainmodule.name}.classes")
+ compiler.new_file("{c_name}.classes")
compiler.do_property_coloring
for m in mainmodule.in_importation.greaters do
for mclass in m.intro_mclasses do
end
# The main function of the C
- compiler.new_file("{mainmodule.name}.main")
+ compiler.new_file("{c_name}.main")
compiler.compile_nitni_global_ref_functions
compiler.compile_main_function
compiler.compile_finalizer_function
# compile methods
for m in mainmodule.in_importation.greaters do
- self.toolcontext.info("Generate C for module {m}", 2)
- compiler.new_file("{m.name}.sep")
+ self.toolcontext.info("Generate C for module {m.full_name}", 2)
+ compiler.new_file("{m.c_name}.sep")
compiler.compile_module_to_c(m)
end
# compile live & cast type structures
self.toolcontext.info("Type coloring", 2)
- compiler.new_file("{mainmodule.name}.types")
+ compiler.new_file("{c_name}.types")
var mtypes = compiler.do_type_coloring
for t in mtypes do
compiler.compile_type_to_c(t)
private var undead_types: Set[MType] = new HashSet[MType]
private var live_unresolved_types: Map[MClassDef, Set[MType]] = new HashMap[MClassDef, HashSet[MType]]
- private var type_ids: Map[MType, Int]
- private var type_colors: Map[MType, Int]
- private var opentype_colors: Map[MType, Int]
- protected var method_colors: Map[PropertyLayoutElement, Int]
- protected var attr_colors: Map[MAttribute, Int]
+ private var type_ids: Map[MType, Int] is noinit
+ private var type_colors: Map[MType, Int] is noinit
+ private var opentype_colors: Map[MType, Int] is noinit
+ protected var method_colors: Map[PropertyLayoutElement, Int] is noinit
+ protected var attr_colors: Map[MAttribute, Int] is noinit
- init(mainmodule: MModule, mmbuilder: ModelBuilder, runtime_type_analysis: nullable RapidTypeAnalysis) do
- super(mainmodule, mmbuilder)
+ init do
var file = new_file("nit.common")
self.header = new CodeWriter(file)
- self.runtime_type_analysis = runtime_type_analysis
self.compile_box_kinds
end
var compiler = new SeparateErasureCompiler(mainmodule, self, runtime_type_analysis)
compiler.compile_header
+ var c_name = mainmodule.c_name
+
# compile class structures
self.toolcontext.info("Property coloring", 2)
- compiler.new_file("{mainmodule.name}.tables")
+ compiler.new_file("{c_name}.tables")
compiler.do_property_coloring
for m in mainmodule.in_importation.greaters do
for mclass in m.intro_mclasses do
compiler.compile_color_consts(compiler.vt_colors)
# The main function of the C
- compiler.new_file("{mainmodule.name}.main")
+ compiler.new_file("{c_name}.main")
compiler.compile_nitni_global_ref_functions
compiler.compile_main_function
# compile methods
for m in mainmodule.in_importation.greaters do
- self.toolcontext.info("Generate C for module {m}", 2)
- compiler.new_file("{m.name}.sep")
+ self.toolcontext.info("Generate C for module {m.full_name}", 2)
+ compiler.new_file("{m.c_name}.sep")
compiler.compile_module_to_c(m)
end
class SeparateErasureCompiler
super SeparateCompiler
- private var class_ids: Map[MClass, Int]
- private var class_colors: Map[MClass, Int]
- protected var vt_colors: Map[MVirtualTypeProp, Int]
+ private var class_ids: Map[MClass, Int] is noinit
+ private var class_colors: Map[MClass, Int] is noinit
+ protected var vt_colors: Map[MVirtualTypeProp, Int] is noinit
- init(mainmodule: MModule, mmbuilder: ModelBuilder, runtime_type_analysis: nullable RapidTypeAnalysis) do
- super
+ init do
# Class coloring
var poset = mainmodule.flatten_mclass_hierarchy
# Stats
- private var class_tables: Map[MClass, Array[nullable MClass]]
- private var vt_tables: Map[MClass, Array[nullable MPropDef]]
+ private var class_tables: Map[MClass, Array[nullable MClass]] is noinit
+ private var vt_tables: Map[MClass, Array[nullable MPropDef]] is noinit
redef fun display_sizes
do
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
# The Nitdoc class explores the model and generate pages for each mentities found
class Nitdoc
+ var ctx: ToolContext
var model: Model
var mainmodule: MModule
- var ctx: ToolContext
-
- init(ctx: ToolContext, model: Model, mainmodule: MModule) do
- self.ctx = ctx
- self.model = model
- self.mainmodule = mainmodule
- end
fun generate do
init_output_dir
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
end
# copy shared files
if ctx.opt_shareurl.value == null then
- sys.system("cp -r {sharedir.to_s}/* {output_dir.to_s}/")
+ sys.system("cp -r -- {sharedir.to_s.escape_to_sh}/* {output_dir.to_s.escape_to_sh}/")
else
- sys.system("cp -r {sharedir.to_s}/resources/ {output_dir.to_s}/resources/")
+ sys.system("cp -r -- {sharedir.to_s.escape_to_sh}/resources/ {output_dir.to_s.escape_to_sh}/resources/")
end
end
private var mclasses = new HashSet[MClass]
private var mpropdefs = new HashMap[String, Set[MPropDef]]
- init(ctx: ToolContext, model: Model) do
+ var ctx: ToolContext
+ var model: Model
+
+ init do
for mmodule in model.mmodules do
if mmodule.is_fictive then continue
mmodules.add mmodule
private var mainmodule: MModule
private var name_sorter = new MEntityNameSorter
- init(ctx: ToolContext, model: Model, mainmodule: MModule) do
- self.ctx = ctx
- self.model = model
- self.mainmodule = mainmodule
- end
-
# Render the page as a html template
fun render: Template do
var shareurl = "."
# Clickable graphviz image using dot format
# return null if no graph for this page
- fun tpl_graph(dot: FlatBuffer, name: String, title: nullable String): nullable TplArticle do
+ fun tpl_graph(dot: Buffer, name: String, title: nullable String): nullable TplArticle do
if ctx.opt_nodot.value then return null
var output_dir = ctx.output_dir
- var file = new OFStream.open("{output_dir}/{name}.dot")
+ var path = output_dir / name
+ var path_sh = path.escape_to_sh
+ var file = new OFStream.open("{path}.dot")
file.write(dot)
file.close
- sys.system("\{ test -f {output_dir}/{name}.png && test -f {output_dir}/{name}.s.dot && diff {output_dir}/{name}.dot {output_dir}/{name}.s.dot >/dev/null 2>&1 ; \} || \{ cp {output_dir}/{name}.dot {output_dir}/{name}.s.dot && dot -Tpng -o{output_dir}/{name}.png -Tcmapx -o{output_dir}/{name}.map {output_dir}/{name}.s.dot ; \}")
- var fmap = new IFStream.open("{output_dir}/{name}.map")
+ sys.system("\{ test -f {path_sh}.png && test -f {path_sh}.s.dot && diff -- {path_sh}.dot {path_sh}.s.dot >/dev/null 2>&1 ; \} || \{ cp -- {path_sh}.dot {path_sh}.s.dot && dot -Tpng -o{path_sh}.png -Tcmapx -o{path_sh}.map {path_sh}.s.dot ; \}")
+ var fmap = new IFStream.open("{path}.map")
var map = fmap.read_all
fmap.close
var alt = ""
if title != null then
article.title = title
- alt = "alt='{title}'"
+ alt = "alt='{title.html_escape}'"
end
article.css_classes.add "text-center"
var content = new Template
- content.add "<img src='{name}.png' usemap='#{name}' style='margin:auto' {alt}/>"
+ var name_html = name.html_escape
+ content.add "<img src='{name_html}.png' usemap='#{name_html}' style='margin:auto' {alt}/>"
content.add map
article.content = content
return article
private var mgroup: MGroup
- private var concerns: ConcernsTree
- private var intros: Set[MClass]
- private var redefs: Set[MClass]
+ private var concerns: ConcernsTree is noinit
+ private var intros: Set[MClass] is noinit
+ private var redefs: Set[MClass] is noinit
- init(ctx: ToolContext, model: Model, mainmodule: MModule, mgroup: MGroup) do
- super
- self.mgroup = mgroup
+ init do
self.concerns = model.concerns_tree(mgroup.collect_mmodules)
self.concerns.sort_with(new MConcernRankSorter)
self.intros = mgroup.in_nesting_intro_mclasses(ctx.min_visibility)
super NitdocPage
private var mmodule: MModule
- private var concerns: ConcernsTree
- private var mclasses2mdefs: Map[MClass, Set[MClassDef]]
- private var mmodules2mclasses: Map[MModule, Set[MClass]]
+ private var concerns: ConcernsTree is noinit
+ private var mclasses2mdefs: Map[MClass, Set[MClassDef]] is noinit
+ private var mmodules2mclasses: Map[MModule, Set[MClass]] is noinit
- init(ctx: ToolContext, model: Model, mainmodule: MModule, mmodule: MModule) do
- super
- self.mmodule = mmodule
+ init do
var mclassdefs = new HashSet[MClassDef]
mclassdefs.add_all mmodule.intro_mclassdefs(ctx.min_visibility)
mclassdefs.add_all mmodule.redef_mclassdefs(ctx.min_visibility)
end
end
# build graph
- var op = new FlatBuffer
- var name = "dep_{mmodule.name}"
- op.append("digraph {name} \{ rankdir=BT; node[shape=none,margin=0,width=0,height=0,fontsize=10]; edge[dir=none,color=gray]; ranksep=0.2; nodesep=0.1;\n")
+ var op = new RopeBuffer
+ var name = "dep_module_{mmodule.nitdoc_id}"
+ op.append("digraph \"{name.escape_to_dot}\" \{ rankdir=BT; node[shape=none,margin=0,width=0,height=0,fontsize=10]; edge[dir=none,color=gray]; ranksep=0.2; nodesep=0.1;\n")
for mmodule in poset do
if mmodule == self.mmodule then
- op.append("\"{mmodule.name}\"[shape=box,margin=0.03];\n")
+ op.append("\"{mmodule.name.escape_to_dot}\"[shape=box,margin=0.03];\n")
else
- op.append("\"{mmodule.name}\"[URL=\"{mmodule.nitdoc_url}\"];\n")
+ op.append("\"{mmodule.name.escape_to_dot}\"[URL=\"{mmodule.nitdoc_url.escape_to_dot}\"];\n")
end
for omodule in poset[mmodule].direct_greaters do
- op.append("\"{mmodule.name}\"->\"{omodule.name}\";\n")
+ op.append("\"{mmodule.name.escape_to_dot}\"->\"{omodule.name.escape_to_dot}\";\n")
end
end
op.append("\}\n")
super NitdocPage
private var mclass: MClass
- private var concerns: ConcernsTree
- private var mprops2mdefs: Map[MProperty, Set[MPropDef]]
- private var mmodules2mprops: Map[MModule, Set[MProperty]]
+ private var concerns: ConcernsTree is noinit
+ private var mprops2mdefs: Map[MProperty, Set[MPropDef]] is noinit
+ private var mmodules2mprops: Map[MModule, Set[MProperty]] is noinit
- init(ctx: ToolContext, model: Model, mainmodule: MModule, mclass: MClass) do
- super
- self.mclass = mclass
+ init do
var mpropdefs = new HashSet[MPropDef]
mpropdefs.add_all mclass.intro_mpropdefs(ctx.min_visibility)
mpropdefs.add_all mclass.redef_mpropdefs(ctx.min_visibility)
end
end
- var op = new FlatBuffer
- var name = "dep_{mclass.name}"
- op.append("digraph {name} \{ rankdir=BT; node[shape=none,margin=0,width=0,height=0,fontsize=10]; edge[dir=none,color=gray]; ranksep=0.2; nodesep=0.1;\n")
+ var op = new RopeBuffer
+ var name = "dep_class_{mclass.nitdoc_id}"
+ op.append("digraph \"{name.escape_to_dot}\" \{ rankdir=BT; node[shape=none,margin=0,width=0,height=0,fontsize=10]; edge[dir=none,color=gray]; ranksep=0.2; nodesep=0.1;\n")
var classes = poset.to_a
var todo = new Array[MClass]
var done = new HashSet[MClass]
if done.has(c) then continue
done.add c
if c == mclass then
- op.append("\"{c.name}\"[shape=box,margin=0.03];\n")
+ op.append("\"{c.name.escape_to_dot}\"[shape=box,margin=0.03];\n")
else
- op.append("\"{c.name}\"[URL=\"{c.nitdoc_url}\"];\n")
+ op.append("\"{c.name.escape_to_dot}\"[URL=\"{c.nitdoc_url.escape_to_dot}\"];\n")
end
var smallers = poset[c].direct_smallers
if smallers.length < 10 then
for c2 in smallers do
- op.append("\"{c2.name}\"->\"{c.name}\";\n")
+ op.append("\"{c2.name.escape_to_dot}\"->\"{c.name.escape_to_dot}\";\n")
end
todo.add_all smallers
else
- op.append("\"...\"->\"{c.name}\";\n")
+ op.append("\"...\"->\"{c.name.escape_to_dot}\";\n")
end
end
op.append("\}\n")
super NitdocPage
private var mproperty: MProperty
- private var concerns: ConcernsTree
- private var mmodules2mdefs: Map[MModule, Set[MPropDef]]
+ private var concerns: ConcernsTree is noinit
+ private var mmodules2mdefs: Map[MModule, Set[MPropDef]] is noinit
- init(ctx: ToolContext, model: Model, mainmodule: MModule, mproperty: MProperty) do
- super
+ init do
self.mproperty = mproperty
self.mmodules2mdefs = sort_by_mmodule(collect_mpropdefs)
self.concerns = model.concerns_tree(mmodules2mdefs.keys)
# JS scripts to append at the end of the body
var scripts = new Array[TplScript]
- init do end
-
# Add a section to this page
fun add_section(section: TplSection) do
sections.add section
# Used to select the active link.
private var current_url: String
- init(current_url: String) do
- self.current_url = current_url
- end
-
# Add a new link to the menu.
fun add_link(content: TplLink) do
var is_active = content.href == current_url
# Box HTML id
# equals to `title.to_cmangle` by default
# Used for collapsing
- var id: String
+ var id: String is noinit
# Content to display in the box
# box will not be rendered if the content is null
- var content: nullable Streamable is writable
+ var content: nullable Streamable = null is writable
# Is the box opened by default
# otherwise, the user will have to clic on the title to display the content
var is_open = false is writable
- init(title: String) do
- self.title = title
+ init do
self.id = title.to_cmangle
end
# Will be displayed as a tree
var children = new Array[TplSummaryElt]
- init(text: Streamable) do self.text = text
-
redef fun add_child(child) do children.add child
redef fun rendering do
# Title to display if any
# if both `title` and `summary_title` are null then
# the section will not appear in the summary
- var title: nullable Streamable is writable
+ var title: nullable Streamable = null is writable
# Subtitle to display if any
- var subtitle: nullable Streamable is writable
+ var subtitle: nullable Streamable = null is writable
# Title that appear in the summary
# if null use `title` instead
- var summary_title: nullable String is writable
+ var summary_title: nullable String = null is writable
# CSS classes to apply on the section element
var css_classes = new Array[String]
var title_classes = new Array[String]
# Parent article/section if any
- var parent: nullable TplSectionElt
-
- init(id: String) do self.id = id
+ var parent: nullable TplSectionElt = null
init with_title(id: String, title: Streamable) do
init(id)
var text: Streamable is writable
# Optional title
- var title: nullable String is writable
-
- init(href, text: String) do
- self.href = href
- self.text = text
- end
+ var title: nullable String = null is writable
init with_title(href, text, title: String) do
init(href, text)
# The panel id.
#
# Used to show/hide panel.
- var id: String
+ var id: String is noinit
# The panel name.
#
var name: String
var value: nullable String
- init(name: String, value: nullable String) do
- self.name = name
- self.value = value
- end
-
redef fun rendering do
var value = self.value
if value == null then
var tracker_url: String
var site_id: String
- init(tracker_url, site_id: String) do
- super
- self.tracker_url = tracker_url
- self.site_id = site_id
- end
-
redef fun render_content do
add "<!-- Piwik -->"
add "var _paq = _paq || [];"
--- /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
super ForeignType
redef var ctype: String
-
- init(ctype: String)
- do
- self.ctype = ctype
- end
end
redef class NitniCallback
class ToCCallContext
super CallContext
- private init do end
+ # TODO: private init because singleton instance (see `to_c_call_context`)
redef fun name_mtype(mtype)
do
class FromCCallContext
super CallContext
- private init do end
+ # TODO: private init because singleton instance (see `from_c_call_context`)
redef fun name_mtype(mtype) do return mtype.cname
end
super CCompilerOption
var option: String
- init (opt: String) do option = opt
end
class ExecCCompilerOption
var command: Array[String]
var exec_node: ACallExpr
-
- init (command: Array[String], exec_node: ACallExpr)
- do
- self.command = command
- self.exec_node = exec_node
- end
end
end
fc.exprs.add(mproperty.build_ccall(mclass_type, mmodule, "___cpp_impl", long_signature, cpp_call_context, "_for_cpp"))
fc.exprs.add("\n")
- mmodule.cpp_file.add_local_function(fc)
+ mmodule.cpp_file.add_exported_function(fc)
# Custom C++, the body of the Nit C++ method is copied to its own C++ function
var cpp_signature = mproperty.build_csignature(mclass_type, mmodule, "___cpp_impl", long_signature, cpp_call_context)
super ExternFile
var mmodule: MModule
- init(path: String, mmodule: MModule)
- do
- super
- self.mmodule = mmodule
- end
redef fun makefile_rule_name do return "{filename.basename("")}.o"
redef fun makefile_rule_content do return "$(CXX) $(CFLAGS) {mmodule.cpp_compiler_options} -c {filename.basename("")} -o {filename.basename("")}.o"
super ForeignType
var cpp_type: String
-
- init (cpp_type: String)
- do
- self.cpp_type = cpp_type
- end
end
redef class NitniCallback
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
# Visitor for a specific languages. Works kinda like a `Phase` and is executed
# by a `Phase`.
class FFILanguage
- init(ffi_language_assignation_phase: FFILanguageAssignationPhase)
+ var ffi_language_assignation_phase: FFILanguageAssignationPhase
+
+ init
do
ffi_language_assignation_phase.languages.add(self)
end
{{{block.code}}}
}
"""
+
+ mmodule.callbacks_used_from_java.join m.foreign_callbacks
end
redef fun compile_extern_class(block, m, ccu, mmodule) do end
mmodule.insert_compiler_options
# Enable linking C callbacks to java native methods
- mmodule.ensure_linking_callback_methods(ffi_ccu.as(not null), mmodule.ffi_callbacks[self])
+ mmodule.ensure_linking_callback_methods(ffi_ccu.as(not null))
# Java implementation code
var java_file = mmodule.java_file
end
redef class MModule
+ private var callbacks_used_from_java = new ForeignCallbackSet
# Pure java class source file
private var java_file: nullable JavaClassTemplate = null
end
# Compile C code to call JNI and link C callbacks implementations to Java extern methods
- private fun ensure_linking_callback_methods(ccu: CCompilationUnit, callbacks: Set[NitniCallback])
+ private fun ensure_linking_callback_methods(ccu: CCompilationUnit)
do
+ var callbacks = callbacks_used_from_java.callbacks
if callbacks.is_empty then
ccu.body_decl.add "static int nit_ffi_with_java_registered_natives = 1;\n"
return
jni_methods.add_all(cb.jni_methods_declaration(self))
end
- var cf = new CFunction("static void nit_ffi_with_java_register_natives(JNIEnv* env, jclass jclazz)")
+ var cf = new CFunction("void nit_ffi_with_java_register_natives(JNIEnv* env, jclass jclazz)")
cf.exprs.add """
nit_ffi_with_java_registered_natives = 1;
super Template
var java_class_name: String
- init(name: String) do self.java_class_name = name
var header = new Template
var class_content = new Template
super ForeignType
var java_type: String
- init (java_type: String) do self.java_type = java_type
end
redef class NitniCallback
redef class MExplicitCall
redef fun compile_callback_to_java(mmodule, mainmodule, ccu)
do
+ if not mmodule.callbacks_used_from_java.callbacks.has(self) then return
+
var mproperty = mproperty
assert mproperty isa MMethod
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
private class CachedPhase
super Phase
- init(toolcontext, depends)
+ init
do
# FIXME The phase has to be executed just after `modelize_property_phase`
# But there is no simple way to express this
# The mmodule is the current module
var mmodule: MModule
- init(toolcontext: ToolContext, mmodule: MModule)
- do
- self.toolcontext = toolcontext
- self.mmodule = mmodule
- end
-
redef fun visit(node)
do
# Recursively visit all sub-nodes
var mclassdef: MClassDef
var toolcontext: ToolContext
- init(npropdef: AMethPropdef, mclassdef: MClassDef, toolcontext: ToolContext)
- do
- self.npropdef = npropdef
- self.mclassdef = mclassdef
- self.toolcontext = toolcontext
- end
-
redef fun visit(n) do n.accept_precise_type_visitor(self)
end
do
toolcontext.warning(node.hot_location, tag, msg)
end
-
- init(toolcontext: ToolContext)
- do
- self.toolcontext = toolcontext
- end
end
redef class ScopeVisitor
- redef init(toolcontext)
+ redef init
do
super
if toolcontext.dbg != null then
private class TraceObject
# Map of the local names bound to a frame
- var trace_map: HashMap[Frame, String]
+ var trace_map = new HashMap[Frame, String]
+
# Decides if breaking or printing statement when the variable is encountered
var break_on_encounter: Bool
- init(break_on_encounter: Bool)
- do
- trace_map = new HashMap[Frame, String]
- self.break_on_encounter = break_on_encounter
- end
-
# Adds the local alias for a variable and the frame bound to it
fun add_frame_variable(frame: Frame, variable_name: String)
do
var arguments: Array[String]
# The main Sys instance
- var mainobj: nullable Instance
+ var mainobj: nullable Instance is noinit
- init(modelbuilder: ModelBuilder, mainmodule: MModule, arguments: Array[String])
+ init
do
- self.modelbuilder = modelbuilder
- self.mainmodule = mainmodule
- self.arguments = arguments
self.true_instance = new PrimitiveInstance[Bool](mainmodule.bool_type, true)
+ init_instance_primitive(self.true_instance)
self.false_instance = new PrimitiveInstance[Bool](mainmodule.bool_type, false)
+ init_instance_primitive(self.false_instance)
self.null_instance = new MutableInstance(mainmodule.model.null_type)
end
# Return the integer instance associated with `val`.
fun int_instance(val: Int): Instance
do
- var ic = self.mainmodule.get_primitive_class("Int")
- return new PrimitiveInstance[Int](ic.mclass_type, val)
+ var ic = get_primitive_class("Int")
+ var instance = new PrimitiveInstance[Int](ic.mclass_type, val)
+ init_instance_primitive(instance)
+ return instance
end
# Return the char instance associated with `val`.
fun char_instance(val: Char): Instance
do
- var ic = self.mainmodule.get_primitive_class("Char")
- return new PrimitiveInstance[Char](ic.mclass_type, val)
+ var ic = get_primitive_class("Char")
+ var instance = new PrimitiveInstance[Char](ic.mclass_type, val)
+ init_instance_primitive(instance)
+ return instance
end
# Return the float instance associated with `val`.
fun float_instance(val: Float): Instance
do
- var ic = self.mainmodule.get_primitive_class("Float")
- return new PrimitiveInstance[Float](ic.mclass_type, val)
+ var ic = get_primitive_class("Float")
+ var instance = new PrimitiveInstance[Float](ic.mclass_type, val)
+ init_instance_primitive(instance)
+ return instance
end
# The unique instance of the `true` value.
- var true_instance: Instance
+ var true_instance: Instance is noinit
# The unique instance of the `false` value.
- var false_instance: Instance
+ var false_instance: Instance is noinit
# The unique instance of the `null` value.
- var null_instance: Instance
+ var null_instance: Instance is noinit
# Return a new array made of `values`.
# The dynamic type of the result is Array[elttype].
fun array_instance(values: Array[Instance], elttype: MType): Instance
do
assert not elttype.need_anchor
- var nat = new PrimitiveInstance[Array[Instance]](self.mainmodule.get_primitive_class("NativeArray").get_mtype([elttype]), values)
- var mtype = self.mainmodule.get_primitive_class("Array").get_mtype([elttype])
+ var nat = new PrimitiveInstance[Array[Instance]](get_primitive_class("NativeArray").get_mtype([elttype]), values)
+ init_instance_primitive(nat)
+ var mtype = get_primitive_class("Array").get_mtype([elttype])
var res = new MutableInstance(mtype)
self.init_instance(res)
self.send(self.force_get_primitive_method("with_native", mtype), [res, nat, self.int_instance(values.length)])
do
var val = new FlatBuffer.from(txt)
val.add('\0')
- var ic = self.mainmodule.get_primitive_class("NativeString")
- return new PrimitiveInstance[Buffer](ic.mclass_type, val)
+ var ic = get_primitive_class("NativeString")
+ var instance = new PrimitiveInstance[Buffer](ic.mclass_type, val)
+ init_instance_primitive(instance)
+ return instance
end
# Return a new String instance for `txt`
end
end
+ # A hook to initialize a `PrimitiveInstance`
+ fun init_instance_primitive(recv: Instance) do end
+
+ # Return the primitive `MClass` corresponding to the `name` given in parameter
+ # `name` : name of the primitive class
+ fun get_primitive_class(name: String): MClass
+ do
+ return mainmodule.get_primitive_class(name)
+ end
+
# This function determine the correct type according the reciever of the current definition (self).
fun unanchor_type(mtype: MType): MType
do
# The real value encapsulated
redef var val: E
- init(mtype: MType, val: E)
- do
- super(mtype)
- self.val = val
- end
-
redef fun is_true
do
if val == true then return true
else if cname == "NativeArray" then
if pname == "new" then
var val = new Array[Instance].filled_with(v.null_instance, args[1].to_i)
- return new PrimitiveInstance[Array[Instance]](args[0].mtype, val)
+ var instance = new PrimitiveInstance[Array[Instance]](args[0].mtype, val)
+ v.init_instance_primitive(instance)
+ return instance
end
var recvval = args.first.val.as(Array[Instance])
if pname == "[]" then
end
else if cname == "NativeFile" then
if pname == "native_stdout" then
- return new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, sys.stdout)
+ var instance = new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, sys.stdout)
+ v.init_instance_primitive(instance)
+ return instance
else if pname == "native_stdin" then
- return new PrimitiveInstance[IStream](mpropdef.mclassdef.mclass.mclass_type, sys.stdin)
+ var instance = new PrimitiveInstance[IStream](mpropdef.mclassdef.mclass.mclass_type, sys.stdin)
+ v.init_instance_primitive(instance)
+ return instance
else if pname == "native_stderr" then
- return new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, sys.stderr)
+ var instance = new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, sys.stderr)
+ v.init_instance_primitive(instance)
+ return instance
else if pname == "io_open_read" then
var a1 = args[1].val.as(Buffer)
- return new PrimitiveInstance[IStream](mpropdef.mclassdef.mclass.mclass_type, new IFStream.open(a1.to_s))
+ var instance = new PrimitiveInstance[IStream](mpropdef.mclassdef.mclass.mclass_type, new IFStream.open(a1.to_s))
+ v.init_instance_primitive(instance)
+ return instance
else if pname == "io_open_write" then
var a1 = args[1].val.as(Buffer)
- return new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, new OFStream.open(a1.to_s))
+ var instance = new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, new OFStream.open(a1.to_s))
+ v.init_instance_primitive(instance)
+ return instance
end
var recvval = args.first.val
if pname == "io_write" then
else if pname == "calloc_array" then
var recvtype = args.first.mtype.as(MClassType)
var mtype: MType
- mtype = recvtype.supertype_to(v.mainmodule, recvtype, v.mainmodule.get_primitive_class("ArrayCapable"))
+ mtype = recvtype.supertype_to(v.mainmodule, recvtype, v.get_primitive_class("ArrayCapable"))
mtype = mtype.arguments.first
var val = new Array[Instance].filled_with(v.null_instance, args[1].to_i)
- return new PrimitiveInstance[Array[Instance]](v.mainmodule.get_primitive_class("NativeArray").get_mtype([mtype]), val)
+ var instance = new PrimitiveInstance[Array[Instance]](v.get_primitive_class("NativeArray").get_mtype([mtype]), val)
+ v.init_instance_primitive(instance)
+ return instance
else if pname == "native_argc" then
return v.int_instance(v.arguments.length)
else if pname == "native_argv" then
if i == null then return null
array.add(i)
end
- var i = v.array_instance(array, v.mainmodule.get_primitive_class("Object").mclass_type)
+ var i = v.array_instance(array, v.get_primitive_class("Object").mclass_type)
var res = v.send(v.force_get_primitive_method("to_s", i.mtype), [i])
assert res != null
return res
var toolcontext: ToolContext
- init(toolcontext: ToolContext)
- do
- self.toolcontext = toolcontext
- end
-
redef fun visit(n)
do
n.accept_literal(self)
var filename: String
# The content of the source
- var string: String
+ var string: String is noinit
- # Create a new sourcefile using a filename and a stream
- init(filename: String, stream: IStream)
+ # The original stream used to initialize `string`
+ var stream: IStream
+
+ init
do
- self.filename = filename
string = stream.read_all
line_starts[0] = 0
end
var column_start: Int
var column_end: Int
- init(f: nullable SourceFile, line_s: Int, line_e: Int, column_s: Int, column_e: Int) do
- file = f
- line_start = line_s
- line_end = line_e
- column_start = column_s
- column_end = column_e
- end
-
# The index in the start character in the source
fun pstart: Int do return file.line_starts[line_start-1] + column_start-1
return res
end
- private var text_cache: nullable String
+ private var text_cache: nullable String = null
init with_file(f: SourceFile) do init(f,0,0,0,0)
dot.mprojects.add(g.mproject)
end
var projectpath = toolcontext.output_dir.join_path("project_hierarchy.dot")
- print "generating {projectpath}"
+ print "generating project_hierarchy.dot"
dot.write_to_file(projectpath)
var modulepath = toolcontext.output_dir.join_path("module_hierarchy.dot")
dot.mprojects.add_all(model.mprojects)
- print "generating {modulepath}"
+ print "generating module_hierarchy.dot"
dot.write_to_file(modulepath)
end
# The view of the module in the `model.mmodule_nesting_hierarchy`
#
# TODO REMOVE, rely on mgroup instead
- var in_nesting: POSetElement[MModule]
+ var in_nesting: POSetElement[MModule] is noinit
# The view of the module in the `model.mmodule_importation_hierarchy`
- var in_importation: POSetElement[MModule]
+ var in_importation: POSetElement[MModule] is noinit
# The canonical name of the module
# Example: `"project::name"`
end
# Create a new empty module and register it to a model
- init(model: Model, mgroup: nullable MGroup, name: String, location: Location)
+ init
do
- self.model = model
- self.name = name
- self.location = location
model.mmodules_by_name.add_one(name, self)
model.mmodules.add(self)
self.in_nesting = model.mmodule_nesting_hierarchy.add_node(self)
- self.mgroup = mgroup
if mgroup != null then
mgroup.mmodules.add(self)
if mgroup.name == name then
# The number of generic formal parameters
# 0 if the class is not generic
- var arity: Int
+ var arity: Int is noinit
# Each generic formal parameters in order.
# is empty if the class is not generic
var mparameters = new Array[MParameterType]
- # The kind of the class (interface, abstract class, etc.)
- # In Nit, the kind of a class cannot evolve in refinements
- var kind: MClassKind
-
- # The visibility of the class
- # In Nit, the visibility of a class cannot evolve in refinements
- var visibility: MVisibility
-
- init(intro_mmodule: MModule, name: String, parameter_names: nullable Array[String], kind: MClassKind, visibility: MVisibility)
+ protected fun setup_parameter_names(parameter_names: nullable Array[String]) is
+ autoinit
do
- self.intro_mmodule = intro_mmodule
- self.name = name
if parameter_names == null then
self.arity = 0
else
self.arity = parameter_names.length
end
- self.kind = kind
- self.visibility = visibility
- intro_mmodule.intro_mclasses.add(self)
- var model = intro_mmodule.model
- model.mclasses_by_name.add_one(name, self)
- model.mclasses.add(self)
# Create the formal parameter types
if arity > 0 then
end
end
+ # The kind of the class (interface, abstract class, etc.)
+ # In Nit, the kind of a class cannot evolve in refinements
+ var kind: MClassKind
+
+ # The visibility of the class
+ # In Nit, the visibility of a class cannot evolve in refinements
+ var visibility: MVisibility
+
+ init
+ do
+ intro_mmodule.intro_mclasses.add(self)
+ var model = intro_mmodule.model
+ model.mclasses_by_name.add_one(name, self)
+ model.mclasses.add(self)
+ end
+
redef fun model do return intro_mmodule.model
# All class definitions (introduction and refinements)
#
# Warning: such a definition may not exist in the early life of the object.
# In this case, the method will abort.
- var intro: MClassDef
+ var intro: MClassDef is noinit
# Return the class `self` in the class hierarchy of the module `mmodule`.
#
# To get other types based on a generic class, see `get_mtype`.
#
# ENSURE: `mclass_type.mclass == self`
- var mclass_type: MClassType
+ var mclass_type: MClassType is noinit
# Return a generic type based on the class
# Is the class is not generic, then the result is `mclass_type`
var mmodule: MModule
# The associated `MClass`
- var mclass: MClass
+ var mclass: MClass is noinit
# The bounded type associated to the mclassdef
#
# Internal name combining the module and the class
# Example: "mymodule#MyClass"
- redef var to_s: String
+ redef var to_s: String is noinit
- init(mmodule: MModule, bound_mtype: MClassType, location: Location)
+ init
do
- self.bound_mtype = bound_mtype
- self.mmodule = mmodule
self.mclass = bound_mtype.mclass
- self.location = location
mmodule.mclassdefs.add(self)
mclass.mclassdefs.add(self)
if mclass.intro_mmodule == mmodule then
redef fun model do return self.mclass.intro_mmodule.model
- private init(mclass: MClass)
- do
- self.mclass = mclass
- end
+ # TODO: private init because strongly bounded to its mclass. see `mclass.mclass_type`
# The formal arguments of the type
# ENSURE: `result.length == self.mclass.arity`
class MGenericType
super MClassType
- private init(mclass: MClass, arguments: Array[MType])
+ redef var arguments
+
+ # TODO: private init because strongly bounded to its mclass. see `mclass.get_mtype`
+
+ init
do
- super(mclass)
assert self.mclass.arity == arguments.length
- self.arguments = arguments
self.need_anchor = false
for t in arguments do
# Recursively print the type of the arguments within brackets.
# Example: `"Map[String, List[Int]]"`
- redef var to_s: String
+ redef var to_s: String is noinit
- redef var need_anchor: Bool
+ redef var need_anchor: Bool is noinit
redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual)
do
end
redef fun to_s do return self.mproperty.to_s
-
- init(mproperty: MProperty)
- do
- self.mproperty = mproperty
- end
end
# The type associated to a formal parameter generic type of a class
end
return mtype.collect_mclassdefs(mmodule).has(mclass.intro)
end
-
- init(mclass: MClass, rank: Int, name: String)
- do
- self.mclass = mclass
- self.rank = rank
- self.name = name
- end
end
# A type prefixed with "nullable"
redef fun model do return self.mtype.model
- init(mtype: MType)
+ init
do
- self.mtype = mtype
self.to_s = "nullable {mtype}"
end
- redef var to_s: String
+ redef var to_s: String is noinit
redef fun need_anchor do return mtype.need_anchor
redef fun as_nullable do return self
class MNullType
super MType
redef var model: Model
- protected init(model: Model)
- do
- self.model = model
- end
redef fun to_s do return "null"
redef fun as_nullable do return self
redef fun need_anchor do return false
end
# REQUIRE: 1 <= mparameters.count p -> p.is_vararg
- init(mparameters: Array[MParameter], return_mtype: nullable MType)
+ init
do
var vararg_rank = -1
for i in [0..mparameters.length[ do
vararg_rank = i
end
end
- self.mparameters = mparameters
- self.return_mtype = return_mtype
self.vararg_rank = vararg_rank
end
# The rank of the ellipsis (`...`) for vararg (starting from 0).
# value is -1 if there is no vararg.
# Example: for "(a: Int, b: Bool..., c: Char)" #-> vararg_rank=1
- var vararg_rank: Int
+ var vararg_rank: Int is noinit
# The number or parameters
fun arity: Int do return mparameters.length
# Is the parameter a vararg?
var is_vararg: Bool
- init(name: String, mtype: MType, is_vararg: Bool) do
- self.name = name
- self.mtype = mtype
- self.is_vararg = is_vararg
- end
-
redef fun to_s
do
if is_vararg then
# The visibility of the property
var visibility: MVisibility
- init(intro_mclassdef: MClassDef, name: String, visibility: MVisibility)
+ init
do
- self.intro_mclassdef = intro_mclassdef
- self.name = name
- self.visibility = visibility
intro_mclassdef.intro_mproperties.add(self)
var model = intro_mclassdef.mmodule.model
model.mproperties_by_name.add_one(name, self)
#
# Warning: such a definition may not exist in the early life of the object.
# In this case, the method will abort.
- var intro: MPROPDEF
+ var intro: MPROPDEF is noinit
redef fun model do return intro.model
redef type MPROPDEF: MMethodDef
- init(intro_mclassdef: MClassDef, name: String, visibility: MVisibility)
- do
- super
- end
-
# Is the property defined at the top_level of the module?
# Currently such a property are stored in `Object`
var is_toplevel: Bool = false is writable
redef type MPROPDEF: MAttributeDef
- init(intro_mclassdef: MClassDef, name: String, visibility: MVisibility)
- do
- super
- end
end
# A global virtual type
redef type MPROPDEF: MVirtualTypeDef
- init(intro_mclassdef: MClassDef, name: String, visibility: MVisibility)
- do
- super
- end
-
# The formal type associated to the virtual type property
var mvirtualtype = new MVirtualType(self)
end
# Self class
type MPROPDEF: MPropDef
- # The origin of the definition
- var location: Location
-
# The class definition where the property definition is
var mclassdef: MClassDef
# The associated global property
var mproperty: MPROPERTY
- init(mclassdef: MClassDef, mproperty: MPROPERTY, location: Location)
+ # The origin of the definition
+ var location: Location
+
+ init
do
- self.mclassdef = mclassdef
- self.mproperty = mproperty
- self.location = location
mclassdef.mpropdefs.add(self)
mproperty.mpropdefs.add(self)
if mproperty.intro_mclassdef == mclassdef then
# Internal name combining the module, the class and the property
# Example: "mymodule#MyClass#mymethod"
- redef var to_s: String
+ redef var to_s: String is noinit
# Is self the definition that introduce the property?
fun is_intro: Bool do return mproperty.intro == self
redef type MPROPERTY: MMethod
redef type MPROPDEF: MMethodDef
- init(mclassdef: MClassDef, mproperty: MPROPERTY, location: Location)
- do
- super
- end
-
# The signature attached to the property definition
var msignature: nullable MSignature = null is writable
redef type MPROPERTY: MAttribute
redef type MPROPDEF: MAttributeDef
- init(mclassdef: MClassDef, mproperty: MPROPERTY, location: Location)
- do
- super
- end
-
# The static type of the attribute
var static_mtype: nullable MType = null is writable
end
redef type MPROPERTY: MVirtualTypeProp
redef type MPROPDEF: MVirtualTypeDef
- init(mclassdef: MClassDef, mproperty: MPROPERTY, location: Location)
- do
- super
- end
-
# The bound of the virtual type
var bound: nullable MType = null is writable
# Is a constructor required?
var need_init: Bool
- private init(s: String, need_init: Bool)
- do
- self.to_s = s
- self.need_init = need_init
- end
+
+ # TODO: private init because enumeration.
# Can a class of kind `self` specializes a class of kine `other`?
fun can_specialize(other: MClassKind): Bool
private var level: Int
- private init(s: String, level: Int)
- do
- self.to_s = s
- self.level = level
- end
+ # TODO: private init because enumeration.
# Is self give less visibility than other
# none < private < protected < public < intrude
# The model where to look for information
var model: Model
- init(model: Model) do self.model = model
-
redef fun display(a) do
if a isa MGroup then
if a.parent == null then return "{a.mproject.name} ({a.filepath.to_s})"
redef fun to_s do return name
- init(name: String, model: Model)
+ init
do
- self.name = name
- self.model = model
model.mprojects.add(self)
model.mproject_by_name.add_one(name, self)
end
# The group is the group tree on the project (`mproject.mgroups`)
# nested groups (children) are smaller
# nesting group (see `parent`) is bigger
- var in_nesting: POSetElement[MGroup]
+ var in_nesting: POSetElement[MGroup] is noinit
# Is `self` the root of its project?
fun is_root: Bool do return mproject.root == self
# The filepath (usually a directory) of the group, if any
- var filepath: nullable String is writable
+ var filepath: nullable String = null is writable
- init (name: String, mproject: MProject, parent: nullable MGroup)
+ init
do
- self.name = name
- self.mproject = mproject
- self.parent = parent
var tree = mproject.mgroups
self.in_nesting = tree.add_node(self)
+ var parent = self.parent
if parent != null then
tree.add_edge(self, parent)
end
# Instantiate a modelbuilder for a model and a toolcontext
# Important, the options of the toolcontext must be correctly set (parse_option already called)
- init(model: Model, toolcontext: ToolContext)
+ init
do
- self.model = model
- self.toolcontext = toolcontext
assert toolcontext.modelbuilder_real == null
toolcontext.modelbuilder_real = self
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.
# Can self be used as a root init?
- private fun look_like_a_root_init(modelbuilder: ModelBuilder): Bool
+ private fun look_like_a_root_init(modelbuilder: ModelBuilder, mclassdef: MClassDef): Bool
do
# Need the `init` keyword
if n_kwinit == null then return false
# Need to by anonymous
if self.n_methid != null then return false
- # No parameters
- if self.n_signature.n_params.length > 0 then return false
- # Cannot be private or something
- if not self.n_visibility isa APublicVisibility then return false
# No annotation on itself
if get_single_annotation("old_style_init", modelbuilder) != null then return false
# Nor on its module
var old = amoddecl.get_single_annotation("old_style_init", modelbuilder)
if old != null then return false
end
+ # No parameters
+ if self.n_signature.n_params.length > 0 then
+ modelbuilder.advice(self, "old-init", "Warning: init with signature in {mclassdef}")
+ return false
+ end
+ # Cannot be private or something
+ if not self.n_visibility isa APublicVisibility then
+ modelbuilder.advice(self, "old-init", "Warning: non-public init in {mclassdef}")
+ return false
+ end
return true
end
end
end
+ var look_like_a_root_init = look_like_a_root_init(modelbuilder, mclassdef)
var mprop: nullable MMethod = null
if not is_init or n_kwredef != null then mprop = modelbuilder.try_get_mproperty_by_name(name_node, mclassdef, name).as(nullable MMethod)
- if mprop == null and look_like_a_root_init(modelbuilder) then
+ if mprop == null and look_like_a_root_init then
mprop = modelbuilder.the_root_init_mmethod
var nb = n_block
if nb isa ABlockExpr and nb.n_expr.is_empty and n_doc == null then
if mprop == null then
var mvisibility = new_property_visibility(modelbuilder, mclassdef, self.n_visibility)
mprop = new MMethod(mclassdef, name, mvisibility)
- if look_like_a_root_init(modelbuilder) and modelbuilder.the_root_init_mmethod == null then
+ if look_like_a_root_init and modelbuilder.the_root_init_mmethod == null then
modelbuilder.the_root_init_mmethod = mprop
mprop.is_root_init = true
end
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")
# Length of the signature of a C function (long version hase the module name as prefix)
class SignatureLength
private var long: Bool
- private init(long: Bool) do self.long = long
+
+ # TODO: private init because singleton class.
end
var file = toolcontext.opt_output.value
if file == null then file = "nitunit.xml"
page.write_to_file(file)
-print "Results saved in {file}"
# print docunits results
-print "\nDocUnits:"
+print "DocUnits:"
if modelbuilder.unit_entities == 0 then
print "No doc units found"
else if modelbuilder.failed_entities == 0 and not toolcontext.opt_noact.value then
# then wait for query on std in to display documentation
class NitIndex
private var toolcontext: ToolContext
- private var model: Model
- private var mbuilder: ModelBuilder
- private var mainmodule: MModule
- private var arguments: Array[String]
- private var renderer: PagerMatchesRenderer
+ private var model: Model is noinit
+ private var mbuilder: ModelBuilder is noinit
+ private var mainmodule: MModule is noinit
+ private var arguments: Array[String] is noinit
+ private var renderer: PagerMatchesRenderer is noinit
# New constructor to use the pre-calculated model when interpreting a module
init with_infos(mbuilder: ModelBuilder, mmodule: MModule) do
renderer = new PagerMatchesRenderer(self)
end
- init(toolcontext: ToolContext) do
+ init do
# We need a model to collect stufs
- self.toolcontext = toolcontext
self.arguments = toolcontext.option_context.rest
if arguments.length > 2 then
private class IndexQuery
var string: String
var keyword: String
- init(string: String, keyword: String) do
- self.string = string
- self.keyword = keyword
- end
end
private class IndexQueryPair
super IndexQuery
var category: String
- init(string: String, keyword: String, category: String) do
- super(string, keyword)
- self.category = category
- end
end
# A match to a query in the nit index
private class PagerMatchesRenderer
var index: NitIndex
- init(index: NitIndex) do self.index = index
fun render_matches(query: IndexQuery, matches: Collection[IndexMatch]) do
var pager = new Pager
# It is better user with the Parser
class Lexer
super TablesCapable
+
# Last peeked token
- var token: nullable Token
+ var token: nullable Token = null
# Lexer current state
private var state: Int = 0
# Constante state values
private fun state_initial: Int do return 0 end
- # Create a new lexer for a stream (and a name)
- init(file: SourceFile)
- do
- self.file = file
- end
-
# The last peeked token to chain them
private var last_token: nullable Token = null
class Start
super Prod
var n_base: nullable AModule is writable
- var n_eof: EOF is writable, noinit
- init(n_base: nullable AModule, n_eof: EOF)
- do
- self._n_base = n_base
- self._n_eof = n_eof
- end
+ var n_eof: EOF is writable
end
# The node stored with the state in the stack
var nodes: nullable Object
-
- init(state: Int, nodes: nullable Object)
- do
- _state = state
- _nodes = nodes
- end
end
# The parser of the Nit language.
var lexer: Lexer
# Stack of pushed states and productions
- private var stack: Array[State]
+ private var stack = new Array[State]
# Position in the stack
- private var stack_pos: Int
+ private var stack_pos: Int = -1
- # Create a new parser based on a given lexer
- init(lexer: Lexer)
+ init
do
- _lexer = lexer
- _stack = new Array[State]
- _stack_pos = -1
build_reduce_table
end
end
end
- private var reduce_table: Array[ReduceAction]
+ private var reduce_table: Array[ReduceAction] is noinit
private fun build_reduce_table is abstract
end
return l1
end
var goto: Int
- init(g: Int) do _goto = g
end
private class CollectTokensByTextVisitor
super Visitor
var text: String
- init(text: String) do self.text = text
var result = new Array[Token]
redef fun visit(node)
do
private class CollectAnnotationsByNameVisitor
super Visitor
var name: String
- init(name: String) do self.name = name
var result = new Array[AAnnotation]
redef fun visit(node)
do
var toolcontext: ToolContext
# The dependence relation of the phase with the other phases
- var in_hierarchy: POSetElement[Phase]
+ var in_hierarchy: POSetElement[Phase] is noinit
+
+ # The explicit dependences, used to initialize `in_importation`
+ var depends: nullable Collection[Phase]
# Initialize and register a phase to the toolcontext
- init(toolcontext: ToolContext, depends: nullable Collection[Phase])
+ init
do
- self.toolcontext = toolcontext
in_hierarchy = toolcontext.phases.add_node(self)
+ var depends = self.depends
if depends != null then
for d in depends do
toolcontext.phases.add_edge(self, d)
var receiver: MClassType
var mpropdef: MPropDef
- init(analysis: RapidTypeAnalysis, receiver: MClassType, mpropdef: MPropDef)
+ init
do
- self.analysis = analysis
- self.receiver = receiver
- self.mpropdef = mpropdef
assert not receiver.need_anchor
end
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
private class FlowVisitor
super Visitor
- var current_flow_context: FlowContext
+ var current_flow_context = new FlowContext
var toolcontext: ToolContext
- init(toolcontext: ToolContext)
+ init
do
- self.toolcontext = toolcontext
- current_flow_context = new FlowContext
flows.add(current_flow_context)
current_flow_context.is_start = true
end
- var first: nullable ANode
+ var first: nullable ANode = null
redef fun visit(node)
do
var toolcontext: ToolContext
- init(toolcontext: ToolContext)
- do
- self.toolcontext = toolcontext
- end
-
# Local variables that are possibly unset (ie local variable without an initial value)
var maybe_unset_vars: Set[Variable] = new HashSet[Variable]
var selfvariable = new Variable("self")
- init(toolcontext: ToolContext)
+ init
do
- self.toolcontext = toolcontext
scopes.add(new Scope)
end
# The static type of the receiver
# Mainly used for type tests and type resolutions
- var anchor: nullable MClassType
+ var anchor: nullable MClassType = null
# The analyzed mclassdef
- var mclassdef: nullable MClassDef
+ var mclassdef: nullable MClassDef = null
# The analyzed property
var mpropdef: nullable MPropDef
# * method called on the implicit self must be top-level
var is_toplevel_context = false
- init(modelbuilder: ModelBuilder, mmodule: MModule, mpropdef: nullable MPropDef)
+ init
do
- self.modelbuilder = modelbuilder
- self.mmodule = mmodule
+ var mpropdef = self.mpropdef
if mpropdef != null then
self.mpropdef = mpropdef
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
class NitUnitExecutor
super Doc2Mdwn
- # The module to import
- var mmodule: MModule
-
# The prefix of the generated Nit source-file
var prefix: String
+ # The module to import
+ var mmodule: MModule
+
# The XML node associated to the module
var testsuite: HTMLTag
- # Initialize a new e
- init(toolcontext: ToolContext, prefix: String, mmodule: MModule, testsuite: HTMLTag)
- do
- super(toolcontext)
- self.prefix = prefix
- self.mmodule = mmodule
- self.testsuite = testsuite
- end
-
# All blocks of code from a same `ADoc`
var blocks = new Array[Array[String]]
end
# The associated node to localize warnings
- var ndoc: nullable ADoc
+ var ndoc: nullable ADoc = null
# used to generate distinct names
var cpt = 0
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 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
- 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
var toolcontext: ToolContext
- init(toolcontext: ToolContext) do
- self.toolcontext = toolcontext
- end
-
private fun extract_options_names: Array[String] do
var names = new Array[String]
for option in toolcontext.option_context.options do
do
var val
- var v = new TransformVisitor(self, npropdef)
+ var v = new TransformVisitor(self, npropdef.mpropdef.as(not null))
v.enter_visit(npropdef)
val = new ASTValidationVisitor
super Visitor
var phase: TransformPhase
- var mmodule: MModule
- var mclassdef: MClassDef
+ var mmodule: MModule is noinit
+ var mclassdef: MClassDef is noinit
var mpropdef: MPropDef
- var builder: ASTBuilder
+ var builder: ASTBuilder is noinit
- init(phase: TransformPhase, npropdef: APropdef)
+ init
do
- self.phase = phase
- self.mpropdef = npropdef.mpropdef.as(not null)
self.mclassdef = mpropdef.mclassdef
self.mmodule = mclassdef.mmodule
self.builder = new ASTBuilder(mmodule, mpropdef.mclassdef.bound_mtype)
init(modelbuilder: ModelBuilder, mainmodule: MModule, arguments: Array[String])
do
- super
var init_type = new MInitType(mainmodule.model)
initialization_value = new MutableInstance(init_type)
+ super
end
# Subtyping test for the virtual machine
recv.vtable = recv.mtype.as(MClassType).mclass.vtable
- assert(recv isa MutableInstance)
+ assert recv isa MutableInstance
recv.internal_attributes = init_internal_attributes(initialization_value, recv.mtype.as(MClassType).mclass.all_mattributes(mainmodule, none_visibility).length)
super
end
+ # Associate a `PrimitiveInstance` to its `VTable`
+ redef fun init_instance_primitive(recv: Instance)
+ do
+ if not recv.mtype.as(MClassType).mclass.loaded then create_class(recv.mtype.as(MClassType).mclass)
+
+ recv.vtable = recv.mtype.as(MClassType).mclass.vtable
+ end
+
+ # Create a virtual table for this `MClass` if not already done
+ redef fun get_primitive_class(name: String): MClass
+ do
+ var mclass = super
+
+ if not mclass.loaded then create_class(mclass)
+
+ return mclass
+ end
+
# Initialize the internal representation of an object (its attribute values)
# `init_instance` is the initial value of attributes
private fun init_internal_attributes(init_instance: Instance, size: Int): Pointer
# Creates the runtime structures for this class
fun create_class(mclass: MClass) do mclass.make_vt(self)
+ # Execute `mproperty` for a `args` (where `args[0]` is the receiver).
+ redef fun send(mproperty: MMethod, args: Array[Instance]): nullable Instance
+ do
+ var recv = args.first
+ var mtype = recv.mtype
+ var ret = send_commons(mproperty, args, mtype)
+ if ret != null then return ret
+
+ var propdef = method_dispatch(mproperty, recv.vtable.as(not null))
+
+ return self.call(propdef, args)
+ end
+
+ # Method dispatch, for a given global method `mproperty`
+ # returns the most specific local method in the class corresponding to `vtable`
+ private fun method_dispatch(mproperty: MMethod, vtable: VTable): MMethodDef
+ do
+ return method_dispatch_ph(vtable.internal_vtable, vtable.mask,
+ mproperty.intro_mclassdef.mclass.vtable.id, mproperty.offset)
+ end
+
+ # Execute a method dispatch with perfect hashing
+ private fun method_dispatch_ph(vtable: Pointer, mask: Int, id: Int, offset: Int): MMethodDef `{
+ // Perfect hashing position
+ int hv = mask & id;
+ long unsigned int *pointer = (long unsigned int*)(((long int *)vtable)[-hv]);
+
+ // pointer+2 is the position where methods are
+ // Add the offset of property and get the method implementation
+ MMethodDef propdef = (MMethodDef)*(pointer + 2 + offset);
+
+ return propdef;
+ `}
+
# Return the value of the attribute `mproperty` for the object `recv`
redef fun read_attribute(mproperty: MAttribute, recv: Instance): Instance
do
# When all super-classes have their identifiers and vtables, allocate current one
allocate_vtable(v, ids, nb_methods, nb_attributes, offset_attributes, offset_methods)
loaded = true
+
# The virtual table now needs to be filled with pointer to methods
+ superclasses.add(self)
+ for cl in superclasses do
+ fill_vtable(v, vtable.as(not null), cl)
+ end
end
# Allocate a single vtable
var self_methods = 0
var nb_introduced_attributes = 0
- # For self attributes, fixing offsets
- var relative_offset = 0
+ # Fixing offsets for self attributes and methods
+ var relative_offset_attr = 0
+ var relative_offset_meth = 0
for p in intro_mproperties(none_visibility) do
- if p isa MMethod then self_methods += 1
+ if p isa MMethod then
+ self_methods += 1
+ p.offset = relative_offset_meth
+ relative_offset_meth += 1
+ end
if p isa MAttribute then
nb_introduced_attributes += 1
- p.offset = relative_offset
- relative_offset += 1
+ p.offset = relative_offset_attr
+ relative_offset_attr += 1
end
end
vtable.internal_vtable = v.memory_manager.init_vtable(ids_total, nb_methods_total, d, vtable.mask)
end
+ # Fill the vtable with methods of `self` class
+ # `v` : Current instance of the VirtualMachine
+ # `table` : the table of self class, will be filled with its methods
+ private fun fill_vtable(v:VirtualMachine, table: VTable, cl: MClass)
+ do
+ var methods = new Array[MMethodDef]
+ for m in cl.intro_mproperties(none_visibility) do
+ if m isa MMethod then
+ # `propdef` is the most specific implementation for this MMethod
+ var propdef = m.lookup_first_definition(v.mainmodule, self.intro.bound_mtype)
+ methods.push(propdef)
+ end
+ end
+
+ # Call a method in C to put propdefs of self methods in the vtables
+ v.memory_manager.put_methods(vtable.internal_vtable, vtable.mask, cl.vtable.id, methods)
+ end
+
# Computes delta for each class
# A delta represents the offset for this group of attributes in the object
# `nb_attributes` : number of attributes for each class (classes are linearized from Object to current)
var offset: Int
end
+redef class MMethod
+ # Represents the relative offset of this attribute in the runtime instance
+ var offset: Int
+end
+
# Redef MutableInstance to improve implementation of attributes in objects
redef class MutableInstance
var internal_attributes: Pointer
end
+# Redef to associate an `Instance` to its `VTable`
+redef class Instance
+ var vtable: nullable VTable
+end
+
# Is the type of the initial value inside attributes
class MInitType
super MType
var classname: String is noinit
end
-redef class Instance
- var vtable: nullable VTable
-end
-
# Handle memory, used for allocate virtual table and associated structures
class MemoryManager
return vtable;
`}
+
+ # Put implementation of methods of a class in `vtable`
+ # `vtable` : Pointer to the C-virtual table
+ # `mask` : perfect-hashing mask of the class corresponding to the vtable
+ # `id` : id of the target class
+ # `methods` : array of MMethodDef of the target class
+ fun put_methods(vtable: Pointer, mask: Int, id: Int, methods: Array[MMethodDef])
+ import Array[MMethodDef].length, Array[MMethodDef].[] `{
+
+ // Get the area to fill with methods by a sequence of perfect hashing
+ int hv = mask & id;
+ long unsigned int *pointer = (long unsigned int*)(((long unsigned int *)vtable)[-hv]);
+
+ // pointer+2 is the beginning of the area for methods implementation
+ int length = Array_of_MMethodDef_length(methods);
+ long unsigned int *area = (pointer + 2);
+ int i;
+
+ for(i=0; i<length; i++)
+ {
+ MMethodDef method = Array_of_MMethodDef__index(methods, i);
+ area[i] = (long unsigned int)method;
+ MMethodDef_incr_ref(method);
+ }
+ `}
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
# See the License for the specific language governing permissions and
# limitations under the License.
+#alt1 import standard
+#alt1 import standard::ropes
+
var n = 7
if not args.is_empty then
n = args.first.to_i
var s = "*"
var i = 0
while i < n do
- var s2 = new FlatBuffer.from("Je dis «")
+ var s2: Buffer = new FlatBuffer.from("Je dis «")
+ #alt1 s2 = new RopeBuffer.from("Je dis «")
s2.append(s)
s2.append("» et redis «")
s2.append(s)
# See the License for the specific language governing permissions and
# limitations under the License.
+#alt1 import standard
+#alt1 import standard::ropes
+
# A procedural program (without explicit class).
fun first_word(s: String): String
do
- var result = new FlatBuffer
+ var result: Buffer = new FlatBuffer
+ #alt1 result = new RopeBuffer
var i = 0
while i < s.length and s.chars[i] != ' ' do
result.add(s.chars[i])
# It displays the value of a local variable.
# It exhibs ways to concatenate strings.
+#alt1 import standard
+#alt1 import standard::ropes
+
var a = 10
# First way: Multiple parameters.
# Pro: Simple.
# Second way: Build a string and display it.
# Pro: Eiffel way (rigourous).
# Con: Eiffel way (heavy).
-var s = new FlatBuffer.from("The value of a is: ")
+var s: Buffer = new FlatBuffer.from("The value of a is: ")
+#alt1 s = new RopeBuffer.from("The value of a is: ")
s.append(a.to_s)
s.append(".\n")
printn(s)
#!/bin/sh
-printf "%s\n" "$@" *.nit \
+printf "%s\n" "$@" \
+ ../src/nit*.nit \
+ ../src/test_*.nit \
../examples/*.nit \
../examples/*/*.nit \
../examples/shoot/src/shoot_logic.nit \
../lib/*/examples/*.nit \
../contrib/friendz/src/solver_cmd.nit \
../contrib/pep8analysis/src/pep8analysis.nit \
- ../src/nit*.nit \
- ../src/test_*.nit
+ *.nit
--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.
--- /dev/null
+1092
+1365
+147447
-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].
--- /dev/null
+The value of a is: 10.
+The value of a is: 10.
+The value of a is: 10.
+The value of a is: 10.
+The value of a is: 10.
class_module_1__A.html
class_module_1__B.html
css/
-dep_A.dot
-dep_A.map
-dep_A.png
-dep_A.s.dot
-dep_B.dot
-dep_B.map
-dep_B.png
-dep_B.s.dot
-dep_Int.dot
-dep_Int.map
-dep_Int.png
-dep_Int.s.dot
-dep_Object.dot
-dep_Object.map
-dep_Object.png
-dep_Object.s.dot
-dep_Sys.dot
-dep_Sys.map
-dep_Sys.png
-dep_Sys.s.dot
-dep_module_0.dot
-dep_module_0.map
-dep_module_0.png
-dep_module_0.s.dot
-dep_module_1.dot
-dep_module_1.map
-dep_module_1.png
-dep_module_1.s.dot
+dep_class_module_0__Int.dot
+dep_class_module_0__Int.map
+dep_class_module_0__Int.png
+dep_class_module_0__Int.s.dot
+dep_class_module_0__Object.dot
+dep_class_module_0__Object.map
+dep_class_module_0__Object.png
+dep_class_module_0__Object.s.dot
+dep_class_module_0__Sys.dot
+dep_class_module_0__Sys.map
+dep_class_module_0__Sys.png
+dep_class_module_0__Sys.s.dot
+dep_class_module_1__A.dot
+dep_class_module_1__A.map
+dep_class_module_1__A.png
+dep_class_module_1__A.s.dot
+dep_class_module_1__B.dot
+dep_class_module_1__B.map
+dep_class_module_1__B.png
+dep_class_module_1__B.s.dot
+dep_module_module_0__module_0__module_0.dot
+dep_module_module_0__module_0__module_0.map
+dep_module_module_0__module_0__module_0.png
+dep_module_module_0__module_0__module_0.s.dot
+dep_module_module_1__module_1__module_1.dot
+dep_module_module_1__module_1__module_1.map
+dep_module_module_1__module_1__module_1.png
+dep_module_module_1__module_1__module_1.s.dot
group_module_0__module_0.html
group_module_1__module_1.html
index.html
+++ /dev/null
-Compilation error
+++ /dev/null
-Compilation error
+++ /dev/null
-Compilation error
+++ /dev/null
-Compilation error
+++ /dev/null
-Compilation error
+++ /dev/null
-Compilation error
+++ /dev/null
-Compilation error
+++ /dev/null
-Compilation error
+++ /dev/null
-Compilation error
+++ /dev/null
-Compilation error
+++ /dev/null
-Compilation error
+++ /dev/null
-Compilation error
Total size of tables (classes and instances): 38 (not including stuff like info for subtyping or call-next-method)
Average size of table by runtime class: 6.33
Values never redefined: 32 (84.21%)
-generating out/nitmetrics_args1.write/project_hierarchy.dot
-generating out/nitmetrics_args1.write/module_hierarchy.dot
+generating project_hierarchy.dot
+generating module_hierarchy.dot
# Inheritance metrics
test_test_nitunit.nit:36,2--40,4: ERROR: test_foo1 (in file .nitunit/test_test_nitunit_TestX_test_foo1.nit): Runtime error: Assert failed (test_test_nitunit.nit:39)
-Results saved in out/nitunit_args1.write
-
DocUnits:
Entities: 27; Documented ones: 3; With nitunits: 3; Failures: 2
eab
f.c
dgh
-Solved, after looking at 14 positions during 0.0s
+Solved, after looking at 14 positions
Solution in 10 moves: right(>) down(v) left(<) left(<) up(^) right(>) right(>) up(^) left(<) left(<)
+++ /dev/null
-digraph g {
-[label = 6];
- -> [label = "left"];
-[label = "AB" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = AB"];
- -> [label = "right"];
-[label = 4];
- -> [label = "left"];
-[label = "CD" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = CD"];
- -> [label = "right"];
-[label = "EF" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = EF"];
-}
-
-ABCDEF
-digraph g {
-[label = 6];
- -> [label = "left"];
-[label = 4];
- -> [label = "left"];
-[label = "AB" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = AB"];
- -> [label = "right"];
-[label = "CD" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = CD"];
- -> [label = "right"];
-[label = "EF" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = EF"];
-}
-
-ABCDEF
-ABCDEFGH
-digraph g {
-[label = 8];
- -> [label = "left"];
-[label = 6];
- -> [label = "left"];
-[label = 4];
- -> [label = "left"];
-[label = "AB" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = AB"];
- -> [label = "right"];
-[label = "CD" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = CD"];
- -> [label = "right"];
-[label = "EF" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = EF"];
- -> [label = "right"];
-[label = "GH" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = GH"];
-}
-
-ABCDEFGH
-digraph g {
-[label = 8];
- -> [label = "left"];
-[label = "AB" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = AB"];
- -> [label = "right"];
-[label = 6];
- -> [label = "left"];
-[label = 4];
- -> [label = "left"];
-[label = "CD" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = CD"];
- -> [label = "right"];
-[label = "EF" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = EF"];
- -> [label = "right"];
-[label = "GH" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = GH"];
-}
-
-ABCDEFGH
-digraph g {
-[label = 8];
- -> [label = "left"];
-[label = "AB" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = AB"];
- -> [label = "right"];
-[label = 6];
- -> [label = "left"];
-[label = "CD" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = CD"];
- -> [label = "right"];
-[label = 4];
- -> [label = "left"];
-[label = "EF" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = EF"];
- -> [label = "right"];
-[label = "GH" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = GH"];
-}
-
-ABCDEFGH
-digraph g {
-[label = 8];
- -> [label = "left"];
-[label = 6];
- -> [label = "left"];
-[label = "AB" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = AB"];
- -> [label = "right"];
-[label = 4];
- -> [label = "left"];
-[label = "CD" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = CD"];
- -> [label = "right"];
-[label = "EF" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = EF"];
- -> [label = "right"];
-[label = "GH" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = GH"];
-}
-
-ABCDEFGH
-digraph g {
-[label = 8];
- -> [label = "left"];
-[label = 6];
- -> [label = "left"];
-[label = "AB" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = AB"];
- -> [label = "right"];
-[label = 4];
- -> [label = "left"];
-[label = "CD" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = CD"];
- -> [label = "right"];
-[label = "EF" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = EF"];
- -> [label = "right"];
-[label = "GH" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = GH"];
-}
-
-ABCDEFGH
-digraph g {
-[label = 8];
- -> [label = "left"];
-[label = 4];
- -> [label = "left"];
-[label = "AB" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = AB"];
- -> [label = "right"];
-[label = "CD" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = CD"];
- -> [label = "right"];
-[label = 4];
- -> [label = "left"];
-[label = "EF" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = EF"];
- -> [label = "right"];
-[label = "GH" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = GH"];
-}
-
-ABCDEFGH
-digraph g {
-[label = 8];
- -> [label = "left"];
-[label = "AB" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = AB"];
- -> [label = "right"];
-[label = 6];
- -> [label = "left"];
-[label = 4];
- -> [label = "left"];
-[label = "CD" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = CD"];
- -> [label = "right"];
-[label = "EF" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = EF"];
- -> [label = "right"];
-[label = "GH" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = GH"];
-}
-
-ABCDEFGH
-digraph g {
-[label = 8];
- -> [label = "left"];
-[label = 4];
- -> [label = "left"];
-[label = "AB" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = AB"];
- -> [label = "right"];
-[label = "CD" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = CD"];
- -> [label = "right"];
-[label = 4];
- -> [label = "left"];
-[label = "EF" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = EF"];
- -> [label = "right"];
-[label = "GH" shape = rect];
- -> [label = "contains"];
- [label="FlatString\nindex_from = 0\nindex_to = 1\nNativeString = GH"];
-}
-
--- /dev/null
+resulttrim = nono nono
+returntrim + nono nono
+thirdtrim = nono nono
+emptytrim =
+bufferemptytrim =
+onelettertrim = d
+oneletterbuftest = d
+twolettertrim = hg
+twoletterbuftest = hg
+firstlettertrimtest = d
+firstlettertrimbuftest = d
+lastlettertrimtest = d
+lastlettertrimbuftest = d
--- /dev/null
+Hello from `a`.
--- /dev/null
+Hello from `a`.
+Hello from `b`.
--- /dev/null
+Hello from `a`.
--- /dev/null
+Hello from `a`.
+Hello from `b`.
-Runtime error: Cast failed. Expected `E`, got `Bool` (../lib/standard/collection/array.nit:778)
+Runtime error: Cast failed. Expected `E`, got `Bool` (../lib/standard/collection/array.nit:789)
NativeString
N
Nit
now step live...
live...
.
- live stepnow
...evil pets won
n
now step live... step live...
+++ /dev/null
-NODEATTEST
-INZZ
-INDDZZ
-EEINDDZZ
-EEINDDZZFF
-eeinddzzff
-EEINDDZZFF
-FFZZDDNIEE
-hello_world.types.1.o
-now step live...
-...evil pets won
-now step live...
-now step live...
- live...
-.
- live stepnow
-...evil pets won
-n
-now step live... step live...
-w s
-ZZ
-ZZZZZZZZZZ
-ZZAAZZZZZZZZ
-NNZZAAZZZZZZZZ
-NIINZZAAZZZZZZZZ
-NINIINZZAAZZZZZZZZINZZAAZZZZZZZZ
+++ /dev/null
-NODEATTEST
-INZZ
-INDDZZ
-EEINDDZZ
-EEINDDZZFF
-eeinddzzff
-EEINDDZZFF
-FFZZDDNIEE
-hello_world.types.1.o
-now step live...
-...evil pets won
-now step live...
-now step live...
- live...
-.
-now step live
-...evil pets won
-n
-now step live... step live...
-w s
-ZZ
-ZZZZZZZZZZ
-ZZAAZZZZZZZZ
-NNZZAAZZZZZZZZ
-NIINZZAAZZZZZZZZ
-NINIINZZAAZZZZZZZZINZZAAZZZZZZZZ
--- /dev/null
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
+Bonjour !
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
fun nsieve(n: Int): Int
do
var count = 0
- var array = new FlatBuffer.with_capacity(n)
+ var array: Buffer = new FlatBuffer.with_capacity(n)
for i in [0..n[ do
array.chars[i] = 'o'
end
+++ /dev/null
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# This file is free software, which comes along with NIT. This software is
-# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE. You can modify it is you want, provided this header
-# is kept unaltered, and a notification of the changes is added.
-# You are allowed to redistribute it and sell it, alone or is a part of
-# another product.
-
-intrude import splay_ropes
-intrude import standard::ropes
-intrude import ropes_debug
-
-redef class Leaf
- redef fun to_dot(s): String
- do
- s += "[label = \"{str}\" shape = rect];\n"
- s += " -> [label = \"contains\"];\n"
- s = str.to_dot(s)
- return s
- end
-end
-
-redef class Concat
- redef fun to_dot(s): String
- do
- s += "[label = {length}];\n"
- if left != null then
- s += " -> [label = \"left\"];\n"
- s = left.to_dot(s)
- end
- if right != null then
- s += " -> [label = \"right\"];\n"
- s = right.to_dot(s)
- end
- return s
- end
-end
-
-redef class FlatString
- redef fun to_dot(s: String): String
- do
- return s + " [label=\"FlatString\\nindex_from = {index_from}\\nindex_to = {index_to}\\nNativeString = {items.to_s_with_length(items.cstring_length)}\"];\n"
- end
-end
-
-redef class FlatBuffer
- redef fun to_dot(s: String): String
- do
- return s + " [label=\"FlatBuffer\\length = {length}\\ncapacity = {capacity}\\nitems = {items.to_s_with_length(items.cstring_length)}\"];\n"
- end
-end
-
-
-redef class RopeString
-
- redef fun to_dot(f)
- do
- var ret: String = new RopeString.from("digraph g \{\n")
- ret = root.to_dot(ret).as(RopeString)
- ret += "\}\n"
- print ret
- return ret
- end
-
-end
-
-var ab = new StringLeaf("AB".as(FlatString))
-var cd = new StringLeaf("CD".as(FlatString))
-var ef = new StringLeaf("EF".as(FlatString))
-var gh = new StringLeaf("GH".as(FlatString))
-
-# Zig test
-
-var c = new Concat(cd,ef)
-c = new Concat(ab,c)
-var ro = new RopeString.from_root(c)
-
-ro.to_dot("Zig-Before_splay.dot")
-print ro
-
-var p = ro.node_at(5)
-
-ro = new RopeString.from_root(ro.splay(p).as(not null))
-
-ro.to_dot("Zig-After_splay.dot")
-print ro
-
-# Zig-zig test left left
-
-var d = new Concat(ab,cd)
-var e = new Concat(d,ef)
-var f = new Concat(e,gh)
-ro = new RopeString.from_root(f)
-
-p = ro.node_at(0)
-
-print ro
-ro.to_dot("Zig-zigll-Before_splay.dot")
-
-ro = new RopeString.from_root(ro.splay(p).as(not null))
-
-print ro
-ro.to_dot("Zig-zigll-After_splay.dot")
-
-# Zig-zig test right right
-
-d = new Concat(ef,gh)
-e = new Concat(cd,d)
-f = new Concat(ab,e)
-ro = new RopeString.from_root(f)
-
-p = ro.node_at(7)
-
-print ro
-ro.to_dot("Zig-zigrr-Before_splay.dot")
-
-ro = new RopeString.from_root(ro.splay(p).as(not null))
-
-print ro
-ro.to_dot("Zig-zigrr-After_splay.dot")
-
-# Zig-zag test left right
-
-d = new Concat(cd,ef)
-e = new Concat(ab,d)
-f = new Concat(e,gh)
-ro = new RopeString.from_root(f)
-
-p = ro.node_at(4)
-
-print ro
-ro.to_dot("Zig-zaglr-Before_splay.dot")
-
-ro = new RopeString.from_root(ro.splay(p).as(not null))
-
-print ro
-ro.to_dot("Zig-zaglr-After_splay.dot")
-
-# Zig-zag test right left
-
-d = new Concat(cd,ef)
-e = new Concat(d,gh)
-f = new Concat(ab,e)
-ro = new RopeString.from_root(f)
-
-p = ro.node_at(4)
-
-print ro
-ro.to_dot("Zig-zagrl-Before_splay.dot")
-
-ro = new RopeString.from_root(ro.splay(p).as(not null))
-
-print ro
-ro.to_dot("Zig-zagrl-After_splay.dot")
-
-module string_trim
+#alt1 import standard::ropes
+#alt1 import standard
var trimtest = " \t nono nono \n \t"
var subtrim = trimtest.substring(2,15)
-var buffertrimtest = new FlatBuffer.from(trimtest)
+var buffertrimtest: Buffer = new FlatBuffer.from(trimtest)
+#alt1 buffertrimtest = new RopeBuffer.from(trimtest)
print "resulttrim = {buffertrimtest.trim}"
var emptytrim = " \t "
-var bufferemptytest = new FlatBuffer.from(emptytrim)
+var bufferemptytest: Buffer = new FlatBuffer.from(emptytrim)
+#alt1 bufferemptytest = new RopeBuffer.from(emptytrim)
print "emptytrim = {emptytrim.trim}"
var onelettertrim = " \n d \n\t "
-var oneletterbuftest = new FlatBuffer.from(onelettertrim)
+var oneletterbuftest: Buffer = new FlatBuffer.from(onelettertrim)
+#alt1 oneletterbuftest = new RopeBuffer.from(onelettertrim)
print "onelettertrim = {onelettertrim.trim}"
var twolettertrim = " \n hg \n\t "
-var twoletterbuftest = new FlatBuffer.from(twolettertrim)
+var twoletterbuftest: Buffer = new FlatBuffer.from(twolettertrim)
+#alt1 twoletterbuftest = new RopeBuffer.from(twolettertrim)
print "twolettertrim = {twolettertrim.trim}"
var firstlettertrim = "d "
-var firstlettertrimbuf = new FlatBuffer.from(firstlettertrim)
+var firstlettertrimbuf: Buffer = new FlatBuffer.from(firstlettertrim)
+#alt1 firstlettertrimbuf = new RopeBuffer.from(firstlettertrim)
print "firstlettertrimtest = {firstlettertrim.trim}"
var lastlettertrim = " d"
-var lastlettertrimbuf = new FlatBuffer.from(lastlettertrim)
+var lastlettertrimbuf: Buffer = new FlatBuffer.from(lastlettertrim)
+#alt1 lastlettertrimbuf = new RopeBuffer.from(lastlettertrim)
print "lastlettertrimtest = {lastlettertrim.trim}"
# See the License for the specific language governing permissions and
# limitations under the License.
-var rp: String = new RopeString.from("xxx")
-rp += "yyy"
+import standard
+intrude import standard::ropes
+
+var rp: String = new Concat("xxx", "yyy")
rp += "zzz"
var arr = ["FlatString", rp]
print arr.to_s
--- /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.
+
+`{
+ #include <stdio.h>
+`}
+
+fun print_a(str: String) import String.to_cstring `{
+ puts(String_to_cstring(str));
+`}
+
+print_a "Hello from `a`."
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import test_ffi_c_duplicated_callback_a
+
+`{
+ #include <stdio.h>
+`}
+
+fun print_b(str: String) import String.to_cstring `{
+ puts(String_to_cstring(str));
+`}
+
+print_a "Hello from `a`."
+print_b "Hello from `b`."
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+in "C++ Header" `{
+ #include <stdio.h>
+`}
+
+fun print_a(str: String) import String.to_cstring in "C++" `{
+ puts(String_to_cstring(str));
+`}
+
+print_a "Hello from `a`."
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import test_ffi_cpp_duplicated_callback_a
+
+in "C++ header" `{
+ #include <stdio.h>
+`}
+
+fun print_b(str: String) import String.to_cstring in "C++" `{
+ puts(String_to_cstring(str));
+`}
+
+print_a "Hello from `a`."
+print_b "Hello from `b`."
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import java
+
+# Called method
+fun foo import String.output in "Java" `{
+`}
+
+# Dead method
+fun bar import Text.output in "Java" `{
+`}
+
+foo
# See the License for the specific language governing permissions and
# limitations under the License.
-#alt1 import splay_ropes
-#alt2 import bufferized_ropes
+#alt1 import standard
+#alt1 import buffered_ropes
var st = "quick brown fox over the lazy dog"
# See the License for the specific language governing permissions and
# limitations under the License.
-#alt1 import splay_ropes
-#alt2 import bufferized_ropes
+import standard
+intrude import standard::ropes
-var x :String = new RopeString
+# Force building a Rope
+redef fun maxlen: Int do return once 2
-x = x + "NODE"
-x = x + "AT"
-x = x + "TEST"
+var x :String = new Concat("NODE", "AT")
+
+x += "TEST"
print x
var lst = new List[String]
-lst.push(new RopeString.from("ZZ"))
+lst.push("ZZ")
lst.push((lst.last * 5))
print ss
-ss = ss.as(RopeString).insert_at("DD", 2)
+ss = ss.insert_at("DD", 2)
print ss
var atb = new Array[String]
-var s: String = new RopeString
-s = s + "./examples/hello_world.nit".substring(11,11) + ".types"
+var s: String = "./examples/hello_world.nit".substring(11,11) + ".types"
s += "."
s += "1"
s += ".o"
print s
-var str = new RopeString.from("now") + " step" + " live..."
+var str = "now" + " step" + " live..."
print str
for i in str.chars.iterator_from(str.length-1) do printn i
printn "\n"
-for i in str.as(RopeString).reverse_substrings_from(12) do printn i
-printn "\n"
-
for i in str.chars.reverse_iterator do printn i
printn "\n"
for i in str.chars.reverse_iterator_from(0) do printn i
printn "\n"
-var str2 = str.as(RopeString).insert_at(str.substring_from(3), 3)
+var str2 = str.insert_at(str.substring_from(3), 3)
print str2
# See the License for the specific language governing permissions and
# limitations under the License.
+#alt1 import standard
+#alt1 import standard::ropes
var s = "Bonjour !\n"
-var r = new FlatBuffer.with_capacity(50)
-var r2 = new FlatBuffer
+var r: Buffer = new FlatBuffer.with_capacity(50)
+#alt1 r = new RopeBuffer
+var r2: Buffer = new FlatBuffer
+#alt1 r2 = new RopeBuffer
var i = 0
while i < 5000 do
# See the License for the specific language governing permissions and
# limitations under the License.
-#alt3 import bufferized_ropes
+#alt2 import standard
+#alt2 import buffered_ropes
var str = "Woe to you, oh earth and sea for the Devil sends the beast with wrath because he knows the time is short. Let him who hath understanding reckon the number of the beast, for it is a human number, its number is Six Hundred and Sixty-Six."
var spaces = " "
#alt1 trimable.append(spaces)
#alt1 num = new FlatBuffer.from(numstr)
-#alt2 txt = new RopeString.from(str)
-#alt2 trimable = new RopeString.from(spaces)
-#alt2 trimable = trimable + str
-#alt2 trimable = trimable + spaces
-#alt2 num = new RopeString.from(numstr)
-
-#alt3 txt = new RopeString.from(str)
-#alt3 trimable = new RopeString.from(spaces)
-#alt3 trimable = trimable + str
-#alt3 trimable = trimable + spaces
-#alt3 num = new RopeString.from(numstr)
+#alt3 txt = new RopeBuffer.from(str)
+#alt3 trimable = new RopeBuffer.from(spaces)
+#alt3 trimable.append(str)
+#alt3 trimable.append(spaces)
+#alt3 num = new RopeBuffer.from(numstr)
# Test Text methods on all types of receivers
# See the License for the specific language governing permissions and
# limitations under the License.
-var x = new FlatBuffer.from("test")
-var y = new FlatBuffer.from("TEST")
+#alt1 import standard::ropes
+
+var x: Buffer = new FlatBuffer.from("test")
+#alt1 x = new RopeBuffer.from("test")
+var y: Buffer = new FlatBuffer.from("TEST")
+#alt1 y = new RopeBuffer.from("TEST")
x.upper
y.lower
if [ "x$XMLDIR" = "x" ]; then
xml="tests-$engine.xml"
else
- xml="$XMLDIR/tests-$engine.xml"
+ sum=`echo $@ | md5sum | cut -f1 -d " "`
+ xml="$XMLDIR/tests-$engine-$sum.xml"
+ mkdir -p "$XMLDIR"
fi
echo >$xml "<testsuites><testsuite>"
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"