Merge: Ropefix
authorJean Privat <jean@pryen.org>
Fri, 30 Jan 2015 02:01:18 +0000 (09:01 +0700)
committerJean Privat <jean@pryen.org>
Fri, 30 Jan 2015 02:01:18 +0000 (09:01 +0700)
A few modifications to ropes, I discovered that the `+` routine used to create too many Concat nodes passed a certain point, which inceased the RAM use of Strings unnecessarily (might help with #1106's example program, on my machine the memory went from 200M+ used to 20M).

While I was at it, I removed a few old-style-inits that were no longer necessary.

Some others however I could not remove, maybe there is a way I can do so, but with the spec of the new constructors I'm not entirely sure how to do so without retaining unnneeded information or complexifying instanciation, that'll have to wait.

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

98 files changed:
.gitignore
benchmarks/markdown/README.md [new file with mode: 0644]
benchmarks/markdown/bench_markdown.sh [new file with mode: 0755]
benchmarks/markdown/benches/Makefile [new file with mode: 0644]
benchmarks/markdown/benches/gen_benches.nit [new file with mode: 0644]
benchmarks/markdown/benches/hello.md [new file with mode: 0644]
benchmarks/markdown/benches/plain.md [new file with mode: 0644]
benchmarks/markdown/engines/Makefile [new file with mode: 0644]
benchmarks/markdown/engines/markdown4j/Makefile [new file with mode: 0644]
benchmarks/markdown/engines/markdown4j/Markdown4j.java [new file with mode: 0644]
benchmarks/markdown/engines/nitmd/Makefile [new file with mode: 0644]
benchmarks/markdown/engines/nitmd/nitmd.nit [new file with mode: 0644]
benchmarks/markdown/engines/txtmark/Makefile [new file with mode: 0644]
benchmarks/markdown/engines/txtmark/Txtmark.java [new file with mode: 0644]
contrib/jwrapper/src/code_generator.nit
contrib/jwrapper/src/javap_visitor.nit
contrib/jwrapper/src/model.nit
contrib/nitiwiki/src/wiki_html.nit
contrib/nitiwiki/tests/res/nitiwiki_render.res
contrib/nitiwiki/tests/res/nitiwiki_status.res
contrib/pep8analysis/src/pep8analysis_web.nit
examples/calculator/Makefile
examples/calculator/src/calculator_gtk.nit
examples/calculator/src/calculator_logic.nit
examples/mnit_simple/assets/testsound.ogg [moved from examples/mnit_simple/assets/sound.ogg with 100% similarity]
examples/mnit_simple/res/raw/testsound.ogg [moved from examples/mnit_simple/res/raw/sound.ogg with 100% similarity]
examples/mnit_simple/res/values/dimens.xml
examples/mnit_simple/src/test_audio.nit
examples/rosettacode/doors_with_classes.nit [new file with mode: 0644]
lib/android/assets_and_resources.nit
lib/android/audio.nit
lib/android/aware.nit [new file with mode: 0644]
lib/android/input_events.nit
lib/android/log.nit
lib/android/native_app_glue.nit
lib/android/platform.nit
lib/android/ui.nit
lib/app/audio.nit [new file with mode: 0644]
lib/c.nit
lib/cocoa/app_kit.nit
lib/cocoa/cocoa.nit
lib/cocoa/foundation.nit
lib/cpp.nit
lib/egl.nit
lib/github/api.nit
lib/github/cache.nit [new file with mode: 0644]
lib/github/events.nit [new file with mode: 0644]
lib/github/github.nit
lib/github/hooks.nit [new file with mode: 0644]
lib/glesv2/glesv2.nit
lib/gtk/v3_4/gtk_core.nit
lib/java/java.nit
lib/jvm.nit
lib/mnit_android/android_assets.nit
lib/mnit_android/android_opengles1.nit
lib/mnit_input.nit
lib/more_collections.nit
lib/mpi.nit
lib/pthreads/extra.nit
lib/pthreads/pthreads.nit
lib/realtime.nit
lib/sdl.nit
lib/sdl2/image.nit
share/libgc/.gitignore [new file with mode: 0644]
share/libgc/android-setup-libgc.sh [new file with mode: 0755]
src/c_tools.nit
src/changelog.sh
src/compiler/abstract_compiler.nit
src/compiler/compiler_ffi.nit
src/ffi/c.nit
src/ffi/c_compiler_options.nit
src/ffi/cpp.nit
src/ffi/ffi.nit
src/ffi/java.nit
src/ffi/objc.nit
src/frontend/check_annotation.nit
src/interpreter/naive_interpreter.nit
src/nit.nit
src/nitvm.nit
src/platform/android.nit
src/platform/emscripten.nit
src/platform/platform.nit
src/platform/pnacl.nit
src/semantize/typing.nit
src/vm.nit
src/vm_optimizations.nit [new file with mode: 0644]
tests/base_attr_init_val_block.nit
tests/error_annot_c_compiler.nit
tests/sav/base_attr_init_val_block_alt1.res [new file with mode: 0644]
tests/sav/base_attr_init_val_block_alt2.res [new file with mode: 0644]
tests/sav/doors_with_classes.res [new file with mode: 0644]
tests/sav/error_annot_c_compiler_alt1.res
tests/sav/error_annot_c_compiler_alt2.res
tests/sav/error_annot_c_compiler_alt3.res
tests/sav/error_annot_c_compiler_alt4.res
tests/sav/error_annot_c_compiler_alt5.res
tests/sav/error_annot_c_compiler_alt6.res
tests/test_annot_c_compiler.nit

index 5cd49a0..2156619 100644 (file)
@@ -55,3 +55,4 @@ nitunit.xml
 *.stub.nit.[ch]
 
 .metadata/*
+.github_data
diff --git a/benchmarks/markdown/README.md b/benchmarks/markdown/README.md
new file mode 100644 (file)
index 0000000..a739cd8
--- /dev/null
@@ -0,0 +1,79 @@
+# Bench Markdown
+
+Benches markdown parsers.
+
+## Usage
+
+    ./bench_markdown.sh all
+
+## Engines
+
+* nitmd
+* txtmark 0.11 (https://github.com/rjeschke/txtmark)
+* markdown4j 2.2 (https://code.google.com/p/markdown4j/)
+
+## Benches
+
+Benches are inspired from the [Henkelmann's Actuarius benches](http://henkelmann.eu/2011/01/10/performance_comparison_of_markdown_processor_for_the_jvm).
+
+Benches are variations of the same text generate from `benches/plain.md`
+This text is De finibus bonorum et malorum which is said to be the basis for
+the commonly used Lorem Ipsum test text.
+
+The generator rudely chops it up in a configurable number of paragraphs,
+lines per paragraph and approximate chars per line.
+Depending on the variation, it “decorates” parts of the text with Markdown syntax.
+All tests consist of 30 Paragraphs with 20 lines each and approx. 80 chars per line (before “decoration”).
+
+Here are the descriptions of the variations:
+
+* Plain Paragraphs: No modifications, just the plain text.
+
+* Emphasis: Every word emphasized,
+
+  so the input `foo` is decorated as `*foo*` which should render as `<em>foo</em>`
+
+* Strong: Every word emphasized,
+
+  `foo` → `**foo**` → `<strong>foo</strong>`
+
+* Inline Code: Every word marked as inline code:
+
+  `foo` → ````foo```` → `<code>foo</code>`
+
+* Fast Links: Every word a link without title or wrapped text:
+
+  `foo` → `<foo>` → `<a href="foo">foo</a>`
+
+* Special XML Chars: Every word is replaced by chars that need to be escaped in XML:
+
+  `foo` → `"><&` → `&quot;&gt;&lt;'&amp;`
+
+* Inline HTML: Every word is wrapped in verbatim HTML:
+
+  `foo` → `<blink>foo</blink>` → `<blink>foo</blink>`
+
+* Manual Line Breaks: Every line gets appended with `\n`:
+
+  `some line` → `some line\n` → `some line<br/>\n`
+
+* Full Links: Every word is turned into a link with wrapped text, url and title:
+
+  `foo` → `[foo](http://example.com/foo "foo Title")` → `<a href="http://example.com/foo" title="foo Title">foo</a>`
+
+* Full Images: Like full links, every word turned into an image reference
+
+* Reference Links: Every word is turned into a link reference with an increasing id counter.
+  The link reference definition is added after the paragraph the link occurs in:
+
+  `foo` → `[foo][id123]` → `<a href="http://example.com/foo" title="foo Title">foo</a>`
+
+* Block Quotes: Every paragraph is turned into a block quote by prepending a `>` to each line.
+
+* Code Blocks: Every paragraph is turned into a code block by prepending four spaces to each line.
+
+* Unordered Lists: Every paragraph is turned into a list with an item for each line by prepending `*` to each line.
+
+* Mixed Test: A mix of all of the above: Some paragraphs lists, some code, some word emphasized etc.
+
+Variation details can be found in `benches/gen_bench.nit`.
diff --git a/benchmarks/markdown/bench_markdown.sh b/benchmarks/markdown/bench_markdown.sh
new file mode 100755 (executable)
index 0000000..4cb0f15
--- /dev/null
@@ -0,0 +1,123 @@
+#!/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.
+
+# Shell script to bench nitmd over different kind of document.
+
+source ../bench_common.sh
+source ../bench_plot.sh
+
+## CONFIGURATION OPTIONS ##
+
+# Default number of times a command must be run with bench_command
+# Can be overrided with 'the option -n'
+count=2
+
+### HELPER FUNCTIONS ##
+
+function die()
+{
+       echo >&2 "error: $*"
+       died=1
+}
+
+## HANDLE OPTIONS ##
+
+function usage()
+{
+       echo "run_bench: [options]* benchname"
+       echo "  -v: verbose mode"
+       echo "  -n count: number of execution for each bar (default: $count)"
+       echo "  --dry: Do not run the commands, just reuse the data and generate the graph"
+       echo "  -h: this help"
+}
+
+stop=false
+while [ "$stop" = false ]; do
+       case "$1" in
+               -v) verbose=true; shift;;
+               -h) usage; exit;;
+               -n) count="$2"; shift; shift;;
+               --dry) dry_run=true; shift;;
+               *) stop=true
+       esac
+done
+
+## GEN BENCHES
+cd benches; make; cd ..
+
+## COMPILE ENGINES
+cd engines; make; cd ..
+
+NOTSKIPED="$*"
+
+if test -z "$NOTSKIPED"; then
+       usage
+       echo "List of available benches:"
+       echo "* all: run all the benches"
+fi
+
+## EFFECTIVE BENCHS ##
+outdir="./out"
+engdir="./engines"
+bncdir="./benches/out"
+mkdir -p $outdir
+
+s=50
+
+function bench_nitmd()
+{
+       name="$FUNCNAME"
+       skip_test "$name" && return
+       prepare_res $outdir/nitmd.dat "nitmd" "nitmd"
+       for file in $bncdir/*.md; do
+               bench=`basename $file .md`
+               bench_command "$bench" "" "$engdir/nitmd/nitmd" "$file" "$s"
+       done
+}
+bench_nitmd
+
+function bench_txtmark()
+{
+       name="$FUNCNAME"
+       skip_test "$name" && return
+       prepare_res $outdir/txtmark.dat "txtmark" "txtmark"
+       for file in $bncdir/*.md; do
+               bench=`basename $file .md`
+               bench_command "$bench" "" "java" "-cp" "$engdir/txtmark/.:$engdir/txtmark/txtmark-0.11.jar" "Txtmark" "$file" "$s"
+       done
+}
+bench_txtmark
+
+function bench_markdown4j()
+{
+       name="$FUNCNAME"
+       skip_test "$name" && return
+       prepare_res $outdir/markdown4j.dat "markdown4j" "markdown4j"
+       for file in $bncdir/*.md; do
+               name=`basename $file .md`
+               bench_command "$bench" "" "java" "-cp" "$engdir/markdown4j/.:$engdir/markdown4j/markdown4j-2.2.jar" "Markdown4j" "$file" "$s"
+       done
+}
+bench_markdown4j
+
+if test "$#" -gt 0; then
+    plot $outdir/bench_markdown.gnu
+fi
+
+if test -n "$died"; then
+       echo "Some commands failed"
+       exit 1
+fi
+exit 0
diff --git a/benchmarks/markdown/benches/Makefile b/benchmarks/markdown/benches/Makefile
new file mode 100644 (file)
index 0000000..641c47e
--- /dev/null
@@ -0,0 +1,31 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2015 Alexandre Terrasa <alexandre@moz-code.org>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+all: out
+
+gen_benches:
+       nitc gen_benches.nit
+
+out: gen_benches
+       ./gen_benches ./plain.md -o ./out
+
+test: gen_benches
+       ./gen_benches ./hello.md -o ./test
+
+clean:
+       rm -rf gen_benches
+       rm -rf out
+       rm -rf test
diff --git a/benchmarks/markdown/benches/gen_benches.nit b/benchmarks/markdown/benches/gen_benches.nit
new file mode 100644 (file)
index 0000000..4d974a6
--- /dev/null
@@ -0,0 +1,291 @@
+# 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.
+
+# Generate bench suites for markdown parsers.
+module gen_benches
+
+import opts
+
+# Decorate a markdown plain text for bench puposes.
+#
+# *This is not the markdown you are looking for.*
+interface MarkdownDecorator
+
+       # Parse the text and decorate it.
+       # Behavior depends on `LineDecorator` and `WordDecorator`.
+       fun decorate_text(txt: Text): Text is abstract
+
+       # Is `c` a something else than a letter a digit or a `-`?
+       fun is_word_break(c: Char): Bool do
+               return not (c.is_letter or c.is_digit or c == '-')
+       end
+
+       # Parses the next word from `pos` and return the ending position.
+       # Returns `-1` if next word is a word break symbol or there is no more text.
+       private fun parse_word(txt: Text, pos: Int, res: FlatBuffer): Int do
+               while pos >= 0 and pos < txt.length do
+                       var c = txt[pos]
+                       if is_word_break(c) then break
+                       res.add c
+                       pos += 1
+               end
+               return pos
+       end
+end
+
+# Break text in lines of ~80 chars and call `decorate_line` for each.
+abstract class LineDecorator
+       super MarkdownDecorator
+
+       redef fun decorate_text(txt) do return decorate_lines(txt)
+
+       private fun decorate_lines(txt: Text): Text do
+               var pos = 0
+               var res = new FlatBuffer
+               var line = new FlatBuffer
+               var word = new FlatBuffer
+               while pos < txt.length do
+                       var c = txt[pos]
+                       if is_word_break(c) then
+                               pos += 1
+                               line.add c
+                               if c == '\n' then
+                                       res.append decorate_line(line)
+                                       line.clear
+                               end
+                       else
+                               pos = parse_word(txt, pos, word)
+                               if line.length + word.length > 80 then
+                                       res.append decorate_line(line)
+                                       line.clear
+                               end
+                               line.append word
+                               word.clear
+                       end
+               end
+               return res
+       end
+
+       # Returns the decorated version of `line`.
+       fun decorate_line(line: Text): Text is abstract
+end
+
+# Add a `\n` after each line.
+class ManualBreakDecorator
+       super LineDecorator
+
+       redef fun decorate_line(line) do return "{line}\n"
+end
+
+# Add a `> ` before each line.
+class BlockQuoteDecorator
+       super ManualBreakDecorator
+
+       redef fun decorate_line(line) do return super("> {line}")
+end
+
+# Add four spaces before each line.
+class CodeBlockDecorator
+       super ManualBreakDecorator
+
+       redef fun decorate_line(line) do return super("    {line}")
+end
+
+# Add "* " before each line.
+class UnorderedListDecorator
+       super ManualBreakDecorator
+
+       redef fun decorate_line(line) do return super("* {line}")
+end
+
+
+# WordDecorator is used to decorate each word of a text.
+abstract class WordDecorator
+       super MarkdownDecorator
+
+       redef fun decorate_text(txt): Text do return decorate_words(txt)
+
+       private fun decorate_words(txt: Text): Text do
+               var pos = 0
+               var res = new FlatBuffer
+               var tmp = new FlatBuffer
+               while pos < txt.length do
+                       var c = txt[pos]
+                       if is_word_break(c) then
+                               pos += 1
+                               res.add c
+                       else
+                               pos = parse_word(txt, pos, tmp)
+                               res.append decorate_word(tmp)
+                               tmp.clear
+                       end
+               end
+               return res
+       end
+
+       # Returns the decorated version of `word`.
+       fun decorate_word(word: Text): Text is abstract
+end
+
+# Returns the word as this.
+class PlainDecorator
+       super WordDecorator
+
+       redef fun decorate_word(word) do return word
+end
+
+# Wraps the word with `*empthasis*`.
+class EmphasisDecorator
+       super WordDecorator
+
+       redef fun decorate_word(w) do return "*{w}*"
+end
+
+# Wraps the word with `**strong**`.
+class StrongDecorator
+       super WordDecorator
+
+       redef fun decorate_word(w) do return "**{w}**"
+end
+
+# Wraps the word with ````inline code````.
+class InlineCodeDecorator
+       super WordDecorator
+
+       redef fun decorate_word(w) do return "`{w}`"
+end
+
+# Wraps the word with `<fastlink>`.
+class FastLinkDecorator
+       super WordDecorator
+
+       redef fun decorate_word(w) do return "<{w}>"
+end
+
+# Replaces the word letters by random special XML chars.
+class SpecialXmlCharsDecorator
+       super WordDecorator
+
+       # Random chars used
+       var chars: Array[Char] = ['<', '>', '&']
+
+       redef fun decorate_word(w) do
+               var res = new FlatBuffer
+               for c in w do
+                       var i = chars.length.rand
+                       res.add chars[i]
+               end
+               return res
+       end
+end
+
+# Wraps the word with `<blink>inline html<block>`.
+class InlineHtmlDecorator
+       super WordDecorator
+
+       redef fun decorate_word(w) do return "<blink>{w}</blink>"
+end
+
+# Replaces the word with `[link](htt://example.com/link "link Title")`.
+class FullLinkDecorator
+       super WordDecorator
+
+       redef fun decorate_word(w) do
+               return "[{w}](http://example.com/{w} \"{w} Title\")"
+       end
+end
+
+# Replaces the word with `![link](htt://example.com/link "link Title")`.
+class FullImageDecorator
+       super WordDecorator
+
+       redef fun decorate_word(w) do
+               return "![{w}](http://example.com/{w} \"{w} Title\")"
+       end
+end
+
+# Replaces the word with `[reflink][id123]`.
+class RefLinkDecorator
+       super WordDecorator
+
+       redef fun decorate_word(w) do
+               return "[{w}][id123]"
+       end
+end
+
+# Uses other decorators randomly.
+class MixedDecorator
+       super LineDecorator
+       super WordDecorator
+
+       redef fun decorate_text(txt) do
+               return decorate_lines(txt)
+       end
+
+       private var line_decs: Array[LineDecorator] is lazy do
+               return [new ManualBreakDecorator, new BlockQuoteDecorator,
+               new CodeBlockDecorator, new UnorderedListDecorator: LineDecorator]
+       end
+
+       private var current_dec: LineDecorator = line_decs.first is lazy
+
+       redef fun decorate_line(line) do
+               var re = "\n$".to_re
+               var txt = current_dec.decorate_line(line)
+               if line.has(re) then
+                       var i = line_decs.length.rand
+                       current_dec = line_decs[i]
+               end
+               return decorate_words(txt)
+       end
+
+       private var word_decs: Array[WordDecorator] is lazy do
+               return [new PlainDecorator, new EmphasisDecorator, new StrongDecorator,
+               new InlineCodeDecorator, new FastLinkDecorator, new SpecialXmlCharsDecorator,
+               new InlineHtmlDecorator, new FullLinkDecorator, new FullImageDecorator,
+               new RefLinkDecorator: WordDecorator]
+       end
+
+       redef fun decorate_word(w) do
+               var i = word_decs.length.rand
+               return word_decs[i].decorate_word(w)
+       end
+end
+
+var opt_dir = new OptionString("Output directory", "-o", "--output")
+var ctx = new OptionContext
+ctx.add_option(opt_dir)
+ctx.parse(args)
+
+if ctx.rest.length != 1 then
+       print "Usage:"
+       print "gen_benches path/to/base/text.md"
+       exit 0
+end
+
+var out_dir = opt_dir.value or else "markdown.out/"
+out_dir.mkdir
+
+var txt = ctx.rest.first.to_path.read_all
+
+var lst = [new ManualBreakDecorator, new BlockQuoteDecorator, new CodeBlockDecorator,
+               new UnorderedListDecorator, new MixedDecorator, new EmphasisDecorator,
+               new StrongDecorator, new InlineCodeDecorator, new FastLinkDecorator,
+               new SpecialXmlCharsDecorator, new InlineHtmlDecorator, new FullLinkDecorator,
+               new FullImageDecorator, new RefLinkDecorator: MarkdownDecorator]
+
+for dec in lst do
+       var name = dec.class_name.to_snake_case.basename("_decorator")
+       dec.decorate_text(txt).write_to_file("{out_dir}/{name}.md")
+end
diff --git a/benchmarks/markdown/benches/hello.md b/benchmarks/markdown/benches/hello.md
new file mode 100644 (file)
index 0000000..980a0d5
--- /dev/null
@@ -0,0 +1 @@
+Hello World!
diff --git a/benchmarks/markdown/benches/plain.md b/benchmarks/markdown/benches/plain.md
new file mode 100644 (file)
index 0000000..1416ce8
--- /dev/null
@@ -0,0 +1,86 @@
+Non eram nescius, Brute, cum, quae summis ingeniis exquisitaque doctrina philosophi Graeco sermone  tractavissent, ea Latinis litteris mandaremus, fore ut hic noster labor in varias reprehensiones incurreret. nam quibusdam, et iis quidem non admodum indoctis, totum hoc displicet philosophari. quidam autem non tam id reprehendunt, si remissius agatur, sed tantum studium tamque multam operam ponendam in eo non arbitrantur. erunt etiam, et ii quidem eruditi Graecis litteris, contemnentes Latinas, qui se dicant in Graecis legendis operam malle consumere. postremo aliquos futuros suspicor, qui me ad alias litteras vocent, genus hoc scribendi, etsi sit elegans, personae tamen et dignitatis esse negent.
+Contra quos omnis dicendum breviter existimo. Quamquam philosophiae quidem vituperatoribus satis responsum est eo libro, quo a nobis philosophia defensa et collaudata est, cum esset accusata et vituperata ab Hortensio. qui liber cum et tibi probatus videretur et iis, quos ego posse iudicare arbitrarer, plura suscepi veritus ne movere hominum studia viderer, retinere non posse. Qui autem, si maxime hoc placeat, moderatius tamen id volunt fieri, difficilem quandam temperantiam postulant in eo, quod semel admissum coerceri reprimique non potest, ut propemodum iustioribus utamur illis, qui omnino avocent a philosophia, quam his, qui rebus infinitis modum constituant in reque eo meliore, quo maior sit, mediocritatem desiderent.
+Sive enim ad sapientiam perveniri potest, non paranda nobis solum ea, sed fruenda etiam sapientia est; sive hoc difficile est, tamen nec modus est ullus investigandi veri, nisi inveneris, et quaerendi defatigatio turpis est, cum id, quod quaeritur, sit pulcherrimum. etenim si delectamur, cum scribimus, quis est tam invidus, qui ab eo nos abducat? sin laboramus, quis est, qui alienae modum statuat industriae? nam ut Terentianus Chremes non inhumanus, qui novum vicinum non vult 'fodere aut arare aut aliquid ferre denique' -- non enim illum ab industria, sed ab inliberali labore deterret --, sic isti curiosi, quos offendit noster minime nobis iniucundus labor.
+Iis igitur est difficilius satis facere, qui se Latina scripta dicunt contemnere. in quibus hoc primum est in quo admirer, cur in gravissimis rebus non delectet eos sermo patrius, cum idem fabellas Latinas ad verbum e Graecis expressas non inviti legant. quis enim tam inimicus paene nomini Romano est, qui Ennii Medeam aut Antiopam Pacuvii spernat aut reiciat, quod se isdem Euripidis fabulis delectari dicat, Latinas litteras oderit?
+Synephebos ego, inquit, potius Caecilii aut Andriam Terentii quam utramque Menandri legam?
+A quibus tantum dissentio, ut, cum Sophocles vel optime scripserit Electram, tamen male conversam Atilii mihi legendam putem, de quo Lucilius: 'ferreum scriptorem', verum, opinor, scriptorem tamen, ut legendus sit. rudem enim esse omnino in nostris poetis aut inertissimae segnitiae est aut fastidii delicatissimi. mihi quidem nulli satis eruditi videntur, quibus nostra ignota sunt. an 'Utinam ne in nemore . . .' nihilo minus legimus quam hoc idem Graecum, quae autem de bene beateque vivendo a Platone disputata sunt, haec explicari non placebit Latine?
+Quid? si nos non interpretum fungimur munere, sed tuemur ea, quae dicta sunt ab iis quos probamus, eisque nostrum iudicium et nostrum scribendi ordinem adiungimus, quid habent, cur Graeca anteponant iis, quae et splendide dicta sint neque sint conversa de Graecis? nam si dicent ab illis has res esse tractatas, ne ipsos quidem Graecos est cur tam multos legant, quam legendi sunt. quid enim est a Chrysippo praetermissum in Stoicis? legimus tamen Diogenem, Antipatrum, Mnesarchum, Panaetium, multos alios in primisque familiarem nostrum Posidonium. quid? Theophrastus mediocriterne delectat, cum tractat locos ab Aristotele ante tractatos? quid? Epicurei num desistunt de isdem, de quibus et ab Epicuro scriptum est et ab antiquis, ad arbitrium suum scribere? quodsi Graeci leguntur a Graecis isdem de rebus alia ratione compositis, quid est, cur nostri a nostris non legantur?
+Quamquam, si plane sic verterem Platonem aut Aristotelem, ut verterunt nostri poetae fabulas, male, credo, mererer de meis civibus, si ad eorum cognitionem divina illa ingenia transferrem. sed id neque feci adhuc nec mihi tamen, ne faciam, interdictum puto. locos quidem quosdam, si videbitur, transferam, et maxime ab iis, quos modo nominavi, cum inciderit, ut id apte fieri possit, ut ab Homero Ennius, Afranius a Menandro solet. Nec vero, ut noster Lucilius, recusabo, quo minus omnes mea legant. utinam esset ille Persius, Scipio vero et Rutilius multo etiam magis, quorum ille iudicium reformidans Tarentinis ait se et Consentinis et Siculis scribere. facete is quidem, sicut alia; sed neque tam docti tum erant, ad quorum iudicium elaboraret, et sunt illius scripta leviora, ut urbanitas summa appareat, doctrina mediocris.
+Ego autem quem timeam lectorem, cum ad te ne Graecis quidem cedentem in philosophia audeam scribere? quamquam a te ipso id quidem facio provocatus gratissimo mihi libro, quem ad me de virtute misisti. Sed ex eo credo quibusdam usu venire; ut abhorreant a Latinis, quod inciderint in inculta quaedam et horrida, de malis Graecis Latine scripta deterius. quibus ego assentior, dum modo de isdem rebus ne Graecos quidem legendos putent. res vero bonas verbis electis graviter ornateque dictas quis non legat? nisi qui se plane Graecum dici velit, ut a Scaevola est praetore salutatus Athenis Albucius.
+Quem quidem locum comit multa venustate et omni sale idem Lucilius, apud quem praeclare Scaevola:
+Graecum te, Albuci, quam Romanum atque Sabinum,
+municipem Ponti, Tritani, centurionum,
+praeclarorum hominum ac primorum signiferumque,
+maluisti dici. Graece ergo praetor Athenis,
+id quod maluisti, te, cum ad me accedis, saluto:
+'chaere,' inquam, 'Tite!' lictores, turma omnis chorusque:
+'chaere, Tite!' hinc hostis mi Albucius, hinc inimicus.
+Sed iure Mucius. ego autem mirari non queo unde hoc sit tam insolens domesticarum rerum fastidium. non est omnino hic docendi locus; sed ita sentio et saepe disserui, Latinam linguam non modo non inopem, ut vulgo putarent, sed locupletiorem etiam esse quam Graecam. quando enim nobis, vel dicam aut oratoribus bonis aut poetis, postea quidem quam fuit quem imitarentur, ullus orationis vel copiosae vel elegantis ornatus defuit? Ego vero, quoniam forensibus operis, laboribus, periculis non deseruisse mihi videor praesidium, in quo a populo Romano locatus sum, debeo profecto, quantumcumque possum, in eo quoque elaborare, ut sint opera, studio, labore meo doctiores cives mei, nec cum istis tantopere pugnare, qui Graeca legere malint, modo legant illa ipsa, ne simulent, et iis servire, qui vel utrisque litteris uti velint vel, si suas habent, illas non magnopere desiderent.
+Qui autem alia malunt scribi a nobis, aequi esse debent, quod et scripta multa sunt, sic ut plura nemini e nostris, et scribentur fortasse plura, si vita suppetet; et tamen, qui diligenter haec, quae de philosophia litteris mandamus, legere assueverit, iudicabit nulla ad legendum his esse potiora. quid est enim in vita tantopere quaerendum quam cum omnia in philosophia, tum id, quod his libris quaeritur, qui sit finis, quid extremum, quid ultimum, quo sint omnia bene vivendi recteque faciendi consilia referenda, quid sequatur natura ut summum ex rebus expetendis, quid fugiat ut extremum malorum? qua de re cum sit inter doctissimos summa dissensio, quis alienum putet eius esse dignitatis, quam mihi quisque tribuat, quid in omni munere vitae optimum et verissimum sit, exquirere?
+An, partus ancillae sitne in fructu habendus, disseretur inter principes civitatis, P. Scaevolam M'.que Manilium, ab iisque M. Brutus dissentiet -- quod et acutum genus est et ad usus civium non inutile, nosque ea scripta reliquaque eiusdem generis et legimus libenter et legemus --, haec, quae vitam omnem continent, neglegentur? nam, ut sint illa vendibiliora, haec uberiora certe sunt. quamquam id quidem licebit iis existimare, qui legerint. nos autem hanc omnem quaestionem de finibus bonorum et malorum fere a nobis explicatam esse his litteris arbitramur, in quibus, quantum potuimus, non modo quid nobis probaretur, sed etiam quid a singulis philosophiae disciplinis diceretur, persecuti sumus.
+Ut autem a facillimis ordiamur, prima veniat in medium Epicuri ratio, quae plerisque notissima est. quam a nobis sic intelleges eitam, ut ab ipsis, qui eam disciplinam probant, non soleat accuratius explicari; verum enim invenire volumus, non tamquam adversarium aliquem convincere. accurate autem quondam a L. Torquato, homine omni doctrina erudito, defensa est Epicuri sententia de voluptate, a meque ei responsum, cum C. Triarius, in primis gravis et doctus adolescens, ei disputationi interesset.
+Nam cum ad me in Cumanum salutandi causa uterque venisset, pauca primo inter nos de litteris, quarum summum erat in utroque studium, deinde Torquatus: Quoniam nacti te, inquit, sumus aliquando otiosum, certe audiam, quid sit, quod Epicurum nostrum non tu quidem oderis, ut fere faciunt, qui ab eo dissentiunt, sed certe non probes, eum quem ego arbitror unum vidisse verum maximisque erroribus animos hominum liberavisse et omnia tradidisse, quae pertinerent ad bene beateque vivendum. sed existimo te, sicut nostrum Triarium, minus ab eo delectari, quod ista Platonis, Aristoteli, Theophrasti orationis ornamenta neglexerit. nam illud quidem adduci vix possum, ut ea, quae senserit ille, tibi non vera videantur.
+Vide, quantum, inquam, fallare, Torquate. oratio me istius philosophi non offendit; nam et complectitur verbis, quod vult, et dicit plane, quod intellegam; et tamen ego a philosopho, si afferat eloquentiam, non asperner, si non habeat, non admodum flagitem. re mihi non aeque satisfacit, et quidem locis pluribus. sed quot homines, tot sententiae; falli igitur possumus.
+Quam ob rem tandem, inquit, non satisfacit? te enim iudicem aequum puto, modo quae dicat ille bene noris.
+Nisi mihi Phaedrum, inquam, tu mentitum aut Zenonem putas, quorum utrumque audivi, cum mihi nihil sane praeter sedulitatem probarent, omnes mihi Epicuri sententiae satis notae sunt. atque eos, quos nominavi, cum Attico nostro frequenter audivi, cum miraretur ille quidem utrumque, Phaedrum autem etiam amaret, cotidieque inter nos ea, quae audiebamus, conferebamus, neque erat umquam controversia, quid ego intellegerem, sed quid probarem.
+Quid igitur est? inquit; audire enim cupio, quid non probes. Principio, inquam, in physicis, quibus maxime gloriatur, primum totus est alienus. Democritea dicit perpauca mutans, sed ita, ut ea, quae corrigere vult, mihi quidem depravare videatur. ille atomos quas appellat, id est corpora individua propter soliditatem, censet in infinito inani, in quo nihil nec summum nec infimum nec medium nec ultimum nec extremum sit, ita ferri, ut concursionibus inter se cohaerescant, ex quo efficiantur ea, quae sint quaeque cernantur, omnia, eumque motum atomorum nullo a principio, sed ex aeterno tempore intellegi convenire.
+Epicurus autem, in quibus sequitur Democritum, non fere labitur. quamquam utriusque cum multa non probo, tum illud in primis, quod, cum in rerum natura duo quaerenda sint, unum, quae materia sit, ex qua quaeque res efficiatur, alterum, quae vis sit, quae quidque efficiat, de materia disseruerunt, vim et causam efficiendi reliquerunt. sed hoc commune vitium, illae Epicuri propriae ruinae: censet enim eadem illa individua et solida corpora ferri deorsum suo pondere ad lineam, hunc naturalem esse omnium corporum motum.
+Deinde ibidem homo acutus, cum illud ocurreret, si omnia deorsus e regione ferrentur et, ut dixi, ad lineam, numquam fore ut atomus altera alteram posset attingere itaque ** attulit rem commenticiam: declinare dixit atomum perpaulum, quo nihil posset fieri minus; ita effici complexiones et copulationes et adhaesiones atomorum inter se, ex quo efficeretur mundus omnesque partes mundi, quaeque in eo essent. Quae cum tota res (est) ficta pueriliter, tum ne efficit [quidem], quod vult. nam et ipsa declinatio ad libidinem fingitur -- ait enim declinare atomum sine causa; quo nihil turpius physico, quam fieri quicquam sine causa dicere, -- et illum motum naturalem omnium ponderum, ut ipse constituit, e regione inferiorem locum petentium sine causa eripuit atomis nec tamen id, cuius causa haec finxerat, assecutus est.
+Nam si omnes atomi declinabunt, nullae umquam cohaerescent, sive aliae declinabunt, aliae suo nutu recte ferentur, primum erit hoc quasi, provincias atomis dare, quae recte, quae oblique ferantur, deinde eadem illa atomorum, in quo etiam Democritus haeret, turbulenta concursio hunc mundi ornatum efficere non poterit. ne illud quidem physici, credere aliquid esse minimum, quod profecto numquam putavisset, si a Polyaeno, familiari suo, geometrica discere maluisset quam illum etiam ipsum dedocere. Sol Democrito magnus videtur, quippe homini erudito in geometriaque perfecto, huic pedalis fortasse; tantum enim esse censet, quantus videtur, vel paulo aut maiorem aut minorem.
+Ita, quae mutat, ea corrumpit, quae sequitur sunt tota Democriti, atomi, inane, imagines, quae eidola nominant, quorum incursione non solum videamus, sed etiam cogitemus; infinitio ipsa, quam apeirian vocant, tota ab illo est, tum innumerabiles mundi, qui et oriantur et intereant cotidie. Quae etsi mihi nullo modo probantur, tamen Democritum laudatum a ceteris ab hoc, qui eum unum secutus esset, nollem vituperatum.
+Iam in altera philosophiae parte. quae est quaerendi ac disserendi, quae logikh dicitur, iste vester plane, ut mihi quidem videtur, inermis ac nudus est. tollit definitiones, nihil de dividendo ac partiendo docet, non quo modo efficiatur concludaturque ratio tradit, non qua via captiosa solvantur ambigua distinguantur ostendit; iudicia rerum in sensibus ponit, quibus si semel aliquid falsi pro vero probatum sit, sublatum esse omne iudicium veri et falsi putat.
+Confirmat autem illud vel maxime, quod ipsa natura, ut ait ille, sciscat et probet, id est voluptatem et dolorem. ad haec et quae sequamur et quae fugiamus refert omnia. quod quamquam Aristippi est a Cyrenaicisque melius liberiusque defenditur, tamen eius modi esse iudico, ut nihil homine videatur indignius. ad maiora enim quaedam nos natura genuit et conformavit, ut mihi quidem videtur. ac fieri potest, ut errem, sed ita prorsus existimo, neque eum Torquatum, qui hoc primus cognomen invenerit, aut torquem illum hosti detraxisse, ut aliquam ex eo perciperet corpore voluptatem, aut cum Latinis tertio consulatu conflixisse apud Veserim propter voluptatem; quod vero securi percussit filium, privavisse se etiam videtur multis voluptatibus, cum ipsi naturae patrioque amori praetulerit ius maiestatis atque imperii.
+quid? T. Torquatus, is qui consul cum Cn. Octavio fuit, cum illam severitatem in eo filio adhibuit, quem in adoptionem D. Silano emancipaverat, ut eum Macedonum legatis accusantibus, quod pecunias praetorem in provincia cepisse arguerent, causam apud se dicere iuberet reque ex utraque parte audita pronuntiaret eum non talem videri fuisse in imperio, quales eius maiores fuissent, et in conspectum suum venire vetuit, numquid tibi videtur de voluptatibus suis cogitavisse?
+Sed ut omittam pericula, labores, dolorem etiam, quem optimus quisque pro patria et pro suis suscipit, ut non modo nullam captet, sed etiam praetereat omnes voluptates, dolores denique quosvis suscipere malit quam deserere ullam officii partem, ad ea, quae hoc non minus declarant, sed videntur leviora, veniamus.
+Quid tibi, Torquate, quid huic Triario litterae, quid historiae cognitioque rerum, quid poetarum evolutio, quid tanta tot versuum memoria voluptatis affert? nec mihi illud dixeris: 'Haec enim ipsa mihi sunt voluptati, et erant illa Torquatis.' Numquam hoc ita defendit Epicurus neque Metrodorus aut quisquam eorum, qui aut saperet aliquid aut ista didicisset. et quod quaeritur saepe, cur tam multi sint Epicurei, sunt aliae quoque causae, sed multitudinem haec maxime allicit, quod ita putant dici ab illo, recta et honesta quae sint, ea facere ipsa per se laetitiam, id est voluptatem. homines optimi non intellegunt totam rationem everti, si ita res se habeat. nam si concederetur, etiamsi ad corpus nihil referatur, ista sua sponte et per se esse iucunda, per se esset et virtus et cognitio rerum, quod minime ille vult expetenda.
+Haec igitur Epicuri non probo, inquam. De cetero vellem equidem aut ipse doctrinis fuisset instructior -- est enim, quod tibi ita videri necesse est, non satis politus iis artibus, quas qui tenent, eruditi appellantur -- aut ne deterruisset alios a studiis. quamquam te quidem video minime esse deterritum.
+Quae cum dixissem, magis ut illum provocarem quam ut ipse loquerer, tum Triarius leniter arridens: Tu quidem, inquit, totum Epicurum paene e philosophorum choro sustulisti. Quid ei reliquisti, nisi te, quoquo modo loqueretur, intellegere, quid diceret? Aliena dixit in physicis nec ea ipsa, quae tibi probarentur; si qua in iis corrigere voluit, deteriora fecit. disserendi artem nullam habuit. voluptatem cum summum bonum diceret, primum in eo ipso parum vidit, deinde hoc quoque alienum; nam ante Aristippus, et ille melius. addidisti ad extremum etiam indoctum fuisse.
+Fieri, inquam, Triari, nullo pacto potest, ut non dicas, quid non probes eius, a quo dissentias. quid enim me prohiberet Epicureum esse, si probarem, quae ille diceret? cum praesertim illa perdiscere ludus esset. Quam ob rem dissentientium inter se reprehensiones non sunt vituperandae, maledicta, contumeliae, tum iracundiae, contentiones concertationesque in disputando pertinaces indignae philosophia mihi videri solent.
+Tum Torquatus: Prorsus, inquit, assentior; neque enim disputari sine reprehensione nec cum iracundia aut pertinacia recte disputari potest. sed ad haec, nisi molestum est, habeo quae velim. An me, inquam, nisi te audire vellem, censes haec dicturum fuisse? Utrum igitur percurri omnem Epicuri disciplinam placet an de una voluptate quaeri, de qua omne certamen est? Tuo vero id quidem, inquam, arbitratu. Sic faciam igitur, inquit: unam rem explicabo, eamque maximam, de physicis alias, et quidem tibi et declinationem istam atomorum et magnitudinem solis probabo et Democriti errata ab Epicuro reprehensa et correcta permulta. nunc dicam de voluptate, nihil scilicet novi, ea tamen, quae te ipsum probaturum esse confidam.
+Certe, inquam, pertinax non ero tibique, si mihi probabis ea, quae dices, libenter assentiar. Probabo, inquit, modo ista sis aequitate, quam ostendis. sed uti oratione perpetua malo quam interrogare aut interrogari. Ut placet, inquam. Tum dicere exorsus est. Primum igitur, inquit, sic agam, ut ipsi auctori huius disciplinae placet: constituam, quid et quale sit id, de quo quaerimus, non quo ignorare vos arbitrer, sed ut ratione et via procedat oratio. quaerimus igitur, quid sit extremum et ultimum bonorum, quod omnium philosophorum sententia tale debet esse, ut ad id omnia referri oporteat, ipsum autem nusquam. hoc Epicurus in voluptate ponit, quod summum bonum esse vult, summumque malum dolorem, idque instituit docere sic:
+Omne animal, simul atque natum sit, voluptatem appetere eaque gaudere ut summo bono, dolorem aspernari ut summum malum et, quantum possit, a se repellere, idque facere nondum depravatum ipsa natura incorrupte atque integre iudicante. itaque negat opus esse ratione neque disputatione, quam ob rem voluptas expetenda, fugiendus dolor sit. sentiri haec putat, ut calere ignem, nivem esse albam, dulce mel. quorum nihil oportere exquisitis rationibus confirmare, tantum satis esse admonere. interesse enim inter argumentum conclusionemque rationis et inter mediocrem animadversionem atque admonitionem. altera occulta quaedam et quasi involuta aperiri, altera prompta et aperta iudicari. etenim quoniam detractis de homine sensibus reliqui nihil est, necesse est, quid aut ad naturam aut contra sit, a natura ipsa iudicari. ea quid percipit aut quid iudicat, quo aut petat aut fugiat aliquid, praeter voluptatem et dolorem?
+Sunt autem quidam e nostris, qui haec subtilius velint tradere et negent satis esse, quid bonum sit aut quid malum, sensu iudicari, sed animo etiam ac ratione intellegi posse et voluptatem ipsam per se esse expetendam et dolorem ipsum per se esse fugiendum. itaque aiunt hanc quasi naturalem atque insitam in animis nostris inesse notionem, ut alterum esse appetendum, alterum aspernandum sentiamus. Alii autem, quibus ego assentior, cum a philosophis compluribus permulta dicantur, cur nec voluptas in bonis sit numeranda nec in malis dolor, non existimant oportere nimium nos causae confidere, sed et argumentandum et accurate disserendum et rationibus conquisitis de voluptate et dolore disputandum putant.
+Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt, explicabo. nemo enim ipsam voluptatem, quia voluptas sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos, qui ratione voluptatem sequi nesciunt, neque porro quisquam est, qui dolorem ipsum, quia dolor sit, amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt, ut labore et dolore magnam aliquam quaerat voluptatem. ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? quis autem vel eum iure reprehenderit, qui in ea voluptate velit esse, quam nihil molestiae consequatur, vel illum, qui dolorem eum fugiat, quo voluptas nulla pariatur?
+At vero eos et accusamus et iusto odio dignissimos ducimus, qui blanditiis praesentium voluptatum deleniti atque corrupti, quos dolores et quas molestias excepturi sint, obcaecati cupiditate non provident, similique sunt in culpa, qui officia deserunt mollitia animi, id est laborum et dolorum fuga. et harum quidem rerum facilis est et expedita distinctio. nam libero tempore, cum soluta nobis est eligendi optio, cumque nihil impedit, quo minus id, quod maxime placeat, facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet, ut et voluptates repudiandae sint et molestiae non recusandae. itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.
+Hanc ego cum teneam sententiam, quid est cur verear, ne ad eam non possim accommodare Torquatos nostros? quos tu paulo ante cum memoriter, tum etiam erga nos amice et benivole collegisti, nec me tamen laudandis maioribus meis corrupisti nec segniorem ad respondendum reddidisti. quorum facta quem ad modum, quaeso, interpretaris? sicine eos censes aut in armatum hostem impetum fecisse aut in liberos atque in sanguinem suum tam crudelis fuisse, nihil ut de utilitatibus, nihil ut de commodis suis cogitarent? at id ne ferae quidem faciunt, ut ita ruant itaque turbent, ut earum motus et impetus quo pertineant non intellegamus, tu tam egregios viros censes tantas res gessisse sine causa?
+Quae fuerit causa, mox videro; interea hoc tenebo, si ob aliquam causam ista, quae sine dubio praeclara sunt, fecerint, virtutem iis per se ipsam causam non fuisse. -- Torquem detraxit hosti. -- Et quidem se texit, ne interiret. -- At magnum periculum adiit. -- In oculis quidem exercitus. -- Quid ex eo est consecutus? -- Laudem et caritatem, quae sunt vitae sine metu degendae praesidia firmissima. -- Filium morte multavit. -- Si sine causa, nollem me ab eo ortum, tam inportuno tamque crudeli; sin, ut dolore suo sanciret militaris imperii disciplinam exercitumque in gravissimo bello animadversionis metu contineret, saluti prospexit civium, qua intellegebat contineri suam. atque haec ratio late patet.
+In quo enim maxime consuevit iactare vestra se oratio, tua praesertim, qui studiose antiqua persequeris, claris et fortibus viris commemorandis eorumque factis non emolumento aliquo, sed ipsius honestatis decore laudandis, id totum evertitur eo delectu rerum, quem modo dixi, constituto, ut aut voluptates omittantur maiorum voluptatum adipiscendarum causa aut dolores suscipiantur maiorum dolorum effugiendorum gratia.
+Sed de clarorum hominum factis illustribus et gloriosis satis hoc loco dictum sit. erit enim iam de omnium virtutum cursu ad voluptatem proprius disserendi locus. nunc autem explicabo, voluptas ipsa quae qualisque sit, ut tollatur error omnis imperitorum intellegaturque ea, quae voluptaria, delicata, mollis habeatur disciplina, quam gravis, quam continens, quam severa sit. Non enim hanc solam sequimur, quae suavitate aliqua naturam ipsam movet et cum iucunditate quadam percipitur sensibus, sed maximam voluptatem illam habemus, quae percipitur omni dolore detracto, nam quoniam, cum privamur dolore, ipsa liberatione et vacuitate omnis molestiae gaudemus, omne autem id, quo gaudemus, voluptas est, ut omne, quo offendimur, dolor, doloris omnis privatio recte nominata est voluptas. ut enim, cum cibo et potione fames sitisque depulsa est, ipsa detractio molestiae consecutionem affert voluptatis, sic in omni re doloris amotio successionem efficit voluptatis.
+Itaque non placuit Epicuro medium esse se quiddam inter dolorem et voluptatem; illud enim ipsum, quod quibusdam medium videretur, cum omni dolore careret, non modo voluptatem esse, verum etiam summam voluptatem. quisquis enim sentit, quem ad modum sit affectus, eum necesse est aut in voluptate esse aut in dolore. omnis autem privatione doloris putat Epicurus terminari summam voluptatem, ut postea variari voluptas distinguique possit, augeri amplificarique non possit.
+At etiam Athenis, ut e patre audiebam facete et urbane Stoicos irridente, statua est in Ceramico Chrysippi sedentis porrecta manu, quae manus significet illum in hae esse rogatiuncula delectatum: 'Numquidnam manus tua sic affecta, quem ad modum affecta nunc est, desiderat?' -- Nihil sane. -- 'At, si voluptas esset bonum, desideraret.' -- Ita credo. -- 'Non est igitur voluptas bonum.' Hoc ne statuam quidem dicturam pater aiebat, si loqui posset. conclusum est enim contra Cyrenaicos satis acute, nihil ad Epicurum. nam si ea sola voluptas esset, quae quasi titillaret sensus, ut ita dicam, et ad eos cum suavitate afflueret et illaberetur, nec manus esse contenta posset nec ulla pars vacuitate doloris sine iucundo motu voluptatis. sin autem summa voluptas est, ut Epicuro placet, nihil dolere, primum tibi recte, Chrysippe, concessum est nihil desiderare manum, cum ita esset affecta, secundum non recte, si voluptas esset bonum, fuisse desideraturam. idcirco enim non desideraret, quia, quod dolore caret, id in voluptate est.
+Extremum autem esse bonorum voluptatem ex hoc facillime perspici potest: Constituamus aliquem magnis, multis, perpetuis fruentem et animo et corpore voluptatibus nullo dolore nec impediente nec inpendente, quem tandem hoc statu praestabiliorem aut magis expetendum possimus dicere? inesse enim necesse est in eo, qui ita sit affectus, et firmitatem animi nec mortem nec dolorem timentis, quod mors sensu careat, dolor in longinquitate levis, in gravitate brevis soleat esse, ut eius magnitudinem celeritas, diuturnitatem allevatio consoletur.
+Ad ea cum accedit, ut neque divinum numen horreat nec praeteritas voluptates effluere patiatur earumque assidua recordatione laetetur, quid est, quod huc possit, quod melius sit, accedere? Statue contra aliquem confectum tantis animi corporisque doloribus, quanti in hominem maximi cadere possunt, nulla spe proposita fore levius aliquando, nulla praeterea neque praesenti nec expectata voluptate, quid eo miserius dici aut fingi potest? quodsi vita doloribus referta maxime fugienda est, summum profecto malum est vivere cum dolore, cui sententiae consentaneum est ultimum esse bonorum eum voluptate vivere. nec enim habet nostra mens quicquam, ubi consistat tamquam in extremo, omnesque et metus et aegritudines ad dolorem referuntur, nec praeterea est res ulla, quae sua natura aut sollicitare possit aut angere.
+Praeterea et appetendi et refugiendi et omnino rerum gerendarum initia proficiscuntur aut a voluptate aut a dolore. quod cum ita sit, perspicuum est omnis rectas res atque laudabilis eo referri, ut cum voluptate vivatur. quoniam autem id est vel summum bonorum vel ultimum vel extremum -- quod Graeci telos nominant --, quod ipsum nullam ad aliam rem, ad id autem res referuntur omnes, fatendum est summum esse bonum iucunde vivere.
+Id qui in una virtute ponunt et splendore nominis capti quid natura postulet non intellegunt, errore maximo, si Epicurum audire voluerint, liberabuntur: istae enim vestrae eximiae pulchraeque virtutes nisi voluptatem efficerent, quis eas aut laudabilis aut expetendas arbitraretur? ut enim medicorum scientiam non ipsius artis, sed bonae valetudinis causa probamus, et gubernatoris ars, quia bene navigandi rationem habet, utilitate, non arte laudatur, sic sapientia, quae ars vivendi putanda est, non expeteretur, si nihil efficeret; nunc expetitur, quod est tamquam artifex conquirendae et comparandae voluptatis --
+Quam autem ego dicam voluptatem, iam videtis, ne invidia verbi labefactetur oratio mea --. nam cum ignoratione rerum bonarum et malarum maxime hominum vita vexetur, ob eumque errorem et voluptatibus maximis saepe priventur et durissimis animi doloribus torqueantur, sapientia est adhibenda, quae et terroribus cupiditatibusque detractis et omnium falsarum opinionum temeritate derepta certissimam se nobis ducem praebeat ad voluptatem. sapientia enim est una, quae maestitiam pellat ex animis, quae nos exhorrescere metu non sinat. qua praeceptrice in tranquillitate vivi potest omnium cupiditatum ardore restincto. cupiditates enim sunt insatiabiles, quae non modo singulos homines, sed universas familias evertunt, totam etiam labefactant saepe rem publicam.
+Ex cupiditatibus odia, discidia, discordiae, seditiones, bella nascuntur, nec eae se foris solum iactant nec tantum in alios caeco impetu incurrunt, sed intus etiam in animis inclusae inter se dissident atque discordant, ex quo vitam amarissimam necesse est effici, ut sapiens solum amputata circumcisaque inanitate omni et errore naturae finibus contentus sine aegritudine possit et sine metu vivere.
+Quae est enim aut utilior aut ad bene vivendum aptior partitio quam illa, qua est usus Epicurus? qui unum genus posuit earum cupiditatum, quae essent et naturales et necessariae, alterum, quae naturales essent nec tamen necessariae, tertium, quae nec naturales nec necessariae. quarum ea ratio est, ut necessariae nec opera multa nec impensa expleantur; ne naturales quidem multa desiderant, propterea quod ipsa natura divitias, quibus contenta sit, et parabilis et terminatas habet; inanium autem cupiditatum nec modus ullus nec finis inveniri potest.
+Quodsi vitam omnem perturbari videmus errore et inscientia, sapientiamque esse solam, quae nos a libidinum impetu et a formidinum terrore vindicet et ipsius fortunae modice ferre doceat iniurias et omnis monstret vias, quae ad quietem et ad tranquillitatem ferant, quid est cur dubitemus dicere et sapientiam propter voluptates expetendam et insipientiam propter molestias esse fugiendam?
+Eademque ratione ne temperantiam quidem propter se expetendam esse dicemus, sed quia pacem animis afferat et eos quasi concordia quadam placet ac leniat. temperantia est enim, quae in rebus aut expetendis aut fugiendis ut rationem sequamur monet. nec enim satis est iudicare quid faciendum non faciendumve sit, sed stare etiam oportet in eo, quod sit iudicatum. plerique autem, quod tenere atque servare id, quod ipsi statuerunt, non possunt, victi et debilitati obiecta specie voluptatis tradunt se libidinibus constringendos nec quid eventurum sit provident ob eamque causam propter voluptatem et parvam et non necessariam et quae vel aliter pararetur et qua etiam carere possent sine dolore tum in morbos gravis, tum in damna, tum in dedecora incurrunt, saepe etiam legum iudiciorumque poenis obligantur.
+Qui autem ita frui volunt voluptatibus, ut nulli propter eas consequantur dolores, et qui suum iudicium retinent, ne voluptate victi faciant id, quod sentiant non esse faciendum, ii voluptatem maximam adipiscuntur praetermittenda voluptate. idem etiam dolorem saepe perpetiuntur, ne, si id non faciant, incidant in maiorem. ex quo intellegitur nec intemperantiam propter se esse fugiendam temperantiamque expetendam, non quia voluptates fugiat, sed quia maiores consequatur.
+Eadem fortitudinis ratio reperietur. nam neque laborum perfunctio neque perpessio dolorum per se ipsa allicit nec patientia nec assiduitas nec vigiliae nec ea ipsa, quae laudatur, industria, ne fortitudo quidem, sed ista sequimur, ut sine cura metuque vivamus animumque et corpus, quantum efficere possimus, molestia liberemus. ut enim mortis metu omnis quietae vitae status perturbatur, et ut succumbere doloribus eosque humili animo inbecilloque ferre miserum est, ob eamque debilitatem animi multi parentes, multi amicos, non nulli patriam, plerique autem se ipsos penitus perdiderunt, sic robustus animus et excelsus omni est liber cura et angore, cum et mortem contemnit, qua qui affecti sunt in eadem causa sunt, qua ante quam nati, et ad dolores ita paratus est, ut meminerit maximos morte finiri, parvos multa habere intervalla requietis, mediocrium nos esse dominos, ut, si tolerabiles sint, feramus, si minus, animo aequo e vita, cum ea non placeat, tamquam e theatro exeamus. quibus rebus intellegitur nec timiditatem ignaviamque vituperari nec fortitudinem patientiamque laudari suo nomine, sed illas reici, quia dolorem pariant, has optari, quia voluptatem.
+Iustitia restat, ut de omni virtute sit dictum. sed similia fere dici possunt. ut enim sapientiam, temperantiam, fortitudinem copulatas esse docui cum voluptate, ut ab ea nullo modo nec divelli nec distrahi possint, sic de iustitia iudicandum est, quae non modo numquam nocet cuiquam, sed contra semper afficit cum vi sua atque natura, quod tranquillat animos, tum spe nihil earum rerum defuturum, quas natura non depravata desiderat. [et] quem ad modum temeritas et libido et ignavia semper animum excruciant et semper sollicitant turbulentaeque sunt, sic [inprobitas si] cuius in mente consedit, hoc ipso, quod adest, turbulenta est; si vero molita quippiam est, quamvis occulte fecerit, numquam tamen id confidet fore semper occultum. plerumque improborum facta primo suspicio insequitur, dein sermo atque fama, tum accusator, tum iudex;
+Multi etiam, ut te consule, ipsi se indicaverunt. quodsi qui satis sibi contra hominum conscientiam saepti esse et muniti videntur, deorum tamen horrent easque ipsas sollicitudines, quibus eorum animi noctesque diesque exeduntur, a diis inmortalibus supplicii causa importari putant. quae autem tanta ex improbis factis ad minuendas vitae molestias accessio potest fieri, quanta ad augendas, cum conscientia factorum, tum poena legum odioque civium? et tamen in quibusdam neque pecuniae modus est neque honoris neque imperii nec libidinum nec epularum nec reliquarum cupiditatum, quas nulla praeda umquam improbe parta minuit, [sed] potius inflammat, ut coercendi magis quam dedocendi esse videantur.
+Invitat igitur vera ratio bene sanos ad iustitiam, aequitatem, fidem, neque homini infanti aut inpotenti iniuste facta conducunt, qui nec facile efficere possit, quod conetur, nec optinere, si effecerit, et opes vel fortunae vel ingenii liberalitati magis conveniunt, qua qui utuntur, benivolentiam sibi conciliant et, quod aptissimum est ad quiete vivendum, caritatem, praesertim cum omnino nulla sit causa peccandi.
+Quae enim cupiditates a natura proficiscuntur, facile explentur sine ulla iniuria, quae autem inanes sunt, iis parendum non est. nihil enim desiderabile concupiscunt, plusque in ipsa iniuria detrimenti est quam in iis rebus emolumenti, quae pariuntur iniuria. Itaque ne iustitiam quidem recte quis dixerit per se ipsam optabilem, sed quia iucunditatis vel plurimum afferat. nam diligi et carum esse iucundum est propterea, quia tutiorem vitam et voluptatem pleniorem efficit. itaque non ob ea solum incommoda, quae eveniunt inprobis, fugiendam inprobitatem putamus, sed multo etiam magis, quod, cuius in animo versatur, numquam sinit eum respirare, numquam adquiescere.
+Quodsi ne ipsarum quidem virtutum laus, in qua maxime ceterorum philosophorum exultat oratio, reperire exitum potest, nisi derigatur ad voluptatem, voluptas autem est sola, quae nos vocet ad se et alliciat suapte natura, non potest esse dubium, quin id sit summum atque extremum bonorum omnium, beateque vivere nihil aliud sit nisi cum voluptate vivere.
+Huic certae stabilique sententiae quae sint coniuncta explicabo brevi. nullus in ipsis error est finibus bonorum et malorum, id est in voluptate aut in dolore, sed in his rebus peccant, cum e quibus haec efficiantur ignorant. animi autem voluptates et dolores nasci fatemur e corporis voluptatibus et doloribus -- itaque concedo, quod modo dicebas, cadere causa, si qui e nostris aliter existimant, quos quidem video esse multos, sed imperitos --, quamquam autem et laetitiam nobis voluptas animi et molestiam dolor afferat, eorum tamen utrumque et ortum esse e corpore et ad corpus referri, nec ob eam causam non multo maiores esse et voluptates et dolores animi quam corporis. nam corpore nihil nisi praesens et quod adest sentire possumus, animo autem et praeterita et futura. ut enim aeque doleamus animo, cum corpore dolemus, fieri tamen permagna accessio potest, si aliquod aeternum et infinitum impendere malum nobis opinemur. quod idem licet transferre in voluptatem, ut ea maior sit, si nihil tale metuamus.
+Iam illud quidem perspicuum est, maximam animi aut voluptatem aut molestiam plus aut ad beatam aut ad miseram vitam afferre momenti quam eorum utrumvis, si aeque diu sit in corpore. Non placet autem detracta voluptate aegritudinem statim consequi, nisi in voluptatis locum dolor forte successerit, at contra gaudere nosmet omittendis doloribus, etiamsi voluptas ea, quae sensum moveat, nulla successerit, eoque intellegi potest quanta voluptas sit non dolere.
+Sed ut iis bonis erigimur, quae expectamus, sic laetamur iis, quae recordamur. stulti autem malorum memoria torquentur, sapientes bona praeterita grata recordatione renovata delectant. est autem situm in nobis ut et adversa quasi perpetua oblivione obruamus et secunda iucunde ac suaviter meminerimus. sed cum ea, quae praeterierunt, acri animo et attento intuemur, tum fit ut aegritudo sequatur, si illa mala sint, laetitia, si bona.
+O praeclaram beate vivendi et apertam et simplicem et directam viam! eum enim certe nihil homini possit melius esse quam vacare omni dolore et molestia perfruique maximis et animi et corporis voluptatibus, videtisne quam nihil praetermittatur quod vitam adiuvet, quo facilius id, quod propositum est, summum bonum consequamur? clamat Epicurus, is quem vos nimis voluptatibus esse deditum dicitis; non posse iucunde vivi, nisi sapienter, honeste iusteque vivatur, nec sapienter, honeste, iuste, nisi iucunde.
+Neque enim civitas in seditione beata esse potest nec in discordia dominorum domus; quo minus animus a se ipse dissidens secumque discordans gustare partem ullam liquidae voluptatis et liberae potest. atqui pugnantibus et contrariis studiis consiliisque semper utens nihil quieti videre, nihil tranquilli potest.
+Quodsi corporis gravioribus morbis vitae iucunditas impeditur, quanto magis animi morbis impediri necesse est! animi autem morbi sunt cupiditates inmensae et inanes divitiarum, gloriae, dominationis, libidinosarum etiam voluptatum. accedunt aegritudines, molestiae, maerores, qui exedunt animos conficiuntque curis hominum non intellegentium nihil dolendum esse animo, quod sit a dolore corporis praesenti futurove seiunctum. nec vero quisquam stultus non horum morborum aliquo laborat, nemo igitur est non miser.
+Accedit etiam mors, quae quasi saxum Tantalo semper impendet, tum superstitio, qua qui est imbutus quietus esse numquam potest. praeterea bona praeterita non meminerunt, praesentibus non fruuntur, futura modo expectant, quae quia certa esse non possunt, conficiuntur et angore et metu maximeque cruciantur, cum sero sentiunt frustra se aut pecuniae studuisse aut imperiis aut opibus aut gloriae. nullas enim consequuntur voluptates, quarum potiendi spe inflammati multos labores magnosque susceperant.
+ecce autem alii minuti et angusti aut omnia semper desperantes aut malivoli, invidi, difficiles, lucifugi, maledici, monstruosi, alii autem etiam amatoriis levitatibus dediti, alii petulantes, alii audaces, protervi, idem intemperantes et ignavi, numquam in sententia permanentes, quas ob causas in eorum vita nulla est intercapedo molestiae. igitur neque stultorum quisquam beatus neque sapientium non beatus. Multoque hoc melius nos veriusque quam Stoici. illi enim negant esse bonum quicquam nisi nescio quam illam umbram, quod appellant honestum non tam solido quam splendido nomine, virtutem autem nixam hoc honesto nullam requirere voluptatem atque ad beate vivendum se ipsa esse contentam.
+Sed possunt haec quadam ratione dici non modo non repugnantibus, verum etiam approbantibus nobis. sic enim ab Epicuro sapiens semper beatus inducitur: finitas habet cupiditates, neglegit mortem, de diis inmortalibus sine ullo metu vera sentit, non dubitat, si ita melius sit, migrare de vita. his rebus instructus semper est in voluptate. neque enim tempus est ullum, quo non plus voluptatum habeat quam dolorum. nam et praeterita grate meminit et praesentibus ita potitur, ut animadvertat quanta sint ea quamque iucunda, neque pendet ex futuris, sed expectat illa, fruitur praesentibus ab iisque vitiis, quae paulo ante collegi, abest plurimum et, cum stultorum vitam cum sua comparat, magna afficitur voluptate. dolores autem si qui incurrunt, numquam vim tantam habent, ut non plus habeat sapiens, quod gaudeat, quam quod angatur.
+Optime vero Epicurus, quod exiguam dixit fortunam intervenire sapienti maximasque ab eo et gravissimas res consilio ipsius et ratione administrari neque maiorem voluptatem ex infinito tempore aetatis percipi posse, quam ex hoc percipiatur, quod videamus esse finitum. In dialectica autem vestra nullam existimavit esse nec ad melius vivendum nec ad commodius disserendum viam. In physicis plurimum posuit. ea scientia et verborum vis et natura orationis et consequentium repugnantiumve ratio potest perspici. omnium autem rerum natura cognita levamur superstitione, liberamur mortis metu, non conturbamur ignoratione rerum, e qua ipsa horribiles existunt saepe formidines. denique etiam morati melius erimus, cum didicerimus quid natura desideret. tum vero, si stabilem scientiam rerum tenebimus, servata illa, quae quasi delapsa de caelo est ad cognitionem omnium, regula, ad quam omnia iudicia rerum dirigentur, numquam ullius oratione victi sententia desistemus.
+Nisi autem rerum natura perspecta erit, nullo modo poterimus sensuum iudicia defendere. quicquid porro animo cernimus, id omne oritur a sensibus; qui si omnes veri erunt, ut Epicuri ratio docet, tum denique poterit aliquid cognosci et percipi. quos qui tollunt et nihil posse percipi dicunt, ii remotis sensibus ne id ipsum quidem expedire possunt, quod disserunt. praeterea sublata cognitione et scientia tollitur omnis ratio et vitae degendae et rerum gerendarum. sic e physicis et fortitudo sumitur contra mortis timorem et constantia contra metum religionis et sedatio animi omnium rerum occultarum ignoratione sublata et moderatio natura cupiditatum generibusque earum explicatis, et, ut modo docui, cognitionis regula et iudicio ab eadem illa constituto veri a falso distinctio traditur.
+Restat locus huic disputationi vel maxime necessarius de amicitia, quam, si voluptas summum sit bonum, affirmatis nullam omnino fore. de qua Epicurus quidem ita dicit, omnium rerum, quas ad beate vivendum sapientia comparaverit, nihil esse maius amicitia, nihil uberius, nihil iucundius. nec vero hoc oratione solum, sed multo magis vita et factis et moribus comprobavit. quod quam magnum sit fictae veterum fabulae declarant, in quibus tam multis tamque variis ab ultima antiquitate repetitis tria vix amicorum paria reperiuntur, ut ad Orestem pervenias profectus a Theseo. at vero Epicurus una in domo, et ea quidem angusta, quam magnos quantaque amoris conspiratione consentientis tenuit amicorum greges! quod fit etiam nunc ab Epicureis. sed ad rem redeamus; de hominibus dici non necesse est.
+Tribus igitur modis video esse a nostris de amicitia disputatum. alii cum eas voluptates, quae ad amicos pertinerent, negarent esse per se ipsas tam expetendas, quam nostras expeteremus, quo loco videtur quibusdam stabilitas amicitiae vacillare, tuentur tamen eum locum seque facile, ut mihi videtur, expediunt. ut enim virtutes, de quibus ante dictum est, sic amicitiam negant posse a voluptate discedere. nam cum solitudo et vita sine amicis insidiarum et metus plena sit, ratio ipsa monet amicitias comparare, quibus partis confirmatur animus et a spe pariendarum voluptatum seiungi non potest.
+Atque ut odia, invidiae, despicationes adversantur voluptatibus, sic amicitiae non modo fautrices fidelissimae, sed etiam effectrices sunt voluptatum tam amicis quam sibi, quibus non solum praesentibus fruuntur, sed etiam spe eriguntur consequentis ac posteri temporis. quod quia nullo modo sine amicitia firmam et perpetuam iucunditatem vitae tenere possumus neque vero ipsam amicitiam tueri, nisi aeque amicos et nosmet ipsos diligamus, idcirco et hoc ipsum efficitur in amicitia, et amicitia cum voluptate conectitur. nam et laetamur amicorum laetitia aeque atque nostra et pariter dolemus angoribus.
+Quocirca eodem modo sapiens erit affectus erga amicum, quo in se ipsum, quosque labores propter suam voluptatem susciperet, eosdem suscipiet propter amici voluptatem. quaeque de virtutibus dicta sunt, quem ad modum eae semper voluptatibus inhaererent, eadem de amicitia dicenda sunt. praeclare enim Epicurus his paene verbis: 'Eadem', inquit, 'scientia confirmavit animum, ne quod aut sempiternum aut diuturnum timeret malum, quae perspexit in hoc ipso vitae spatio amicitiae praesidium esse firmissimum.'
+Sunt autem quidam Epicurei timidiores paulo contra vestra convicia, sed tamen satis acuti, qui verentur ne, si amicitiam propter nostram voluptatem expetendam putemus, tota amicitia quasi claudicare videatur. itaque primos congressus copulationesque et consuetudinum instituendarum voluntates fieri propter voluptatem; cum autem usus progrediens familiaritatem effecerit, tum amorem efflorescere tantum, ut, etiamsi nulla sit utilitas ex amicitia, tamen ipsi amici propter se ipsos amentur. etenim si loca, si fana, si urbes, si gymnasia, si campum, si canes, si equos, si ludicra exercendi aut venandi consuetudine adamare solemus, quanto id in hominum consuetudine facilius fieri poterit et iustius?
+Sunt autem, qui dicant foedus esse quoddam sapientium, ut ne minus amicos quam se ipsos diligant. quod et posse fieri intellegimus et saepe etiam videmus, et perspicuum est nihil ad iucunde vivendum reperiri posse, quod coniunctione tali sit aptius. Quibus ex omnibus iudicari potest non modo non impediri rationem amicitiae, si summum bonum in voluptate ponatur, sed sine hoc institutionem omnino amicitiae non posse reperiri.
+Quapropter si ea, quae dixi, sole ipso illustriora et clariora sunt, si omnia dixi hausta e fonte naturae, si tota oratio nostra omnem sibi fidem sensibus confirmat, id est incorruptis atque integris testibus, si infantes pueri, mutae etiam bestiae paene loquuntur magistra ac duce natura nihil esse prosperum nisi voluptatem, nihil asperum nisi dolorem, de quibus neque depravate iudicant neque corrupte, nonne ei maximam gratiam habere debemus, qui hac exaudita quasi voce naturae sic eam firme graviterque comprehenderit, ut omnes bene sanos in viam placatae, tranquillae, quietae, beatae vitae deduceret? Qui quod tibi parum videtur eruditus, ea causa est, quod nullam eruditionem esse duxit, nisi quae beatae vitae disciplinam iuvaret.
+An ille tempus aut in poetis evolvendis, ut ego et Triarius te hortatore facimus, consumeret, in quibus nulla solida utilitas omnisque puerilis est delectatio, aut se, ut Plato, in musicis, geometria, numeris, astris contereret, quae et a falsis initiis profecta vera esse non possunt et, si essent vera, nihil afferrent, quo iucundius, id est quo melius viveremus, eas ergo artes persequeretur, vivendi artem tantam tamque et operosam et perinde fructuosam relinqueret? non ergo Epicurus ineruditus, sed ii indocti, qui, quae pueros non didicisse turpe est, ea putant usque ad senectutem esse discenda.
+Quae cum dixisset, Explicavi, inquit, sententiam meam, et eo quidem consilio, tuum iudicium ut cognoscerem, quoniam mihi ea facultas, ut id meo arbitratu facerem, ante hoc tempus numquam est data.
diff --git a/benchmarks/markdown/engines/Makefile b/benchmarks/markdown/engines/Makefile
new file mode 100644 (file)
index 0000000..588e744
--- /dev/null
@@ -0,0 +1,31 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2015 Alexandre Terrasa <alexandre@moz-code.org>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+all: nitmd/nitmd txtmark/Txtmark.class markdown4j/Markdown4j.class
+
+nitmd/nitmd:
+       make -C nitmd
+
+txtmark/Txtmark.class:
+       make -C txtmark
+
+markdown4j/Markdown4j.class:
+       make -C markdown4j
+
+clean:
+       make -C nitmd clean
+       make -C txtmark clean
+       make -C markdown4j clean
diff --git a/benchmarks/markdown/engines/markdown4j/Makefile b/benchmarks/markdown/engines/markdown4j/Makefile
new file mode 100644 (file)
index 0000000..eff078b
--- /dev/null
@@ -0,0 +1,28 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2015 Alexandre Terrasa <alexandre@moz-code.org>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+Markdown4j.class: markdown4j-2.2.jar
+       javac -cp markdown4j-2.2.jar Markdown4j.java
+
+markdown4j-2.2.jar:
+       wget https://markdown4j.googlecode.com/files/markdown4j-2.2.jar
+
+test: Markdown4j.class
+       java -cp .:markdown4j-2.2.jar Markdown4j ../../benches/hello.md 5
+
+clean:
+       rm -rf markdown4j-2.2.jar
+       rm -rf Markdown4j.class
diff --git a/benchmarks/markdown/engines/markdown4j/Markdown4j.java b/benchmarks/markdown/engines/markdown4j/Markdown4j.java
new file mode 100644 (file)
index 0000000..547b9ac
--- /dev/null
@@ -0,0 +1,12 @@
+import com.github.rjeschke.txtmark.Processor;
+import java.io.File;
+import java.io.IOException;
+
+public class Markdown4j {
+       public static void main(String[] args) throws IOException {
+               int n = Integer.parseInt(args[1]);
+               for(int i = 0; i < n; i++) {
+                       System.out.println(Processor.process(new File(args[0])));
+               }
+       }
+}
diff --git a/benchmarks/markdown/engines/nitmd/Makefile b/benchmarks/markdown/engines/nitmd/Makefile
new file mode 100644 (file)
index 0000000..aa79fbc
--- /dev/null
@@ -0,0 +1,24 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2015 Alexandre Terrasa <alexandre@moz-code.org>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+nitmd:
+       nitc nitmd.nit
+
+test: nitmd
+       ./nitmd ../../benches/hello.md 5
+
+clean:
+       rm -rf nitmd
diff --git a/benchmarks/markdown/engines/nitmd/nitmd.nit b/benchmarks/markdown/engines/nitmd/nitmd.nit
new file mode 100644 (file)
index 0000000..2db91b2
--- /dev/null
@@ -0,0 +1,24 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import markdown
+
+var file = args.first
+var n = args[1].to_i
+
+var str = file.to_path.read_all
+var parser = new MarkdownProcessor
+for i in [1..n] do
+       print parser.process(str)
+end
diff --git a/benchmarks/markdown/engines/txtmark/Makefile b/benchmarks/markdown/engines/txtmark/Makefile
new file mode 100644 (file)
index 0000000..0c119d0
--- /dev/null
@@ -0,0 +1,27 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2015 Alexandre Terrasa <alexandre@moz-code.org>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+Txtmark.class: txtmark-0.11.jar
+       javac -cp txtmark-0.11.jar Txtmark.java
+
+txtmark-0.11.jar:
+       wget -O txtmark-0.11.jar http://search.maven.org/remotecontent?filepath=com/github/rjeschke/txtmark/0.11/txtmark-0.11.jar
+
+test: Txtmark.class
+       java -cp .:txtmark-0.11.jar Txtmark ../../benches/hello.md 5
+
+clean:
+       rm -rf txtmark-0.11.jar Txtmark.class
diff --git a/benchmarks/markdown/engines/txtmark/Txtmark.java b/benchmarks/markdown/engines/txtmark/Txtmark.java
new file mode 100644 (file)
index 0000000..dfca8c6
--- /dev/null
@@ -0,0 +1,12 @@
+import com.github.rjeschke.txtmark.Processor;
+import java.io.File;
+import java.io.IOException;
+
+public class Txtmark {
+       public static void main(String[] args) throws IOException {
+               int n = Integer.parseInt(args[1]);
+               for(int i = 0; i < n; i++) {
+                       System.out.println(Processor.process(new File(args[0])));
+               }
+       }
+}
index 0da3c77..ed456f6 100644 (file)
@@ -27,7 +27,6 @@ class CodeGenerator
        var java_class: JavaClass
        var nb_params: Int
        var module_name: String
-       fun code_warehouse: CodeWarehouse do return once new CodeWarehouse
 
        init (file_name: String, jclass: JavaClass, with_attributes, comment: Bool)
        do
@@ -81,9 +80,8 @@ class CodeGenerator
 
        fun gen_licence: String
        do
-               return """# This file is part of NIT (http://www.nitlanguage.org).
-#
-# Copyright [Year] [Author name] <Author e-mail>
+               return """
+# 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.
@@ -97,7 +95,7 @@ class CodeGenerator
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# This code has been generated using `javap`
+# This code has been generated using `jwrapper`
 """
        end
 
@@ -229,33 +227,6 @@ class CodeGenerator
        end
 end
 
-# Contains raw code mostly used to copy collections
-class CodeWarehouse
-
-       private fun create_imports(nit_type: NitType, is_param: Bool): String
-       do
-               var imports = ""
-               var ntype = nit_type.to_s
-               var gen_type = nit_type.generic_params.join(", ")
-
-               if not is_param then
-                       if nit_type.is_map then
-                               imports = """ import {{{ntype}}}, {{{ntype}}}.[]="""
-                       else
-                               imports = """ import {{{ntype}}}, {{{ntype}}}.add"""
-                       end
-               else if nit_type.id == "Array" then
-                       imports = """ import {{{ntype}}}, {{{ntype}}}.length, {{{ntype}}}.[]"""
-               else if nit_type.is_map then
-                       imports = """ import {{{ntype}}}.iterator, Iterator[{{{gen_type}}}].is_ok, Iterator[{{{gen_type}}}].next, Iterator[{{{gen_type}}}].item, Iterator[{{{gen_type}}}].key"""
-               else
-                       imports = """ import {{{ntype}}}.iterator, Iterator[{{{gen_type}}}].is_ok, Iterator[{{{gen_type}}}].next, Iterator[{{{gen_type}}}].item"""
-               end
-
-               return imports
-       end
-end
-
 redef class String
        # Convert the Java method name `self` to the Nit style
        #
@@ -264,16 +235,13 @@ redef class String
        # * Add suffix `=` to setters
        fun to_nit_method_name: String
        do
-               var name
-               if self.has_prefix("Get") then
-                       name = self.substring_from(3)
-               else if self.has_prefix("Set") then
-                       name = self.substring_from(3)
-                       name += "="
-               else
-                       name = self
+               var name = self.to_snake_case
+               if name.has_prefix("get_") then
+                       name = name.substring_from(4)
+               else if name.has_prefix("set_") then
+                       name = name.substring_from(4) + "="
                end
 
-               return name.to_snake_case
+               return name
        end
 end
index 9ee4190..64415a4 100644 (file)
@@ -61,6 +61,22 @@ class JavaVisitor
                self.variable_type = new JavaType(self.converter)
                super
        end
+
+       # Add the identifier from `token` to the current context
+       fun add_identifier(token: NToken)
+       do
+               if declaration_type == "variable" then
+                       if declaration_element == "type" then
+                               variable_type.identifier.add(token.text)
+                       end
+               else if declaration_type == "method" then
+                       if declaration_element == "return_type" then
+                               method_return_type.identifier.add(token.text)
+                       else if declaration_element == "parameter_list" then
+                               method_params[param_index].identifier.add(token.text)
+                       end
+               end
+       end
 end
 
 redef class Node
@@ -162,139 +178,35 @@ redef class N_39d_91d_93d_39d
 end
 
 redef class N_39dchar_39d
-       redef fun accept_visitor(v)
-       do
-               if v.declaration_type == "variable" then
-                       if v.declaration_element == "type" then
-                               v.variable_type.identifier.add(self.text)
-                       end
-               else if v.declaration_type == "method" then
-                       if v.declaration_element == "return_type" then
-                               v.method_return_type.identifier.add(self.text)
-                       else if v.declaration_element == "parameter_list" then
-                               v.method_params[v.param_index].identifier.add(self.text)
-                       end
-               end
-       end
+       redef fun accept_visitor(v) do v.add_identifier self
 end
 
 redef class N_39dboolean_39d
-       redef fun accept_visitor(v)
-       do
-               if v.declaration_type == "variable" then
-                       if v.declaration_element == "type" then
-                               v.variable_type.identifier.add(self.text)
-                       end
-               else if v.declaration_type == "method" then
-                       if v.declaration_element == "return_type" then
-                               v.method_return_type.identifier.add(self.text)
-                       else if v.declaration_element == "parameter_list" then
-                               v.method_params[v.param_index].identifier.add(self.text)
-                       end
-               end
-       end
+       redef fun accept_visitor(v) do v.add_identifier self
 end
 
 redef class N_39dfloat_39d
-       redef fun accept_visitor(v)
-       do
-               if v.declaration_type == "variable" then
-                       if v.declaration_element == "type" then
-                               v.variable_type.identifier.add(self.text)
-                       end
-               else if v.declaration_type == "method" then
-                       if v.declaration_element == "return_type" then
-                               v.method_return_type.identifier.add(self.text)
-                       else if v.declaration_element == "parameter_list" then
-                               v.method_params[v.param_index].identifier.add(self.text)
-                       end
-               end
-       end
+       redef fun accept_visitor(v) do v.add_identifier self
 end
 
 redef class N_39ddouble_39d
-       redef fun accept_visitor(v)
-       do
-               if v.declaration_type == "variable" then
-                       if v.declaration_element == "type" then
-                               v.variable_type.identifier.add(self.text)
-                       end
-               else if v.declaration_type == "method" then
-                       if v.declaration_element == "return_type" then
-                               v.method_return_type.identifier.add(self.text)
-                       else if v.declaration_element == "parameter_list" then
-                               v.method_params[v.param_index].identifier.add(self.text)
-                       end
-               end
-       end
+       redef fun accept_visitor(v) do v.add_identifier self
 end
 
 redef class N_39dbyte_39d
-       redef fun accept_visitor(v)
-       do
-               if v.declaration_type == "variable" then
-                       if v.declaration_element == "type" then
-                               v.variable_type.identifier.add(self.text)
-                       end
-               else if v.declaration_type == "method" then
-                       if v.declaration_element == "return_type" then
-                               v.method_return_type.identifier.add(self.text)
-                       else if v.declaration_element == "parameter_list" then
-                               v.method_params[v.param_index].identifier.add(self.text)
-                       end
-               end
-       end
+       redef fun accept_visitor(v) do v.add_identifier self
 end
 
 redef class N_39dshort_39d
-       redef fun accept_visitor(v)
-       do
-               if v.declaration_type == "variable" then
-                       if v.declaration_element == "type" then
-                               v.variable_type.identifier.add(self.text)
-                       end
-               else if v.declaration_type == "method" then
-                       if v.declaration_element == "return_type" then
-                               v.method_return_type.identifier.add(self.text)
-                       else if v.declaration_element == "parameter_list" then
-                               v.method_params[v.param_index].identifier.add(self.text)
-                       end
-               end
-       end
+       redef fun accept_visitor(v) do v.add_identifier self
 end
 
 redef class N_39dint_39d
-       redef fun accept_visitor(v)
-       do
-               if v.declaration_type == "variable" then
-                       if v.declaration_element == "type" then
-                               v.variable_type.identifier.add(self.text)
-                       end
-               else if v.declaration_type == "method" then
-                       if v.declaration_element == "return_type" then
-                               v.method_return_type.identifier.add(self.text)
-                       else if v.declaration_element == "parameter_list" then
-                               v.method_params[v.param_index].identifier.add(self.text)
-                       end
-               end
-       end
+       redef fun accept_visitor(v) do v.add_identifier self
 end
 
 redef class N_39dlong_39d
-       redef fun accept_visitor(v)
-       do
-               if v.declaration_type == "variable" then
-                       if v.declaration_element == "type" then
-                               v.variable_type.identifier.add(self.text)
-                       end
-               else if v.declaration_type == "method" then
-                       if v.declaration_element == "return_type" then
-                               v.method_return_type.identifier.add(self.text)
-                       else if v.declaration_element == "parameter_list" then
-                               v.method_params[v.param_index].identifier.add(self.text)
-                       end
-               end
-       end
+       redef fun accept_visitor(v) do v.add_identifier self
 end
 
 #                                  #
index b77c734..cb99a23 100644 (file)
@@ -85,8 +85,6 @@ class JavaType
 
        fun is_collection: Bool do return is_primitive_array or collections_list.has(self.id)
 
-       fun is_map: Bool do return maps.has(self.id)
-
        fun is_wrapped: Bool do return find_extern_class != null
 
        fun extern_name: NitType
@@ -249,7 +247,6 @@ class NitType
        var is_complete: Bool = true
 
        fun has_generic_params: Bool do return not generic_params == null
-       fun maps: Array[String] is cached do return ["HashMap", "RBTreeMap"]
 
        fun id: String do return identifier
 
@@ -271,8 +268,6 @@ class NitType
                self.mod = mod
        end
 
-       fun is_map: Bool do return maps.has(self.identifier)
-
        redef fun to_s: String
        do
                var id = self.identifier
index 7f213b7..89546ce 100644 (file)
@@ -81,6 +81,7 @@ redef class WikiSection
                end
                var index = self.index
                if index isa WikiSectionIndex then
+                       wiki.message("Render auto-index for section {out_path}", 1)
                        index.is_dirty = true
                        add_child index
                end
@@ -322,6 +323,10 @@ class WikiSectionIndex
        # The section described by `self`.
        var section: WikiSection
 
+       redef fun title do return section.title
+
+       redef fun url do return section.url
+
        redef var is_dirty = false
 
        redef fun tpl_article do
index adf25a7..25f17ab 100644 (file)
@@ -1 +1,6 @@
 Render section out
+Render section out/sec1
+Render section out/sec2
+Render auto-index for section out/sec2
+Render section out/sec2/sub-sec21
+Render section out/sec2/sub-sec22
index 936a764..9eb2262 100644 (file)
@@ -6,5 +6,12 @@ url: http://localhost/
 There is modified files:
  + pages
  + /pages/index.md
+ + pages/sec1
+ + /pages/sec1/index.md
+ + pages/sec2
+ + pages/sec2/sub-sec21
+ + /pages/sec2/sub-sec21/index.md
+ + pages/sec2/sub-sec22
+ + /pages/sec2/sub-sec22/index.md
 
 Use nitiwiki --render to render modified files
index dacc9ff..b991952 100644 (file)
@@ -20,8 +20,8 @@
 # analysis results. The result graph will be sent to the JavaScript function
 # `show_graph` with the source of the graph in Graphviz's dot.
 module pep8analysis_web is
-       cpp_compiler_option("--std=c++11 --bind")
-       c_linker_option("--bind")
+       cppflags "--std=c++11 --bind"
+       ldflags "--bind"
 end
 
 import emscripten
index f16f885..43cdcc4 100644 (file)
@@ -1,6 +1,8 @@
 all:
        mkdir -p bin/
-       ../../bin/nitc --dir bin/ src/calculator_gtk.nit src/calculator_test.nit
+
+       # Compile in global mode to silence warnings on unused GTK deprecated
+       ../../bin/nitc --global --dir bin/ src/calculator_gtk.nit src/calculator_test.nit
 
 android:
        mkdir -p bin/ res/
index bd2bd11..bd01986 100644 (file)
@@ -21,17 +21,18 @@ import calculator_logic
 
 import gtk
 
+# GTK calculator UI
 class CalculatorGui
        super GtkCallable
 
-       var win : GtkWindow is noinit
-       var container : GtkGrid is noinit
+       private var win: GtkWindow is noinit
+       private var container: GtkGrid is noinit
 
-       var lbl_disp : GtkLabel is noinit
-       var but_eq : GtkButton is noinit
-       var but_dot : GtkButton is noinit
+       private var lbl_disp: GtkLabel is noinit
+       private var but_eq: GtkButton is noinit
+       private var but_dot: GtkButton is noinit
 
-       var context = new CalculatorContext
+       private var context = new CalculatorContext
 
        redef fun signal(sender, op)
        do
@@ -54,57 +55,57 @@ class CalculatorGui
        do
                init_gtk
 
-               win = new GtkWindow( 0 )
+               win = new GtkWindow(0)
 
-               container = new GtkGrid(5,5,true)
-               win.add( container )
+               container = new GtkGrid(5, 5, true)
+               win.add(container)
 
-               lbl_disp = new GtkLabel( "_" )
-               container.attach( lbl_disp, 0, 0, 5, 1 )
+               lbl_disp = new GtkLabel("_")
+               container.attach(lbl_disp, 0, 0, 5, 1)
 
-               # digits
+               # Digits
                for n in [0..9] do
-                       var but = new GtkButton.with_label( n.to_s )
-                       but.request_size( 64, 64 )
-                       but.signal_connect( "clicked", self, n )
+                       var but = new GtkButton.with_label(n.to_s)
+                       but.request_size(64, 64)
+                       but.signal_connect("clicked", self, n)
                        if n == 0 then
-                               container.attach( but, 0, 4, 1, 1 )
-                       else container.attach( but, (n-1)%3, 3-(n-1)/3, 1, 1 )
+                               container.attach(but, 0, 4, 1, 1)
+                       else container.attach(but, (n-1)%3, 3-(n-1)/3, 1, 1)
                end
 
-               # operators
+               # Operators
                var r = 1
-               for op in ['+', '-', '*', '/' ] do
-                       var but = new GtkButton.with_label( op.to_s )
-                       but.request_size( 64, 64 )
-                       but.signal_connect( "clicked", self, op )
-                       container.attach( but, 3, r, 1, 1 )
+               for op in ['+', '-', '*', '/'] do
+                       var but = new GtkButton.with_label(op.to_s)
+                       but.request_size(64, 64)
+                       but.signal_connect("clicked", self, op)
+                       container.attach(but, 3, r, 1, 1)
                        r+=1
                end
 
                # =
-               but_eq = new GtkButton.with_label( "=" )
-               but_eq.request_size( 64, 64 )
-               but_eq.signal_connect( "clicked", self, '=' )
-               container.attach( but_eq, 4, 3, 1, 2 )
+               but_eq = new GtkButton.with_label("=")
+               but_eq.request_size(64, 64)
+               but_eq.signal_connect("clicked", self, '=')
+               container.attach(but_eq, 4, 3, 1, 2)
 
                # .
-               but_dot = new GtkButton.with_label( "." )
-               but_dot.request_size( 64, 64 )
-               but_dot.signal_connect( "clicked", self, '.' )
-               container.attach( but_dot, 1, 4, 1, 1 )
-
-               #C
-               var but_c =  new GtkButton.with_label( "C" )
-               but_c.request_size( 64, 64 )
+               but_dot = new GtkButton.with_label(".")
+               but_dot.request_size(64, 64)
+               but_dot.signal_connect("clicked", self, '.')
+               container.attach(but_dot, 1, 4, 1, 1)
+
+               # C
+               var but_c =  new GtkButton.with_label("C")
+               but_c.request_size(64, 64)
                but_c.signal_connect("clicked", self, 'C')
-               container.attach( but_c, 2, 4, 1, 1 )
+               container.attach(but_c, 2, 4, 1, 1)
 
                win.show_all
        end
 end
 
-# graphical application
+# Do not show GUI in when testing
 if "NIT_TESTING".environ == "true" then exit 0
 
 var app = new CalculatorGui
index c5fbaf7..57d3b5a 100644 (file)
@@ -1,7 +1,5 @@
 # This file is part of NIT ( http://www.nitlanguage.org ).
 #
-# Copyright 2013-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
 # Business logic of a calculator
 module calculator_logic
 
+# Hold the state of the calculator and its services
 class CalculatorContext
+       # Result of the last operation
        var result: nullable Numeric = null
 
+       # Last operation pushed with `push_op`, to be executed on the next push
        var last_op: nullable Char = null
 
+       # Value currently being entered
        var current: nullable FlatBuffer = null
+
+       # Text to display on screen
        fun display_text: String
        do
                var result = result
@@ -51,7 +55,8 @@ class CalculatorContext
                return buf.to_s
        end
 
-       fun push_op( op : Char )
+       # Push operation `op`, will usually execute the last operation
+       fun push_op(op: Char)
        do
                apply_last_op_if_any
                if op == 'C' then
@@ -65,7 +70,8 @@ class CalculatorContext
                self.current = null
        end
 
-       fun push_digit( digit : Int )
+       # Push a digit
+       fun push_digit(digit: Int)
        do
                var current = current
                if current == null then current = new FlatBuffer
@@ -78,6 +84,7 @@ class CalculatorContext
                end
        end
 
+       # Switch entry mode from integer to decimal
        fun switch_to_decimals
        do
                var current = current
@@ -86,7 +93,8 @@ class CalculatorContext
                self.current = current
        end
 
-       fun apply_last_op_if_any
+       # Execute the last operation it not null
+       protected fun apply_last_op_if_any
        do
                var op = last_op
 
@@ -106,6 +114,7 @@ class CalculatorContext
                else if op == '*' then
                        result = result.mul(current.to_n)
                end
+
                self.result = result
                self.current = null
        end
index da43c8f..fa1d020 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
-    <dimen name="test_dimen_1">25dp</dimen>
-    <dimen name="test_dimen_2">150dp</dimen>
-</resources> 
+    <dimen name="test_dimen_1">25px</dimen>
+    <dimen name="test_dimen_2">150px</dimen>
+</resources>
index decf7c5..88a2812 100644 (file)
@@ -21,27 +21,29 @@ import simple_android
 import android::audio
 
 redef class App
-       var soundsp: Sound
-       var soundmp: Sound
+       var soundsp: nullable Sound
+       var soundmp: nullable Sound
+       var test_assets = false
+       var test_ressources = true
 
-       redef fun init_window
+       redef fun window_created
        do
                super
-
-               default_mediaplayer.reset
-               manage_audio_mode
-
-               # Retrieve sound
-               soundsp = load_sound("sound.ogg")
-               soundmp = load_music("xylofon.ogg")
+               if test_assets then
+                       soundsp = load_sound("testsound.ogg")
+                       soundmp = load_music("xylofon.ogg")
+               end
+               if test_ressources then
+                       soundsp = load_sound_from_res("testsound")
+                       soundmp = load_music_from_res("xylofon")
+               end
                default_mediaplayer.looping = true
-               default_mediaplayer.prepare
                soundmp.play
        end
 
        redef fun input( ie )
        do
-               if ie isa PointerEvent and ie.depressed then 
+               if ie isa PointerEvent and ie.depressed then
                        soundsp.play
                end
                return super
diff --git a/examples/rosettacode/doors_with_classes.nit b/examples/rosettacode/doors_with_classes.nit
new file mode 100644 (file)
index 0000000..62c5f14
--- /dev/null
@@ -0,0 +1,34 @@
+#!/usr/bin/env nit
+#
+# This file is part of NIT ( http://www.nitlanguage.org ).
+# This program is public domain
+
+# Task: 100 doors
+# SEE: <http://rosettacode.org/wiki/100_doors>
+
+# A door with two states: open or closed
+class Door
+       # Is this door open?
+       var open = false
+
+       # Toggle bool value of open
+       fun toggle do open = not open
+
+       redef fun to_s: String
+       do
+               return if open then "Open" else "Closed"
+       end
+end
+
+var doors = new Array[Door]
+for door in [0..100[ do doors.add(new Door)
+
+var n = 100
+for visit in [0..n[ do
+       var i = visit
+       while i < n do
+               doors[i].toggle
+               i += visit+1
+       end
+end
+for i in [0..n[ do print "Door {i+1}: {doors[i]}"
index 82ae3d1..8195e2c 100644 (file)
@@ -102,6 +102,13 @@ extern class NativeAssetManager in "Java" `{ android.content.res.AssetManager `}
                }
                return afd;
        `}
+
+       # HACK for bug #845
+       redef fun new_global_ref import sys, Sys.jni_env `{
+               Sys sys = NativeResources_sys(recv);
+               JNIEnv *env = Sys_jni_env(sys);
+               return (*env)->NewGlobalRef(env, recv);
+       `}
 end
 
 # Assets manager using a `NativeAssetManager` to manage android assets
@@ -138,14 +145,18 @@ class AssetManager
 
        # Open an asset using ACCESS_STREAMING mode, returning a NativeInputStream
        fun open(file_name: String): NativeInputStream do
+               sys.jni_env.push_local_frame(1)
                var return_value =  native_assets_manager.open(file_name.to_java_string)
+               sys.jni_env.pop_local_frame
                return return_value
        end
 
        # Open an asset using it's name and returning a NativeAssetFileDescriptor
        # `file_name` is
        fun open_fd(file_name: String): NativeAssetFileDescriptor do
-               var return_value = native_assets_manager.open_fd(file_name.to_java_string)
+               sys.jni_env.push_local_frame(1)
+               var return_value = native_assets_manager.open_fd(file_name.to_java_string).new_global_ref
+               sys.jni_env.pop_local_frame
                return return_value
        end
 
@@ -158,7 +169,7 @@ class AssetManager
        # Return a bitmap from the assets
        fun bitmap(name: String): NativeBitmap do
                sys.jni_env.push_local_frame(1)
-               var return_value = new NativeBitmap.from_stream(native_assets_manager.open(name.to_java_string))
+               var return_value = new NativeBitmap.from_stream(native_assets_manager.open(name.to_java_string)).new_global_ref
                sys.jni_env.pop_local_frame
                return return_value
        end
@@ -291,6 +302,14 @@ extern class NativeBitmap in "Java" `{ android.graphics.Bitmap `}
        new from_resources(res: NativeResources, id: Int) in "Java" `{ return BitmapFactory.decodeResource(res, (int)id); `}
        fun width: Int in "Java" `{ return recv.getWidth(); `}
        fun height: Int in "Java" `{ return recv.getHeight(); `}
+
+       # HACK for bug #845
+       redef fun new_global_ref import sys, Sys.jni_env `{
+               Sys sys = NativeResources_sys(recv);
+               JNIEnv *env = Sys_jni_env(sys);
+               return (*env)->NewGlobalRef(env, recv);
+       `}
+
 end
 
 # Android AssetFileDescriptor, can be retrieve by AssetManager and used to load a sound in a SoundPool
@@ -337,6 +356,13 @@ extern class NativeAssetFileDescriptor in "Java" `{ android.content.res.AssetFil
        fun length: Int in "Java" `{ return (int)recv.getLength(); `}
        fun start_offset: Int in "Java" `{ return (int)recv.getStartOffset(); `}
        redef fun to_s: String import JavaString.to_s in "Java" `{ return JavaString_to_s(recv.toString()); `}
+
+       # HACK for bug #845
+       redef fun new_global_ref import sys, Sys.jni_env `{
+               Sys sys = NativeResources_sys(recv);
+               JNIEnv *env = Sys_jni_env(sys);
+               return (*env)->NewGlobalRef(env, recv);
+       `}
 end
 
 # Native class representing something drawable, can be retrieved from the resources
index 366c7d4..2301bd0 100644 (file)
@@ -1,4 +1,4 @@
-# this file is part of NIT ( http://www.nitlanguage.org ).
+# This file is part of NIT ( http://www.nitlanguage.org ).
 #
 # Copyright 2014 Romain Chanoir <romain.chanoir@viacesi.fr>
 #
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Android audio services
+# Android audio services, wraps a part of android audio API
 #
-# You can get a sound by loading it with a `SoundPool` or a `MediaPlayer`
-# the recommended way to load a sound is by it's resource ID or it's name
-# other ways are for advanced use
+# For this example, the sounds "test_sound" and "test_music" are located in the "assets/sounds" folder,
+# they both have ".ogg" extension. "test_sound" is a short sound and "test_music" a music track
+# ~~~nitish
+# # Note that you need to specify the path from "assets" folder and the extension
+# var s = app.load_sound("sounds/test_sound.ogg")
+# var m = app.load_music("sounds/test_music.ogg")
+# s.play
+# m.play
+# ~~~
+#
+# Now, the sounds are in "res/raw"
+# ~~~nitish
+# s = app.load_sound_from_res("test_sound")
+# m = app.load_music_from_res("test_sound")
+# s.play
+# m.play
+# ~~~
+#
+# See http://developer.android.com/reference/android/media/package-summary.html for more infos
 module audio
 
 import java
 import java::io
 import assets_and_resources
-import app
+import app::audio
 
 in "Java" `{
        import android.media.MediaPlayer;
        import android.media.SoundPool;
        import java.io.IOException;
        import android.media.AudioManager;
+       import android.media.AudioManager.OnAudioFocusChangeListener;
        import android.content.Context;
        import android.util.Log;
 `}
 
+# FIXME: This listener is not working at the moment, but is needed to gain or give up the audio focus
+# of the application
+in "Java inner" `{
+       static OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() {
+               public void onAudioFocusChange(int focusChange) {
+                       if(focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
+                       }else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
+                       }else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
+                       }
+               }
+       };
+`}
+
 # AudioManager of the application, used to manage the audio mode
 extern class NativeAudioManager in "Java" `{ android.media.AudioManager `}
        super JavaObject
 
+       # Current audio mode.
+       # ( MODE_NORMAL = 0, MODE_RINGTONE = 1, MODE_IN_CALL = 2 or MODE_IN_COMMUNICATION = 3 )
        fun mode: Int in "Java" `{ return recv.getMode(); `}
+
+       # Sets the audio mode.
+       # ( MODE_NORMAL = 0, MODE_RINGTONE = 1, MODE_IN_CALL = 2 or MODE_IN_COMMUNICATION = 3 )
        fun mode=(i: Int) in "Java" `{ recv.setMode((int)i); `}
-       fun wired_headset_on: Bool in "Java" `{ return recv.isWiredHeadsetOn(); `}
-       fun wired_headset_on=(b: Bool) in "Java" `{ recv.setWiredHeadsetOn(b); `}
-       fun speakerphone_on: Bool in "Java" `{ return recv.isSpeakerphoneOn(); `}
-       fun speakerphone_on=(b: Bool) in "Java" `{ recv.setSpeakerphoneOn(b); `}
-       fun manage_audio_mode in "Java" `{
-               recv.setMode(0);
-               if (recv.isWiredHeadsetOn()) {
-                       recv.setSpeakerphoneOn(false);
-               } else {
-                       recv.setSpeakerphoneOn(true);
-               }
+
+       # Sends a request to obtain audio focus
+       fun request_audio_focus: Int in "Java" `{
+               return recv.requestAudioFocus(afChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
        `}
 
+       # Gives up audio focus
+       fun abandon_audio_focus: Int in "Java" `{ return recv.abandonAudioFocus(afChangeListener); `}
 end
 
 # Media Player from Java, used to play long sounds or musics, not simultaneously
 # This is a low-level class, use `MediaPlater` instead
-extern class NativeMediaPlayer in "Java" `{ android.media.MediaPlayer `}
+private extern class NativeMediaPlayer in "Java" `{ android.media.MediaPlayer `}
        super JavaObject
 
-       new in "Java" `{ return new MediaPlayer(); `}
+       new in "Java" `{
+               MediaPlayer mp = new MediaPlayer();
+               mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
+               return mp;
+       `}
        fun start in "Java" `{ recv.start(); `}
        fun prepare in "Java" `{
                try {
@@ -104,7 +138,7 @@ end
 
 # Sound Pool from Java, used to play sounds simultaneously
 # This is a low-level class, use `SoundPool`instead
-extern class NativeSoundPool in "Java" `{ android.media.SoundPool `}
+private extern class NativeSoundPool in "Java" `{ android.media.SoundPool `}
        super JavaObject
 
        new(max_streams, stream_type, src_quality: Int) in "Java" `{
@@ -165,7 +199,7 @@ class SoundPool
                return new SoundSP(null, nsoundpool.load_asset_fd(afd, priority), self)
        end
 
-       # Load the sound from it's resource id
+       # Load the sound from its resource id
        fun load_id(context: NativeActivity, id:Int): Sound do
                return new SoundSP(null, nsoundpool.load_id(context, id, priority), self)
        end
@@ -184,7 +218,7 @@ class SoundPool
                return nsoundpool.play(id, left_volume, right_volume, priority, looping, rate)
        end
 
-       # Load a sound by it's name in the resources, the sound must be in the `res/raw` folder
+       # Load a sound by its name in the resources, the sound must be in the `res/raw` folder
        fun load_name(resource_manager: ResourcesManager, context: NativeActivity, sound: String): Sound do
                var id = resource_manager.raw_id(sound)
                return new SoundSP(id, nsoundpool.load_id(context, id, priority), self)
@@ -231,8 +265,11 @@ end
 class MediaPlayer
        private var nmedia_player: NativeMediaPlayer is noinit
 
+       # Used to control the state of the mediaplayer
+       private var is_prepared = false is writable
+
        # The sound associated with this mediaplayer
-       var sound: nullable Sound = null
+       var sound: nullable Sound = null is writable
 
        # Create a new MediaPlayer, but no sound is attached, you'll need
        # to use `load_sound` before using it
@@ -249,20 +286,21 @@ class MediaPlayer
        fun load_sound(id: Int, context: NativeActivity): Sound do
                self.nmedia_player = self.nmedia_player.create(context, id)
                self.sound = new SoundMP(id, self)
+               self.is_prepared = true
                return self.sound.as(not null)
        end
 
-       # Starts or resume playback
+       # Starts or resumes playback
        # REQUIRE `self.sound != null`
        fun start do
-               assert sound != null
+               if not is_prepared then prepare
                nmedia_player.start
        end
 
        # Stops playback after playback has been stopped or paused
        # REQUIRE `self.sound != null`
        fun stop do
-               assert sound != null
+               is_prepared = false
                nmedia_player.stop
        end
 
@@ -271,6 +309,7 @@ class MediaPlayer
        fun prepare do
                assert sound != null
                nmedia_player.prepare
+               is_prepared = true
        end
 
        # Pauses playback
@@ -292,7 +331,7 @@ class MediaPlayer
        # Reset MediaPlayer to its initial state
        fun reset do nmedia_player.reset
 
-       # Sets the datasource (file-pathor http/rtsp URL) to use
+       # Sets the datasource (file-path or http/rtsp URL) to use
        fun data_source(path: String): Sound do
                sys.jni_env.push_local_frame(1)
                nmedia_player.data_source_path(path.to_java_string)
@@ -323,14 +362,10 @@ class MediaPlayer
        fun stream_type=(stream_type: Int) do nmedia_player.stream_type = stream_type
 end
 
-# Represents an android sound that can be played by a SoundPool or a MediaPlayer
-# The only way to get a sound is by a MediaPlayer, a SoundPool, or the App
-abstract class Sound
+redef class Sound
 
-       # The resource ID of this sound
+       # Resource ID of this sound
        var id: nullable Int
-
-       fun play is abstract
 end
 
 # Sound implemented with a SoundPool
@@ -350,6 +385,8 @@ class SoundSP
        end
 
        redef fun play do soundpool.play(soundpool_id)
+       redef fun pause do soundpool.pause_stream(soundpool_id)
+       redef fun resume do soundpool.resume(soundpool_id)
 end
 
 # Sound Implemented with a MediaPlayer
@@ -364,53 +401,81 @@ class SoundMP
                self.media_player = media_player
        end
 
-       redef fun play do self.media_player.start
+       redef fun play do media_player.start
+       redef fun pause do media_player.pause
+       redef fun resume do play
 end
 
 redef class App
 
+       # Sounds handled by the application, when you load a sound, it's added to this list.
+       # This array is used in `pause` and `resume`
+       private var sounds = new Array[Sound]
+
+       # Returns the default MediaPlayer of the application.
+       # When you load a music, it goes in this MediaPlayer.
+       # Use it for advanced sound management
        fun default_mediaplayer: MediaPlayer is cached do return new MediaPlayer
+
+       # Returns the default MediaPlayer of the application.
+       # When you load a short sound (not a music), it's added to this soundpool.
+       # Use it for advanced sound management.
        fun default_soundpool: SoundPool is cached do return new SoundPool
 
        # Get the native audio manager
-       private fun audio_manager: NativeAudioManager import native_activity in "Java" `{
+       fun audio_manager: NativeAudioManager import native_activity in "Java" `{
                return (AudioManager)App_native_activity(recv).getSystemService(Context.AUDIO_SERVICE);
        `}
 
-       # Manages whether the app sound need to be in headphones mode or not
-       # TODO: this method is not ideal, need to find a better way
-       fun manage_audio_mode import native_activity in "Java" `{
-               AudioManager manager = (AudioManager)App_native_activity(recv).getSystemService(Context.AUDIO_SERVICE);
-               manager.setMode(0);
-                       if (manager.isWiredHeadsetOn()) {
-                               manager.setSpeakerphoneOn(false);
-                       } else {
-                               manager.setSpeakerphoneOn(true);
-                       }
+       # Sets the stream of the app to STREAM_MUSIC.
+       # STREAM_MUSIC is the default stream used by android apps.
+       private fun manage_audio_stream import native_activity, native_app_glue in "Java" `{
+               App_native_activity(recv).setVolumeControlStream(AudioManager.STREAM_MUSIC);
        `}
 
-       # Retrieve a sound with a soundpool in the `assets` folder using it's name
+       # Retrieves a sound with a soundpool in the `assets` folder using its name.
        # Used to play short songs, can play multiple sounds simultaneously
-       fun load_sound(path: String): Sound do
-               return default_soundpool.load_asset_fd(asset_manager.open_fd(path))
+       redef fun load_sound(path: String): Sound do
+               return add_to_sounds(default_soundpool.load_asset_fd(asset_manager.open_fd(path)))
        end
 
-       # Retrieve a music with a media player in the `assets`folder using it's name
+       # Retrieves a music with a media player in the `assets` folder using its name.
        # Used to play long sounds or musics, can't play multiple sounds simultaneously
        fun load_music(path: String): Sound do
                var fd = asset_manager.open_fd(path)
-               var sound =  default_mediaplayer.data_source_fd(fd.file_descriptor, fd.start_offset, fd.length)
-               return sound
+               return add_to_sounds(default_mediaplayer.data_source_fd(fd.file_descriptor, fd.start_offset, fd.length))
        end
 
-       # same as `load_sound` but load the sound from the `res\raw` folder
+       # Same as `load_sound` but load the sound from the `res/raw` folder
        fun load_sound_from_res(sound_name: String): Sound do
-               return default_soundpool.load_name(resource_manager,self.native_activity, sound_name)
+               return add_to_sounds(default_soundpool.load_name(resource_manager,self.native_activity, sound_name))
        end
 
-       # same as `load_music` but load the sound from the `res\raw` folder
+       # Same as `load_music` but load the sound from the `res/raw` folder
        fun load_music_from_res(music: String): Sound do
-               return default_mediaplayer.load_sound(resource_manager.raw_id(music), self.native_activity)
+               return add_to_sounds(default_mediaplayer.load_sound(resource_manager.raw_id(music), self.native_activity))
        end
 
+       # Factorizes `sounds.add` to use it in `load_music`, `load_sound`, `load_music_from_res` and `load_sound_from_res`
+       private fun add_to_sounds(sound: Sound): Sound do
+               sounds.add(sound)
+               return sound
+       end
+
+       redef fun pause do
+               for s in sounds do s.pause
+               audio_manager.abandon_audio_focus
+       end
+
+       redef fun init_window do
+               super
+               audio_manager.request_audio_focus
+               manage_audio_stream
+       end
+
+       redef fun resume do
+               super
+               audio_manager.request_audio_focus
+               for s in sounds do s.resume
+       end
 end
diff --git a/lib/android/aware.nit b/lib/android/aware.nit
new file mode 100644 (file)
index 0000000..92a3a80
--- /dev/null
@@ -0,0 +1,20 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Android compatibility module
+#
+# Defines the `@android` annotation used to tag `ldflags` annotations.
+module aware is new_annotation(android)
index c766a16..55f21a5 100644 (file)
@@ -216,6 +216,8 @@ extern class AndroidKeyEvent `{AInputEvent *`}
                return 0;
        `}
 
+       redef fun name do return key_code.to_s
+
        # Was this event raised by the back key?
        fun is_back_key: Bool do return key_code == 4
 
index 30beb62..c165331 100644 (file)
@@ -15,7 +15,7 @@
 # limitations under the License.
 
 # Advanced Android logging services
-module log
+module log is ldflags "-llog"
 
 import platform
 
index fc5a19f..4ae4753 100644 (file)
@@ -36,7 +36,7 @@
 #   which is a subclass of `Activity` and `Context` (in Java). It represent
 #   main activity of the running application. Use it to get anything related
 #   to the `Context` and as anchor to execute Java UI code.
-module native_app_glue
+module native_app_glue is ldflags "-landroid"
 
 import platform
 import log
@@ -301,7 +301,10 @@ extern class NativeAppGlue `{ struct android_app* `}
        # We use the `userData` field of the C structure to store an handle to
        # the associated App
        private fun user_data: App `{ return recv->userData; `}
-       private fun user_data=(val: App) `{ recv->userData = val; `}
+       private fun user_data=(val: App) `{
+               App_incr_ref(val);
+               recv->userData = val;
+       `}
 
        # Fill this in with the function to process input events.  At this point
        # the event has already been pre-dispatched, and it will be finished upon
index fca03e0..7c15af5 100644 (file)
@@ -27,3 +27,4 @@ end
 
 import java
 import app
+import aware
index 98ee444..ae5d572 100644 (file)
@@ -331,22 +331,15 @@ extern class NativeTextView in "Java" `{ android.widget.TextView `}
 
        fun text=(value: JavaString) in "Java" `{
 
-               android.util.Log.d("Nity", "1");
                final TextView final_recv = recv;
                final String final_value = value;
 
-               android.util.Log.d("Nity", "4");
                ((NativeActivity)recv.getContext()).runOnUiThread(new Runnable() {
                        @Override
                        public void run()  {
-                               android.util.Log.d("Nity", "-5");
-                               android.util.Log.d("Nity", final_value);
-                               android.util.Log.d("Nity", "-5.5");
                                final_recv.setText(final_value);
-                               android.util.Log.d("Nity", "-6");
                        }
                });
-               android.util.Log.d("Nity", "7");
        `}
 
        fun enabled: Bool in "Java" `{ return recv.isEnabled(); `}
diff --git a/lib/app/audio.nit b/lib/app/audio.nit
new file mode 100644 (file)
index 0000000..de68bb9
--- /dev/null
@@ -0,0 +1,43 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Romain Chanoir <romain.chanoir@viacesi.fr>
+#
+# 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.
+
+# App audio abstraction
+#
+# Once the application has started (after `App.setup`)
+# use `App.load_sound` to get a sound
+# then `Sound.play` to play it
+module audio
+
+import app_base
+
+# Abstraction of a sound
+abstract class Sound
+
+       # Plays the sound
+       fun play is abstract
+
+       # Pauses the sound
+       fun pause is abstract
+
+       # Resumes the sound
+       fun resume is abstract
+end
+
+redef class App
+
+       # Loads a sound from the assets of the app, returns `null` if the loading failed
+       fun load_sound(name: String): nullable Sound do return null
+end
index d94ae8e..ae1b875 100644 (file)
--- a/lib/c.nit
+++ b/lib/c.nit
@@ -70,10 +70,10 @@ extern class NativeCArray `{ void * `}
        type E: nullable Object
 
        # Get element at `index`.
-       fun [](index: E): E is abstract
+       fun [](index: Int): E is abstract
 
        # Set `val` at `index`.
-       fun []=(index: E, val: E) is abstract
+       fun []=(index: Int, val: E) is abstract
 
        # Return pointer to the address to the second element of this array
        #
index 91bc87c..5fe0af2 100644 (file)
@@ -15,7 +15,7 @@
 # limitations under the License.
 
 # The Application Kit provides services to create GUI
-module app_kit is c_linker_option "-framework AppKit"
+module app_kit is ldflags "-framework AppKit"
 
 import foundation
 
index 99c6b12..09e1291 100644 (file)
@@ -20,7 +20,7 @@
 #
 # This wrapper of the Cocoa API regroups the Foundation Kit and the
 # Application Kit.
-module cocoa is c_linker_option "-framework Cocoa"
+module cocoa is ldflags "-framework Cocoa"
 
 import foundation
 import app_kit
index ab027fd..cbe8f08 100644 (file)
@@ -15,7 +15,7 @@
 # limitations under the License.
 
 # The Foundation Kit provides basic Objective-C classes and structures
-module foundation is c_linker_option "-framework Foundation"
+module foundation is ldflags "-framework Foundation"
 
 in "ObjC Header" `{
        #import <Foundation/Foundation.h>
index 6fe897a..78bb96c 100644 (file)
@@ -16,7 +16,7 @@
 
 # Offers features to interface with C++ code and libraries
 module cpp is
-       new_annotation cpp_compiler_option
+       new_annotation cppflags
 end
 
 # A pointer to a C++ std::string instance
index 5c50387..b664c8a 100644 (file)
 # C library. If a method or class is not documented in Nit, refer to
 # the official documentation by the Khronos Group at:
 # http://www.khronos.org/registry/egl/sdk/docs/man/xhtml/
-module egl is pkgconfig
+module egl is
+       pkgconfig
+       ldflags("-lEGL")@android
+end
+
+import android::aware
 
 in "C Header" `{
        #include <EGL/egl.h>
@@ -412,6 +417,12 @@ class EGLConfigChooser
        fun surface_type=(flag: Int) do insert_attrib_with_val(0x3033, flag)
        fun surface_type_egl do surface_type = 4
 
+       # Set which client rendering APIs are supported
+       fun renderable_type=(flag: Int) do insert_attrib_with_val(0x3040, flag)
+
+       # Set EGL as the only supported rendering API
+       fun renderable_type_egl do renderable_type = 4
+
        fun blue_size=(size: Int) do insert_attrib_with_val(0x3022, size)
        fun green_size=(size: Int) do insert_attrib_with_val(0x3023, size)
        fun red_size=(size: Int) do insert_attrib_with_val(0x3024, size)
index b979b5d..2655ae3 100644 (file)
@@ -133,7 +133,7 @@ class GithubAPI
 
        # Load the json object from Github.
        # See `GithubEntity::load_from_github`.
-       private fun load_from_github(key: String): JsonObject do
+       protected fun load_from_github(key: String): JsonObject do
                message(1, "Get {key} (github)")
                var res = get(key)
                if was_error then return new JsonObject
diff --git a/lib/github/cache.nit b/lib/github/cache.nit
new file mode 100644 (file)
index 0000000..559b4a8
--- /dev/null
@@ -0,0 +1,80 @@
+# 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.
+
+# Enable caching on Github API accesses.
+#
+# If `GithubAPI::enable_cache` is set to true then Github JSON responses
+# will be cached locally using `JsonStore`.
+#
+# Cache can be used to limit the number of access on the API and lighten
+# the rate limit on your github key.
+#
+# Usage:
+#
+# ~~~
+# var api = new GithubAPI(get_github_oauth)
+# api.enable_cache = true
+#
+# var name = "privat/nit"
+# assert not api.has_cache(name)
+# var repo = api.load_repo(name) # load from GitHub
+# assert api.has_cache(name)
+# repo = api.load_repo(name) # load from cache
+#
+# api.clear_cache
+# assert not api.has_cache(name)
+# ~~~
+module cache
+
+intrude import github::api
+import json::store
+
+redef class GithubAPI
+
+       # Enable caching for this client.
+       # Default is `false`.
+       var enable_cache = false is writable
+
+       # JsonStore used to cache data.
+       #
+       # Default directory is `".github_data/"`.
+       var store = new JsonStore(".github_data/") is writable, lazy
+
+       # Delete the cache directory.
+       fun clear_cache do store.clear
+
+       # If no cache data is found for `key` then json is loaded from Github API.
+       redef fun load_from_github(key) do
+               if not enable_cache then return super
+               if store.has_key(key) then
+                       message(1, "Get {key} (cache)")
+                       was_error = false
+                       return store.load_object(key)
+               end
+               var obj = super
+               if not was_error then cache(key, obj)
+               return obj
+       end
+
+       # Save `json` data in cache under `key`.
+       private fun cache(key: String, json: JsonObject) do
+               message(2, "Cache key {key}")
+               store.store_object(key, json)
+       end
+
+       # Check if a cache file exists for `key`.
+       fun has_cache(key: String): Bool do
+               return store.has_key(key)
+       end
+end
diff --git a/lib/github/events.nit b/lib/github/events.nit
new file mode 100644 (file)
index 0000000..b6e5af3
--- /dev/null
@@ -0,0 +1,302 @@
+# 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.
+
+# Events are emitted by Github Hooks.
+#
+# See <https://developer.github.com/v3/activity/events/types/>
+module events
+
+import api
+
+# Github event stub.
+class GithubEvent
+
+       # Github API client.
+       var api: GithubAPI
+
+       # Json representation of `self`.
+       var json: JsonObject is noinit
+
+       init do
+               json = new JsonObject
+       end
+
+       # Init `self` from a `json` object.
+       init from_json(api: GithubAPI, json: JsonObject) do
+               self.api = api
+               self.json = json
+       end
+
+       # Action performed by the event.
+       fun action: String do return json["action"].to_s
+
+       # Repo where this event occured.
+       fun repo: Repo do
+               return new Repo.from_json(api, json["repository"].as(JsonObject))
+       end
+end
+
+# Triggered when a commit comment is created.
+class CommitCommentEvent
+       super GithubEvent
+
+       # The `Comment` itself.
+       fun comment: CommitComment do
+               return new CommitComment.from_json(api, repo, json["comment"].as(JsonObject))
+       end
+end
+
+# Triggered when a repository, branch, or tag is created.
+class CreateEvent
+       super GithubEvent
+
+       # Oject type that was created.
+       #
+       # Can be one of `repository`, `branch`, or `tag`.
+       fun ref_type: String do return json["ref_type"].to_s
+
+       # Git ref (or null if only a repository was created).
+       fun ref: String do return json["ref"].to_s
+
+       # Name of the repo's default branch (usually master).
+       fun master_branch: String do return json["master_branch"].to_s
+
+       # Repo's current description.
+       fun description: String do return json["description"].to_s
+end
+
+# Triggered when a branch or a tag is deleted.
+class DeleteEvent
+       super GithubEvent
+
+       # Object type that was deleted.
+       #
+       # Can be one of `repository`, `branch`, or `tag`.
+       fun ref_type: String do return json["ref_type"].to_s
+
+       # Git ref (or null if only a repository was deleted).
+       fun ref: String do return json["ref"].to_s
+end
+
+# Triggered when a new snapshot is deployed.
+#
+# Deployement are mainly used with integration testing servers.
+class DeploymentEvent
+       super GithubEvent
+
+       # Commit SHA for which this deployment was created.
+       fun sha: String do return json["sha"].to_s
+
+       # Name of repository for this deployment, formatted as :owner/:repo.
+       fun name: String do return json["name"].to_s
+
+       # Optional extra information for this deployment.
+       fun payload: nullable String do
+               if not json.has_key("payload") then return null
+               return json["payload"].to_s
+       end
+
+       # Optional environment to deploy to.
+       # Default: "production"
+       fun environment: nullable String do
+               if not json.has_key("environment") then return null
+               return json["environment"].to_s
+       end
+
+       # Optional human-readable description added to the deployment.
+       fun description: nullable String do
+               if not json.has_key("description") then return null
+               return json["description"].to_s
+       end
+end
+
+# Triggered when a deployement's status changes.
+class DeploymentStatusEvent
+       super GithubEvent
+
+       # New deployment state.
+       #
+       # Can be `pending`, `success`, `failure`, or `error`.
+       fun state: String do return json["state"].to_s
+
+       # Optional link added to the status.
+       fun target_url: nullable String do
+               if not json.has_key("target_url") then return null
+               return json["target_url"].to_s
+       end
+
+       # Deployment hash that this status is associated with.
+       fun deployment: String do return json["deployment"].to_s
+
+       # Optional human-readable description added to the status.
+       fun description: nullable String do
+               if not json.has_key("description") then return null
+               return json["description"].to_s
+       end
+end
+
+# Triggered when a user forks a repository.
+class ForkEvent
+       super GithubEvent
+
+       # Created repository.
+       fun forkee: Repo do return new Repo.from_json(api, json["forkee"].as(JsonObject))
+end
+
+# Triggered when an issue comment is created.
+class IssueCommentEvent
+       super GithubEvent
+
+       # `Issue` the comment belongs to.
+       fun issue: Issue do
+               return new Issue.from_json(api, repo, json["issue"].as(JsonObject))
+       end
+
+       # The `Comment` itself.
+       fun comment: IssueComment do
+               return new IssueComment.from_json(api, repo, json["comment"].as(JsonObject))
+       end
+end
+
+# Triggered when an event occurs on an issue.
+#
+# Triggered when an issue is assigned, unassigned, labeled, unlabeled,
+# opened, closed or reopened.
+class IssuesEvent
+       super GithubEvent
+
+       # The `Issue` itself.
+       fun issue: Issue do return new Issue.from_json(api, repo, json["issue"].as(JsonObject))
+
+       # Optional `Label` that was added or removed from the issue.
+       fun lbl: nullable Label do
+               if not json.has_key("label") then return null
+               return new Label.from_json(api, repo, json["label"].as(JsonObject))
+       end
+
+       # Optional `User` that was assigned or unassigned from the issue.
+       fun assignee: nullable User do
+               if not json.has_key("assignee") then return null
+               return new User.from_json(api, json["assignee"].as(JsonObject))
+       end
+end
+
+# Triggered when a user is added as a collaborator to a repository.
+class MemberEvent
+       super GithubEvent
+
+       # `User` that was added.
+       fun member: User do return new User.from_json(api, json["member"].as(JsonObject))
+end
+
+# Triggered when an event occurs on a pull request.
+#
+# Triggered when a pull request is assigned, unassigned,
+# labeled, unlabeled, opened, closed, reopened, or synchronized.
+class PullRequestEvent
+       super GithubEvent
+
+       # The pull request number.
+       fun number: Int do return json["number"].as(Int)
+
+       # The `PullRequest` itself.
+       fun pull: PullRequest do
+               return new PullRequest.from_json(api, repo, json["pull_request"].as(JsonObject))
+       end
+end
+
+# Triggered when a comment is created on a pull request diff.
+class PullRequestReviewCommentEvent
+       super GithubEvent
+
+       # The `Comment` itself.
+       fun comment: ReviewComment do
+               return new ReviewComment.from_json(api, repo, json["comment"].as(JsonObject))
+       end
+
+       # `PullRequest` the `comment` belongs to.
+       fun pull: PullRequest do
+               return new PullRequest.from_json(api, repo, json["pull_request"].as(JsonObject))
+       end
+end
+
+# Triggered when a repository branch is pushed to.
+class PushEvent
+       super GithubEvent
+
+       # SHA of the HEAD commit on the repository.
+       fun head: String do return json["head"].to_s
+
+       # Full Git ref that was pushed.
+       #
+       # Example: “refs/heads/master”
+       fun ref: String do return json["ref"].to_s
+
+       # Number of commits in the push.
+       fun size: Int do return json["size"].as(Int)
+
+       # Array of pushed commits.
+       fun commits: Array[Commit] do
+               var res = new Array[Commit]
+               var arr = json["commits"].as(JsonArray)
+               for obj in arr do
+                       if not obj isa JsonObject then continue
+                       res.add api.load_commit(repo, obj["sha"].to_s).as(not null)
+               end
+               return res
+       end
+end
+
+# Triggered when the status of a Git commit changes.
+class StatusEvent
+       super GithubEvent
+
+       # The `Commit` itself.
+       fun commit: Commit do
+               return api.load_commit(repo, json["sha"].to_s).as(not null)
+       end
+
+       # New state.
+       #
+       # Can be `pending`, `success`, `failure`, or `error`.
+       fun state: String do return json["state"].to_s
+
+       # Optional human-readable description added to the status.
+       fun description: nullable String do
+               if not json.has_key("description") then return null
+               return json["description"].to_s
+       end
+
+       # Optional link added to the status.
+       fun target_url: nullable String do
+               if not json.has_key("target_url") then return null
+               return json["target_url"].to_s
+       end
+
+       # Array of branches containing the status' SHA.
+       #
+       # Each branch contains the given SHA,
+       # but the SHA may or may not be the head of the branch.
+       #
+       # The array includes a maximum of 10 branches.
+       fun branches: Array[Branch] do
+               var res = new Array[Branch]
+               var arr = json["branches"].as(JsonArray)
+               for obj in arr do
+                       if not obj isa JsonObject then continue
+                       res.add api.load_branch(repo, obj["name"].to_s).as(not null)
+               end
+               return res
+       end
+end
index 778f826..9bc63a8 100644 (file)
@@ -15,4 +15,4 @@
 # Github API related features.
 module github
 
-import api
+import cache
diff --git a/lib/github/hooks.nit b/lib/github/hooks.nit
new file mode 100644 (file)
index 0000000..351042b
--- /dev/null
@@ -0,0 +1,150 @@
+# 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.
+
+# Github hook event listening with `nitcorn`.
+#
+# Usage:
+#
+# ~~~
+# import github::hooks
+#
+# # A simple hook listener that print received events in stdout.
+# class LogHookListener
+#    super HookListener
+#
+#    # Use double dispatch to implement log behavior.
+#    redef fun apply_event(event) do event.log_event(self)
+# end
+#
+# redef class GithubEvent
+#    # Log this event.
+#    #
+#    # Do nothing by default.
+#    fun log_event(l: LogHookListener) do end
+# end
+#
+# redef class CommitCommentEvent
+#
+#    redef fun log_event(l) do
+#        print "new comment on commit {comment.commit.sha}"
+#    end
+# end
+#
+# var api = new GithubAPI(get_github_oauth)
+# var listener = new LogHookListener(api, "127.0.0.1", 8080)
+# # listener.listen # uncomment to start listening
+# ~~~
+module hooks
+
+import events
+import nitcorn
+
+# A nitcorn listener for Github hooks.
+class HookListener
+
+       # Api client used to perform Github API requests.
+       var api: GithubAPI
+
+       # Host to listen.
+       var host: String
+
+       # Port to listen.
+       var port: Int
+
+       # VirtualHost listened
+       private var vh: VirtualHost is noinit
+
+       init do
+               vh = new VirtualHost("{host}:{port}")
+               vh.routes.add new Route("/", new HookAction(self))
+       end
+
+       # Verbosity level (0: quiet, 1: debug).
+       # Default: 0
+       var verbosity = 0
+
+       # Print `message` if `lvl` <= `verbosity`
+       fun message(lvl: Int, message: String) do
+               if lvl <= verbosity then print message
+       end
+
+       # Start listening and responding to event.
+       fun listen do
+               message(1, "Hook listening on {host}:{port}")
+               var factory = new HttpFactory.and_libevent
+               factory.config.virtual_hosts.add vh
+               factory.run
+       end
+
+       # How to build events from received json objects.
+       fun event_factory(kind: String, json: JsonObject): GithubEvent do
+               if kind == "commit_comment" then
+                       return new CommitCommentEvent.from_json(api, json)
+               else if kind == "create" then
+                       return new CreateEvent.from_json(api, json)
+               else if kind == "delete" then
+                       return new DeleteEvent.from_json(api, json)
+               else if kind == "deployment" then
+                       return new DeploymentEvent.from_json(api, json)
+               else if kind == "deployment_status" then
+                       return new DeploymentStatusEvent.from_json(api, json)
+               else if kind == "fork" then
+                       return new ForkEvent.from_json(api, json)
+               else if kind == "issues" then
+                       return new IssuesEvent.from_json(api, json)
+               else if kind == "issue_comment" then
+                       return new IssueCommentEvent.from_json(api, json)
+               else if kind == "member" then
+                       return new MemberEvent.from_json(api, json)
+               else if kind == "pull_request" then
+                       return new PullRequestEvent.from_json(api, json)
+               else if kind == "pull_request_review_comment" then
+                       return new PullRequestReviewCommentEvent.from_json(api, json)
+               else if kind == "push" then
+                       return new PushEvent.from_json(api, json)
+               else if kind == "status" then
+                       return new StatusEvent.from_json(api, json)
+               else
+                       return new GithubEvent.from_json(api, json)
+               end
+       end
+
+       # What to do when we receive an event from a hook?
+       fun apply_event(event: GithubEvent) is abstract
+end
+
+# A nitcorn action dedicated to GitHub hook listening.
+private class HookAction
+       super Action
+
+       # Listener that contains this action.
+       #
+       # The `listener` is used for its `event_factory` method
+       # and the `apply_event`.
+       var listener: HookListener
+
+       # Parse hook request then call `listener.apply_event`.
+       redef fun answer(request, uri) do
+               # get event type
+               var kind = request.header.get_or_null("X-GitHub-Event")
+               if kind == null then return new HttpResponse(403)
+               # get POST object
+               var obj = request.body.parse_json
+               if not obj isa JsonObject then return new HttpResponse(403)
+               # parse event
+               var event = listener.event_factory(kind, obj)
+               listener.apply_event(event)
+               return new HttpResponse(200)
+       end
+end
index 01ca43c..ca7faf1 100644 (file)
@@ -33,8 +33,10 @@ module glesv2 is
        pkgconfig
        new_annotation glsl_vertex_shader
        new_annotation glsl_fragment_shader
+       ldflags("-lGLESv2")@android
 end
 
+import android::aware
 
 in "C Header" `{
        #include <GLES2/gl2.h>
@@ -146,15 +148,21 @@ extern class GLProgram `{GLuint`}
                return active_attrib_name_native(index, max_size).to_s
        end
        private fun active_attrib_name_native(index, max_size: Int): NativeString `{
+               // We get more values than we need, for compatibility. At least the
+               // NVidia driver tries to fill them even if NULL.
+
                char *name = malloc(max_size);
-               glGetActiveAttrib(recv, index, max_size, NULL, NULL, NULL, name);
+               int size;
+               GLenum type;
+               glGetActiveAttrib(recv, index, max_size, NULL, &size, &type, name);
                return name;
        `}
 
        # Size of the active attribute at `index`
        fun active_attrib_size(index: Int): Int `{
                int size;
-               glGetActiveAttrib(recv, index, 0, NULL, NULL, &size, NULL);
+               GLenum type;
+               glGetActiveAttrib(recv, index, 0, NULL, &size, &type, NULL);
                return size;
        `}
 
@@ -162,8 +170,9 @@ extern class GLProgram `{GLuint`}
        #
        # May only be float related data types (single float, vectors and matrix).
        fun active_attrib_type(index: Int): GLFloatDataType `{
+               int size;
                GLenum type;
-               glGetActiveAttrib(recv, index, 0, NULL, &type, NULL, NULL);
+               glGetActiveAttrib(recv, index, 0, NULL, &size, &type, NULL);
                return type;
        `}
 
@@ -175,14 +184,17 @@ extern class GLProgram `{GLuint`}
        end
        private fun active_uniform_name_native(index, max_size: Int): NativeString `{
                char *name = malloc(max_size);
-               glGetActiveUniform(recv, index, max_size, NULL, NULL, NULL, name);
+               int size;
+               GLenum type;
+               glGetActiveUniform(recv, index, max_size, NULL, &size, &type, name);
                return name;
        `}
 
        # Size of the active uniform at `index`
        fun active_uniform_size(index: Int): Int `{
                int size;
-               glGetActiveUniform(recv, index, 0, NULL, NULL, &size, NULL);
+               GLenum type;
+               glGetActiveUniform(recv, index, 0, NULL, &size, &type, NULL);
                return size;
        `}
 
@@ -190,8 +202,9 @@ extern class GLProgram `{GLuint`}
        #
        # May be any data type supported by OpenGL ES 2.0 shaders.
        fun active_uniform_type(index: Int): GLDataType `{
-               GLenum type;
-               glGetActiveUniform(recv, index, 0, NULL, &type, NULL, NULL);
+               int size;
+               GLenum type = 0;
+               glGetActiveUniform(recv, index, 0, NULL, &size, &type, NULL);
                return type;
        `}
 end
index f6f10aa..64b7b49 100644 (file)
@@ -404,8 +404,8 @@ extern class GtkEntry `{GtkEntry *`}
                 return (GtkEntry *)gtk_entry_new();
        `}
 
-       fun text : String is extern import NativeString.to_s `{
-               return NativeString_to_s( (char *)gtk_entry_get_text( recv ) );
+       fun text : String is extern import NativeString.to_s_with_copy `{
+               return NativeString_to_s_with_copy( (char *)gtk_entry_get_text( recv ) );
        `}
 
        fun text=( value : String) is extern import String.to_cstring`{
index c3db430..2020e30 100644 (file)
@@ -27,8 +27,8 @@
 # most of JNI functions. You can use it to further customize the behavior
 # of your code.
 module java is
-       c_compiler_option "-I $(JAVA_HOME)/include/ -I $(JAVA_HOME)/include/linux/"
-       c_linker_option("-L $(JNI_LIB_PATH) -ljvm")
+       cflags "-I $(JAVA_HOME)/include/ -I $(JAVA_HOME)/include/linux/"
+       ldflags "-L $(JNI_LIB_PATH) -ljvm"
        new_annotation extra_java_files
 end
 
index 6063f23..abdcab6 100644 (file)
@@ -19,8 +19,8 @@
 #
 # 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/ -I $(JAVA_HOME)/include/linux/"
-       c_linker_option "-L $(JNI_LIB_PATH) -ljvm"
+       cflags "-I $(JAVA_HOME)/include/ -I $(JAVA_HOME)/include/linux/"
+       ldflags "-L $(JNI_LIB_PATH) -ljvm"
 end
 
 in "C Header" `{
index 2c703bb..8f61c90 100644 (file)
@@ -21,7 +21,7 @@
 # * The Android ndk
 # * zlib (which is included in the Android ndk)
 # * libpng which must be provided by the Nit compilation framework
-module android_assets
+module android_assets is ldflags "-lz"
 
 import mnit
 import android_app
index 5996214..5ff9e7c 100644 (file)
@@ -16,7 +16,7 @@
 
 # Adapts OpenGL ES 1.0 for use on Android by offering services to get
 # a handler to the native display and window.
-module android_opengles1
+module android_opengles1 is ldflags "-lEGL -lGLESv1_CM"
 
 import android_app
 import android
index cd6c59d..58864e4 100644 (file)
@@ -85,6 +85,11 @@ interface KeyEvent
 
        # Get Char value of key, if any
        fun to_c: nullable Char is abstract
+
+       # Name of the key that raised `self`
+       #
+       # Use mainly for debug since it is implementation dependent.
+       fun name: String is abstract
 end
 
 # Mobile hardware (or pseudo hardware) event
index 6396ec2..ecbbf9f 100644 (file)
@@ -86,6 +86,17 @@ class HashMap2[K1, K2, V]
                end
                level2[k2] = v
        end
+
+       # Remove the item at `k1` and `k2`
+       fun remove_at(k1: K1, k2: K2)
+       do
+               var level1 = self.level1
+
+               if not level1.has_key(k1) then return
+
+               var level2 = level1[k1]
+               level2.keys.remove(k2)
+       end
 end
 
 # Simple way to store an `HashMap[K1, HashMap[K2, HashMap[K3, V]]]`
@@ -123,6 +134,17 @@ class HashMap3[K1, K2, K3, V]
                end
                level2[k2, k3] = v
        end
+
+       # Remove the item at `k1`, `k2` and `k3`
+       fun remove_at(k1: K1, k2: K2, k3: K3)
+       do
+               var level1 = self.level1
+
+               if not level1.has_key(k1) then return
+
+               var level2 = level1[k1]
+               level2.remove_at(k2, k3)
+       end
 end
 
 # A map with a default value.
index 01137f7..de91686 100644 (file)
@@ -26,8 +26,8 @@
 # Since this module is a thin wrapper around OpenMPI, in case of missing
 # documentation, you can refer to https://www.open-mpi.org/doc/v1.8/.
 module mpi is
-       c_compiler_option(exec("mpicc", "-showme:compile"))
-       c_linker_option(exec("mpicc", "-showme:link"))
+       cflags exec("mpicc", "-showme:compile")
+       ldflags exec("mpicc", "-showme:link")
 end
 
 import c
index 416b174..e408270 100644 (file)
@@ -16,8 +16,8 @@
 
 # Offers some POSIX threads services that are not available on all platforms
 module extra is
-       c_compiler_option("-pthread")
-       c_linker_option("-pthread")
+       cflags "-pthread"
+       ldflags "-pthread"
 end
 
 intrude import pthreads
index bce93c4..5d6b80d 100644 (file)
@@ -16,8 +16,8 @@
 
 # Main POSIX threads support and intro the classes `Thread`, `Mutex` and `Barrier`
 module pthreads is
-       c_compiler_option("-pthread")
-       c_linker_option("-pthread")
+       cflags "-pthread"
+       ldflags "-pthread"
        pkgconfig "bdw-gc"
 end
 
index b66ade0..3a02d86 100644 (file)
@@ -11,7 +11,7 @@
 # another product.
 
 # Provides the Clock utility class to keep time of real time flow
-module realtime is c_linker_option("-lrt")
+module realtime is ldflags "-lrt"
 
 in "C header" `{
 #ifdef _POSIX_C_SOURCE
index 5225f9f..6de6d2d 100644 (file)
 
 # SDL display support (used in Linux for windows and inputes only)
 module sdl is
-       c_compiler_option(exec("sdl-config", "--cflags"))
-       c_linker_option(exec("sdl-config", "--libs"), "-lSDL_image -lSDL_ttf")
+       cflags exec("sdl-config", "--cflags")
+       ldflags(exec("sdl-config", "--libs"), "-lSDL_image -lSDL_ttf")
 end
 
 import mnit_display
+import c
 
 in "C header" `{
        #include <unistd.h>
@@ -160,7 +161,32 @@ extern class SDLDisplay `{SDL_Surface *`}
        fun warp_mouse(x,y: Int) `{ SDL_WarpMouse(x, y); `}
 
        # Show or hide the cursor
-       fun show_cursor(show: Bool) `{ SDL_ShowCursor(show); `}
+       fun show_cursor=(val: Bool) `{ SDL_ShowCursor(val? SDL_ENABLE: SDL_DISABLE); `}
+
+       # Is the cursor visible?
+       fun show_cursor: Bool `{ SDL_ShowCursor(SDL_QUERY); `}
+
+       # Grab or release the input
+       fun grab_input=(val: Bool) `{ SDL_WM_GrabInput(val? SDL_GRAB_ON: SDL_GRAB_OFF); `}
+
+       # Is the input grabbed?
+       fun grab_input: Bool `{ SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_ON; `}
+
+       # Are instances of `SDLMouseMotionEvent` ignored?
+       fun ignore_mouse_motion_events: Bool `{
+               return SDL_EventState(SDL_MOUSEMOTION, SDL_QUERY);
+       `}
+
+       # Do not raise instances of `SDLMouseMotionEvent` if `val`
+       fun ignore_mouse_motion_events=(val: Bool) `{
+               SDL_EventState(SDL_MOUSEMOTION, val? SDL_IGNORE: SDL_ENABLE);
+       `}
+
+       # Does `self` has the mouse focus?
+       fun mouse_focus: Bool `{ return SDL_GetAppState() & SDL_APPMOUSEFOCUS; `}
+
+       # Does `self` has the input focus?
+       fun input_focus: Bool `{ return SDL_GetAppState() & SDL_APPINPUTFOCUS; `}
 end
 
 # Basic Drawing figures
@@ -225,6 +251,12 @@ extern class SDLImage
        redef fun height: Int `{ return recv->h; `}
 
        fun is_ok: Bool do return not address_is_null
+
+       # Returns a reference to the pixels of the texture
+       fun pixels: NativeCByteArray `{ return recv->pixels; `}
+
+       # Does this texture has an alpha mask?
+       fun amask: Bool `{ return recv->format->Amask; `}
 end
 
 # A simple rectangle
@@ -284,10 +316,10 @@ class SDLMouseButtonEvent
        fun is_left_button: Bool do return button == 1
 
        # Is this event raised by the right button?
-       fun is_right_button: Bool do return button == 2
+       fun is_right_button: Bool do return button == 3
 
        # Is this event raised by the middle button?
-       fun is_middle_button: Bool do return button == 3
+       fun is_middle_button: Bool do return button == 2
 
        # Is this event raised by the wheel going down?
        fun is_down_wheel: Bool do return button == 4
@@ -343,27 +375,27 @@ class SDLKeyEvent
        super KeyEvent
        super SDLInputEvent
 
-       var key_name: String
+       redef var name
        var down: Bool
 
        init (key_name: String, down: Bool)
        do
-               self.key_name = key_name
+               self.name = key_name
                self.down = down
        end
 
        redef fun to_c: nullable Char
        do
-               if key_name.length == 1 then return key_name.chars.first
+               if name.length == 1 then return name.chars.first
                return null
        end
 
        redef fun to_s
        do
                if down then
-                       return "KeyboardEvent key {key_name} down"
+                       return "KeyboardEvent key {name} down"
                else
-                       return "KeyboardEvent key {key_name} up"
+                       return "KeyboardEvent key {name} up"
                end
        end
 
@@ -371,13 +403,13 @@ class SDLKeyEvent
        redef fun is_down do return down
 
        # Return true if the key is the up arrow
-       redef fun is_arrow_up do return key_name == "up"
+       redef fun is_arrow_up do return name == "up"
        # Return true if the key is the left arrow
-       redef fun is_arrow_left do return key_name == "left"
+       redef fun is_arrow_left do return name == "left"
        # Return true if the key is the down arrow
-       redef fun is_arrow_down do return key_name == "down"
+       redef fun is_arrow_down do return name == "down"
        # Return true if the key is the right arrow
-       redef fun is_arrow_right do return key_name == "right"
+       redef fun is_arrow_right do return name == "right"
 end
 
 class SDLQuitEvent
index 6dc53b3..ce642b8 100644 (file)
@@ -20,7 +20,7 @@
 # alone: JPG, PNG, TIF, GIT, ICO and much more.
 module image is
        pkgconfig "sdl2"
-       c_linker_option "-lSDL2_image"
+       ldflags "-lSDL2_image"
 end
 
 import sdl2
diff --git a/share/libgc/.gitignore b/share/libgc/.gitignore
new file mode 100644 (file)
index 0000000..98279d0
--- /dev/null
@@ -0,0 +1,4 @@
+include
+lib
+share
+src
diff --git a/share/libgc/android-setup-libgc.sh b/share/libgc/android-setup-libgc.sh
new file mode 100755 (executable)
index 0000000..8e20ca0
--- /dev/null
@@ -0,0 +1,98 @@
+#!/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.
+
+# Fetch, configure and build libgc (the Boehm GC) for Android
+#
+# Will produce libgc.a which can be linked to Android NDK applications.
+#
+# The `ndk-build` tool from the Android NDK must be in PATH before
+# invoking this tool. It will be used to guess the path to the NDK.
+#
+# Alternatively, you may define a custom path to the NDK by setting
+# `ANDROID_NDK`.
+
+# If ANDROID_NDK is not set, get it from the path to `ndk-build`
+if test -z "$ANDROID_NDK"; then
+       ndk_build_path=`which ndk-build`
+       if test $? -ne 0; then
+               echo "Error: ndk-build from the Android NDK must be in your PATH"
+               exit 1
+       fi
+
+       ANDROID_NDK=`dirname $ndk_build_path`
+fi
+
+# Get the first platform available (it shouldn't change much, but it may
+# have to be adjusted)
+for platform in `echo $ANDROID_NDK/platforms/android-*/arch-arm`; do
+       SYS_ROOT=$platform
+       break
+done
+
+if test -z "$SYS_ROOT"; then
+       echo "Error: could not an Android platform in the NDK, define ANDROID_NDK to the correct path."
+       exit 1
+fi
+
+# Information on the currently targeted libgc and libatomic_ops source URL
+# These may have to be updated according to server-side changes and newer
+# versions of the Boehm GC.
+libgc_url=http://www.hboehm.info/gc/gc_source/gc-7.4.0.tar.gz
+libgc_dir=gc-7.4.0
+libatomic_ops_url=http://www.hboehm.info/gc/gc_source/libatomic_ops-7.4.0.tar.gz
+libatomic_ops_dir=libatomic_ops-7.4.0
+
+# Absolute installation path
+if expr match "$0" "^/.*"; then
+       install="`dirname "$0"`"
+else
+       install="`pwd`/`dirname "$0"`"
+fi
+
+# Local source directory
+mkdir -p "$install/src"
+cd "$install/src"
+
+# Download libs
+for url in $libgc_url $libatomic_ops_url; do
+       echo "Downloading $url..."
+       curl --progress-bar -o `basename $url` $url || exit 1
+done
+
+if test -d $libgc_dir; then
+       rm -r $libgc_dir
+fi
+
+# Extract
+tar -xzf `basename $libgc_url` || exit 1
+tar -xzf `basename $libatomic_ops_url` || exit 1
+mv $libatomic_ops_dir $libgc_dir/libatomic_ops || exit 1
+
+cd $libgc_dir || exit 1
+
+# Configure for Android
+path="$ANDROID_NDK/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/"
+export CC="$path/arm-linux-androideabi-gcc --sysroot=$SYS_ROOT"
+export CXX="$path/arm-linux-androideabi-g++ --sysroot=$SYS_ROOT"
+export LD="$path/arm-linux-androideabi-ld"
+export AR="$path/arm-linux-androideabi-ar"
+export RANLIB="$path/arm-linux-androideabi-ranlib"
+export STRIP="$path/arm-linux-androideabi-strip"
+export CFLAGS="-DIGNORE_DYNAMIC_LOADING -DPLATFORM_ANDROID -I libatomic_ops/src/"
+export LIBS="-lc -lgcc"
+./configure --host=arm-linux-androideabi --enable-static --disable-shared --prefix="$install" || exit 1
+
+# Compile and install locally
+make install -j 4 || exit 1
index b835f2a..6fa1f05 100644 (file)
@@ -125,7 +125,7 @@ end
 class ExternCFile
        super ExternFile
 
-       # Additional specific CC compiler -c flags
+       # Custom options for the C compiler (CFLAGS)
        var cflags: String
 
        redef fun hash do return filename.hash
index 754f545..e85393d 100755 (executable)
@@ -26,8 +26,10 @@ echo "shortstat"
 git diff --shortstat "$orig".."$cur"
 echo "PR"
 git log --first-parent "$orig".."$cur" | grep 'Pull-Request: #' | wc -l
+echo "non-merge commits"
+git log --no-merges --oneline "$orig".."$cur"  | wc -l
 echo "shortlog"
-git shortlog -ens "$orig".."$cur"
+git shortlog -ens --no-merges "$orig".."$cur"
 echo log
 echo
 git log --format="* %s [[!commit %h]]" --first-parent "$orig".."$cur" | tac
index dfe463c..b1a5879 100644 (file)
@@ -2990,7 +2990,7 @@ redef class MModule
 
        # Give requided addinional system libraries (as given to LD_LIBS)
        # Note: can return null instead of an empty set
-       fun collect_linker_libs: nullable Set[String] do return null
+       fun collect_linker_libs: nullable Array[String] do return null
 end
 
 # Create a tool context to handle options and paths
index 8466af1..dea917b 100644 (file)
@@ -49,10 +49,11 @@ extern void nitni_global_ref_incr(void*);
 extern void nitni_global_ref_decr(void*);
 """
 
+               var cflags = self.cflags[""].join(" ")
                nitni_ccu.write_as_nitni(self, v.compiler.modelbuilder.compile_dir)
 
                for file in nitni_ccu.files do
-                       var f = new ExternCFile(file, c_compiler_options)
+                       var f = new ExternCFile(file, cflags)
                        f.pkgconfigs.add_all pkgconfigs
                        v.compiler.extern_bodies.add(f)
                end
@@ -76,11 +77,8 @@ extern void nitni_global_ref_decr(void*);
 
        redef fun collect_linker_libs
        do
-               var s = c_linker_options
-               if s.is_empty then return null
-               var res = new ArraySet[String]
-               res.add s
-               return res
+               if not self.ldflags.keys.has("") then return null
+               return self.ldflags[""]
        end
 
        private var compiled_callbacks = new Array[NitniCallback]
index 8ae08b9..495d4e6 100644 (file)
@@ -31,11 +31,13 @@ class CLanguage
        redef fun compile_module_block(block, ecc, mmodule)
        do
                if block.is_c_header then
-                       ecc.header_custom.add( block.location.as_line_pragma )
-                       ecc.header_custom.add( block.code )
+                       ecc.header_custom.add block.location.as_line_pragma
+                       ecc.header_custom.add "\n"
+                       ecc.header_custom.add block.code
                else if block.is_c_body then
-                       ecc.body_custom.add( block.location.as_line_pragma )
-                       ecc.body_impl.add( block.code )
+                       ecc.body_impl.add block.location.as_line_pragma
+                       ecc.body_impl.add "\n"
+                       ecc.body_impl.add block.code
                end
        end
 
@@ -72,8 +74,14 @@ redef class Location
 end
 
 redef class MModule
-       var c_compiler_options = "" is writable
-       var c_linker_options = "" is writable
+       # FIXME make nullable the key of `cflags`, `ldflags` and `cppflags` when
+       # supported by the bootstrap
+
+       # Custom options for the C compiler (CFLAGS)
+       var cflags = new MultiHashMap[String, String]
+
+       # Custom options for the C linker (LDFLAGS)
+       var ldflags = new MultiHashMap[String, String]
 
        # Additional libraries needed for the compilation
        # Will be used with pkg-config
index af4e938..4fbd5c4 100644 (file)
@@ -14,7 +14,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Offers the annotations `c_compiler_option` and `c_linker_option` to specify
+# Offers the annotations `cflags` and `ldflags` to specify
 # options for the C compiler directly or indirectly. Differs from the `pkgconfig`
 # annotation by the separation of the options between the compiler and linker.
 module c_compiler_options
@@ -22,17 +22,19 @@ module c_compiler_options
 import c
 import cpp
 private import annotation
+private import platform
 
 redef class ToolContext
-       var c_compiler_options_phase: Phase = new CCompilerOptionsPhase(self, null)
+       # Phase to find `cflags`, `ldflags` and `cppflags`
+       var cflags_phase: Phase = new CCompilerOptionsPhase(self, [platform_phase])
 end
 
 private class CCompilerOptionsPhase
        super Phase
 
-       fun compiler_annotation_name: String do return "c_compiler_option"
-       fun linker_annotation_name: String do return "c_linker_option"
-       fun cpp_compiler_annotation_name: String do return "cpp_compiler_option"
+       fun compiler_annotation_name: String do return "cflags"
+       fun linker_annotation_name: String do return "ldflags"
+       fun cpp_compiler_annotation_name: String do return "cppflags"
 
        redef fun process_annotated_node(nmoduledecl, nat)
        do
@@ -128,35 +130,45 @@ private class CCompilerOptionsPhase
                        end
                end
 
-               # retreive module
+               # Retrieve module
                var mmodule = nmoduledecl.parent.as(AModule).mmodule.as(not null)
 
+               # Get target platform from annotation on annotation
+               var platform = ""
+
+               ## Is there an imported platform?
+               var target_platform = mmodule.target_platform
+               if target_platform != null then
+                       platform = target_platform.name or else ""
+               end
+
+               ## Is the platform declared explicitly?
+               var annots = nat.n_annotations
+               if annots != null then
+                       var items = annots.n_items
+                       if items.length > 1 then
+                               modelbuilder.error(annots, "Annotation error: `annotation_name` accepts only a single annotation, the platform name")
+                               return
+                       end
+                       assert items.length == 1
+
+                       var item = items.first
+                       platform = item.name
+               end
+
+               # Store the flags in the module
                for opt in simplified_options do
-                       var cmd = opt.option
+                       var arg = opt.option
                        if annotation_name == compiler_annotation_name then
-                               process_c_compiler_annotation(mmodule, cmd)
+                               mmodule.cflags.add_one(platform, arg)
                        else if annotation_name == linker_annotation_name then
-                               process_c_linker_annotation(mmodule, cmd)
+                               mmodule.ldflags.add_one(platform, arg)
                        else if annotation_name == cpp_compiler_annotation_name then
-                               process_cpp_compiler_annotation(mmodule, cmd)
+                               mmodule.cppflags.add_one(platform, arg)
                        else abort
                end
        end
 
-       fun process_c_compiler_annotation(mmodule: MModule, opt: String)
-       do
-               mmodule.c_compiler_options = "{mmodule.c_compiler_options} {opt}"
-       end
-
-       fun process_c_linker_annotation(mmodule: MModule, opt: String)
-       do
-               mmodule.c_linker_options = "{mmodule.c_linker_options} {opt}"
-       end
-
-       fun process_cpp_compiler_annotation(mmodule: MModule, opt: String)
-       do
-               mmodule.cpp_compiler_options = "{mmodule.cpp_compiler_options} {opt}"
-       end
 end
 
 abstract class CCompilerOption
index a6a8ca3..ba6c2e0 100644 (file)
@@ -27,7 +27,8 @@ end
 redef class MModule
        private var cpp_file: nullable CPPCompilationUnit = null
 
-       var cpp_compiler_options = "" is writable
+       # Custom options for the C++ compiler (CPPFLAGS)
+       var cppflags = new MultiHashMap[String, String]
 end
 
 class CPPLanguage
@@ -133,7 +134,7 @@ class CPPLanguage
                mmodule.ffi_files.add(file)
 
                # add linked option to support C++
-               mmodule.c_linker_options = "{mmodule.c_linker_options} -lstdc++"
+               mmodule.ldflags.add_one("", "-lstdc++")
        end
 
        redef fun compile_callback(callback, mmodule, mainmodule, ecc)
@@ -180,7 +181,7 @@ class ExternCppFile
        var mmodule: MModule
 
        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"
+       redef fun makefile_rule_content do return "$(CXX) $(CFLAGS) {mmodule.cppflags[""].join(" ")} -c {filename.basename("")} -o {filename.basename("")}.o"
        redef fun compiles_to_o_file do return true
 end
 
index b854750..93acf66 100644 (file)
@@ -60,9 +60,11 @@ redef class MModule
                        if mod.uses_ffi then ffi_ccu.header_custom.add("#include \"{mod.c_name}._ffi.h\"\n")
                end
 
+               var cflags = self.cflags[""].join(" ")
+
                ffi_ccu.write_as_impl(self, compdir)
                for filename in ffi_ccu.files do
-                       var f = new ExternCFile(filename, c_compiler_options)
+                       var f = new ExternCFile(filename, cflags)
                        f.pkgconfigs.add_all pkgconfigs
                        ffi_files.add(f)
                end
index 1fa56e9..7827dac 100644 (file)
@@ -242,8 +242,8 @@ redef class MModule
        # Tell the C compiler where to find jni.h and how to link with libjvm
        private fun insert_compiler_options
        do
-               c_compiler_options = "{c_compiler_options} -I $(JAVA_HOME)/include/ -I $(JAVA_HOME)/include/linux/"
-               c_linker_options = "{c_linker_options} -L $(JNI_LIB_PATH) -ljvm"
+               cflags.add_one("", "-I $(JAVA_HOME)/include/ -I $(JAVA_HOME)/include/linux/")
+               ldflags.add_one("", "-L $(JNI_LIB_PATH) -ljvm")
        end
 
        # Name of the generated Java class where to store all implementation methods of this module
index f031289..4aafb91 100644 (file)
@@ -154,7 +154,7 @@ private class ObjCCompilationUnit
 
                files.add compdir/c_file
 
-               mmodule.c_linker_options = "{mmodule.c_linker_options} -lobjc"
+               mmodule.ldflags.add_one("", "-lobjc")
 
                return new ExternObjCFile(compdir/c_file, mmodule)
        end
index fa909bc..a51bece 100644 (file)
@@ -92,8 +92,8 @@ extern
 no_warning
 
 pkgconfig
-c_compiler_option
-c_linker_option
+cflags
+ldflags
 
 platform
 """
index 5cc3892..e297f9c 100644 (file)
@@ -1216,7 +1216,7 @@ redef class AExpr
        # Return a possible value
        # NOTE: Do not call this method directly, but use `v.expr`
        # This method is here to be implemented by subclasses.
-       private fun expr(v: NaiveInterpreter): nullable Instance
+       protected fun expr(v: NaiveInterpreter): nullable Instance
        do
                fatal(v, "NOT YET IMPLEMENTED expr {class_name}")
                abort
@@ -1225,7 +1225,7 @@ redef class AExpr
        # Evaluate the node as a statement.
        # NOTE: Do not call this method directly, but use `v.stmt`
        # This method is here to be implemented by subclasses (no need to return something).
-       private fun stmt(v: NaiveInterpreter)
+       protected fun stmt(v: NaiveInterpreter)
        do
                expr(v)
        end
index 5a74d48..8be9ae2 100644 (file)
@@ -21,6 +21,7 @@ import interpreter
 import frontend
 import parser_util
 import vm
+import vm_optimizations
 
 # Create a tool context to handle options and paths
 var toolcontext = new ToolContext
index 088cd92..5e5dde3 100644 (file)
@@ -18,6 +18,7 @@
 module nitvm
 
 import vm
+import vm_optimizations
 import frontend
 
 # Create a tool context to handle options and paths
index 6ba5502..f4b04a6 100644 (file)
@@ -34,6 +34,10 @@ end
 class AndroidPlatform
        super Platform
 
+       redef fun name do return "android"
+
+       redef fun supports_libgc do return true
+
        redef fun supports_libunwind do return false
 
        redef fun supports_linker_script do return false
@@ -59,14 +63,16 @@ class AndroidToolchain
        do
                var android_project_root = android_project_root.as(not null)
                var project = toolcontext.modelbuilder.android_project_for(compiler.mainmodule)
-               var short_project_name = compiler.mainmodule.name
+               var short_project_name = compiler.mainmodule.name.replace("-", "_")
                var release = toolcontext.opt_release.value
 
                var app_name = project.name
                if app_name == null then app_name = compiler.mainmodule.name
+               if not release then app_name += " Debug"
 
                var app_package = project.java_package
                if app_package == null then app_package = "org.nitlanguage.{short_project_name}"
+               if not release then app_package += "_debug"
 
                var app_version = project.version
                if app_version == null then app_version = "1.0"
@@ -134,23 +140,32 @@ class AndroidToolchain
                        end
                end
 
-               ## Generate delagating makefile
+               ## Generate delegating makefile
                dir = "{android_project_root}/jni/"
                """
 include $(call all-subdir-makefiles)
                """.write_to_file("{dir}/Android.mk")
 
+               # Gather ldflags for Android
+               var ldflags = new Array[String]
+               var platform_name = "android"
+               for mmodule in compiler.mainmodule.in_importation.greaters do
+                       if mmodule.ldflags.keys.has(platform_name) then
+                               ldflags.add_all mmodule.ldflags[platform_name]
+                       end
+               end
+
                ### generate makefile into "{compile_dir}/Android.mk"
                dir = compile_dir
                """
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_CFLAGS   := -D ANDROID
+LOCAL_CFLAGS   := -D ANDROID -D WITH_LIBGC
 LOCAL_MODULE    := main
 LOCAL_SRC_FILES := \\
 {{{cfiles.join(" \\\n")}}}
-LOCAL_LDLIBS    := -llog -landroid -lEGL -lGLESv1_CM -lz
+LOCAL_LDLIBS    := {{{ldflags.join(" ")}}} libgc.a
 LOCAL_STATIC_LIBRARIES := android_native_app_glue png
 
 include $(BUILD_SHARED_LIBRARY)
@@ -177,7 +192,8 @@ $(call import-module,android/native_app_glue)
                android:label="@string/app_name"
                android:hasCode="true"
                android:debuggable="{{{not release}}}"
-               {{{icon_declaration}}}>
+               {{{icon_declaration}}}
+               android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation">
 
         <!-- Our activity is the built-in NativeActivity framework class.
              This will take care of integrating with our NDK code. -->
@@ -219,6 +235,15 @@ $(call import-module,android/native_app_glue)
                        toolcontext.exec_and_check(["ln", "-s", "{share_dir}/png/", target_png_dir], "Android project error")
                end
 
+               # Ensure that android-setup-libgc.sh has been executed
+               if not "{share_dir}/libgc/lib".file_exists then
+                       toolcontext.exec_and_check(["{share_dir}/libgc/android-setup-libgc.sh"], "Android project error")
+               end
+
+               # Copy GC files
+               toolcontext.exec_and_check(["cp", "{share_dir}/libgc/lib/libgc.a", "{android_project_root}/libgc.a"], "Android project error")
+               toolcontext.exec_and_check(["ln", "-s", "{share_dir}/libgc/include/gc/", "{android_project_root}/jni/nit_compile/gc"], "Android project error")
+
                ### Link to assets (for mnit and others)
                # This will be accessed from `android_project_root`
                var assets_dir
@@ -278,6 +303,7 @@ $(call import-module,android/native_app_glue)
        redef fun compile_c_code(compiler, compile_dir)
        do
                var android_project_root = android_project_root.as(not null)
+               var short_project_name = compiler.mainmodule.name.replace("-", "_")
                var release = toolcontext.opt_release.value
 
                # Compile C code (and thus Nit)
@@ -294,7 +320,7 @@ $(call import-module,android/native_app_glue)
                var outname = outfile(compiler.mainmodule)
 
                if release then
-                       var apk_path = "{android_project_root}/bin/{compiler.mainmodule.name}-release-unsigned.apk"
+                       var apk_path = "{android_project_root}/bin/{short_project_name}-release-unsigned.apk"
 
                        # Sign APK
                        var keystore_path= "KEYSTORE".environ
@@ -324,7 +350,7 @@ $(call import-module,android/native_app_glue)
                        toolcontext.exec_and_check(args, "Android project error")
                else
                        # Move to the expected output path
-                       args = ["mv", "{android_project_root}/bin/{compiler.mainmodule.name}-debug.apk", outname]
+                       args = ["mv", "{android_project_root}/bin/{short_project_name}-debug.apk", outname]
                        toolcontext.exec_and_check(args, "Android project error")
                end
        end
index dc2662f..3e9199a 100644 (file)
@@ -31,6 +31,7 @@ end
 class EmscriptenPlatform
        super Platform
 
+       redef fun name do return "emscripten"
        redef fun supports_libunwind do return false
        redef fun supports_libgc do return false
        redef fun supports_linker_script do return false
index 5b7f7a5..40069c4 100644 (file)
@@ -104,6 +104,10 @@ end
 #
 # Services will be added to this class in other modules.
 class Platform
+
+       # Simple lower-case name of the platform
+       fun name: nullable String do return null
+
        # Does the platform provide and support the library `unwind`?
        fun supports_libunwind: Bool do return true
 
index 9fceaad..d7103db 100644 (file)
@@ -31,6 +31,8 @@ end
 class PnaclPlatform
        super Platform
 
+       redef fun name do return "pnacl"
+
        redef fun supports_libunwind do return false
 
        redef fun no_main do return true
index 8fb3852..343edbd 100644 (file)
@@ -609,6 +609,10 @@ redef class AAttrPropdef
                var nblock = self.n_block
                if nblock != null then
                        v.visit_stmt(nblock)
+                       if not nblock.after_flow_context.is_unreachable then
+                               # We reach the end of the init without having a return, it is bad
+                               v.error(self, "Control error: Reached end of block (a 'return' with a value was expected).")
+                       end
                end
        end
 end
index 17d2d34..b253533 100644 (file)
@@ -131,7 +131,10 @@ class VirtualMachine super NaiveInterpreter
        end
 
        # Subtyping test with perfect hashing
-       private fun inter_is_subtype_ph(id: Int, mask:Int, vtable: Pointer): Bool `{
+       # * `id` is the identifier of the target class
+       # * `mask` is the perfect hashing mask of the receiver class
+       # * `vtable` is the pointer to the virtual table of the receiver class
+       fun inter_is_subtype_ph(id: Int, mask:Int, vtable: Pointer): Bool `{
                // hv is the position in hashtable
                int hv = id & mask;
 
@@ -143,7 +146,10 @@ class VirtualMachine super NaiveInterpreter
        `}
 
        # Subtyping test with Cohen test (direct access)
-       private fun inter_is_subtype_sst(id: Int, position: Int, vtable: Pointer): Bool `{
+       # * `id` is the identifier of the target class
+       # * `mask` is the absolute position of the target identifier in the virtual table
+       # * `vtable` is the pointer to the virtual table of the receiver class
+       fun inter_is_subtype_sst(id: Int, position: Int, vtable: Pointer): Bool `{
                // Direct access to the position given in parameter
                int tableid = (long unsigned int)((long int *)vtable)[position];
 
@@ -224,8 +230,12 @@ class VirtualMachine super NaiveInterpreter
                end
        end
 
-       # Execute a method dispatch with perfect hashing
-       private fun method_dispatch_ph(vtable: Pointer, mask: Int, id: Int, offset: Int): MMethodDef `{
+       # Execute a method dispatch with perfect hashing and return the appropriate `MMethodDef`
+       # * `vtable` Pointer to the internal virtual table of the class
+       # * `mask` Perfect hashing mask of the receiver class
+       # * `id` Identifier of the class which introduce the method
+       # * `offset` Relative offset of the method from the beginning of the block
+       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]);
@@ -238,9 +248,9 @@ class VirtualMachine super NaiveInterpreter
        `}
 
        # Execute a method dispatch with direct access and return the appropriate `MMethodDef`
-       # `vtable` : Pointer to the internal pointer of the class
-       # `absolute_offset` : Absolute offset from the beginning of the virtual table
-       private fun method_dispatch_sst(vtable: Pointer, absolute_offset: Int): MMethodDef `{
+       # * `vtable` Pointer to the internal virtual table of the class
+       # * `absolute_offset` Absolute offset from the beginning of the virtual table
+       fun method_dispatch_sst(vtable: Pointer, absolute_offset: Int): MMethodDef `{
                // pointer+2 is the position where methods are
                // Add the offset of property and get the method implementation
                MMethodDef propdef = (MMethodDef)((long int *)vtable)[absolute_offset];
@@ -281,7 +291,7 @@ class VirtualMachine super NaiveInterpreter
        # * `mask` is the perfect hashing mask of the class
        # * `id` is the identifier of the class
        # * `offset` is the relative offset of this attribute
-       private fun read_attribute_ph(instance: Pointer, vtable: Pointer, mask: Int, id: Int, offset: Int): Instance `{
+       fun read_attribute_ph(instance: Pointer, vtable: Pointer, mask: Int, id: Int, offset: Int): Instance `{
                // Perfect hashing position
                int hv = mask & id;
                long unsigned int *pointer = (long unsigned int*)(((long int *)vtable)[-hv]);
@@ -297,7 +307,7 @@ class VirtualMachine super NaiveInterpreter
        # Return the attribute value in `instance` with a direct access (SST)
        # * `instance` is the attributes array of the receiver
        # * `offset` is the absolute offset of this attribute
-       private fun read_attribute_sst(instance: Pointer, offset: Int): Instance `{
+       fun read_attribute_sst(instance: Pointer, offset: Int): Instance `{
                /* We can make a direct access to the attribute value
                   because this attribute is always at the same position
                   for the class of this receiver */
@@ -331,7 +341,7 @@ class VirtualMachine super NaiveInterpreter
        # * `id` is the identifier of the class
        # * `offset` is the relative offset of this attribute
        # * `value` is the new value for this attribute
-       private fun write_attribute_ph(instance: Pointer, vtable: Pointer, mask: Int, id: Int, offset: Int, value: Instance) `{
+       fun write_attribute_ph(instance: Pointer, vtable: Pointer, mask: Int, id: Int, offset: Int, value: Instance) `{
                // Perfect hashing position
                int hv = mask & id;
                long unsigned int *pointer = (long unsigned int*)(((long int *)vtable)[-hv]);
@@ -347,7 +357,7 @@ class VirtualMachine super NaiveInterpreter
        # * `instance` is the attributes array of the receiver
        # * `offset` is the absolute offset of this attribute
        # * `value` is the new value for this attribute
-       private fun write_attribute_sst(instance: Pointer, offset: Int, value: Instance) `{
+       fun write_attribute_sst(instance: Pointer, offset: Int, value: Instance) `{
                // Direct access to the position with the absolute offset
                ((Instance *)instance)[offset] = value;
                Instance_incr_ref(value);
diff --git a/src/vm_optimizations.nit b/src/vm_optimizations.nit
new file mode 100644 (file)
index 0000000..f657786
--- /dev/null
@@ -0,0 +1,342 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2015 Julien Pagès <julien.pages@lirmm.fr>
+#
+# 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.
+
+# Optimization of the nitvm
+module vm_optimizations
+
+import vm
+
+redef class VirtualMachine
+
+       # Add optimization of the method dispatch
+       redef fun callsite(callsite: nullable CallSite, arguments: Array[Instance]): nullable Instance
+       do
+               var initializers = callsite.mpropdef.initializers
+               if initializers.is_empty then return send_optimize(callsite.as(not null), arguments)
+
+               var recv = arguments.first
+               var i = 1
+               for p in initializers do
+                       if p isa MMethod then
+                               var args = [recv]
+                               for x in p.intro.msignature.mparameters do
+                                       args.add arguments[i]
+                                       i += 1
+                               end
+                               self.send(p, args)
+                       else if p isa MAttribute then
+                               assert recv isa MutableInstance
+                               write_attribute(p, recv, arguments[i])
+                               i += 1
+                       else abort
+               end
+               assert i == arguments.length
+
+               return send_optimize(callsite.as(not null), [recv])
+       end
+
+       # Try to have the most efficient implementation of the method dispatch
+       fun send_optimize(callsite: CallSite, args: Array[Instance]): nullable Instance
+       do
+               var recv = args.first
+               var mtype = recv.mtype
+               var ret = send_commons(callsite.mproperty, args, mtype)
+               if ret != null then return ret
+
+               if callsite.status == 0 then callsite.optimize(recv)
+
+               var propdef
+               if callsite.status == 1 then
+                       propdef = method_dispatch_sst(recv.vtable.internal_vtable, callsite.offset)
+               else
+                       propdef = method_dispatch_ph(recv.vtable.internal_vtable, recv.vtable.mask,
+                               callsite.id, callsite.offset)
+               end
+
+               return self.call(propdef, args)
+       end
+end
+
+redef class AAttrFormExpr
+       # Position of the attribute in attribute table
+       #
+       # The relative position of this attribute if perfect hashing is used,
+       # The absolute position of this attribute if SST is used
+       var offset: Int
+
+       # Indicate the status of the optimization for this node
+       #
+       # 0: default value
+       # 1: SST (direct access) can be used
+       # 2: PH (multiple inheritance implementation) must be used
+       var status: Int = 0
+
+       # Identifier of the class which introduced the attribute
+       var id: Int
+
+       # Optimize this attribute access
+       # * `mproperty` The attribute which is accessed
+       # * `recv` The receiver (The object) of the access
+       protected fun optimize(mproperty: MAttribute, recv: MutableInstance)
+       do
+               if mproperty.intro_mclassdef.mclass.positions_attributes[recv.mtype.as(MClassType).mclass] != -1 then
+                       # if this attribute class has an unique position for this receiver, then use direct access
+                       offset = mproperty.absolute_offset
+                       status = 1
+               else
+                       # Otherwise, perfect hashing must be used
+                       id = mproperty.intro_mclassdef.mclass.vtable.id
+                       offset = mproperty.offset
+                       status = 2
+               end
+       end
+end
+
+redef class AAttrExpr
+       redef fun expr(v)
+       do
+               # TODO : a workaround for now
+               if not v isa VirtualMachine then return super
+
+               var recv = v.expr(self.n_expr)
+               if recv == null then return null
+               if recv.mtype isa MNullType then fatal(v, "Receiver is null")
+               var mproperty = self.mproperty.as(not null)
+
+               assert recv isa MutableInstance
+               if status == 0 then optimize(mproperty, recv)
+
+               var i: Instance
+               if status == 1 then
+                       # SST
+                       i = v.read_attribute_sst(recv.internal_attributes, offset)
+               else
+                       # PH
+                       i = v.read_attribute_ph(recv.internal_attributes, recv.vtable.internal_vtable, recv.vtable.mask, id, offset)
+               end
+
+               # If we get a `MInit` value, throw an error
+               if i == v.initialization_value then
+                       v.fatal("Uninitialized attribute {mproperty.name}")
+                       abort
+               end
+
+               return i
+       end
+end
+
+redef class AAttrAssignExpr
+       redef fun stmt(v)
+       do
+               # TODO : a workaround for now
+               if not v isa VirtualMachine then
+                       super
+                       return
+               end
+
+               var recv = v.expr(self.n_expr)
+               if recv == null then return
+               if recv.mtype isa MNullType then fatal(v, "Receiver is null")
+               var i = v.expr(self.n_value)
+               if i == null then return
+               var mproperty = self.mproperty.as(not null)
+
+               assert recv isa MutableInstance
+               if status == 0 then optimize(mproperty, recv)
+
+               if status == 1 then
+                       v.write_attribute_sst(recv.internal_attributes, offset, i)
+               else
+                       v.write_attribute_ph(recv.internal_attributes, recv.vtable.internal_vtable,
+                                       recv.vtable.mask, id, offset, i)
+               end
+       end
+end
+
+# Add informations to optimize some method calls
+redef class CallSite
+       # Position of the method in virtual table
+       #
+       # The relative position of this MMethod if perfect hashing is used,
+       # The absolute position of this MMethod if SST is used
+       var offset: Int
+
+       # Indicate the status of the optimization for this node
+       #
+       # 0: default value
+       # 1: SST (direct access) can be used
+       # 2: PH (multiple inheritance implementation) must be used
+       var status: Int = 0
+
+       # Identifier of the class which introduced the MMethod
+       var id: Int
+
+       # Optimize a method dispatch,
+       # If this method is always at the same position in virtual table, we can use direct access,
+       # Otherwise we must use perfect hashing
+       fun optimize(recv: Instance)
+       do
+               if mproperty.intro_mclassdef.mclass.positions_methods[recv.mtype.as(MClassType).mclass] != -1 then
+                       offset = mproperty.absolute_offset
+                       status = 1
+               else
+                       offset = mproperty.offset
+                       status = 2
+               end
+               id = mproperty.intro_mclassdef.mclass.vtable.id
+       end
+end
+
+redef class AIsaExpr
+       # Identifier of the target class type
+       var id: Int
+
+       # If the Cohen test is used, the position of the target id in vtable
+       var position: Int
+
+       # Indicate the status of the optimization for this node
+       #
+       # 0 : the default value
+       # 1 : this test can be implemented with direct access
+       # 2 : this test must be implemented with perfect hashing
+       var status: Int = 0
+
+       redef fun expr(v)
+       do
+               # TODO : a workaround for now
+               if not v isa VirtualMachine then return super
+
+               var recv = v.expr(self.n_expr)
+               if recv == null then return null
+
+               if status == 0 then optimize(v, recv.mtype, self.cast_type.as(not null))
+               var mtype = v.unanchor_type(self.cast_type.as(not null))
+
+               # If this test can be optimized, directly call appropriate subtyping methods
+               if status == 1 and recv.mtype isa MClassType then
+                       # Direct access
+                       return v.bool_instance(v.inter_is_subtype_sst(id, position, recv.mtype.as(MClassType).mclass.vtable.internal_vtable))
+               else if status == 2 and recv.mtype isa MClassType then
+                       # Perfect hashing
+                       return v.bool_instance(v.inter_is_subtype_ph(id, recv.vtable.mask, recv.mtype.as(MClassType).mclass.vtable.internal_vtable))
+               else
+                       # Use the slow path (default)
+                       return v.bool_instance(v.is_subtype(recv.mtype, mtype))
+               end
+       end
+
+       # Optimize a `AIsaExpr`
+       # `source` the source type of the expression
+       # `target` the target type of the subtyping test
+       private fun optimize(v: VirtualMachine, source: MType, target: MType)
+       do
+               # If the source class and target class are not classic classes (non-generics) then return
+               if not source isa MClassType or not target isa MClassType or target isa MGenericType then
+                       return
+               end
+
+               if not target.mclass.loaded then return
+
+               # Try to get the position of the target type in source's structures
+               var value = source.mclass.positions_methods.get_or_null(target.mclass)
+
+               if value != null then
+                       if value != -1 then
+                               # Store informations for Cohen test
+                               position = target.mclass.color
+                               status = 1
+                       else
+                               # We use perfect hashing
+                               status = 2
+                       end
+               end
+               id = target.mclass.vtable.id
+       end
+end
+
+redef class AAsCastExpr
+       # Identifier of the target class type
+       var id: Int
+
+       # If the Cohen test is used, the position of the target id in vtable
+       var position: Int
+
+       # Indicate the status of the optimization for this node
+       #
+       # 0 : the default value
+       # 1 : this test can be implemented with direct access
+       # 2 : this test must be implemented with perfect hashing
+       var status: Int = 0
+
+       redef fun expr(v)
+       do
+               # TODO : a workaround for now
+               if not v isa VirtualMachine then return super
+
+               var recv = v.expr(self.n_expr)
+               if recv == null then return null
+
+               if status == 0 then optimize(v, recv.mtype, self.mtype.as(not null))
+
+               var mtype = self.mtype.as(not null)
+               var amtype = v.unanchor_type(mtype)
+
+               var res: Bool
+               if status == 1 and recv.mtype isa MClassType then
+                       # Direct access
+                       res = v.inter_is_subtype_sst(id, position, recv.mtype.as(MClassType).mclass.vtable.internal_vtable)
+               else if status == 2 and recv.mtype isa MClassType then
+                       # Perfect hashing
+                       res = v.inter_is_subtype_ph(id, recv.vtable.mask, recv.mtype.as(MClassType).mclass.vtable.internal_vtable)
+               else
+                       # Use the slow path (default)
+                       res = v.is_subtype(recv.mtype, amtype)
+               end
+
+               if not res then
+                       fatal(v, "Cast failed. Expected `{amtype}`, got `{recv.mtype}`")
+               end
+               return recv
+       end
+
+       # Optimize a `AAsCastExpr`
+       # * `source` the source type of the expression
+       # * `target` the target type of the subtyping test
+       private fun optimize(v: VirtualMachine, source: MType, target: MType)
+       do
+               # If the source class and target class are not classic classes (non-generics) then return
+               if not source isa MClassType or not target isa MClassType or target isa MGenericType then
+                       return
+               end
+
+               if not target.mclass.loaded then return
+
+               # Try to get the position of the target type in source's structures
+               var value = source.mclass.positions_methods.get_or_null(target.mclass)
+
+               if value != null then
+                       if value != -1 then
+                               # Store informations for Cohen test
+                               position = target.mclass.color
+                               status = 1
+                       else
+                               # We use perfect hashing
+                               status = 2
+                       end
+               end
+               id = target.mclass.vtable.id
+       end
+end
index 6d2badc..fdafa3d 100644 (file)
@@ -24,7 +24,7 @@ class A
                2.output
                var res = a
                if res == 10 then res = 20
-               return res
+               return res #alt1# return #alt2#
        end
 end
 
index 69e3f0d..6eddab1 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-#alt1# module error_annot_c_compiler_alt1 is c_compiler_option
-#alt2# module error_annot_c_compiler_alt2 is c_compiler_option(foo("llvm-config"))
-#alt3# module error_annot_c_compiler_alt3 is c_compiler_option(foo("llvm-config", "2nd arg"))
-#alt4# module error_annot_c_compiler_alt4 is c_linker_option
-#alt5# module error_annot_c_compiler_alt5 is c_compiler_option(exec("invalid-program"))
-#alt6# module error_annot_c_compiler_alt6 is c_compiler_option(exec)
+#alt1# module error_annot_c_compiler_alt1 is cflags
+#alt2# module error_annot_c_compiler_alt2 is cflags(foo("llvm-config"))
+#alt3# module error_annot_c_compiler_alt3 is cflags(foo("llvm-config", "2nd arg"))
+#alt4# module error_annot_c_compiler_alt4 is ldflags
+#alt5# module error_annot_c_compiler_alt5 is cflags(exec("invalid-program"))
+#alt6# module error_annot_c_compiler_alt6 is cflags(exec)
 
 fun foo `{ printf("nothing...\n"); `}
 
diff --git a/tests/sav/base_attr_init_val_block_alt1.res b/tests/sav/base_attr_init_val_block_alt1.res
new file mode 100644 (file)
index 0000000..e50539b
--- /dev/null
@@ -0,0 +1 @@
+alt/base_attr_init_val_block_alt1.nit:27,3--8: Error: Return without value in a function.
diff --git a/tests/sav/base_attr_init_val_block_alt2.res b/tests/sav/base_attr_init_val_block_alt2.res
new file mode 100644 (file)
index 0000000..8545480
--- /dev/null
@@ -0,0 +1 @@
+alt/base_attr_init_val_block_alt2.nit:23,6: Control error: Reached end of block (a 'return' with a value was expected).
diff --git a/tests/sav/doors_with_classes.res b/tests/sav/doors_with_classes.res
new file mode 100644 (file)
index 0000000..23c9daf
--- /dev/null
@@ -0,0 +1,100 @@
+Door 1: Open
+Door 2: Closed
+Door 3: Closed
+Door 4: Open
+Door 5: Closed
+Door 6: Closed
+Door 7: Closed
+Door 8: Closed
+Door 9: Open
+Door 10: Closed
+Door 11: Closed
+Door 12: Closed
+Door 13: Closed
+Door 14: Closed
+Door 15: Closed
+Door 16: Open
+Door 17: Closed
+Door 18: Closed
+Door 19: Closed
+Door 20: Closed
+Door 21: Closed
+Door 22: Closed
+Door 23: Closed
+Door 24: Closed
+Door 25: Open
+Door 26: Closed
+Door 27: Closed
+Door 28: Closed
+Door 29: Closed
+Door 30: Closed
+Door 31: Closed
+Door 32: Closed
+Door 33: Closed
+Door 34: Closed
+Door 35: Closed
+Door 36: Open
+Door 37: Closed
+Door 38: Closed
+Door 39: Closed
+Door 40: Closed
+Door 41: Closed
+Door 42: Closed
+Door 43: Closed
+Door 44: Closed
+Door 45: Closed
+Door 46: Closed
+Door 47: Closed
+Door 48: Closed
+Door 49: Open
+Door 50: Closed
+Door 51: Closed
+Door 52: Closed
+Door 53: Closed
+Door 54: Closed
+Door 55: Closed
+Door 56: Closed
+Door 57: Closed
+Door 58: Closed
+Door 59: Closed
+Door 60: Closed
+Door 61: Closed
+Door 62: Closed
+Door 63: Closed
+Door 64: Open
+Door 65: Closed
+Door 66: Closed
+Door 67: Closed
+Door 68: Closed
+Door 69: Closed
+Door 70: Closed
+Door 71: Closed
+Door 72: Closed
+Door 73: Closed
+Door 74: Closed
+Door 75: Closed
+Door 76: Closed
+Door 77: Closed
+Door 78: Closed
+Door 79: Closed
+Door 80: Closed
+Door 81: Open
+Door 82: Closed
+Door 83: Closed
+Door 84: Closed
+Door 85: Closed
+Door 86: Closed
+Door 87: Closed
+Door 88: Closed
+Door 89: Closed
+Door 90: Closed
+Door 91: Closed
+Door 92: Closed
+Door 93: Closed
+Door 94: Closed
+Door 95: Closed
+Door 96: Closed
+Door 97: Closed
+Door 98: Closed
+Door 99: Closed
+Door 100: Open
index 981a90b..23b9437 100644 (file)
@@ -1 +1 @@
-alt/error_annot_c_compiler_alt1.nit:17,39--55: Syntax error: "c_compiler_option" expects at least one argument.
+alt/error_annot_c_compiler_alt1.nit:17,39--44: Syntax error: "cflags" expects at least one argument.
index b460682..2459cd4 100644 (file)
@@ -1 +1 @@
-alt/error_annot_c_compiler_alt2.nit:18,39--75: Syntax error: "c_compiler_option" accepts only calls to `exec` with the command as arguments.
+alt/error_annot_c_compiler_alt2.nit:18,39--64: Syntax error: "cflags" accepts only calls to `exec` with the command as arguments.
index 8142bf8..a584f16 100644 (file)
@@ -1 +1 @@
-alt/error_annot_c_compiler_alt3.nit:19,39--86: Syntax error: "c_compiler_option" accepts only calls to `exec` with the command as arguments.
+alt/error_annot_c_compiler_alt3.nit:19,39--75: Syntax error: "cflags" accepts only calls to `exec` with the command as arguments.
index d753ea9..f34ea44 100644 (file)
@@ -1 +1 @@
-alt/error_annot_c_compiler_alt4.nit:20,39--53: Syntax error: "c_linker_option" expects at least one argument.
+alt/error_annot_c_compiler_alt4.nit:20,39--45: Syntax error: "ldflags" expects at least one argument.
index 2251e01..133d200 100644 (file)
@@ -1 +1 @@
-alt/error_annot_c_compiler_alt5.nit:21,57--79: Annotation error: Something went wrong executing the argument of annotation "c_compiler_option", make sure the command is valid.
+alt/error_annot_c_compiler_alt5.nit:21,46--68: Annotation error: Something went wrong executing the argument of annotation "cflags", make sure the command is valid.
index 694b887..cc29f8a 100644 (file)
@@ -1 +1 @@
-alt/error_annot_c_compiler_alt6.nit:22,39--61: Syntax error: "c_compiler_option" accepts only calls to `exec` with the command as arguments.
+alt/error_annot_c_compiler_alt6.nit:22,39--50: Syntax error: "cflags" accepts only calls to `exec` with the command as arguments.
index e55ae8a..7277957 100644 (file)
 # limitations under the License.
 
 module test_annot_c_compiler is
-       c_compiler_option("-I /usr/include")
-       c_compiler_option(exec("pkg-config", "--cflags", "sdl"))
-       c_linker_option("-lm")
-       c_linker_option("-lm", "-L /usr/bin")
+       cflags "-I /usr/include"
+       cflags exec("pkg-config", "--cflags", "sdl")
+       ldflags "-lm"
+       ldflags("-lm", "-L /usr/bin")
 end
 
 fun dummy `{ printf("nothing...\n"); `}