Compare commits

..

21 Commits

Author SHA1 Message Date
Christoffer Lerno
14d7fd1d08 Additional macro inlining error improvements. 2024-06-11 19:22:18 +02:00
Christoffer Lerno
43c11118ec Update tests for LLVM 19 2024-06-11 00:38:11 +02:00
Christoffer Lerno
407dec0238 Fix macro error trace. 2024-06-10 22:31:06 +02:00
Christoffer Lerno
9b21f411ba Use vswhere to find msvc. 2024-06-10 00:54:03 +02:00
Christoffer Lerno
cbb2cad2b8 Removed unused fields in find_msvc. 2024-06-09 17:13:29 +02:00
Christoffer Lerno
f99baf479e Compiler crash using enum nameof from different module #1205. 2024-06-09 16:51:32 +02:00
Christoffer Lerno
4fc1e39fa2 Improve inlining warning messages. Added index_of_char_from. 2024-06-09 14:38:57 +02:00
Christoffer Lerno
5a6443060e Improve inlining warning messages. 2024-06-08 22:31:36 +02:00
Christian Buttner
ab2e18e255 Allow linking libraries directly by file path. 2024-06-08 18:50:48 +02:00
Christoffer Lerno
4548c474bc Fix of default argument stacktrace. 2024-06-08 18:14:26 +02:00
Christoffer Lerno
c644af7ced Updated Linux stacktrace 2024-06-08 13:12:14 +02:00
Christoffer Lerno
f6697b33bf Error of @if depends on @if 2024-06-07 00:11:09 +02:00
Christoffer Lerno
a4df94d228 $foreach doesn't create an implicit syntactic scope. Fix of previous debug info fix. 2024-06-06 23:15:21 +02:00
Christoffer Lerno
edd0a4022b Improved debug information on defer. 2024-06-06 17:40:07 +02:00
Christoffer Lerno
f7e7e16c25 Fix problems using reflection on interface types #1203. 2024-06-03 21:59:18 +02:00
Christoffer Lerno
ddfc9313e0 Upgrade of mingw in CI 2024-05-26 23:53:27 +02:00
Christoffer Lerno
7e7a4094f1 Improve debug info exactness. 2024-05-25 23:35:57 +02:00
Christoffer Lerno
e90254da03 Rollback expression / macro unification. 2024-05-24 00:45:44 +02:00
Christoffer Lerno
c1b57f9391 Fix inline in different file. 2024-05-23 16:51:19 +02:00
Christoffer Lerno
522a7a9011 Add inline to macro expansion. 2024-05-23 15:54:09 +02:00
Christoffer Lerno
fc849c1440 0.6.0: init_new/init_temp removed. LinkedList API rewritten. List "pop" and "remove" function now return Optionals. RingBuffer API rewritten. Allocator interface changed. Deprecated Allocator, DString and mem functions removed. "identity" functions are now constants for Matrix and Complex numbers. @default implementations for interfaces removed. any* => any, same for interfaces. Emit local/private globals as "private" in LLVM, following C "static". Updated enum syntax. Add support [rgba] properties in vectors. Improved checks of aliased "void". Subarray -> slice. Fix of llvm codegen enum check. Improved alignment handling. Add --output-dir #1155. Removed List/Object append. GenericList renamed AnyList. Remove unused "unwrap". Fixes to cond. Optimize output in dead branches. Better checking of operator methods. Disallow any from implementing dynamic methods. Check for operator mismatch. Remove unnecessary bitfield. Remove numbering in --list* commands Old style enum declaration for params/type, but now the type is optional. Add note on #1086. Allow making distinct types out of "void", "typeid", "anyfault" and faults. Remove system linker build options. "Try" expressions must be simple expressions. Add optimized build to Mac tests. Register int. assert(false) only allowed in unused branches or in tests. Compile time failed asserts is a compile time error. Remove current_block_is_target. Bug when assigning an optional from an optional. Remove unused emit_zstring. Simplify phi code. Remove unnecessary unreachable blocks and remove unnecessary current_block NULL assignments. Proper handling of '.' and Win32 '//server' paths. Unify expression and macro blocks in the middle end. Add "no discard" to expression blocks with a return value. Detect "unsigned >= 0" as errors. Fix issue with distinct void as a member #1147. Improve callstack debug information #1184. Fix issue with absolute output-dir paths. Lambdas were not type checked thoroughly #1185. Fix compilation warning #1187. Request jump table using @jump for switches. Path normalization - fix possible null terminator out of bounds. Improved error messages on inlined macros. 2024-05-22 18:22:04 +02:00
325 changed files with 13153 additions and 20326 deletions

2
.github/FUNDING.yml vendored
View File

@@ -3,7 +3,7 @@
github: [c3lang]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: c3lang
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username

View File

@@ -4,14 +4,11 @@ on:
push:
branches: [ master, dev, ci_testing, experiments ]
pull_request:
branches: [ master, dev ]
branches: [ master ]
env:
LLVM_RELEASE_VERSION_WINDOWS: 18
LLVM_RELEASE_VERSION_MAC: 18
LLVM_RELEASE_VERSION_LINUX: 17
LLVM_RELEASE_VERSION_UBUNTU20: 17
LLVM_DEV_VERSION: 20
LLVM_RELEASE_VERSION: 16
jobs:
build-msvc:
@@ -36,31 +33,28 @@ jobs:
- name: Compile and run some examples
run: |
cd resources
..\build\${{ matrix.build_type }}\c3c.exe compile-run -L C:\ --print-linking examples\hello_world_many.c3
..\build\${{ matrix.build_type }}\c3c.exe compile-run --print-linking examples\hello_world_many.c3
..\build\${{ matrix.build_type }}\c3c.exe compile-run --print-linking examples\time.c3
..\build\${{ matrix.build_type }}\c3c.exe compile-run --print-linking examples\fannkuch-redux.c3
..\build\${{ matrix.build_type }}\c3c.exe compile-run examples\contextfree\boolerr.c3
..\build\${{ matrix.build_type }}\c3c.exe compile-run examples\ls.c3
..\build\${{ matrix.build_type }}\c3c.exe compile-run examples\load_world.c3
..\build\${{ matrix.build_type }}\c3c.exe compile-run examples\process.c3
..\build\${{ matrix.build_type }}\c3c.exe compile-run examples\args.c3 -- foo -bar "baz baz"
..\build\${{ matrix.build_type }}\c3c.exe compile --no-entry --test -g -O0 --threads 1 --target macos-x64 examples\constants.c3
..\build\${{ matrix.build_type }}\c3c.exe compile --test -g -O0 --threads 1 --target macos-x64 examples\constants.c3
..\build\${{ matrix.build_type }}\c3c.exe compile-run msvc_stack.c3
- name: Build testproject
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
cd resources/testproject
..\..\build\${{ matrix.build_type }}\c3c.exe --debug-log --emit-llvm run hello_world_win32
dir build\llvm_ir
..\..\build\${{ matrix.build_type }}\c3c.exe clean
dir build\llvm_ir
- name: Build testproject lib
run: |
cd resources/testproject
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
..\..\build\${{ matrix.build_type }}\c3c.exe --debug-log build hello_world_win32_lib
- name: Vendor-fetch
@@ -70,7 +64,7 @@ jobs:
- name: Try raylib
run: |
cd resources
..\build\${{ matrix.build_type }}\c3c.exe vendor-fetch raylib
..\build\${{ matrix.build_type }}\c3c.exe vendor-fetch raylib
..\build\${{ matrix.build_type }}\c3c.exe compile --lib raylib --wincrt=none examples\raylib\raylib_arkanoid.c3
..\build\${{ matrix.build_type }}\c3c.exe compile --lib raylib --wincrt=none examples\raylib\raylib_snake.c3
..\build\${{ matrix.build_type }}\c3c.exe compile --lib raylib --wincrt=none examples\raylib\raylib_tetris.c3
@@ -94,9 +88,7 @@ jobs:
uses: actions/upload-artifact@v3
with:
name: c3-windows-${{ matrix.build_type }}
path: |
build\${{ matrix.build_type }}\c3c.exe
build\${{ matrix.build_type }}\c3c_rt
path: build\${{ matrix.build_type }}\c3c.exe
build-msys2-mingw:
runs-on: windows-latest
@@ -120,8 +112,8 @@ jobs:
install: git binutils mingw-w64-x86_64-clang mingw-w64-x86_64-ninja mingw-w64-x86_64-cmake mingw-w64-x86_64-toolchain mingw-w64-x86_64-python
- shell: msys2 {0}
run: |
pacman --noconfirm -U https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-llvm-18.1.8-1-any.pkg.tar.zst
pacman --noconfirm -U https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-lld-18.1.8-1-any.pkg.tar.zst
pacman --noconfirm -U https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-llvm-18.1.6-1-any.pkg.tar.zst
pacman --noconfirm -U https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-lld-18.1.6-1-any.pkg.tar.zst
- name: CMake
run: |
cmake -B build -G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
@@ -135,8 +127,7 @@ jobs:
../build/c3c compile-run --print-linking examples/fannkuch-redux.c3
../build/c3c compile-run --print-linking examples/contextfree/boolerr.c3
../build/c3c compile-run --print-linking examples/load_world.c3
../build/c3c compile-run --print-linking examples/args.c3 -- foo -bar "baz baz"
../build/c3c compile --no-entry --test -g -O0 --threads 1 --target macos-x64 examples/constants.c3
../build/c3c compile --test -g -O0 --threads 1 --target macos-x64 examples/constants.c3
- name: Build testproject
run: |
@@ -150,7 +141,7 @@ jobs:
- name: Build testproject lib
run: |
cd resources/testproject
../../build/c3c build hello_world_lib --cc cc --debug-log
../../build/c3c build hello_world_lib --debug-log
- name: run compiler tests
run: |
@@ -192,8 +183,7 @@ jobs:
../build/c3c compile-run examples/fannkuch-redux.c3
../build/c3c compile-run examples/contextfree/boolerr.c3
../build/c3c compile-run examples/load_world.c3
../build/c3c compile-run examples/args.c3 -- foo -bar "baz baz"
../build/c3c compile --no-entry --test -g -O0 --threads 1 --target macos-x64 examples/constants.c3
../build/c3c compile --test -g -O0 --threads 1 --target macos-x64 examples/constants.c3
- name: Build testproject
run: |
cd resources/testproject
@@ -216,7 +206,7 @@ jobs:
fail-fast: false
matrix:
build_type: [Release, Debug]
llvm_version: [17, 18, 19, 20]
llvm_version: [15, 16, 17, 18, 19]
steps:
- uses: actions/checkout@v4
@@ -227,29 +217,25 @@ jobs:
- name: Install Clang ${{matrix.llvm_version}}
run: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
if [[ "${{matrix.llvm_version}}" < 18 ]]; then
if [[ "${{matrix.llvm_version}}" < 16 ]]; then
sudo apt remove libllvm15
fi
if [[ "${{matrix.llvm_version}}" < 19 ]]; then
sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-${{matrix.llvm_version}} main"
sudo apt-get update
sudo apt-get install -y -t llvm-toolchain-focal-${{matrix.llvm_version}} libpolly-${{matrix.llvm_version}}-dev \
clang-${{matrix.llvm_version}} llvm-${{matrix.llvm_version}} llvm-${{matrix.llvm_version}}-dev \
lld-${{matrix.llvm_version}} liblld-${{matrix.llvm_version}}-dev libmlir-${{matrix.llvm_version}} \
libmlir-${{matrix.llvm_version}}-dev mlir-${{matrix.llvm_version}}-tools
libmlir-${{matrix.llvm_version}}-dev mlir-${{matrix.llvm_version}}-tools
else
if [[ "${{matrix.llvm_version}}" < "${{env.LLVM_DEV_VERSION}}" ]]; then
sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-${{matrix.llvm_version}} main"
sudo apt-get update
sudo apt-get install -y -t llvm-toolchain-focal-${{matrix.llvm_version}} libpolly-${{matrix.llvm_version}}-dev \
clang-${{matrix.llvm_version}} llvm-${{matrix.llvm_version}} llvm-${{matrix.llvm_version}}-dev \
lld-${{matrix.llvm_version}} liblld-${{matrix.llvm_version}}-dev
else
sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal main"
sudo apt-get install -y -t llvm-toolchain-focal libpolly-${{matrix.llvm_version}}-dev \
clang-${{matrix.llvm_version}} llvm-${{matrix.llvm_version}} llvm-${{matrix.llvm_version}}-dev \
lld-${{matrix.llvm_version}} liblld-${{matrix.llvm_version}}-dev
fi
sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal main"
sudo apt-get install -y -t llvm-toolchain-focal libpolly-${{matrix.llvm_version}}-dev \
clang-${{matrix.llvm_version}} llvm-${{matrix.llvm_version}} llvm-${{matrix.llvm_version}}-dev \
lld-${{matrix.llvm_version}} liblld-${{matrix.llvm_version}}-dev libmlir-${{matrix.llvm_version}} \
libmlir-${{matrix.llvm_version}}-dev mlir-${{matrix.llvm_version}}-tools
fi
- name: CMake
if: matrix.llvm_version < 18 || matrix.llvm_version == env.LLVM_DEV_VERSION
if: matrix.llvm_version != 18
run: |
cmake -B build \
-G Ninja \
@@ -263,7 +249,7 @@ jobs:
-DC3_LLVM_VERSION=${{matrix.llvm_version}}
cmake --build build
- name: CMake18
if: matrix.llvm_version >= 18 && matrix.llvm_version != env.LLVM_DEV_VERSION
if: matrix.llvm_version == 18
run: |
cmake -B build \
-G Ninja \
@@ -274,12 +260,12 @@ jobs:
-DCMAKE_OBJCOPY=llvm-objcopy-${{matrix.llvm_version}} \
-DCMAKE_STRIP=llvm-strip-${{matrix.llvm_version}} \
-DCMAKE_DLLTOOL=llvm-dlltool-${{matrix.llvm_version}} \
-DC3_LLVM_VERSION=${{matrix.llvm_version}}.1
-DC3_LLVM_VERSION=18.1
cmake --build build
- name: Compile and run some examples
run: |
cd resources
cd resources
../build/c3c compile examples/base64.c3
../build/c3c compile examples/binarydigits.c3
../build/c3c compile examples/brainfk.c3
@@ -287,9 +273,9 @@ jobs:
../build/c3c compile examples/fasta.c3
../build/c3c compile examples/gameoflife.c3
../build/c3c compile examples/hash.c3
../build/c3c compile-only examples/levenshtein.c3
../build/c3c compile examples/levenshtein.c3
../build/c3c compile examples/load_world.c3
../build/c3c compile-only examples/map.c3
../build/c3c compile examples/map.c3
../build/c3c compile examples/mandelbrot.c3
../build/c3c compile examples/plus_minus.c3
../build/c3c compile examples/nbodies.c3
@@ -298,8 +284,8 @@ jobs:
../build/c3c compile examples/contextfree/boolerr.c3
../build/c3c compile examples/contextfree/dynscope.c3
../build/c3c compile examples/contextfree/guess_number.c3
../build/c3c compile examples/contextfree/multi.c3
../build/c3c compile examples/contextfree/cleanup.c3
../build/c3c compile examples/contextfree/multi.c3
../build/c3c compile examples/contextfree/cleanup.c3
../build/c3c compile-run examples/hello_world_many.c3
../build/c3c compile-run examples/time.c3
../build/c3c compile-run examples/fannkuch-redux.c3
@@ -309,7 +295,6 @@ jobs:
../build/c3c compile-run examples/ls.c3
../build/c3c compile-run --linker=builtin linux_stack.c3
../build/c3c compile-run linux_stack.c3
../build/c3c compile-run examples/args.c3 -- foo -bar "baz baz"
- name: Compile run unit tests
run: |
@@ -321,48 +306,27 @@ jobs:
cd resources/testproject
../../build/c3c run --debug-log
- name: Test WASM
run: |
cd resources/testfragments
../../build/c3c compile --reloc=none --target wasm32 -g0 --link-libc=no --no-entry -Os wasm4.c3
- name: Install QEMU and Risc-V toolchain
run: |
sudo apt-get install opensbi qemu-system-misc u-boot-qemu gcc-riscv64-unknown-elf
- name: Compile and run Baremetal Risc-V Example
run: |
cd resources/examples/embedded/riscv-qemu
make C3C_PATH=../../../../build/ run
- name: Build testproject direct linker
run: |
cd resources/testproject
../../build/c3c run --debug-log --linker=builtin
- name: Init a library & a project
run: |
./build/c3c init-lib mylib
ls mylib.c3l
./build/c3c init myproject
ls myproject
- name: run compiler tests
run: |
cd test
python3 src/tester.py ../build/c3c test_suite/
- name: bundle_output
if: matrix.llvm_version == env.LLVM_RELEASE_VERSION_LINUX
if: matrix.llvm_version == 16
run: |
mkdir c3
cp -r lib c3
cp msvc_build_libraries.py c3
cp build/c3c c3
tar czf c3-linux-${{matrix.build_type}}.tar.gz c3
mkdir linux
cp -r lib linux
cp msvc_build_libraries.py linux
cp build/c3c linux
tar czf c3-linux-${{matrix.build_type}}.tar.gz linux
- name: upload artifacts
if: matrix.llvm_version == env.LLVM_RELEASE_VERSION_LINUX
if: matrix.llvm_version == 16
uses: actions/upload-artifact@v3
with:
name: c3-linux-${{matrix.build_type}}
@@ -375,7 +339,8 @@ jobs:
fail-fast: false
matrix:
build_type: [Release, Debug]
llvm_version: [17, 18, 19]
llvm_version: [16]
steps:
- uses: actions/checkout@v4
- name: Install common deps
@@ -385,17 +350,16 @@ jobs:
- name: Install Clang ${{matrix.llvm_version}}
run: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
if [[ "${{matrix.llvm_version}}" < "${{env.LLVM_DEV_VERSION}}" ]]; then
if [[ "${{matrix.llvm_version}}" < 17 ]]; then
sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-${{matrix.llvm_version}} main"
else
sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal main"
fi
sudo apt-get update
sudo apt-get update
sudo apt-get install -y clang-${{matrix.llvm_version}} llvm-${{matrix.llvm_version}} llvm-${{matrix.llvm_version}}-dev lld-${{matrix.llvm_version}} liblld-${{matrix.llvm_version}}-dev
sudo apt-get install -y libmlir-${{matrix.llvm_version}} libmlir-${{matrix.llvm_version}}-dev mlir-${{matrix.llvm_version}}-tools
sudo apt-get install -y libmlir-${{matrix.llvm_version}} libmlir-${{matrix.llvm_version}}-dev mlir-${{matrix.llvm_version}}-tools
sudo apt-get install -y libpolly-${{matrix.llvm_version}}-dev
- name: CMake Old
if: matrix.llvm_version < 18 || matrix.llvm_version == env.LLVM_DEV_VERSION
- name: CMake
run: |
cmake -B build \
-G Ninja \
@@ -408,26 +372,13 @@ jobs:
-DCMAKE_DLLTOOL=llvm-dlltool-${{matrix.llvm_version}} \
-DC3_LLVM_VERSION=${{matrix.llvm_version}}
cmake --build build
- name: CMake
if: matrix.llvm_version >= 18 && matrix.llvm_version != env.LLVM_DEV_VERSION
run: |
cmake -B build \
-G Ninja \
-DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
-DCMAKE_C_COMPILER=clang-${{matrix.llvm_version}} \
-DCMAKE_CXX_COMPILER=clang++-${{matrix.llvm_version}} \
-DCMAKE_LINKER=lld-link-${{matrix.llvm_version}} \
-DCMAKE_OBJCOPY=llvm-objcopy-${{matrix.llvm_version}} \
-DCMAKE_STRIP=llvm-strip-${{matrix.llvm_version}} \
-DCMAKE_DLLTOOL=llvm-dlltool-${{matrix.llvm_version}} \
-DC3_LLVM_VERSION=${{matrix.llvm_version}}.1
cmake --build build
- name: Compile and run some examples
run: |
cd resources
../build/c3c compile examples/gameoflife.c3
../build/c3c compile-only examples/levenshtein.c3
../build/c3c compile-only examples/map.c3
../build/c3c compile examples/levenshtein.c3
../build/c3c compile examples/map.c3
../build/c3c compile examples/mandelbrot.c3
../build/c3c compile examples/plus_minus.c3
../build/c3c compile examples/spectralnorm.c3
@@ -437,8 +388,8 @@ jobs:
../build/c3c compile-run examples/nbodies.c3
../build/c3c compile-run examples/contextfree/boolerr.c3
../build/c3c compile-run examples/contextfree/dynscope.c3
../build/c3c compile-run examples/contextfree/multi.c3
../build/c3c compile-run examples/contextfree/cleanup.c3
../build/c3c compile-run examples/contextfree/multi.c3
../build/c3c compile-run examples/contextfree/cleanup.c3
../build/c3c compile-run examples/hello_world_many.c3
../build/c3c compile-run examples/time.c3
../build/c3c compile-run examples/fannkuch-redux.c3
@@ -451,7 +402,6 @@ jobs:
../build/c3c compile-run examples/process.c3
../build/c3c compile-run --linker=builtin linux_stack.c3
../build/c3c compile-run linux_stack.c3
../build/c3c compile-run examples/args.c3 -- foo -bar "baz baz"
- name: Compile run unit tests
run: |
@@ -474,108 +424,20 @@ jobs:
python3 src/tester.py ../build/c3c test_suite/
- name: bundle_output
if: matrix.llvm_version == env.LLVM_RELEASE_VERSION_UBUNTU20
if: matrix.llvm_version == 16
run: |
mkdir c3
cp -r lib c3
cp msvc_build_libraries.py c3
cp build/c3c c3
tar czf c3-ubuntu-20-${{matrix.build_type}}.tar.gz c3
mkdir linux
cp -r lib linux
cp msvc_build_libraries.py linux
cp build/c3c linux
tar czf c3-ubuntu-20-${{matrix.build_type}}.tar.gz linux
- name: upload artifacts
if: matrix.llvm_version == env.LLVM_RELEASE_VERSION_UBUNTU20
if: matrix.llvm_version == 16
uses: actions/upload-artifact@v3
with:
name: c3-ubuntu-20-${{matrix.build_type}}
path: c3-ubuntu-20-${{matrix.build_type}}.tar.gz
build-with-docker:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
ubuntu_version: [20.04, 22.04]
build_type: [Release, Debug]
llvm_version: [17, 18, 19, 20]
steps:
- uses: actions/checkout@v4
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Make script executable
run: chmod +x ./build-with-docker.sh
- name: Run build
run: |
LLVM_VERSION=${{ matrix.llvm_version }} UBUNTU_VERSION=${{ matrix.ubuntu_version }} CMAKE_BUILD_TYPE=${{ matrix.build_type }} ./build-with-docker.sh
- name: Compile and run some examples
run: |
cd resources
../build/c3c compile examples/base64.c3
../build/c3c compile examples/binarydigits.c3
../build/c3c compile examples/brainfk.c3
../build/c3c compile examples/factorial_macro.c3
../build/c3c compile examples/fasta.c3
../build/c3c compile examples/gameoflife.c3
../build/c3c compile examples/hash.c3
../build/c3c compile-only examples/levenshtein.c3
../build/c3c compile examples/load_world.c3
../build/c3c compile-only examples/map.c3
../build/c3c compile examples/mandelbrot.c3
../build/c3c compile examples/plus_minus.c3
../build/c3c compile examples/nbodies.c3
../build/c3c compile examples/spectralnorm.c3
../build/c3c compile examples/swap.c3
../build/c3c compile examples/contextfree/boolerr.c3
../build/c3c compile examples/contextfree/dynscope.c3
../build/c3c compile examples/contextfree/guess_number.c3
../build/c3c compile examples/contextfree/multi.c3
../build/c3c compile examples/contextfree/cleanup.c3
../build/c3c compile-run examples/hello_world_many.c3
../build/c3c compile-run examples/time.c3
../build/c3c compile-run examples/fannkuch-redux.c3
../build/c3c compile-run examples/contextfree/boolerr.c3
../build/c3c compile-run examples/load_world.c3
../build/c3c compile-run examples/process.c3
../build/c3c compile-run examples/ls.c3
../build/c3c compile-run --linker=builtin linux_stack.c3
../build/c3c compile-run linux_stack.c3
../build/c3c compile-run examples/args.c3 -- foo -bar "baz baz"
- name: Compile run unit tests
run: |
cd test
../build/c3c compile-test unit
- name: Build testproject
run: |
cd resources/testproject
../../build/c3c run --debug-log
- name: Test WASM
run: |
cd resources/testfragments
../../build/c3c compile --reloc=none --target wasm32 -g0 --link-libc=no --no-entry -Os wasm4.c3
- name: Build testproject direct linker
run: |
cd resources/testproject
../../build/c3c run --debug-log --linker=builtin
- name: Init a library & a project
run: |
./build/c3c init-lib mylib
ls mylib.c3l
./build/c3c init myproject
ls myproject
- name: run compiler tests
run: |
cd test
python3 src/tester.py ../build/c3c test_suite/
build-mac:
runs-on: macos-latest
@@ -584,26 +446,20 @@ jobs:
fail-fast: false
matrix:
build_type: [Release, Debug]
llvm_version: [17, 18]
llvm_version: [15, 16, 17]
steps:
- uses: actions/checkout@v4
- name: Download LLVM
run: |
brew install llvm@${{ matrix.llvm_version }} ninja curl
echo "/opt/homebrew/opt/llvm@${{ matrix.llvm_version }}/bin" >> $GITHUB_PATH
echo "/opt/homebrew/opt/llvm@${{ matrix.llvm_version }}/bin" >> $GITHUB_PATH
TMP_PATH=$(xcrun --show-sdk-path)/user/include
echo "CPATH=$TMP_PATH" >> $GITHUB_ENV
- name: CMake
if: matrix.llvm_version < 18
run: |
cmake -B build -G Ninja -DC3_LLVM_VERSION=${{matrix.llvm_version}} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
cmake --build build
- name: CMake18
if: matrix.llvm_version >= 18
run: |
cmake -B build -G Ninja -DC3_LLVM_VERSION=${{matrix.llvm_version}}.1 -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
cmake --build build
- name: Vendor-fetch
run: |
@@ -619,7 +475,6 @@ jobs:
../build/c3c compile-run examples/process.c3
../build/c3c compile-run examples/load_world.c3
../build/c3c compile-run -O5 examples/load_world.c3
../build/c3c compile-run examples/args.c3 -- foo -bar "baz baz"
- name: Compile run unit tests
run: |
@@ -647,7 +502,7 @@ jobs:
python3 src/tester.py ../build/c3c test_suite/
- name: bundle_output
if: matrix.llvm_version == env.LLVM_RELEASE_VERSION_MAC
if: matrix.llvm_version == env.LLVM_RELEASE_VERSION
run: |
mkdir macos
cp -r lib macos
@@ -656,7 +511,7 @@ jobs:
zip -r c3-macos-${{matrix.build_type}}.zip macos
- name: upload artifacts
if: matrix.llvm_version == env.LLVM_RELEASE_VERSION_MAC
if: matrix.llvm_version == env.LLVM_RELEASE_VERSION
uses: actions/upload-artifact@v3
with:
name: c3-macos-${{matrix.build_type}}

3
.gitignore vendored
View File

