From 05bf380d21a52357d506baca86659f782d89c7e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Laferri=C3=A8re?= Date: Tue, 29 Sep 2026 09:51:31 -0400 Subject: [PATCH 01/13] tests: correctly apply `gitlab_ci.skip` only when running on GitLab CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the skip file for GitLab CI to actually apply only to GitLab CI. A missing $ made the list apply everywhere and the Objective-C tests never ran. Signed-off-by: Alexis Laferrière --- tests/tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tests.sh b/tests/tests.sh index c19a9a89dc..93b55655b4 100755 --- a/tests/tests.sh +++ b/tests/tests.sh @@ -411,7 +411,7 @@ need_skip() echo >>$xml "" return 0 fi - if test -n "GITLAB_CI" && echo "$1" | grep -f "gitlab_ci.skip" >/dev/null 2>&1; then + if test -n "$GITLAB_CI" && echo "$1" | grep -f "gitlab_ci.skip" >/dev/null 2>&1; then echo "=> $2: [skip gitlab ci]" echo >>$xml "" return 0 From 620d2f27cab7938c34fb46a91147f7602d360bdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Laferri=C3=A8re?= Date: Tue, 29 Sep 2026 09:51:31 -0400 Subject: [PATCH 02/13] tests: ensure skipping `mpi` doesn't skip `compiler` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Match `mpi` only at the start of a word, which still covers `mpi_simple` and the `lib/mpi` paths. The bare `mpi` pattern also matched `compiler` and skipped: - `base_compile` - `error_annot_c_compiler` - `test_annot_c_compiler` - `test_annot_c_compiler_conditional` Signed-off-by: Alexis Laferrière --- tests/Darwin.skip | 2 +- tests/MINGW64_NT.skip | 2 +- tests/gitlab_ci.skip | 2 +- tests/turing.skip | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Darwin.skip b/tests/Darwin.skip index cb3996288e..1600b6b20e 100644 --- a/tests/Darwin.skip +++ b/tests/Darwin.skip @@ -2,7 +2,7 @@ android java jvm neo -mpi +\ Date: Tue, 29 Sep 2026 20:34:22 -0700 Subject: [PATCH 03/13] tests: ensure more skip patterns don't match unrelated tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix bare patterns in the skip files that skipped more than intended: - `neo` also skipped `chameneosredux`, so it was never compiled on macOS. Replace it by `test_neo`, which still covers `test_neo` and `test_neo4j`. - `nitc_args1` also skipped `nitc_args10`, `11` and `12` under the interpreters, these never ran on niti and nitvm. - The `nit_args` also matched the `nitunit_args`. Signed-off-by: Alexis Laferrière --- tests/Darwin.skip | 2 +- tests/niti.skip | 24 ++++++++++++------------ tests/nitvm.skip | 24 ++++++++++++------------ tests/turing.skip | 2 +- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/tests/Darwin.skip b/tests/Darwin.skip index 1600b6b20e..24c5f66ae8 100644 --- a/tests/Darwin.skip +++ b/tests/Darwin.skip @@ -1,7 +1,7 @@ android java jvm -neo +test_neo \ +\ +\ +\ +\ +\ +\ nitvm_args1 nitvm_args3 nitin -nitc_args1 -nitc_args3 -nitc_args5 -nitc_args6 -nitc_args8 +\ +\ +\ +\ +\ nitpick_args1 nitunit_args test_docdown_args diff --git a/tests/nitvm.skip b/tests/nitvm.skip index 61f68f8ce8..a2c3f5ae08 100644 --- a/tests/nitvm.skip +++ b/tests/nitvm.skip @@ -1,19 +1,19 @@ shoot_logic -nit_args1 -nit_args3 -nit_args4 -nit_args5 -nit_args6 -nit_args8 -nit_args9 +\ +\ +\ +\ +\ +\ +\ nitvm_args1 nitvm_args3 nitin -nitc_args1 -nitc_args3 -nitc_args5 -nitc_args6 -nitc_args8 +\ +\ +\ +\ +\ nitpick_args1 nitunit_args test_docdown_args diff --git a/tests/turing.skip b/tests/turing.skip index d988a33460..6f446b1f80 100644 --- a/tests/turing.skip +++ b/tests/turing.skip @@ -3,7 +3,7 @@ _linux android gles curl -neo +test_neo gtk nitcorn ffi_objc From 436fcdfcc2ab65755326b3d0298ad5f4750e430f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Laferri=C3=A8re?= Date: Wed, 30 Sep 2026 09:02:52 -0700 Subject: [PATCH 04/13] tests: remove dead skip patterns and listed paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The skip files listed tests that were renamed or deleted: - `converter` and `actors_` in `exec.skip` - `wiringPi` in `gitlab_ci.skip` - `shoot_logic`, `test_docdown_args` and `test_ropebuffer` in `niti.skip` and `nitvm.skip` - `test_docdown` and `^neo_doxygen` in `nitcg.skip` `listfull.sh` still listed the deleted `shoot` example, `friendz` and `neo_doxygen`, and globs on `examples/*/src/` that now match nothing. Signed-off-by: Alexis Laferrière --- tests/exec.skip | 2 -- tests/gitlab_ci.skip | 1 - tests/listfull.sh | 6 ------ tests/nitcg.skip | 2 -- tests/niti.skip | 3 --- tests/nitvm.skip | 3 --- 6 files changed, 17 deletions(-) diff --git a/tests/exec.skip b/tests/exec.skip index 3be05dd243..42fea95d0f 100644 --- a/tests/exec.skip +++ b/tests/exec.skip @@ -2,7 +2,6 @@ example_exec_ls leapfrog_curses simple_file_server websocket_server -converter show_basedir langannot loops_infinite @@ -10,4 +9,3 @@ read_entire_file letter_frequency threadpool_example chameneosredux -actors_ diff --git a/tests/gitlab_ci.skip b/tests/gitlab_ci.skip index 6139ab331e..f41cc7ab21 100644 --- a/tests/gitlab_ci.skip +++ b/tests/gitlab_ci.skip @@ -2,4 +2,3 @@ emscripten glsl \ \ \ @@ -16,7 +15,6 @@ nitin \ nitpick_args1 nitunit_args -test_docdown_args pep8analysis emscripten nitserial_args @@ -35,7 +33,6 @@ input first_letter_last_letter fibonacci_word shootout_nsieve -test_ropebuffer ui_test test_text_stat nitsaf_args diff --git a/tests/nitvm.skip b/tests/nitvm.skip index a2c3f5ae08..386c5c6a65 100644 --- a/tests/nitvm.skip +++ b/tests/nitvm.skip @@ -1,4 +1,3 @@ -shoot_logic \ \ \ @@ -16,7 +15,6 @@ nitin \ nitpick_args1 nitunit_args -test_docdown_args pep8analysis emscripten nitserial_args @@ -35,7 +33,6 @@ input first_letter_last_letter fibonacci_word shootout_nsieve -test_ropebuffer ui_test test_text_stat nitsaf.args From f9ee9846e44ee9320016992a0775a4e469d53e25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Laferri=C3=A8re?= Date: Wed, 30 Sep 2026 10:58:50 -0700 Subject: [PATCH 05/13] glsl_validation: report all shader errors with `glslangValidator -C` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since glslang 11, the validator stops at the first error by default. Let's use the `-C` flag, for cascading errors, which restores reporting all errors. Signed-off-by: Alexis Laferrière --- src/frontend/glsl_validation.nit | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/frontend/glsl_validation.nit b/src/frontend/glsl_validation.nit index f6f3760fbc..cb7f31a2fc 100644 --- a/src/frontend/glsl_validation.nit +++ b/src/frontend/glsl_validation.nit @@ -88,8 +88,8 @@ private class GLSLValidationPhase shader.write_to_file path - # Execute the validator - var proc_validator = new ProcessReader("glslangValidator", path) + # Execute the validator, `-C` reports all errors instead of stopping at the first + var proc_validator = new ProcessReader("glslangValidator", "-C", path) proc_validator.wait var lines = proc_validator.read_all.split('\n') proc_validator.close From c8466f9f7cd97650b449b6da1ff31038ccc3e65b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Laferri=C3=A8re?= Date: Wed, 30 Sep 2026 09:15:52 -0700 Subject: [PATCH 06/13] gitlab ci: run the Objective-C, GLSL, MPI and Emscripten tests on GitHub MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the `gitlab_ci.skip` fix more tests will run on GitHub and some would fail. Install what they need on the Ubuntu runners: - `clang` and `gobjc` for the Objective-C FFI - `glslang-tools` for `test_glsl_validation` - `emscripten` for `emscripten_nodejs` Signed-off-by: Alexis Laferrière --- .github/workflows/ci-pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-pr.yml b/.github/workflows/ci-pr.yml index ca23efdb1f..caeb56257e 100644 --- a/.github/workflows/ci-pr.yml +++ b/.github/workflows/ci-pr.yml @@ -5,7 +5,7 @@ env: # BASIC_PACKAGES is used fo the basic tools (make) BASIC_PACKAGES: git build-essential ccache libgc-dev graphviz libunwind-dev libreadline-dev pkg-config # MORE_PACKAGES is used for more tools and libs (make more) - MORE_PACKAGES: libgmp-dev libcurl4-openssl-dev libevent-dev openjdk-17-jdk-headless libgles-dev libegl-dev libsdl1.2-dev libsdl2-dev libsdl2-mixer-dev libsdl2-gfx-dev libsdl2-image-dev libsdl2-net-dev libsdl2-ttf-dev libgtk-3-dev inkscape postgresql libxdg-basedir-dev gettext libsqlite3-dev libpq-dev libmongoc-dev openmpi-bin libopenmpi-dev + MORE_PACKAGES: libgmp-dev libcurl4-openssl-dev libevent-dev openjdk-17-jdk-headless libgles-dev libegl-dev libsdl1.2-dev libsdl2-dev libsdl2-mixer-dev libsdl2-gfx-dev libsdl2-image-dev libsdl2-net-dev libsdl2-ttf-dev libgtk-3-dev inkscape postgresql libxdg-basedir-dev gettext libsqlite3-dev libpq-dev libmongoc-dev openmpi-bin libopenmpi-dev clang gobjc glslang-tools emscripten JAVA_HOME: /usr/lib/jvm/java-17-openjdk-amd64/ JNI_LIB_PATH: /usr/lib/jvm/java-17-openjdk-amd64/lib/server/ LD_LIBRARY_PATH: /usr/lib/jvm/java-17-openjdk-amd64/lib/server/ From 6187b0cb50abb75a08f14337f26f1415781f5937 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Laferri=C3=A8re?= Date: Wed, 30 Sep 2026 09:15:52 -0700 Subject: [PATCH 07/13] github ci: fix the artifact path of the full test results MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A stray backtick in the path prevented uploading the `.res` files of the tests-full jobs. Signed-off-by: Alexis Laferrière --- .github/workflows/ci-pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-pr.yml b/.github/workflows/ci-pr.yml index caeb56257e..0cca76e68f 100644 --- a/.github/workflows/ci-pr.yml +++ b/.github/workflows/ci-pr.yml @@ -112,7 +112,7 @@ jobs: - uses: actions/upload-artifact@v4 if: ${{ !cancelled() }} with: - path: 'tests/out/*.res`' + path: 'tests/out/*.res' name: tests-full-${{ matrix.engine }}-res nitunit-some: From e0903b269c8354967ac1083f52d1b3205d0551d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Laferri=C3=A8re?= Date: Wed, 30 Sep 2026 17:07:05 -0700 Subject: [PATCH 08/13] nitcorn: percent-decode the keys of POST arguments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Decode the POST keys like we do for POST values, and the keys of GET arguments. Signed-off-by: Alexis Laferrière --- lib/nitcorn/http_request.nit | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/nitcorn/http_request.nit b/lib/nitcorn/http_request.nit index f1135a584e..80fc9a08cb 100644 --- a/lib/nitcorn/http_request.nit +++ b/lib/nitcorn/http_request.nit @@ -152,9 +152,10 @@ class HttpRequestParser for line in lines do if not line.trim.is_empty then var parts = line.split_once_on('=') if parts.length > 1 then + var key = parts[0].replace('+', " ").from_percent_encoding var decoded = parts[1].replace('+', " ").from_percent_encoding - http_request.post_args[parts[0]] = decoded - http_request.all_args[parts[0]] = decoded + http_request.post_args[key] = decoded + http_request.all_args[key] = decoded end end end From 6ec0f3cc7d524c5f2af9b678f5d2fef0936649e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Laferri=C3=A8re?= Date: Wed, 30 Sep 2026 18:32:44 -0700 Subject: [PATCH 09/13] nitcorn: wrap the hello world example server in a function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function takes the interface and the root of the Web site to serve. This enables other programs to run the server. The `/hello/:name` action also echoes the arguments of POST requests. Signed-off-by: Alexis Laferrière --- .../examples/src/nitcorn_hello_world.nit | 36 +++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/lib/nitcorn/examples/src/nitcorn_hello_world.nit b/lib/nitcorn/examples/src/nitcorn_hello_world.nit index adcebd2de0..d60f864907 100644 --- a/lib/nitcorn/examples/src/nitcorn_hello_world.nit +++ b/lib/nitcorn/examples/src/nitcorn_hello_world.nit @@ -58,25 +58,39 @@ class ParamAction do var response = new HttpResponse(200) var name = http_request.param("name") + var body if name == null then - response.body = "No name..." + body = "No name..." else - response.body = "Hello {name}" + body = "Hello {name}" end + + # Echo the arguments of a POST request + for key, value in http_request.post_args do body += "\n{key} = {value}" + + response.body = body return response end end -var vh = new VirtualHost("localhost:8080") +# Run the hello world Web server on `interfac` +# +# Serve files other than the dynamic pages from the local directory `www_root`. +fun hello_world_server(interfac, www_root: String) +do + var vh = new VirtualHost(interfac) -# Serve index.html with our custom handler -vh.routes.add new Route("/index.html", new StaticAction) -vh.routes.add new Route("/hello/:name", new ParamAction) + # Serve index.html with our custom handler + vh.routes.add new Route("/index.html", new StaticAction) + vh.routes.add new Route("/hello/:name", new ParamAction) -# Serve everything else with a standard `FileServer` with a root at "www/hello_world/" -vh.routes.add new Route(null, new FileServer("www/hello_world/")) + # Serve everything else with a standard `FileServer` with a root at `www_root` + vh.routes.add new Route(null, new FileServer(www_root)) + + var factory = new HttpFactory.and_libevent + factory.config.virtual_hosts.add vh + factory.run +end -var factory = new HttpFactory.and_libevent -factory.config.virtual_hosts.add vh -factory.run +hello_world_server("localhost:8080", "www/hello_world/") From c9f02753814e7f8768591332897e975fb165e5e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Laferri=C3=A8re?= Date: Wed, 30 Sep 2026 18:32:44 -0700 Subject: [PATCH 10/13] curl: split the `curl_http` example and test it against a local server MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The curl tests relied on the availability and content of `example.org`. The website content isn't stable and not designed for testing. Let's instead launch a local nitcorn server for testing against. Replace `curl_http` by three straightforward examples. Each exposes its request as a function and expects a URL on the command line: - `curl_http_get` - `curl_http_post` - `curl_http_download` Intro `curl_http_local_server`, it runs `hello_world_server` from the nitcorn examples in a thread and executes the three requests against it. Signed-off-by: Alexis Laferrière --- lib/curl/examples/curl_http.nit | 104 ------------------- lib/curl/examples/curl_http_download.nit | 46 ++++++++ lib/curl/examples/curl_http_get.nit | 40 +++++++ lib/curl/examples/curl_http_local_server.nit | 93 +++++++++++++++++ lib/curl/examples/curl_http_post.nit | 57 ++++++++++ tests/.gitignore | 1 - tests/curl_http.args | 3 - tests/sav/curl_http.res | 1 - tests/sav/curl_http_args1.res | 3 - tests/sav/curl_http_args2.res | 4 - tests/sav/curl_http_args3.res | 3 - tests/sav/curl_http_download.res | 1 + tests/sav/curl_http_get.res | 1 + tests/sav/curl_http_local_server.res | 25 +++++ tests/sav/curl_http_post.res | 1 + 15 files changed, 264 insertions(+), 119 deletions(-) delete mode 100644 lib/curl/examples/curl_http.nit create mode 100644 lib/curl/examples/curl_http_download.nit create mode 100644 lib/curl/examples/curl_http_get.nit create mode 100644 lib/curl/examples/curl_http_local_server.nit create mode 100644 lib/curl/examples/curl_http_post.nit delete mode 100644 tests/curl_http.args delete mode 100644 tests/sav/curl_http.res delete mode 100644 tests/sav/curl_http_args1.res delete mode 100644 tests/sav/curl_http_args2.res delete mode 100644 tests/sav/curl_http_args3.res create mode 100644 tests/sav/curl_http_download.res create mode 100644 tests/sav/curl_http_get.res create mode 100644 tests/sav/curl_http_local_server.res create mode 100644 tests/sav/curl_http_post.res diff --git a/lib/curl/examples/curl_http.nit b/lib/curl/examples/curl_http.nit deleted file mode 100644 index e4fdf79037..0000000000 --- a/lib/curl/examples/curl_http.nit +++ /dev/null @@ -1,104 +0,0 @@ -# This file is part of NIT ( http://www.nitlanguage.org ). -# -# Copyright 2013 Matthieu Lucas -# -# 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. - -# Example use of the Curl module -module curl_http is example - -import curl - -# Custom delegate to receive callbacks from a Curl transfer -class MyHttpFetcher - super CurlCallbacks - - # Body of the downloaded file - var fetched_body = "" - - redef fun header_callback(line) do - # We keep this callback silent for testing purposes - #if not line.has_prefix("Date:") then print "Header_callback: {line}" - end - - redef fun body_callback(line) do self.fetched_body += line - - redef fun stream_callback(buffer) do print "Stream_callback: {buffer}" -end - -private fun print_usage do print "Usage: curl_http [POST|GET|GET_FILE] url" - -if args.length < 2 then - print_usage - exit 1 -end - -var url = args[1] -var request = new CurlHTTPRequest(url) -request.verbose = false # Set to `true` to debug - -if args[0] == "GET" then - # HTTP Get Request - var response = request.execute - - if response isa CurlResponseSuccess then - print "Status code: {response.status_code}" - print "Body: {response.body_str}" - else if response isa CurlResponseFailed then - print "Error code: {response.error_code}" - print "Error msg: {response.error_msg}" - end - -else if args[0] == "POST" then - # HTTP Post Request - var my_http_fetcher = new MyHttpFetcher - request.delegate = my_http_fetcher - - var post_data = new HeaderMap - post_data["Bugs Bunny"] = "Daffy Duck" - post_data["Batman"] = "Robin likes special characters @#ùà!è§'(\"é&://,;<>∞~*" - post_data["Batman"] = "Yes you can set multiple identical keys, but APACHE will consider only one, the last one" - request.data = post_data - var response = request.execute - - print "Our body from the callback: {my_http_fetcher.fetched_body}" - - if response isa CurlResponseSuccess then - print "*** Answer ***" - print "Status code: {response.status_code}" - print "Body should be empty, because we decided to manage callbacks: {response.body_str.length}" - else if response isa CurlResponseFailed then - print "Error code: {response.error_code}" - print "Error msg: {response.error_msg}" - end - -else if args[0] == "GET_FILE" then - # HTTP Get to file Request - var headers = new HeaderMap - headers["Accept"] = "Moo" - request.headers = headers - var response = request.download_to_file(null) - - if response isa CurlFileResponseSuccess then - print "*** Answer ***" - print "Status code: {response.status_code}" - print "Size downloaded: {response.size_download}" - else if response isa CurlResponseFailed then - print "Error code: {response.error_code}" - print "Error msg: {response.error_msg}" - end - -else - print_usage - exit 1 -end diff --git a/lib/curl/examples/curl_http_download.nit b/lib/curl/examples/curl_http_download.nit new file mode 100644 index 0000000000..46879b5001 --- /dev/null +++ b/lib/curl/examples/curl_http_download.nit @@ -0,0 +1,46 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Example of downloading a file with the Curl module +module curl_http_download is example + +import curl + +# Download `url` to the local file `file_path` +fun http_download(url, file_path: String): CurlResponse +do + var request = new CurlHTTPRequest(url) + request.verbose = false # Set to `true` to debug + + # Custom header + var headers = new HeaderMap + headers["Accept"] = "Moo" + request.headers = headers + + return request.download_to_file(file_path) +end + +if args.length != 2 then + print "Usage: curl_http_download url file" + exit 1 +end + +var response = http_download(args[0], args[1]) +if response isa CurlFileResponseSuccess then + print "Status code: {response.status_code}" + print "Size downloaded: {response.size_download}" +else if response isa CurlResponseFailed then + print "Error code: {response.error_code}" + print "Error msg: {response.error_msg}" +end diff --git a/lib/curl/examples/curl_http_get.nit b/lib/curl/examples/curl_http_get.nit new file mode 100644 index 0000000000..ce96de4953 --- /dev/null +++ b/lib/curl/examples/curl_http_get.nit @@ -0,0 +1,40 @@ +# 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. + +# Example of an HTTP GET request with the Curl module +module curl_http_get is example + +import curl + +# Execute an HTTP GET request on `url` +fun http_get(url: String): CurlResponse +do + var request = new CurlHTTPRequest(url) + request.verbose = false # Set to `true` to debug + return request.execute +end + +if args.length != 1 then + print "Usage: curl_http_get url" + exit 1 +end + +var response = http_get(args.first) +if response isa CurlResponseSuccess then + print "Status code: {response.status_code}" + print "Body: {response.body_str}" +else if response isa CurlResponseFailed then + print "Error code: {response.error_code}" + print "Error msg: {response.error_msg}" +end diff --git a/lib/curl/examples/curl_http_local_server.nit b/lib/curl/examples/curl_http_local_server.nit new file mode 100644 index 0000000000..4625449e97 --- /dev/null +++ b/lib/curl/examples/curl_http_local_server.nit @@ -0,0 +1,93 @@ +# 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. + +# Run the `curl_http_*` examples against the local `nitcorn_hello_world` server +# +# The server answers with the content of the hello world Web site. +# This is mainly used by the tests. +module curl_http_local_server is example + +import curl_http_get +import curl_http_post +import curl_http_download +import nitcorn::nitcorn_hello_world +import pthreads + +# Port of the local server, unique to each run of the tests +fun local_port: Int +do + var testing_id = "NIT_TESTING_ID".environ + if testing_id.is_int then return 20000 + testing_id.to_i % 10000 + return 20000 +end + +# Thread running the local server +class ServerThread + super Thread + + redef fun main + do + # Hide the testing concept from nitcorn to force it to actually run + "NIT_TESTING".setenv("false") + + # The file server of the example is not used, only its dynamic pages + hello_world_server("localhost:{local_port}", ".") + return null + end +end + +# Print the status of `response`, or its error +fun print_response(response: CurlResponse) +do + if response isa CurlResponseSuccess then + print "Status code: {response.status_code}" + else if response isa CurlFileResponseSuccess then + print "Status code: {response.status_code}" + else if response isa CurlResponseFailed then + print "Error code: {response.error_code}" + print "Error msg: {response.error_msg}" + end +end + +var host = "http://localhost:{local_port}" + +# Launch the server in the background +var server = new ServerThread +server.start +0.1.sleep + +print "# GET" + +var get_response = http_get(host / "index.html") +print_response get_response +if get_response isa CurlResponseSuccess then + print "Body: {get_response.body_str}" +end + +print "# POST" + +print_response http_post(host / "hello/curl") + +print "# Download" + +var write_dir = "WRITE".environ +if write_dir.is_empty then write_dir = "." +write_dir.mkdir + +var download_response = http_download(host / "index.html", + write_dir / "index.html") +print_response download_response +if download_response isa CurlFileResponseSuccess then + print "Size downloaded: {download_response.size_download}" +end diff --git a/lib/curl/examples/curl_http_post.nit b/lib/curl/examples/curl_http_post.nit new file mode 100644 index 0000000000..0643573a36 --- /dev/null +++ b/lib/curl/examples/curl_http_post.nit @@ -0,0 +1,57 @@ +# 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. + +# Example of an HTTP POST request with the Curl module +module curl_http_post is example + +import curl + +# Callbacks printing the body of the answer as it is received +class PrintBodyCallbacks + super CurlCallbacks + + redef fun body_callback(line) do print "Received: {line}" +end + +# Execute an HTTP POST request on `url` with sample data +# +# The body of the answer is passed to `PrintBodyCallbacks` instead of +# being stored in the response. +fun http_post(url: String): CurlResponse +do + var request = new CurlHTTPRequest(url) + request.verbose = false # Set to `true` to debug + request.delegate = new PrintBodyCallbacks + + var data = new HeaderMap + data["Bugs Bunny"] = "Daffy Duck" + data["Batman"] = "Robin likes special characters @#ùà!è§'(\"é&://,;<>∞~*" + data["Batman"] = "Yes you can set multiple identical keys, but APACHE will consider only one, the last one" + request.data = data + + return request.execute +end + +if args.length != 1 then + print "Usage: curl_http_post url" + exit 1 +end + +var response = http_post(args.first) +if response isa CurlResponseSuccess then + print "Status code: {response.status_code}" +else if response isa CurlResponseFailed then + print "Error code: {response.error_code}" + print "Error msg: {response.error_msg}" +end diff --git a/tests/.gitignore b/tests/.gitignore index 68eac5303e..888f9f6072 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1,4 +1,3 @@ -example.org fulltest listtest.sh modifs diff --git a/tests/curl_http.args b/tests/curl_http.args deleted file mode 100644 index 86fbf1003c..0000000000 --- a/tests/curl_http.args +++ /dev/null @@ -1,3 +0,0 @@ -GET example.org -POST example.com -GET_FILE example.org diff --git a/tests/sav/curl_http.res b/tests/sav/curl_http.res deleted file mode 100644 index 5118616f2e..0000000000 --- a/tests/sav/curl_http.res +++ /dev/null @@ -1 +0,0 @@ -Usage: curl_http [POST|GET|GET_FILE] url diff --git a/tests/sav/curl_http_args1.res b/tests/sav/curl_http_args1.res deleted file mode 100644 index a035b4181a..0000000000 --- a/tests/sav/curl_http_args1.res +++ /dev/null @@ -1,3 +0,0 @@ -Status code: 200 -Body: Example Domain

Example Domain

This domain is for use in documentation examples without needing permission. Avoid use in operations.

Learn more

- diff --git a/tests/sav/curl_http_args2.res b/tests/sav/curl_http_args2.res deleted file mode 100644 index c391a76df8..0000000000 --- a/tests/sav/curl_http_args2.res +++ /dev/null @@ -1,4 +0,0 @@ -Our body from the callback: Example Domain

Example Domain

This domain is for use in documentation examples without needing permission. Avoid use in operations.

Learn more

-*** Answer *** -Status code: 405 -Body should be empty, because we decided to manage callbacks: 0 diff --git a/tests/sav/curl_http_args3.res b/tests/sav/curl_http_args3.res deleted file mode 100644 index 85013d64f9..0000000000 --- a/tests/sav/curl_http_args3.res +++ /dev/null @@ -1,3 +0,0 @@ -*** Answer *** -Status code: 200 -Size downloaded: 559.0 diff --git a/tests/sav/curl_http_download.res b/tests/sav/curl_http_download.res new file mode 100644 index 0000000000..51fffe9c9a --- /dev/null +++ b/tests/sav/curl_http_download.res @@ -0,0 +1 @@ +Usage: curl_http_download url file diff --git a/tests/sav/curl_http_get.res b/tests/sav/curl_http_get.res new file mode 100644 index 0000000000..8413db350b --- /dev/null +++ b/tests/sav/curl_http_get.res @@ -0,0 +1 @@ +Usage: curl_http_get url diff --git a/tests/sav/curl_http_local_server.res b/tests/sav/curl_http_local_server.res new file mode 100644 index 0000000000..6078c2308c --- /dev/null +++ b/tests/sav/curl_http_local_server.res @@ -0,0 +1,25 @@ +# GET +Status code: 200 +Body: + + + + + Hello World from Nitcorn! + + +
+

Hello World from Nitcorn!

+

See also a directory.

+
+ + +# POST +Received: Hello curl +Bugs Bunny = Daffy Duck +Batman = Yes you can set multiple identical keys, but APACHE will consider only one, the last one +Status code: 200 +# Download +Status code: 200 +Size downloaded: 391.0 +index.html diff --git a/tests/sav/curl_http_post.res b/tests/sav/curl_http_post.res new file mode 100644 index 0000000000..ec574273b4 --- /dev/null +++ b/tests/sav/curl_http_post.res @@ -0,0 +1 @@ +Usage: curl_http_post url From 2a6571ce76cbbc0c5491c7586bbc5788b80a6f56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Laferri=C3=A8re?= Date: Thu, 1 Oct 2026 16:00:36 -0700 Subject: [PATCH 11/13] tests: have niti skip `nitc_args10` to `12`, intro reduced test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Making the skip lists more specific enabled more tests, some were slow and others were slow and revealed bugs. Let's skip the slow ones again. `nitc_args10` to `nitc_args12` have nitc compile `core`, which is very slow when nitc is interpreted. But `nitc_args11` and `nitc_args12` also fail with niti on Linux. The programs created by the interpreted nitc would crash at startup because the interpreter mixes up local variables. Keeping this issue in the reduced `base_var_assign_in_branch` for future investigation. Signed-off-by: Alexis Laferrière --- tests/base_var_assign_in_branch.nit | 30 +++++++++++++++++++ tests/niti.skip | 3 ++ tests/nitvm.skip | 3 ++ tests/sav/base_var_assign_in_branch.res | 2 ++ .../niti/fixme/base_var_assign_in_branch.res | 2 ++ 5 files changed, 40 insertions(+) create mode 100644 tests/base_var_assign_in_branch.nit create mode 100644 tests/sav/base_var_assign_in_branch.res create mode 100644 tests/sav/niti/fixme/base_var_assign_in_branch.res diff --git a/tests/base_var_assign_in_branch.nit b/tests/base_var_assign_in_branch.nit new file mode 100644 index 0000000000..54d2ec87a6 --- /dev/null +++ b/tests/base_var_assign_in_branch.nit @@ -0,0 +1,30 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +fun f(cached: Bool): String +do + var recv + if cached then + var name = "name" + var guard = "guard" + recv = "recv" + return "{recv} {name} {guard}" + else + recv = "other" + end + return recv +end + +print f(false) +print f(true) diff --git a/tests/niti.skip b/tests/niti.skip index 55543a7bff..7f543a5a04 100644 --- a/tests/niti.skip +++ b/tests/niti.skip @@ -13,6 +13,9 @@ nitin \ \ \ +\ +\ +\ nitpick_args1 nitunit_args pep8analysis diff --git a/tests/nitvm.skip b/tests/nitvm.skip index 386c5c6a65..cb42beff8b 100644 --- a/tests/nitvm.skip +++ b/tests/nitvm.skip @@ -13,6 +13,9 @@ nitin \ \ \ +\ +\ +\ nitpick_args1 nitunit_args pep8analysis diff --git a/tests/sav/base_var_assign_in_branch.res b/tests/sav/base_var_assign_in_branch.res new file mode 100644 index 0000000000..d4676dab5f --- /dev/null +++ b/tests/sav/base_var_assign_in_branch.res @@ -0,0 +1,2 @@ +other +recv name guard diff --git a/tests/sav/niti/fixme/base_var_assign_in_branch.res b/tests/sav/niti/fixme/base_var_assign_in_branch.res new file mode 100644 index 0000000000..0c9c388601 --- /dev/null +++ b/tests/sav/niti/fixme/base_var_assign_in_branch.res @@ -0,0 +1,2 @@ +other +recv recv guard From ab20abb0a796f85349d51288358319956ed65074 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Laferri=C3=A8re?= Date: Fri, 2 Oct 2026 17:38:57 -0700 Subject: [PATCH 12/13] emscripten: drop the partial GC integration as it's not available anymore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The emscripten library included `gc.h`, it used to be provided by the garbage collector emulated in JavaScript in the old Emscripten toolchain. It has been removed from Emscripten since then, breaking the numerous emscripten Nit clients. The GC wasn't fully supported on emscripten even back then, see the manual triggers. We could likely add Nit GC support to that platform by building libgc ourselves like we do for iOS. Signed-off-by: Alexis Laferrière --- contrib/pep8analysis/src/pep8analysis_web.nit | 14 -------------- lib/emscripten/emscripten.nit | 8 -------- 2 files changed, 22 deletions(-) diff --git a/contrib/pep8analysis/src/pep8analysis_web.nit b/contrib/pep8analysis/src/pep8analysis_web.nit index e9a81d839a..b9efd5c396 100644 --- a/contrib/pep8analysis/src/pep8analysis_web.nit +++ b/contrib/pep8analysis/src/pep8analysis_web.nit @@ -48,14 +48,10 @@ redef class AnalysisManager fun run_web(src: String) do - sys.suggest_garbage_collection - var stream = new StringReader(src) var ast = build_ast("web", stream) if ast == null then return - sys.suggest_garbage_collection - if failed then exit 1 # Build program model @@ -67,31 +63,21 @@ redef class AnalysisManager return end - sys.suggest_garbage_collection - # Create CFG var cfg = build_cfg(model) if failed then exit 1 # Run analyses - sys.suggest_garbage_collection - ## Reaching defs do_reaching_defs_analysis(cfg) - sys.suggest_garbage_collection - ## Range do_range_analysis(ast, cfg) - sys.suggest_garbage_collection - ## Types do_types_analysis(ast, cfg) - sys.suggest_garbage_collection - print_notes if notes.is_empty then print "Success: Nothing wrong detected" diff --git a/lib/emscripten/emscripten.nit b/lib/emscripten/emscripten.nit index bc320d4480..da57548edd 100644 --- a/lib/emscripten/emscripten.nit +++ b/lib/emscripten/emscripten.nit @@ -22,7 +22,6 @@ module emscripten is platform `{ #include - #include `} redef class Text @@ -37,10 +36,3 @@ redef class Text # Raise a JavaScript alert fun alert do "alert('{self.escape_to_js}')".run_js end - -redef class Sys - redef fun force_garbage_collection `{ GC_FORCE_COLLECT(); `} - - # The emscripten GC *must* be manually invoked, it will not act by itself - fun suggest_garbage_collection `{ GC_MAYBE_COLLECT(); `} -end From 0781a00e71544950662b32c940caf7153836042e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Laferri=C3=A8re?= Date: Sat, 3 Oct 2026 12:03:34 -0700 Subject: [PATCH 13/13] nitcg: don't confuse a thunk with its target function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a missing check on `c_name` in the `==` service of the class `CustomizedRuntimeFunction` to distinguish it from its subclass `CustomizedThunkFunction`. In the rare case where the hash of a thunk and its target function would lead to the same bucket, the missing check on `c_name` could mix them up. Let's also move including the `c_name` in the hash from `CustomizedThunkFunction` to `CustomizedRuntimeFunction`. This is mostly to align it with the equality check and prevent such errors in the future. However, we need the `c_name` in the equality check of the parent class `CustomizedRuntimeFunction` for it to be symmetric between both classes. This caused non-deterministic compilation errors in the generated C code where we'd print a reference to the thunk without declaring it. Signed-off-by: Alexis Laferrière --- src/compiler/global_compiler.nit | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/compiler/global_compiler.nit b/src/compiler/global_compiler.nit index 737ec48f3a..9dd7b78e03 100644 --- a/src/compiler/global_compiler.nit +++ b/src/compiler/global_compiler.nit @@ -1040,11 +1040,12 @@ private class CustomizedRuntimeFunction if not o isa CustomizedRuntimeFunction then return false if self.mmethoddef != o.mmethoddef then return false if self.recv != o.recv then return false + if self.c_name != o.c_name then return false return true end # used in the compiler work-list - redef fun hash do return self.mmethoddef.hash + self.recv.hash + redef fun hash do return self.mmethoddef.hash + self.recv.hash + self.c_name.hash redef fun to_s do @@ -1166,16 +1167,11 @@ class CustomizedThunkFunction super ThunkFunction super CustomizedRuntimeFunction - redef fun c_name + redef fun build_c_name do return "THUNK_" + super end - redef fun hash - do - return super + c_name.hash - end - redef fun resolve_receiver(v) do var res = super(v)