diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 82e99c3..a360d1d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - compiler: [gcc, clang] + compiler: [gcc, clang, filc] steps: - uses: actions/checkout@v4.3.0 @@ -16,6 +16,11 @@ jobs: - name: Install Nix uses: cachix/install-nix-action@v31.5.0 + - name: Use Fil-C Cachix cache + uses: cachix/cachix-action@v17 + with: + name: filc + - name: Build run: nix-shell --run "make test CC=${{ matrix.compiler }}" @@ -26,7 +31,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - compiler: [gcc, clang] + compiler: [gcc, clang, filc] steps: - uses: actions/checkout@v4.3.0 @@ -36,6 +41,11 @@ jobs: - name: Install Nix uses: cachix/install-nix-action@v31.5.0 + - name: Use Fil-C Cachix cache + uses: cachix/cachix-action@v17 + with: + name: filc + - name: Build run: nix-shell --run "make bench CC=${{ matrix.compiler }}" @@ -61,5 +71,10 @@ jobs: - name: Install Nix uses: cachix/install-nix-action@v31.5.0 + - name: Use Fil-C Cachix cache + uses: cachix/cachix-action@v17 + with: + name: filc + - name: Build run: nix-shell --run "make style-check" diff --git a/Makefile b/Makefile index 6e25da0..0020d54 100644 --- a/Makefile +++ b/Makefile @@ -2,15 +2,17 @@ BUILD_DIR=build BENCH_DATA_DIR=bench/data CC ?= cc -CFLAGS=-std=c99 -O3 -Wextra -Wall -Werror +CFLAGS=-std=c99 -Wextra -Wall -Werror LDFLAGS=-I. SRC = cparsec.h bench/c/*.[ch] test/*.[ch] test/linkage/*.[ch] all: test bench +test: CFLAGS += -O0 test: $(BUILD_DIR)/basic $(BUILD_DIR)/unnamed $(BUILD_DIR)/simd $(BUILD_DIR)/linkage $(BUILD_DIR)/freestanding $(BUILD_DIR)/example +bench: CFLAGS += -O3 bench: $(BUILD_DIR)/attoparsec_csv $(BUILD_DIR)/csv_demo $(BUILD_DIR)/csv_simd_demo $(BUILD_DIR)/csv-rust-demo $(BENCH_DATA_DIR)/customers-1000000.csv $(BUILD_DIR)/example: examples/example.c cparsec.h $(BUILD_DIR)/.gitignore diff --git a/bench/bench.sh b/bench/bench.sh index 3288dd1..6173fe4 100755 --- a/bench/bench.sh +++ b/bench/bench.sh @@ -17,14 +17,14 @@ diff -u \ # Print the report in markdown echo -e "# Parsing 1M CSV rows" -echo -e "\n## CParseC vs Haskell \n" +#echo -e "\n## CParseC vs Haskell \n" -hyperfine --warmup 3 \ - "$bin < bench/data/customers-1000000.csv" \ - './build/attoparsec_csv < bench/data/customers-1000000.csv' \ - --export-markdown build/report-c-hs.md 1>&2 +#hyperfine --warmup 3 \ + #"$bin < bench/data/customers-1000000.csv" \ + #'./build/attoparsec_csv < bench/data/customers-1000000.csv' \ + #--export-markdown build/report-c-hs.md 1>&2 -cat build/report-c-hs.md +#cat build/report-c-hs.md echo -e "\n## CParseC vs Rust\n" diff --git a/cparsec.h b/cparsec.h index 7c9b643..a59ef01 100644 --- a/cparsec.h +++ b/cparsec.h @@ -456,9 +456,9 @@ CPCAPI ___CPC_ANY(CPC_ANY_) #define CPC_MATCH(name, parser) \ CPC_DEFINE_PARSER(name) { \ /* mark is for restoring the arena state */ \ - size_t mark = A->offset; \ + size_t mark = A ? A->offset : 0; \ CpcResult r = CPC_PARSE(parser, input, A, err); \ - A->offset = mark; \ + if (A) A->offset = mark; \ return r.ok ? cpc_res_ok( \ cpc_val_slice(cpc_slice_sub(input, 0, (size_t)(r.rest.ptr - input.ptr))), \ r.rest) \ diff --git a/flake.lock b/flake.lock index a696576..8cc788d 100644 --- a/flake.lock +++ b/flake.lock @@ -16,8 +16,44 @@ "type": "github" } }, + "filnix": { + "inputs": { + "nixpkgs": "filnix-nixpkgs" + }, + "locked": { + "lastModified": 1785153603, + "narHash": "sha256-vJSk5zlj1hUvpjaTRCFg8FxzOqdUArZb+SnLpwWVB00=", + "owner": "mbrock", + "repo": "filnix", + "rev": "d3531442f8fd3e1e553bf9c0d2f7b85fdf4c70ca", + "type": "github" + }, + "original": { + "owner": "mbrock", + "repo": "filnix", + "type": "github" + } + }, + "filnix-nixpkgs": { + "flake": false, + "locked": { + "lastModified": 1762633274, + "narHash": "sha256-Ygv7dtGtshVgYPWE9pNaCxA7s9V8OleD7UbFjuZr5ug=", + "owner": "lessrest", + "repo": "filnixpkgs", + "rev": "400439b089773d3fc593b512250e283a33485de4", + "type": "github" + }, + "original": { + "owner": "lessrest", + "repo": "filnixpkgs", + "rev": "400439b089773d3fc593b512250e283a33485de4", + "type": "github" + } + }, "root": { "inputs": { + "filnix": "filnix", "nixpkgs": "nixpkgs" } } diff --git a/flake.nix b/flake.nix index daae89a..505edfb 100644 --- a/flake.nix +++ b/flake.nix @@ -1,13 +1,19 @@ { - inputs.nixpkgs.url = "github:NixOS/nixpkgs/e6f23dc08d3624daab7094b701aa3954923c6bbb"; + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/e6f23dc08d3624daab7094b701aa3954923c6bbb"; + filnix.url = "github:mbrock/filnix"; + }; - outputs = { self, nixpkgs }: + outputs = { self, nixpkgs, filnix }: let systems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ]; forAllSystems = nixpkgs.lib.genAttrs systems; in { devShells = forAllSystems (system: { - default = import ./shell.nix { pkgs = nixpkgs.legacyPackages.${system}; }; + default = import ./shell.nix { + pkgs = nixpkgs.legacyPackages.${system}; + filcc = if system == "x86_64-linux" then filnix.packages.${system}.filcc else null; + }; }); }; } diff --git a/shell.nix b/shell.nix index f14355f..f096132 100644 --- a/shell.nix +++ b/shell.nix @@ -1,14 +1,31 @@ let lock = builtins.fromJSON (builtins.readFile ./flake.lock); nixpkgsLock = lock.nodes.${lock.nodes.root.inputs.nixpkgs}.locked; + filnixLock = lock.nodes.${lock.nodes.root.inputs.filnix}.locked; + filnix = builtins.getFlake + "github:${filnixLock.owner}/${filnixLock.repo}/${filnixLock.rev}?narHash=${filnixLock.narHash}"; in { pkgs ? import (builtins.fetchTarball { name = nixpkgsLock.rev; url = "https://github.com/${nixpkgsLock.owner}/${nixpkgsLock.repo}/archive/${nixpkgsLock.rev}.tar.gz"; sha256 = nixpkgsLock.narHash; - }) {} + }) {}, + filcc ? if builtins.currentSystem == "x86_64-linux" then + filnix.packages.${builtins.currentSystem}.filcc + else + null }: with pkgs; +let + filc = + if filcc != null then + [ + (writeShellScriptBin "filc" '' + exec ${filcc}/bin/clang "$@" + '') + ] + else []; +in mkShellNoCC { buildInputs = [ @@ -20,7 +37,7 @@ mkShellNoCC { rustc cargo clang - ]; + ] ++ filc; shellHook = '' export HISTFILE=.history ''; diff --git a/test/test.sh b/test/test.sh index 2d91c12..3071871 100755 --- a/test/test.sh +++ b/test/test.sh @@ -3,9 +3,14 @@ set -euo pipefail echo -e "\n=== TEST: linking works correctly\n" ./build/linkage -echo -e "\n=== TEST: freestanding symbol hygiene\n" -if nm -u build/freestanding | grep .; then - exit 1 +# Clang emits memcpy/memset calls for some reason at -O0, so we skip this test under clang +if ! readelf --string-dump=.comment build/freestanding 2>/dev/null | grep -qi 'clang'; then + echo -e "\n=== TEST: freestanding symbol hygiene\n" + + # Fil-C adds calls to its runtime for safety checks even for freestanding, so we exclude the `fil_c/verse_` prefixes. + if nm -u build/freestanding | awk '$NF !~ /^(filc_|verse_)/ { print; found = 1 } END { exit !found }'; then + exit 1 + fi fi echo -e "\n=== TEST: basic parsers\n"