@@ -67,6 +67,3 @@ out/
/cmake-build-debug/
/cmake-build-release/
# Emacs files
TAGS

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.20)
cmake_minimum_required(VERSION 3.15)
# Grab the version
file(READ "src/version.h" ver)
@@ -10,11 +10,6 @@ endif()
project(c3c VERSION ${CMAKE_MATCH_1})
message("C3C version: ${CMAKE_PROJECT_VERSION}")
# Avoid warning for FetchContent
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0")
cmake_policy(SET CMP0135 NEW)
endif()
if (NOT DEFINED CMAKE_INSTALL_LIBDIR)
if (MSVC)
set(CMAKE_INSTALL_LIBDIR "c:\\c3c\\lib")
@@ -37,7 +32,6 @@ set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
if(MSVC)
message(STATUS "MSVC version ${MSVC_VERSION}")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /O2 /EHsc")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /O2 /EHsc")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Od /Zi /EHa")
@@ -81,7 +75,7 @@ if (NOT WIN32)
find_package(CURL)
endif()
if (NOT C3_LLVM_VERSION STREQUAL "auto")
if (${C3_LLVM_VERSION} VERSION_LESS 17 OR ${C3_LLVM_VERSION} VERSION_GREATER 20)
if (${C3_LLVM_VERSION} VERSION_LESS 15 OR ${C3_LLVM_VERSION} VERSION_GREATER 19)
message(FATAL_ERROR "LLVM ${C3_LLVM_VERSION} is not supported!")
endif()
endif()
@@ -103,27 +97,25 @@ endif()
if(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
if (C3_LLVM_VERSION STREQUAL "auto")
set(C3_LLVM_VERSION "18")
set(C3_LLVM_VERSION "16")
endif()
FetchContent_Declare(
LLVM_Windows
URL https://github.com/c3lang/win-llvm/releases/download/llvm_18_1_8_with_rt/llvm-18.1.8-windows-amd64-msvc17-libcmt.7z
URL https://github.com/c3lang/win-llvm/releases/download/llvm_16_0_2/llvm-16.0.2-windows-amd64-msvc17-libcmt.7z
)
FetchContent_Declare(
LLVM_Windows_debug
URL https://github.com/c3lang/win-llvm/releases/download/llvm_18_1_8_with_rt/llvm-18.1.8-windows-amd64-msvc17-libcmt-dbg.7z
URL https://github.com/c3lang/win-llvm/releases/download/llvm_16_0_2/llvm-16.0.2-windows-amd64-msvc17-libcmt-dbg.7z
)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
message("Loading Windows LLVM debug libraries, this may take a while...")
FetchContent_MakeAvailable(LLVM_Windows_debug)
set(llvm_dir ${llvm_windows_debug_SOURCE_DIR})
set(CMAKE_SYSTEM_PREFIX_PATH ${llvm_windows_debug_SOURCE_DIR} ${CMAKE_SYSTEM_PREFIX_PATH})
else()
message("Loading Windows LLVM libraries, this may take a while...")
FetchContent_MakeAvailable(LLVM_Windows)
set(llvm_dir ${llvm_windows_SOURCE_DIR})
set(CMAKE_SYSTEM_PREFIX_PATH ${llvm_windows_SOURCE_DIR} ${CMAKE_SYSTEM_PREFIX_PATH})
endif()
set(CMAKE_SYSTEM_PREFIX_PATH ${llvm_dir} ${CMAKE_SYSTEM_PREFIX_PATH})
find_package(LLVM REQUIRED CONFIG)
find_package(LLD REQUIRED CONFIG)
else()
@@ -138,19 +130,12 @@ message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
message(STATUS "Libraries located in: ${LLVM_LIBRARY_DIRS}")
if (NOT LLVM_PACKAGE_VERSION VERSION_GREATER_EQUAL 15.0)
message(FATAL_ERROR "LLVM version 15.0 or later is required.")
endif()
if(LLVM_ENABLE_RTTI)
message(STATUS "LLVM was built with RTTI")
else()
message(STATUS "LLVM was not built with RTTI")
endif()
string(REPLACE "." ";" VERSION_LIST ${LLVM_PACKAGE_VERSION})
list(GET VERSION_LIST 0 LLVM_MAJOR_VERSION)
include_directories(${LLVM_INCLUDE_DIRS})
link_directories(${LLVM_LIBRARY_DIRS})
add_definitions(${LLVM_DEFINITIONS})
@@ -210,35 +195,33 @@ else()
find_library(LLD_WASM NAMES liblldWasm.so PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
endif()
if (NOT(${CMAKE_BINARY_DIR} EQUAL ${CMAKE_SOURCE_DIR}))
file(REMOVE_RECURSE ${CMAKE_BINARY_DIR}/lib)
file(COPY ${CMAKE_SOURCE_DIR}/lib DESTINATION ${CMAKE_BINARY_DIR})
endif()
file(REMOVE_RECURSE ${CMAKE_BINARY_DIR}/lib)
file(COPY ${CMAKE_SOURCE_DIR}/lib DESTINATION ${CMAKE_BINARY_DIR})
find_library(LLD_LOONG NAMES libLLVMLoongArchCodeGen.lib libLLVMLoongArchAsmParser.lib libLLVMLoongArchCodeGen.a libLLVMLoongArchAsmParser.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
set(lld_libs
${LLD_COFF}
${LLD_COMMON}
${LLD_WASM}
${LLD_MINGW}
${LLD_ELF}
${LLD_MACHO}
)
if (${LLVM_PACKAGE_VERSION} VERSION_GREATER_EQUAL 16)
find_library(LLD_LOONG NAMES libLLVMLoongArchCodeGen.lib libLLVMLoongArchAsmParser.lib libLLVMLoongArchCodeGen.a libLLVMLoongArchAsmParser.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
set(lld_libs
${LLD_COFF}
${LLD_COMMON}
${LLD_WASM}
${LLD_MINGW}
${LLD_ELF}
${LLD_MACHO}
)
else()
set(lld_libs
${LLD_COFF}
${LLD_COMMON}
${LLD_WASM}
${LLD_MINGW}
${LLD_ELF}
${LLD_MACHO}
)
endif()
if (APPLE)
set(lld_libs ${lld_libs} xar)
find_file(RT_ASAN_DYNAMIC NAMES libclang_rt.asan_osx_dynamic.dylib PATHS "${LLVM_LIBRARY_DIRS}/clang/${LLVM_MAJOR_VERSION}/lib/darwin")
find_file(RT_TSAN_DYNAMIC NAMES libclang_rt.tsan_osx_dynamic.dylib PATHS "${LLVM_LIBRARY_DIRS}/clang/${LLVM_MAJOR_VERSION}/lib/darwin")
find_file(RT_UBSAN_DYNAMIC NAMES libclang_rt.ubsan_osx_dynamic.dylib PATHS "${LLVM_LIBRARY_DIRS}/clang/${LLVM_MAJOR_VERSION}/lib/darwin")
find_file(RT_LSAN_DYNAMIC NAMES libclang_rt.lsan_osx_dynamic.dylib PATHS "${LLVM_LIBRARY_DIRS}/clang/${LLVM_MAJOR_VERSION}/lib/darwin")
set(sanitizer_runtime_libraries
${RT_ASAN_DYNAMIC}
${RT_TSAN_DYNAMIC}
# Unused
# ${RT_UBSAN_DYNAMIC}
# ${RT_LSAN_DYNAMIC}
)
endif()
endif ()
message(STATUS "linking to llvm libs ${lld_libs}")
message(STATUS "Found lld libs ${lld_libs}")
@@ -251,15 +234,11 @@ add_executable(c3c
src/build/builder.c
src/build/build_options.c
src/build/project_creation.c
src/build/project_manipulation.c
src/build/libraries.c
src/compiler/ast.c
src/compiler/bigint.c
src/compiler/codegen_general.c
src/compiler/compiler.c
src/compiler/compiler.h
src/compiler/subprocess.c
src/compiler/subprocess.h
src/compiler/context.c
src/compiler/copying.c
src/compiler/diagnostics.c
@@ -267,6 +246,7 @@ add_executable(c3c
src/compiler/headers.c
src/compiler/json_output.c
src/compiler/lexer.c
src/compiler/libraries.c
src/compiler/linker.c
src/compiler/llvm_codegen.c
src/compiler/abi/c_abi_aarch64.c
@@ -335,8 +315,7 @@ add_executable(c3c
src/compiler/expr.c
src/utils/time.c
src/utils/http.c
src/compiler/sema_liveness.c
src/build/common_build.c)
src/compiler/sema_liveness.c)
if (C3_USE_TB)
@@ -377,12 +356,11 @@ endif()
target_include_directories(c3c PRIVATE
"${CMAKE_SOURCE_DIR}/src/"
"${CMAKE_SOURCE_DIR}/wrapper/include/")
"${CMAKE_SOURCE_DIR}/src/")
target_include_directories(c3c_wrappers PRIVATE
"${CMAKE_SOURCE_DIR}/wrapper/include/")
"${CMAKE_SOURCE_DIR}/wrapper/src/")
target_include_directories(miniz PUBLIC
"${CMAKE_SOURCE_DIR}/dependencies/miniz/")
@@ -410,9 +388,6 @@ if(MSVC)
message("Adding MSVC options")
target_compile_options(c3c PRIVATE /wd4068 /wd4090 /WX /Wv:18)
target_compile_options(c3c_wrappers PUBLIC /wd4624 /wd4267 /wd4244 /WX /Wv:18)
if (NOT LLVM_ENABLE_RTTI)
target_compile_options(c3c_wrappers PUBLIC /GR-)
endif()
target_link_options(c3c_wrappers PUBLIC /ignore:4099)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
target_compile_options(c3c PUBLIC /MTd)
@@ -429,41 +404,16 @@ if(MSVC)
target_compile_options(tilde-backend PUBLIC /MT)
endif()
endif()
set(clang_lib_dir ${llvm_dir}/lib/clang/${C3_LLVM_VERSION}/lib/windows)
set(sanitizer_runtime_libraries
${clang_lib_dir}/clang_rt.asan-x86_64.lib
${clang_lib_dir}/clang_rt.asan_dynamic-x86_64.lib
${clang_lib_dir}/clang_rt.asan_dynamic-x86_64.dll
${clang_lib_dir}/clang_rt.asan_dynamic_runtime_thunk-x86_64.lib)
else()
message(STATUS "using gcc/clang warning switches")
target_link_options(c3c PRIVATE -pthread)
if (NOT LLVM_ENABLE_RTTI)
target_compile_options(c3c_wrappers PRIVATE -fno-rtti)
endif()
target_compile_options(c3c PRIVATE -pthread -Wall -Werror -Wno-unknown-pragmas -Wno-unused-result
-Wno-unused-function -Wno-unused-variable -Wno-unused-parameter)
endif()
install(TARGETS c3c DESTINATION bin)
install(DIRECTORY lib/ DESTINATION lib/c3)
if (DEFINED sanitizer_runtime_libraries)
add_custom_command(TARGET c3c POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E rm -rf -- $<TARGET_FILE_DIR:c3c>/c3c_rt
COMMAND "${CMAKE_COMMAND}" -E make_directory $<TARGET_FILE_DIR:c3c>/c3c_rt
COMMAND "${CMAKE_COMMAND}" -E copy ${sanitizer_runtime_libraries} $<TARGET_FILE_DIR:c3c>/c3c_rt
VERBATIM
COMMENT "Copying sanitizer runtime libraries to output directory")
if (APPLE)
# Change LC_ID_DYLIB to be rpath-based instead of having an absolute path
add_custom_command(TARGET c3c POST_BUILD
COMMAND find $<TARGET_FILE_DIR:c3c>/c3c_rt -type f -name "*.dylib" -execdir ${LLVM_TOOLS_BINARY_DIR}/llvm-install-name-tool -id @rpath/{} {} $<SEMICOLON>
VERBATIM)
endif()
install(DIRECTORY $<TARGET_FILE_DIR:c3c>/c3c_rt/ DESTINATION bin/c3c_rt)
endif()
feature_summary(WHAT ALL)

View File

@@ -137,9 +137,9 @@ fn void main()
### Current status
The current stable version of the compiler is **version 0.6.1**.
The current stable version of the compiler is **version 0.5**.
The upcoming 0.6.x releases will focus on expanding the standard library.
The upcoming 0.6 release will focus on expanding the standard library.
Follow the issues [here](https://github.com/c3lang/c3c/issues).
If you have suggestions on how to improve the language, either [file an issue](https://github.com/c3lang/c3c/issues)
@@ -212,7 +212,7 @@ More platforms will be supported in the future.
3. Unzip executable and standard lib.
4. Run `./c3c`.
(*Note that there is a known issue with debug symbol generation on MacOS 13, see [issue #1086](https://github.com/c3lang/c3c/issues/1086))
(*Note that there is a known issue with debug symbol generation on MacOS 13, see issue #1086)
#### Installing on Arch Linux
There is an AUR package for the c3c compiler : [c3c-git](https://aur.archlinux.org/packages/c3c-git).
@@ -253,7 +253,7 @@ A `c3c` executable will be found under `bin/`.
#### Installing on OS X using Homebrew
2. Install CMake: `brew install cmake`
3. Install LLVM 17+: `brew install llvm`
3. Install LLVM 15: `brew install llvm`
4. Clone the C3C github repository: `git clone https://github.com/c3lang/c3c.git`
5. Enter the C3C directory `cd c3c`.
6. Create a build directory `mkdir build`
@@ -308,7 +308,7 @@ You can try it out by running some sample code: `c3c.exe compile ../resources/ex
1. Make sure you have a C compiler that handles C11 and a C++ compiler, such as GCC or Clang. Git also needs to be installed.
2. Install CMake: `sudo apt install cmake`
3. Install LLVM 17+ (or greater: C3C supports LLVM 17+): `sudo apt-get install clang-17 zlib1g zlib1g-dev libllvm17 llvm-17 llvm-17-dev llvm-17-runtime liblld-17-dev liblld-17`
3. Install LLVM 15 (or greater: C3C supports LLVM 15-17): `sudo apt-get install clang-15 zlib1g zlib1g-dev libllvm15 llvm-15 llvm-15-dev llvm-15-runtime liblld-15-dev liblld-15`
4. Clone the C3C github repository: `git clone https://github.com/c3lang/c3c.git`
5. Enter the C3C directory `cd c3c`.
6. Create a build directory `mkdir build`
@@ -323,7 +323,7 @@ You can try it out by running some sample code: `./c3c compile ../resources/exam
#### Compiling on Void Linux
1. As root, ensure that all project dependencies are installed: `xbps-install git cmake llvm17 lld17-devel libcurl-devel ncurses-devel zlib-devel libzstd-devel libxml2-devel`
1. As root, ensure that all project dependencies are installed: `xbps-install git cmake llvm15 lld-devel libcurl-devel ncurses-devel zlib-devel libzstd-devel libxml2-devel`
2. Clone the C3C repository: `git clone https://github.com/c3lang/c3c.git`
- If you only need the latest commit, you may want to make a shallow clone instead: `git clone https://github.com/c3lang/c3c.git --depth=1`
3. Enter the directory: `cd c3c`
@@ -339,7 +339,7 @@ For a sytem-wide installation, run the following as root: `cmake --install .`
#### Compiling on other Linux / Unix variants
1. Install CMake.
2. Install or compile LLVM and LLD *libraries* (version 17+ or higher)
2. Install or compile LLVM and LLD *libraries* (version 15+ or higher)
3. Clone the C3C github repository: `git clone https://github.com/c3lang/c3c.git`
4. Enter the C3C directory `cd c3c`.
5. Create a build directory `mkdir build`

View File

@@ -1,44 +1,43 @@
#!/bin/bash
## build-with-docker.sh
## @author gdm85
## @modified by Kenta
##
## Script to build c3c for Ubuntu 22
##
#
: ${DOCKER:=docker}
: ${IMAGE:="c3c-builder"}
: ${CMAKE_BUILD_TYPE:=Release}
: ${LLVM_VERSION:=18}
: ${UBUNTU_VERSION:="22.04"}
: ${CMAKE_VERSION:="3.20.0"}
read -p "Select Build Type: Debug/Release: " config
cd docker || exit 1 # Exit if the 'docker' directory doesn't exist
set -e
$DOCKER build \
--build-arg LLVM_VERSION=$LLVM_VERSION \
--build-arg CMAKE_VERSION=$CMAKE_VERSION \
--build-arg UBUNTU_VERSION=$UBUNTU_VERSION \
-t $IMAGE .
if [ $? -ne 0 ]; then
echo "Docker image build failed. Exiting."
exit 1
DOCKER=docker
DOCKER_RUN=""
IMAGE="c3c-builder"
if type podman 2>/dev/null >/dev/null; then
DOCKER=podman
DOCKER_RUN="--userns=keep-id"
IMAGE="localhost/$IMAGE"
fi
if [ $config == "Debug" ]; then
CMAKE_BUILD_TYPE=Debug
else
CMAKE_BUILD_TYPE="$config"
fi
UBUNTU_VERSION="22.10"
LLVM_VERSION="15"
IMAGE="$IMAGE:22"
cd docker && $DOCKER build -t $IMAGE\
--build-arg DEPS="llvm-$LLVM_VERSION-dev liblld-$LLVM_VERSION-dev clang-$LLVM_VERSION libllvm$LLVM_VERSION llvm-$LLVM_VERSION-runtime" \
--build-arg UBUNTU_VERSION="$UBUNTU_VERSION" .
cd ..
rm -rf build bin
mkdir -p build bin
chmod -R 777 build bin
exec $DOCKER run -i --rm \
-v "$PWD":/home/c3c/source \
-w /home/c3c/source $IMAGE bash -c \
"cmake -S . -B build \
-G Ninja \
-DCMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE \
-DCMAKE_C_COMPILER=clang-$LLVM_VERSION \
-DCMAKE_CXX_COMPILER=clang++-$LLVM_VERSION \
-DCMAKE_LINKER=lld-$LLVM_VERSION \
-DCMAKE_OBJCOPY=llvm-objcopy-$LLVM_VERSION \
-DCMAKE_STRIP=llvm-strip-$LLVM_VERSION \
-DCMAKE_DLLTOOL=llvm-dlltool-$LLVM_VERSION \
-DC3_LLVM_VERSION=auto && \
cmake --build build && \
cp -r build/c3c build/lib bin"
exec $DOCKER run -ti --rm --tmpfs=/tmp $DOCKER_RUN -v "$PWD":/home/c3c/source -w /home/c3c/source $IMAGE bash -c \
"cd build && cmake -DCMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE -DC3_LLVM_VERSION=$LLVM_VERSION .. && cmake --build . && mv c3c lib ../bin/"

View File

@@ -1,49 +1,16 @@
ARG UBUNTU_VERSION=22.04
FROM ubuntu:${UBUNTU_VERSION}
ARG LLVM_VERSION=18
ENV LLVM_DEV_VERSION=20
ARG UBUNTU_VERSION
FROM ubuntu:$UBUNTU_VERSION
ARG CMAKE_VERSION=3.20
ARG DEPS
RUN apt-get update && apt-get install -y wget gnupg software-properties-common zlib1g zlib1g-dev python3 ninja-build curl g++ && \
wget https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-$CMAKE_VERSION-linux-x86_64.sh && \
mkdir -p /opt/cmake && \
sh cmake-${CMAKE_VERSION}-linux-x86_64.sh --prefix=/opt/cmake --skip-license && \
rm cmake-${CMAKE_VERSION}-linux-x86_64.sh && \
ln -s /opt/cmake/bin/cmake /usr/local/bin/cmake
RUN export DEBIAN_FRONTEND=noninteractive && export TERM=xterm && apt-get update && apt-get install -y build-essential cmake zlib1g zlib1g-dev \
$DEPS && \
rm -rf /var/lib/apt/lists/*
RUN wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - && \
if [ "${LLVM_VERSION}" -lt 18 ]; then \
add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-${LLVM_VERSION} main" && \
apt-get update && \
apt-get install -y -t llvm-toolchain-focal-${LLVM_VERSION} \
libpolly-${LLVM_VERSION}-dev \
clang-${LLVM_VERSION} llvm-${LLVM_VERSION} llvm-${LLVM_VERSION}-dev \
lld-${LLVM_VERSION} liblld-${LLVM_VERSION}-dev libmlir-${LLVM_VERSION} \
libmlir-${LLVM_VERSION}-dev mlir-${LLVM_VERSION}-tools; \
elif [ "${LLVM_VERSION}" -lt "${LLVM_DEV_VERSION}" ]; then \
add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-${LLVM_VERSION} main" && \
apt-get update && \
apt-get install -y -t llvm-toolchain-focal-${LLVM_VERSION} \
libpolly-${LLVM_VERSION}-dev \
clang-${LLVM_VERSION} clang++-${LLVM_VERSION} llvm-${LLVM_VERSION} llvm-${LLVM_VERSION}-dev \
lld-${LLVM_VERSION} liblld-${LLVM_VERSION}-dev; \
else \
add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal main" && \
apt-get update && \
apt-get install -y -t llvm-toolchain-focal \
libpolly-${LLVM_VERSION}-dev \
clang-${LLVM_VERSION} llvm-${LLVM_VERSION} llvm-${LLVM_VERSION}-dev \
lld-${LLVM_VERSION} liblld-${LLVM_VERSION}-dev; \
fi && \
rm -rf /var/lib/apt/lists/*
ARG GID=1000
ARG UID=1000
RUN groupadd -g 1337 c3c && \
useradd -m -u 1337 -g c3c c3c
RUN groupadd -o --gid=$GID c3c && useradd --gid=$GID --uid=$GID --create-home --shell /bin/bash c3c
# Add cmake to PATH for user c3c
USER c3c
ENV PATH="/opt/cmake/bin:${PATH}"
WORKDIR /home/c3c

View File

@@ -1,434 +0,0 @@
// Copyright (c) 2021-2024 Christoffer Lerno. All rights reserved.
// Use of self source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
/**
* @require MAX_SIZE >= 1 `The size must be at least 1 element big.`
**/
module std::collections::elastic_array(<Type, MAX_SIZE>);
import std::io, std::math, std::collections::list_common;
def ElementPredicate = fn bool(Type *type);
def ElementTest = fn bool(Type *type, any context);
const ELEMENT_IS_EQUATABLE = types::is_equatable_type(Type);
const ELEMENT_IS_POINTER = Type.kindof == POINTER;
macro type_is_overaligned() => Type.alignof > mem::DEFAULT_MEM_ALIGNMENT;
struct ElasticArray (Printable)
{
usz size;
Type[MAX_SIZE] entries;
}
fn usz! ElasticArray.to_format(&self, Formatter* formatter) @dynamic
{
switch (self.size)
{
case 0:
return formatter.print("[]")!;
case 1:
return formatter.printf("[%s]", self.entries[0])!;
default:
usz n = formatter.print("[")!;
foreach (i, element : self.entries[:self.size])
{
if (i != 0) formatter.print(", ")!;
n += formatter.printf("%s", element)!;
}
n += formatter.print("]")!;
return n;
}
}
fn String ElasticArray.to_string(&self, Allocator allocator) @dynamic
{
return string::new_format("%s", *self, .allocator = allocator);
}
fn String ElasticArray.to_tstring(&self)
{
return string::tformat("%s", *self);
}
fn void! ElasticArray.push_try(&self, Type element) @inline
{
if (self.size == MAX_SIZE) return AllocationFailure.OUT_OF_MEMORY?;
self.entries[self.size++] = element;
}
/**
* @require self.size < MAX_SIZE `Tried to exceed the max size`
**/
fn void ElasticArray.push(&self, Type element) @inline
{
self.entries[self.size++] = element;
}
fn Type! ElasticArray.pop(&self)
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
return self.entries[--self.size];
}
fn void ElasticArray.clear(&self)
{
self.size = 0;
}
/**
* @require self.size > 0
**/
fn Type! ElasticArray.pop_first(&self)
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
defer self.remove_at(0);
return self.entries[0];
}
/**
* @require index < self.size
**/
fn void ElasticArray.remove_at(&self, usz index)
{
if (!--self.size || index == self.size) return;
self.entries[index .. self.size - 1] = self.entries[index + 1 .. self.size];
}
/**
* @require other_list.size + self.size <= MAX_SIZE
**/
fn void ElasticArray.add_all(&self, ElasticArray* other_list)
{
if (!other_list.size) return;
foreach (&value : other_list)
{
self.entries[self.size++] = *value;
}
}
/**
* Add as many elements as possible to the new array,
* returning the number of elements that didn't fit.
**/
fn usz ElasticArray.add_all_to_limit(&self, ElasticArray* other_list)
{
if (!other_list.size) return 0;
foreach (i, &value : other_list)
{
if (self.size == MAX_SIZE) return other_list.size - i;
self.entries[self.size++] = *value;
}
return 0;
}
/**
* Add as many values from this array as possible, returning the
* number of elements that didn't fit.
*
* @param [in] array
**/
fn usz ElasticArray.add_array_to_limit(&self, Type[] array)
{
if (!array.len) return 0;
foreach (i, &value : array)
{
if (self.size == MAX_SIZE) return array.len - i;
self.entries[self.size++] = *value;
}
return 0;
}
/**
* Add the values of an array to this list.
*
* @param [in] array
* @require array.len + self.size <= MAX_SIZE `Size would exceed max.`
* @ensure self.size >= array.len
**/
fn void ElasticArray.add_array(&self, Type[] array)
{
if (!array.len) return;
foreach (&value : array)
{
self.entries[self.size++] = *value;
}
}
/**
* IMPORTANT The returned array must be freed using free_aligned.
**/
fn Type[] ElasticArray.to_new_aligned_array(&self, Allocator allocator = allocator::heap())
{
return list_common::list_to_new_aligned_array(Type, self, allocator);
}
/**
* @require !type_is_overaligned() : "This function is not available on overaligned types"
**/
macro Type[] ElasticArray.to_new_array(&self, Allocator allocator = allocator::heap())
{
return list_common::list_to_new_array(Type, self, allocator);
}
fn Type[] ElasticArray.to_tarray(&self)
{
$if type_is_overaligned():
return self.to_new_aligned_array(allocator::temp());
$else
return self.to_new_array(allocator::temp());
$endif;
}
/**
* Reverse the elements in a list.
**/
fn void ElasticArray.reverse(&self)
{
list_common::list_reverse(self);
}
fn Type[] ElasticArray.array_view(&self)
{
return self.entries[:self.size];
}
/**
* @require self.size < MAX_SIZE `List would exceed max size`
**/
fn void ElasticArray.push_front(&self, Type type) @inline
{
self.insert_at(0, type);
}
/**
* @require self.size < MAX_SIZE `List would exceed max size`
**/
fn void! ElasticArray.push_front_try(&self, Type type) @inline
{
return self.insert_at_try(0, type);
}
/**
* @require index <= self.size
**/
fn void! ElasticArray.insert_at_try(&self, usz index, Type value)
{
if (self.size == MAX_SIZE) return AllocationFailure.OUT_OF_MEMORY?;
self.insert_at(index, value);
}
/**
* @require self.size < MAX_SIZE `List would exceed max size`
* @require index <= self.size
**/
fn void ElasticArray.insert_at(&self, usz index, Type type)
{
for (usz i = self.size; i > index; i--)
{
self.entries[i] = self.entries[i - 1];
}
self.size++;
self.entries[index] = type;
}
/**
* @require index < self.size
**/
fn void ElasticArray.set_at(&self, usz index, Type type)
{
self.entries[index] = type;
}
fn void! ElasticArray.remove_last(&self) @maydiscard
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
self.size--;
}
fn void! ElasticArray.remove_first(&self) @maydiscard
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
self.remove_at(0);
}
fn Type! ElasticArray.first(&self)
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
return self.entries[0];
}
fn Type! ElasticArray.last(&self)
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
return self.entries[self.size - 1];
}
fn bool ElasticArray.is_empty(&self) @inline
{
return !self.size;
}
fn usz ElasticArray.byte_size(&self) @inline
{
return Type.sizeof * self.size;
}
fn usz ElasticArray.len(&self) @operator(len) @inline
{
return self.size;
}
fn Type ElasticArray.get(&self, usz index) @inline
{
return self.entries[index];
}
fn void ElasticArray.swap(&self, usz i, usz j)
{
@swap(self.entries[i], self.entries[j]);
}
/**
* @param filter "The function to determine if it should be removed or not"
* @return "the number of deleted elements"
**/
fn usz ElasticArray.remove_if(&self, ElementPredicate filter)
{
return list_common::list_remove_if(self, filter, false);
}
/**
* @param selection "The function to determine if it should be kept or not"
* @return "the number of deleted elements"
**/
fn usz ElasticArray.retain_if(&self, ElementPredicate selection)
{
return list_common::list_remove_if(self, selection, true);
}
fn usz ElasticArray.remove_using_test(&self, ElementTest filter, any context)
{
return list_common::list_remove_using_test(self, filter, false, context);
}
fn usz ElasticArray.retain_using_test(&self, ElementTest filter, any context)
{
return list_common::list_remove_using_test(self, filter, true, context);
}
macro Type ElasticArray.@item_at(&self, usz index) @operator([])
{
return self.entries[index];
}
fn Type* ElasticArray.get_ref(&self, usz index) @operator(&[]) @inline
{
return &self.entries[index];
}
fn void ElasticArray.set(&self, usz index, Type value) @operator([]=)
{
self.entries[index] = value;
}
// Functions for equatable types
fn usz! ElasticArray.index_of(&self, Type type) @if(ELEMENT_IS_EQUATABLE)
{
foreach (i, v : self)
{
if (equals(v, type)) return i;
}
return SearchResult.MISSING?;
}
fn usz! ElasticArray.rindex_of(&self, Type type) @if(ELEMENT_IS_EQUATABLE)
{
foreach_r (i, v : self)
{
if (equals(v, type)) return i;
}
return SearchResult.MISSING?;
}
fn bool ElasticArray.equals(&self, ElasticArray other_list) @if(ELEMENT_IS_EQUATABLE)
{
if (self.size != other_list.size) return false;
foreach (i, v : self)
{
if (!equals(v, other_list.entries[i])) return false;
}
return true;
}
/**
* Check for presence of a value in a list.
*
* @param [&in] self "the list to find elements in"
* @param value "The value to search for"
* @return "True if the value is found, false otherwise"
**/
fn bool ElasticArray.contains(&self, Type value) @if(ELEMENT_IS_EQUATABLE)
{
foreach (i, v : self)
{
if (equals(v, value)) return true;
}
return false;
}
/**
* @param [&inout] self "The list to remove elements from"
* @param value "The value to remove"
* @return "true if the value was found"
**/
fn bool ElasticArray.remove_last_item(&self, Type value) @if(ELEMENT_IS_EQUATABLE)
{
return @ok(self.remove_at(self.rindex_of(value)));
}
/**
* @param [&inout] self "The list to remove elements from"
* @param value "The value to remove"
* @return "true if the value was found"
**/
fn bool ElasticArray.remove_first_item(&self, Type value) @if(ELEMENT_IS_EQUATABLE)
{
return @ok(self.remove_at(self.index_of(value)));
}
/**
* @param [&inout] self "The list to remove elements from"
* @param value "The value to remove"
* @return "the number of deleted elements."
**/
fn usz ElasticArray.remove_item(&self, Type value) @if(ELEMENT_IS_EQUATABLE)
{
return list_common::list_remove_item(self, value);
}
fn void ElasticArray.remove_all_from(&self, ElasticArray* other_list) @if(ELEMENT_IS_EQUATABLE)
{
if (!other_list.size) return;
foreach (v : other_list) self.remove_item(v);
}
/**
* @param [&in] self
* @return "The number non-null values in the list"
**/
fn usz ElasticArray.compact_count(&self) @if(ELEMENT_IS_POINTER)
{
usz vals = 0;
foreach (v : self) if (v) vals++;
return vals;
}
fn usz ElasticArray.compact(&self) @if(ELEMENT_IS_POINTER)
{
return list_common::list_compact(self);
}

View File

@@ -1,400 +0,0 @@
// Copyright (c) 2023 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::collections::map(<Key, Value>);
import std::math;
struct HashMap
{
Entry*[] table;
Allocator allocator;
uint count; // Number of elements
uint threshold; // Resize limit
float load_factor;
}
/**
* @param [&inout] allocator "The allocator to use"
* @require capacity > 0 "The capacity must be 1 or higher"
* @require load_factor > 0.0 "The load factor must be higher than 0"
* @require !self.allocator "Map was already initialized"
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
**/
fn HashMap* HashMap.new_init(&self, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap())
{
capacity = math::next_power_of_2(capacity);
self.allocator = allocator;
self.load_factor = load_factor;
self.threshold = (uint)(capacity * load_factor);
self.table = allocator::new_array(allocator, Entry*, capacity);
return self;
}
/**
* @require capacity > 0 "The capacity must be 1 or higher"
* @require load_factor > 0.0 "The load factor must be higher than 0"
* @require !self.allocator "Map was already initialized"
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
**/
fn HashMap* HashMap.temp_init(&self, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR)
{
return self.new_init(capacity, load_factor, allocator::temp()) @inline;
}
/**
* Has this hash map been initialized yet?
*
* @param [&in] map "The hash map we are testing"
* @return "Returns true if it has been initialized, false otherwise"
**/
fn bool HashMap.is_initialized(&map)
{
return (bool)map.allocator;
}
/**
* @param [&inout] allocator "The allocator to use"
* @param [&in] other_map "The map to copy from."
**/
fn HashMap* HashMap.new_init_from_map(&self, HashMap* other_map, Allocator allocator = allocator::heap())
{
self.new_init(other_map.table.len, other_map.load_factor, allocator);
self.put_all_for_create(other_map);
return self;
}
/**
* @param [&in] other_map "The map to copy from."
**/
fn HashMap* HashMap.temp_init_from_map(&map, HashMap* other_map)
{
return map.new_init_from_map(other_map, allocator::temp()) @inline;
}
fn bool HashMap.is_empty(&map) @inline
{
return !map.count;
}
fn usz HashMap.len(&map) @inline
{
return map.count;
}
fn Value*! HashMap.get_ref(&map, Key key)
{
if (!map.count) return SearchResult.MISSING?;
uint hash = rehash(key.hash());
for (Entry *e = map.table[index_for(hash, map.table.len)]; e != null; e = e.next)
{
if (e.hash == hash && equals(key, e.key)) return &e.value;
}
return SearchResult.MISSING?;
}
fn Entry*! HashMap.get_entry(&map, Key key)
{
if (!map.count) return SearchResult.MISSING?;
uint hash = rehash(key.hash());
for (Entry *e = map.table[index_for(hash, map.table.len)]; e != null; e = e.next)
{
if (e.hash == hash && equals(key, e.key)) return e;
}
return SearchResult.MISSING?;
}
/**
* Get the value or update and
* @require $assignable(#expr, Value)
**/
macro Value HashMap.@get_or_set(&map, Key key, Value #expr)
{
if (!map.count)
{
Value val = #expr;
map.set(key, val);
return val;
}
uint hash = rehash(key.hash());
uint index = index_for(hash, map.table.len);
for (Entry *e = map.table[index]; e != null; e = e.next)
{
if (e.hash == hash && equals(key, e.key)) return e.value;
}
Value val = #expr;
map.add_entry(hash, key, val, index);
return val;
}
fn Value! HashMap.get(&map, Key key) @operator([])
{
return *map.get_ref(key) @inline;
}
fn bool HashMap.has_key(&map, Key key)
{
return @ok(map.get_ref(key));
}
fn bool HashMap.set(&map, Key key, Value value) @operator([]=)
{
// If the map isn't initialized, use the defaults to initialize it.
if (!map.allocator)
{
map.new_init();
}
uint hash = rehash(key.hash());
uint index = index_for(hash, map.table.len);
for (Entry *e = map.table[index]; e != null; e = e.next)
{
if (e.hash == hash && equals(key, e.key))
{
e.value = value;
return true;
}
}
map.add_entry(hash, key, value, index);
return false;
}
fn void! HashMap.remove(&map, Key key) @maydiscard
{
if (!map.remove_entry_for_key(key)) return SearchResult.MISSING?;
}
fn void HashMap.clear(&map)
{
if (!map.count) return;
foreach (Entry** &entry_ref : map.table)
{
Entry* entry = *entry_ref;
if (!entry) continue;
Entry *next = entry.next;
while (next)
{
Entry *to_delete = next;
next = next.next;
map.free_entry(to_delete);
}
map.free_entry(entry);
*entry_ref = null;
}
map.count = 0;
}
fn void HashMap.free(&map)
{
if (!map.allocator) return;
map.clear();
map.free_internal(map.table.ptr);
map.table = {};
}
fn Key[] HashMap.key_tlist(&map)
{
return map.key_new_list(allocator::temp()) @inline;
}
fn Key[] HashMap.key_new_list(&map, Allocator allocator = allocator::heap())
{
if (!map.count) return {};
Key[] list = allocator::alloc_array(allocator, Key, map.count);
usz index = 0;
foreach (Entry* entry : map.table)
{
while (entry)
{
list[index++] = entry.key;
entry = entry.next;
}
}
return list;
}
macro HashMap.@each(map; @body(key, value))
{
map.@each_entry(; Entry* entry) {
@body(entry.key, entry.value);
};
}
macro HashMap.@each_entry(map; @body(entry))
{
if (map.count)
{
foreach (Entry* entry : map.table)
{
while (entry)
{
@body(entry);
entry = entry.next;
}
}
}
}
fn Value[] HashMap.value_tlist(&map)
{
return map.value_new_list(allocator::temp()) @inline;
}
fn Value[] HashMap.value_new_list(&map, Allocator allocator = allocator::heap())
{
if (!map.count) return {};
Value[] list = allocator::alloc_array(allocator, Value, map.count);
usz index = 0;
foreach (Entry* entry : map.table)
{
while (entry)
{
list[index++] = entry.value;
entry = entry.next;
}
}
return list;
}
fn bool HashMap.has_value(&map, Value v) @if(VALUE_IS_EQUATABLE)
{
if (!map.count) return false;
foreach (Entry* entry : map.table)
{
while (entry)
{
if (equals(v, entry.value)) return true;
entry = entry.next;
}
}
return false;
}
// --- private methods
fn void HashMap.add_entry(&map, uint hash, Key key, Value value, uint bucket_index) @private
{
$if COPY_KEYS:
key = key.copy(map.allocator);
$endif
Entry* entry = allocator::new(map.allocator, Entry, { .hash = hash, .key = key, .value = value, .next = map.table[bucket_index] });
map.table[bucket_index] = entry;
if (map.count++ >= map.threshold)
{
map.resize(map.table.len * 2);
}
}
fn void HashMap.resize(&map, uint new_capacity) @private
{
Entry*[] old_table = map.table;
uint old_capacity = old_table.len;
if (old_capacity == MAXIMUM_CAPACITY)
{
map.threshold = uint.max;
return;
}
Entry*[] new_table = allocator::new_array(map.allocator, Entry*, new_capacity);
map.transfer(new_table);
map.table = new_table;
map.free_internal(old_table.ptr);
map.threshold = (uint)(new_capacity * map.load_factor);
}
fn void HashMap.transfer(&map, Entry*[] new_table) @private
{
Entry*[] src = map.table;
uint new_capacity = new_table.len;
foreach (uint j, Entry *e : src)
{
if (!e) continue;
do
{
Entry* next = e.next;
uint i = index_for(e.hash, new_capacity);
e.next = new_table[i];
new_table[i] = e;
e = next;
}
while (e);
}
}
fn void HashMap.put_all_for_create(&map, HashMap* other_map) @private
{
if (!other_map.count) return;
foreach (Entry *e : other_map.table)
{
if (!e) continue;
map.put_for_create(e.key, e.value);
}
}
fn void HashMap.put_for_create(&map, Key key, Value value) @private
{
uint hash = rehash(key.hash());
uint i = index_for(hash, map.table.len);
for (Entry *e = map.table[i]; e != null; e = e.next)
{
if (e.hash == hash && equals(key, e.key))
{
e.value = value;
return;
}
}
map.create_entry(hash, key, value, i);
}
fn void HashMap.free_internal(&map, void* ptr) @inline @private
{
allocator::free(map.allocator, ptr);
}
fn bool HashMap.remove_entry_for_key(&map, Key key) @private
{
uint hash = rehash(key.hash());
uint i = index_for(hash, map.table.len);
Entry* prev = map.table[i];
Entry* e = prev;
while (e)
{
Entry *next = e.next;
if (e.hash == hash && equals(key, e.key))
{
map.count--;
if (prev == e)
{
map.table[i] = next;
}
else
{
prev.next = next;
}
map.free_entry(e);
return true;
}
prev = e;
e = next;
}
return false;
}
fn void HashMap.create_entry(&map, uint hash, Key key, Value value, int bucket_index) @private
{
Entry *e = map.table[bucket_index];
$if COPY_KEYS:
key = key.copy(map.allocator);
$endif
Entry* entry = allocator::new(map.allocator, Entry, { .hash = hash, .key = key, .value = value, .next = map.table[bucket_index] });
map.table[bucket_index] = entry;
map.count++;
}
fn void HashMap.free_entry(&self, Entry *entry) @local
{
$if COPY_KEYS:
allocator::free(self.allocator, entry.key);
$endif
self.free_internal(entry);
}

View File

@@ -2,15 +2,13 @@
// Use of self source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::collections::list(<Type>);
import std::io, std::math, std::collections::list_common;
import std::io,std::math;
def ElementPredicate = fn bool(Type *type);
def ElementTest = fn bool(Type *type, any context);
const ELEMENT_IS_EQUATABLE = types::is_equatable_type(Type);
const ELEMENT_IS_POINTER = Type.kindof == POINTER;
macro type_is_overaligned() => Type.alignof > mem::DEFAULT_MEM_ALIGNMENT;
struct List (Printable)
{
usz size;
@@ -19,6 +17,7 @@ struct List (Printable)
Type *entries;
}
/**
* @param initial_capacity "The initial capacity to reserve"
* @param [&inout] allocator "The allocator to use, defaults to the heap allocator"
@@ -27,9 +26,16 @@ fn List* List.new_init(&self, usz initial_capacity = 16, Allocator allocator = a
{
self.allocator = allocator;
self.size = 0;
self.capacity = 0;
self.entries = null;
self.reserve(initial_capacity);
if (initial_capacity > 0)
{
initial_capacity = math::next_power_of_2(initial_capacity);
self.entries = allocator::malloc_aligned(allocator, Type.sizeof * initial_capacity, .alignment = Type[1].alignof)!!;
}
else
{
self.entries = null;
}
self.capacity = initial_capacity;
return self;
}
@@ -44,40 +50,14 @@ fn List* List.temp_init(&self, usz initial_capacity = 16)
}
/**
* Initialize a new list with an array.
*
* @param [in] values `The values to initialize the list with.`
* @require self.size == 0 "The List must be empty"
**/
fn List* List.new_init_with_array(&self, Type[] values, Allocator allocator = allocator::heap())
{
self.new_init(values.len, allocator) @inline;
self.add_array(values) @inline;
return self;
}
/**
* Initialize a temporary list with an array.
*
* @param [in] values `The values to initialize the list with.`
* @require self.size == 0 "The List must be empty"
**/
fn List* List.temp_init_with_array(&self, Type[] values)
{
self.temp_init(values.len) @inline;
self.add_array(values) @inline;
return self;
}
/**
* @require self.capacity == 0 "The List must not be allocated"
**/
fn void List.init_wrapping_array(&self, Type[] types, Allocator allocator = allocator::heap())
{
self.allocator = allocator;
self.size = types.len;
self.capacity = types.len;
self.entries = types.ptr;
self.set_size(types.len);
}
fn usz! List.to_format(&self, Formatter* formatter) @dynamic
@@ -112,20 +92,19 @@ fn String List.to_tstring(&self)
fn void List.push(&self, Type element) @inline
{
self.reserve(1);
self.entries[self.set_size(self.size + 1)] = element;
self.ensure_capacity();
self.entries[self.size++] = element;
}
fn Type! List.pop(&self)
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
defer self.set_size(self.size - 1);
return self.entries[self.size - 1];
return self.entries[--self.size];
}
fn void List.clear(&self)
{
self.set_size(0);
self.size = 0;
}
/**
@@ -143,8 +122,7 @@ fn Type! List.pop_first(&self)
**/
fn void List.remove_at(&self, usz index)
{
self.set_size(self.size - 1);
if (!self.size || index == self.size) return;
if (!--self.size || index == self.size) return;
self.entries[index .. self.size - 1] = self.entries[index + 1 .. self.size];
}
@@ -152,37 +130,24 @@ fn void List.add_all(&self, List* other_list)
{
if (!other_list.size) return;
self.reserve(other_list.size);
usz index = self.set_size(self.size + other_list.size);
foreach (&value : other_list)
{
self.entries[index++] = *value;
self.entries[self.size++] = *value;
}
}
/**
* IMPORTANT The returned array must be freed using free_aligned.
**/
fn Type[] List.to_new_aligned_array(&self, Allocator allocator = allocator::heap())
fn Type[] List.to_new_array(&self, Allocator allocator = allocator::heap())
{
return list_common::list_to_new_aligned_array(Type, self, allocator);
}
/**
* @require !type_is_overaligned() : "This function is not available on overaligned types"
**/
macro Type[] List.to_new_array(&self, Allocator allocator = allocator::heap())
{
return list_common::list_to_new_array(Type, self, allocator);
if (!self.size) return Type[] {};
Type[] result = allocator::alloc_array(allocator, Type, self.size);
result[..] = self.entries[:self.size];
return result;
}
fn Type[] List.to_tarray(&self)
{
$if type_is_overaligned():
return self.to_new_aligned_array(allocator::temp());
$else
return self.to_new_array(allocator::temp());
$endif;
}
/**
@@ -190,7 +155,13 @@ fn Type[] List.to_tarray(&self)
**/
fn void List.reverse(&self)
{
list_common::list_reverse(self);
if (self.size < 2) return;
usz half = self.size / 2U;
usz end = self.size - 1;
for (usz i = 0; i < half; i++)
{
@swap(self.entries[i], self.entries[end - i]);
}
}
fn Type[] List.array_view(&self)
@@ -198,18 +169,14 @@ fn Type[] List.array_view(&self)
return self.entries[:self.size];
}
/**
* Add the values of an array to this list.
*
* @param [in] array
* @ensure self.size >= array.len
**/
fn void List.add_array(&self, Type[] array)
{
if (!array.len) return;
self.reserve(array.len);
usz index = self.set_size(self.size + array.len);
self.entries[index : array.len] = array[..];
foreach (&value : array)
{
self.entries[self.size++] = *value;
}
}
fn void List.push_front(&self, Type type) @inline
@@ -218,16 +185,16 @@ fn void List.push_front(&self, Type type) @inline
}
/**
* @require index <= self.size
* @require index < self.size
**/
fn void List.insert_at(&self, usz index, Type type)
{
self.reserve(1);
self.ensure_capacity();
for (usz i = self.size; i > index; i--)
{
self.entries[i] = self.entries[i - 1];
}
self.set_size(self.size + 1);
self.size++;
self.entries[index] = type;
}
@@ -242,7 +209,7 @@ fn void List.set_at(&self, usz index, Type type)
fn void! List.remove_last(&self) @maydiscard
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
self.set_size(self.size - 1);
self.size--;
}
fn void! List.remove_first(&self) @maydiscard
@@ -285,15 +252,8 @@ fn Type List.get(&self, usz index) @inline
fn void List.free(&self)
{
if (!self.allocator || !self.capacity) return;
self.pre_free(); // Remove sanitizer annotation
$if type_is_overaligned():
allocator::free_aligned(self.allocator, self.entries);
$else
allocator::free(self.allocator, self.entries);
$endif;
if (!self.allocator) return;
allocator::free_aligned(self.allocator, self.entries);
self.capacity = 0;
self.size = 0;
self.entries = null;
@@ -310,7 +270,7 @@ fn void List.swap(&self, usz i, usz j)
**/
fn usz List.remove_if(&self, ElementPredicate filter)
{
return list_common::list_remove_if(self, filter, false);
return self._remove_if(filter, false);
}
/**
@@ -319,46 +279,80 @@ fn usz List.remove_if(&self, ElementPredicate filter)
**/
fn usz List.retain_if(&self, ElementPredicate selection)
{
return list_common::list_remove_if(self, selection, true);
return self._remove_if(selection, true);
}
macro usz List._remove_if(&self, ElementPredicate filter, bool $invert) @local
{
usz size = self.size;
for (usz i = size, usz k = size; k > 0; k = i)
{
// Find last index of item to be deleted.
$if $invert:
while (i > 0 && !filter(&self.entries[i - 1])) i--;
$else
while (i > 0 && filter(&self.entries[i - 1])) i--;
$endif
// Remove the items from this index up to the one not to be deleted.
usz n = self.size - k;
self.entries[i:n] = self.entries[k:n];
self.size -= k - i;
// Find last index of item not to be deleted.
$if $invert:
while (i > 0 && filter(&self.entries[i - 1])) i--;
$else
while (i > 0 && !filter(&self.entries[i - 1])) i--;
$endif
}
return size - self.size;
}
fn usz List.remove_using_test(&self, ElementTest filter, any context)
{
usz old_size = self.size;
defer {
if (old_size != self.size) self._update_size_change(old_size, self.size);
}
return list_common::list_remove_using_test(self, filter, false, context);
return self._remove_using_test(filter, false, context);
}
fn usz List.retain_using_test(&self, ElementTest filter, any context)
{
usz old_size = self.size;
defer {
if (old_size != self.size) self._update_size_change(old_size, self.size);
}
return list_common::list_remove_using_test(self, filter, true, context);
return self._remove_using_test(filter, true, context);
}
fn void List.ensure_capacity(&self, usz min_capacity) @local
macro usz List._remove_using_test(&self, ElementTest filter, bool $invert, ctx) @local
{
usz size = self.size;
for (usz i = size, usz k = size; k > 0; k = i)
{
// Find last index of item to be deleted.
$if $invert:
while (i > 0 && !filter(&self.entries[i - 1], ctx)) i--;
$else
while (i > 0 && filter(&self.entries[i - 1], ctx)) i--;
$endif
// Remove the items from this index up to the one not to be deleted.
usz n = self.size - k;
self.entries[i:n] = self.entries[k:n];
self.size -= k - i;
// Find last index of item not to be deleted.
$if $invert:
while (i > 0 && filter(&self.entries[i - 1], ctx)) i--;
$else
while (i > 0 && !filter(&self.entries[i - 1], ctx)) i--;
$endif
}
return size - self.size;
}
/**
* Reserve at least min_capacity
**/
fn void List.reserve(&self, usz min_capacity)
{
if (!min_capacity) return;
if (self.capacity >= min_capacity) return;
if (!self.allocator) self.allocator = allocator::heap();
self.pre_free(); // Remove sanitizer annotation
min_capacity = math::next_power_of_2(min_capacity);
$if type_is_overaligned():
self.entries = allocator::realloc_aligned(self.allocator, self.entries, Type.sizeof * min_capacity, .alignment = Type[1].alignof)!!;
$else
self.entries = allocator::realloc(self.allocator, self.entries, Type.sizeof * min_capacity);
$endif;
self.entries = allocator::realloc_aligned(self.allocator, self.entries, Type.sizeof * min_capacity, .alignment = Type[1].alignof) ?? null;
self.capacity = min_capacity;
self.post_alloc(); // Add sanitizer annotation
}
macro Type List.@item_at(&self, usz index) @operator([])
@@ -376,7 +370,7 @@ fn void List.set(&self, usz index, Type value) @operator([]=)
self.entries[index] = value;
}
fn void List.reserve(&self, usz added)
fn void List.ensure_capacity(&self, usz added = 1) @inline @private
{
usz new_size = self.size + added;
if (self.capacity >= new_size) return;
@@ -384,40 +378,7 @@ fn void List.reserve(&self, usz added)
assert(new_size < usz.max / 2U);
usz new_capacity = self.capacity ? 2U * self.capacity : 16U;
while (new_capacity < new_size) new_capacity *= 2U;
self.ensure_capacity(new_capacity);
}
fn void List._update_size_change(&self,usz old_size, usz new_size)
{
if (old_size == new_size) return;
sanitizer::annotate_contiguous_container(self.entries,
&self.entries[self.capacity],
&self.entries[old_size],
&self.entries[new_size]);
}
/**
* @require new_size == 0 || self.capacity != 0
**/
fn usz List.set_size(&self, usz new_size) @inline @private
{
usz old_size = self.size;
self._update_size_change(old_size, new_size);
self.size = new_size;
return old_size;
}
macro void List.pre_free(&self) @private
{
if (!self.capacity) return;
self._update_size_change(self.size, self.capacity);
}
/**
* @require self.capacity
**/
macro void List.post_alloc(&self) @private
{
self._update_size_change(self.capacity, self.size);
self.reserve(new_capacity);
}
// Functions for equatable types
@@ -467,12 +428,13 @@ fn bool List.contains(&self, Type value) @if(ELEMENT_IS_EQUATABLE)
return false;
}
/**
* @param [&inout] self "The list to remove elements from"
* @param value "The value to remove"
* @return "true if the value was found"
**/
fn bool List.remove_last_item(&self, Type value) @if(ELEMENT_IS_EQUATABLE)
fn bool List.remove_last_match(&self, Type value) @if(ELEMENT_IS_EQUATABLE)
{
return @ok(self.remove_at(self.rindex_of(value)));
}
@@ -482,34 +444,35 @@ fn bool List.remove_last_item(&self, Type value) @if(ELEMENT_IS_EQUATABLE)
* @param value "The value to remove"
* @return "true if the value was found"
**/
fn bool List.remove_first_item(&self, Type value) @if(ELEMENT_IS_EQUATABLE)
fn bool List.remove_first_match(&self, Type value) @if(ELEMENT_IS_EQUATABLE)
{
return @ok(self.remove_at(self.index_of(value)));
}
/**
* @param [&inout] self "The list to remove elements from"
* @param value "The value to remove"
* @return "the number of deleted elements."
**/
fn usz List.remove_item(&self, Type value) @if(ELEMENT_IS_EQUATABLE)
fn usz List.remove_all_matches(&self, Type value) @if(ELEMENT_IS_EQUATABLE)
{
usz old_size = self.size;
defer {
if (old_size != self.size) self._update_size_change(old_size, self.size);
usz size = self.size;
for (usz i = size; i > 0; i--)
{
if (!equals(self.entries[i - 1], value)) continue;
for (usz j = i; j < self.size; j++)
{
self.entries[j - 1] = self.entries[j];
}
self.size--;
}
return list_common::list_remove_item(self, value);
return size - self.size;
}
fn void List.remove_all_from(&self, List* other_list) @if(ELEMENT_IS_EQUATABLE)
{
if (!other_list.size) return;
usz old_size = self.size;
defer {
if (old_size != self.size) self._update_size_change(old_size, self.size);
}
foreach (v : other_list) self.remove_item(v);
foreach (v : other_list) self.remove_all_matches(v);
}
/**
@@ -525,42 +488,15 @@ fn usz List.compact_count(&self) @if(ELEMENT_IS_POINTER)
fn usz List.compact(&self) @if(ELEMENT_IS_POINTER)
{
usz old_size = self.size;
defer {
if (old_size != self.size) self._update_size_change(old_size, self.size);
usz size = self.size;
for (usz i = size; i > 0; i--)
{
if (self.entries[i - 1]) continue;
for (usz j = i; j < size; j++)
{
self.entries[j - 1] = self.entries[j];
}
self.size--;
}
return list_common::list_compact(self);
}
// --> Deprecated
/**
* @param [&inout] self "The list to remove elements from"
* @param value "The value to remove"
* @return "true if the value was found"
**/
fn bool List.remove_last_match(&self, Type value) @if(ELEMENT_IS_EQUATABLE) @deprecated
{
return self.remove_last_item(value) @inline;
}
/**
* @param [&inout] self "The list to remove elements from"
* @param value "The value to remove"
* @return "true if the value was found"
**/
fn bool List.remove_first_match(&self, Type value) @if(ELEMENT_IS_EQUATABLE) @deprecated
{
return self.remove_first_item(value) @inline;
}
/**
* @param [&inout] self "The list to remove elements from"
* @param value "The value to remove"
* @return "the number of deleted elements."
**/
fn usz List.remove_all_matches(&self, Type value) @if(ELEMENT_IS_EQUATABLE) @deprecated
{
return self.remove_item(value) @inline;
return size - self.size;
}

View File

@@ -1,112 +0,0 @@
module std::collections::list_common;
/**
* IMPORTANT The returned array must be freed using free_aligned.
**/
macro list_to_new_aligned_array($Type, self, Allocator allocator)
{
if (!self.size) return $Type[] {};
$Type[] result = allocator::alloc_array_aligned(allocator, $Type, self.size);
result[..] = self.entries[:self.size];
return result;
}
macro list_to_new_array($Type, self, Allocator allocator)
{
if (!self.size) return $Type[] {};
$Type[] result = allocator::alloc_array(allocator, $Type, self.size);
result[..] = self.entries[:self.size];
return result;
}
macro void list_reverse(self)
{
if (self.size < 2) return;
usz half = self.size / 2U;
usz end = self.size - 1;
for (usz i = 0; i < half; i++)
{
@swap(self.entries[i], self.entries[end - i]);
}
}
macro usz list_remove_using_test(self, filter, bool $invert, ctx)
{
usz size = self.size;
for (usz i = size, usz k = size; k > 0; k = i)
{
// Find last index of item to be deleted.
$if $invert:
while (i > 0 && !filter(&self.entries[i - 1], ctx)) i--;
$else
while (i > 0 && filter(&self.entries[i - 1], ctx)) i--;
$endif
// Remove the items from this index up to the one not to be deleted.
usz n = self.size - k;
self.entries[i:n] = self.entries[k:n];
self.size -= k - i;
// Find last index of item not to be deleted.
$if $invert:
while (i > 0 && filter(&self.entries[i - 1], ctx)) i--;
$else
while (i > 0 && !filter(&self.entries[i - 1], ctx)) i--;
$endif
}
return size - self.size;
}
macro usz list_compact(self)
{
usz size = self.size;
for (usz i = size; i > 0; i--)
{
if (self.entries[i - 1]) continue;
for (usz j = i; j < size; j++)
{
self.entries[j - 1] = self.entries[j];
}
self.size--;
}
return size - self.size;
}
macro usz list_remove_item(self, value)
{
usz size = self.size;
for (usz i = size; i > 0; i--)
{
if (!equals(self.entries[i - 1], value)) continue;
for (usz j = i; j < self.size; j++)
{
self.entries[j - 1] = self.entries[j];
}
self.size--;
}
return size - self.size;
}
macro usz list_remove_if(self, filter, bool $invert)
{
usz size = self.size;
for (usz i = size, usz k = size; k > 0; k = i)
{
// Find last index of item to be deleted.
$if $invert:
while (i > 0 && !filter(&self.entries[i - 1])) i--;
$else
while (i > 0 && filter(&self.entries[i - 1])) i--;
$endif
// Remove the items from this index up to the one not to be deleted.
usz n = self.size - k;
self.entries[i:n] = self.entries[k:n];
self.size -= k - i;
// Find last index of item not to be deleted.
$if $invert:
while (i > 0 && filter(&self.entries[i - 1])) i--;
$else
while (i > 0 && !filter(&self.entries[i - 1])) i--;
$endif
}
return size - self.size;
}

View File

@@ -10,9 +10,7 @@ const float DEFAULT_LOAD_FACTOR = 0.75;
const VALUE_IS_EQUATABLE = Value.is_eq;
const bool COPY_KEYS = types::implements_copy(Key);
distinct Map = void*;
struct MapImpl
struct HashMap
{
Entry*[] table;
Allocator allocator;
@@ -22,72 +20,77 @@ struct MapImpl
}
/**
* @param [&inout] allocator "The allocator to use"
* @require capacity > 0 "The capacity must be 1 or higher"
* @require load_factor > 0.0 "The load factor must be higher than 0"
* @require !self.allocator "Map was already initialized"
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
**/
fn Map new(uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap())
fn HashMap* HashMap.new_init(&self, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap())
{
MapImpl* map = allocator::alloc(allocator, MapImpl);
_init(map, capacity, load_factor, allocator);
return (Map)map;
capacity = math::next_power_of_2(capacity);
self.allocator = allocator;
self.load_factor = load_factor;
self.threshold = (uint)(capacity * load_factor);
self.table = allocator::new_array(allocator, Entry*, capacity);
return self;
}
/**
* @require capacity > 0 "The capacity must be 1 or higher"
* @require load_factor > 0.0 "The load factor must be higher than 0"
* @require !self.allocator "Map was already initialized"
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
**/
fn Map temp(uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR)
fn HashMap* HashMap.temp_init(&self, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR)
{
MapImpl* map = mem::temp_alloc(MapImpl);
_init(map, capacity, load_factor, allocator::temp());
return (Map)map;
return self.new_init(capacity, load_factor, allocator::temp()) @inline;
}
/**
* Has this hash map been initialized yet?
*
* @param [&in] map "The hash map we are testing"
* @return "Returns true if it has been initialized, false otherwise"
**/
fn bool HashMap.is_initialized(&map)
{
return (bool)map.allocator;
}
/**
* @param [&inout] allocator "The allocator to use"
* @param [&in] other_map "The map to copy from."
**/
fn HashMap* HashMap.new_init_from_map(&self, HashMap* other_map, Allocator allocator = allocator::heap())
{
self.new_init(other_map.table.len, other_map.load_factor, allocator);
self.put_all_for_create(other_map);
return self;
}
/**
* @param [&in] other_map "The map to copy from."
**/
fn Map new_from_map(Map other_map, Allocator allocator = null)
fn HashMap* HashMap.temp_init_from_map(&map, HashMap* other_map)
{
MapImpl* other_map_impl = (MapImpl*)other_map;
if (!other_map_impl)
{
if (allocator) return new(.allocator = allocator);
return null;
}
MapImpl* map = (MapImpl*)new(other_map_impl.table.len, other_map_impl.load_factor, allocator ?: allocator::heap());
if (!other_map_impl.count) return (Map)map;
foreach (Entry *e : other_map_impl.table)
{
if (!e) continue;
map._put_for_create(e.key, e.value);
}
return (Map)map;
return map.new_init_from_map(other_map, allocator::temp()) @inline;
}
/**
* @param [&in] other_map "The map to copy from."
**/
fn Map temp_from_map(Map other_map)
fn bool HashMap.is_empty(&map) @inline
{
return new_from_map(other_map, allocator::temp());
return !map.count;
}
fn bool Map.is_empty(map) @inline
fn usz HashMap.len(&map) @inline
{
return !map || !((MapImpl*)map).count;
return map.count;
}
fn usz Map.len(map) @inline
fn Value*! HashMap.get_ref(&map, Key key)
{
return map ? ((MapImpl*)map).count : 0;
}
fn Value*! Map.get_ref(self, Key key)
{
MapImpl *map = (MapImpl*)self;
if (!map || !map.count) return SearchResult.MISSING?;
if (!map.count) return SearchResult.MISSING?;
uint hash = rehash(key.hash());
for (Entry *e = map.table[index_for(hash, map.table.len)]; e != null; e = e.next)
{
@@ -96,12 +99,11 @@ fn Value*! Map.get_ref(self, Key key)
return SearchResult.MISSING?;
}
fn Entry*! Map.get_entry(map, Key key)
fn Entry*! HashMap.get_entry(&map, Key key)
{
MapImpl *map_impl = (MapImpl*)map;
if (!map_impl || !map_impl.count) return SearchResult.MISSING?;
if (!map.count) return SearchResult.MISSING?;
uint hash = rehash(key.hash());
for (Entry *e = map_impl.table[index_for(hash, map_impl.table.len)]; e != null; e = e.next)
for (Entry *e = map.table[index_for(hash, map.table.len)]; e != null; e = e.next)
{
if (e.hash == hash && equals(key, e.key)) return e;
}
@@ -112,10 +114,9 @@ fn Entry*! Map.get_entry(map, Key key)
* Get the value or update and
* @require $assignable(#expr, Value)
**/
macro Value Map.@get_or_set(&self, Key key, Value #expr)
macro Value HashMap.@get_or_set(&map, Key key, Value #expr)
{
MapImpl *map = (MapImpl*)*self;
if (!map || !map.count)
if (!map.count)
{
Value val = #expr;
map.set(key, val);
@@ -132,27 +133,23 @@ macro Value Map.@get_or_set(&self, Key key, Value #expr)
return val;
}
fn Value! Map.get(map, Key key) @operator([])
fn Value! HashMap.get(&map, Key key) @operator([])
{
return *map.get_ref(key) @inline;
}
fn bool Map.has_key(map, Key key)
fn bool HashMap.has_key(&map, Key key)
{
return @ok(map.get_ref(key));
}
macro Value Map.set_value_return(&map, Key key, Value value) @operator([]=)
{
map.set(key, value);
return value;
}
fn bool Map.set(&self, Key key, Value value)
fn bool HashMap.set(&map, Key key, Value value) @operator([]=)
{
// If the map isn't initialized, use the defaults to initialize it.
if (!*self) *self = new();
MapImpl* map = (MapImpl*)*self;
if (!map.allocator)
{
map.new_init();
}
uint hash = rehash(key.hash());
uint index = index_for(hash, map.table.len);
for (Entry *e = map.table[index]; e != null; e = e.next)
@@ -163,19 +160,18 @@ fn bool Map.set(&self, Key key, Value value)
return true;
}
}
map._add_entry(hash, key, value, index);
map.add_entry(hash, key, value, index);
return false;
}
fn void! Map.remove(map, Key key) @maydiscard
fn void! HashMap.remove(&map, Key key) @maydiscard
{
if (!map || !((MapImpl*)map)._remove_entry_for_key(key)) return SearchResult.MISSING?;
if (!map.remove_entry_for_key(key)) return SearchResult.MISSING?;
}
fn void Map.clear(self)
fn void HashMap.clear(&map)
{
MapImpl* map = (MapImpl*)self;
if (!map || !map.count) return;
if (!map.count) return;
foreach (Entry** &entry_ref : map.table)
{
Entry* entry = *entry_ref;
@@ -185,33 +181,30 @@ fn void Map.clear(self)
{
Entry *to_delete = next;
next = next.next;
map._free_entry(to_delete);
map.free_entry(to_delete);
}
map._free_entry(entry);
map.free_entry(entry);
*entry_ref = null;
}
map.count = 0;
}
fn void Map.free(self)
fn void HashMap.free(&map)
{
if (!self) return;
MapImpl* map = (MapImpl*)self;
self.clear();
map._free_internal(map.table.ptr);
if (!map.allocator) return;
map.clear();
map.free_internal(map.table.ptr);
map.table = {};
allocator::free(map.allocator, map);
}
fn Key[] Map.temp_keys_list(map)
fn Key[] HashMap.key_tlist(&map)
{
return map.new_keys_list(allocator::temp()) @inline;
return map.key_new_list(allocator::temp()) @inline;
}
fn Key[] Map.new_keys_list(self, Allocator allocator = allocator::heap())
fn Key[] HashMap.key_new_list(&map, Allocator allocator = allocator::heap())
{
MapImpl* map = (MapImpl*)self;
if (!map || !map.count) return {};
if (!map.count) return {};
Key[] list = allocator::alloc_array(allocator, Key, map.count);
usz index = 0;
@@ -226,36 +219,36 @@ fn Key[] Map.new_keys_list(self, Allocator allocator = allocator::heap())
return list;
}
macro Map.@each(map; @body(key, value))
macro HashMap.@each(map; @body(key, value))
{
map.@each_entry(; Entry* entry) {
@body(entry.key, entry.value);
};
}
macro Map.@each_entry(self; @body(entry))
macro HashMap.@each_entry(map; @body(entry))
{
MapImpl *map = (MapImpl*)self;
if (!map || !map.count) return;
foreach (Entry* entry : map.table)
if (map.count)
{
while (entry)
foreach (Entry* entry : map.table)
{
@body(entry);
entry = entry.next;
while (entry)
{
@body(entry);
entry = entry.next;
}
}
}
}
fn Value[] Map.temp_values_list(map)
fn Value[] HashMap.value_tlist(&map)
{
return map.new_values_list(allocator::temp()) @inline;
return map.value_new_list(allocator::temp()) @inline;
}
fn Value[] Map.new_values_list(self, Allocator allocator = allocator::heap())
fn Value[] HashMap.value_new_list(&map, Allocator allocator = allocator::heap())
{
MapImpl* map = (MapImpl*)self;
if (!map || !map.count) return {};
if (!map.count) return {};
Value[] list = allocator::alloc_array(allocator, Value, map.count);
usz index = 0;
foreach (Entry* entry : map.table)
@@ -269,10 +262,9 @@ fn Value[] Map.new_values_list(self, Allocator allocator = allocator::heap())
return list;
}
fn bool Map.has_value(self, Value v) @if(VALUE_IS_EQUATABLE)
fn bool HashMap.has_value(&map, Value v) @if(VALUE_IS_EQUATABLE)
{
MapImpl* map = (MapImpl*)self;
if (!map || !map.count) return false;
if (!map.count) return false;
foreach (Entry* entry : map.table)
{
while (entry)
@@ -286,7 +278,7 @@ fn bool Map.has_value(self, Value v) @if(VALUE_IS_EQUATABLE)
// --- private methods
fn void MapImpl._add_entry(&map, uint hash, Key key, Value value, uint bucket_index) @private
fn void HashMap.add_entry(&map, uint hash, Key key, Value value, uint bucket_index) @private
{
$if COPY_KEYS:
key = key.copy(map.allocator);
@@ -295,11 +287,11 @@ fn void MapImpl._add_entry(&map, uint hash, Key key, Value value, uint bucket_in
map.table[bucket_index] = entry;
if (map.count++ >= map.threshold)
{
map._resize(map.table.len * 2);
map.resize(map.table.len * 2);
}
}
fn void MapImpl._resize(&map, uint new_capacity) @private
fn void HashMap.resize(&map, uint new_capacity) @private
{
Entry*[] old_table = map.table;
uint old_capacity = old_table.len;
@@ -309,9 +301,9 @@ fn void MapImpl._resize(&map, uint new_capacity) @private
return;
}
Entry*[] new_table = allocator::new_array(map.allocator, Entry*, new_capacity);
map._transfer(new_table);
map.transfer(new_table);
map.table = new_table;
map._free_internal(old_table.ptr);
map.free_internal(old_table.ptr);
map.threshold = (uint)(new_capacity * map.load_factor);
}
@@ -326,7 +318,7 @@ macro uint index_for(uint hash, uint capacity) @private
return hash & (capacity - 1);
}
fn void MapImpl._transfer(&map, Entry*[] new_table) @private
fn void HashMap.transfer(&map, Entry*[] new_table) @private
{
Entry*[] src = map.table;
uint new_capacity = new_table.len;
@@ -345,18 +337,17 @@ fn void MapImpl._transfer(&map, Entry*[] new_table) @private
}
}
fn void _init(MapImpl* impl, uint capacity, float load_factor, Allocator allocator) @private
fn void HashMap.put_all_for_create(&map, HashMap* other_map) @private
{
capacity = math::next_power_of_2(capacity);
*impl = {
.allocator = allocator,
.load_factor = load_factor,
.threshold = (uint)(capacity * load_factor),
.table = allocator::new_array(allocator, Entry*, capacity)
};
if (!other_map.count) return;
foreach (Entry *e : other_map.table)
{
if (!e) continue;
map.put_for_create(e.key, e.value);
}
}
fn void MapImpl._put_for_create(&map, Key key, Value value) @private
fn void HashMap.put_for_create(&map, Key key, Value value) @private
{
uint hash = rehash(key.hash());
uint i = index_for(hash, map.table.len);
@@ -368,17 +359,16 @@ fn void MapImpl._put_for_create(&map, Key key, Value value) @private
return;
}
}
map._create_entry(hash, key, value, i);
map.create_entry(hash, key, value, i);
}
fn void MapImpl._free_internal(&map, void* ptr) @inline @private
fn void HashMap.free_internal(&map, void* ptr) @inline @private
{
allocator::free(map.allocator, ptr);
}
fn bool MapImpl._remove_entry_for_key(&map, Key key) @private
fn bool HashMap.remove_entry_for_key(&map, Key key) @private
{
if (!map.count) return false;
uint hash = rehash(key.hash());
uint i = index_for(hash, map.table.len);
Entry* prev = map.table[i];
@@ -397,7 +387,7 @@ fn bool MapImpl._remove_entry_for_key(&map, Key key) @private
{
prev.next = next;
}
map._free_entry(e);
map.free_entry(e);
return true;
}
prev = e;
@@ -406,7 +396,7 @@ fn bool MapImpl._remove_entry_for_key(&map, Key key) @private
return false;
}
fn void MapImpl._create_entry(&map, uint hash, Key key, Value value, int bucket_index) @private
fn void HashMap.create_entry(&map, uint hash, Key key, Value value, int bucket_index) @private
{
Entry *e = map.table[bucket_index];
$if COPY_KEYS:
@@ -417,12 +407,12 @@ fn void MapImpl._create_entry(&map, uint hash, Key key, Value value, int bucket_
map.count++;
}
fn void MapImpl._free_entry(&self, Entry *entry) @local
fn void HashMap.free_entry(&self, Entry *entry) @local
{
$if COPY_KEYS:
allocator::free(self.allocator, entry.key);
$endif
self._free_internal(entry);
self.free_internal(entry);
}
struct Entry
@@ -431,4 +421,4 @@ struct Entry
Key key;
Value value;
Entry* next;
}
}

View File

@@ -48,9 +48,9 @@ fn usz! Object.to_format(&self, Formatter* formatter) @dynamic
return n;
case ObjectInternalMap:
usz n = formatter.printf("{")!;
@stack_mem(1024; Allocator mem)
@pool()
{
foreach (i, key : self.map.key_new_list(mem))
foreach (i, key : self.map.key_tlist())
{
if (i > 0) n += formatter.printf(",")!;
n += formatter.printf(`"%s":`, key)!;
@@ -190,6 +190,7 @@ fn void Object.set_object(&self, String key, Object* new_object) @private
macro Object* Object.object_from_value(&self, value) @private
{
var $Type = $typeof(value);
$switch
$case types::is_int($Type):
return new_int(value, self.allocator);

View File

@@ -24,14 +24,12 @@ fn void DynamicArenaAllocator.init(&self, usz page_size, Allocator allocator)
self.backing_allocator = allocator;
}
import std::io;
fn void DynamicArenaAllocator.free(&self)
{
DynamicArenaPage* page = self.page;
while (page)
{
DynamicArenaPage* next_page = page.prev_arena;
allocator::free(self.backing_allocator, page.memory);
allocator::free(self.backing_allocator, page);
page = next_page;
}
@@ -39,7 +37,6 @@ fn void DynamicArenaAllocator.free(&self)
while (page)
{
DynamicArenaPage* next_page = page.prev_arena;
allocator::free(self.backing_allocator, page.memory);
allocator::free(self.backing_allocator, page);
page = next_page;
}
@@ -134,8 +131,8 @@ fn void DynamicArenaAllocator.reset(&self, usz mark = 0) @dynamic
fn void*! DynamicArenaAllocator._alloc_new(&self, usz size, usz alignment) @local
{
// First, make sure that we can align it, extending the page size if needed.
usz page_size = max(self.page_size, mem::aligned_offset(size + DynamicArenaChunk.sizeof + alignment, alignment));
assert(page_size > size + DynamicArenaChunk.sizeof);
usz page_size = max(self.page_size, mem::aligned_offset(size + DynamicArenaChunk.sizeof, alignment));
// Grab the page without alignment (we do it ourselves)
void* mem = allocator::malloc_try(self.backing_allocator, page_size)!;
DynamicArenaPage*! page = allocator::new_try(self.backing_allocator, DynamicArenaPage);

View File

@@ -79,7 +79,7 @@ fn void*! LibcAllocator.acquire(&self, usz bytes, AllocInitType init_type, usz a
{
if (alignment > 0)
{
return win32::_aligned_recalloc(null, 1, bytes, alignment) ?: AllocationFailure.OUT_OF_MEMORY?;
return win32::_aligned_recalloc(null, bytes, alignment) ?: AllocationFailure.OUT_OF_MEMORY?;
}
return libc::calloc(1, bytes) ?: AllocationFailure.OUT_OF_MEMORY?;
}

View File

@@ -45,13 +45,6 @@ fn TempAllocator*! new_temp_allocator(usz size, Allocator allocator)
return temp;
}
fn void TempAllocator.destroy(&self)
{
self.reset(0);
if (self.last_page) (void)self._free_page(self.last_page);
allocator::free(self.backing_allocator, self);
}
fn usz TempAllocator.mark(&self) @dynamic => self.used;
fn void TempAllocator.release(&self, void* old_pointer, bool) @dynamic
@@ -60,7 +53,6 @@ fn void TempAllocator.release(&self, void* old_pointer, bool) @dynamic
if (old_pointer + old_size == &self.data[self.used])
{
self.used -= old_size;
asan::poison_memory_region(&self.data[self.used], old_size);
}
}
fn void TempAllocator.reset(&self, usz mark) @dynamic
@@ -73,19 +65,6 @@ fn void TempAllocator.reset(&self, usz mark) @dynamic
self._free_page(to_free)!!;
}
self.last_page = last_page;
$if env::COMPILER_SAFE_MODE || env::ADDRESS_SANITIZER:
if (!last_page)
{
usz cleaned = self.used - mark;
if (cleaned > 0)
{
$if env::COMPILER_SAFE_MODE:
self.data[mark : cleaned] = 0xAA;
$endif
asan::poison_memory_region(&self.data[mark], cleaned);
}
}
$endif
self.used = mark;
}
@@ -151,10 +130,9 @@ fn void*! TempAllocator.acquire(&self, usz size, AllocInitType init_type, usz al
}
usz new_usage = (usz)(mem - start_mem) + size;
// Arena allocation, simple!
// Arena alignment, simple!
if (new_usage <= self.capacity)
{
asan::unpoison_memory_region(starting_ptr, new_usage - self.used);
TempAllocatorChunk* chunk_start = mem - TempAllocatorChunk.sizeof;
chunk_start.size = size;
self.used = new_usage;

View File

@@ -7,19 +7,26 @@ import libc, std::hash, std::io, std::os::backtrace;
/**
* Use `IteratorResult` when reading the end of an iterator, or accessing a result out of bounds.
**/
fault IteratorResult { NO_MORE_ELEMENT }
fault IteratorResult
{
NO_MORE_ELEMENT
}
/**
* Use `SearchResult` when trying to return a value from some collection but the element is missing.
**/
fault SearchResult { MISSING }
fault SearchResult
{
MISSING
}
/**
* Use `CastResult` when an attempt at conversion fails.
**/
fault CastResult { TYPE_MISMATCH }
def VoidFn = fn void();
fault CastResult
{
TYPE_MISMATCH
}
/**
* Stores a variable on the stack, then restores it at the end of the
@@ -136,9 +143,7 @@ fn void panicf(String fmt, String file, String function, uint line, args...)
**/
macro void unreachable(String string = "Unreachable statement reached.", ...) @builtin @noreturn
{
$if env::COMPILER_SAFE_MODE:
panicf(string, $$FILE, $$FUNC, $$LINE, $vasplat);
$endif;
panicf(string, $$FILE, $$FUNC, $$LINE, $vasplat());
$$unreachable();
}
@@ -148,18 +153,10 @@ macro void unreachable(String string = "Unreachable statement reached.", ...) @b
**/
macro void unsupported(String string = "Unsupported function invoked") @builtin @noreturn
{
panicf(string, $$FILE, $$FUNC, $$LINE, $vasplat);
panicf(string, $$FILE, $$FUNC, $$LINE, $vasplat());
$$unreachable();
}
/**
* Unconditionally break into an attached debugger when reached.
**/
macro void breakpoint() @builtin
{
$$breakpoint();
}
macro any_make(void* ptr, typeid type) @builtin
{
return $$any_make(ptr, type);
@@ -293,12 +290,12 @@ macro @prefetch(void* ptr, PrefetchLocality $locality = VERY_NEAR, bool $write =
macro swizzle(v, ...) @builtin
{
return $$swizzle(v, $vasplat);
return $$swizzle(v, $vasplat());
}
macro swizzle2(v, v2, ...) @builtin
{
return $$swizzle2(v, v2, $vasplat);
return $$swizzle2(v, v2, $vasplat());
}
macro anyfault @catch(#expr) @builtin
@@ -318,11 +315,6 @@ macro char[] @as_char_view(&value) @builtin
return ((char*)value)[:$sizeof(*value)];
}
macro isz @str_find(String $string, String $needle) @builtin => $$str_find($string, $needle);
macro String @str_upper(String $str) @builtin => $$str_upper($str);
macro String @str_lower(String $str) @builtin => $$str_lower($str);
macro uint @str_hash(String $str) @builtin => $$str_hash($str);
macro uint int.hash(int i) => i;
macro uint uint.hash(uint i) => i;
macro uint short.hash(short s) => s;
@@ -339,11 +331,6 @@ macro uint String.hash(String c) => (uint)fnv32a::encode(c);
macro uint char[].hash(char[] c) => (uint)fnv32a::encode(c);
macro uint void*.hash(void* ptr) => ((ulong)(uptr)ptr).hash();
distinct EmptySlot = void*;
const EmptySlot EMPTY_MACRO_SLOT @builtin = null;
macro @is_empty_macro_slot(#arg) @builtin => @typeis(#arg, EmptySlot);
macro @is_valid_macro_slot(#arg) @builtin => !@typeis(#arg, EmptySlot);
const MAX_FRAMEADDRESS = 128;
/**
* @require n >= 0
@@ -676,7 +663,7 @@ fn void install_signal_handler(CInt signal, SignalFunction func) @local
}
// Clean this up
fn void install_signal_handlers() @init(101) @local @if(env::BACKTRACE)
fn void install_signal_handlers() @init(101) @local
{
install_signal_handler(libc::SIGBUS, &sig_bus_error);
install_signal_handler(libc::SIGSEGV, &sig_segmentation_fault);

View File

@@ -4,7 +4,7 @@
module std::core::builtin;
/**
* @require types::@comparable_value(a) && types::@comparable_value(b)
* @require types::is_comparable_value(a) && types::is_comparable_value(b)
**/
macro less(a, b) @builtin
{
@@ -19,7 +19,7 @@ macro less(a, b) @builtin
}
/**
* @require types::@comparable_value(a) && types::@comparable_value(b)
* @require types::is_comparable_value(a) && types::is_comparable_value(b)
**/
macro less_eq(a, b) @builtin
{
@@ -34,7 +34,7 @@ macro less_eq(a, b) @builtin
}
/**
* @require types::@comparable_value(a) && types::@comparable_value(b)
* @require types::is_comparable_value(a) && types::is_comparable_value(b)
**/
macro greater(a, b) @builtin
{
@@ -49,7 +49,7 @@ macro greater(a, b) @builtin
}
/**
* @require types::@comparable_value(a) && types::@comparable_value(b)
* @require types::is_comparable_value(a) && types::is_comparable_value(b)
**/
macro int compare_to(a, b) @builtin
{
@@ -63,7 +63,7 @@ macro int compare_to(a, b) @builtin
$endswitch
}
/**
* @require types::@comparable_value(a) && types::@comparable_value(b)
* @require types::is_comparable_value(a) && types::is_comparable_value(b)
**/
macro greater_eq(a, b) @builtin
{
@@ -78,7 +78,7 @@ macro greater_eq(a, b) @builtin
}
/**
* @require types::@equatable_value(a) && types::@equatable_value(b) `values must be equatable`
* @require types::is_equatable_value(a) && types::is_equatable_value(b) `values must be equatable`
**/
macro bool equals(a, b) @builtin
{
@@ -97,13 +97,13 @@ macro bool equals(a, b) @builtin
macro min(x, ...) @builtin
{
$if $vacount == 1:
return less(x, $vaarg[0]) ? x : $vaarg[0];
return less(x, $vaarg(0)) ? x : $vaarg(0);
$else
var result = x;
$for (var $i = 0; $i < $vacount; $i++)
if (less($vaarg[$i], result))
if (less($vaarg($i), result))
{
result = $vaarg[$i];
result = $vaarg($i);
}
$endfor
return result;
@@ -113,13 +113,13 @@ macro min(x, ...) @builtin
macro max(x, ...) @builtin
{
$if $vacount == 1:
return greater(x, $vaarg[0]) ? x : $vaarg[0];
return greater(x, $vaarg(0)) ? x : $vaarg(0);
$else
var result = x;
$for (var $i = 0; $i < $vacount; $i++)
if (greater($vaarg[$i], result))
if (greater($vaarg($i), result))
{
result = $vaarg[$i];
result = $vaarg($i);
}
$endfor
return result;

View File

@@ -108,14 +108,14 @@ fn usz char32_to_utf8_unsafe(Char32 c, char** output)
{
switch
{
case c <= 0x7f:
case c < 0x7f:
(*output)++[0] = (char)c;
return 1;
case c <= 0x7ff:
case c < 0x7ff:
(*output)++[0] = (char)(0xC0 | c >> 6);
(*output)++[0] = (char)(0x80 | (c & 0x3F));
return 2;
case c <= 0xffff:
case c < 0xffff:
(*output)++[0] = (char)(0xE0 | c >> 12);
(*output)++[0] = (char)(0x80 | (c >> 6 & 0x3F));
(*output)++[0] = (char)(0x80 | (c & 0x3F));
@@ -210,11 +210,11 @@ fn usz utf8len_for_utf32(Char32[] utf32)
{
switch (true)
{
case uc <= 0x7f:
case uc < 0x7f:
len++;
case uc <= 0x7ff:
case uc < 0x7ff:
len += 2;
case uc <= 0xffff:
case uc < 0xffff:
len += 3;
default:
len += 4;
@@ -237,12 +237,12 @@ fn usz utf8len_for_utf16(Char16[] utf16)
Char16 c = utf16[i];
if (c & UTF16_SURROGATE_GENERIC_MASK != UTF16_SURROGATE_GENERIC_VALUE)
{
if (c <= 0x7f)
if (c < 0x7f)
{
len++;
continue;
}
if (c <= 0x7ff)
if (c < 0x7ff)
{
len += 2;
continue;

View File

@@ -48,56 +48,6 @@ fn DString new(String c = "", Allocator allocator = allocator::heap())
fn DString temp_new(String s = "") => new(s, allocator::temp()) @inline;
fn void DString.replace_char(self, char ch, char replacement)
{
StringData* data = self.data();
foreach (&c : data.chars[:data.len])
{
if (*c == ch) *c = replacement;
}
}
fn void DString.replace(&self, String needle, String replacement)
{
StringData* data = self.data();
usz needle_len = needle.len;
if (!data || data.len < needle_len) return;
usz replace_len = replacement.len;
if (needle_len == 1 && replace_len == 1)
{
self.replace_char(needle[0], replacement[0]);
return;
}
@pool(data.allocator) {
String str = self.tcopy_str();
self.clear();
usz len = str.len;
usz match = 0;
foreach (i, c : str)
{
if (c == needle[match])
{
match++;
if (match == needle_len)
{
self.append_chars(replacement);
match = 0;
continue;
}
continue;
}
if (match > 0)
{
self.append_chars(str[i - match:match]);
match = 0;
}
self.append_char(c);
}
if (match > 0) self.append_chars(str[^match:match]);
};
}
fn DString DString.new_concat(self, DString b, Allocator allocator = allocator::heap())
{
DString string;
@@ -421,26 +371,18 @@ fn void DString.insert_at(&self, usz index, String s)
fn usz! DString.appendf(&self, String format, args...) @maydiscard
{
if (!self.data()) self.new_init(format.len + 20);
@pool(self.data().allocator)
{
Formatter formatter;
formatter.init(&out_string_append_fn, self);
return formatter.vprintf(format, args);
};
Formatter formatter;
formatter.init(&out_string_append_fn, self);
return formatter.vprintf(format, args);
}
fn usz! DString.appendfn(&self, String format, args...) @maydiscard
{
if (!self.data()) self.new_init(format.len + 20);
@pool(self.data().allocator)
{
Formatter formatter;
formatter.init(&out_string_append_fn, self);
usz len = formatter.vprintf(format, args)!;
self.append('\n');
return len + 1;
};
Formatter formatter;
formatter.init(&out_string_append_fn, self);
usz len = formatter.vprintf(format, args)!;
self.append('\n');
return len + 1;
}
fn DString new_join(String[] s, String joiner, Allocator allocator = allocator::heap())

View File

@@ -112,13 +112,10 @@ enum ArchType
WASM64, // WebAssembly with 64-bit pointers
RSCRIPT32, // 32-bit RenderScript
RSCRIPT64, // 64-bit RenderScript
XTENSA, // Xtensa
}
const OsType OS_TYPE = (OsType)$$OS_TYPE;
const ArchType ARCH_TYPE = (ArchType)$$ARCH_TYPE;
const bool ARCH_32_BIT = $$REGISTER_SIZE == 32;
const bool ARCH_64_BIT = $$REGISTER_SIZE == 64;
const bool LIBC = $$COMPILER_LIBC_AVAILABLE;
const bool NO_LIBC = !$$COMPILER_LIBC_AVAILABLE;
const CompilerOptLevel COMPILER_OPT_LEVEL = (CompilerOptLevel)$$COMPILER_OPT_LEVEL;
@@ -129,7 +126,6 @@ const bool F128_SUPPORT = $$PLATFORM_F128_SUPPORTED;
const REGISTER_SIZE = $$REGISTER_SIZE;
const bool COMPILER_SAFE_MODE = $$COMPILER_SAFE_MODE;
const bool DEBUG_SYMBOLS = $$DEBUG_SYMBOLS;
const bool BACKTRACE = $$BACKTRACE;
const usz LLVM_VERSION = $$LLVM_VERSION;
const bool BENCHMARKING = $$BENCHMARKING;
const bool TESTING = $$TESTING;
@@ -148,12 +144,8 @@ const bool FREEBSD = LIBC && OS_TYPE == FREEBSD;
const bool NETBSD = LIBC && OS_TYPE == NETBSD;
const bool WASI = LIBC && OS_TYPE == WASI;
const bool WASM_NOLIBC @builtin = !LIBC && ARCH_TYPE == ArchType.WASM32 || ARCH_TYPE == ArchType.WASM64;
const bool ADDRESS_SANITIZER = $$ADDRESS_SANITIZER;
const bool MEMORY_SANITIZER = $$MEMORY_SANITIZER;
const bool THREAD_SANITIZER = $$THREAD_SANITIZER;
const bool ANY_SANITIZER = ADDRESS_SANITIZER || MEMORY_SANITIZER || THREAD_SANITIZER;
macro bool os_is_darwin() @const
macro bool os_is_darwin()
{
$switch (OS_TYPE)
$case IOS:
@@ -166,7 +158,7 @@ macro bool os_is_darwin() @const
$endswitch
}
macro bool os_is_posix() @const
macro bool os_is_posix()
{
$switch (OS_TYPE)
$case IOS:

View File

@@ -8,10 +8,6 @@ import std::math;
const MAX_MEMORY_ALIGNMENT = 0x1000_0000;
const DEFAULT_MEM_ALIGNMENT = (void*.alignof) * 2;
macro bool @constant_is_power_of_2($x) @const @private
{
return $x != 0 && ($x & ($x - 1)) == 0;
}
/**
* Load a vector from memory according to a mask assuming default alignment.
@@ -41,7 +37,7 @@ macro masked_load(ptr, bool[<*>] mask, passthru)
* @require $assignable(&&passthru, $typeof(ptr)) : "Pointer and passthru must match"
* @require @typekind(passthru) == VECTOR : "Expected passthru to be a vector"
* @require passthru.len == mask.len : "Mask and passthru must have the same length"
* @require @constant_is_power_of_2($alignment) : "The alignment must be a power of two"
* @require math::is_power_of_2($alignment) : "The alignment must be a power of two"
*
* @return "A vector with the loaded values where the mask is true, passthru where the mask is false"
**/
@@ -84,7 +80,7 @@ macro gather(ptrvec, bool[<*>] mask, passthru)
* @require $assignable(&&passthru[0], $typeof(ptrvec[0])) : "Pointer and passthru must match"
* @require passthru.len == mask.len : "Mask and passthru must have the same length"
* @require mask.len == ptrvec.len : "Mask and ptrvec must have the same length"
* @require @constant_is_power_of_2($alignment) : "The alignment must be a power of two"
* @require math::is_power_of_2($alignment) : "The alignment must be a power of two"
*
* @return "A vector with the loaded values where the mask is true, passthru where the mask is false"
**/
@@ -119,7 +115,7 @@ macro masked_store(ptr, value, bool[<*>] mask)
* @require $assignable(&&value, $typeof(ptr)) : "Pointer and value must match"
* @require @typekind(value) == VECTOR : "Expected value to be a vector"
* @require value.len == mask.len : "Mask and value must have the same length"
* @require @constant_is_power_of_2($alignment) : "The alignment must be a power of two"
* @require math::is_power_of_2($alignment) : "The alignment must be a power of two"
*
**/
macro @masked_store_aligned(ptr, value, bool[<*>] mask, usz $alignment)
@@ -154,39 +150,13 @@ macro scatter(ptrvec, value, bool[<*>] mask)
* @require $assignable(&&value[0], $typeof(ptrvec[0])) : "Pointer and value must match"
* @require value.len == mask.len : "Mask and value must have the same length"
* @require mask.len == ptrvec.len : "Mask and ptrvec must have the same length"
* @require @constant_is_power_of_2($alignment) : "The alignment must be a power of two"
* @require math::is_power_of_2($alignment) : "The alignment must be a power of two"
**/
macro @scatter_aligned(ptrvec, value, bool[<*>] mask, usz $alignment)
{
return $$scatter(ptrvec, value, mask, $alignment);
}
/**
* @param [in] x "The variable or dereferenced pointer to load."
* @param $alignment "The alignment to assume for the load"
* @return "The value of x"
*
* @require @constant_is_power_of_2($alignment) : "The alignment must be a power of two"
**/
macro @unaligned_load(&x, usz $alignment) @builtin
{
return $$unaligned_load(x, $alignment);
}
/**
* @param [out] x "The variable or dereferenced pointer to store to."
* @param value "The value to store."
* @param $alignment "The alignment to assume for the store"
* @return "The value of x"
*
* @require $assignable(value, $typeof(*x)) : "The value doesn't match the variable"
* @require @constant_is_power_of_2($alignment) : "The alignment must be a power of two"
**/
macro @unaligned_store(&x, value, usz $alignment) @builtin
{
return $$unaligned_store(x, ($typeof(*x))value, $alignment);
}
macro @volatile_load(&x) @builtin
{
return $$volatile_load(x);
@@ -528,11 +498,14 @@ macro void @pool(TempAllocator* #other_temp = null; @body) @builtin
@body();
}
import libc;
module std::core::mem @if(WASM_NOLIBC);
import std::core::mem::allocator @public;
SimpleHeapAllocator wasm_allocator @private;
extern int __heap_base;
@@ -543,8 +516,8 @@ fn void initialize_wasm_mem() @init(1) @private
uptr start = (uptr)&__heap_base;
if (start > mem::DEFAULT_MEM_ALIGNMENT) allocator::wasm_memory.use = start;
wasm_allocator.init(fn (x) => allocator::wasm_memory.allocate_block(x));
temp_base_allocator = &wasm_allocator;
allocator::thread_allocator = &wasm_allocator;
allocator::init_default_temp_allocators();
}
module std::core::mem;
@@ -574,15 +547,6 @@ fn void* malloc(usz size) @builtin @inline @nodiscard
return allocator::malloc(allocator::heap(), size);
}
/**
* Allocate using an aligned allocation. This is necessary for types with a default memory alignment
* exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned.
**/
fn void* malloc_aligned(usz size, usz alignment) @builtin @inline @nodiscard
{
return allocator::malloc_aligned(allocator::heap(), size, alignment)!!;
}
fn void* tmalloc(usz size, usz alignment = 0) @builtin @inline @nodiscard
{
if (!size) return null;
@@ -591,7 +555,7 @@ fn void* tmalloc(usz size, usz alignment = 0) @builtin @inline @nodiscard
/**
* @require $vacount < 2 : "Too many arguments."
* @require $vacount == 0 ||| $assignable($vaexpr[0], $Type) : "The second argument must be an initializer for the type"
* @require $or($vacount == 0, $assignable($vaexpr(0), $Type)) : "The second argument must be an initializer for the type"
* @require $Type.alignof <= DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'alloc_aligned' instead"
**/
macro new($Type, ...) @nodiscard
@@ -600,7 +564,7 @@ macro new($Type, ...) @nodiscard
return ($Type*)calloc($Type.sizeof);
$else
$Type* val = malloc($Type.sizeof);
*val = $vaexpr[0];
*val = $vaexpr(0);
return val;
$endif
}
@@ -609,7 +573,7 @@ macro new($Type, ...) @nodiscard
* Allocate using an aligned allocation. This is necessary for types with a default memory alignment
* exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned.
* @require $vacount < 2 : "Too many arguments."
* @require $vacount == 0 ||| $assignable($vaexpr[0], $Type) : "The second argument must be an initializer for the type"
* @require $or($vacount == 0, $assignable($vaexpr(0), $Type)) : "The second argument must be an initializer for the type"
**/
macro new_aligned($Type, ...) @nodiscard
{
@@ -617,7 +581,7 @@ macro new_aligned($Type, ...) @nodiscard
return ($Type*)calloc_aligned($Type.sizeof, $Type.alignof);
$else
$Type* val = malloc_aligned($Type.sizeof, $Type.alignof);
*val = $vaexpr[0];
*val = $vaexpr(0);
return val;
$endif
}
@@ -641,7 +605,7 @@ macro alloc_aligned($Type) @nodiscard
/**
* @require $vacount < 2 : "Too many arguments."
* @require $vacount == 0 ||| $assignable($vaexpr[0], $Type) : "The second argument must be an initializer for the type"
* @require $or($vacount == 0, $assignable($vaexpr(0), $Type)) : "The second argument must be an initializer for the type"
**/
macro temp_new($Type, ...) @nodiscard
{
@@ -649,7 +613,7 @@ macro temp_new($Type, ...) @nodiscard
return ($Type*)tcalloc($Type.sizeof) @inline;
$else
$Type* val = tmalloc($Type.sizeof) @inline;
*val = $vaexpr[0];
*val = $vaexpr(0);
return val;
$endif
}
@@ -691,7 +655,7 @@ macro alloc_array($Type, usz elements) @nodiscard
**/
macro alloc_array_aligned($Type, usz elements) @nodiscard
{
return allocator::alloc_array_aligned(allocator::heap(), $Type, elements);
return allocator::alloc_array(allocator::heap(), $Type, elements);
}
macro temp_alloc_array($Type, usz elements) @nodiscard
@@ -709,10 +673,6 @@ fn void* calloc(usz size) @builtin @inline @nodiscard
return allocator::calloc(allocator::heap(), size);
}
/**
* Allocate using an aligned allocation. This is necessary for types with a default memory alignment
* exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned.
**/
fn void* calloc_aligned(usz size, usz alignment) @builtin @inline @nodiscard
{
return allocator::calloc_aligned(allocator::heap(), size, alignment)!!;

View File

@@ -49,7 +49,7 @@ fault AllocationFailure
fn usz alignment_for_allocation(usz alignment) @inline @private
{
return alignment < mem::DEFAULT_MEM_ALIGNMENT ? mem::DEFAULT_MEM_ALIGNMENT : alignment;
return alignment < mem::DEFAULT_MEM_ALIGNMENT ? alignment = mem::DEFAULT_MEM_ALIGNMENT : alignment;
}
macro void* malloc(Allocator allocator, usz size) @nodiscard
@@ -147,9 +147,8 @@ macro void free_aligned(Allocator allocator, void* ptr)
}
/**
* @require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'new_aligned' instead"
* @require $vacount < 2 : "Too many arguments."
* @require $vacount == 0 ||| $assignable($vaexpr[0], $Type) : "The second argument must be an initializer for the type"
* @require $or($vacount == 0, $assignable($vaexpr(0), $Type)) : "The second argument must be an initializer for the type"
**/
macro new(Allocator allocator, $Type, ...) @nodiscard
{
@@ -157,15 +156,14 @@ macro new(Allocator allocator, $Type, ...) @nodiscard
return ($Type*)calloc(allocator, $Type.sizeof);
$else
$Type* val = malloc(allocator, $Type.sizeof);
*val = $vaexpr[0];
*val = $vaexpr(0);
return val;
$endif
}
/**
* @require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'new_aligned' instead"
* @require $vacount < 2 : "Too many arguments."
* @require $vacount == 0 ||| $assignable($vaexpr[0], $Type) : "The second argument must be an initializer for the type"
* @require $or($vacount == 0, $assignable($vaexpr(0), $Type)) : "The second argument must be an initializer for the type"
**/
macro new_try(Allocator allocator, $Type, ...) @nodiscard
{
@@ -173,114 +171,56 @@ macro new_try(Allocator allocator, $Type, ...) @nodiscard
return ($Type*)calloc_try(allocator, $Type.sizeof);
$else
$Type* val = malloc_try(allocator, $Type.sizeof)!;
*val = $vaexpr[0];
*val = $vaexpr(0);
return val;
$endif
}
/**
* Allocate using an aligned allocation. This is necessary for types with a default memory alignment
* exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned.
* @require $vacount < 2 : "Too many arguments."
* @require $vacount == 0 ||| $assignable($vaexpr[0], $Type) : "The second argument must be an initializer for the type"
**/
macro new_aligned($Type, ...) @nodiscard
{
$if $vacount == 0:
return ($Type*)calloc_aligned(allocator, $Type.sizeof, $Type.alignof);
$else
$Type* val = malloc_aligned(allocator, $Type.sizeof, $Type.alignof);
*val = $vaexpr[0];
return val;
$endif
}
/**
* @require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT
**/
macro new_with_padding(Allocator allocator, $Type, usz padding) @nodiscard
{
return ($Type*)calloc_try(allocator, $Type.sizeof + padding);
}
/**
* @require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'alloc_aligned' instead"
**/
macro alloc(Allocator allocator, $Type) @nodiscard
{
return ($Type*)malloc(allocator, $Type.sizeof);
}
/**
* @require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'alloc_aligned' instead"
**/
macro alloc_try(Allocator allocator, $Type) @nodiscard
{
return ($Type*)malloc_try(allocator, $Type.sizeof);
}
/**
* Allocate using an aligned allocation. This is necessary for types with a default memory alignment
* exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned.
**/
macro alloc_aligned(Allocator allocator, $Type) @nodiscard
{
return ($Type*)malloc_aligned(allocator, $Type.sizeof, $Type.alignof);
}
/**
* @require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT
**/
macro alloc_with_padding(Allocator allocator, $Type, usz padding) @nodiscard
{
return ($Type*)malloc_try(allocator, $Type.sizeof + padding);
}
/**
* @require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'new_array_aligned' instead"
**/
macro new_array(Allocator allocator, $Type, usz elements) @nodiscard
{
return new_array_try(allocator, $Type, elements)!!;
}
/**
* @require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'new_array_aligned' instead"
**/
macro new_array_try(Allocator allocator, $Type, usz elements) @nodiscard
{
return (($Type*)calloc_try(allocator, $Type.sizeof * elements))[:elements];
}
/**
* Allocate using an aligned allocation. This is necessary for types with a default memory alignment
* exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned.
**/
macro new_array_aligned(Allocator allocator, $Type, usz elements) @nodiscard
{
return (($Type*)calloc_aligned(allocator, $Type.sizeof * elements, $Type.alignof))[:elements]!!;
return ((Type*)calloc_aligned(allocator, $Type.sizeof * elements, $Type.alignof))[:elements]!!;
}
/**
* @require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'alloc_array_aligned' instead"
**/
macro alloc_array(Allocator allocator, $Type, usz elements) @nodiscard
{
return alloc_array_try(allocator, $Type, elements)!!;
}
/**
* Allocate using an aligned allocation. This is necessary for types with a default memory alignment
* exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned.
**/
macro alloc_array_aligned(Allocator allocator, $Type, usz elements) @nodiscard
{
return (($Type*)malloc_aligned(allocator, $Type.sizeof * elements, $Type.alignof))[:elements]!!;
return ((Type*)malloc_aligned(allocator, $Type.sizeof * elements, $Type.alignof))[:elements]!!;
}
/**
* @require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'alloc_array_aligned' instead"
**/
macro alloc_array_try(Allocator allocator, $Type, usz elements) @nodiscard
{
return (($Type*)malloc_try(allocator, $Type.sizeof * elements))[:elements];
@@ -395,23 +335,6 @@ fn void init_default_temp_allocators() @private
thread_temp_allocator = temp_allocator_pair[0];
}
fn void destroy_temp_allocators_after_exit() @finalizer(65535) @local @if(env::LIBC)
{
destroy_temp_allocators();
}
/**
* Call this to destroy any memory used by the temp allocators. This will invalidate all temp memory.
**/
fn void destroy_temp_allocators()
{
if (!thread_temp_allocator) return;
temp_allocator_pair[0].destroy();
temp_allocator_pair[1].destroy();
temp_allocator_pair[..] = null;
thread_temp_allocator = null;
}
fn TempAllocator* temp_allocator_next() @private
{
if (!thread_temp_allocator)
@@ -421,4 +344,4 @@ fn TempAllocator* temp_allocator_next() @private
}
usz index = thread_temp_allocator == temp_allocator_pair[0] ? 1 : 0;
return thread_temp_allocator = temp_allocator_pair[index];
}
}

View File

@@ -175,7 +175,7 @@ fn void runtime_startup() @public @export("__c3_runtime_startup")
}
assert(runtime_state == RUN_CTORS);
runtime_state = READ_DYLIB;
ctor_first = null;
ctor = null;
}
fn void runtime_finalize() @public @export("__c3_runtime_finalize")

View File

@@ -84,19 +84,19 @@ macro void release_wargs(String[] list) @private
free(list.ptr);
}
macro int @win_to_err_main_noargs(#m, void* handle, void* prev_handle, Char16* cmd_line, int show_cmd)
macro int @win_to_err_main_noargs(#m, void* handle, Char16* cmd_line, int show_cmd)
{
if (catch #m()) return 1;
return 0;
}
macro int @win_to_int_main_noargs(#m, void* handle, void* prev_handle, Char16* cmd_line, int show_cmd) => #m();
macro int @win_to_void_main_noargs(#m, void* handle, void* prev_handle, Char16* cmd_line, int show_cmd)
macro int @win_to_int_main_noargs(#m, void* handle, Char16* cmd_line, int show_cmd) => #m();
macro int @win_to_void_main_noargs(#m, void* handle, Char16* cmd_line, int show_cmd)
{
#m();
return 0;
}
macro int @win_to_err_main_args(#m, void* handle, void* prev_handle, Char16* cmd_line, int show_cmd)
macro int @win_to_err_main_args(#m, void* handle, Char16* cmd_line, int show_cmd)
{
String[] args = win_command_line_to_strings(cmd_line);
defer release_wargs(args);
@@ -104,14 +104,14 @@ macro int @win_to_err_main_args(#m, void* handle, void* prev_handle, Char16* cmd
return 0;
}
macro int @win_to_int_main_args(#m, void* handle, void* prev_handle, Char16* cmd_line, int show_cmd)
macro int @win_to_int_main_args(#m, void* handle, Char16* cmd_line, int show_cmd)
{
String[] args = win_command_line_to_strings(cmd_line);
defer release_wargs(args);
return #m(args);
}
macro int @win_to_void_main_args(#m, void* handle, void* prev_handle, Char16* cmd_line, int show_cmd)
macro int @win_to_void_main_args(#m, void* handle, Char16* cmd_line, int show_cmd)
{
String[] args = win_command_line_to_strings(cmd_line);
defer release_wargs(args);
@@ -119,26 +119,26 @@ macro int @win_to_void_main_args(#m, void* handle, void* prev_handle, Char16* cm
return 0;
}
macro int @win_to_err_main(#m, void* handle, void* prev_handle, Char16* cmd_line, int show_cmd)
macro int @win_to_err_main(#m, void* handle, Char16* cmd_line, int show_cmd)
{
String[] args = win_command_line_to_strings(cmd_line);
defer release_wargs(args);
if (catch #m(handle, prev_handle, args, show_cmd)) return 1;
if (catch #m(handle, args, show_cmd)) return 1;
return 0;
}
macro int @win_to_int_main(#m, void* handle, void* prev_handle, Char16* cmd_line, int show_cmd)
macro int @win_to_int_main(#m, void* handle, Char16* cmd_line, int show_cmd)
{
String[] args = win_command_line_to_strings(cmd_line);
defer release_wargs(args);
return #m(handle, prev_handle, args, show_cmd);
return #m(handle, args, show_cmd);
}
macro int @win_to_void_main(#m, void* handle, void* prev_handle, Char16* cmd_line, int show_cmd)
macro int @win_to_void_main(#m, void* handle, Char16* cmd_line, int show_cmd)
{
String[] args = win_command_line_to_strings(cmd_line);
defer release_wargs(args);
#m(handle, prev_handle, args, show_cmd);
#m(handle, args, show_cmd);
return 0;
}

View File

@@ -1,127 +0,0 @@
// Add this to your code to suppress leak detection or set other default options
// fn ZString __asan_default_options() @export("__asan_default_options") @if(env::ADDRESS_SANITIZER)
// {
// return "detect_leaks=0";
// }
// Add this to break on error
// asan::set_error_report_callback(fn (ZString err)
// {
// breakpoint();
// });
module std::core::sanitizer::asan;
def ErrorCallback = fn void (ZString);
/**
* Marks a memory region ([addr, addr+size)) as unaddressable.
*
* This memory must be previously allocated by your program. Instrumented
* code is forbidden from accessing addresses in this region until it is
* unpoisoned. This function is not guaranteed to poison the entire region -
* it could poison only a subregion of [addr, addr+size) due to ASan
* alignment restrictions.
*
* NOTE This function is not thread-safe because no two threads can poison or
* unpoison memory in the same memory region simultaneously.
*
* @param addr "Start of memory region."
* @param size "Size of memory region."
**/
macro poison_memory_region(void* addr, usz size)
{
$if env::ADDRESS_SANITIZER:
__asan_poison_memory_region(addr, size);
$endif
}
/**
* Marks a memory region ([addr, addr+size)) as addressable.
*
* This memory must be previously allocated by your program. Accessing
* addresses in this region is allowed until this region is poisoned again.
* This function could unpoison a super-region of [addr, addr+size) due
* to ASan alignment restrictions.
*
* NOTE This function is not thread-safe because no two threads can
* poison or unpoison memory in the same memory region simultaneously.
*
* @param addr "Start of memory region."
* @param size "Size of memory region."
**/
macro unpoison_memory_region(void* addr, usz size)
{
$if env::ADDRESS_SANITIZER:
__asan_unpoison_memory_region(addr, size);
$endif
}
/**
* Checks if an address is poisoned.
* @return "True if 'addr' is poisoned (that is, 1-byte read/write access to this address would result in an error report from ASan). Otherwise returns false."
* @param addr "Address to check."
**/
macro bool address_is_poisoned(void* addr)
{
$if env::ADDRESS_SANITIZER:
return (bool)__asan_address_is_poisoned(addr);
$else
return false;
$endif
}
/**
* Checks if a region is poisoned.
*
* If at least one byte in [beg, beg+size) is poisoned, returns the
* address of the first such byte. Otherwise returns 0.
*
* @param beg "Start of memory region."
* @param size "Start of memory region."
* @return "Address of first poisoned byte."
**/
macro void* region_is_poisoned(void* beg, usz size)
{
$if env::ADDRESS_SANITIZER:
return __asan_region_is_poisoned(addr);
$else
return null;
$endif
}
/**
* Sets the callback function to be called during ASan error reporting.
**/
fn void set_error_report_callback(ErrorCallback callback)
{
$if env::ADDRESS_SANITIZER:
__asan_set_error_report_callback(callback);
$endif
}
module std::core::sanitizer::asan @if(env::ADDRESS_SANITIZER);
extern fn void __asan_poison_memory_region(void* addr, usz size);
extern fn void __asan_unpoison_memory_region(void* addr, usz size);
extern fn CInt __asan_address_is_poisoned(void* addr);
extern fn void* __asan_region_is_poisoned(void* beg, usz size);
extern fn void __asan_describe_address(void* addr);
extern fn CInt __asan_report_present();
extern fn void* __asan_get_report_pc();
extern fn void* __asan_get_report_bp();
extern fn void* __asan_get_report_sp();
extern fn void* __asan_get_report_address();
extern fn CInt __asan_get_report_access_type();
extern fn usz __asan_get_report_access_size();
extern fn ZString __asan_get_report_description();
extern fn ZString __asan_locate_address(void* addr, char* name, usz name_size, void** region_address, usz* region_size);
extern fn usz __asan_get_alloc_stack(void* addr, void** trace, usz size, CInt* thread_id);
extern fn usz __asan_get_free_stack(void* addr, void** trace, usz size, CInt* thread_id);
extern fn void __asan_get_shadow_mapping(usz* shadow_scale, usz* shadow_offset);
extern fn void __asan_set_error_report_callback(ErrorCallback callback);
extern fn void __asan_print_accumulated_stats();
extern fn void* __asan_get_current_fake_stack();
extern fn void* __asan_addr_is_in_fake_stack(void* fake_stack, void* addr, void** beg, void** end);
extern fn void __asan_handle_no_return();
extern fn CInt __asan_update_allocation_context(void* addr);

View File

@@ -1,80 +0,0 @@
module std::core::sanitizer;
macro void annotate_contiguous_container(void* beg, void* end, void* old_mid, void* new_mid)
{
$if env::ADDRESS_SANITIZER:
__sanitizer_annotate_contiguous_container(beg, end, old_mid, new_mid);
$endif
}
macro void annotate_double_ended_contiguous_container(void* storage_beg, void* storage_end, void* old_container_beg, void* old_container_end, void* new_container_beg, void* new_container_end)
{
$if env::ADDRESS_SANITIZER:
__sanitizer_annotate_double_ended_contiguous_container(storage_beg, storage_end, old_container_beg, old_container_end, new_container_beg, new_container_end);
$endif
}
macro void print_stack_trace()
{
$if env::ADDRESS_SANITIZER:
__sanitizer_print_stack_trace();
$endif
}
fn void set_death_callback(VoidFn callback)
{
$if env::ANY_SANITIZER:
__sanitizer_set_death_callback(callback);
$endif
}
module std::core::sanitizer @if (env::ANY_SANITIZER);
struct __Sanitizer_sandbox_arguments
{
CInt coverage_sandboxed;
iptr coverage_fd;
CUInt coverage_max_block_size;
}
extern fn void __sanitizer_set_report_path(ZString path);
extern fn void __sanitizer_set_report_fd(void* fd);
extern fn ZString __sanitizer_get_report_path();
extern fn void __sanitizer_sandbox_on_notify(__Sanitizer_sandbox_arguments* args);
extern fn void __sanitizer_report_error_summary(ZString error_summary);
extern fn ushort __sanitizer_unaligned_load16(void* p);
extern fn uint __sanitizer_unaligned_load32(void* p);
extern fn ulong __sanitizer_unaligned_load64(void* p);
extern fn void __sanitizer_unaligned_store16(void* p, ushort x);
extern fn void __sanitizer_unaligned_store32(void* p, uint x);
extern fn void __sanitizer_unaligned_store64(void* p, ulong x);
extern fn CInt __sanitizer_acquire_crash_state();
extern fn void __sanitizer_annotate_contiguous_container(void* beg, void* end, void* old_mid, void* new_mid);
extern fn void __sanitizer_annotate_double_ended_contiguous_container(void* storage_beg, void* storage_end,
void* old_container_beg, void* old_container_end,
void* new_container_beg, void* new_container_end);
extern fn CInt __sanitizer_verify_contiguous_container(void* beg, void* mid, void* end);
extern fn CInt __sanitizer_verify_double_ended_contiguous_container(
void* storage_beg, void* container_beg,
void* container_end, void* storage_end);
extern fn void* __sanitizer_contiguous_container_find_bad_address(void* beg, void* mid, void* end);
extern fn void* __sanitizer_double_ended_contiguous_container_find_bad_address(
void* storage_beg, void* container_beg,
void* container_end, void* storage_end);
extern fn void __sanitizer_print_stack_trace();
extern fn void __sanitizer_symbolize_pc(void* pc, ZString fmt, char* out_buf, usz out_buf_size);
extern fn void __sanitizer_symbolize_global(void* data_ptr, ZString fmt, char* out_buf, usz out_buf_size);
extern fn void __sanitizer_set_death_callback(VoidFn callback);
extern fn void __sanitizer_weak_hook_memcmp(void* called_pc, void* s1, void* s2, usz n, CInt result);
extern fn void __sanitizer_weak_hook_strncmp(void* called_pc, ZString s1, ZString s2, usz n, CInt result);
extern fn void __sanitizer_weak_hook_strncasecmp(void* called_pc, ZString s1, ZString s2, usz n, CInt result);
extern fn void __sanitizer_weak_hook_strcmp(void* called_pc, ZString s1, ZString s2, CInt result);
extern fn void __sanitizer_weak_hook_strcasecmp(void* called_pc, ZString s1, ZString s2, CInt result);
extern fn void __sanitizer_weak_hook_strstr(void* called_pc, ZString s1, ZString s2, char* result);
extern fn void __sanitizer_weak_hook_strcasestr(void* called_pc, ZString s1, ZString s2, char* result);
extern fn void __sanitizer_weak_hook_memmem(void* called_pc, void* s1, usz len1, void* s2, usz len2, void* result);
extern fn void __sanitizer_print_memory_profile(usz top_percent, usz max_number_of_contexts);
extern fn void __sanitizer_start_switch_fiber(void** fake_stack_save, void* bottom, usz size);
extern fn void __sanitizer_finish_switch_fiber(void* fake_stack_save, void** bottom_old, usz* size_old);
extern fn CInt __sanitizer_get_module_and_offset_for_pc(void* pc, char* module_path, usz module_path_len, void** pc_offset);

View File

@@ -1,39 +0,0 @@
module std::core::sanitizer::tsan;
distinct MutexFlags = inline CUInt;
const MutexFlags MUTEX_LINKER_INIT = 1 << 0;
const MutexFlags MUTEX_WRITE_REENTRANT = 1 << 1;
const MutexFlags MUTEX_READ_REENTRANT = 1 << 2;
const MutexFlags MUTEX_NOT_STATIC = 1 << 8;
const MutexFlags MUTEX_READ_LOCK = 1 << 3;
const MutexFlags MUTEX_TRY_LOCK = 1 << 4;
const MutexFlags MUTEX_TRY_LOCK_FAILED = 1 << 5;
const MutexFlags MUTEX_RECURSIVE_LOCK = 1 << 6;
const MutexFlags MUTEX_RECURSIVE_UNLOCK = 1 << 7;
const MutexFlags MUTEX_TRY_READ_LOCK = MUTEX_READ_LOCK | MUTEX_TRY_LOCK;
const MutexFlags MUTEX_TRY_READ_LOCK_FAILED = MUTEX_TRY_READ_LOCK | MUTEX_TRY_LOCK_FAILED;
macro void mutex_create(void* addr, MutexFlags flags) { $if env::THREAD_SANITIZER: __tsan_mutex_create(addr, flags); $endif }
macro void mutex_destroy(void* addr, MutexFlags flags) { $if env::THREAD_SANITIZER: __tsan_mutex_destroy(addr, flags); $endif }
macro void mutex_pre_lock(void* addr, MutexFlags flags) { $if env::THREAD_SANITIZER: __tsan_mutex_pre_lock(addr, flags); $endif }
macro void mutex_post_lock(void* addr, MutexFlags flags, CInt recursion) { $if env::THREAD_SANITIZER: __tsan_mutex_post_lock(addr, flags, recursion); $endif }
macro CInt mutex_pre_unlock(void* addr, MutexFlags flags) { $if env::THREAD_SANITIZER: return __tsan_mutex_pre_unlock(addr, flags); $else return 0; $endif }
macro void mutex_post_unlock(void* addr, MutexFlags flags) { $if env::THREAD_SANITIZER: __tsan_mutex_post_unlock(addr, flags); $endif }
macro void mutex_pre_signal(void* addr, MutexFlags flags) { $if env::THREAD_SANITIZER: __tsan_mutex_pre_signal(addr, flags); $endif }
macro void mutex_post_signal(void* addr, MutexFlags flags) { $if env::THREAD_SANITIZER: __tsan_mutex_post_signal(addr, flags); $endif }
macro void mutex_pre_divert(void* addr, MutexFlags flags) { $if env::THREAD_SANITIZER: __tsan_mutex_pre_divert(addr, flags); $endif }
macro void mutex_post_divert(void* addr, MutexFlags flags) { $if env::THREAD_SANITIZER: __tsan_mutex_post_divert(addr, flags); $endif }
module std::core::sanitizer::tsan @if(env::THREAD_SANITIZER) @private;
extern fn void __tsan_mutex_create(void* addr, CUInt flags);
extern fn void __tsan_mutex_destroy(void* addr, CUInt flags);
extern fn void __tsan_mutex_pre_lock(void* addr, CUInt flags);
extern fn void __tsan_mutex_post_lock(void* addr, CUInt flags, CInt recursion);
extern fn CInt __tsan_mutex_pre_unlock(void* addr, CUInt flags);
extern fn void __tsan_mutex_post_unlock(void* addr, CUInt flags);
extern fn void __tsan_mutex_pre_signal(void* addr, CUInt flags);
extern fn void __tsan_mutex_post_signal(void* addr, CUInt flags);
extern fn void __tsan_mutex_pre_divert(void* addr, CUInt flags);
extern fn void __tsan_mutex_post_divert(void* addr, CUInt flags);

View File

@@ -1,7 +1,6 @@
module std::core::string;
import std::ascii;
distinct String @if(!$defined(String)) = inline char[];
distinct ZString = inline char*;
distinct WString = inline Char16*;
def Char32 = uint;
@@ -40,7 +39,7 @@ fault NumberConversion
macro String tformat(String fmt, ...)
{
DString str = dstring::temp_with_capacity(fmt.len + $vacount * 8);
str.appendf(fmt, $vasplat);
str.appendf(fmt, $vasplat());
return str.str_view();
}
@@ -52,7 +51,7 @@ macro String tformat(String fmt, ...)
macro ZString tformat_zstr(String fmt, ...)
{
DString str = dstring::temp_with_capacity(fmt.len + $vacount * 8);
str.appendf(fmt, $vasplat);
str.appendf(fmt, $vasplat());
return str.zstr_view();
}
@@ -67,7 +66,7 @@ macro String new_format(String fmt, ..., Allocator allocator = allocator::heap()
@pool(allocator)
{
DString str = dstring::temp_with_capacity(fmt.len + $vacount * 8);
str.appendf(fmt, $vasplat);
str.appendf(fmt, $vasplat());
return str.copy_str(allocator);
};
}
@@ -83,7 +82,7 @@ macro ZString new_format_zstr(String fmt, ..., Allocator allocator = allocator::
@pool(allocator)
{
DString str = dstring::temp_with_capacity(fmt.len + $vacount * 8);
str.appendf(fmt, $vasplat);
str.appendf(fmt, $vasplat());
return str.copy_zstr(allocator);
};
}

View File

@@ -13,37 +13,11 @@ fn void StringIterator.reset(&self)
fn Char32! StringIterator.next(&self)
{
usz len = self.utf8.len;
usz current = self.current;
if (current >= len) return IteratorResult.NO_MORE_ELEMENT?;
usz read = (len - current < 4 ? len - current : 4);
Char32 res = conv::utf8_to_char32(&self.utf8[current], &read)!;
self.current += read;
return res;
}
fn Char32! StringIterator.peek(&self)
{
usz len = self.utf8.len;
usz current = self.current;
if (current >= len) return IteratorResult.NO_MORE_ELEMENT?;
usz read = (len - current < 4 ? len - current : 4);
Char32 res = conv::utf8_to_char32(&self.utf8[current], &read)!;
return res;
}
fn bool StringIterator.has_next(&self)
{
return self.current < self.utf8.len;
}
fn Char32! StringIterator.get(&self)
{
usz len = self.utf8.len;
usz current = self.current;
usz read = (len - current < 4 ? len - current : 4);
usz index = current > read ? current - read : 0;
if (index >= len) return IteratorResult.NO_MORE_ELEMENT?;
Char32 res = conv::utf8_to_char32(&self.utf8[index], &read)!;
return res;
usz len = self.utf8.len;
usz current = self.current;
if (current >= len) return IteratorResult.NO_MORE_ELEMENT?;
usz read = (len - current < 4 ? len - current : 4);
Char32 res = conv::utf8_to_char32(&self.utf8[current], &read)!;
self.current += read;
return res;
}

View File

@@ -120,20 +120,10 @@ macro bool is_slice_convertable($Type)
$endswitch
}
macro bool is_bool($Type) @const => $Type.kindof == TypeKind.BOOL;
macro bool is_int($Type) @const => $Type.kindof == TypeKind.SIGNED_INT || $Type.kindof == TypeKind.UNSIGNED_INT;
macro bool is_bool($Type) => $Type.kindof == TypeKind.BOOL;
macro bool is_int($Type) => $Type.kindof == TypeKind.SIGNED_INT || $Type.kindof == TypeKind.UNSIGNED_INT;
macro bool is_indexable($Type) @const
{
return $defined($Type{}[0]);
}
macro bool is_ref_indexable($Type) @const
{
return $defined(&$Type{}[0]);
}
macro bool is_intlike($Type) @const
macro bool is_intlike($Type)
{
$switch ($Type.kindof)
$case SIGNED_INT:
@@ -146,7 +136,7 @@ macro bool is_intlike($Type) @const
$endswitch
}
macro bool is_underlying_int($Type) @const
macro bool is_underlying_int($Type)
{
$switch ($Type.kindof)
$case SIGNED_INT:
@@ -159,9 +149,9 @@ macro bool is_underlying_int($Type) @const
$endswitch
}
macro bool is_float($Type) @const => $Type.kindof == TypeKind.FLOAT;
macro bool is_float($Type) => $Type.kindof == TypeKind.FLOAT;
macro bool is_floatlike($Type) @const
macro bool is_floatlike($Type)
{
$switch ($Type.kindof)
$case FLOAT:
@@ -173,12 +163,12 @@ macro bool is_floatlike($Type) @const
$endswitch
}
macro bool is_vector($Type) @const
macro bool is_vector($Type)
{
return $Type.kindof == TypeKind.VECTOR;
}
macro TypeKind inner_kind($Type) @const
macro TypeKind inner_kind($Type)
{
$if $Type.kindof == TypeKind.DISTINCT:
return inner_kind($typefrom($Type.inner));
@@ -187,26 +177,26 @@ macro TypeKind inner_kind($Type) @const
$endif
}
macro bool is_same($TypeA, $TypeB) @const
macro bool is_same($TypeA, $TypeB)
{
return $TypeA.typeid == $TypeB.typeid;
}
macro bool @has_same(#a, #b, ...) @const
macro bool @has_same(#a, #b, ...)
{
var $type_a = @typeid(#a);
$if $type_a != @typeid(#b):
return false;
$endif
$for (var $i = 0; $i < $vacount; $i++)
$if @typeid($vaexpr[$i]) != $type_a:
$if @typeid($vaexpr($i)) != $type_a:
return false;
$endif
$endfor
return true;
}
macro bool may_load_atomic($Type) @const
macro bool may_load_atomic($Type)
{
$switch ($Type.kindof)
$case SIGNED_INT:
@@ -221,7 +211,7 @@ macro bool may_load_atomic($Type) @const
$endswitch
}
macro lower_to_atomic_compatible_type($Type) @const
macro lower_to_atomic_compatible_type($Type)
{
$switch ($Type.kindof)
$case SIGNED_INT:
@@ -247,10 +237,10 @@ macro lower_to_atomic_compatible_type($Type) @const
$endswitch
}
macro bool is_promotable_to_floatlike($Type) @const => types::is_floatlike($Type) || types::is_int($Type);
macro bool is_promotable_to_float($Type) @const => types::is_float($Type) || types::is_int($Type);
macro bool is_promotable_to_floatlike($Type) => types::is_floatlike($Type) || types::is_int($Type);
macro bool is_promotable_to_float($Type) => types::is_float($Type) || types::is_int($Type);
macro bool is_same_vector_type($Type1, $Type2) @const
macro bool is_same_vector_type($Type1, $Type2)
{
$if $Type1.kindof != TypeKind.VECTOR:
return $Type2.kindof != TypeKind.VECTOR;
@@ -259,7 +249,7 @@ macro bool is_same_vector_type($Type1, $Type2) @const
$endif
}
macro bool is_equatable_type($Type) @const
macro bool is_equatable_type($Type)
{
$if $defined($Type.less) || $defined($Type.compare_to) || $defined($Type.equals):
return true;
@@ -271,31 +261,17 @@ macro bool is_equatable_type($Type) @const
/**
* Checks if a type implements the copy protocol.
**/
macro bool implements_copy($Type) @const
macro bool implements_copy($Type)
{
return $defined($Type.copy) && $defined($Type.free);
}
macro bool is_equatable_value(value) @deprecated
macro bool is_equatable_value(value)
{
return is_equatable_type($typeof(value));
}
macro bool @equatable_value(#value) @const
{
return is_equatable_type($typeof(#value));
}
macro bool @comparable_value(#value) @const
{
$if $defined(#value.less) || $defined(#value.compare_to):
return true;
$else
return $typeof(#value).is_ordered;
$endif
}
macro bool is_comparable_value(value) @deprecated
macro bool is_comparable_value(value)
{
$if $defined(value.less) || $defined(value.compare_to):
return true;

View File

@@ -1,21 +1,21 @@
module std::core::values;
macro typeid @typeid(#value) @const @builtin => $typeof(#value).typeid;
macro TypeKind @typekind(#value) @const @builtin => $typeof(#value).kindof;
macro bool @typeis(#value, $Type) @const @builtin => $typeof(#value).typeid == $Type.typeid;
macro typeid @typeid(#value) @builtin => $typeof(#value).typeid;
macro TypeKind @typekind(#value) @builtin => $typeof(#value).kindof;
macro bool @typeis(#value, $Type) @builtin => $typeof(#value).typeid == $Type.typeid;
/**
* Return true if two values have the same type before any conversions.
**/
macro bool @is_same_type(#value1, #value2) @const => $typeof(#value1).typeid == $typeof(#value2).typeid;
macro bool @is_bool(#value) @const => types::is_bool($typeof(#value));
macro bool @is_int(#value) @const => types::is_int($typeof(#value));
macro bool @is_floatlike(#value) @const => types::is_floatlike($typeof(#value));
macro bool @is_float(#value) @const => types::is_float($typeof(#value));
macro bool @is_promotable_to_floatlike(#value) @const => types::is_promotable_to_floatlike($typeof(#value));
macro bool @is_promotable_to_float(#value) @const => types::is_promotable_to_float($typeof(#value));
macro bool @is_vector(#value) @const => types::is_vector($typeof(#value));
macro bool @is_same_vector_type(#value1, #value2) @const => types::is_same_vector_type($typeof(#value1), $typeof(#value2));
macro bool @assign_to(#value1, #value2) @const => $assignable(#value1, $typeof(#value2));
macro bool @is_same_type(#value1, #value2) => $typeof(#value1).typeid == $typeof(#value2).typeid;
macro bool @is_bool(#value) => types::is_bool($typeof(#value));
macro bool @is_int(#value) => types::is_int($typeof(#value));
macro bool @is_floatlike(#value) => types::is_floatlike($typeof(#value));
macro bool @is_float(#value) => types::is_float($typeof(#value));
macro bool @is_promotable_to_floatlike(#value) => types::is_promotable_to_floatlike($typeof(#value));
macro bool @is_promotable_to_float(#value) => types::is_promotable_to_float($typeof(#value));
macro bool @is_vector(#value) => types::is_vector($typeof(#value));
macro bool @is_same_vector_type(#value1, #value2) => types::is_same_vector_type($typeof(#value1), $typeof(#value2));
macro bool @assign_to(#value1, #value2) => $assignable(#value1, $typeof(#value2));
macro promote_int(x)
{
@@ -26,21 +26,5 @@ macro promote_int(x)
$endif
}
macro promote_int_same(x, y)
{
$if @is_int(x):
$switch
$case @is_vector(y) &&& $typeof(y).inner == float.typeid:
return (float)x;
$case $typeof(y).typeid == float.typeid:
return (float)x;
$default:
return (double)x;
$endswitch
$else
return x;
$endif
}
macro TypeKind @inner_kind(#value) @const => types::inner_kind($typeof(#value));
macro TypeKind @inner_kind(#value) => types::inner_kind($typeof(#value));

View File

@@ -28,18 +28,6 @@ fn void Rc4.init(&self, char[] key)
self.j = 0;
}
/**
* Run a single pass of en/decryption using a particular key.
* @param [in] key
* @param [inout] data
**/
fn void crypt(char[] key, char[] data)
{
Rc4 rc4;
rc4.init(key);
rc4.crypt(data, data);
}
/**
* Encrypt or decrypt a sequence of bytes.
*

View File

@@ -15,29 +15,11 @@ fault JsonParsingError
INVALID_NUMBER,
}
fn Object*! parse_string(String s, Allocator allocator = allocator::heap())
{
return parse(ByteReader{}.init(s), allocator);
}
fn Object*! temp_parse_string(String s)
{
return parse(ByteReader{}.init(s), allocator::temp());
}
fn Object*! parse(InStream s, Allocator allocator = allocator::heap())
{
JsonContext context = { .last_string = dstring::new_with_capacity(64, allocator), .stream = s, .allocator = allocator };
defer context.last_string.free();
@pool(allocator)
{
return parse_any(&context);
};
}
fn Object*! temp_parse(InStream s)
{
return parse(s, allocator::temp());
return parse_any(&context);
}
// -- Implementation follows --

View File

@@ -85,7 +85,6 @@ fn usz! Formatter.print_with_function(&self, Printable arg)
self.width = old_width;
self.prec = old_prec;
}
if (!arg) return self.out_substr("(null)");
return arg.to_format(self);
}
if (&arg.to_new_string)
@@ -99,7 +98,6 @@ fn usz! Formatter.print_with_function(&self, Printable arg)
self.width = old_width;
self.prec = old_prec;
}
if (!arg) return self.out_substr("(null)");
@stack_mem(1024; Allocator mem)
{
return self.out_substr(arg.to_new_string(mem));
@@ -152,8 +150,17 @@ fn usz! Formatter.out_str(&self, any arg) @private
default:
}
usz! n = self.print_with_function((Printable)arg);
if (try n) return n;
if (@catch(n) != SearchResult.MISSING) n!;
if (catch err = n)
{
case SearchResult.MISSING:
break;
default:
return err?;
}
else
{
return n;
}
switch (arg.type.kindof)
{
case ENUM:
@@ -171,23 +178,14 @@ fn usz! Formatter.out_str(&self, any arg) @private
case DISTINCT:
if (arg.type == ZString.typeid)
{
return self.out_substr(*(ZString*)arg ? ((ZString*)arg).str_view() : "(null)");
return self.out_substr(((ZString*)arg).str_view());
}
if (arg.type == DString.typeid)
{
return self.out_substr(*(DString*)arg ? ((DString*)arg).str_view() : "(null)");
return self.out_substr(((DString*)arg).str_view());
}
return self.out_str(arg.as_inner());
case POINTER:
typeid inner = arg.type.inner;
void** pointer = arg.ptr;
if (arg.type.inner != void.typeid)
{
any deref = any_make(*pointer, inner);
n = self.print_with_function((Printable)deref);
if (try n) return n;
if (@catch(n) != SearchResult.MISSING) n!;
}
PrintFlags flags = self.flags;
uint width = self.width;
defer
@@ -195,8 +193,8 @@ fn usz! Formatter.out_str(&self, any arg) @private
self.flags = flags;
self.width = width;
}
self.flags = {};
self.width = 0;
self.out_substr("0x")!;
return self.ntoa_any(arg, 16);
case ARRAY:
// this is SomeType[*] so grab the "SomeType"

View File

@@ -628,15 +628,15 @@ fn usz! Formatter.out_reverse(&self, char[] buf) @private
usz buffer_start_idx = self.idx;
usz len = buf.len;
// pad spaces up to given width
if (!self.flags.zeropad && !self.flags.left)
if (!self.flags.zeropad)
{
n += self.pad(' ', self.width, len)!;
n += self.adjust(len)!;
}
// reverse string
while (len) n += self.out(buf[--len])!;
// append pad spaces up to given width
n += self.adjust(n)!;
n += self.adjust(self.idx - buffer_start_idx)!;
return n;
}

View File

@@ -46,18 +46,12 @@ fault IoError
/**
* Read from a stream (default is stdin) to the next "\n"
* or to the end of the stream, whatever comes first.
* "\r" will be filtered from the String.
*
* @param stream `The stream to read from.`
* @require @is_instream(stream) `The stream must implement InStream.`
* @param [inout] allocator `the allocator to use.`
* @return `The string containing the data read.`
* @param stream
* @require @is_instream(stream)
**/
macro String! readline(stream = io::stdin(), Allocator allocator = allocator::heap())
{
bool $is_stream = @typeis(stream, InStream);
bool $is_stream = @typeid(stream) == InStream.typeid;
$if $is_stream:
$typeof(&stream.read_byte) func = &stream.read_byte;
char val = func((void*)stream)!;
@@ -90,51 +84,30 @@ macro String! readline(stream = io::stdin(), Allocator allocator = allocator::he
};
}
/**
* Reads a string, see `readline`, except the it is allocated
* on the temporary allocator and does not need to be freed.
*
* @param stream `The stream to read from.`
* @require @is_instream(stream) `The stream must implement InStream.`
* @return `The temporary string containing the data read.`
**/
macro String! treadline(stream = io::stdin())
{
return readline(stream, allocator::temp()) @inline;
}
macro String! treadline(stream = io::stdin()) => readline(stream, allocator::temp()) @inline;
/**
* Print a value to a stream.
*
* @param out `the stream to print to`
* @param x `the value to print`
* @require @is_outstream(out) `The output must implement OutStream.`
* @return `the number of bytes printed.`
* @require @is_outstream(out) "The output must implement OutStream"
*/
macro usz! fprint(out, x)
{
var $Type = $typeof(x);
$switch ($Type)
$case String: return out.write(x);
$case ZString: return out.write(x.str_view());
$case DString: return out.write(x.str_view());
$default:
$if $assignable(x, String):
return out.write((String)x);
$else
return fprintf(out, "%s", x);
$endif
$case String:
return out.write(x);
$case ZString:
return out.write(x.str_view());
$case DString:
return out.write(x.str_view());
$default:
$if $assignable(x, String):
return out.write((String)x);
$else
return fprintf(out, "%s", x);
$endif
$endswitch
}
/**
* Prints using a 'printf'-style formatting string.
* See `printf` for details on formatting.
*
* @param [inout] out `The OutStream to print to`
* @param [in] format `The printf-style format string`
* @return `the number of characters printed`
**/
fn usz! fprintf(OutStream out, String format, args...)
{
Formatter formatter;
@@ -142,14 +115,6 @@ fn usz! fprintf(OutStream out, String format, args...)
return formatter.vprintf(format, args);
}
/**
* Prints using a 'printf'-style formatting string,
* appending '\n' at the end. See `printf`.
*
* @param [inout] out `The OutStream to print to`
* @param [in] format `The printf-style format string`
* @return `the number of characters printed`
**/
fn usz! fprintfn(OutStream out, String format, args...) @maydiscard
{
Formatter formatter;
@@ -176,37 +141,21 @@ macro usz! fprintn(out, x = "")
return len + 1;
}
/**
* Print any value to stdout.
**/
macro void print(x)
{
(void)fprint(io::stdout(), x);
}
/**
* Print any value to stdout, appending an '\n after.
*
* @param x "The value to print"
**/
macro void printn(x = "")
{
(void)fprintn(io::stdout(), x);
}
/**
* Print any value to stderr.
**/
macro void eprint(x)
{
(void)fprint(io::stderr(), x);
}
/**
* Print any value to stderr, appending an '\n after.
*
* @param x "The value to print"
**/
macro void eprintn(x)
{
(void)fprintn(io::stderr(), x);
@@ -224,20 +173,6 @@ fn void! out_putchar_fn(void* data @unused, char c) @private
libc::putchar(c);
}
/**
* Prints using a 'printf'-style formatting string.
* To print integer numbers, use "%d" or "%x"/"%X,
* the latter gives the hexadecimal representation.
*
* All types can be printed using "%s" which gives
* the default representation of the value.
*
* To create a custom output for a type, implement
* the Printable interface.
*
* @param [in] format `The printf-style format string`
* @return `the number of characters printed`
**/
fn usz! printf(String format, args...) @maydiscard
{
Formatter formatter;
@@ -245,13 +180,6 @@ fn usz! printf(String format, args...) @maydiscard
return formatter.vprintf(format, args);
}
/**
* Prints using a 'printf'-style formatting string,
* appending '\n' at the end. See `printf`.
*
* @param [in] format `The printf-style format string`
* @return `the number of characters printed`
**/
fn usz! printfn(String format, args...) @maydiscard
{
Formatter formatter;
@@ -262,13 +190,6 @@ fn usz! printfn(String format, args...) @maydiscard
return len + 1;
}
/**
* Prints using a 'printf'-style formatting string
* to stderr.
*
* @param [in] format `The printf-style format string`
* @return `the number of characters printed`
**/
fn usz! eprintf(String format, args...) @maydiscard
{
Formatter formatter;
@@ -278,13 +199,6 @@ fn usz! eprintf(String format, args...) @maydiscard
}
/**
* Prints using a 'printf'-style formatting string,
* to stderr appending '\n' at the end. See `printf`.
*
* @param [in] format `The printf-style format string`
* @return `the number of characters printed`
**/
fn usz! eprintfn(String format, args...) @maydiscard
{
Formatter formatter;
@@ -296,14 +210,6 @@ fn usz! eprintfn(String format, args...) @maydiscard
return len;
}
/**
* Prints using a 'printf'-style formatting string,
* to a string buffer. See `printf`.
*
* @param [inout] buffer `The buffer to print to`
* @param [in] format `The printf-style format string`
* @return `a slice formed from the "buffer" with the resulting length.`
**/
fn char[]! bprintf(char[] buffer, String format, args...) @maydiscard
{
Formatter formatter;
@@ -313,7 +219,6 @@ fn char[]! bprintf(char[] buffer, String format, args...) @maydiscard
return buffer[:data.written];
}
// Used to print to a buffer.
fn void! out_buffer_fn(void *data, char c) @private
{
BufferData *buffer_data = data;
@@ -321,30 +226,22 @@ fn void! out_buffer_fn(void *data, char c) @private
buffer_data.buffer[buffer_data.written++] = c;
}
// Used for buffer printing
struct BufferData @private
{
char[] buffer;
usz written;
}
// Only available with LIBC
module std::io @if (env::LIBC);
import libc;
/**
* Libc `putchar`, prints a single character to stdout.
**/
fn void putchar(char c) @inline
{
libc::putchar(c);
}
/**
* Get standard out.
*
* @return `stdout as a File`
**/
fn File* stdout()
{
static File file;
@@ -352,11 +249,6 @@ fn File* stdout()
return &file;
}
/**
* Get standard err.
*
* @return `stderr as a File`
**/
fn File* stderr()
{
static File file;
@@ -364,11 +256,6 @@ fn File* stderr()
return &file;
}
/**
* Get standard in.
*
* @return `stdin as a File`
**/
fn File* stdin()
{
static File file;
@@ -384,7 +271,7 @@ File stderr_file;
fn void putchar(char c) @inline
{
(void)stdout_file.write_byte(c);
(void)stdout_file.putc(c);
}
fn File* stdout()

View File

@@ -95,7 +95,7 @@ fn bool native_is_file(String path)
$case env::DARWIN:
$case env::LINUX:
Stat stat;
return @ok(native_stat(&stat, path)) && libc_S_ISTYPE(stat.st_mode, libc::S_IFREG);
return @ok(native_stat(&stat, path)) && stat.st_mode & libc::S_IFREG;
$default:
File! f = file::open(path, "r");
defer (void)f.close();
@@ -107,7 +107,7 @@ fn bool native_is_dir(String path)
{
$if env::DARWIN || env::LINUX:
Stat stat;
return @ok(native_stat(&stat, path)) && libc_S_ISTYPE(stat.st_mode, libc::S_IFDIR);
return @ok(native_stat(&stat, path)) && stat.st_mode & libc::S_IFDIR;
$else
return native_file_or_dir_exists(path) && !native_is_file(path);
$endif

View File

@@ -16,7 +16,7 @@ fn void! native_rmtree(Path dir)
{
String name = ((ZString)&entry.name).str_view();
if (!name || name == "." || name == "..") continue;
Path new_path = dir.temp_append(name)!;
Path new_path = dir.tappend(name)!;
if (entry.d_type == posix::DT_DIR)
{
native_rmtree(new_path)!;
@@ -49,7 +49,7 @@ fn void! native_rmtree(Path path)
{
String filename = string::new_from_wstring((WString)&find_data.cFileName, allocator::temp())!;
if (filename == "." || filename == "..") continue;
Path file_path = path.temp_append(filename)!;
Path file_path = path.tappend(filename)!;
if (find_data.dwFileAttributes & win32::FILE_ATTRIBUTE_DIRECTORY)
{
native_rmtree(file_path)!;

View File

@@ -24,7 +24,6 @@ fn Path! native_temp_directory(Allocator allocator = allocator::heap()) @if(env:
}
module std::io::os @if(env::NO_LIBC);
import std::io::path;
macro Path! native_temp_directory(Allocator allocator = allocator::heap())
{

View File

@@ -15,9 +15,7 @@ fault PathResult
NO_PARENT,
}
def Path = PathImp;
struct PathImp (Printable)
struct Path (Printable)
{
String path_string;
PathEnv env;
@@ -29,15 +27,7 @@ enum PathEnv
POSIX
}
fn Path! new_cwd(Allocator allocator = allocator::heap())
{
@pool(allocator)
{
return new(os::getcwd(allocator::temp()), allocator);
};
}
fn Path! getcwd(Allocator allocator = allocator::heap()) @deprecated("Use new_cwd()")
fn Path! getcwd(Allocator allocator = allocator::heap())
{
@pool(allocator)
{
@@ -49,8 +39,7 @@ fn bool is_dir(Path path) => os::native_is_dir(path.str_view());
fn bool is_file(Path path) => os::native_is_file(path.str_view());
fn usz! file_size(Path path) => os::native_file_size(path.str_view());
fn bool exists(Path path) => os::native_file_or_dir_exists(path.str_view());
fn Path! temp_cwd() => new_cwd(allocator::temp()) @inline;
fn Path! tgetcwd() @deprecated("Use temp_cwd()") => new_cwd(allocator::temp()) @inline;
fn Path! tgetcwd() => getcwd(allocator::temp()) @inline;
fn void! chdir(Path path) => os::native_chdir(path) @inline;
fn Path! temp_directory(Allocator allocator = allocator::heap()) => os::native_temp_directory(allocator);
fn void! delete(Path path) => os::native_remove(path.str_view()) @inline;
@@ -70,17 +59,7 @@ macro bool is_win32_separator(char c)
return c == '/' || c == '\\';
}
fn PathList! ls(Path dir, bool no_dirs = false, bool no_symlinks = false, String mask = "", Allocator allocator = allocator::heap()) @deprecated("use new_ls")
{
return new_ls(dir, no_dirs, no_symlinks, mask, allocator);
}
fn PathList! temp_ls(Path dir, bool no_dirs = false, bool no_symlinks = false, String mask = "")
{
return new_ls(dir, no_dirs, no_symlinks, mask, allocator::temp()) @inline;
}
fn PathList! new_ls(Path dir, bool no_dirs = false, bool no_symlinks = false, String mask = "", Allocator allocator = allocator::heap())
fn PathList! ls(Path dir, bool no_dirs = false, bool no_symlinks = false, String mask = "", Allocator allocator = allocator::heap())
{
$if $defined(os::native_ls):
return os::native_ls(dir, no_dirs, no_symlinks, mask, allocator);
@@ -160,17 +139,12 @@ fn bool Path.equals(self, Path p2)
return self.env == p2.env && self.path_string == p2.path_string;
}
fn Path! Path.append(self, String filename, Allocator allocator = allocator::heap()) @deprecated("Use path.new_append(...)")
{
return self.new_append(filename, allocator) @inline;
}
/**
* Append the string to the current path.
*
* @param [in] filename
**/
fn Path! Path.new_append(self, String filename, Allocator allocator = allocator::heap())
fn Path! Path.append(self, String filename, Allocator allocator = allocator::heap())
{
if (!self.path_string.len) return new(filename, allocator, self.env)!;
assert(!is_separator(self.path_string[^1], self.env));
@@ -185,9 +159,7 @@ fn Path! Path.new_append(self, String filename, Allocator allocator = allocator:
};
}
fn Path! Path.temp_append(self, String filename) => self.new_append(filename, allocator::temp());
fn Path! Path.tappend(self, String filename) @deprecated("Use path.temp_append(...)") => self.new_append(filename, allocator::temp());
fn Path! Path.tappend(self, String filename) => self.append(filename, allocator::temp());
fn usz Path.start_of_base_name(self) @local
{
@@ -221,15 +193,10 @@ fn bool! Path.is_absolute(self)
return path_start < path_str.len && is_separator(path_str[path_start], self.env);
}
fn Path! Path.absolute(self, Allocator allocator = allocator::heap()) @deprecated("Use path.new_absolute()")
{
return self.new_absolute(allocator) @inline;
}
/**
* @require self.env == DEFAULT_PATH_ENV : "This method is only available on native paths"
**/
fn Path! Path.new_absolute(self, Allocator allocator = allocator::heap())
fn Path! Path.absolute(self, Allocator allocator = allocator::heap())
{
String path_str = self.str_view();
if (!path_str.len) return PathResult.INVALID_PATH?;
@@ -253,7 +220,7 @@ fn Path! Path.new_absolute(self, Allocator allocator = allocator::heap())
};
$else
String cwd = os::getcwd(allocator::temp())!;
return Path { cwd, self.env }.new_append(path_str, allocator)!;
return Path { cwd, self.env }.append(path_str, allocator)!;
$endif
}
@@ -283,22 +250,6 @@ fn String Path.dirname(self)
return path_str[:basename_start - 1];
}
/**
* Test if the path has the given extension, so given the path /foo/bar.c3
* this would be true matching the extension "c3"
*
* @param [in] extension `The extension name (not including the leading '.')`
* @require extension.len > 0 : `The extension cannot be empty`
* @return `true if the extension matches`
**/
fn bool Path.has_extension(self, String extension)
{
String basename = self.basename();
if (basename.len <= extension.len) return false;
if (basename[^extension.len + 1] != '.') return false;
return basename[^extension.len..] == extension;
}
fn String! Path.extension(self)
{
String basename = self.basename();
@@ -519,12 +470,12 @@ fn bool! Path.walk(self, PathWalker w, void* data)
const PATH_MAX = 512;
@stack_mem(PATH_MAX; Allocator allocator)
{
Path abs = self.new_absolute(allocator)!;
PathList files = new_ls(abs, .allocator = allocator)!;
Path abs = self.absolute(allocator)!;
PathList files = ls(abs, .allocator = allocator)!;
foreach (f : files)
{
if (f.str_view() == "." || f.str_view() == "..") continue;
f = abs.new_append(f.str_view(), allocator)!;
f = abs.append(f.str_view(), allocator)!;
bool is_directory = is_dir(f);
if (w(f, is_directory, data)!) return true;
if (is_directory && f.walk(w, data)!) return true;

View File

@@ -141,9 +141,15 @@ fn usz! copy_to(InStream in, OutStream dst, char[] buffer = {})
if (&dst.read_to) return dst.read_to(in);
$switch (env::MEMORY_ENV)
$case NORMAL:
return copy_through_buffer(in, dst, &&char[4096]{});
@pool()
{
return copy_through_buffer(in, dst, mem::temp_alloc_array(char, 4096));
};
$case SMALL:
return copy_through_buffer(in, dst, &&char[1024]{});
@pool()
{
return copy_through_buffer(in, dst, mem::temp_alloc_array(char, 1024));
};
$case TINY:
$case NONE:
return copy_through_buffer(in, dst, &&(char[256]{}));

View File

@@ -11,7 +11,7 @@ struct ByteWriter (OutStream)
/**
* @param [&inout] self
* @param [&inout] allocator
* @require self.bytes.len == 0 "Init may not run on already initialized data"
* @require self.bytes.len == 0 "Init may not run on on already initialized data"
* @ensure (bool)allocator, self.index == 0
**/
fn ByteWriter* ByteWriter.new_init(&self, Allocator allocator = allocator::heap())
@@ -22,7 +22,7 @@ fn ByteWriter* ByteWriter.new_init(&self, Allocator allocator = allocator::heap(
/**
* @param [&inout] self
* @require self.bytes.len == 0 "Init may not run on already initialized data"
* @require self.bytes.len == 0 "Init may not run on on already initialized data"
* @ensure self.index == 0
**/
fn ByteWriter* ByteWriter.temp_init(&self)

View File

@@ -183,8 +183,8 @@ extern fn isz write(Fd fd, void* buffer, usz count) @if(!env::WIN32);
extern fn CFile fmemopen(void* ptr, usz size, ZString mode);
extern fn isz getline(char** linep, usz* linecapp, CFile stream);
extern fn CInt timespec_get(TimeSpec* ts, CInt base);
extern fn CInt nanosleep(TimeSpec* req, TimeSpec* remaining);
extern fn int timespec_get(TimeSpec* ts, int base);
extern fn int nanosleep(TimeSpec* req, TimeSpec* remaining);
extern fn ZString ctime(Time_t *timer);
extern fn Time_t time(Time_t *timer);
@@ -360,7 +360,6 @@ const int EOF = -1;
const int FOPEN_MAX = 20;
const int FILENAME_MAX = 1024;
macro bool libc_S_ISTYPE(value, mask) @builtin => (value & S_IFMT) == mask;
const S_IFMT = 0o170000; // type of file mask
const S_IFIFO = 0o010000; // named pipe (fifo)
const S_IFCHR = 0o020000; // character special

View File

@@ -1,7 +1,5 @@
module libc @if(env::POSIX);
extern fn isz recv(Fd socket, void *buffer, usz length, CInt flags);
extern fn isz send(Fd socket, void *buffer, usz length, CInt flags);
extern fn void* dlopen(ZString path, int flags);
extern fn CInt dlclose(void*);
@@ -55,139 +53,3 @@ struct Stack_t
extern fn CInt sigaltstack(Stack_t* ss, Stack_t* old_ss);
extern fn CInt sigaction(CInt signum, Sigaction *action, Sigaction *oldaction);
module libc::termios @if(env::LIBC &&& env::POSIX);
distinct Cc = char;
distinct Speed = CUInt;
distinct Tcflags = CUInt;
const Tcflags TCOOFF = 0;
const Tcflags TCOON = 1;
const Tcflags TCIOFF = 2;
const Tcflags TCION = 3;
const Tcflags TCIFLUSH = 0;
const Tcflags TCOFLUSH = 1;
const Tcflags TCIOFLUSH = 2;
const Tcflags TCSANOW = 0;
const Tcflags TCSADRAIN = 1;
const Tcflags TCSAFLUSH = 2;
const Speed B0 = 0000000;
const Speed B50 = 0000001;
const Speed B75 = 0000002;
const Speed B110 = 0000003;
const Speed B134 = 0000004;
const Speed B150 = 0000005;
const Speed B200 = 0000006;
const Speed B300 = 0000007;
const Speed B600 = 0000010;
const Speed B1200 = 0000011;
const Speed B1800 = 0000012;
const Speed B2400 = 0000013;
const Speed B4800 = 0000014;
const Speed B9600 = 0000015;
const Speed B19200 = 0000016;
const Speed B38400 = 0000017;
const Speed B57600 = 0010001;
const Speed B115200 = 0010002;
const Speed B230400 = 0010003;
const Speed B460800 = 0010004;
const Speed B500000 = 0010005;
const Speed B576000 = 0010006;
const Speed B921600 = 0010007;
const Speed B1000000 = 0010010;
const Speed B1152000 = 0010011;
const Speed B1500000 = 0010012;
const Speed B2000000 = 0010013;
const Speed B2500000 = 0010014;
const Speed B3000000 = 0010015;
const Speed B3500000 = 0010016;
const Speed B4000000 = 0010017;
const Speed MAX_BAUD = B4000000;
const CInt VINTR = 0;
const CInt VQUIT = 1;
const CInt VERASE = 2;
const CInt VKILL = 3;
const CInt VEOF = 4;
const CInt VTIME = 5;
const CInt VMIN = 6;
const CInt VSWTC = 7;
const CInt VSTART = 8;
const CInt VSTOP = 9;
const CInt VSUSP = 10;
const CInt VEOL = 11;
const CInt VREPRINT = 12;
const CInt VDISCARD = 13;
const CInt VWERASE = 14;
const CInt VLNEXT = 15;
const CInt VEOL2 = 16;
const CInt ISIG = 0000001;
const CInt ICANON = 0000002;
const CInt ECHO = 0000010;
const CInt ECHOE = 0000020;
const CInt ECHOK = 0000040;
const CInt ECHONL = 0000100;
const CInt NOFLSH = 0000200;
const CInt TOSTOP = 0000400;
const CInt IEXTEN = 0100000;
const CInt CSIZE = 0000060;
const CInt CS5 = 0000000;
const CInt CS6 = 0000020;
const CInt CS7 = 0000040;
const CInt CS8 = 0000060;
const CInt CSTOPB = 0000100;
const CInt CREAD = 0000200;
const CInt PARENB = 0000400;
const CInt PARODD = 0001000;
const CInt HUPCL = 0002000;
const CInt CLOCAL = 0004000;
const CInt OPOST = 0000001;
const CInt OLCUC = 0000002;
const CInt ONLCR = 0000004;
const CInt OCRNL = 0000010;
const CInt ONOCR = 0000020;
const CInt ONLRET = 0000040;
const CInt OFILL = 0000100;
const CInt OFDEL = 0000200;
const CInt VTDLY = 0040000;
const CInt VT0 = 0000000;
const CInt VT1 = 0040000;
const CInt IGNBRK = 0000001;
const CInt BRKINT = 0000002;
const CInt IGNPAR = 0000004;
const CInt PARMRK = 0000010;
const CInt INPCK = 0000020;
const CInt ISTRIP = 0000040;
const CInt INLCR = 0000100;
const CInt IGNCR = 0000200;
const CInt ICRNL = 0000400;
const CInt IUCLC = 0001000;
const CInt IXON = 0002000;
const CInt IXANY = 0004000;
const CInt IXOFF = 0010000;
const CInt IMAXBEL = 0020000;
const CInt IUTF8 = 0040000;
extern fn CInt tcgetattr(Fd fd, Termios* self);
extern fn CInt tcsetattr(Fd fd, CInt optional_actions, Termios* self);
extern fn CInt tcsendbreak(Fd fd, CInt duration);
extern fn CInt tcdrain(Fd fd);
extern fn CInt tcflush(Fd fd, CInt queue_selector);
extern fn CInt tcflow(Fd fd, CInt action);
extern fn Speed cfgetospeed(Termios* self);
extern fn Speed cfgetispeed(Termios* self);
extern fn CInt cfsetospeed(Termios* self, Speed speed);
extern fn CInt cfsetispeed(Termios* self, Speed speed);
const CInt NCCS = 32;
struct Termios {
Tcflags c_iflag;
Tcflags c_oflag;
Tcflags c_cflag;
Tcflags c_lflag;
Cc c_line;
Cc[NCCS] c_cc;
Speed c_ispeed;
Speed c_ospeed;
}

View File

@@ -1,5 +1,5 @@
module libc @if(env::WIN32);
import std::os::win32;
extern fn CFile __acrt_iob_func(CInt c);
extern fn CInt _close(Fd fd); def close = _close;
@@ -15,13 +15,11 @@ extern fn Time_t _mkgmtime64(Tm* timeptr); def timegm = _mkgmtime64;
extern fn Time_t _mktime64(Tm *timeptr); def mktime = _mktime64;
extern fn usz _msize(void* ptr);
extern fn CInt _read(Fd fd, void* buffer, CUInt buffer_size);
extern fn CInt _setjmp(JmpBuf* buffer, void* frameptr);
extern fn CInt _setjmp(void* frameptr, JmpBuf* buffer) @if(env::WIN32);
extern fn CFile _wfopen(WString, WString);
extern fn CFile _wfreopen(WString, WString, CFile);
extern fn CInt _write(Fd fd, void* buffer, CUInt count);
extern fn CInt _wremove(WString);
extern fn int recv(Win32_SOCKET s, void* buf, int len, int flags);
extern fn int send(Win32_SOCKET s, void* buf, int len, int flags);
struct SystemInfo
{
@@ -47,7 +45,7 @@ extern fn CInt get_system_info(SystemInfo*) @extern("GetSystemInfo");
// Aliases to simplify libc use
macro Tm* localtime_r(Time_t* timer, Tm* buf) => _localtime64_s(buf, timer);
macro CInt setjmp(JmpBuf* buffer) => _setjmp(buffer, null);
macro CInt setjmp(JmpBuf* buffer) => _setjmp($$frameaddress(0), buffer);
macro Tm* gmtime_r(Time_t* timer, Tm* buf) => _gmtime64_s(buf, timer);
macro isz read(Fd fd, void* buffer, usz buffer_size) => _read(fd, buffer, (CUInt)buffer_size);
macro isz write(Fd fd, void* buffer, usz count) => _write(fd, buffer, (CUInt)count);

View File

@@ -1,122 +0,0 @@
module libc::termios @if(env::LIBC &&& env::POSIX);
fn int sendBreak(Fd fd, int duration) => tcsendbreak(fd, duration);
fn int drain(Fd fd) => tcdrain(fd);
fn int flush(Fd fd, int queue_selector) => tcflush(fd, queue_selector);
fn int flow(Fd fd, int action) => tcflow(fd, action);
fn Speed Termios.getOSpeed(Termios* self) => cfgetospeed(self);
fn Speed Termios.getISpeed(Termios* self) => cfgetispeed(self);
fn int Termios.setOSpeed(Termios* self, Speed speed) => cfsetospeed(self, speed);
fn int Termios.setISpeed(Termios* self, Speed speed) => cfsetispeed(self, speed);
fn int Termios.getAttr(Termios* self, Fd fd) => tcgetattr(fd, self);
fn int Termios.setAttr(Termios* self, Fd fd, int optional_actions) => tcsetattr(fd, optional_actions, self);
module libc::termios @if(!env::LIBC ||| !env::POSIX);
distinct Cc = char;
distinct Speed = CUInt;
distinct Tcflags = CUInt;
struct Termios {
void* dummy;
}
fn CInt tcgetattr(Fd fd, Termios* self)
{
unreachable("tcgetattr unavailable");
}
fn CInt tcsetattr(Fd fd, CInt optional_actions, Termios* self)
{
unreachable("tcsetattr unavailable");
}
fn CInt tcsendbreak(Fd fd, CInt duration)
{
unreachable("tcsendbreak unavailable");
}
fn CInt tcdrain(Fd fd)
{
unreachable("tcdrain unavailable");
}
fn CInt tcflush(Fd fd, CInt queue_selector)
{
unreachable("tcflush unavailable");
}
fn CInt tcflow(Fd fd, CInt action)
{
unreachable("tcflow unavailable");
}
fn Speed cfgetospeed(Termios* self)
{
unreachable("cfgetospeed unavailable");
}
fn Speed cfgetispeed(Termios* self)
{
unreachable("cfgetispeed unavailable");
}
fn CInt cfsetospeed(Termios* self, Speed speed)
{
unreachable("cfsetospeed unavailable");
}
fn CInt cfsetispeed(Termios* self, Speed speed)
{
unreachable("cfsetispeed unavailable");
}
fn int sendBreak(Fd fd, int duration)
{
unreachable("sendBreak unavailable");
}
fn int drain(Fd fd)
{
unreachable("drain unavailable");
}
fn int flush(Fd fd, int queue_selector)
{
unreachable("flush unavailable");
}
fn int flow(Fd fd, int action)
{
unreachable("flow unavailable");
}
fn Speed Termios.getOSpeed(Termios* self)
{
unreachable("Termios.getOSpeed unavailable");
}
fn Speed Termios.getISpeed(Termios* self)
{
unreachable("Termios.getISpeed unavailable");
}
fn int Termios.setOSpeed(Termios* self, Speed speed)
{
unreachable("Termios.setOSpeed unavailable");
}
fn int Termios.setISpeed(Termios* self, Speed speed)
{
unreachable("Termios.setISpeed unavailable");
}
fn int Termios.getAttr(Termios* self, Fd fd)
{
unreachable("Termios.getAttr unavailable");
}
fn int Termios.setAttr(Termios* self, Fd fd, int optional_actions)
{
unreachable("Termios.setAttr unavailable");
}

View File

@@ -159,7 +159,7 @@ macro atan2(x, y)
/**
* @require values::@is_int(x) || values::@is_float(x) "Expected an integer or floating point value"
* @require (@typekind(y) == ARRAY || @typekind(y) == VECTOR) &&& y.len == 2
* @require $and(@typekind(y) == ARRAY || @typekind(y) == VECTOR, y.len == 2)
* @require $assignable(x, $typeof(y[0]))
**/
macro sincos(x, y)
@@ -266,7 +266,7 @@ macro clamp(x, lower, upper) => $$max(($typeof(x))lower, $$min(x, ($typeof(x))up
* @require values::@is_promotable_to_floatlike(mag) `The input must be a number value or float vector`
* @require values::@assign_to(sgn, values::promote_int(mag))
**/
macro copysign(mag, sgn) => $$copysign(values::promote_int_same(mag, sgn), ($typeof(values::promote_int_same(mag, sgn)))sgn);
macro copysign(mag, sgn) => $$copysign(values::promote_int(mag), ($typeof(values::promote_int(mag)))sgn);
/**
* @require values::@is_promotable_to_floatlike(x) `The input must be a number value or float vector`
@@ -339,10 +339,7 @@ macro ln(x) => $$log(values::promote_int(x));
* @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector`
* @require values::@is_promotable_to_floatlike(base) `The base must be a number or a float vector`
**/
macro log(x, base)
{
return $$log(values::promote_int_same(x, base)) / $$log(values::promote_int_same(base, x));
}
macro log(x, base) => $$log(values::promote_int(x)) / $$log(values::promote_int(base));
/**
* @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector`
@@ -365,7 +362,7 @@ macro max(x, y, ...)
$else
var m = $$max(x, y);
$for (var $i = 0; $i < $vacount; $i++)
m = $$max(m, $vaarg[$i]);
m = $$max(m, $vaarg($i));
$endfor
return m;
$endif
@@ -382,7 +379,7 @@ macro min(x, y, ...)
$else
var m = $$min(x, y);
$for (var $i = 0; $i < $vacount; $i++)
m = $$min(m, $vaarg[$i]);
m = $$min(m, $vaarg($i));
$endfor
return m;
$endif
@@ -406,7 +403,7 @@ macro nearbyint(x) => $$nearbyint(x);
macro pow(x, exp)
{
$if types::is_floatlike($typeof(exp)):
return $$pow(values::promote_int_same(x, exp), ($typeof(values::promote_int_same(x, exp)))exp);
return $$pow(values::promote_int(x), ($typeof(values::promote_int(x)))exp);
$else
return $$pow_int(values::promote_int(x), exp);
$endif
@@ -693,7 +690,6 @@ macro ichar ichar[<*>].or(ichar[<*>] x) => $$reduce_or(x);
macro ichar ichar[<*>].xor(ichar[<*>] x) => $$reduce_xor(x);
macro ichar ichar[<*>].max(ichar[<*>] x) => $$reduce_max(x);
macro ichar ichar[<*>].min(ichar[<*>] x) => $$reduce_min(x);
macro ichar ichar[<*>].dot(ichar[<*>] x, ichar[<*>] y) => (x * y).sum();
macro bool[<*>] short[<*>].comp_lt(short[<*>] x, short[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] short[<*>].comp_le(short[<*>] x, short[<*>] y) => $$veccomple(x, y);
@@ -709,7 +705,6 @@ macro short short[<*>].or(short[<*>] x) => $$reduce_or(x);
macro short short[<*>].xor(short[<*>] x) => $$reduce_xor(x);
macro short short[<*>].max(short[<*>] x) => $$reduce_max(x);
macro short short[<*>].min(short[<*>] x) => $$reduce_min(x);
macro short short[<*>].dot(short[<*>] x, short[<*>] y) => (x * y).sum();
macro bool[<*>] int[<*>].comp_lt(int[<*>] x, int[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] int[<*>].comp_le(int[<*>] x, int[<*>] y) => $$veccomple(x, y);
@@ -725,7 +720,6 @@ macro int int[<*>].or(int[<*>] x) => $$reduce_or(x);
macro int int[<*>].xor(int[<*>] x) => $$reduce_xor(x);
macro int int[<*>].max(int[<*>] x) => $$reduce_max(x);
macro int int[<*>].min(int[<*>] x) => $$reduce_min(x);
macro int int[<*>].dot(int[<*>] x, int[<*>] y) => (x * y).sum();
macro bool[<*>] long[<*>].comp_lt(long[<*>] x, long[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] long[<*>].comp_le(long[<*>] x, long[<*>] y) => $$veccomple(x, y);
@@ -740,7 +734,6 @@ macro long long[<*>].or(long[<*>] x) => $$reduce_or(x);
macro long long[<*>].xor(long[<*>] x) => $$reduce_xor(x);
macro long long[<*>].max(long[<*>] x) => $$reduce_max(x);
macro long long[<*>].min(long[<*>] x) => $$reduce_min(x);
macro long long[<*>].dot(long[<*>] x, long[<*>] y) => (x * y).sum();
macro bool[<*>] int128[<*>].comp_lt(int128[<*>] x, int128[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] int128[<*>].comp_le(int128[<*>] x, int128[<*>] y) => $$veccomple(x, y);
@@ -755,7 +748,6 @@ macro int128 int128[<*>].or(int128[<*>] x) => $$reduce_or(x);
macro int128 int128[<*>].xor(int128[<*>] x) => $$reduce_xor(x);
macro int128 int128[<*>].max(int128[<*>] x) => $$reduce_max(x);
macro int128 int128[<*>].min(int128[<*>] x) => $$reduce_min(x);
macro int128 int128[<*>].dot(int128[<*>] x, int128[<*>] y) => (x * y).sum();
macro bool[<*>] bool[<*>].comp_lt(bool[<*>] x, bool[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] bool[<*>].comp_le(bool[<*>] x, bool[<*>] y) => $$veccomple(x, y);
@@ -786,7 +778,6 @@ macro char char[<*>].or(char[<*>] x) => $$reduce_or(x);
macro char char[<*>].xor(char[<*>] x) => $$reduce_xor(x);
macro char char[<*>].max(char[<*>] x) => $$reduce_max(x);
macro char char[<*>].min(char[<*>] x) => $$reduce_min(x);
macro char char[<*>].dot(char[<*>] x, char[<*>] y) => (x * y).sum();
macro bool[<*>] ushort[<*>].comp_lt(ushort[<*>] x, ushort[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] ushort[<*>].comp_le(ushort[<*>] x, ushort[<*>] y) => $$veccomple(x, y);
@@ -802,7 +793,6 @@ macro ushort ushort[<*>].or(ushort[<*>] x) => $$reduce_or(x);
macro ushort ushort[<*>].xor(ushort[<*>] x) => $$reduce_xor(x);
macro ushort ushort[<*>].max(ushort[<*>] x) => $$reduce_max(x);
macro ushort ushort[<*>].min(ushort[<*>] x) => $$reduce_min(x);
macro ushort ushort[<*>].dot(ushort[<*>] x, ushort[<*>] y) => (x * y).sum();
macro bool[<*>] uint[<*>].comp_lt(uint[<*>] x, uint[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] uint[<*>].comp_le(uint[<*>] x, uint[<*>] y) => $$veccomple(x, y);
@@ -818,7 +808,6 @@ macro uint uint[<*>].or(uint[<*>] x) => $$reduce_or(x);
macro uint uint[<*>].xor(uint[<*>] x) => $$reduce_xor(x);
macro uint uint[<*>].max(uint[<*>] x) => $$reduce_max(x);
macro uint uint[<*>].min(uint[<*>] x) => $$reduce_min(x);
macro uint uint[<*>].dot(uint[<*>] x, uint[<*>] y) => (x * y).sum();
macro bool[<*>] ulong[<*>].comp_lt(ulong[<*>] x, ulong[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] ulong[<*>].comp_le(ulong[<*>] x, ulong[<*>] y) => $$veccomple(x, y);
@@ -834,7 +823,6 @@ macro ulong ulong[<*>].or(ulong[<*>] x) => $$reduce_or(x);
macro ulong ulong[<*>].xor(ulong[<*>] x) => $$reduce_xor(x);
macro ulong ulong[<*>].max(ulong[<*>] x) => $$reduce_max(x);
macro ulong ulong[<*>].min(ulong[<*>] x) => $$reduce_min(x);
macro ulong ulong[<*>].dot(ulong[<*>] x, ulong[<*>] y) => (x * y).sum();
macro bool[<*>] uint128[<*>].comp_lt(uint128[<*>] x, uint128[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] uint128[<*>].comp_le(uint128[<*>] x, uint128[<*>] y) => $$veccomple(x, y);
@@ -850,7 +838,6 @@ macro uint128 uint128[<*>].or(uint128[<*>] x) => $$reduce_or(x);
macro uint128 uint128[<*>].xor(uint128[<*>] x) => $$reduce_xor(x);
macro uint128 uint128[<*>].max(uint128[<*>] x) => $$reduce_max(x);
macro uint128 uint128[<*>].min(uint128[<*>] x) => $$reduce_min(x);
macro uint128 uint128[<*>].dot(uint128[<*>] x, uint128[<*>] y) => (x * y).sum();
macro char char.sat_add(char x, char y) => $$sat_add(x, y);
macro char char.sat_sub(char x, char y) => $$sat_sub(x, y);
@@ -1096,70 +1083,3 @@ macro overflow_mul_helper(x, y) @local
if ($$overflow_mul(x, y, &res)) return MathError.OVERFLOW?;
return res;
}
macro mul_div_helper(val, mul, div) @private
{
var $Type = $typeof(val);
return ($Type)(($Type)mul * (val / ($Type)div) + ($Type)mul * (val % ($Type)div) / ($Type)div);
}
macro char char.muldiv(self, char mul, char div) => mul_div_helper(self, mul, div);
macro ichar ichar.muldiv(self, ichar mul, ichar div) => mul_div_helper(self, mul, div);
macro short short.muldiv(self, short mul, short div) => mul_div_helper(self, mul, div);
macro ushort ushort.muldiv(self, ushort mul, ushort div) => mul_div_helper(self, mul, div);
macro int int.muldiv(self, int mul, int div) => mul_div_helper(self, mul, div);
macro uint uint.muldiv(self, uint mul, uint div) => mul_div_helper(self, mul, div);
macro long long.muldiv(self, long mul, long div) => mul_div_helper(self, mul, div);
macro ulong ulong.muldiv(self, ulong mul, ulong div) => mul_div_helper(self, mul, div);
macro bool @is_same_vector_or_scalar(#vector_value, #vector_or_scalar) @private
{
return (values::@is_vector(#vector_or_scalar) &&& values::@is_same_vector_type(#vector_value, #vector_or_scalar)) ||| values::@is_int(#vector_or_scalar);
}
/**
* @require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar`
* @require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar`
*/
macro char[<*>] char[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
/**
* @require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar`
* @require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar`
*/
macro ichar[<*>] ichar[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
/**
* @require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar`
* @require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar`
*/
macro short[<*>] short[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
/**
* @require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar`
* @require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar`
*/
macro ushort[<*>] ushort[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
/**
* @require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar`
* @require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar`
*/
macro int[<*>] int[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
/**
* @require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar`
* @require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar`
*/
macro uint[<*>] uint[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
/**
* @require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar`
* @require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar`
*/
macro long[<*>] long[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
/**
* @require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar`
* @require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar`
*/
macro ulong[<*>] ulong[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);

View File

@@ -60,7 +60,7 @@ fn double __tan(double x, double y, int odd) @extern("__tan") @weak @nostrip
w = x + r;
if (big)
{
s = (double)(1 - 2 * odd);
s = 1 - 2 * odd;
v = s - 2.0 * (x + (r - w*w/(w + s)));
return sign ? -v : v;
}

View File

@@ -63,7 +63,7 @@ fn int __rem_pio2f(float x, double *y)
if (ix >= 0x7f800000)
{
// x is inf or NaN */
*y = x - (double)x;
*y = x-x;
return 0;
}
/* scale x into [2^23, 2^24-1] */

View File

@@ -1,15 +1,18 @@
/**
* Randoms:
* General usage -
* 1. Create a Random (see std/math/random for various alternatives), or pick DefaultRandom
* 2. Define it `DefaultRandom my_random;`
* 3. Seed it: `random::seed(&my_random, some_seed);` or `rand::seed_entropy(&my_random);`
* 4. Use it with the functions in random: `float random_float = random::next_float(&my_random);`
*
* For just a simple integer between 0 and n (not including n), you can use `rand(n)`.
**/
module std::math::random;
interface Random
{
fn void set_seed(char[] input);
fn char next_byte();
fn ushort next_short();
fn uint next_int();
fn ulong next_long();
fn uint128 next_int128();
fn void next_bytes(char[] buffer);
}
macro bool is_random(random) => $assignable(random, Random*);
/**
* @require is_random(random)
**/
@@ -18,19 +21,12 @@ macro void seed(random, seed)
random.set_seed(@as_char_view(seed));
}
/**
* Seed the random with some best effort entropy.
*
* @require is_random(random)
**/
macro void seed_entropy(random)
{
random.set_seed(&&entropy());
}
/**
* Get the next value between 0 and max (not including max).
*
* @require is_random(random)
**/
macro int next(random, int max)
@@ -38,11 +34,6 @@ macro int next(random, int max)
return (int)(next_double(random) * max);
}
def DefaultRandom = Sfc64Random;
/**
* Get a default random value between 0 and max (not including max)
**/
fn int rand(int max) @builtin
{
tlocal Sfc64Random default_random;
@@ -54,20 +45,15 @@ fn int rand(int max) @builtin
}
return next(&default_random, max);
}
/**
* Get 'true' or 'false'
*
* @require is_random(random)
**/
macro bool next_bool(random)
{
return (bool)(random.next_byte() & 1);
return random.next_byte() & 1;
}
/**
* Get a float between 0 and 1.0, not including 1.0.
*
* @require is_random(random)
**/
macro float next_float(random)
@@ -77,8 +63,6 @@ macro float next_float(random)
}
/**
* Get a double between 0 and 1.0, not including 1.0.
*
* @require is_random(random)
**/
macro double next_double(random)
@@ -87,9 +71,6 @@ macro double next_double(random)
return val * 0x1.0p-53;
}
// True if the value is a Random.
macro bool is_random(random) => $assignable(random, Random);
macro uint128 @long_to_int128(#function) => (uint128)#function << 64 + #function;
macro ulong @int_to_long(#function) => (ulong)#function << 32 + #function;
macro uint @short_to_int(#function) => (uint)#function << 16 + #function;
@@ -114,16 +95,3 @@ macro @random_value_to_bytes(#function, char[] bytes)
}
unreachable();
}
// This is the interface to implement for Random implementations, usually
// it is not invoked directly.
interface Random
{
fn void set_seed(char[] input);
fn char next_byte();
fn ushort next_short();
fn uint next_int();
fn ulong next_long();
fn uint128 next_int128();
fn void next_bytes(char[] buffer);
}

View File

@@ -25,11 +25,11 @@ macro Vec4.distance_sq(self, Vec4 v2) => (self - v2).length_sq();
macro Vec2f.transform(self, Matrix4f mat) => transform2(self, mat);
macro Vec2f.rotate(self, float angle) => rotate(self, angle);
macro Vec2f.angle(self, Vec2f v2) => math::atan2(v2.y, v2.x) - math::atan2(self.y, self.x);
macro Vec2f.angle(self, Vec2f v2) => math::atan2(v2[1], v2[0]) - math::atan2(self[1], v2[0]);
macro Vec2.transform(self, Matrix4 mat) => transform2(self, mat);
macro Vec2.rotate(self, double angle) => rotate(self, angle);
macro Vec2.angle(self, Vec2 v2) => math::atan2(v2.y, v2.x) - math::atan2(self.y, self.x);
macro Vec2.angle(self, Vec2 v2) => math::atan2(v2[1], v2[0]) - math::atan2(self[1], v2[0]);
macro Vec2f.clamp_mag(self, float min, float max) => clamp_magnitude(self, min, max);
macro Vec3f.clamp_mag(self, float min, float max) => clamp_magnitude(self, min, max);
@@ -190,7 +190,7 @@ macro rotate_axis_angle(v, axis, angle) @private
var w = axis * math::sin(angle);
var wv = w.cross(v);
var wwv = w.cross(wv);
wv *= math::cos(($typeof(v))angle) * 2;
wv *= math::cos(angle) * 2;
wwv *= 2;
return v + wv + wwv;

View File

@@ -27,7 +27,6 @@ fault NetError
ALREADY_CONNECTED,
NETWORK_UNREACHABLE,
OPERATION_NOT_SUPPORTED_ON_SOCKET,
CONNECTION_RESET,
}
fn uint! ipv4toint(String s)

View File

@@ -16,11 +16,11 @@ struct Posix_pollfd
def Posix_nfds_t = CUInt;
extern fn CInt connect(NativeSocket socket, SockAddrPtr address, Socklen_t address_len);
extern fn NativeSocket socket(AIFamily af, AISockType type, AIProtocol ip_protocol);
extern fn int fcntl(NativeSocket socket, int cmd, ...);
extern fn CInt bind(NativeSocket socket, SockAddrPtr address, Socklen_t address_len);
extern fn CInt listen(NativeSocket socket, CInt backlog);
extern fn NativeSocket accept(NativeSocket socket, SockAddrPtr address, Socklen_t* address_len);
extern fn NativeSocket socket(AIFamily af, AISockType type, AIProtocol ip_protocol) @extern("socket");
extern fn int fcntl(NativeSocket socket, int cmd, ...) @extern("fcntl");
extern fn CInt bind(NativeSocket socket, SockAddrPtr address, Socklen_t address_len) @extern("bind");
extern fn CInt listen(NativeSocket socket, CInt backlog) @extern("listen");
extern fn NativeSocket accept(NativeSocket socket, SockAddrPtr address, Socklen_t* address_len) @extern("accept");
extern fn CInt poll(Posix_pollfd* fds, Posix_nfds_t nfds, CInt timeout);
const CUShort POLLIN = 0x0001;
@@ -39,7 +39,6 @@ fn anyfault convert_error(Errno error)
case errno::EALREADY: return NetError.CONNECTION_ALREADY_IN_PROGRESS;
case errno::EBADF: return NetError.BAD_SOCKET_DESCRIPTOR;
case errno::ECONNREFUSED: return NetError.CONNECTION_REFUSED;
case errno::ECONNRESET: return NetError.CONNECTION_RESET;
case errno::EISCONN: return NetError.ALREADY_CONNECTED;
case errno::ENETUNREACH: return NetError.NETWORK_UNREACHABLE;
case errno::ENOTSOCK: return NetError.NOT_A_SOCKET;
@@ -56,11 +55,6 @@ fn anyfault socket_error()
return convert_error(libc::errno());
}
macro bool NativeSocket.is_valid(self)
{
return (iptr)self >= 0;
}
macro void! NativeSocket.close(self)
{
if (libc::close(self))

View File

@@ -12,7 +12,7 @@ const int FIONREAD = 1074030207;
const int FIONBIO = -2147195266;
const int FIOASYNC = -2147195267;
distinct NativeSocket = inline Win32_SOCKET;
distinct NativeSocket = uptr;
extern fn CInt ioctlsocket(NativeSocket, CLong cmd, CULong *argp);
extern fn WSAError closesocket(NativeSocket);
@@ -22,11 +22,6 @@ extern fn int bind(NativeSocket, SockAddrPtr address, Socklen_t address_len);
extern fn int listen(NativeSocket, int backlog);
extern fn NativeSocket accept(NativeSocket, SockAddrPtr address, Socklen_t* address_len);
macro bool NativeSocket.is_valid(self)
{
return self != (NativeSocket)(uptr)-1;
}
fn void! NativeSocket.set_non_blocking(self, bool non_blocking)
{
if (ioctlsocket(self, win32::FIONBIO, &&(CULong)non_blocking))
@@ -81,7 +76,6 @@ fn anyfault convert_error(WSAError error)
case wsa::ENOTSOCK: return NetError.NOT_A_SOCKET;
case wsa::EOPNOTSUPP: return NetError.OPERATION_NOT_SUPPORTED_ON_SOCKET;
case wsa::ETIMEDOUT: return NetError.CONNECTION_TIMED_OUT;
case wsa::ECONNRESET: return NetError.CONNECTION_RESET;
default: return IoError.GENERAL_ERROR;
}
}

View File

@@ -15,7 +15,7 @@ macro void @loop_over_ai(AddrInfo* ai; @body(NativeSocket fd, AddrInfo* ai))
while (ai)
{
NativeSocket sockfd = os::socket(ai.ai_family, ai.ai_socktype, ai.ai_protocol);
if (sockfd.is_valid())
if (sockfd > 0)
{
@body(sockfd, ai);
}
@@ -120,12 +120,8 @@ fn bool! Socket.get_option(&self, SocketOption option)
fn usz! Socket.read(&self, char[] bytes) @dynamic
{
$if env::WIN32:
isz n = libc::recv(self.sock, bytes.ptr, (int)bytes.len, 0);
$else
isz n = libc::recv(self.sock, bytes.ptr, bytes.len, 0);
$endif
if (n < 0) return os::socket_error()?;
isz n = libc::read((Fd)self.sock, bytes.ptr, bytes.len);
if (n < 0) return NetError.READ_FAILED?;
return (usz)n;
}
@@ -133,12 +129,8 @@ fn char! Socket.read_byte(&self) @dynamic => io::@read_byte_using_read(self);
fn usz! Socket.write(&self, char[] bytes) @dynamic
{
$if env::WIN32:
isz n = libc::send(self.sock, bytes.ptr, (int)bytes.len, 0);
$else
isz n = libc::send(self.sock, bytes.ptr, bytes.len, 0);
$endif
if (n < 0) return os::socket_error()?;
isz n = libc::write((Fd)self.sock, bytes.ptr, bytes.len);
if (n < 0) return NetError.WRITE_FAILED?;
return (usz)n;
}

View File

@@ -43,9 +43,8 @@ fn TcpServerSocket! listen(String host, uint port, uint backlog, SocketOption...
fn TcpSocket! accept(TcpServerSocket* server_socket)
{
TcpSocket socket;
socket.ai_addrlen = socket.ai_addr_storage.len;
socket.sock = os::accept(server_socket.sock, (SockAddrPtr)&socket.ai_addr_storage, &socket.ai_addrlen);
if (!socket.sock.is_valid()) return NetError.ACCEPT_FAILED?;
if (socket.sock < 0) return NetError.ACCEPT_FAILED?;
return socket;
}

View File

@@ -83,15 +83,10 @@ fn String! get_home_dir(Allocator using = allocator::heap())
return get_var(home, using);
}
fn Path! get_config_dir(Allocator allocator = allocator::heap()) @deprecated("use new_get_config_dir()")
{
return new_get_config_dir(allocator) @inline;
}
/**
* Returns the current user's config directory.
**/
fn Path! new_get_config_dir(Allocator allocator = allocator::heap())
fn Path! get_config_dir(Allocator allocator = allocator::heap())
{
@pool(allocator)
{
@@ -105,7 +100,7 @@ fn Path! new_get_config_dir(Allocator allocator = allocator::heap())
String s = get_var_temp("XDG_CONFIG_HOME") ?? get_var_temp("HOME")!;
const DIR = ".config";
$endif
return path::temp_new(s).new_append(DIR, .allocator = allocator);
return path::temp_new(s).append(DIR, .allocator = allocator);
$endif
};
}
@@ -131,16 +126,11 @@ fn bool clear_var(String name)
};
}
fn String! executable_path(Allocator allocator = allocator::heap()) @deprecated("use new_executable_path()")
{
return new_executable_path(allocator) @inline;
}
fn String! new_executable_path(Allocator allocator = allocator::heap())
fn String! executable_path(Allocator allocator = allocator::heap())
{
$if env::DARWIN:
return darwin::executable_path(allocator);
$else
return SearchResult.MISSING?;
return "<Unsupported>";
$endif
}

View File

@@ -80,7 +80,7 @@ fn uptr! load_address() @local
{
Darwin_segment_command_64* cmd = darwin::getsegbyname("__TEXT");
if (!cmd) return BacktraceFault.SEGMENT_NOT_FOUND?;
String path = env::new_executable_path(allocator::temp()) ?? BacktraceFault.EXECUTABLE_PATH_NOT_FOUND?!;
String path = env::executable_path(allocator::temp()) ?? BacktraceFault.EXECUTABLE_PATH_NOT_FOUND?!;
uint dyld_count = darwin::_dyld_image_count();
for (uint i = 0; i < dyld_count; i++)
{

View File

@@ -6,6 +6,7 @@ enum Win32_GET_FILEEX_INFO_LEVELS
MAX,
}
struct Win32_FILE_ATTRIBUTE_DATA
{
Win32_DWORD dwFileAttributes;
@@ -16,6 +17,7 @@ struct Win32_FILE_ATTRIBUTE_DATA
Win32_DWORD nFileSizeLow;
}
const MAX_PATH = 260;
struct Win32_WIN32_FIND_DATAW

View File

@@ -1,6 +0,0 @@
module std::os::win32 @if(env::WIN32);
extern fn Win32_HBRUSH createSolidBrush(Win32_COLORREF) @extern("CreateSolidBrush");
extern fn Win32_COLORREF setTextColor(Win32_HDC, Win32_COLORREF) @extern("SetTextColor");
extern fn CInt setBkMode(Win32_HDC, CInt) @extern("SetBkMode");
extern fn Win32_BOOL textOut(Win32_HDC, CInt, CInt, Win32_LPCWSTR, CInt) @extern("TextOutW");

View File

@@ -2,10 +2,10 @@ module std::os::win32 @if(env::WIN32);
extern fn void* _aligned_malloc(usz size, usz alignment);
extern fn void* _aligned_realloc(void* memblock, usz size, usz alignment);
extern fn void* _aligned_recalloc(void* memblock, usz num, usz size, usz alignment);
extern fn void* _aligned_recalloc(void* memblock, usz size, usz alignment);
extern fn void _aligned_free(void* memblock);
extern fn void _aligned_msize(void* memblock, usz alignment, usz offset);
extern fn void* _aligned_offset_malloc(usz size, usz alignment, usz offset);
extern fn void* _aligned_offset_realloc(void* memblock, usz size, usz alignment, usz offset);
extern fn void* _aligned_offset_recalloc(void* memblock, usz num, usz size, usz alignment, usz offset);
extern fn void* _aligned_offset_recalloc(void* memblock, usz size, usz alignment, usz offset);
extern fn usz _msize(void* memblock);

View File

@@ -53,17 +53,15 @@ extern fn Win32_BOOL releaseMutex(Win32_HANDLE) @extern("ReleaseMutex");
extern fn void enterCriticalSection(Win32_CRITICAL_SECTION* section) @extern("EnterCriticalSection");
extern fn void leaveCriticalSection(Win32_CRITICAL_SECTION* section) @extern("LeaveCriticalSection");
extern fn Win32_BOOL tryEnterCriticalSection(Win32_CRITICAL_SECTION* section) @extern("TryEnterCriticalSection");
extern fn Win32_DWORD waitForSingleObject(Win32_HANDLE hHandle, Win32_DWORD dwMilliseconds) @extern("WaitForSingleObject");
extern fn Win32_DWORD waitForSingleObjectEx(Win32_HANDLE hHandle, Win32_DWORD dwMilliseconds, Win32_BOOL bAlertable) @extern("WaitForSingleObjectEx");
extern fn Win32_DWORD waitForMultipleObjects(Win32_DWORD nCount, Win32_HANDLE* lpHandles, Win32_BOOL bWaitAll, Win32_DWORD dwMilliseconds) @extern("WaitForMultipleObjects");
extern fn Win32_DWORD waitForMultipleObjectsEx(Win32_DWORD nCount, Win32_HANDLE* lpHandles, Win32_BOOL bWaitAll, Win32_DWORD dwMilliseconds, Win32_BOOL bAlertable) @extern("WaitForMultipleObjectsEx");
extern fn uint waitForSingleObject(Win32_HANDLE, uint milliseconds) @extern("WaitForSingleObject");
extern fn void sleep(uint ms) @extern("Sleep");
extern fn uint waitForMultipleObjects(uint count, Win32_HANDLE* handles, Win32_BOOL wait_all, uint ms) @extern("WaitForMultipleObjects");
extern fn Win32_BOOL resetEvent(Win32_HANDLE event) @extern("ResetEvent");
extern fn Win32_BOOL setEvent(Win32_HANDLE handle) @extern("SetEvent");
extern fn long interlockedCompareExchange(int* dest, int exchange, int comperand) @extern("InterlockedCompareExchange");
extern fn Win32_DWORD sleepEx(Win32_DWORD ms, Win32_BOOL alertable) @extern("SleepEx");
extern fn Win32_HANDLE createThread(void* attributes, usz stack, ThreadFn func, Win32_LPVOID arg, Win32_DWORD flags, Win32_LPDWORD thread_id) @extern("CreateThread");
extern fn Win32_BOOL getExitCodeThread(Win32_HANDLE handle, Win32_LPDWORD exit_code) @extern("GetExitCodeThread");
extern fn Win32_HANDLE createThread(void* attributes, usz stack, ThreadFn func, void* arg, uint flags, uint* thread_id) @extern("CreateThread");
extern fn Win32_BOOL getExitCodeThread(Win32_HANDLE handle, uint* exit_code) @extern("GetExitCodeThread");
extern fn Win32_BOOL getExitCodeProcess(Win32_HANDLE hProcess, Win32_LPDWORD lpExitCode) @extern("GetExitCodeProcess");
extern fn Win32_DWORD getThreadId(Win32_HANDLE) @extern("GetThreadId");
extern fn void exitThread(Win32_DWORD dwExitCode) @noreturn @extern("ExitThread");

View File

@@ -1,33 +0,0 @@
module std::os::win32 @if(env::WIN32);
struct Win32_RECT
{
Win32_LONG left;
Win32_LONG top;
Win32_LONG right;
Win32_LONG bottom;
}
struct Win32_POINT
{
Win32_LONG x;
Win32_LONG y;
}
struct Win32_SIZE
{
Win32_LONG cx;
Win32_LONG cy;
}
def Win32_PSIZE = Win32_SIZE*;
def Win32_NPSIZE = Win32_SIZE*;
def Win32_LPSIZE = Win32_SIZE*;
def Win32_PPOINT = Win32_POINT*;
def Win32_NPOINT = Win32_POINT*;
def Win32_LPOINT = Win32_POINT*;
def Win32_PRECT = Win32_RECT*;
def Win32_NPRECT = Win32_RECT*;
def Win32_LPRECT = Win32_RECT*;

View File

@@ -1,150 +0,0 @@
module std::os::win32 @if(env::WIN32);
def Win32_WNDPROC = fn Win32_LRESULT(Win32_HWND, Win32_UINT, Win32_WPARAM, Win32_LPARAM);
struct Win32_WNDCLASSEXW
{
Win32_UINT cbSize;
Win32_UINT style;
Win32_WNDPROC lpfnWndProc;
CInt cbClsExtra;
CInt cbWndExtra;
Win32_HINSTANCE hInstance;
Win32_HICON hIcon;
Win32_HCURSOR hCursor;
Win32_HBRUSH hbrBackground;
Win32_LPCWSTR lpszMenuName;
Win32_LPCWSTR lpszClassName;
Win32_HICON hIconSm;
}
struct Win32_MSG
{
Win32_HWND hwnd;
Win32_UINT message;
Win32_WPARAM wParam;
Win32_LPARAM lParam;
Win32_DWORD time;
Win32_POINT pt;
Win32_DWORD lPrivate;
}
struct Win32_PAINTSTRUCT
{
Win32_HDC hdc;
Win32_BOOL fErase;
Win32_RECT rcPaint;
Win32_BOOL fRestore;
Win32_BOOL fIncUpdate;
Win32_BYTE[32] rgbReserved;
}
def Win32_PWNDCLASSEXW = Win32_WNDCLASSEXW*;
def Win32_LPWNDCLASSEXW = Win32_WNDCLASSEXW*;
def Win32_NPWNDCLASSEXW = Win32_WNDCLASSEXW*;
def Win32_PPAINTSTRUCT = Win32_PAINTSTRUCT*;
def Win32_LPPAINTSTRUCT = Win32_PAINTSTRUCT*;
def Win32_NPPAINTSTRUCT = Win32_PAINTSTRUCT*;
def Win32_PMSG = Win32_MSG*;
def Win32_LPMSG = Win32_MSG*;
def Win32_NPMSG = Win32_MSG*;
def Win32_ATOM = ushort;
const Win32_DWORD WS_BORDER = 0x00800000L;
const Win32_DWORD WS_CAPTION = 0x00C00000L;
const Win32_DWORD WS_CHILD = 0x40000000L;
const Win32_DWORD WS_CHILDWINDOW = 0x40000000L;
const Win32_DWORD WS_CLIPCHILDREN = 0x02000000L;
const Win32_DWORD WS_CLIPSIBLINGS = 0x04000000L;
const Win32_DWORD WS_DISABLED = 0x08000000L;
const Win32_DWORD WS_DLGFRAME = 0x00400000L;
const Win32_DWORD WS_GROUP = 0x00020000L;
const Win32_DWORD WS_HSCROLL = 0x00100000L;
const Win32_DWORD WS_ICONIC = 0x20000000L;
const Win32_DWORD WS_MAXIMIZE = 0x01000000L;
const Win32_DWORD WS_MAXIMIZEBOX = 0x00010000L;
const Win32_DWORD WS_MINIMIZE = 0x20000000L;
const Win32_DWORD WS_MINIMIZEBOX = 0x00020000L;
const Win32_DWORD WS_OVERLAPPED = 0x00000000L;
const Win32_DWORD WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
const Win32_DWORD WS_POPUP = 0x80000000L;
const Win32_DWORD WS_POPUPWINDOW = WS_POPUP | WS_BORDER | WS_SYSMENU;
const Win32_DWORD WS_SIZEBOX = 0x00040000L;
const Win32_DWORD WS_SYSMENU = 0x00080000L;
const Win32_DWORD WS_TABSTOP = 0x00010000L;
const Win32_DWORD WS_THICKFRAME = 0x00040000L;
const Win32_DWORD WS_TILED = 0x00000000L;
const Win32_DWORD WS_TILEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
const Win32_DWORD WS_VISIBLE = 0x10000000L;
const Win32_DWORD WS_VSCROLL = 0x00200000L;
const Win32_UINT MB_OK = 0x00000000;
const Win32_UINT MB_OKCANCEL = 0x00000001;
const Win32_UINT MB_ABORTRETRYIGNORE = 0x00000002;
const Win32_UINT MB_YESNOCANCEL = 0x00000003;
const Win32_UINT MB_YESNO = 0x00000004;
const Win32_UINT MB_RETRYCANCEL = 0x00000005;
const Win32_UINT MB_CANCELTRYCONTINUE = 0x00000006;
const Win32_UINT MB_ICONHAND = 0x00000010;
const Win32_UINT MB_ICONQUESTION = 0x00000020;
const Win32_UINT MB_ICONEXCLAMATION = 0x00000030;
const Win32_UINT MB_ICONASTERISK = 0x00000040;
const Win32_UINT MB_USERICON = 0x00000080;
const Win32_UINT MB_ICONWARNING = MB_ICONEXCLAMATION;
const Win32_UINT MB_ICONERROR = MB_ICONHAND;
const Win32_UINT MB_ICONINFORMATION = MB_ICONASTERISK;
const Win32_UINT MB_ICONSTOP = MB_ICONHAND;
const GWL_WNDPROC @if(env::ARCH_32_BIT) = -4;
const GWL_HINSTANCE @if(env::ARCH_32_BIT) = -6;
const GWL_HWNDPARENT @if(env::ARCH_32_BIT) = -8;
const GWL_STYLE = -16;
const GWL_EXSTYLE = -20;
const GWL_USERDATA @if(env::ARCH_32_BIT) = -21;
const GWL_ID = -12;
const GWLP_WNDPROC = -4;
const GWLP_HINSTANCE = -6;
const GWLP_HWNDPARENT = -8;
const GWLP_USERDATA = -21;
const GWLP_ID = -12;
extern fn Win32_HDC beginPaint(Win32_HWND, Win32_LPPAINTSTRUCT) @extern("BeginPaint");
extern fn Win32_LRESULT callWindowProcW(Win32_WNDPROC lpPrevWndFunc, Win32_HWND hWnd, Win32_UINT msg, Win32_WPARAM wParam, Win32_LPARAM lParam) @extern("CallWindowProcW");
extern fn Win32_HWND createWindowExW(Win32_DWORD, Win32_LPCWSTR, Win32_LPCWSTR, Win32_DWORD, CInt, CInt, CInt, CInt, Win32_HWND, Win32_HMENU, Win32_HINSTANCE, Win32_LPVOID) @extern("CreateWindowExW");
extern fn Win32_LRESULT defWindowProcW(Win32_HWND, Win32_UINT, Win32_WPARAM, Win32_LPARAM) @extern("DefWindowProcW");
extern fn Win32_BOOL dispatchMessage(Win32_MSG* lpMsg) @extern("DispatchMessageW");
extern fn Win32_BOOL endPaint(Win32_HWND, Win32_LPPAINTSTRUCT) @extern("EndPaint");
extern fn Win32_BOOL getMessageW(Win32_LPMSG, Win32_HWND, Win32_UINT, Win32_UINT) @extern("GetMessageW");
extern fn Win32_BOOL getUpdateRect(Win32_HWND hWnd, Win32_LPRECT lpRect, Win32_BOOL bErase) @extern("GetUpdateRect");
extern fn Win32_LONG_PTR getWindowLongPtrW(Win32_HWND hWnd, CInt nIndex) @extern("GetWindowLongPtrW");
extern fn Win32_LONG getWindowLongW(Win32_HWND hWnd, CInt nIndex) @extern("GetWindowLongW");
extern fn Win32_HCURSOR loadCursorW(Win32_HINSTANCE instance, Win32_LPCWSTR cursorName) @extern("LoadCursorW");
extern fn Win32_HICON loadIconW(Win32_HINSTANCE instance, Win32_LPCWSTR iconName) @extern("LoadIconW");
extern fn int messageBoxW(Win32_HWND hWnd, Win32_LPCWSTR lpText, Win32_LPCWSTR lpCaption, Win32_UINT uType) @extern("MessageBoxW");
extern fn void postQuitMessage(CInt) @extern("PostQuitMessage");
extern fn Win32_ATOM registerClassExW(Win32_WNDCLASSEXW*) @extern("RegisterClassExW");
extern fn Win32_LONG_PTR setWindowLongPtrW(Win32_HWND hWnd, CInt nIndex, Win32_LONG_PTR dwNewLong) @extern("SetWindowLongPtrW");
extern fn Win32_LONG setWindowLongW(Win32_HWND hWnd, CInt nIndex, Win32_LONG dwNewLong) @extern("SetWindowLongW");
extern fn Win32_BOOL showWindow(Win32_HWND, CInt) @extern("ShowWindow");
extern fn Win32_BOOL translateMessage(Win32_MSG* lpMsg) @extern("TranslateMessage");
extern fn Win32_BOOL updateWindow(Win32_HWND) @extern("UpdateWindow");
macro getWindowLongPtr(Win32_HWND hWnd, CInt nIndex)
{
$if env::ARCH_64_BIT:
return getWindowLongPtrW(hWnd, nIndex);
$else
return getWindowLongW(hWnd, nIndex);
$endif
}
macro setWindowLongPtr(Win32_HWND hWnd, CInt nIndex, dwNewLong)
{
$if env::ARCH_64_BIT:
return setWindowLongPtrW(hWnd, nIndex, dwNewLong);
$else
return setWindowLongW(hWnd, nIndex, dwNewLong);
$endif
}

View File

@@ -32,8 +32,6 @@ extern fn CInt win32_WSAPoll(Win32_LPWSAPOLLFD fdArray, Win32_ULONG fds, Win32_I
extern fn WSAError win32_WSAGetLastError() @extern("WSAGetLastError") @builtin;
extern fn void win32_WSASetLastError(WSAError error) @extern("WSASetLastError") @builtin;
extern fn CInt win32_WSAStartup(Win32_WORD, void*) @extern("WSAStartup") @builtin;
extern fn CInt win32_WSACleanup() @extern("WSACleanup") @builtin;
const int FIONBIO = -2147195266;
const int FIONREAD = 1074030207;
const int SIOCATMARK = 1074033415;

View File

@@ -3,20 +3,17 @@ module std::sort;
/**
* Perform a binary search over the sorted array and return the index
* in [0, array.len) where x would be inserted or cmp(i) is true and cmp(j) is true for j in [i, array.len).
* @require @is_sortable(list) "The list must be sortable"
* @require @is_valid_cmp_fn(cmp, list, context) "Expected a comparison function which compares values"
* @require @is_valid_context(cmp, context) "Expected a valid context"
* @require $defined(list[0]) && $defined(list.len) "The list must be indexable"
* @require $or(@typeid(cmp) == void*.typeid, @is_comparer(cmp, list)) "Expected a comparison function which compares values"
**/
macro usz binarysearch(list, x, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLOT) @builtin
macro usz binarysearch(list, x, cmp = null) @builtin
{
usz i;
usz len = @len_from_list(list);
var $no_cmp = @is_empty_macro_slot(cmp);
var $has_context = @is_valid_macro_slot(context);
for (usz j = len; i < j;)
{
usz half = i + (j - i) / 2;
$if $no_cmp:
$if @typeid(cmp) == void*.typeid:
switch
{
case greater(list[half], x): j = half;
@@ -24,20 +21,11 @@ macro usz binarysearch(list, x, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SL
default: return half;
}
$else
$switch
$case $defined(cmp(list[0], list[0], context)):
int res = cmp(list[half], x, context);
$case $defined(cmp(list[0], list[0])):
assert(!$has_context);
$case $typeof(cmp).params[0] == @typeid(list[0]):
int res = cmp(list[half], x);
$case $defined(cmp(&list[0], &list[0], context)):
int res = cmp(&list[half], &x, context);
$case $defined(cmp(&list[0], &list[0])):
assert(!$has_context);
int res = cmp(&list[half], &x);
$default:
assert(false, "Invalid comparison function");
int res = cmp(&list[half], &x);
$endswitch
switch
{

View File

@@ -1,181 +0,0 @@
module std::sort;
import std::sort::is;
import std::sort::cs;
import std::sort::qs;
/**
* Sort list using the counting sort algorithm.
* @require @is_sortable(list) "The list must be indexable and support .len or .len()"
* @require @is_cmp_key_fn(key_fn, list) "Expected a transformation function which returns an unsigned integer."
**/
macro countingsort(list, key_fn = EMPTY_MACRO_SLOT) @builtin
{
usz len = sort::@len_from_list(list);
cs::csort(<$typeof(list), $typeof(key_fn)>)(list, 0, len, key_fn, ~((uint)0));
}
macro insertionsort_indexed(list, start, end, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLOT) @builtin
{
is::isort(<$typeof(list), $typeof(cmp), $typeof(context)>)(list, (usz)start, (usz)end, cmp, context);
}
macro quicksort_indexed(list, start, end, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLOT) @builtin
{
qs::qsort(<$typeof(list), $typeof(cmp), $typeof(context)>)(list, (isz)start, (isz)(end-1), cmp, context);
}
module std::sort::cs(<Type, KeyFn>);
def Counts = usz[256] @private;
def Ranges = usz[257] @private;
def Indexs = char[256] @private;
def ElementType = $typeof(Type{}[0]);
const bool NO_KEY_FN @private = types::is_same(KeyFn, EmptySlot);
const bool KEY_BY_VALUE @private = NO_KEY_FN ||| $assignable(Type{}[0], $typefrom(KeyFn.params[0]));
const bool LIST_HAS_REF @private = $defined(&Type{}[0]);
def KeyFnReturnType = $typefrom(KeyFn.returns) @if(!NO_KEY_FN);
def KeyFnReturnType = ElementType @if(NO_KEY_FN);
def CmpCallback = fn int(ElementType, ElementType) @if(KEY_BY_VALUE && NO_KEY_FN);
def CmpCallback = fn int(ElementType*, ElementType*) @if(!KEY_BY_VALUE && NO_KEY_FN);
def CmpCallback = fn int(ElementType, ElementType, KeyFn) @if(KEY_BY_VALUE && !NO_KEY_FN);
def CmpCallback = fn int(ElementType*, ElementType*, KeyFn) @if(!KEY_BY_VALUE && !NO_KEY_FN);
fn void csort(Type list, usz low, usz high, KeyFn key_fn, uint byte_idx)
{
if (high <= low) return;
$if NO_KEY_FN:
CmpCallback compare_fn = fn (lhs, rhs) => compare_to(lhs, rhs);
$else
CmpCallback compare_fn = fn (lhs, rhs, key_fn) => compare_to(key_fn(lhs), key_fn(rhs));
$endif;
byte_idx = byte_idx >= KeyFnReturnType.sizeof ? KeyFnReturnType.sizeof - 1 : byte_idx;
Counts counts;
Ranges ranges;
Indexs indexs;
KeyFnReturnType mn = ~(KeyFnReturnType)0;
KeyFnReturnType mx = 0;
char last_key = 0;
char keys_ordered = 1;
for (usz i = low; i < high; i++)
{
$switch
$case NO_KEY_FN:
KeyFnReturnType k = list[i];
$case KEY_BY_VALUE:
KeyFnReturnType k = key_fn(list[i]);
$case LIST_HAS_REF:
KeyFnReturnType k = key_fn(&list[i]);
$default:
KeyFnReturnType k = key_fn(&&list[i]);
$endswitch;
char key_byte = (char)((k >> (byte_idx * 8)) & 0xff);
++counts[key_byte];
mn = k < mn ? k : mn;
mx = k > mx ? k : mx;
keys_ordered = keys_ordered & (char)(key_byte >= last_key);
last_key = key_byte;
}
KeyFnReturnType diff = mx - mn;
if (diff == 0) return;
ushort fallback0_count = 0;
ushort fallback1_count = 0;
ushort recursion_count = 0;
usz total = 0;
foreach (char i, count : counts)
{
indexs[fallback0_count] = i;
indexs[255 - recursion_count] = i;
fallback0_count += (ushort)(count > 1 && count <= 32);
recursion_count += (ushort)(count > 128);
counts[i] = total;
ranges[i] = total;
total += count;
}
ranges[256] = total;
ushort remaining_indexs = 256 - (fallback0_count + recursion_count);
for(ushort i = 0; (i < 256) && remaining_indexs; i++) {
indexs[fallback0_count + fallback1_count] = (char)i;
usz count = ranges[i + 1] - ranges[i];
ushort within_fallback1_range = (ushort)(count > 32 && count <= 128);
fallback1_count += within_fallback1_range;
remaining_indexs -= within_fallback1_range;
}
if (!keys_ordered)
{
usz sorted_count = 0;
do
{
foreach (x, s : counts)
{
usz e = ranges[x + 1];
sorted_count += (e - s);
for (; s < e; s++)
{
$switch
$case NO_KEY_FN:
KeyFnReturnType k = list[low + s];
$case KEY_BY_VALUE:
KeyFnReturnType k = key_fn(list[low + s]);
$case LIST_HAS_REF:
KeyFnReturnType k = key_fn(&list[low + s]);
$default:
KeyFnReturnType k = key_fn(&&list[low + s]);
$endswitch;
char k_idx = (char)(k >> (byte_idx * 8));
usz target_idx = counts[k_idx];
@swap(list[low + s], list[low + target_idx]);
counts[k_idx]++;
}
}
} while (sorted_count < ranges[256]);
}
if (byte_idx)
{
for (usz p = 0; p < fallback0_count; p++) {
usz i = indexs[p];
usz start_offset = ranges[i];
usz end_offset = ranges[i + 1];
insertionsort_indexed(list, low + start_offset, low + end_offset, compare_fn, key_fn);
}
for (usz p = 0; p < fallback1_count; p++) {
usz i = indexs[fallback0_count + p];
usz start_offset = ranges[i];
usz end_offset = ranges[i + 1];
quicksort_indexed(list, low + start_offset, low + end_offset, compare_fn, key_fn);
}
for (usz p = 0; p < recursion_count; p++)
{
usz i = indexs[255 - p];
usz start_offset = ranges[i];
usz end_offset = ranges[i + 1];
csort(list, low + start_offset, low + end_offset, key_fn, byte_idx - 1);
}
}
}

View File

@@ -1,65 +0,0 @@
module std::sort;
import std::sort::is;
/**
* Sort list using the quick sort algorithm.
* @require @is_sortable(list) "The list must be indexable and support .len or .len()"
* @require @is_valid_cmp_fn(cmp, list, context) "Expected a comparison function which compares values"
**/
macro insertionsort(list, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLOT) @builtin
{
usz len = sort::@len_from_list(list);
is::isort(<$typeof(list), $typeof(cmp), $typeof(context)>)(list, 0, (isz)len, cmp, context);
}
module std::sort::is(<Type, CmpFn, Context>);
def ElementType = $typeof(Type{}[0]);
fn void isort(Type list, usz low, usz high, CmpFn comp, Context context)
{
var $has_cmp = @is_valid_macro_slot(comp);
var $has_context = @is_valid_macro_slot(context);
var $cmp_by_value = $has_cmp &&& $assignable(list[0], $typefrom(CmpFn.params[0]));
var $has_get_ref = $defined(&list[0]);
for (usz i = low; i < high; ++i)
{
usz j = i;
for (;j > low;)
{
$if $has_get_ref:
ElementType *rhs = &list[j];
ElementType *lhs = &list[--j];
$switch
$case $cmp_by_value && $has_context:
if (comp(*rhs, *lhs, context) >= 0) break;
$case $cmp_by_value:
if (comp(*rhs, *lhs) >= 0) break;
$case $has_cmp && $has_context:
if (comp(rhs, lhs, context) >= 0) break;
$case $has_cmp:
if (comp(rhs, lhs) >= 0) break;
$default:
if (!less(*rhs, *lhs)) break;
$endswitch
@swap(*rhs, *lhs);
$else
usz r = j;
--j;
$switch
$case $cmp_by_value && $has_context:
if (comp(list[r], list[j], context) >= 0) break;
$case $cmp_by_value:
if (comp(list[r], list[j]) >= 0) break;
$case $has_cmp && $has_context:
if (comp(&list[r], &list[j], context) >= 0) break;
$case $has_cmp:
if (comp(&list[r], &list[j]) >= 0) break;
$default:
if (!less(list[r], list[j])) break;
$endswitch
@swap(list[r], list[j]);
$endif
}
}
}

View File

@@ -3,17 +3,18 @@ import std::sort::qs;
/**
* Sort list using the quick sort algorithm.
* @require @is_sortable(list) "The list must be indexable and support .len or .len()"
* @require @is_valid_cmp_fn(cmp, list, context) "Expected a comparison function which compares values"
* @require @is_valid_context(cmp, context) "Expected a valid context"
* @require $defined(list[0]) && $defined(list.len) "The list must be indexable and support .len or .len()"
* @require $or(@typeid(cmp) == void*.typeid, @is_comparer(cmp, list)) "Expected a comparison function which compares values"
**/
macro quicksort(list, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLOT) @builtin
macro quicksort(list, cmp = null) @builtin
{
var $Type = $typeof(list);
var $CmpType = $typeof(cmp);
usz len = sort::@len_from_list(list);
qs::qsort(<$typeof(list), $typeof(cmp), $typeof(context)>)(list, 0, (isz)len - 1, cmp, context);
qs::qsort(<$Type, $CmpType>)(list, 0, (isz)len - 1, cmp);
}
module std::sort::qs(<Type, CmpFn, Context>);
module std::sort::qs(<Type, Comparer>);
def ElementType = $typeof(Type{}[0]);
@@ -27,12 +28,10 @@ def Stack = StackElementItem[64] @private;
// Based on https://alienryderflex.com/quicksort by Darel Rex Finley, Public Domain.
fn void qsort(Type list, isz low, isz high, CmpFn cmp, Context context)
fn void qsort(Type list, isz low, isz high, Comparer cmp)
{
var $has_cmp = @is_valid_macro_slot(cmp);
var $has_context = @is_valid_macro_slot(context);
var $cmp_by_value = $has_cmp &&& $assignable(list[0], $typefrom(CmpFn.params[0]));
var $no_cmp = Comparer.typeid == void*.typeid;
var $cmp_by_value = $and(!$no_cmp, Comparer.params[0] == @typeid(list[0]));
if (low >= 0 && high >= 0 && low < high)
{
Stack stack;
@@ -52,25 +51,20 @@ fn void qsort(Type list, isz low, isz high, CmpFn cmp, Context context)
while (l < h)
{
$switch
$case $cmp_by_value && $has_context:
while (cmp(list[h], pivot, context) >= 0 && l < h) h--;
if (l < h) list[l++] = list[h];
while (cmp(list[l], pivot, context) <= 0 && l < h) l++;
$case $cmp_by_value:
while (cmp(list[h], pivot) >= 0 && l < h) h--;
if (l < h) list[l++] = list[h];
while (cmp(list[l], pivot) <= 0 && l < h) l++;
$case $has_cmp && $has_context:
while (cmp(&list[h], &pivot, context) >= 0 && l < h) h--;
if (l < h) list[l++] = list[h];
while (cmp(&list[l], &pivot, context) <= 0 && l < h) l++;
$case $has_cmp:
$case !$no_cmp:
while (cmp(&list[h], &pivot) >= 0 && l < h) h--;
if (l < h) list[l++] = list[h];
while (cmp(&list[l], &pivot) <= 0 && l < h) l++;
$default:
while (greater_eq(list[h], pivot) && l < h) h--;
if (l < h) list[l++] = list[h];
$endswitch
if (l < h) list[l++] = list[h];
$switch
$case $cmp_by_value:
while (cmp(list[l], pivot) <= 0 && l < h) l++;
$case !$no_cmp:
while (cmp(&list[l], &pivot) <= 0 && l < h) l++;
$default:
while (less_eq(list[l], pivot) && l < h) l++;
$endswitch
if (l < h) list[h--] = list[l];

View File

@@ -1,5 +1,6 @@
module std::sort;
macro usz @len_from_list(&list)
{
$if $defined(list.len()):
@@ -9,48 +10,24 @@ macro usz @len_from_list(&list)
$endif
}
macro bool @is_sortable(#list)
macro bool @is_comparer(#cmp, #list)
{
$switch
$case !$defined(#list[0]):
var $params = $typeof(#cmp).params;
$if $params.len != 2:
return false;
$else
$if $params[0] != $params[1]:
return false;
$case !$defined(#list.len):
return false;
$case $defined(&#list[0]) &&& !types::is_same($typeof(&#list[0]), $typeof(#list[0])*):
return false;
$default:
return true;
$endswitch
}
macro bool @is_valid_context(#cmp, #context)
{
return @is_valid_macro_slot(#cmp) || @is_empty_macro_slot(#context);
}
macro bool @is_valid_cmp_fn(#cmp, #list, #context)
{
var $Type = $typeof(#cmp);
var $no_context = @is_empty_macro_slot(#context);
$switch
$case @is_empty_macro_slot(#cmp): return true;
$case $Type.kindof != FUNC ||| $Type.returns.kindof != SIGNED_INT: return false;
$case $defined(#cmp(#list[0], #list[0], #context)): return true;
$case $defined(#cmp(#list[0], #list[0])): return $no_context;
$case $defined(#cmp(&#list[0], &#list[0], #context)): return true;
$case $defined(#cmp(&#list[0], &#list[0])): return $no_context;
$default: return false;
$endswitch
}
macro bool @is_cmp_key_fn(#key_fn, #list)
{
$switch
$case @is_empty_macro_slot(#key_fn): return true;
$case $typeof(#key_fn).kindof != FUNC: return false;
$case $typeof(#key_fn).returns.kindof != UNSIGNED_INT: return false;
$case $defined(#key_fn(#list[0])): return true;
$case $defined(#key_fn(&&(#list[0]))): return true;
$default: return false;
$endswitch
$else
var $element = @typeid(#list[0]);
$switch
$case $element == $params[0]:
return true;
$case $and($params[0].kindof == POINTER, $params[0].inner == $element):
return true;
$default:
return false;
$endswitch
$endif
$endif
}

View File

@@ -62,7 +62,7 @@ fn void! NativeMutex.lock_timeout(&self, ulong ms)
{
if (!ms) break;
ulong sleep = min(5, ms);
if (!libc::nanosleep(&&time::ms(ms).to_timespec(), null)) return ThreadFault.LOCK_FAILED?;
if (!libc::nanosleep(&& TimeSpec { .s = 0, .ns = (CLong)sleep * 1000_000 }, null)) return ThreadFault.LOCK_FAILED?;
ms -= sleep;
}
switch (result)
@@ -128,9 +128,8 @@ fn void! NativeConditionVariable.wait_timeout(&cond, NativeMutex* mtx, ulong ms)
{
TimeSpec now;
if (libc::timespec_get(&now, libc::TIME_UTC) != libc::TIME_UTC) return ThreadFault.WAIT_FAILED?;
now.s += (Time_t)(ms / 1000);
now.ns += (CLong)((ms % 1000) * 1000_000);
now.s += (Time_t)(ms / 1000 + now.ns / 1000_000_000);
now.ns = now.ns % 1000_000_000;
switch (posix::pthread_cond_timedwait(cond, &mtx.mutex, &now))
{
case errno::ETIMEDOUT:

View File

@@ -90,9 +90,8 @@ fn void! NativeMutex.lock(&mtx)
/**
* @require mtx.timed "Only available for timed locks"
**/
fn void! NativeMutex.lock_timeout(&mtx, ulong ms)
fn void! NativeMutex.lock_timeout(&mtx, usz ms)
{
if (ms > uint.max) ms = uint.max;
switch (win32::waitForSingleObject(mtx.handle, (uint)ms))
{
case win32::WAIT_OBJECT_0:
@@ -245,10 +244,9 @@ fn void! NativeConditionVariable.wait(&cond, NativeMutex* mtx) @inline
return timedwait(cond, mtx, win32::INFINITE) @inline;
}
fn void! NativeConditionVariable.wait_timeout(&cond, NativeMutex* mtx, ulong ms) @inline
fn void! NativeConditionVariable.wait_timeout(&cond, NativeMutex* mtx, uint time) @inline
{
if (ms > uint.max) ms = uint.max;
return timedwait(cond, mtx, (uint)ms) @inline;
return timedwait(cond, mtx, time) @inline;
}
fn void! NativeThread.create(&thread, ThreadFn func, void* args)

View File

@@ -53,9 +53,9 @@ macro void! ConditionVariable.wait(&cond, Mutex* mutex)
{
return NativeConditionVariable.wait((NativeConditionVariable*)cond, (NativeMutex*)mutex);
}
macro void! ConditionVariable.wait_timeout(&cond, Mutex* mutex, ulong ms)
macro void! ConditionVariable.wait_timeout(&cond, Mutex* mutex, ulong timeout)
{
return NativeConditionVariable.wait_timeout((NativeConditionVariable*)cond, (NativeMutex*)mutex, ms);
return NativeConditionVariable.wait_timeout((NativeConditionVariable*)cond, (NativeMutex*)mutex, timeout);
}

View File

@@ -1,6 +1,5 @@
module std::time::os @if(env::WIN32);
import std::os::win32;
import std::math;
extern fn void win32_GetSystemTimeAsFileTime(Win32_FILETIME* time) @extern("GetSystemTimeAsFileTime");
extern fn Win32_BOOL win32_QueryPerformanceFrequency(Win32_LARGE_INTEGER* lpFrequency) @extern("QueryPerformanceFrequency");
@@ -9,19 +8,16 @@ extern fn Win32_BOOL win32_QueryPerformanceCounter(Win32_LARGE_INTEGER* lpPerfor
const ulong WINDOWS_TICK_US @local = 10;
const ulong WIN_TO_UNIX_EPOCH_US @local = 116444736000000000u64 / WINDOWS_TICK_US;
fn Clock native_clock()
{
static Win32_LARGE_INTEGER freq;
static ulong div = 0;
ulong mult = 0;
if (!freq.quadPart)
{
if (!win32_QueryPerformanceFrequency(&freq)) return 0;
}
Win32_LARGE_INTEGER counter @noinit;
if (!win32_QueryPerformanceCounter(&counter)) return 0;
return (Clock)counter.quadPart.muldiv(1_000_000_000, freq.quadPart);
return (Clock)counter.quadPart;
}
fn Time native_timestamp()

View File

@@ -6,7 +6,6 @@ distinct Duration = long;
distinct Clock = ulong;
distinct NanoDuration (Printable) = long;
const Duration US = 1;
const Duration MS = 1_000;
const Duration SEC = 1_000_000;
const Duration MIN = 60 * SEC;
@@ -16,7 +15,6 @@ const Duration WEEK = 7 * DAY;
const Duration MONTH = 30 * WEEK;
const Duration YEAR = 36525 * DAY / 100;
fn Duration us(long l) @inline => (Duration)l * US;
fn Duration ms(long l) @inline => (Duration)l * MS;
fn Duration sec(long l) @inline => (Duration)l * SEC;
fn Duration min(long l) @inline => (Duration)l * MIN;

View File

@@ -10,26 +10,15 @@ import json
import shutil
import hashlib
import zipfile
import tempfile
import argparse
import subprocess
import urllib.request
import os
import ssl
import tempfile
from pathlib import Path
if (platform.system() == "Windows"):
print("Creating msvc_sdk for compilation without VS.")
else:
print("Creating msvc_sdk for cross platform compilation to Windows.")
OUTPUT = Path(tempfile.mkdtemp()) # output folder
OUTPUT = Path("msvc_temp") # output folder
SDK_OUTPUT = Path("msvc_sdk")
if (not os.environ.get('PYTHONHTTPSVERIFY', '') and
getattr(ssl, '_create_unverified_context', None)):
ssl._create_default_https_context = ssl._create_unverified_context
MANIFEST_URL = "https://aka.ms/vs/17/release/channel"
def download(url):
@@ -68,6 +57,7 @@ def get_msi_cabs(msi):
def first(items, cond):
return next(item for item in items if cond(item))
### parse command-line arguments
@@ -145,7 +135,9 @@ if not args.accept_license:
if not accept or accept[0].lower() != "y":
exit(0)
shutil.rmtree(OUTPUT, ignore_errors = True)
shutil.rmtree(SDK_OUTPUT, ignore_errors = True)
OUTPUT.mkdir()
total_download = 0
### download Windows SDK
@@ -165,7 +157,7 @@ for arch in archs:
msvc_packages.append(f"microsoft.vc.{msvc_ver}.crt.{arch}.desktop.base")
msvc_packages.append(f"microsoft.vc.{msvc_ver}.crt.{arch}.store.base")
msvc_packages.append(f"microsoft.vc.{msvc_ver}.asan.{arch}.base")
for pkg in msvc_packages:
p = first(packages[pkg], lambda p: p.get("language") in (None, "en-US"))
for payload in p["payloads"]:
@@ -234,10 +226,15 @@ lib = list((OUTPUT / "VC/Tools/MSVC/").glob("*/lib"))[0]
SDK_OUTPUT.mkdir(exist_ok=True)
for arch in archs:
out_dir = SDK_OUTPUT / arch
shutil.copytree(ucrt / arch, out_dir, dirs_exist_ok=True)
shutil.copytree(um / arch, out_dir, dirs_exist_ok=True)
shutil.copytree(um / arch, out_dir, dirs_exist_ok=True)
shutil.copytree(lib / arch, out_dir, dirs_exist_ok=True)
print("Congratulations! The 'msvc_sdk' directory was successfully generated.")
### cleanup
shutil.rmtree(OUTPUT, ignore_errors=True)

View File

@@ -1,169 +1,5 @@
# C3C Release Notes
## 0.6.2 Change list
### Changes / improvements
- Updated LLVM passes
- Added `is_substruct` type property.
- Scalar -> vector not implicit in call or assign.
- Added `--vector-conv` to enable the old scalar->vector conversion behaviour.
- Added "weak" type aliases `def Foo = my_foo::Foo @weak;`
- `*-add` keys in targets in `manifest.json` and `project.json` are deprecated.
- Made "add" the default for things like `sources`, `dependencies` and other keys in project and library files.
- Give some symbol name suggestions when the path is matched.
- Don't generate .o files on `compile` and `compile-run` if there is no `main`.
- c3c init-lib does not create the directory with the .c3l suffix #1253
- Permit foreach values to be optional.
- Add `--show-backtrace` option to disable backtrace for even smaller binary.
- Untested Xtensa support.
- && doesn't work correctly with lambdas #1279.
- Fix incorrect override of optimization levels when using projects.
- Add experimental `@noalias` attribute.
- Add a `--run-once` option to delete the output file after running it.
- Add `@const` attribute for macros, for better error messages with constant macros.
- Add `wincrt` setting to libraries.
- Add `+++` `&&&` `|||` as replacement for `$concat`, `$and` and `$or`.
- Add `methodsof` to type info for struct, union and bitstruct.
- Added `@tag` `tagof` and `has_tagof` to user defined types and members.
- Added `c-include-dirs` project/manifest setting.
- The compiler now skips UTF8 BOM.
- Printable values passed to the Formatter as pointers, will print as if passed by value.
- Pointers are rendered with "0x" prefix when passed to '%s'.
- Add temp allocator scribble.
- Use PIC by default on Linux.
- `$exec` may now provide a stdin parameter.
- Introduce `$vaarg[...]` syntax and deprecate the old `$vaarg(...)`.
- Similar change to `$vasplat`: `$vasplat` and `$vasplat[1..]`.
- Add `$member.get(value)` to replace `value.$eval($member.nameof)`
### Fixes
- Broken WASM library code.
- Regression: Invalid is_random implementation due to changes in 0.6.
- `dbghelp.lib` was linked even on nolibc on Windows.
- Fix incorrect linker selection on some platforms.
- Struct members declared in a single line declaration were not sharing attributes. #1266
- `opt` project setting now properly documented.
- Incorrect justify formatting of integers.
- Assertion with duplicate function pointer signatures #1286
- Distinct func type would not accept direct function address assign. #1287
- Distinct inline would not implement protocol if the inlined implemented it. #1292
- Distinct inline can now be called if it is aliasing a function pointer.
- Bug in List add_array when reserving memory.
- Fix issue where a compile time parameter is followed by "...".
- Fix issue with some conversions to untyped list.
- Issue where a `if (catch e = ...)` in a defer would be incorrectly copied. Causing codegen error.
- Variable in if-try / if-catch cannot be a reused variable name.
- Vararg interfaces were broken.
- LLVM codegen for constants in enums could fail.
- Fixes to the socket functions.
- Improved output when pointer is out of range.
- Better error when casting to a distinct fails.
- With single module, name the .o file after what `-o` provides. #1306
- Bitstruct members can now have attributes.
- `%` analysis was incorrect for int vectors.
- When resolving inherited interfaces, the interface type wasn't always resolved.
- Fix issues when checking methods and interfaces hasn't been resolved yet.
- Fix Vec2.angle
- Update to libc::setjmp on Win32, to do no stack unwinding.
- Recursively follow interfaces when looking up method.
- Int128 alignment change in LLVM fixed on x64.
- Fix interface lazy resolution errors.
- Interface resolution when part of generics #1348.
- Assert not properly traced #1354.
- Ordering issues with `$include` / `$exec` fixed #1302.
- Issues with wincrt linking.
- Debug info with recursive canonical type usage could cause segfault.
- Missing check on optional left hand side for `s.x`.
- Incorrect zero analysis on `foo["test"] = {}` #1360.
- Bug converting untyped list #1360.
- Benchmark / test no longer suppresses debug info. #1364.
- Bug when compile time subtracting a distinct type.
- `insert_at` incorrectly prevented inserts at the end of a list.
- Fix aligned alloc for Win32 targets.
### Stdlib changes
- `send` and `recv` added to `libc` for Posix / Win32.
- Add support to destroy temp allocators.
- Deprecated `path.append`, `path.tappend`, `getcwd`, `tgetcwd`, `path.absolute`, `ls`.
- Deprecated `env::get_config_dir`, replaced by `env::new_get_config_dir`.
- Added `path.has_extension`, `path.new_append`, `path.temp_append`, `new_cwd`, `temp_cwd`, `path.new_absolute`, `new_ls`, `temp_ls`.
- Added `dstring.replace`
- New hashmap type, `Map`
- Added `ElasticArray`.
## 0.6.1 Change list
### Changes / improvements
- Addition of $append and $concat functions.
- Added $$str_hash, $$str_upper, $$str_lower, $$str_find builtins.
- Improved error notes when call expressions have errors.
- Trailing body arguments may now be `&ref`, `#hash`, `$const` and `$Type` arguments.
- "panic-msg" setting to suppress panic message output.
- Require `@export` functions to have `@export` types.
- Disallow leading/trailing/duplicate '_' in module names.
- Updated mangling.
- Added `$$unaligned_load` and `$$unaligned_store`.
- `--no-headers` option to suppress creating headers when generating a library.
- Support c-file compilation in libraries.
- Allow using $defined(&a[1]) to check if the operation is supported.
- Max number of members in a struct is limited to 65535.
- The maximum number of parameters in a call is now 255, up from 127.
- Array comparison now uses built-in memcmp on LLVM to enable optimizations.
- Prevent implicit array casts to pointers with higher alignment #1237.
- Macro `$case` statements now pick the first match and does not evaluate the rest.
- `manifest.json` is now checked for incorrect keys.
- Added `--list-manifest-properties` to list the available properties in `manifest.json`.
- Indexing into a constant array / struct now works at compile time.
- Improved error message when trying user foreach with an untyped list.
### Fixes
- Error with unsigned compare in `@ensure` when early returning 0 #1207.
- Prevent Mach-O from removing `@init` and `@dynamic` in a more reliable way #1200.
- Fix of missing copy of parameterized custom attributes.
- Fixed crash on certain recursive function definitions #1209.
- Return the typekind "FUNC" for a function pointer.
- No longer possible to dereference a function pointer.
- Fix bug with @jump miscompile.
- Bit negate does implicit integer promotion.
- Bitstructs, unions and flexible arrays now correctly emitted in headers.
- Fix distinct inline conversions.
- Bit negating const zero flags would give an incorrect result.
- Fix to scalar -> vector conversions.
- Bug fix for rethrow + defer catch.
- Wrong size for structs containing overaligned structs #1219
- $typeof(*x) should be valid when x is an `[out]` parameter #1226
- Fix ABI lowering for 128 bit vectors on Linux.
- Bad error message when using a generic method without generic parameters #1228
- Private function called from nested macro not visible to linker #1232
- Bitstructs in structs would not be correctly be handled in some cases.
- Fix problem where a $$FUNC would return "<GLOBAL>" when evaluated for a static in a function #1236.
- `ordinal` is no longer a valid associated value name for enums.
- Constants defined by indexing into another constant could fail codegen.
- Stdlib nolibc code bugs fixed.
- Regression: duplicate symbols with static variable declared in macro #1248.
- Unsplat with named parameters was accidentally disallowed.
- Reference parameter doesn't work with vector subscript #1250.
- The msvc_sdk script failed to work properly on windows when run in folders with spaces.
- Using winmain would call the wrong definition #1265.
- DynamicArenaAllocator would not correctly free.
### Stdlib changes
- Added `remove_first_item` `remove_last_item` and `remove_item` as aliases for the `match` functions.
- Added @str_hash, @str_upper, @str_lower, @str_find compile time macros.
- Remove "panic" text from unreachable() when safe mode is turned off.
- Added `@unaligned_store` and `@unaligned_load`.
- Null ZString, DString or pointer prints "(null)" for printf.
- Updated sorting API.
- Insertion sort and counting sort added.
- Added missing `mem` and `mem::allocator` functions for aligned allocations.
- Added `new_init_with_array` and `temp_init_with_array` for List.
- Fixed posix `NativeMutex.lock_timeout`.
- Fixed `env::ARCH_32_BIT` and `env::ARCH_64_BIT`.
- Added `time::us`.
## 0.6.0 Change list
### Changes / improvements
@@ -189,12 +25,6 @@
- Introduce MSVC compatible SIMD ABI.
- `$foreach` doesn't create an implicit syntactic scope.
- Error of `@if` depends on `@if`
- Support `defer (catch err)`
- Added `print-input` command argument to print all files used for compilation
- Allow recursive function definitions as long as they are pointers. #1182
- Default CPU to native if less than AVX, otherwise use AVX.
- Bounds checking on length for `foo[1:2]` slicing #1191.
- Foreach uses non-wrapping add/dec.
### Fixes
- Fixed issue in safe mode when converting enums.
@@ -204,6 +34,30 @@
- Fix problems using reflection on interface types #1203.
- `@param` with unnamed macro varargs could crash the compiler.
- Compiler crash using enum nameof from different module #1205.
### Stdlib changes
- "init_new/init_temp" removed.
- LinkedList API rewritten.
- List "pop" and "remove" function now return Optionals.
- RingBuffer API rewritten. Allocator interface changed.
- Deprecated Allocator, DString and mem functions removed.
- "identity" functions are now constants for Matrix and Complex numbers.
- Removed 'append' from Object and List, replaced by 'push'.
- `GenericList` renamed `AnyList`.
- Proper handling of '.' and Win32 '//server' paths.
- Path normalization - fix possible null terminator out of bounds.
## 0.5.6 Change list
### Changes / improvements
- Support `defer (catch err)`
- Added `print-input` command argument to print all files used for compilation
- Allow recursive function definitions as long as they are pointers. #1182
- Default CPU to native if less than AVX, otherwise use AVX.
- Bounds checking on length for `foo[1:2]` slicing #1191.
- Foreach uses non-wrapping add/dec.
### Fixes
- Incorrect length passed to scratch buffer printf.
- Casting to a bitstruct would be allowed even if the type was the wrong size.
- Generic modules parameterized with constants would sometimes get the wrong parameterized module name causing conversion errors #1192.
@@ -217,16 +71,6 @@
- Compiler crash on designated initializer for structs with bitstruct.
### Stdlib changes
- "init_new/init_temp" removed.
- LinkedList API rewritten.
- List "pop" and "remove" function now return Optionals.
- RingBuffer API rewritten. Allocator interface changed.
- Deprecated Allocator, DString and mem functions removed.
- "identity" functions are now constants for Matrix and Complex numbers.
- Removed 'append' from Object and List, replaced by 'push'.
- `GenericList` renamed `AnyList`.
- Proper handling of '.' and Win32 '//server' paths.
- Path normalization - fix possible null terminator out of bounds.
- Add 'zstr' variants for `string::new_format` / `string::tformat`.
- Fix mutex and wait signatures for Win32.

View File

@@ -1,6 +0,0 @@
import std::io;
fn void main(String[] args)
{
io::printn(args);
}

View File

@@ -19,7 +19,7 @@ macro @with_mode(String user, #action, ...)
@scope(context_user)
{
context_user = user;
return #action($vasplat);
return #action($vasplat());
};
}

View File

@@ -1,21 +0,0 @@
SRCS_C3 := $(wildcard *.c3)
default: hello.elf
hello.a: $(SRCS_C3)
$(C3C_PATH)c3c -g --use-stdlib=no --no-entry --target elf-riscv32 static-lib $(SRCS_C3)
start.o: start.s
riscv64-unknown-elf-as -g -march=rv32i -mabi=ilp32 -misa-spec=20191213 -o start.o start.s
hello.elf: hello.a start.o baremetal.ld
riscv64-unknown-elf-ld -T baremetal.ld -m elf32lriscv -o hello.elf hello.a start.o
run: hello.elf
qemu-system-riscv32 -nographic -serial mon:stdio -machine virt -semihosting -bios hello.elf
debug: hello.elf
qemu-system-riscv32 -nographic -serial mon:stdio -machine virt -semihosting -s -S -bios hello.elf
clean:
rm -f *.o *.a hello.elf

View File

@@ -1,8 +0,0 @@
# Risc-V 32 Embedded Example With QEMU
## Prereqs
- QEMU
- Risc-V toolchain
- C3C
- Make
## Running
`make run`

View File

@@ -1,14 +0,0 @@
EXTERN(main)
SECTIONS
{
. = 0x80000000; /* QEMU default load address to run bios */
.text : {
KEEP(*(.text._start)); /* Ensure _start is placed first */
*(.text*); /* Program code here */
}
. = ALIGN (CONSTANT (COMMONPAGESIZE)); /* Make sure linker does not jam data into text section, making text writable */
.data : {
*(.data*) /* Stack goes here */
}
}

View File

@@ -1,11 +0,0 @@
import uart;
import semihost;
const UART0_BASE = 0x10000000;
fn void main() @export("main") {
Uart* uart0 = (Uart*)UART0_BASE; // Create pointer to UART 0
uart0.fcr = uart::UARTFCR_FFENA; // Enable FIFO
uart0.puts("Hello World!\n"); // Write the string to the UART
semihost::exit(0); // Semihosting call to exit host
}

View File

@@ -1,20 +0,0 @@
module semihost;
// See: https://github.com/ARM-software/abi-aa/blob/main/semihosting/semihosting.rst#sys-exit-extended-0x20
extern fn int sys_semihost(int operation, SemihostParameters* parms);
struct SemihostParameters {
int field1;
int field2;
}
const int SYS_EXIT_EXTENDED = 0x20;
const int ADP_STOPPED_APPLICATIONEXIT = 0x20026;
fn void exit(int status) {
SemihostParameters parms;
parms.field1 = ADP_STOPPED_APPLICATIONEXIT;
parms.field2 = status;
sys_semihost(SYS_EXIT_EXTENDED, &parms);
}

View File

@@ -1,29 +0,0 @@
# Simple C runtime startup bootstrap
# Two primary functions:
# - Stack allocation and initializing stack pointer
# - Jumping to main
.section .text._start
.global _start
_start:
la sp, __stack_top # Load the stack pointer
add s0, sp, zero # Set the frame pointer
jal zero, main # Run main entry point - no argc
loop: j loop # Spin forever in case main returns
# Support semi-hosting calls
.option norvc
.text
.balign 16
.global sys_semihost
.type sys_semihost @function
sys_semihost: # https://github.com/riscv-non-isa/riscv-semihosting/blob/main/src/binary-interface.adoc
slli zero, zero, 0x1f
ebreak
srai zero, zero, 0x7
ret
.section .data
.space 1024*8 # allocate 8K of memory to serve as initial stack
.align 16 # Smallest stack allocation is 16 bytes, so align accordingly
__stack_top: # The stack grows downward according the Risc-V ABI

View File

@@ -1,28 +0,0 @@
module uart;
const UARTFCR_FFENA = 0x01; // UART FIFO Control Register enable bit
const UARTLSR_THRE = 0x20; // UART Line Status Register Transmit Hold Register Empty bit
struct Uart {
char dr; // UART Data Register
char filler1;
char fcr; // FIFO Control Register
char filler2;
char filler3;
char lsr; // Line Status Register
}
fn bool Uart.uart_ff_thr_empty(Uart* this) {
return (bool)($$volatile_load(&this.lsr) & UARTLSR_THRE);
}
fn void Uart.putc(Uart* this, char c) {
while (!this.uart_ff_thr_empty()); // Wait until the FIFO holding register is empty
$$volatile_store(&this.dr, c); // Write character to transmit register
}
fn void Uart.puts(Uart* this, char *str) {
while (*str) { // Loop until value at string pointer is zero
this.putc(*str++); // Write the character and increment pointer
}
}

View File

@@ -16,8 +16,6 @@
// C sources if the project also compiles C sources
// relative to the project file.
// "c-sources": [ "csource/**" ],
// Include directories for C sources relative to the project file.
// "c-include-dirs: [ "csource/include" ],
// Output location, relative to project file.
"output": "../build",
// Architecture and OS target.

View File

@@ -40,6 +40,7 @@ int comment_level = 0;
"$alignof" { count(); return(CT_ALIGNOF); }
"$and" { count(); return(CT_AND); }
"$assert" { count(); return(CT_ASSERT); }
"$assignable" { count(); return(CT_ASSIGNABLE); }
"$case" { count(); return(CT_CASE); }
@@ -54,7 +55,6 @@ int comment_level = 0;
"$error" { count(); return(CT_ERROR); }
"$eval" { count(); return(CT_EVAL); }
"$evaltype" { count(); return(CT_EVALTYPE); }
"$exec" { count(); return(CT_EXEC); }
"$extnameof" { count(); return(CT_EXTNAMEOF); }
"$feature" { count(); return(CT_FEATURE); }
"$for" { count(); return(CT_FOR); }
@@ -195,9 +195,6 @@ b64\`{B64}\` { count(); return(BYTES); }
"!!" { count(); return(BANGBANG); }
"..." { count(); return(ELLIPSIS); }
".." { count(); return(DOTDOT); }
"&&&" { count(); return(CT_AND_OP); }
"|||" { count(); return(CT_OR_OP); }
"+++" { count(); return(CT_CONCAT_OP); }
">>=" { count(); return(SHR_ASSIGN); }
"<<=" { count(); return(SHL_ASSIGN); }
"+=" { count(); return(ADD_ASSIGN); }

View File

@@ -14,7 +14,6 @@ void yyerror(const char *s);
%token TYPE_IDENT CT_TYPE_IDENT
%token AT_TYPE_IDENT AT_IDENT CT_INCLUDE
%token STRING_LITERAL INTEGER
%token CT_AND_OP CT_OR_OP CT_CONCAT_OP CT_EXEC
%token INC_OP DEC_OP SHL_OP SHR_OP LE_OP GE_OP EQ_OP NE_OP
%token AND_OP OR_OP MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN
%token LGENPAR RGENPAR
@@ -91,7 +90,7 @@ ct_analyse
| CT_IS_CONST
;
ct_vaarg
ct_arg
: CT_VACONST
| CT_VAARG
| CT_VAREF
@@ -147,10 +146,11 @@ base_expr_assignable
| '(' expr ')'
| expr_block
| ct_call '(' flat_path ')'
| ct_vaarg '[' expr ']'
| ct_arg '(' expr ')'
| ct_analyse '(' expression_list ')'
| CT_VACOUNT
| CT_FEATURE '(' CONST_IDENT ')'
| CT_AND '(' expression_list ')'
| ct_castable '(' expr ',' type ')'
| lambda_decl compound_statement
;
@@ -333,25 +333,21 @@ try_chain_expr
and_expr
: relational_expr
| and_expr AND_OP relational_expr
| and_expr CT_AND_OP relational_expr
;
and_stmt_expr
: relational_stmt_expr
| and_stmt_expr AND_OP relational_expr
| and_stmt_expr CT_AND_OP relational_expr
;
or_expr
: and_expr
| or_expr OR_OP and_expr
| or_expr CT_OR_OP and_expr
;
or_stmt_expr
: and_stmt_expr
| or_stmt_expr OR_OP and_expr
| or_stmt_expr CT_OR_OP and_expr
;
suffix_expr
@@ -445,11 +441,11 @@ param_path
arg
: param_path '=' expr
| param_path
| type
| param_path '=' type
| expr
| CT_VASPLAT '[' range_expr ']'
| CT_VASPLAT '(' range_expr ')'
| CT_VASPLAT '(' ')'
| ELLIPSIS expr
;
@@ -535,7 +531,7 @@ base_type
| CT_TYPE_IDENT
| CT_TYPEOF '(' expr ')'
| CT_TYPEFROM '(' constant_expr ')'
| CT_VATYPE '[' constant_expr ']'
| CT_VATYPE '(' constant_expr ')'
| CT_EVALTYPE '(' constant_expr ')'
;
@@ -889,8 +885,8 @@ opt_stmt_list
switch_stmt
: SWITCH optional_label '{' switch_body '}'
| SWITCH optional_label '{' '}'
| SWITCH optional_label paren_cond opt_attributes '{' switch_body '}'
| SWITCH optional_label paren_cond opt_attributes '{' '}'
| SWITCH optional_label paren_cond '{' switch_body '}'
| SWITCH optional_label paren_cond '{' '}'
;
expression_list
@@ -1236,16 +1232,9 @@ opt_extern
| empty
;
exec_decl
: CT_EXEC '(' expr ')' opt_attributes ';'
| CT_EXEC '(' expr ',' initializer_list ')' opt_attributes ';'
| CT_EXEC '(' expr ',' initializer_list ',' expr ')' opt_attributes ';'
;
top_level
: module
| import_decl
| exec_decl
| opt_extern func_definition
| opt_extern const_declaration
| opt_extern global_declaration

View File

@@ -1,143 +0,0 @@
// WASM-4: https://wasm4.org/docs
module w4;
// ┌───────────────────────────────────────────────────────────────────────────┐
// │ │
// │ Platform Constants │
// │ │
// └───────────────────────────────────────────────────────────────────────────┘
const SCREEN_SIZE = 160;
// ┌───────────────────────────────────────────────────────────────────────────┐
// │ │
// │ Memory Addresses │
// │ │
// └───────────────────────────────────────────────────────────────────────────┘
const uint* PALETTE = (void*)0x04;
const ushort* DRAW_COLORS = (void*)0x14;
const char* GAMEPAD1 = (void*)0x16;
const char* GAMEPAD2 = (void*)0x17;
const char* GAMEPAD3 = (void*)0x18;
const char* GAMEPAD4 = (void*)0x19;
const short* MOUSE_X = (void*)0x1a;
const short* MOUSE_Y = (void*)0x1c;
const char* MOUSE_BUTTONS = (void*)0x1e;
const char* SYSTEM_FLAGS = (void*)0x1f;
const char* NETPLAY = (void*)0x20;
const char* FRAMEBUFFER = (void*)0xa0;
const BUTTON_1 = 1;
const BUTTON_2 = 2;
const BUTTON_LEFT = 16;
const BUTTON_RIGHT = 32;
const BUTTON_UP = 64;
const BUTTON_DOWN = 128;
const MOUSE_LEFT = 1;
const MOUSE_RIGHT = 2;
const MOUSE_MIDDLE = 4;
const SYSTEM_PRESERVE_FRAMEBUFFER = 1;
const SYSTEM_HIDE_GAMEPAD_OVERLAY = 2;
// ┌───────────────────────────────────────────────────────────────────────────┐
// │ │
// │ Drawing Functions │
// │ │
// └───────────────────────────────────────────────────────────────────────────┘
/* Copies pixels to the framebuffer. */
extern fn void blit(char* data, int x, int y, uint width, uint height, uint flags) @extern("blit");
/* Copies a subregion within a larger sprite atlas to the framebuffer. */
extern fn void blit_sub(char* data, int x, int y, uint width, uint height,
uint src_x, uint src_y, uint stride, uint flags) @extern("blitSub");
const BLIT_2BPP = 1;
const BLIT_1BPP = 0;
const BLIT_FLIP_X = 2;
const BLIT_FLIP_Y = 4;
const BLIT_ROTATE = 8;
/* Draws a line between two points. */
extern fn void line(int x1, int y1, int x2, int y2);
/* Draws a horizontal line. */
extern fn void hline(int x, int y, uint len);
/* Draws a vertical line. */
extern fn void vline(int x, int y, uint len);
/* Draws an oval (or circle). */
extern fn void oval(int x, int y, uint width, uint height);
/* Draws a rectangle. */
extern fn void rect(int x, int y, uint width, uint height);
/* Draws text using the built-in system font. */
extern fn void text(char* text, int x, int y) @extern("text");
// ┌───────────────────────────────────────────────────────────────────────────┐
// │ │
// │ Sound Functions │
// │ │
// └───────────────────────────────────────────────────────────────────────────┘
/* Plays a sound tone. */
extern fn void tone(uint frequency, uint duration, uint volume, uint flags);
const TONE_PULSE1 = 0;
const TONE_PULSE2 = 1;
const TONE_TRIANGLE = 2;
const TONE_NOISE = 3;
const TONE_MODE1 = 0;
const TONE_MODE2 = 4;
const TONE_MODE3 = 8;
const TONE_MODE4 = 12;
const TONE_PAN_LEFT = 16;
const TONE_PAN_RIGHT = 32;
// ┌───────────────────────────────────────────────────────────────────────────┐
// │ │
// │ Storage Functions │
// │ │
// └───────────────────────────────────────────────────────────────────────────┘
/* Reads up to `size` bytes from persistent storage into the pointer `dest`. */
extern fn uint diskr(void* dest, uint size);
/* Writes up to `size` bytes from the pointer `src` into persistent storage. */
extern fn uint diskw (void* src, uint size);
/* Prints a message to the debug console. */
extern fn void trace(char* str);
/* Prints a message to the debug console. */
extern fn void tracef(char* fmt, ...);
char[8] smiley = {
0b11000011,
0b10000001,
0b00100100,
0b00100100,
0b00000000,
0b00100100,
0b10011001,
0b11000011,
};
fn void start() @extern("start")
{}
fn void update() @extern("update")
{
DRAW_COLORS[0] = 2;
text("Hello from C3", 10, 10);
if (GAMEPAD1[0] & BUTTON_1)
{
DRAW_COLORS[0] = 4;
}
blit(&smiley, 76, 76, 8, 8, BLIT_1BPP);
text("Press X to blink", 16, 90);
}

View File

@@ -1,8 +1,6 @@
module hello_world;
import std;
import bar;
import clib;
import clib2;
fn int test_doubler(int x) @if(env::WIN32) => x * x;
extern fn int test_doubler(int) @if(!env::WIN32);
@@ -14,7 +12,6 @@ fn int main()
bar::test();
printf("Hello double: %d\n", test_doubler(11));
if ($feature(ABCD)) io::printn("ABCD");
clib::hello_from_c();
clib2::hello_from_c_zip();
return 0;
}

View File

@@ -1,3 +0,0 @@
module clib;
extern fn void hello_from_c();

View File

@@ -1,5 +0,0 @@
#include <stdio.h>
void hello_from_c(void)
{
puts("Hello from C!");
}

View File

@@ -1,15 +0,0 @@
{
"provides" : "clib",
"c-sources" : ["hello2.c", "whitespace test.c"],
"targets" : {
"macos-x64" : {
},
"macos-aarch64" : {},
"linux-x64" : {
"cflags": "-fPIE"
},
"windows-x64" : {
"c-include-dirs": ["C:\\"]
}
}
}

View File

@@ -1 +0,0 @@
#include <stdio.h>

Binary file not shown.

View File

@@ -11,31 +11,29 @@
"sources": [
"./**"
],
"dependency-search-paths": [ "./lib" ],
"dependencies": ["clib", "clib2"],
// libraries to use
"dependencies": [],
"features": ["ABCD"],
// c compiler
"cc": "cc",
// c sources
"targets": {
"hello_world": {
"type": "executable",
"cc" : "cc",
"c-sources": [
"c-sources-override": [
"./csource/**"
],
"reloc": "PIE",
]
},
"hello_world_win32": {
"type": "executable",
"c-include-dirs": [ "C:\\"],
"c-sources-override": [
]
},
"hello_world_lib": {
"type": "static-lib",
"cc" : "cc",
"c-sources": [
"c-sources-override": [
"./csource/**"
]
},

View File

@@ -3,13 +3,12 @@
// Use of this source code is governed by the GNU LGPLv3.0 license
// a copy of which can be found in the LICENSE file.
#include "../utils/lib.h"
#include "../version.h"
#include <stdint.h>
#include "../utils/lib.h"
#define MAX_BUILD_LIB_DIRS 1024
#define MAX_COMMAND_LINE_FILES 2048
#define MAX_COMMAND_LINE_RUN_ARGS 2048
#define MAX_LIB_DIRS 1024
#define MAX_FILES 2048
#define MAX_INCLUDES 2048
#define MAX_THREADS 0xFFFF
#define DEFAULT_SYMTAB_SIZE (256 * 1024)
#define DEFAULT_SWITCHRANGE_MAX_SIZE (256)
@@ -45,19 +44,11 @@ typedef enum
COMMAND_TEST,
COMMAND_UNIT_TEST,
COMMAND_PRINT_SYNTAX,
COMMAND_PROJECT,
} CompilerCommand;
typedef enum
{
SUBCOMMAND_MISSING = 0,
SUBCOMMAND_VIEW,
SUBCOMMAND_ADD
} ProjectSubcommand;
typedef enum
{
DIAG_NONE = 0, // Don't use!
DIAG_NONE = 0, // Don't use!
DIAG_WARNING_TYPE, // Don't use!
DIAG_UNUSED,
DIAG_UNUSED_PARAMETER,
@@ -133,46 +124,20 @@ typedef enum
typedef enum
{
OPTIMIZATION_NOT_SET = -1,
OPTIMIZATION_NONE = 0, // -O0
OPTIMIZATION_LESS = 1, // -O1
OPTIMIZATION_MORE = 2, // -O2
OPTIMIZATION_AGGRESSIVE = 3, // -O3
OPTIMIZATION_NONE = 0, // -O0
OPTIMIZATION_LESS = 1, // -O1
OPTIMIZATION_MORE = 2, // -O2
OPTIMIZATION_AGGRESSIVE = 3, // -O3
} OptimizationLevel;
typedef enum
{
PANIC_NOT_SET = -1,
PANIC_OFF = 0,
PANIC_ON = 1,
} PanicLevel;
typedef enum
{
SINGLE_MODULE_NOT_SET = -1,
SINGLE_MODULE_OFF = 0, // NOLINT
SINGLE_MODULE_OFF = 0,
SINGLE_MODULE_ON = 1
} SingleModule;
typedef enum
{
UNROLL_LOOPS_NOT_SET = -1,
UNROLL_LOOPS_OFF = 0,
UNROLL_LOOPS_ON = 1
} UnrollLoops;
typedef enum
{
MERGE_FUNCTIONS_NOT_SET = -1,
MERGE_FUNCTIONS_OFF = 0,
MERGE_FUNCTIONS_ON = 1
} MergeFunctions;
typedef enum
{
VECTORIZATION_NOT_SET = -1,
VECTORIZATION_OFF = 0,
VECTORIZATION_ON = 1
} AutoVectorization;
typedef enum
{
STRIP_UNUSED_NOT_SET = -1,
@@ -201,19 +166,12 @@ typedef enum
USE_STDLIB_ON = 1
} UseStdlib;
typedef enum
{
SHOW_BACKTRACE_NOT_SET = -1,
SHOW_BACKTRACE_OFF = 0,
SHOW_BACKTRACE_ON = 1
} ShowBacktrace;
typedef enum
{
SIZE_OPTIMIZATION_NOT_SET = -1,
SIZE_OPTIMIZATION_NONE = 0, // None
SIZE_OPTIMIZATION_SMALL = 1, // -Os
SIZE_OPTIMIZATION_TINY = 2, // -Oz
SIZE_OPTIMIZATION_NONE = 0, // None
SIZE_OPTIMIZATION_SMALL = 1, // -Os
SIZE_OPTIMIZATION_TINY = 2, // -Oz
} SizeOptimizationLevel;
typedef enum
@@ -233,7 +191,7 @@ typedef enum
typedef enum
{
STRUCT_RETURN_DEFAULT = -1,
STRUCT_RETURN_STACK = 0, // NOLINT
STRUCT_RETURN_STACK = 0,
STRUCT_RETURN_REG = 1
} StructReturn;
@@ -291,17 +249,9 @@ typedef enum
WIN_CRT_DEFAULT = -1,
WIN_CRT_NONE = 0,
WIN_CRT_DYNAMIC = 1,
WIN_CRT_DYNAMIC_DEBUG = 2,
WIN_CRT_STATIC = 3,
WIN_CRT_STATIC_DEBUG = 4,
WIN_CRT_STATIC = 2,
} WinCrtLinking;
typedef enum
{
VECTOR_CONV_DEFAULT = 0,
VECTOR_CONV_OLD = 1,
} VectorConv;
typedef enum
{
RELOC_DEFAULT = -1,
@@ -328,7 +278,6 @@ typedef enum
ELF_RISCV64,
ELF_X86,
ELF_X64,
ELF_XTENSA,
FREEBSD_X86,
FREEBSD_X64,
LINUX_AARCH64,
@@ -351,80 +300,38 @@ typedef enum
ARCH_OS_TARGET_LAST = WINDOWS_X64
} ArchOsTarget;
typedef enum
{
SANITIZE_NOT_SET = -1,
SANITIZE_NONE,
SANITIZE_ADDRESS,
SANITIZE_MEMORY,
SANITIZE_THREAD,
} SanitizeMode;
#define ANY_WINDOWS_ARCH_OS WINDOWS_AARCH64: case WINDOWS_X64: case MINGW_X64
typedef enum
{
TARGET_TYPE_EXECUTABLE,
TARGET_TYPE_STATIC_LIB,
TARGET_TYPE_DYNAMIC_LIB,
TARGET_TYPE_OBJECT_FILES,
TARGET_TYPE_BENCHMARK,
TARGET_TYPE_TEST,
} TargetType;
static const char *targets[6] = {
[TARGET_TYPE_EXECUTABLE] = "executable",
[TARGET_TYPE_STATIC_LIB] = "static-lib",
[TARGET_TYPE_DYNAMIC_LIB] = "dynamic-lib",
[TARGET_TYPE_BENCHMARK] = "benchmark",
[TARGET_TYPE_TEST] = "test",
[TARGET_TYPE_OBJECT_FILES] = "object-files"
};
static const char *target_desc[6] = {
[TARGET_TYPE_EXECUTABLE] = "Executable",
[TARGET_TYPE_STATIC_LIB] = "Static library",
[TARGET_TYPE_DYNAMIC_LIB] = "Dynamic library",
[TARGET_TYPE_BENCHMARK] = "benchmark suite",
[TARGET_TYPE_TEST] = "test suite",
[TARGET_TYPE_OBJECT_FILES] = "object files"
};
typedef struct BuildOptions_
{
const char *lib_dir[MAX_BUILD_LIB_DIRS];
size_t lib_dir_count;
const char *libs[MAX_BUILD_LIB_DIRS];
size_t lib_count;
const char* linker_args[MAX_BUILD_LIB_DIRS];
size_t linker_arg_count;
const char* linker_lib_dir[MAX_BUILD_LIB_DIRS];
size_t linker_lib_dir_count;
const char* linker_libs[MAX_BUILD_LIB_DIRS];
size_t linker_lib_count;
const char *lib_dir[MAX_LIB_DIRS];
int lib_dir_count;
const char *libs[MAX_LIB_DIRS];
int lib_count;
const char* linker_args[MAX_LIB_DIRS];
int linker_arg_count;
const char* linker_lib_dir[MAX_LIB_DIRS];
int linker_lib_dir_count;
const char* linker_libs[MAX_LIB_DIRS];
int linker_lib_count;
const char* std_lib_dir;
VectorConv vector_conv;
struct
{
struct {
const char *sdk;
const char *def;
WinCrtLinking crt_linking;
} win;
struct
{
struct {
const char *sysroot;
const char *min_version;
const char *sdk_version;
} macos;
struct
{
struct {
const char *crt;
const char *crtbegin;
} linuxpaths;
int build_threads;
const char **libraries_to_fetch;
const char **files;
const char **args;
const char **feature_names;
const char **removed_feature_names;
const char *output_name;
@@ -436,40 +343,25 @@ typedef struct BuildOptions_
const char *custom_linker_path;
uint32_t symtab_size;
unsigned version;
bool silence_deprecation;
CompilerBackend backend;
CompilerCommand command;
struct
{
ProjectSubcommand command;
const char *target_name;
TargetType target_type;
} project_options;
CompileOption compile_option;
TrustLevel trust_level;
DiagnosticsSeverity severity[DIAG_END_SENTINEL];
OptimizationSetting optsetting;
DebugInfo debug_info_override;
ShowBacktrace show_backtrace;
ArchOsTarget arch_os_target_override;
SafetyLevel safety_level;
PanicLevel panic_level;
SingleModule single_module;
UnrollLoops unroll_loops;
MergeFunctions merge_functions;
AutoVectorization loop_vectorization;
AutoVectorization slp_vectorization;
bool emit_llvm;
bool emit_asm;
bool benchmark_mode;
bool test_mode;
bool no_entry;
bool no_obj;
bool no_headers;
bool read_stdin;
bool print_output;
bool print_input;
bool run_once;
const char *panicfn;
const char *benchfn;
const char *testfn;
@@ -493,61 +385,57 @@ typedef struct BuildOptions_
SizeOptimizationLevel optsize;
RiscvFloatCapability riscv_float_capability;
MemoryEnvironment memory_environment;
SanitizeMode sanitize_mode;
bool print_keywords;
bool print_attributes;
bool print_builtins;
bool print_operators;
bool print_type_properties;
bool print_project_properties;
bool print_manifest_properties;
bool print_precedence;
bool print_build_settings;
bool print_linking;
bool benchmarking;
bool testing;
} BuildOptions;
typedef enum
{
TARGET_TYPE_EXECUTABLE,
TARGET_TYPE_STATIC_LIB,
TARGET_TYPE_DYNAMIC_LIB,
TARGET_TYPE_OBJECT_FILES,
TARGET_TYPE_BENCHMARK,
TARGET_TYPE_TEST,
} TargetType;
typedef struct
{
struct Library__ *parent;
ArchOsTarget arch_os;
const char *cc;
const char *cflags;
WinCrtLinking win_crt;
const char **csource_dirs;
const char **csources;
const char **cinclude_dirs;
const char **execs;
const char **link_flags;
const char **linked_libs;
const char **dependencies;
const char **depends;
} LibraryTarget;
typedef struct Library__
typedef struct
{
const char *dir;
const char *provides;
const char **dependencies;
const char **depends;
const char **execs;
const char *cc;
const char *cflags;
const char **csource_dirs;
const char **cinclude_dirs;
WinCrtLinking win_crt;
LibraryTarget *target_used;
LibraryTarget **targets;
} Library;
typedef struct
{
TargetType type;
Library **library_list;
LibraryTarget **ccompiling_libraries;
const char *name;
const char *version;
const char *langrev;
const char **source_dirs;
const char **test_source_dirs;
const char **sources;
const char **libdirs;
const char **libs;
@@ -562,7 +450,6 @@ typedef struct
const char *asm_file_dir;
const char *script_dir;
bool run_after_compile;
bool delete_after_run;
bool generate_benchmark_runner;
bool generate_test_runner;
bool benchmark_output;
@@ -579,45 +466,35 @@ typedef struct
bool testing;
bool read_stdin;
bool print_output;
bool print_input;
bool print_input;
bool print_linking;
bool no_entry;
bool kernel_build;
bool silence_deprecation;
int build_threads;
TrustLevel trust_level;
OptimizationSetting optsetting;
OptimizationLevel optlevel;
VectorConv vector_conv;
MemoryEnvironment memory_environment;
SizeOptimizationLevel optsize;
SingleModule single_module;
UseStdlib use_stdlib;
EmitStdlib emit_stdlib;
LinkLibc link_libc;
ShowBacktrace show_backtrace;
StripUnused strip_unused;
DebugInfo debug_info;
MergeFunctions merge_functions;
UnrollLoops unroll_loops;
AutoVectorization loop_vectorization;
AutoVectorization slp_vectorization;
RelocModel reloc_model;
ArchOsTarget arch_os_target;
CompilerBackend backend;
LinkerType linker_type;
uint32_t symtab_size;
uint32_t switchrange_max_size;
const char **args;
const char *panicfn;
const char *benchfn;
const char *testfn;
const char *cc;
const char *cflags;
const char **exec;
const char **csource_dirs;
const char **csources;
const char **cinclude_dirs;
const char **exec;
const char **feature_list;
const char *custom_linker_path;
struct
@@ -626,14 +503,10 @@ typedef struct
StructReturn x86_struct_return : 3;
X86VectorCapability x86_vector_capability : 4;
RiscvFloatCapability riscv_float_capability : 4;
Win64Simd pass_win64_simd_as_arrays : 3;
bool trap_on_wrap : 1;
bool sanitize_address : 1;
bool sanitize_memory : 1;
bool sanitize_thread : 1;
Win64Simd pass_win64_simd_as_arrays : 3;
FpOpt fp_math;
SafetyLevel safe_mode;
PanicLevel panic_level;
X86CpuSet x86_cpu_set;
} feature;
struct
@@ -658,7 +531,7 @@ typedef struct
} BuildTarget;
static const char *x86_cpu_set[8] = {
[X86CPU_BASELINE] = "baseline", // NOLINT
[X86CPU_BASELINE] = "baseline",
[X86CPU_SSSE3] = "ssse3",
[X86CPU_SSE4] = "sse4",
[X86CPU_AVX1] = "avx1",
@@ -675,20 +548,15 @@ static BuildTarget default_build_target = {
.optsize = SIZE_OPTIMIZATION_NOT_SET,
.arch_os_target = ARCH_OS_TARGET_DEFAULT,
.debug_info = DEBUG_INFO_NOT_SET,
.show_backtrace = SHOW_BACKTRACE_NOT_SET,
.use_stdlib = USE_STDLIB_NOT_SET,
.link_libc = LINK_LIBC_NOT_SET,
.emit_stdlib = EMIT_STDLIB_NOT_SET,
.linker_type = LINKER_TYPE_NOT_SET,
.single_module = SINGLE_MODULE_NOT_SET,
.unroll_loops = UNROLL_LOOPS_NOT_SET,
.merge_functions = MERGE_FUNCTIONS_NOT_SET,
.slp_vectorization = VECTORIZATION_NOT_SET,
.loop_vectorization = VECTORIZATION_NOT_SET,
.strip_unused = STRIP_UNUSED_NOT_SET,
.symtab_size = DEFAULT_SYMTAB_SIZE,
.reloc_model = RELOC_DEFAULT,
.cc = NULL,
.cc = "cc",
.version = "1.0.0",
.langrev = "1",
.cpu = "generic",
@@ -701,30 +569,14 @@ static BuildTarget default_build_target = {
.feature.x86_vector_capability = X86VECTOR_DEFAULT,
.feature.x86_cpu_set = X86CPU_DEFAULT,
.feature.safe_mode = SAFETY_NOT_SET,
.feature.panic_level = PANIC_NOT_SET,
.win.crt_linking = WIN_CRT_DEFAULT,
.win.def = NULL,
.switchrange_max_size = DEFAULT_SWITCHRANGE_MAX_SIZE,
};
extern const char *project_default_keys[][2];
extern const int project_default_keys_count;
extern const char *project_target_keys[][2];
extern const int project_target_keys_count;
extern const char *manifest_default_keys[][2];
extern const int manifest_default_keys_count;
extern const char *manifest_target_keys[][2];
extern const int manifest_target_keys_count;
extern char *arch_os_target[ARCH_OS_TARGET_LAST + 1];
BuildOptions parse_arguments(int argc, const char *argv[]);
ArchOsTarget arch_os_target_from_string(const char *target);
bool command_accepts_files(CompilerCommand command);
bool command_passes_args(CompilerCommand command);
void update_build_target_with_opt_level(BuildTarget *target,
OptimizationSetting level);
void update_build_target_with_opt_level(BuildTarget *target, OptimizationSetting level);
void create_project(BuildOptions *build_options);
void create_library(BuildOptions *build_options);
void resolve_libraries(BuildTarget *build_target);
void view_project(BuildOptions *build_options);
void add_target_project(BuildOptions *build_options);

View File

@@ -12,13 +12,6 @@ typedef struct
BuildTarget **targets;
} Project;
#define COPY_IF_DEFAULT(target__, value__) \
do { if ((int)target__ == -1) target__ = value__; } while(0)
extern bool silence_deprecation;
extern const char *trust_level[3];
static const char *memory_environment[6] = {
[MEMORY_ENV_NORMAL] = "normal",
[MEMORY_ENV_SMALL] = "small",
@@ -26,17 +19,10 @@ static const char *memory_environment[6] = {
[MEMORY_ENV_NONE] = "none",
};
static const char *wincrt_linking[5] = {
static const char *wincrt_linking[3] = {
[WIN_CRT_NONE] = "none",
[WIN_CRT_DYNAMIC] = "dynamic",
[WIN_CRT_DYNAMIC_DEBUG] = "dynamic-debug",
[WIN_CRT_STATIC] = "static",
[WIN_CRT_STATIC_DEBUG] = "static-debug",
};
static const char *vector_conv[2] = {
[VECTOR_CONV_DEFAULT] = "default",
[VECTOR_CONV_OLD] = "old",
};
static const char *optsizes[3] = {
@@ -88,11 +74,6 @@ static const char *optlevels[4] = {
[OPTIMIZATION_AGGRESSIVE] = "max",
};
static const char *backtrace_levels[2] = {
[SHOW_BACKTRACE_OFF] = "off",
[SHOW_BACKTRACE_ON] = "on",
};
static const char *reloc_models[5] = {
[RELOC_NONE] = "none",
[RELOC_SMALL_PIC] = "pic",
@@ -101,28 +82,6 @@ static const char *reloc_models[5] = {
[RELOC_BIG_PIE] = "PIE",
};
static const char *sanitize_modes[4] = {
[SANITIZE_NONE] = "none",
[SANITIZE_ADDRESS] = "address",
[SANITIZE_MEMORY] = "memory",
[SANITIZE_THREAD] = "thread",
};
Project *project_load(void);
BuildTarget *project_select_target(Project *project, const char *optional_target);
void update_feature_flags(const char ***flags, const char ***removed_flag, const char *arg, bool add);
const char *get_string(const char *file, const char *category, JSONObject *table, const char *key,
const char *default_value);
int get_valid_bool(const char *file, const char *target, JSONObject *json, const char *key, int default_val);
const char *get_optional_string(const char *file, const char *category, JSONObject *table, const char *key);
const char *get_mandatory_string(const char *file, const char *category, JSONObject *object, const char *key);
const char **get_string_array(const char *file, const char *category, JSONObject *table, const char *key, bool mandatory);
const char **get_optional_string_array(const char *file, const char *target, JSONObject *table, const char *key);
const char *get_cflags(const char *file, const char *target, JSONObject *json, const char *original_flags);
void get_list_append_strings(const char *file, const char *target, JSONObject *json, const char ***list_ptr,
const char *base, const char *override, const char *add);
int get_valid_string_setting(const char *file, const char *target, JSONObject *json, const char *key, const char **values, int first_result, int count, const char *expected);
int get_valid_enum_from_string(const char *str, const char *target, const char **values, int count, const char *expected);
void check_json_keys(const char *valid_keys[][2], size_t key_count, const char *deprecated_keys[], size_t deprecated_key_count, JSONObject *json, const char *target_name, const char *option);
long get_valid_integer(JSONObject *table, const char *key, const char *category, bool mandatory);

Some files were not shown because too many files have changed in this diff Show More