mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 20:11:17 +00:00
Compare commits
371 Commits
v0.2.3.2-a
...
v0.2.x
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04695489b4 | ||
|
|
331f9b23f8 | ||
|
|
9886d381c0 | ||
|
|
12c17b62cf | ||
|
|
2698ba1a94 | ||
|
|
6f5f5feb97 | ||
|
|
64d883cb99 | ||
|
|
1adc8b8264 | ||
|
|
c02ce5ce2a | ||
|
|
e36e4b60e4 | ||
|
|
1d808be4b9 | ||
|
|
7065c28a08 | ||
|
|
da4df9d626 | ||
|
|
a7e4dda360 | ||
|
|
4471ccff13 | ||
|
|
cdff5c3e26 | ||
|
|
cc1bc58ed0 | ||
|
|
812bd8b3d0 | ||
|
|
7e0a29ef40 | ||
|
|
c1de3f059e | ||
|
|
62c1d2ddb5 | ||
|
|
b313bec69d | ||
|
|
036859c0c8 | ||
|
|
56a6e0b112 | ||
|
|
18f7f35e80 | ||
|
|
1d572f3e7c | ||
|
|
002ee006c1 | ||
|
|
8afbccd3fe | ||
|
|
6576725ed8 | ||
|
|
d3a053e049 | ||
|
|
4afec24434 | ||
|
|
29edd6e54e | ||
|
|
547d30eb1e | ||
|
|
6cf3c9f46b | ||
|
|
4beb7eff8f | ||
|
|
48a31cfa48 | ||
|
|
cd1138447e | ||
|
|
c29ad77cdb | ||
|
|
1c15ebe6d2 | ||
|
|
a68efec5e8 | ||
|
|
3f6b0646b3 | ||
|
|
28a8e17690 | ||
|
|
2a7d46844a | ||
|
|
92542ac1f9 | ||
|
|
59b41f8deb | ||
|
|
abfccb5576 | ||
|
|
ea5d7cd2e7 | ||
|
|
ca21b1daac | ||
|
|
9fdd66af42 | ||
|
|
d403912ec7 | ||
|
|
05f222616e | ||
|
|
253dbf3603 | ||
|
|
cfbfc29e84 | ||
|
|
bb020a1752 | ||
|
|
c8a614e43f | ||
|
|
bb28f6e61c | ||
|
|
b1d83e2ccd | ||
|
|
df41caabdd | ||
|
|
2f5d51c92c | ||
|
|
224390ce5a | ||
|
|
09d50ebf6c | ||
|
|
2d608a4d51 | ||
|
|
d511f150a7 | ||
|
|
f4dc4f64f2 | ||
|
|
6035cb4600 | ||
|
|
3d1eaad6b9 | ||
|
|
ca2bb505b6 | ||
|
|
8b4b4273cc | ||
|
|
7c91c56f3d | ||
|
|
5edafc5b2f | ||
|
|
dbb0dc302d | ||
|
|
e09e5c06d3 | ||
|
|
b0c55ff777 | ||
|
|
60832019bd | ||
|
|
42b5445225 | ||
|
|
9691d50a6f | ||
|
|
29a9769651 | ||
|
|
15e1db78a7 | ||
|
|
2f23d56a12 | ||
|
|
22ee082d00 | ||
|
|
212bc7d9af | ||
|
|
890c4bc435 | ||
|
|
7df7dd2933 | ||
|
|
ada8652209 | ||
|
|
bf8288ed1c | ||
|
|
9b6e4f9d11 | ||
|
|
ecdcd8f959 | ||
|
|
828724f593 | ||
|
|
f6eb20f725 | ||
|
|
ade4065480 | ||
|
|
b19cef4bc1 | ||
|
|
151cbfd706 | ||
|
|
b99db4be24 | ||
|
|
8743223dd6 | ||
|
|
2e2a1ca21a | ||
|
|
34bd5fa6da | ||
|
|
131bf5ed34 | ||
|
|
78134316b7 | ||
|
|
b31629c5e8 | ||
|
|
bbfc2fc8ab | ||
|
|
1940f6967c | ||
|
|
adf2b2e818 | ||
|
|
6a9b14d107 | ||
|
|
8b8a8d81db | ||
|
|
d1fadf6428 | ||
|
|
05d8e6c7b8 | ||
|
|
6789fab93c | ||
|
|
3490814d73 | ||
|
|
3799dbb082 | ||
|
|
60d7c8aa14 | ||
|
|
55598b2de8 | ||
|
|
4fe2a70ee1 | ||
|
|
ab56b2d047 | ||
|
|
1061b4e1dd | ||
|
|
e02362de0c | ||
|
|
c414459075 | ||
|
|
8f6fb8b7d7 | ||
|
|
fc296ea579 | ||
|
|
4258fe4d01 | ||
|
|
0565e87e5e | ||
|
|
6a48f81485 | ||
|
|
322d714305 | ||
|
|
069a2d40cb | ||
|
|
9b0dfe8ba3 | ||
|
|
2802b2b96d | ||
|
|
4f4bc80953 | ||
|
|
e45853c0cb | ||
|
|
f54a93890a | ||
|
|
6b4e4f6114 | ||
|
|
bf5683b41c | ||
|
|
73351e0aa9 | ||
|
|
df3e51c17e | ||
|
|
d11d80e896 | ||
|
|
7226bff6ea | ||
|
|
fd82f9685f | ||
|
|
c70d6716da | ||
|
|
e57c2710d9 | ||
|
|
d42193dbd6 | ||
|
|
9f9f24c3cc | ||
|
|
f3e326fcd9 | ||
|
|
ee32a5fd47 | ||
|
|
06917f2e65 | ||
|
|
ba66aaaf12 | ||
|
|
9639ad6a73 | ||
|
|
cf56825d26 | ||
|
|
e5bcb74822 | ||
|
|
8eb295bf5b | ||
|
|
bd6c3db413 | ||
|
|
21fd2c4485 | ||
|
|
bc8fbdb54a | ||
|
|
8922399c36 | ||
|
|
1e7ad2e241 | ||
|
|
4f212f7634 | ||
|
|
2c5ae858b8 | ||
|
|
ef95c1a630 | ||
|
|
b2be8349ed | ||
|
|
01e9086666 | ||
|
|
66b763193d | ||
|
|
36e40e59cb | ||
|
|
dce33ba5b5 | ||
|
|
ec291d4a9d | ||
|
|
e6ad9c324d | ||
|
|
3450016978 | ||
|
|
827499ca80 | ||
|
|
556be2ff7f | ||
|
|
8adb0faa06 | ||
|
|
b6450861d2 | ||
|
|
1e56948a22 | ||
|
|
e4e8abbc6c | ||
|
|
3f60443d66 | ||
|
|
f53dd95aa7 | ||
|
|
1743036104 | ||
|
|
a2fa61f58b | ||
|
|
4059d22315 | ||
|
|
05f0059b1b | ||
|
|
bc3b58b3e3 | ||
|
|
99ea0afcbf | ||
|
|
23461b179f | ||
|
|
d916f111b3 | ||
|
|
0f4a43717e | ||
|
|
c5a862f4d1 | ||
|
|
fb22a36aa9 | ||
|
|
889bc27800 | ||
|
|
eed5b7db54 | ||
|
|
5683fe3f8c | ||
|
|
684ad9e663 | ||
|
|
a6b29bccb7 | ||
|
|
71623a1874 | ||
|
|
16179d2513 | ||
|
|
fd8cd6a8e2 | ||
|
|
180b17b213 | ||
|
|
4764981708 | ||
|
|
3cf057ff95 | ||
|
|
ea3b50d039 | ||
|
|
041c096801 | ||
|
|
d942dfbc99 | ||
|
|
a176ae353b | ||
|
|
8a840746f6 | ||
|
|
869aa7ed76 | ||
|
|
1d5ff71b21 | ||
|
|
439ae3e468 | ||
|
|
8f2ae41ea5 | ||
|
|
fd1353f0f1 | ||
|
|
bbeed12600 | ||
|
|
0a7200ac24 | ||
|
|
f509c85514 | ||
|
|
06d3bc8915 | ||
|
|
a0be188902 | ||
|
|
0a9a014e4a | ||
|
|
85ee021585 | ||
|
|
f6de1f7b74 | ||
|
|
cf61f427d4 | ||
|
|
eb54e46569 | ||
|
|
cf0a04977a | ||
|
|
1a9b8095b6 | ||
|
|
012f258fa2 | ||
|
|
eefe782dd6 | ||
|
|
6f77fdf800 | ||
|
|
8f6dd64483 | ||
|
|
04c3efc3c3 | ||
|
|
4575e3dd8d | ||
|
|
b5b625e54a | ||
|
|
52cc4f8ba5 | ||
|
|
4e559e886c | ||
|
|
802398dd44 | ||
|
|
7c76fd02c6 | ||
|
|
dee0199f10 | ||
|
|
5cbc619f13 | ||
|
|
01902b523a | ||
|
|
157d1a959b | ||
|
|
4b3232ead6 | ||
|
|
cc8d266827 | ||
|
|
6d6d410d13 | ||
|
|
6b34a8c82e | ||
|
|
c39c7c3147 | ||
|
|
d360e97439 | ||
|
|
d305f9da49 | ||
|
|
572aafe8b9 | ||
|
|
c52629d60f | ||
|
|
497eef5328 | ||
|
|
680b077eb1 | ||
|
|
5ddbf50e83 | ||
|
|
908ac220c6 | ||
|
|
958db2f594 | ||
|
|
8aa00b015b | ||
|
|
379a66a14b | ||
|
|
0887d1e7dc | ||
|
|
4a6f587c9f | ||
|
|
e54679c01e | ||
|
|
4bc47a195b | ||
|
|
b003b05d5d | ||
|
|
b066c25432 | ||
|
|
bbda3a679f | ||
|
|
49efa4fafc | ||
|
|
4153cbe16d | ||
|
|
d6d4c0a912 | ||
|
|
06124ddb9f | ||
|
|
e1fc028694 | ||
|
|
a9c2e59f60 | ||
|
|
eb81c00ada | ||
|
|
26325f0fd2 | ||
|
|
910b2179f9 | ||
|
|
e20e6071c8 | ||
|
|
cae1933f0f | ||
|
|
bc2d789c2e | ||
|
|
2c802878bb | ||
|
|
c4595d3024 | ||
|
|
20ea6421cc | ||
|
|
f3c3636ac7 | ||
|
|
5a467f11ca | ||
|
|
eef5e1b498 | ||
|
|
60b17004a4 | ||
|
|
6ff05bae6d | ||
|
|
5d30189626 | ||
|
|
1bb9c2d249 | ||
|
|
e31d189837 | ||
|
|
aa7da00323 | ||
|
|
74fa81336f | ||
|
|
3242bcabc0 | ||
|
|
164a1ef59d | ||
|
|
17a03bc104 | ||
|
|
8d4d3b4d5b | ||
|
|
9a7b9bb7a4 | ||
|
|
1ba03f75c2 | ||
|
|
7595f2e17b | ||
|
|
90898d6ed6 | ||
|
|
aafa0d08a2 | ||
|
|
3c9761c946 | ||
|
|
05c9b7cb33 | ||
|
|
bb39cf20c0 | ||
|
|
dad8cd24b1 | ||
|
|
39b1b59011 | ||
|
|
685688f884 | ||
|
|
a1b69a3f50 | ||
|
|
f1f268df4a | ||
|
|
6febd8a143 | ||
|
|
8cc8c321a2 | ||
|
|
0358724451 | ||
|
|
86072ae21f | ||
|
|
0af448ee71 | ||
|
|
a4a6ea16ce | ||
|
|
4d4bbbdebc | ||
|
|
bfde58b9a5 | ||
|
|
7b04e7cf85 | ||
|
|
b7fa3549a3 | ||
|
|
974cd0acc5 | ||
|
|
b52b42d4da | ||
|
|
e2621617f1 | ||
|
|
d3fed67dbe | ||
|
|
91996e5973 | ||
|
|
3156fcb4aa | ||
|
|
8309d84fdb | ||
|
|
4efb433934 | ||
|
|
7142ce2f0c | ||
|
|
a436a9b069 | ||
|
|
fb56d380cc | ||
|
|
7bd76c973c | ||
|
|
42465039e9 | ||
|
|
df0b1df1df | ||
|
|
137b474f44 | ||
|
|
4662133893 | ||
|
|
15f902579b | ||
|
|
4e47f0b624 | ||
|
|
4f09b0c351 | ||
|
|
29e7af843a | ||
|
|
e2a3000c39 | ||
|
|
9942be54dc | ||
|
|
b87e14cba8 | ||
|
|
4ca7ba048b | ||
|
|
1b38e24a9f | ||
|
|
f284a1c575 | ||
|
|
86723540f3 | ||
|
|
aa239c6a87 | ||
|
|
09d9968e97 | ||
|
|
76e4eea4a8 | ||
|
|
43a4967987 | ||
|
|
ab5bacc78a | ||
|
|
af34eec61d | ||
|
|
f48661d35e | ||
|
|
5592d19152 | ||
|
|
55f676dd5c | ||
|
|
96571e2b65 | ||
|
|
4a3f5c4eb3 | ||
|
|
1db23defbc | ||
|
|
6c9b5fd30d | ||
|
|
8e93642535 | ||
|
|
d36fc9b19e | ||
|
|
5dea48101f | ||
|
|
b4df56db54 | ||
|
|
1b086e06f1 | ||
|
|
aca5adebd5 | ||
|
|
dc097fe130 | ||
|
|
ae371d105d | ||
|
|
de6ea0d1ae | ||
|
|
020eba720b | ||
|
|
0a4f35154a | ||
|
|
fb9be722bc | ||
|
|
e4c7dde30b | ||
|
|
1b103a3e22 | ||
|
|
b87b67ebbb | ||
|
|
17dcb742c6 | ||
|
|
b7e423adc2 | ||
|
|
0aef2810c8 | ||
|
|
2b2be6b491 | ||
|
|
49d13c23bb | ||
|
|
bcda6d71c9 | ||
|
|
c76e8e0713 | ||
|
|
29b3535460 | ||
|
|
fd1eafe5bf | ||
|
|
468921225d | ||
|
|
50853bb5de |
4
.gitattributes
vendored
Normal file
4
.gitattributes
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
$ cat .gitattributes
|
||||
* text=auto
|
||||
*.c3 linguist-language=C
|
||||
*.c3t linguist-language=C
|
||||
142
.github/workflows/main.yml
vendored
142
.github/workflows/main.yml
vendored
@@ -7,65 +7,104 @@ on:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
|
||||
build-msvc:
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
# Don't abort runners if a single one fails
|
||||
fail-fast: false
|
||||
matrix:
|
||||
build_type: [ Release, Debug ]
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: cmd
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: CMake
|
||||
run: |
|
||||
cmake -B build -G "Visual Studio 17 2022" -A x64 -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
|
||||
cmake --build build --config ${{ matrix.build_type }}
|
||||
|
||||
- name: Build testproject
|
||||
run: |
|
||||
cd resources/testproject
|
||||
..\..\build\${{ matrix.build_type }}\c3c.exe --debug-log run hello_world_win32
|
||||
|
||||
- name: run compiler tests
|
||||
run: |
|
||||
cd test
|
||||
python3.exe src/tester.py ..\build\${{ matrix.build_type }}\c3c.exe test_suite/
|
||||
|
||||
build-msys2-mingw:
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
# Don't abort runners if a single one fails
|
||||
fail-fast: false
|
||||
matrix:
|
||||
build_type: [Release, Debug]
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: MINGW64
|
||||
update: true
|
||||
install: git binutils mingw-w64-x86_64-cmake mingw-w64-x86_64-toolchain mingw-w64-x86_64-llvm mingw-w64-x86_64-polly mingw-w64-x86_64-python mingw-w64-x86_64-lld
|
||||
|
||||
install: git binutils 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-13.0.1-2-any.pkg.tar.zst
|
||||
pacman --noconfirm -U https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-lld-13.0.1-2-any.pkg.tar.zst
|
||||
- name: CMake
|
||||
run: |
|
||||
mkdir build && cd build
|
||||
cmake .. -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
|
||||
cmake --build .
|
||||
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
|
||||
cmake --build build
|
||||
|
||||
- name: Build testproject
|
||||
run: |
|
||||
cd resources/testproject
|
||||
../../build/c3c build
|
||||
../../build/c3c run --debug-log
|
||||
|
||||
- name: run compiler tests
|
||||
run: |
|
||||
cd test
|
||||
python3 src/tester.py ../build/c3c.exe test_suite/
|
||||
|
||||
|
||||
build-msys2-clang:
|
||||
runs-on: windows-latest
|
||||
if: ${{ false }}
|
||||
strategy:
|
||||
# Don't abort runners if a single one fails
|
||||
fail-fast: false
|
||||
matrix:
|
||||
build_type: [Release, Debug]
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: CLANG64
|
||||
update: true
|
||||
update: false
|
||||
install: git binutils mingw-w64-clang-x86_64-cmake mingw-w64-clang-x86_64-toolchain mingw-w64-clang-x86_64-python
|
||||
|
||||
- name: CMake
|
||||
run: |
|
||||
mkdir build && cd build
|
||||
cmake .. -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
|
||||
cmake --build .
|
||||
cmake -B build -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
|
||||
cmake --build build
|
||||
- name: Build testproject
|
||||
run: |
|
||||
cd resources/testproject
|
||||
../../build/c3c build
|
||||
../../build/c3c run --debug-log
|
||||
|
||||
- name: run compiler tests
|
||||
run: |
|
||||
@@ -75,25 +114,88 @@ jobs:
|
||||
build-linux:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
# Don't abort runners if a single one fails
|
||||
fail-fast: false
|
||||
matrix:
|
||||
build_type: [Release, Debug]
|
||||
llvm_version: [12, 13, 14, 15]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: (Ubuntu) Download LLVM
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install common deps
|
||||
run: |
|
||||
sudo apt-get install zlib1g zlib1g-dev clang-11 libllvm11 llvm-11 llvm-11-dev llvm-11-runtime liblld-11-dev liblld-11 python3
|
||||
sudo apt-get install zlib1g zlib1g-dev python3 ninja-build
|
||||
|
||||
- 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}}" < 15 ]]; 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 install -y clang-${{matrix.llvm_version}} llvm-${{matrix.llvm_version}} llvm-${{matrix.llvm_version}}-dev lld-${{matrix.llvm_version}} liblld-${{matrix.llvm_version}}-dev
|
||||
|
||||
if [[ "${{matrix.llvm_version}}" > 12 ]]; then
|
||||
sudo apt-get install -y libmlir-${{matrix.llvm_version}} libmlir-${{matrix.llvm_version}}-dev mlir-${{matrix.llvm_version}}-tools
|
||||
fi
|
||||
|
||||
- name: CMake
|
||||
run: |
|
||||
mkdir build && cd build
|
||||
cmake .. -DLLVM_DIR=/usr/lib/llvm-11/cmake -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
|
||||
cmake --build .
|
||||
cmake -B build -G Ninja -DCMAKE_C_COMPILER=clang-${{matrix.llvm_version}} -DCMAKE_CXX_COMPILER=clang++-${{matrix.llvm_version}} -DC3_LLVM_VERSION=${{matrix.llvm_version}} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
|
||||
cmake --build build
|
||||
|
||||
- name: Build testproject
|
||||
run: |
|
||||
cd resources/testproject
|
||||
../../build/c3c build
|
||||
../../build/c3c run --debug-log
|
||||
|
||||
- name: Build testproject direct linker
|
||||
run: |
|
||||
cd resources/testproject
|
||||
../../build/c3c run --debug-log --forcelinker
|
||||
|
||||
- name: run compiler tests
|
||||
run: |
|
||||
cd test
|
||||
if [[ "${{matrix.llvm_version}}" < 15 ]]; then
|
||||
python3 src/tester.py ../build/c3c test_suite/
|
||||
else
|
||||
python3 src/tester.py ../build/c3c test_suite2/
|
||||
fi
|
||||
|
||||
build-mac:
|
||||
runs-on: macos-latest
|
||||
strategy:
|
||||
# Don't abort runners if a single one fails
|
||||
fail-fast: false
|
||||
matrix:
|
||||
build_type: [Release, Debug]
|
||||
llvm_version: [12, 13, 14]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Download LLVM
|
||||
run: |
|
||||
brew install llvm@${{ matrix.llvm_version }} botan ninja
|
||||
echo "/usr/local/opt/llvm@${{ matrix.llvm_version }}/bin" >> $GITHUB_PATH
|
||||
TMP_PATH=$(xcrun --show-sdk-path)/user/include
|
||||
echo "CPATH=$TMP_PATH" >> $GITHUB_ENV
|
||||
|
||||
- name: CMake
|
||||
run: |
|
||||
cmake -B build -G Ninja -DC3_LLVM_VERSION=${{matrix.llvm_version}} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
|
||||
cmake --build build
|
||||
|
||||
- name: Build testproject
|
||||
run: |
|
||||
cd resources/testproject
|
||||
../../build/c3c run --debug-log
|
||||
|
||||
- name: Build testproject direct linker
|
||||
run: |
|
||||
cd resources/testproject
|
||||
../../build/c3c run --debug-log --forcelinker
|
||||
|
||||
- name: run compiler tests
|
||||
run: |
|
||||
|
||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -52,7 +52,6 @@ Module.symvers
|
||||
Mkfile.old
|
||||
dkms.conf
|
||||
/build/
|
||||
/cmake-build-debug/
|
||||
.idea/
|
||||
/resources/grammar.tab.c
|
||||
/resources/grammar.vcg
|
||||
@@ -60,3 +59,11 @@ dkms.conf
|
||||
/resources/y.tab.c
|
||||
/resources/y.tab.h
|
||||
/bin/
|
||||
|
||||
#visual studio files
|
||||
.vs/
|
||||
.vscode/
|
||||
out/
|
||||
|
||||
/cmake-build-debug/
|
||||
/cmake-build-release/
|
||||
|
||||
304
CMakeLists.txt
304
CMakeLists.txt
@@ -1,68 +1,144 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
project(c3c)
|
||||
include(FetchContent)
|
||||
include(FeatureSummary)
|
||||
|
||||
SET(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL)
|
||||
SET(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)
|
||||
set(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL)
|
||||
set(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
#set(CMAKE_BUILD_TYPE Release)
|
||||
#set(CMAKE_CXX_FLAGS_RELEASE "-O3")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -gdwarf-3 -O3")
|
||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -gdwarf-3")
|
||||
#set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O1 -fsanitize=undefined")
|
||||
#set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O1 -fsanitize=undefined")
|
||||
#set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -gdwarf-3 -O3 -fsanitize=undefined")
|
||||
#set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -gdwarf-3 -fsanitize=undefined")
|
||||
#set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=undefined")
|
||||
|
||||
find_package(LLVM REQUIRED CONFIG)
|
||||
option(C3_USE_TB "Enable TB" OFF)
|
||||
set(C3_LLVM_VERSION "auto" CACHE STRING "Use LLVM version [default: auto]")
|
||||
option(C3_USE_MIMALLOC "Use built-in mimalloc" OFF)
|
||||
set(C3_MIMALLOC_TAG "v1.7.3" CACHE STRING "Used version of mimalloc")
|
||||
|
||||
set(C3_USE_MIMALLOC OFF)
|
||||
if(C3_USE_MIMALLOC)
|
||||
option(MI_BUILD_TESTS OFF)
|
||||
option(MI_BUILD_SHARED OFF)
|
||||
option(MI_PADDING OFF)
|
||||
option(MI_DEBUG_FULL OFF)
|
||||
FetchContent_Declare(
|
||||
mimalloc
|
||||
GIT_REPOSITORY https://github.com/microsoft/mimalloc.git
|
||||
GIT_TAG ${C3_MIMALLOC_TAG}
|
||||
)
|
||||
FetchContent_MakeAvailable(mimalloc)
|
||||
endif()
|
||||
|
||||
if (NOT C3_LLVM_VERSION STREQUAL "auto")
|
||||
if (${C3_LLVM_VERSION} VERSION_LESS 12 OR ${C3_LLVM_VERSION} VERSION_GREATER 15)
|
||||
message(FATAL_ERROR "LLVM ${C3_LLVM_VERSION} is not supported!")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
|
||||
if (C3_LLVM_VERSION STREQUAL "auto")
|
||||
set(C3_LLVM_VERSION "14")
|
||||
endif()
|
||||
FetchContent_Declare(
|
||||
LLVM_Windows
|
||||
URL https://github.com/c3lang/win-llvm/releases/download/llvm-vs22/llvm-14.0.1-windows-amd64-msvc17-libcmt.7z
|
||||
)
|
||||
FetchContent_Declare(
|
||||
LLVM_Windows_debug
|
||||
URL https://github.com/c3lang/win-llvm/releases/download/llvm-vs22/llvm-14.0.1-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(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(CMAKE_SYSTEM_PREFIX_PATH ${llvm_windows_SOURCE_DIR} ${CMAKE_SYSTEM_PREFIX_PATH})
|
||||
endif()
|
||||
find_package(LLVM REQUIRED CONFIG)
|
||||
find_package(LLD REQUIRED CONFIG)
|
||||
else()
|
||||
if (NOT C3_LLVM_VERSION STREQUAL "auto")
|
||||
find_package(LLVM ${C3_LLVM_VERSION} REQUIRED CONFIG)
|
||||
else()
|
||||
find_package(LLVM REQUIRED CONFIG)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
|
||||
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
|
||||
message(STATUS "Libraries located in: ${LLVM_LIBRARY_DIRS}")
|
||||
|
||||
include_directories(${LLVM_INCLUDE_DIRS})
|
||||
add_definitions(${LLVM_DEFINITIONS})
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
set(LLVM_LINK_COMPONENTS
|
||||
AllTargetsAsmParsers
|
||||
AllTargetsCodeGens
|
||||
AllTargetsDescs
|
||||
AllTargetsDisassemblers
|
||||
AllTargetsInfos
|
||||
AllTargetsCodeGens
|
||||
Analysis
|
||||
AsmPrinter
|
||||
BitReader
|
||||
Core
|
||||
DebugInfoPDB
|
||||
InstCombine
|
||||
IrReader
|
||||
LibDriver
|
||||
Linker
|
||||
LTO
|
||||
MC
|
||||
MCDisassembler
|
||||
native
|
||||
nativecodegen
|
||||
Object
|
||||
Option
|
||||
ScalarOpts
|
||||
Support
|
||||
Target
|
||||
TransformUtils
|
||||
native
|
||||
nativecodegen
|
||||
AsmPrinter
|
||||
Linker
|
||||
LTO
|
||||
WindowsManifest
|
||||
DebugInfoPDB
|
||||
LibDriver
|
||||
Option
|
||||
IrReader
|
||||
)
|
||||
)
|
||||
|
||||
if (${LLVM_PACKAGE_VERSION} VERSION_GREATER 14.1)
|
||||
set(LLVM_LINK_COMPONENTS ${LLVM_LINK_COMPONENTS} WindowsDriver)
|
||||
endif()
|
||||
|
||||
llvm_map_components_to_libnames(llvm_libs ${LLVM_LINK_COMPONENTS})
|
||||
|
||||
file(COPY ${CMAKE_SOURCE_DIR}/resources/lib DESTINATION ${CMAKE_BINARY_DIR})
|
||||
file(COPY ${CMAKE_SOURCE_DIR}/lib DESTINATION ${CMAKE_BINARY_DIR})
|
||||
|
||||
find_library(LLD_COFF NAMES lldCOFF.a liblldCOFF.a PATHS ${LLVM_LIBRARY_DIRS})
|
||||
find_library(LLD_COMMON NAMES lldCommon.a liblldCommon.a PATHS ${LLVM_LIBRARY_DIRS})
|
||||
find_library(LLD_CORE NAMES lldCore.a liblldCore.a PATHS ${LLVM_LIBRARY_DIRS})
|
||||
find_library(LLD_WASM NAMES lldWasm.a liblldWasm.a PATHS ${LLVM_LIBRARY_DIRS})
|
||||
find_library(LLD_MINGW NAMES lldMinGW.a liblldMinGW.a PATHS ${LLVM_LIBRARY_DIRS})
|
||||
find_library(LLD_ELF NAMES lldELF.a liblldELF.a PATHS ${LLVM_LIBRARY_DIRS})
|
||||
find_library(LLD_DRIVER NAMES lldDriver.a liblldDriver.a PATHS ${LLVM_LIBRARY_DIRS})
|
||||
find_library(LLD_READER_WRITER NAMES lldReaderWriter.a liblldReaderWriter.a PATHS ${LLVM_LIBRARY_DIRS})
|
||||
find_library(LLD_MACHO NAMES lldMachO.a liblldMachO.a PATHS ${LLVM_LIBRARY_DIRS})
|
||||
find_library(LLD_YAML NAMES lldYAML.a liblldYAML.a PATHS ${LLVM_LIBRARY_DIRS})
|
||||
|
||||
# These don't seem to be reliable on windows.
|
||||
message(STATUS "using find_library")
|
||||
if(C3_USE_TB)
|
||||
find_library(TB_LIB NAMES tildebackend.a tildebackend.lib PATHS ${CMAKE_SOURCE_DIR}/tb/)
|
||||
endif()
|
||||
find_library(LLD_COFF NAMES lldCOFF.lib lldCOFF.a liblldCOFF.a PATHS ${LLVM_LIBRARY_DIRS})
|
||||
find_library(LLD_COMMON NAMES lldCommon.lib lldCommon.a liblldCommon.a PATHS ${LLVM_LIBRARY_DIRS})
|
||||
find_library(LLD_ELF NAMES lldELF.lib lldELF.a liblldELF.a PATHS ${LLVM_LIBRARY_DIRS})
|
||||
if (${LLVM_PACKAGE_VERSION} VERSION_LESS 14)
|
||||
find_library(LLD_MACHO NAMES lldMachO2.lib lldMachO2.a liblldMachO2.a PATHS ${LLVM_LIBRARY_DIRS})
|
||||
else ()
|
||||
find_library(LLD_MACHO NAMES lldMachO.lib lldMachO.a liblldMachO.a PATHS ${LLVM_LIBRARY_DIRS})
|
||||
endif ()
|
||||
find_library(LLD_MINGW NAMES lldMinGW.lib lldMinGW.a liblldMinGW.a PATHS ${LLVM_LIBRARY_DIRS})
|
||||
find_library(LLD_WASM NAMES lldWasm.lib lldWasm.a liblldWasm.a PATHS ${LLVM_LIBRARY_DIRS})
|
||||
|
||||
if (${LLVM_PACKAGE_VERSION} VERSION_LESS 14)
|
||||
find_library(LLD_CORE NAMES lldCore.lib lldCore.a liblldCore.a PATHS ${LLVM_LIBRARY_DIRS})
|
||||
find_library(LLD_DRIVER NAMES lldDriver.lib lldDriver.a liblldDriver.a PATHS ${LLVM_LIBRARY_DIRS})
|
||||
find_library(LLD_READER_WRITER NAMES lldReaderWriter.lib lldReaderWriter.a liblldReaderWriter.a PATHS ${LLVM_LIBRARY_DIRS})
|
||||
find_library(LLD_YAML NAMES lldYAML.lib lldYAML.a liblldYAML.a PATHS ${LLVM_LIBRARY_DIRS})
|
||||
endif ()
|
||||
|
||||
set(lld_libs
|
||||
${LLD_COFF}
|
||||
@@ -76,90 +152,143 @@ set(lld_libs
|
||||
${LLD_YAML}
|
||||
${LLD_CORE}
|
||||
)
|
||||
if (APPLE)
|
||||
set(lld_libs ${lld_libs} xar)
|
||||
endif ()
|
||||
|
||||
message(STATUS "linking to llvm libs ${lld_libs}")
|
||||
message(STATUS "Found lld libs ${lld_libs}")
|
||||
|
||||
add_library(c3c_wrappers STATIC wrapper/src/wrapper.cpp)
|
||||
|
||||
add_executable(c3c
|
||||
src/main.c
|
||||
src/build/builder.c
|
||||
src/build/build_options.c
|
||||
src/build/project_creation.c
|
||||
src/utils/errors.c
|
||||
src/utils/file_utils.c
|
||||
src/compiler/lexer.c
|
||||
src/compiler/tokens.c
|
||||
src/compiler/symtab.c
|
||||
src/compiler/parser.c
|
||||
src/compiler_tests/tests.c
|
||||
src/compiler_tests/benchmark.c
|
||||
src/utils/malloc.c
|
||||
src/compiler/compiler.c
|
||||
src/compiler/semantic_analyser.c
|
||||
src/compiler/source_file.c
|
||||
src/compiler/diagnostics.c
|
||||
src/compiler/ast.c
|
||||
src/compiler/bigint.c
|
||||
src/compiler/context.c
|
||||
src/compiler/sema_expr.c
|
||||
src/compiler/enums.h
|
||||
src/compiler/sema_casts.c
|
||||
src/compiler/target.c
|
||||
src/compiler/c_abi_internal.h
|
||||
src/compiler/codegen_general.c
|
||||
src/compiler/compiler.c
|
||||
src/compiler/compiler.h
|
||||
src/compiler/types.c
|
||||
src/compiler/module.c
|
||||
src/compiler/llvm_codegen.c
|
||||
src/utils/stringutils.c
|
||||
src/compiler/dwarf.h
|
||||
src/compiler/context.c
|
||||
src/compiler/copying.c
|
||||
src/compiler/llvm_codegen_stmt.c
|
||||
src/compiler/llvm_codegen_expr.c
|
||||
src/compiler/llvm_codegen_debug_info.c
|
||||
src/compiler/llvm_codegen_module.c
|
||||
src/compiler/llvm_codegen_type.c
|
||||
src/compiler/llvm_codegen_function.c
|
||||
src/compiler/diagnostics.c
|
||||
src/compiler/dwarf.h
|
||||
src/compiler/enums.h
|
||||
src/compiler/float.c
|
||||
src/compiler/headers.c
|
||||
src/compiler/lexer.c
|
||||
src/compiler/libraries.c
|
||||
src/compiler/linker.c
|
||||
src/compiler/llvm_codegen.c
|
||||
src/compiler/llvm_codegen_c_abi_aarch64.c
|
||||
src/compiler/llvm_codegen_c_abi.c
|
||||
src/build/builder.c
|
||||
src/utils/toml.c src/build/project.c
|
||||
src/compiler/sema_name_resolution.c
|
||||
src/target_info/target_info.c
|
||||
src/compiler/llvm_codegen_c_abi_riscv.c
|
||||
src/compiler/llvm_codegen_c_abi_wasm.c
|
||||
src/compiler/llvm_codegen_c_abi_win64.c
|
||||
src/compiler/llvm_codegen_c_abi_x64.c
|
||||
src/compiler/llvm_codegen_c_abi_x86.c
|
||||
src/compiler/llvm_codegen_debug_info.c
|
||||
src/compiler/llvm_codegen_expr.c
|
||||
src/compiler/llvm_codegen_function.c
|
||||
src/compiler/llvm_codegen_instr.c
|
||||
src/compiler/llvm_codegen_module.c
|
||||
src/compiler/llvm_codegen_stmt.c
|
||||
src/compiler/llvm_codegen_type.c
|
||||
src/compiler/llvm_codegen_value.c
|
||||
src/compiler/module.c
|
||||
src/compiler/number.c
|
||||
src/compiler/parse_expr.c
|
||||
src/compiler/parse_global.c
|
||||
src/compiler/parser.c
|
||||
src/compiler/parser_internal.h
|
||||
src/compiler/parse_stmt.c
|
||||
src/compiler/parse_global.c
|
||||
src/compiler/sema_passes.c
|
||||
src/compiler/sema_internal.h
|
||||
src/compiler/sema_casts.c
|
||||
src/compiler/sema_decls.c
|
||||
src/compiler/sema_types.c
|
||||
src/compiler/sema_expr.c
|
||||
src/compiler/sema_internal.h
|
||||
src/compiler/sema_name_resolution.c
|
||||
src/compiler/semantic_analyser.c
|
||||
src/compiler/sema_passes.c
|
||||
src/compiler/sema_stmts.c
|
||||
src/compiler/number.c
|
||||
src/compiler/linker.c
|
||||
src/compiler/sema_types.c
|
||||
src/compiler/source_file.c
|
||||
src/compiler/symtab.c
|
||||
src/compiler/target.c
|
||||
src/compiler/tb_codegen.c
|
||||
src/compiler/tilde_codegen.c
|
||||
src/compiler/tilde_codegen_instr.c
|
||||
src/compiler/tilde_codegen_value.c
|
||||
src/compiler/tilde_codegen_storeload.c
|
||||
src/compiler_tests/benchmark.c
|
||||
src/compiler_tests/tests.c
|
||||
src/compiler/tokens.c
|
||||
src/compiler/types.c
|
||||
src/main.c
|
||||
src/utils/errors.c
|
||||
src/utils/file_utils.c
|
||||
src/utils/find_msvc.c
|
||||
src/utils/malloc.c
|
||||
src/utils/stringutils.c
|
||||
src/utils/taskqueue.c
|
||||
src/utils/json.c
|
||||
src/build/project.c
|
||||
src/utils/vmem.c
|
||||
src/utils/vmem.h
|
||||
src/utils/whereami.c
|
||||
src/utils/taskqueue.c
|
||||
src/compiler/llvm_codegen_c_abi_x86.c
|
||||
src/compiler/c_abi_internal.h
|
||||
src/compiler/llvm_codegen_c_abi_x64.c
|
||||
src/compiler/llvm_codegen_c_abi_win64.c
|
||||
src/compiler/llvm_codegen_c_abi_aarch64.c
|
||||
src/compiler/headers.c
|
||||
src/compiler/llvm_codegen_c_abi_riscv.c
|
||||
src/compiler/llvm_codegen_c_abi_wasm.c)
|
||||
|
||||
target_compile_options(c3c PRIVATE -Wall -Werror -Wno-unknown-pragmas -Wno-unused-result
|
||||
-Wno-unused-function -Wno-unused-variable -Wno-unused-parameter)
|
||||
src/compiler/decltable.c
|
||||
src/compiler/mac_support.c
|
||||
src/compiler/tilde_codegen_storeload.c
|
||||
src/compiler/llvm_codegen_storeload.c
|
||||
src/compiler/tilde_codegen_expr.c
|
||||
src/compiler/tilde_codegen_stmt.c
|
||||
src/compiler/tilde_codegen_type.c
|
||||
src/compiler/windows_support.c)
|
||||
|
||||
if(NOT CMAKE_C_COMPILER_ID STREQUAL "MSVC")
|
||||
message(STATUS "using gcc/clang warning switches")
|
||||
target_compile_options(c3c PRIVATE -Wall -Werror -Wno-unknown-pragmas -Wno-unused-result
|
||||
-Wno-unused-function -Wno-unused-variable -Wno-unused-parameter)
|
||||
endif()
|
||||
|
||||
target_include_directories(c3c PRIVATE
|
||||
"${CMAKE_SOURCE_DIR}/src/")
|
||||
|
||||
target_include_directories(c3c PRIVATE
|
||||
"${CMAKE_SOURCE_DIR}/tb/")
|
||||
|
||||
target_include_directories(c3c_wrappers PRIVATE
|
||||
"${CMAKE_SOURCE_DIR}/wrapper/src/")
|
||||
|
||||
|
||||
message(STATUS "Found LLD ${lld_libs}")
|
||||
|
||||
target_link_libraries(c3c_wrappers ${llvm_libs} ${lld_libs})
|
||||
#target_link_libraries(c3c m ${llvm_libs} c3c_wrappers lldCommon lldCore lldCOFF lldWASM lldMinGW lldELF lldDriver lldReaderWriter lldMachO lldYAML)
|
||||
target_link_libraries(c3c m ${llvm_libs} c3c_wrappers ${lld_libs})
|
||||
target_link_libraries(c3c ${llvm_libs} c3c_wrappers ${lld_libs})
|
||||
if(C3_USE_TB)
|
||||
target_link_libraries(c3c c3c_wrappers ${TB_LIB})
|
||||
target_compile_definitions(c3c PUBLIC TB_BACKEND=1)
|
||||
else()
|
||||
target_compile_definitions(c3c PUBLIC TB_BACKEND=0)
|
||||
endif()
|
||||
|
||||
if(C3_USE_MIMALLOC)
|
||||
target_link_libraries(c3c mimalloc-static)
|
||||
endif()
|
||||
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "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(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
target_compile_options(c3c PUBLIC /MTd)
|
||||
target_compile_options(c3c_wrappers PUBLIC /MTd)
|
||||
else()
|
||||
target_compile_options(c3c PUBLIC /MT)
|
||||
target_compile_options(c3c_wrappers PUBLIC /MT)
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
if (CMAKE_C_COMPILER_ID STREQUAL "Clang" OR CMAKE_C_COMPILE_ID STREQUAL "GNU")
|
||||
@@ -171,3 +300,4 @@ endif()
|
||||
|
||||
install(TARGETS c3c DESTINATION bin)
|
||||
|
||||
feature_summary(WHAT ALL)
|
||||
|
||||
15
CMakeSettings.json
Normal file
15
CMakeSettings.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "build",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Release",
|
||||
"inheritEnvironments": [ "msvc_x64_x64" ],
|
||||
"buildRoot": "${projectDir}\\out\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\out\\install\\${name}",
|
||||
"cmakeCommandArgs": "-DLLVM_DIR=C:\\llvm\\llvm\\build\\lib\\cmake\\llvm -DCMAKE_CXX_FLAGS:STRING=\"${CMAKE_CXX_FLAGS} /J\"",
|
||||
"buildCommandArgs": "-v",
|
||||
"ctestCommandArgs": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
20
LICENSE_STDLIB
Normal file
20
LICENSE_STDLIB
Normal file
@@ -0,0 +1,20 @@
|
||||
Copyright (c) 2022 Christoffer Lernö and contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
270
README.md
270
README.md
@@ -1,10 +1,14 @@
|
||||
# C3 Language
|
||||
|
||||
C3 is a C-like language trying to be "an incremental improvement over C" rather than a whole new language.
|
||||
C3 owes a lot to the ideas of the [C2 language](http://c2lang.org): to iterate on top of C without trying to be a
|
||||
whole new language.
|
||||
C3 is a C-like language striving to be an evolution of C, rather than a
|
||||
completely new language. As an alternative in the C/C++ niche it
|
||||
aims to be fast and close to the metal.
|
||||
|
||||
C3 tries to be an alternative in the C/C++ niche: fast and close to the metal.
|
||||
The manual for C3 can be found at [www.c3-lang.org](http://www.c3-lang.org).
|
||||
|
||||

|
||||
|
||||
Thanks to full ABI compatibility with C, it's possible to mix C and C3 in the same project with no effort. As a demonstration, vkQuake was compiled with a small portion of the code converted to C3 and compiled with the c3c compiler. (The fork can be found at https://github.com/c3lang/vkQuake)
|
||||
|
||||
### Design Principles
|
||||
- Procedural "get things done"-type of language.
|
||||
@@ -15,28 +19,95 @@ C3 tries to be an alternative in the C/C++ niche: fast and close to the metal.
|
||||
- Avoid "big ideas" & the "more is better" fallacy.
|
||||
- Introduce some higher level conveniences where the value is great.
|
||||
|
||||
C3 owes its inspiration to the [C2 language](http://c2lang.org): to iterate on top of C without trying to be a
|
||||
whole new language.
|
||||
|
||||
### Example code
|
||||
|
||||
Create a `main.c3` file with:
|
||||
```c++
|
||||
module hello_world;
|
||||
import std::io;
|
||||
The following code shows [generic modules](http://www.c3-lang.org/generics/) (more examples can be found at http://www.c3-lang.org/examples/).
|
||||
|
||||
func void main()
|
||||
```c++
|
||||
module stack <Type>;
|
||||
// Above: the parameterized type is applied to the entire module.
|
||||
|
||||
struct Stack
|
||||
{
|
||||
io::printf("Hello, world!\n");
|
||||
usize capacity;
|
||||
usize size;
|
||||
Type* elems;
|
||||
}
|
||||
|
||||
// The type methods offers dot syntax calls,
|
||||
// so this function can either be called
|
||||
// Stack.push(&my_stack, ...) or
|
||||
// my_stack.push(...)
|
||||
fn void Stack.push(Stack* this, Type element)
|
||||
{
|
||||
if (this.capacity == this.size)
|
||||
{
|
||||
this.capacity *= 2;
|
||||
this.elems = mem::realloc(this.elems, Type.sizeof * this.capacity);
|
||||
}
|
||||
this.elems[this.size++] = element;
|
||||
}
|
||||
|
||||
fn Type Stack.pop(Stack* this)
|
||||
{
|
||||
assert(this.size > 0);
|
||||
return this.elems[--this.size];
|
||||
}
|
||||
|
||||
fn bool Stack.empty(Stack* this)
|
||||
{
|
||||
return !this.size;
|
||||
}
|
||||
```
|
||||
|
||||
Make sure you have the standard libraries at either `../lib/std/` or `/lib/std/`.
|
||||
Testing it out:
|
||||
|
||||
Then run
|
||||
```sh
|
||||
c3c compile main.c3
|
||||
```cpp
|
||||
import stack;
|
||||
|
||||
// Define our new types, the first will implicitly create
|
||||
// a complete copy of the entire Stack module with "Type" set to "int"
|
||||
define IntStack = Stack<int>;
|
||||
// The second creates another copy with "Type" set to "double"
|
||||
define DoubleStack = Stack<double>;
|
||||
|
||||
// If we had added "define IntStack2 = Stack<int>"
|
||||
// no additional copy would have been made (since we already
|
||||
// have an parameterization of Stack<int>) so it would
|
||||
// be same as declaring IntStack2 an alias of IntStack
|
||||
|
||||
// Importing an external C function is straightforward
|
||||
// here is an example of importing libc's printf:
|
||||
extern fn int printf(char* format, ...);
|
||||
|
||||
fn void test()
|
||||
{
|
||||
IntStack stack;
|
||||
// Note that C3 uses zero initialization by default
|
||||
// so the above is equivalent to IntStack stack = {};
|
||||
|
||||
stack.push(1);
|
||||
// The above can also be written IntStack.push(&stack, 1);
|
||||
|
||||
stack.push(2);
|
||||
|
||||
// Prints pop: 2
|
||||
printf("pop: %d\n", stack.pop());
|
||||
// Prints pop: 1
|
||||
printf("pop: %d\n", stack.pop());
|
||||
|
||||
DoubleStack dstack;
|
||||
dstack.push(2.3);
|
||||
dstack.push(3.141);
|
||||
dstack.push(1.1235);
|
||||
// Prints pop: 1.1235
|
||||
printf("pop: %f\n", dstack.pop());
|
||||
}
|
||||
```
|
||||
|
||||
The generated binary will be called `a.out`.
|
||||
|
||||
### In what ways do C3 differ from C?
|
||||
|
||||
- No mandatory header files
|
||||
@@ -50,7 +121,6 @@ The generated binary will be called `a.out`.
|
||||
- Defer
|
||||
- Value methods
|
||||
- Associated enum data
|
||||
- Built-in hooks for convenient string handling
|
||||
- No preprocessor
|
||||
- Less undefined behaviour and runtime checks in "safe" mode
|
||||
- Limited operator overloading to enable userland dynamic arrays
|
||||
@@ -58,107 +128,68 @@ The generated binary will be called `a.out`.
|
||||
|
||||
### Current status
|
||||
|
||||
The current version of the compiler is alpha release 0.2.
|
||||
|
||||
It's possible to try out the current C3 compiler in the browser: https://ide.judge0.com/ – this is courtesy of the
|
||||
developer of Judge0.
|
||||
|
||||
Design work is still being done in the design draft here: https://c3lang.github.io/c3docs/. If you have any suggestions, send a mail to [christoffer@aegik.com](mailto:christoffer@aegik.com), [file an issue](https://github.com/c3lang/c3c/issues) or discuss
|
||||
C3 on its dedicated Discord: https://discord.gg/qN76R87
|
||||
Design work on C3 complete aside from fleshing out details, such as
|
||||
inline asm. As the standard library work progresses, changes and improvements
|
||||
to the language will happen continuously.
|
||||
Follow the issues [here](https://github.com/c3lang/c3c/issues).
|
||||
|
||||
The compiler should compile on Linux, Windows (under Mingw or MSYS2) and MacOS,
|
||||
but needs some install documentation for Windows.
|
||||
If you have suggestions on how to improve the language, either [file an issue](https://github.com/c3lang/c3c/issues)
|
||||
or discuss C3 on its dedicated Discord: [https://discord.gg/qN76R87](https://discord.gg/qN76R87).
|
||||
|
||||
Due to its ABI compatibility with C, it's possible to mix C and C3 in the same project.
|
||||
As a demonstration, vkQuake was compiled with a small portion of the code converted
|
||||
to C3 and compiled with the c3c compiler:
|
||||
The compiler is currently verified to compile on Linux, Windows and MacOS.
|
||||
|
||||

|
||||
|
||||
(The vkFork is at https://github.com/c3lang/vkQuake)
|
||||
|
||||
#### Todo / done
|
||||
|
||||
- [x] For/while/do
|
||||
- [x] `if`/ternary
|
||||
- [x] Structs
|
||||
- [x] Union
|
||||
- [x] Enums
|
||||
- [x] Value methods
|
||||
- [x] Compound literals
|
||||
- [x] Designated initalizers
|
||||
- [x] Slicing syntax
|
||||
- [x] Arrays and subarrays
|
||||
- [x] Modules
|
||||
- [x] `$unreachable`
|
||||
- [x] Compile time assert with `$assert`
|
||||
- [x] Compiler guiding `assert`
|
||||
- [x] C code calling by declaring methods `extern`
|
||||
- [x] Compile time variables
|
||||
- [x] Basic macros
|
||||
- [x] 4cc, 8cc, 2cc
|
||||
- [x] Enum type inference in switch/assignment
|
||||
- [x] Integer type inference
|
||||
- [x] Error type
|
||||
- [x] Failable error handling
|
||||
- [x] `try` for conditional execution
|
||||
- [x] `catch` for error handling
|
||||
- [x] Implicit unwrap after `catch`
|
||||
- [x] `sizeof`
|
||||
- [x] `typeof`
|
||||
- [x] 2s complement wrapping operators
|
||||
- [x] Labelled break / continue
|
||||
- [x] `nextcase` statement
|
||||
- [x] Expression blocks
|
||||
- [x] Do-without-while
|
||||
- [x] Foreach statement
|
||||
- [x] Templates
|
||||
- [x] Distinct types
|
||||
- [x] Built-in linking
|
||||
- [x] CT only macros evaluating to constants
|
||||
- [x] range initializers e.g. `{ [1..2] = 2 }`
|
||||
- [x] Trailing body macros e.g. `@foo(1, 100; int a) { bar(a); };`
|
||||
- [x] Complex macros
|
||||
- [x] CT type constants
|
||||
- [ ] Anonymous structs
|
||||
- [ ] Complete C ABI conformance *in progress*
|
||||
- [ ] Debug info *in progress*
|
||||
- [ ] Virtual type *in progress*
|
||||
- [ ] Enum associated data support
|
||||
- [ ] Windows support *in progress*
|
||||
- [ ] All attributes *in progress*
|
||||
- [ ] Associative array literals
|
||||
- [ ] Reflection methods
|
||||
- [ ] LTO/ThinLTO setup
|
||||
- [ ] `global` / `shared` for globals
|
||||
- [ ] Escape macros
|
||||
- [ ] Implicit capturing macros
|
||||
- [ ] Subarray initializers
|
||||
- [ ] Bitstructs
|
||||
- [ ] `asm` section
|
||||
- [ ] `$switch`
|
||||
- [ ] `$for`
|
||||
- [ ] Pre-post conditions
|
||||
- [ ] Stdlib inclusion
|
||||
- [ ] String functions
|
||||
- [ ] Simd vector types
|
||||
|
||||
#### What can you help with?
|
||||
|
||||
- If you wish to contribute with ideas, please file issues on the c3docs: https://github.com/c3lang/c3docs instead of the compiler.
|
||||
- Discuss the language on discord to help iron out syntax.
|
||||
- If you wish to contribute with ideas, please file issues or discuss on Discord.
|
||||
- Interested in contributing to the stdlib? Please get in touch on Discord.
|
||||
- Are you a Windows dev? Please help make the compiler work on Windows!
|
||||
- Install instructions for other Linux and Unix variants are appreciated.
|
||||
- Would you like to contribute bindings to some library? It would be nice to have support for SDL, Raylib and more.
|
||||
- Build something with C3 and show it off and give feedback. The language is still open for significant tweaks.
|
||||
- Start work on the C -> C3 converter which takes C code and does a "best effort" to translate it to C3. The first version only needs to work on C headers.
|
||||
- Do you have some specific area you have deep knowledge of and could help make C3 even better at doing? File or comment on issues.
|
||||
|
||||
### Installing
|
||||
|
||||
#### Installing on Windows
|
||||
|
||||
1. Make sure you have Visual Studio 17 2022 installed.
|
||||
2. Install CMake
|
||||
3. Clone the C3C github repository: `git clone https://github.com/c3lang/c3c.git`
|
||||
4. Enter the C3C directory `cd c3c`.
|
||||
5. Set up the CMake build `cmake -B build -G "Visual Studio 17 2022" -A x64 -DCMAKE_BUILD_TYPE=Release`
|
||||
6. Build: `cmake --build build --config Release`
|
||||
7. You should now have the c3c.exe
|
||||
|
||||
You should now have a `c3c` executable.
|
||||
|
||||
You can try it out by running some sample code: `c3c.exe compile ../resources/examples/hash.c3`
|
||||
|
||||
#### Installing on Arch Linux
|
||||
There is an AUR package for the C3C compiler : [c3c-git](https://aur.archlinux.org/packages/c3c-git)
|
||||
You can use your AUR package manager or clone it manually:
|
||||
```sh
|
||||
git clone https://aur.archlinux.org/c3c-git.git
|
||||
cd c3c-git
|
||||
makepkg -si
|
||||
```
|
||||
|
||||
#### Installing on Ubuntu 20.10
|
||||
|
||||
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 11: `sudo apt-get install clang-11 zlib1g zlib1g-dev libllvm11 llvm-11 llvm-11-dev llvm-11-runtime liblld-11-dev liblld-11`
|
||||
3. Install LLVM 12 (or greater: C3C supports LLVM 12-15): `sudo apt-get install clang-12 zlib1g zlib1g-dev libllvm12 llvm-12 llvm-12-dev llvm-12-runtime liblld-12-dev liblld-12`
|
||||
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`
|
||||
7. Change directory to the build directory `cd build`
|
||||
8. Set up CMake build for debug: `cmake -DLLVM_DIR=/usr/lib/llvm-11/cmake -DCMAKE_BUILD_TYPE=Debug ..`
|
||||
8. Set up CMake build: `cmake ..`
|
||||
9. Build: `cmake --build .`
|
||||
|
||||
You should now have a `c3c` executable.
|
||||
@@ -185,10 +216,53 @@ A `c3c` executable will be found under `bin/`.
|
||||
#### Installing on OS X using Homebrew
|
||||
|
||||
2. Install CMake: `brew install cmake`
|
||||
3. Install LLVM 11: `brew install llvm`
|
||||
3. Install LLVM 13: `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`
|
||||
7. Change directory to the build directory `cd build`
|
||||
8. Set up CMake build for debug: `cmake ..`
|
||||
9. Build: `cmake --build .`
|
||||
|
||||
#### Installing on other Linux / Unix variants
|
||||
|
||||
1. Install CMake.
|
||||
2. Install or compile LLVM and LLD *libraries* (version 12+ 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`
|
||||
6. Change directory to the build directory `cd build`
|
||||
7. Set up CMake build for debug: `cmake ..`. At this point you may need to manually
|
||||
provide the link path to the LLVM CMake directories, e.g. `cmake -DLLVM_DIR=/usr/local/opt/llvm/lib/cmake/llvm/ ..`
|
||||
8. Build: `cmake --build .`
|
||||
|
||||
#### Getting started with a "hello world"
|
||||
|
||||
Create a `main.c3` file with:
|
||||
```c++
|
||||
module hello_world;
|
||||
import std::io;
|
||||
|
||||
fn void main()
|
||||
{
|
||||
io::println("Hello, world!");
|
||||
}
|
||||
```
|
||||
|
||||
Make sure you have the standard libraries at either `../lib/std/` or `/lib/std/`.
|
||||
|
||||
Then run
|
||||
```sh
|
||||
c3c compile main.c3
|
||||
```
|
||||
|
||||
The generated binary will be called `a.out`.
|
||||
|
||||
#### Licensing
|
||||
|
||||
The C3 compiler is licensed under LGPL 3.0, the standard library itself is
|
||||
MIT licensed.
|
||||
|
||||
#### Editor plugins
|
||||
|
||||
Editor plugins can be found at https://github.com/c3lang/editor-plugins.
|
||||
|
||||
@@ -2,17 +2,26 @@
|
||||
## build-with-docker.sh
|
||||
## @author gdm85
|
||||
##
|
||||
## Script to build c3c for either Ubuntu 18 or Ubuntu 20.
|
||||
## Script to build c3c for either Ubuntu 20, 21 or 22.
|
||||
##
|
||||
#
|
||||
|
||||
if [ $# -ne 1 -a $# -ne 2 ]; then
|
||||
echo "Usage: build-with-docker.sh (18|20) [Debug|Release]" 1>&2
|
||||
echo "Usage: build-with-docker.sh (20|21|22) [Debug|Release]" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -e
|
||||
|
||||
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 [ -z "$2" ]; then
|
||||
CMAKE_BUILD_TYPE=Debug
|
||||
else
|
||||
@@ -20,23 +29,28 @@ else
|
||||
fi
|
||||
|
||||
TAG="$1"
|
||||
if [ "$1" = 18 ]; then
|
||||
UBUNTU_VERSION="18.04"
|
||||
DEPS="llvm-10-dev liblld-10-dev libclang-10-dev"
|
||||
elif [ "$1" = 20 ]; then
|
||||
if [ "$1" = 20 ]; then
|
||||
UBUNTU_VERSION="20.04"
|
||||
DEPS="llvm-11-dev liblld-11-dev clang-11 libllvm11 llvm-11-runtime"
|
||||
LLVM_VERSION="12"
|
||||
elif [ "$1" = 21 ]; then
|
||||
UBUNTU_VERSION="21.10"
|
||||
LLVM_VERSION="13"
|
||||
elif [ "$1" = 22 ]; then
|
||||
UBUNTU_VERSION="22.04"
|
||||
LLVM_VERSION="14"
|
||||
else
|
||||
echo "ERROR: expected 18 or 20 as Ubuntu version argument" 1>&2
|
||||
echo "ERROR: expected 20, 21 or 22 as Ubuntu version argument" 1>&2
|
||||
exit 2
|
||||
fi
|
||||
IMAGE="$IMAGE:$TAG"
|
||||
|
||||
cd docker && docker build -t c3c-builder:$TAG --build-arg UID=$(id -u) --build-arg GID=$(id -g) \
|
||||
--build-arg DEPS="$DEPS" --build-arg UBUNTU_VERSION="$UBUNTU_VERSION" .
|
||||
cd docker && $DOCKER build -t $IMAGE --build-arg UID=$(id -u) --build-arg GID=$(id -g) \
|
||||
--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 lib
|
||||
rm -rf build bin
|
||||
mkdir -p build bin
|
||||
|
||||
exec docker run -ti --rm -v "$PWD":/home/c3c/source -w /home/c3c/source c3c-builder:$TAG bash -c \
|
||||
"cd build && cmake -DLLVM_DIR=/usr/lib/llvm-11/cmake -DCMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE .. && cmake --build . && mv c3c ../bin/ && mv lib ../lib"
|
||||
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/"
|
||||
|
||||
5
lib/std/atomic.c3
Normal file
5
lib/std/atomic.c3
Normal file
@@ -0,0 +1,5 @@
|
||||
// Copyright (c) 2021 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::atomic;
|
||||
|
||||
182
lib/std/core/allocators/dynamic_arena.c3
Normal file
182
lib/std/core/allocators/dynamic_arena.c3
Normal file
@@ -0,0 +1,182 @@
|
||||
module std::core::mem::allocator;
|
||||
|
||||
private struct DynamicArenaPage
|
||||
{
|
||||
void* memory;
|
||||
void* prev_arena;
|
||||
usize total;
|
||||
usize used;
|
||||
void* last_ptr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @require ptr && this
|
||||
* @require this.page `tried to free pointer on invalid allocator`
|
||||
*/
|
||||
private fn void DynamicArenaAllocator.free(DynamicArenaAllocator* this, void* ptr)
|
||||
{
|
||||
DynamicArenaPage* current_page = this.page;
|
||||
if (ptr == current_page.last_ptr)
|
||||
{
|
||||
current_page.used = (usize)((ptr - DEFAULT_SIZE_PREFIX) - current_page.memory);
|
||||
}
|
||||
current_page.last_ptr = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require old_pointer && size > 0
|
||||
* @require this.page `tried to realloc pointer on invalid allocator`
|
||||
*/
|
||||
private fn void*! DynamicArenaAllocator.realloc(DynamicArenaAllocator* this, void* old_pointer, usize size, usize alignment)
|
||||
{
|
||||
DynamicArenaPage* current_page = this.page;
|
||||
alignment = alignment_for_allocation(alignment);
|
||||
usize* old_size_ptr = old_pointer - DEFAULT_SIZE_PREFIX;
|
||||
usize old_size = *old_size_ptr;
|
||||
// We have the old pointer and it's correctly aligned.
|
||||
if (old_size >= size && mem::ptr_is_aligned(old_pointer, alignment))
|
||||
{
|
||||
*old_size_ptr = size;
|
||||
if (current_page.last_ptr == old_pointer)
|
||||
{
|
||||
current_page.used = (usize)((old_pointer - DEFAULT_SIZE_PREFIX) - current_page.memory);
|
||||
}
|
||||
return old_pointer;
|
||||
}
|
||||
if REUSE: (current_page.last_ptr == old_pointer && mem::ptr_is_aligned(old_pointer, alignment))
|
||||
{
|
||||
assert(size > old_size);
|
||||
usize add_size = size - old_size;
|
||||
if (add_size + current_page.used > current_page.total) break REUSE;
|
||||
*old_size_ptr = size;
|
||||
current_page.used += add_size;
|
||||
return old_pointer;
|
||||
}
|
||||
void* new_mem = this.alloc(size, alignment)?;
|
||||
mem::copy(new_mem, old_pointer, old_size);
|
||||
return new_mem;
|
||||
}
|
||||
|
||||
private fn void DynamicArenaAllocator.reset(DynamicArenaAllocator* this)
|
||||
{
|
||||
DynamicArenaPage* page = this.page;
|
||||
DynamicArenaPage** unused_page_ptr = &this.unused_page;
|
||||
while (page)
|
||||
{
|
||||
DynamicArenaPage* next_page = page.prev_arena;
|
||||
page.used = 0;
|
||||
DynamicArenaPage* prev_unused = *unused_page_ptr;
|
||||
*unused_page_ptr = page;
|
||||
page.prev_arena = prev_unused;
|
||||
page = next_page;
|
||||
}
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require math::is_power_of_2(alignment)
|
||||
* @require size > 0
|
||||
*/
|
||||
private fn void*! DynamicArenaAllocator.alloc_new(DynamicArenaAllocator* this, usize size, usize alignment)
|
||||
{
|
||||
usize page_size = max(this.page_size, size + DEFAULT_SIZE_PREFIX + alignment);
|
||||
void* mem = this.backing_allocator.alloc(page_size)?;
|
||||
DynamicArenaPage*! page = this.backing_allocator.alloc(DynamicArenaPage.sizeof);
|
||||
if (catch err = page)
|
||||
{
|
||||
this.backing_allocator.free(mem)?;
|
||||
return err!;
|
||||
}
|
||||
page.memory = mem;
|
||||
usize offset = mem::aligned_offset((usize)mem + DEFAULT_SIZE_PREFIX, alignment) - (usize)mem;
|
||||
usize* size_ptr = mem + offset - DEFAULT_SIZE_PREFIX;
|
||||
*size_ptr = size;
|
||||
page.prev_arena = this.page;
|
||||
page.total = page_size;
|
||||
page.used = size + offset;
|
||||
this.page = page;
|
||||
|
||||
return page.last_ptr = page.memory + offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require !alignment || math::is_power_of_2(alignment)
|
||||
* @require size > 0
|
||||
* @require this
|
||||
*/
|
||||
private fn void*! DynamicArenaAllocator.alloc(DynamicArenaAllocator* this, usize size, usize alignment)
|
||||
{
|
||||
alignment = alignment_for_allocation(alignment);
|
||||
DynamicArenaPage* page = this.page;
|
||||
if (!page && this.unused_page)
|
||||
{
|
||||
this.page = page = this.unused_page;
|
||||
this.unused_page = page.prev_arena;
|
||||
page.prev_arena = null;
|
||||
}
|
||||
if (!page) return this.alloc_new(size, alignment);
|
||||
usize start = mem::aligned_offset((uptr)page.memory + page.used + DEFAULT_SIZE_PREFIX, alignment) - (usize)page.memory;
|
||||
usize new_used = start + size;
|
||||
if ALLOCATE_NEW: (new_used > page.total)
|
||||
{
|
||||
if ((page = this.unused_page))
|
||||
{
|
||||
start = mem::aligned_offset((uptr)page.memory + DEFAULT_SIZE_PREFIX, alignment) - (usize)page.memory;
|
||||
new_used = start + size;
|
||||
if (page.total >= new_used)
|
||||
{
|
||||
this.unused_page = page.prev_arena;
|
||||
page.prev_arena = this.page;
|
||||
this.page = page;
|
||||
break ALLOCATE_NEW;
|
||||
}
|
||||
}
|
||||
return this.alloc_new(size, alignment);
|
||||
}
|
||||
page.used = new_used;
|
||||
void* mem = page.memory + start;
|
||||
usize* size_offset = mem - DEFAULT_SIZE_PREFIX;
|
||||
*size_offset = size;
|
||||
return mem;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require !alignment || math::is_power_of_2(alignment)
|
||||
* @require data `unexpectedly missing the allocator`
|
||||
*/
|
||||
private fn void*! dynamic_arena_allocator_function(Allocator* data, usize size, usize alignment, void* old_pointer, AllocationKind kind)
|
||||
{
|
||||
DynamicArenaAllocator* allocator = (DynamicArenaAllocator*)data;
|
||||
switch (kind)
|
||||
{
|
||||
case CALLOC:
|
||||
assert(!old_pointer, "Unexpected no old pointer for calloc.");
|
||||
if (!size) return null;
|
||||
void* mem = allocator.alloc(size, alignment)?;
|
||||
mem::set(mem, 0, size);
|
||||
return mem;
|
||||
case ALLOC:
|
||||
assert(!old_pointer, "Unexpected no old pointer for alloc.");
|
||||
if (!size) return null;
|
||||
return allocator.alloc(size, alignment);
|
||||
case REALLOC:
|
||||
if (!size)
|
||||
{
|
||||
if (!old_pointer) return null;
|
||||
allocator.free(old_pointer);
|
||||
return null;
|
||||
}
|
||||
if (!old_pointer) return allocator.alloc(size, alignment);
|
||||
void* mem = allocator.realloc(old_pointer, size, alignment)?;
|
||||
return mem;
|
||||
case FREE:
|
||||
if (!old_pointer) return null;
|
||||
allocator.free(old_pointer);
|
||||
return null;
|
||||
case RESET:
|
||||
allocator.reset();
|
||||
return null;
|
||||
}
|
||||
unreachable();
|
||||
}
|
||||
68
lib/std/core/allocators/mem_allocator_fn.c3
Normal file
68
lib/std/core/allocators/mem_allocator_fn.c3
Normal file
@@ -0,0 +1,68 @@
|
||||
module std::core::mem::allocator;
|
||||
import libc;
|
||||
|
||||
private const Allocator _NULL_ALLOCATOR = { &null_allocator_fn };
|
||||
private const Allocator _SYSTEM_ALLOCATOR = { &libc_allocator_fn };
|
||||
|
||||
private fn void*! null_allocator_fn(Allocator* this, usize bytes, usize alignment, void* old_pointer, AllocationKind kind)
|
||||
{
|
||||
switch (kind)
|
||||
{
|
||||
case ALLOC:
|
||||
case CALLOC:
|
||||
case REALLOC:
|
||||
return AllocationFailure.OUT_OF_MEMORY!;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
fn void*! libc_allocator_fn(Allocator* unused, usize bytes, usize alignment, void* old_pointer, AllocationKind kind) @inline
|
||||
{
|
||||
if (!alignment) alignment = DEFAULT_MEM_ALIGNMENT;
|
||||
assert(math::is_power_of_2(alignment), "Alignment was not a power of 2");
|
||||
|
||||
void* data;
|
||||
switch (kind)
|
||||
{
|
||||
case ALLOC:
|
||||
if (alignment > DEFAULT_MEM_ALIGNMENT)
|
||||
{
|
||||
data = (void*)mem::aligned_offset((iptr)libc::malloc(bytes + alignment), alignment);
|
||||
}
|
||||
else
|
||||
{
|
||||
data = libc::malloc(bytes);
|
||||
}
|
||||
if (!data) return AllocationFailure.OUT_OF_MEMORY!;
|
||||
return data;
|
||||
case CALLOC:
|
||||
if (alignment > DEFAULT_MEM_ALIGNMENT)
|
||||
{
|
||||
data = (void*)mem::aligned_offset((iptr)libc::calloc(bytes + alignment, 1), alignment);
|
||||
}
|
||||
else
|
||||
{
|
||||
data = libc::malloc(bytes);
|
||||
}
|
||||
if (!data) return AllocationFailure.OUT_OF_MEMORY!;
|
||||
return data;
|
||||
case REALLOC:
|
||||
if (alignment > DEFAULT_MEM_ALIGNMENT)
|
||||
{
|
||||
data = (void*)mem::aligned_offset((iptr)libc::realloc(old_pointer, bytes + alignment), alignment);
|
||||
}
|
||||
else
|
||||
{
|
||||
data = libc::realloc(old_pointer, bytes);
|
||||
}
|
||||
if (!data) return AllocationFailure.OUT_OF_MEMORY!;
|
||||
return data;
|
||||
case RESET:
|
||||
return AllocationFailure.UNSUPPORTED_OPERATION!;
|
||||
case FREE:
|
||||
libc::free(old_pointer);
|
||||
return null;
|
||||
}
|
||||
unreachable();
|
||||
}
|
||||
82
lib/std/core/allocators/memory_arena.c3
Normal file
82
lib/std/core/allocators/memory_arena.c3
Normal file
@@ -0,0 +1,82 @@
|
||||
module std::core::mem::allocator;
|
||||
|
||||
/**
|
||||
* @require !alignment || math::is_power_of_2(alignment)
|
||||
* @require data `unexpectedly missing the allocator`
|
||||
*/
|
||||
private fn void*! arena_allocator_function(Allocator* data, usize size, usize alignment, void* old_pointer, AllocationKind kind)
|
||||
{
|
||||
MemoryArena* arena = (MemoryArena*)data;
|
||||
switch (kind)
|
||||
{
|
||||
case CALLOC:
|
||||
case ALLOC:
|
||||
assert(!old_pointer, "Unexpected old pointer for alloc.");
|
||||
if (!size) return null;
|
||||
alignment = alignment_for_allocation(alignment);
|
||||
void* mem = arena.alloc(size, alignment, DEFAULT_SIZE_PREFIX)?;
|
||||
*(usize*)(mem - DEFAULT_SIZE_PREFIX) = size;
|
||||
if (kind == AllocationKind.CALLOC) mem::set(mem, 0, size);
|
||||
return mem;
|
||||
case REALLOC:
|
||||
if (!size) nextcase FREE;
|
||||
if (!old_pointer) nextcase ALLOC;
|
||||
assert((uptr)old_pointer >= (uptr)arena.memory, "Pointer originates from a different allocator.");
|
||||
if (size > arena.total) return AllocationFailure.OUT_OF_MEMORY!;
|
||||
alignment = alignment_for_allocation(alignment);
|
||||
usize* old_size_ptr = (usize*)(old_pointer - DEFAULT_SIZE_PREFIX);
|
||||
usize old_size = *old_size_ptr;
|
||||
// Do last allocation and alignment match?
|
||||
if (arena.memory + arena.used == old_pointer + old_size && mem::ptr_is_aligned(old_pointer, alignment))
|
||||
{
|
||||
if (old_size >= size)
|
||||
{
|
||||
*old_size_ptr = size;
|
||||
arena.used -= old_size - size;
|
||||
return old_pointer;
|
||||
}
|
||||
usize new_used = arena.used + size - old_size;
|
||||
if (new_used > arena.total) return AllocationFailure.OUT_OF_MEMORY!;
|
||||
arena.used = new_used;
|
||||
*old_size_ptr = size;
|
||||
return old_pointer;
|
||||
}
|
||||
// Otherwise just allocate new memory.
|
||||
void* mem = arena.alloc(size, alignment, DEFAULT_SIZE_PREFIX)?;
|
||||
*(usize*)(mem - DEFAULT_SIZE_PREFIX) = size;
|
||||
mem::copy(mem, old_pointer, old_size);
|
||||
return mem;
|
||||
case FREE:
|
||||
if (!old_pointer) return null;
|
||||
assert((uptr)old_pointer >= (uptr)arena.memory, "Pointer originates from a different allocator.");
|
||||
usize old_size = *(usize*)(old_pointer - DEFAULT_SIZE_PREFIX);
|
||||
if (old_pointer + old_size == arena.memory + arena.used)
|
||||
{
|
||||
arena.used -= old_size;
|
||||
}
|
||||
return null;
|
||||
case RESET:
|
||||
arena.used = 0;
|
||||
return null;
|
||||
}
|
||||
unreachable();
|
||||
}
|
||||
|
||||
/**
|
||||
* @require alignment > 0 `alignment must be non zero`
|
||||
* @require math::is_power_of_2(alignment)
|
||||
* @require size > 0
|
||||
* @require alignment <= MAX_MEMORY_ALIGNMENT `alignment too big`
|
||||
* @require this != null
|
||||
**/
|
||||
private fn void*! MemoryArena.alloc(MemoryArena* this, usize size, usize alignment, usize prefixed_bytes = 0)
|
||||
{
|
||||
void* start_mem = this.memory;
|
||||
void* unaligned_pointer = start_mem + this.used + prefixed_bytes;
|
||||
if ((uptr)unaligned_pointer < (uptr)start_mem) return AllocationFailure.OUT_OF_MEMORY!;
|
||||
usize offset_start = mem::aligned_offset((usize)(uptr)unaligned_pointer, alignment) - (usize)(uptr)start_mem;
|
||||
usize end = offset_start + size;
|
||||
if (end > this.total || end < offset_start) return AllocationFailure.OUT_OF_MEMORY!;
|
||||
this.used = end;
|
||||
return start_mem + offset_start;
|
||||
}
|
||||
115
lib/std/core/builtin.c3
Normal file
115
lib/std/core/builtin.c3
Normal file
@@ -0,0 +1,115 @@
|
||||
// Copyright (c) 2021-2022 Christoffer Lerno and contributors. 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::core::builtin;
|
||||
import libc;
|
||||
|
||||
fault IteratorResult
|
||||
{
|
||||
NO_MORE_ELEMENT
|
||||
}
|
||||
|
||||
fault SearchResult
|
||||
{
|
||||
MISSING
|
||||
}
|
||||
|
||||
fault VarCastResult
|
||||
{
|
||||
TYPE_MISMATCH
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a variable on the stack, then restores it at the end of the
|
||||
* macro scope.
|
||||
*
|
||||
* @param variable `the variable to store and restore`
|
||||
**/
|
||||
macro void @scope(&variable; @body) @builtin
|
||||
{
|
||||
$typeof(variable) temp = variable;
|
||||
defer variable = temp;
|
||||
@body();
|
||||
}
|
||||
|
||||
macro void @swap(&a, &b) @builtin
|
||||
{
|
||||
$typeof(a) temp = a;
|
||||
a = b;
|
||||
b = temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a variant type to a type, returning an failure if there is a type mismatch.
|
||||
*
|
||||
* @param v `the variant to convert to the given type.`
|
||||
* @param $Type `the type to convert to`
|
||||
* @return `The variant.ptr converted to its type.`
|
||||
**/
|
||||
macro varcast(variant v, $Type) @builtin
|
||||
{
|
||||
if (v.type != $Type.typeid) return VarCastResult.TYPE_MISMATCH!;
|
||||
return ($Type*)v.ptr;
|
||||
}
|
||||
|
||||
struct CallstackElement
|
||||
{
|
||||
CallstackElement* prev;
|
||||
char* function;
|
||||
char* file;
|
||||
uint line;
|
||||
}
|
||||
|
||||
fn void panic(char* message, char *file, char *function, uint line) @builtin
|
||||
{
|
||||
CallstackElement* stack = $$stacktrace();
|
||||
$if ($defined(libc::stderr) && $defined(libc::fprintf)):
|
||||
|
||||
if (stack) stack = stack.prev;
|
||||
if (stack)
|
||||
{
|
||||
libc::fprintf(libc::stderr(), "\nERROR: '%s'\n", message);
|
||||
}
|
||||
else
|
||||
{
|
||||
libc::fprintf(libc::stderr(), "\nERROR: '%s', function %s (%s:%d)\n", message, function, file, line);
|
||||
}
|
||||
while (stack)
|
||||
{
|
||||
libc::fprintf(libc::stderr(), " at function %s (%s:%u)\n", stack.function, stack.file, stack.line);
|
||||
if (stack == stack.prev) break;
|
||||
stack = stack.prev;
|
||||
}
|
||||
|
||||
$endif;
|
||||
|
||||
$$trap();
|
||||
}
|
||||
|
||||
macro void unreachable($string = "Unreachable statement reached.") @builtin @noreturn
|
||||
{
|
||||
panic($string, $$FILE, $$FUNC, $$LINE);
|
||||
$$unreachable();
|
||||
}
|
||||
|
||||
macro bitcast(expr, $Type) @builtin
|
||||
{
|
||||
var $size = (usize)($sizeof(expr));
|
||||
$assert($size == $Type.sizeof, "Cannot bitcast between types of different size.");
|
||||
$Type x = void;
|
||||
mem::memcpy(&x, &expr, $size, false, $alignof($Type), $alignof(expr));
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require $Type.kind == TypeKind.ENUM `Only enums may be used`
|
||||
**/
|
||||
macro enum_by_name($Type, char[] enum_name) @builtin
|
||||
{
|
||||
typeid x = $Type.typeid;
|
||||
foreach (i, name : x.names)
|
||||
{
|
||||
if (str::compare(name, enum_name)) return ($Type)i;
|
||||
}
|
||||
return SearchResult.MISSING!;
|
||||
}
|
||||
76
lib/std/core/builtin_comparison.c3
Normal file
76
lib/std/core/builtin_comparison.c3
Normal file
@@ -0,0 +1,76 @@
|
||||
// Copyright (c) 2021-2022 Christoffer Lerno and contributors. 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::core::builtin;
|
||||
|
||||
/**
|
||||
* @require is_comparable_value(a) && is_comparable_value(b)
|
||||
**/
|
||||
macro less(a, b) @builtin
|
||||
{
|
||||
$if ($defined(a.less)):
|
||||
return a.less(b);
|
||||
$elif ($defined(a.compare_to)):
|
||||
return a.compare_to(b) < 0;
|
||||
$else:
|
||||
return a < b;
|
||||
$endif;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require is_comparable_value(a) && is_comparable_value(b)
|
||||
**/
|
||||
macro less_eq(a, b) @builtin
|
||||
{
|
||||
$if ($defined(a.less)):
|
||||
return !b.less(a);
|
||||
$elif ($defined(a.compare_to)):
|
||||
return a.compare_to(b) <= 0;
|
||||
$else:
|
||||
return a <= b;
|
||||
$endif;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require is_comparable_value(a) && is_comparable_value(b)
|
||||
**/
|
||||
macro greater(a, b) @builtin
|
||||
{
|
||||
$if ($defined(a.less)):
|
||||
return b.less(a);
|
||||
$elif ($defined(a.compare_to)):
|
||||
return a.compare_to(b) > 0;
|
||||
$else:
|
||||
return a > b;
|
||||
$endif;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require is_comparable_value(a) && is_comparable_value(b)
|
||||
**/
|
||||
macro greater_eq(a, b) @builtin
|
||||
{
|
||||
$if ($defined(a.less)):
|
||||
return !a.less(b);
|
||||
$elif ($defined(a.compare_to)):
|
||||
return a.compare_to(b) >= 0;
|
||||
$else:
|
||||
return a >= b;
|
||||
$endif;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require is_equatable_value(a) && is_equatable_value(b) `values must be equatable`
|
||||
**/
|
||||
macro bool equals(a, b) @builtin
|
||||
{
|
||||
$if ($defined(a.equals)):
|
||||
return a.equals(b);
|
||||
$elif ($defined(a.compare_to)):
|
||||
return a.compare_to(b) == 0;
|
||||
$elif ($defined(a.less)):
|
||||
return !a.less(b) && !b.less(a);
|
||||
$else:
|
||||
return a == b;
|
||||
$endif;
|
||||
}
|
||||
@@ -1,9 +1,12 @@
|
||||
module std::cinterop;
|
||||
// Copyright (c) 2021 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::core::cinterop;
|
||||
|
||||
const C_INT_SIZE = ${C_INT_SIZE};
|
||||
const C_LONG_SIZE = ${C_LONG_SIZE};
|
||||
const C_SHORT_SIZE = ${C_SHORT_SIZE};
|
||||
const C_LONG_LONG_SIZE = ${C_LONG_LONG_SIZE};
|
||||
const C_INT_SIZE = $$C_INT_SIZE;
|
||||
const C_LONG_SIZE = $$C_LONG_SIZE;
|
||||
const C_SHORT_SIZE = $$C_SHORT_SIZE;
|
||||
const C_LONG_LONG_SIZE = $$C_LONG_LONG_SIZE;
|
||||
|
||||
$assert (C_SHORT_SIZE < 32);
|
||||
$assert (C_INT_SIZE < 128);
|
||||
@@ -13,65 +16,71 @@ $assert (C_SHORT_SIZE <= C_INT_SIZE);
|
||||
$assert (C_INT_SIZE <= C_LONG_SIZE);
|
||||
$assert (C_LONG_SIZE <= C_LONG_LONG_SIZE);
|
||||
|
||||
$if (C_INT_SIZE == 64):
|
||||
$switch ($$C_INT_SIZE):
|
||||
$case 64:
|
||||
define CInt = long;
|
||||
define CUInt = ulong;
|
||||
$elif (C_INT_SIZE == 32):
|
||||
$case 32:
|
||||
define CInt = int;
|
||||
define CUInt = uint;
|
||||
$elif (C_INT_SIZE == 16):
|
||||
$case 16:
|
||||
define CInt = short;
|
||||
define CUInt = ushort;
|
||||
$else:
|
||||
$default:
|
||||
$assert(false, "Invalid C int size");
|
||||
$endif;
|
||||
$endswitch;
|
||||
|
||||
$if (C_LONG_SIZE == 64):
|
||||
$switch ($$C_LONG_SIZE):
|
||||
$case 64:
|
||||
define CLong = long;
|
||||
define CULong = ulong;
|
||||
$elif (C_LONG_SIZE == 32):
|
||||
$case 32:
|
||||
define CLong = int;
|
||||
define CULong = uint;
|
||||
$elif (C_LONG_SIZE == 16):
|
||||
$case 16:
|
||||
define CLong = short;
|
||||
define CULong = ushort;
|
||||
$else:
|
||||
$default:
|
||||
$assert(false, "Invalid C long size");
|
||||
$endif;
|
||||
$endswitch;
|
||||
|
||||
$if (C_SHORT_SIZE == 32):
|
||||
$switch ($$C_SHORT_SIZE):
|
||||
$case 32:
|
||||
define CShort = int;
|
||||
define CUShort = uint;
|
||||
$elif (C_SHORT_SIZE == 16):
|
||||
$case 16:
|
||||
define CShort = short;
|
||||
define CUShort = ushort;
|
||||
$elif (C_SHORT_SIZE == 8):
|
||||
$case 8:
|
||||
define CShort = ichar;
|
||||
define CUShort = char;
|
||||
$else:
|
||||
$default:
|
||||
$assert(false, "Invalid C short size");
|
||||
$endif;
|
||||
$endswitch;
|
||||
|
||||
$if (C_LONG_LONG_SIZE == 128):
|
||||
$switch ($$C_LONG_LONG_SIZE):
|
||||
$case 128:
|
||||
define CLongLong = int128;
|
||||
define CULongLong = uint128;
|
||||
$elif (C_LONG_LONG_SIZE == 64):
|
||||
$case 64:
|
||||
define CLongLong = long;
|
||||
define CULongLong = ulong;
|
||||
$elif (C_LONG_LONG_SIZE == 32):
|
||||
$case 32:
|
||||
define CLongLong = int;
|
||||
define CULongLong = uint;
|
||||
$elif (C_LONG_LONG_SIZE == 16):
|
||||
$case 16:
|
||||
define CLongLong = short;
|
||||
define CULongLong = ushort;
|
||||
$else:
|
||||
$default:
|
||||
$assert(false, "Invalid C long long size");
|
||||
$endif;
|
||||
$endswitch;
|
||||
|
||||
|
||||
|
||||
define CSChar = ichar;
|
||||
define CUChar = char;
|
||||
|
||||
$if (${C_CHAR_IS_SIGNED}):
|
||||
$if ($$C_CHAR_IS_SIGNED):
|
||||
define CChar = ichar;
|
||||
$else:
|
||||
define CChar = char;
|
||||
404
lib/std/core/conv.c3
Normal file
404
lib/std/core/conv.c3
Normal file
@@ -0,0 +1,404 @@
|
||||
module std::core::string::conv;
|
||||
|
||||
private const uint UTF16_SURROGATE_OFFSET = 0x10000;
|
||||
private const uint UTF16_SURROGATE_GENERIC_MASK = 0xF800;
|
||||
private const uint UTF16_SURROGATE_GENERIC_VALUE = 0xD800;
|
||||
private const uint UTF16_SURROGATE_MASK = 0xFC00;
|
||||
private const uint UTF16_SURROGATE_CODEPOINT_MASK = 0x03FF;
|
||||
private const uint UTF16_SURROGATE_BITS = 10;
|
||||
private const uint UTF16_SURROGATE_LOW_VALUE = 0xDC00;
|
||||
private const uint UTF16_SURROGATE_HIGH_VALUE = 0xD800;
|
||||
|
||||
/**
|
||||
* @param c `The utf32 codepoint to convert`
|
||||
* @param [out] output `the resulting buffer`
|
||||
* @param available `the size available`
|
||||
**/
|
||||
fn usize! char32_to_utf8(Char32 c, char* output, usize available)
|
||||
{
|
||||
if (!available) return UnicodeResult.CONVERSION_FAILED!;
|
||||
switch (true)
|
||||
{
|
||||
case c < 0x7f:
|
||||
output[0] = (char)c;
|
||||
return 1;
|
||||
case c < 0x7ff:
|
||||
if (available < 2) return UnicodeResult.CONVERSION_FAILED!;
|
||||
output[0] = (char)(0xC0 | c >> 6);
|
||||
output[1] = (char)(0x80 | (c & 0x3F));
|
||||
return 2;
|
||||
case c < 0xffff:
|
||||
if (available < 3) return UnicodeResult.CONVERSION_FAILED!;
|
||||
output[0] = (char)(0xE0 | c >> 12);
|
||||
output[1] = (char)(0x80 | (c >> 6 & 0x3F));
|
||||
output[2] = (char)(0x80 | (c & 0x3F));
|
||||
return 3;
|
||||
default:
|
||||
if (available < 4) return UnicodeResult.CONVERSION_FAILED!;
|
||||
output[0] = (char)(0xF0 | c >> 18);
|
||||
output[1] = (char)(0x80 | (c >> 12 & 0x3F));
|
||||
output[2] = (char)(0x80 | (c >> 6 & 0x3F));
|
||||
output[3] = (char)(0x80 | (c & 0x3F));
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a code pointer into 1-2 UTF16 characters.
|
||||
*
|
||||
* @param c `The character to convert.`
|
||||
* @param [inout] output `the resulting UTF16 buffer to write to.`
|
||||
**/
|
||||
fn void char32_to_utf16_unsafe(Char32 c, Char16** output)
|
||||
{
|
||||
if (c < UTF16_SURROGATE_OFFSET)
|
||||
{
|
||||
(*output)++[0] = (Char16)c;
|
||||
return;
|
||||
}
|
||||
c -= UTF16_SURROGATE_OFFSET;
|
||||
Char16 low = (Char16)(UTF16_SURROGATE_LOW_VALUE | (c & UTF16_SURROGATE_CODEPOINT_MASK));
|
||||
c >>= UTF16_SURROGATE_BITS;
|
||||
Char16 high = (Char16)(UTF16_SURROGATE_HIGH_VALUE | (c & UTF16_SURROGATE_CODEPOINT_MASK));
|
||||
(*output)++[0] = (Char16)high;
|
||||
(*output)++[0] = (Char16)low;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert 1-2 UTF16 data points into UTF8.
|
||||
*
|
||||
* @param [in] ptr `The UTF16 data to convert.`
|
||||
* @param [inout] available `amount of UTF16 data available.`
|
||||
* @param [inout] output `the resulting utf8 buffer to write to.`
|
||||
**/
|
||||
fn void! char16_to_utf8_unsafe(Char16 *ptr, usize *available, char** output)
|
||||
{
|
||||
Char16 high = *ptr;
|
||||
if (high & UTF16_SURROGATE_GENERIC_MASK != UTF16_SURROGATE_GENERIC_VALUE)
|
||||
{
|
||||
char32_to_utf8_unsafe(high, output);
|
||||
*available = 1;
|
||||
return;
|
||||
}
|
||||
// Low surrogate first is an error
|
||||
if (high & UTF16_SURROGATE_MASK != UTF16_SURROGATE_HIGH_VALUE) return UnicodeResult.INVALID_UTF16!;
|
||||
|
||||
// Unmatched high surrogate is an error
|
||||
if (*available == 1) return UnicodeResult.INVALID_UTF16!;
|
||||
|
||||
Char16 low = ptr[1];
|
||||
|
||||
// Unmatched high surrogate, invalid
|
||||
if (low & UTF16_SURROGATE_MASK != UTF16_SURROGATE_LOW_VALUE) return UnicodeResult.INVALID_UTF16!;
|
||||
|
||||
// The high bits of the codepoint are the value bits of the high surrogate
|
||||
// The low bits of the codepoint are the value bits of the low surrogate
|
||||
Char32 uc = (high & UTF16_SURROGATE_CODEPOINT_MASK) << UTF16_SURROGATE_BITS
|
||||
| (low & UTF16_SURROGATE_CODEPOINT_MASK) + UTF16_SURROGATE_OFFSET;
|
||||
char32_to_utf8_unsafe(uc, output);
|
||||
*available = 2;
|
||||
}
|
||||
/**
|
||||
* @param c `The utf32 codepoint to convert`
|
||||
* @param [inout] output `the resulting buffer`
|
||||
**/
|
||||
fn void char32_to_utf8_unsafe(Char32 c, char** output)
|
||||
{
|
||||
switch (true)
|
||||
{
|
||||
case c < 0x7f:
|
||||
(*output)++[0] = (char)c;
|
||||
case c < 0x7ff:
|
||||
(*output)++[0] = (char)(0xC0 | c >> 6);
|
||||
(*output)++[0] = (char)(0x80 | (c & 0x3F));
|
||||
case c < 0xffff:
|
||||
(*output)++[0] = (char)(0xE0 | c >> 12);
|
||||
(*output)++[0] = (char)(0x80 | (c >> 6 & 0x3F));
|
||||
(*output)++[0] = (char)(0x80 | (c & 0x3F));
|
||||
default:
|
||||
(*output)++[0] = (char)(0xF0 | c >> 18);
|
||||
(*output)++[0] = (char)(0x80 | (c >> 12 & 0x3F));
|
||||
(*output)++[0] = (char)(0x80 | (c >> 6 & 0x3F));
|
||||
(*output)++[0] = (char)(0x80 | (c & 0x3F));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [in] ptr `pointer to the first character to parse`
|
||||
* @param [inout] size `Set to max characters to read, set to characters read`
|
||||
* @return `the parsed 32 bit codepoint`
|
||||
**/
|
||||
fn Char32! utf8_to_char32(char* ptr, usize* size)
|
||||
{
|
||||
usize max_size = *size;
|
||||
if (max_size < 1) return UnicodeResult.INVALID_UTF8!;
|
||||
char c = (ptr++)[0];
|
||||
|
||||
if ((c & 0x80) == 0)
|
||||
{
|
||||
*size = 1;
|
||||
return c;
|
||||
}
|
||||
if ((c & 0xE0) == 0xC0)
|
||||
{
|
||||
if (max_size < 2) return UnicodeResult.INVALID_UTF8!;
|
||||
*size = 2;
|
||||
Char32 uc = (c & 0x1F) << 6;
|
||||
c = *ptr;
|
||||
if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8!;
|
||||
return uc + c & 0x3F;
|
||||
}
|
||||
if ((c & 0xF0) == 0xE0)
|
||||
{
|
||||
if (max_size < 3) return UnicodeResult.INVALID_UTF8!;
|
||||
*size = 3;
|
||||
Char32 uc = (c & 0x0F) << 12;
|
||||
c = ptr++[0];
|
||||
if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8!;
|
||||
uc += (c & 0x3F) << 6;
|
||||
c = ptr++[0];
|
||||
if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8!;
|
||||
return uc + c & 0x3F;
|
||||
}
|
||||
if (max_size < 4) return UnicodeResult.INVALID_UTF8!;
|
||||
*size = 4;
|
||||
Char32 uc = (c & 0x07) << 18;
|
||||
c = ptr++[0];
|
||||
if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8!;
|
||||
uc += (c & 0x3F) << 12;
|
||||
c = ptr++[0];
|
||||
if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8!;
|
||||
uc += (c & 0x3F) << 6;
|
||||
c = ptr++[0];
|
||||
if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8!;
|
||||
return uc + c & 0x3F;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param utf8 `An UTF-8 encoded slice of bytes`
|
||||
* @return `the number of encoded code points`
|
||||
**/
|
||||
fn usize utf8_codepoints(char[] utf8)
|
||||
{
|
||||
usize len = 0;
|
||||
foreach (char c : utf8)
|
||||
{
|
||||
if (c & 0xC0 != 0x80) len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the UTF8 length required to encode an UTF32 array.
|
||||
* @param [in] utf32 `the utf32 data to calculate from`
|
||||
* @return `the length of the resulting UTF8 array`
|
||||
**/
|
||||
fn usize utf8len_for_utf32(Char32[] utf32)
|
||||
{
|
||||
usize len = 0;
|
||||
foreach (Char32 uc : utf32)
|
||||
{
|
||||
switch (true)
|
||||
{
|
||||
case uc < 0x7f:
|
||||
len++;
|
||||
case uc < 0x7ff:
|
||||
len += 2;
|
||||
case uc < 0xffff:
|
||||
len += 3;
|
||||
default:
|
||||
len += 4;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the UTF8 length required to encode an UTF16 array.
|
||||
* @param [in] utf16 `the utf16 data to calculate from`
|
||||
* @return `the length of the resulting UTF8 array`
|
||||
**/
|
||||
fn usize utf8len_for_utf16(Char16[] utf16)
|
||||
{
|
||||
usize len = 0;
|
||||
usize len16 = utf16.len;
|
||||
for (usize i = 0; i < len16; i++)
|
||||
{
|
||||
Char16 c = utf16[i];
|
||||
if (c & UTF16_SURROGATE_GENERIC_MASK != UTF16_SURROGATE_GENERIC_VALUE)
|
||||
{
|
||||
if (c < 0x7f)
|
||||
{
|
||||
len++;
|
||||
continue;
|
||||
}
|
||||
if (c < 0x7ff)
|
||||
{
|
||||
len += 2;
|
||||
continue;
|
||||
}
|
||||
len += 3;
|
||||
continue;
|
||||
}
|
||||
len += 4;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the UTF16 length required to encode a UTF8 array.
|
||||
* @param utf8 `the utf8 data to calculate from`
|
||||
* @return `the length of the resulting UTF16 array`
|
||||
**/
|
||||
fn usize utf16len_for_utf8(char[] utf8)
|
||||
{
|
||||
usize len = utf8.len;
|
||||
usize len16 = 0;
|
||||
for (usize i = 0; i < len; i++)
|
||||
{
|
||||
len16++;
|
||||
char c = utf8[i];
|
||||
if (c & 0x80 == 0) continue;
|
||||
i++;
|
||||
if (c & 0xE0 == 0xC0) continue;
|
||||
i++;
|
||||
if (c & 0xF0 == 0xE0) continue;
|
||||
i++;
|
||||
len16++;
|
||||
}
|
||||
return len16;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [in] utf32 `the UTF32 array to check the length for`
|
||||
* @return `the required length of an UTF16 array to hold the UTF32 data.`
|
||||
**/
|
||||
fn usize utf16len_for_utf32(Char32[] utf32)
|
||||
{
|
||||
usize len = utf32.len;
|
||||
foreach (Char32 uc : utf32)
|
||||
{
|
||||
if (uc >= UTF16_SURROGATE_OFFSET) len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an UTF32 array to an UTF8 array.
|
||||
*
|
||||
* @param [in] utf32
|
||||
* @param [out] utf8_buffer
|
||||
* @return `the number of bytes written.`
|
||||
**/
|
||||
fn usize! utf32to8(Char32[] utf32, char[] utf8_buffer)
|
||||
{
|
||||
usize len = utf8_buffer.len;
|
||||
char* ptr = utf8_buffer.ptr;
|
||||
foreach (Char32 uc : utf32)
|
||||
{
|
||||
usize used = char32_to_utf8(uc, ptr, len) @inline?;
|
||||
len -= used;
|
||||
ptr += used;
|
||||
}
|
||||
return utf8_buffer.len - len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an UTF8 array to an UTF32 array.
|
||||
*
|
||||
* @param [in] utf8
|
||||
* @param [out] utf32_buffer
|
||||
* @return `the number of Char32s written.`
|
||||
**/
|
||||
fn usize! utf8to32(char[] utf8, Char32[] utf32_buffer)
|
||||
{
|
||||
usize len = utf8.len;
|
||||
Char32* ptr = utf32_buffer.ptr;
|
||||
usize len32 = 0;
|
||||
usize buf_len = utf32_buffer.len;
|
||||
for (usize i = 0; i < len;)
|
||||
{
|
||||
if (len32 == buf_len) return UnicodeResult.CONVERSION_FAILED!;
|
||||
usize width = len - i;
|
||||
Char32 uc = utf8_to_char32(&utf8[i], &width) @inline?;
|
||||
i += width;
|
||||
ptr[len32++] = uc;
|
||||
}
|
||||
return len32;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy an array of UTF16 data into an UTF8 buffer without bounds
|
||||
* checking. This will assume the buffer is sufficiently large to hold
|
||||
* the converted data.
|
||||
*
|
||||
* @param [in] utf16 `The UTF16 array containing the data to convert.`
|
||||
* @param [out] utf8_buffer `the (sufficiently large) buffer to hold the UTF16 data.`
|
||||
**/
|
||||
fn void! utf16to8_unsafe(Char16[] utf16, char* utf8_buffer)
|
||||
{
|
||||
usize len16 = utf16.len;
|
||||
for (usize i = 0; i < len16;)
|
||||
{
|
||||
usize available = len16 - i;
|
||||
char16_to_utf8_unsafe(&utf16[i], &available, &utf8_buffer) @inline?;
|
||||
i += available;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy an array of UTF8 data into an UTF32 buffer without bounds
|
||||
* checking. This will assume the buffer is sufficiently large to hold
|
||||
* the converted data.
|
||||
*
|
||||
* @param [in] utf8 `The UTF8 buffer containing the data to convert.`
|
||||
* @param [out] utf32_buffer `the (sufficiently large) buffer to hold the UTF8 data.`
|
||||
**/
|
||||
fn void! utf8to32_unsafe(char[] utf8, Char32* utf32_buffer)
|
||||
{
|
||||
usize len = utf8.len;
|
||||
for (usize i = 0; i < len;)
|
||||
{
|
||||
usize width = len - i;
|
||||
Char32 uc = utf8_to_char32(&utf8[i], &width) @inline?;
|
||||
i += width;
|
||||
(utf32_buffer++)[0] = uc;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy an array of UTF8 data into an UTF16 buffer without bounds
|
||||
* checking. This will assume the buffer is sufficiently large to hold
|
||||
* the converted data.
|
||||
*
|
||||
* @param [in] utf8 `The UTF8 buffer containing the data to convert.`
|
||||
* @param [out] utf16_buffer `the (sufficiently large) buffer to hold the UTF8 data.`
|
||||
**/
|
||||
fn void! utf8to16_unsafe(char[] utf8, Char16* utf16_buffer)
|
||||
{
|
||||
usize len = utf8.len;
|
||||
for (usize i = 0; i < len;)
|
||||
{
|
||||
usize width = len - i;
|
||||
Char32 uc = utf8_to_char32(&utf8[i], &width) @inline?;
|
||||
char32_to_utf16_unsafe(uc, &utf16_buffer) @inline;
|
||||
i += width;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy an array of UTF32 code points into an UTF8 buffer without bounds
|
||||
* checking. This will assume the buffer is sufficiently large to hold
|
||||
* the converted data.
|
||||
*
|
||||
* @param [in] utf32 `The UTF32 buffer containing the data to convert.`
|
||||
* @param [out] utf8_buffer `the (sufficiently large) buffer to hold the UTF8 data.`
|
||||
**/
|
||||
fn void utf32to8_unsafe(Char32[] utf32, char* utf8_buffer)
|
||||
{
|
||||
char* start = utf8_buffer;
|
||||
foreach (Char32 uc : utf32)
|
||||
{
|
||||
char32_to_utf8_unsafe(uc, &utf8_buffer) @inline;
|
||||
}
|
||||
}
|
||||
58
lib/std/core/env.c3
Normal file
58
lib/std/core/env.c3
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright (c) 2021 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::core::env;
|
||||
|
||||
enum CompilerOptLevel
|
||||
{
|
||||
O0,
|
||||
O1,
|
||||
O2,
|
||||
O3
|
||||
}
|
||||
|
||||
enum OsType
|
||||
{
|
||||
UNKNOWN,
|
||||
NONE,
|
||||
ANANAS,
|
||||
CLOUD_ABI,
|
||||
DRAGON_FLY,
|
||||
FREEBSD,
|
||||
FUCHSIA,
|
||||
IOS,
|
||||
KFREEBSD,
|
||||
LINUX,
|
||||
PS3,
|
||||
MACOSX,
|
||||
NETBSD,
|
||||
OPENBSD,
|
||||
SOLARIS,
|
||||
WIN32,
|
||||
HAIKU,
|
||||
MINIX,
|
||||
RTEMS,
|
||||
NACL, // Native Client
|
||||
CNK, // BG/P Compute-Node Kernel
|
||||
AIX,
|
||||
CUDA,
|
||||
NVOPENCL,
|
||||
AMDHSA,
|
||||
PS4,
|
||||
ELFIAMCU,
|
||||
TVOS,
|
||||
WATCHOS,
|
||||
MESA3D,
|
||||
CONTIKI,
|
||||
AMDPAL,
|
||||
HERMITCORE,
|
||||
HURD,
|
||||
WASI,
|
||||
EMSCRIPTEN,
|
||||
}
|
||||
|
||||
const OsType OS_TYPE = (OsType)($$OS_TYPE);
|
||||
const CompilerOptLevel COMPILER_OPT_LEVEL = (CompilerOptLevel)($$COMPILER_OPT_LEVEL);
|
||||
const bool BIG_ENDIAN = $$PLATFORM_BIG_ENDIAN;
|
||||
const bool I128_SUPPORT = $$PLATFORM_I128_SUPPORTED;
|
||||
const bool COMPILER_SAFE_MODE = $$COMPILER_SAFE_MODE;
|
||||
150
lib/std/core/mem.c3
Normal file
150
lib/std/core/mem.c3
Normal file
@@ -0,0 +1,150 @@
|
||||
// Copyright (c) 2021 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::core::mem;
|
||||
|
||||
macro @volatile_load(&x)
|
||||
{
|
||||
return $$volatile_load(&x);
|
||||
}
|
||||
|
||||
macro @volatile_store(&x, y)
|
||||
{
|
||||
return $$volatile_store(&x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* @require math::is_power_of_2(alignment)
|
||||
**/
|
||||
fn usize aligned_offset(usize offset, usize alignment)
|
||||
{
|
||||
return alignment * ((offset + alignment - 1) / alignment);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @require math::is_power_of_2(alignment)
|
||||
**/
|
||||
fn bool ptr_is_aligned(void* ptr, usize alignment) @inline
|
||||
{
|
||||
return (uptr)ptr & ((uptr)alignment - 1) == 0;
|
||||
}
|
||||
|
||||
fn void copy(char* dst, char* src, usize size) @inline
|
||||
{
|
||||
memcpy(dst, src, size);
|
||||
}
|
||||
|
||||
macro void memcpy(void* dst, void* src, usize size, bool $is_volatile = false, usize $dst_align = 0, usize $src_align = 0)
|
||||
{
|
||||
$$memcpy(dst, src, size, $is_volatile, $dst_align, $src_align);
|
||||
}
|
||||
|
||||
fn void set(void* dst, char val, usize bytes) @inline
|
||||
{
|
||||
memset(dst, val, bytes);
|
||||
}
|
||||
|
||||
macro void memset(void* dst, char val, usize bytes, bool $is_volatile = false, usize $dst_align = 0)
|
||||
{
|
||||
$$memset(dst, val, bytes, $is_volatile, $dst_align);
|
||||
}
|
||||
|
||||
|
||||
|
||||
macro @clone(&value) @builtin
|
||||
{
|
||||
$typeof(value)* x = malloc($typeof(value));
|
||||
*x = value;
|
||||
return x;
|
||||
}
|
||||
|
||||
macro malloc($Type) @builtin
|
||||
{
|
||||
return ($Type*)(mem::alloc($Type.sizeof));
|
||||
}
|
||||
|
||||
fn char[] alloc_bytes(usize bytes) @inline
|
||||
{
|
||||
return ((char*)thread_allocator.alloc(bytes, 1))[0..bytes - 1]!!;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require !alignment || math::is_power_of_2(alignment)
|
||||
*/
|
||||
fn void* alloc(usize size, usize alignment = 0)
|
||||
{
|
||||
return thread_allocator.alloc(size, alignment)!!;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require !alignment || math::is_power_of_2(alignment)
|
||||
*/
|
||||
fn void*! alloc_checked(usize size, usize alignment = 0)
|
||||
{
|
||||
return thread_allocator.alloc(size, alignment);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @require !alignment || math::is_power_of_2(alignment)
|
||||
*/
|
||||
fn void* calloc(usize size, usize alignment = 0)
|
||||
{
|
||||
return thread_allocator.calloc(size, alignment)!!;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require !alignment || math::is_power_of_2(alignment)
|
||||
*/
|
||||
fn void*! calloc_checked(usize size, usize alignment = 0)
|
||||
{
|
||||
return thread_allocator.calloc(size, alignment);
|
||||
}
|
||||
|
||||
/**
|
||||
* @require !alignment || math::is_power_of_2(alignment)
|
||||
*/
|
||||
fn void* realloc(void *ptr, usize new_size, usize alignment = 0)
|
||||
{
|
||||
return thread_allocator.realloc(ptr, new_size, alignment)!!;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require !alignment || math::is_power_of_2(alignment)
|
||||
*/
|
||||
fn void*! realloc_checked(void *ptr, usize new_size, usize alignment = 0)
|
||||
{
|
||||
return thread_allocator.realloc(ptr, new_size, alignment);
|
||||
}
|
||||
|
||||
fn void free(void* ptr) @builtin
|
||||
{
|
||||
return thread_allocator.free(ptr)!!;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run with a specific allocator inside of the macro body.
|
||||
**/
|
||||
macro void @with_allocator(Allocator* allocator; @body())
|
||||
{
|
||||
Allocator* old_allocator = thread_allocator;
|
||||
thread_allocator = allocator;
|
||||
defer thread_allocator = old_allocator;
|
||||
@body();
|
||||
}
|
||||
|
||||
fn void*! talloc(usize size)
|
||||
{
|
||||
return temp_allocator.alloc(size);
|
||||
}
|
||||
|
||||
private tlocal Allocator* thread_allocator = allocator::LIBC_ALLOCATOR;
|
||||
macro Allocator* current_allocator()
|
||||
{
|
||||
return thread_allocator;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
151
lib/std/core/mem_allocator.c3
Normal file
151
lib/std/core/mem_allocator.c3
Normal file
@@ -0,0 +1,151 @@
|
||||
module std::core::mem::allocator;
|
||||
|
||||
const MAX_MEMORY_ALIGNMENT = 0x1000_0000;
|
||||
const DEFAULT_MEM_ALIGNMENT = $alignof(void*) * 2;
|
||||
const DEFAULT_SIZE_PREFIX = usize.sizeof;
|
||||
const DEFAULT_SIZE_PREFIX_ALIGNMENT = $alignof(usize);
|
||||
|
||||
const Allocator* NULL_ALLOCATOR = &_NULL_ALLOCATOR;
|
||||
const Allocator* LIBC_ALLOCATOR = &_SYSTEM_ALLOCATOR;
|
||||
|
||||
define AllocatorFunction = fn void*!(Allocator* allocator, usize new_size, usize alignment, void* old_pointer, AllocationKind kind);
|
||||
|
||||
struct Allocator
|
||||
{
|
||||
AllocatorFunction function;
|
||||
}
|
||||
|
||||
enum AllocationKind
|
||||
{
|
||||
ALLOC,
|
||||
CALLOC,
|
||||
REALLOC,
|
||||
FREE,
|
||||
RESET,
|
||||
}
|
||||
|
||||
fault AllocationFailure
|
||||
{
|
||||
OUT_OF_MEMORY,
|
||||
UNSUPPORTED_OPERATION,
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @require !alignment || math::is_power_of_2(alignment)
|
||||
*/
|
||||
fn void*! Allocator.alloc(Allocator* allocator, usize size, usize alignment = 0) @inline
|
||||
{
|
||||
return allocator.function(allocator, size, alignment, null, ALLOC);
|
||||
}
|
||||
|
||||
/**
|
||||
* @require !alignment || math::is_power_of_2(alignment)
|
||||
*/
|
||||
fn void*! Allocator.realloc(Allocator* allocator, void* old_pointer, usize size, usize alignment = 0) @inline
|
||||
{
|
||||
return allocator.function(allocator, size, alignment, old_pointer, REALLOC);
|
||||
}
|
||||
|
||||
/**
|
||||
* @require !alignment || math::is_power_of_2(alignment)
|
||||
*/
|
||||
fn void*! Allocator.calloc(Allocator* allocator, usize size, usize alignment = 0) @inline
|
||||
{
|
||||
return allocator.function(allocator, size, alignment, null, CALLOC);
|
||||
}
|
||||
|
||||
fn void! Allocator.free(Allocator* allocator, void* old_pointer) @inline
|
||||
{
|
||||
allocator.function(allocator, 0, 0, old_pointer, FREE)?;
|
||||
}
|
||||
|
||||
fn void Allocator.reset(Allocator* allocator)
|
||||
{
|
||||
allocator.function(allocator, 0, 0, null, RESET)!!;
|
||||
}
|
||||
|
||||
private fn usize alignment_for_allocation(usize alignment) @inline
|
||||
{
|
||||
if (alignment < DEFAULT_MEM_ALIGNMENT)
|
||||
{
|
||||
alignment = DEFAULT_SIZE_PREFIX_ALIGNMENT;
|
||||
}
|
||||
return alignment;
|
||||
}
|
||||
|
||||
struct DynamicArenaAllocator
|
||||
{
|
||||
inline Allocator allocator;
|
||||
Allocator* backing_allocator;
|
||||
DynamicArenaPage* page;
|
||||
DynamicArenaPage* unused_page;
|
||||
usize page_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require page_size >= 128
|
||||
* @require this != null
|
||||
**/
|
||||
fn void DynamicArenaAllocator.init(DynamicArenaAllocator* this, usize page_size, Allocator* backing_allocator = mem::allocator())
|
||||
{
|
||||
this.function = &dynamic_arena_allocator_function;
|
||||
this.page = null;
|
||||
this.unused_page = null;
|
||||
this.page_size = page_size;
|
||||
this.backing_allocator = backing_allocator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require this != null
|
||||
**/
|
||||
fn void DynamicArenaAllocator.destroy(DynamicArenaAllocator* this)
|
||||
{
|
||||
DynamicArenaPage* page = this.page;
|
||||
while (page)
|
||||
{
|
||||
DynamicArenaPage* next_page = page.prev_arena;
|
||||
this.backing_allocator.free(page)!!;
|
||||
page = next_page;
|
||||
}
|
||||
page = this.unused_page;
|
||||
while (page)
|
||||
{
|
||||
DynamicArenaPage* next_page = page.prev_arena;
|
||||
this.backing_allocator.free(page)!!;
|
||||
page = next_page;
|
||||
}
|
||||
this.page = null;
|
||||
this.unused_page = null;
|
||||
}
|
||||
|
||||
|
||||
struct MemoryArena
|
||||
{
|
||||
inline Allocator allocator;
|
||||
void* memory;
|
||||
usize total;
|
||||
usize used;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a memory arena for use using the provided bytes.
|
||||
*
|
||||
* @require this != null
|
||||
**/
|
||||
fn void MemoryArena.init(MemoryArena* this, char[] data)
|
||||
{
|
||||
this.function = &arena_allocator_function;
|
||||
this.memory = data.ptr;
|
||||
this.total = data.len;
|
||||
this.used = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require this != null
|
||||
**/
|
||||
fn void MemoryArena.reset(MemoryArena* this)
|
||||
{
|
||||
this.used = 0;
|
||||
}
|
||||
22
lib/std/core/mem_array.c3
Normal file
22
lib/std/core/mem_array.c3
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) 2021 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::core::mem::array;
|
||||
|
||||
/**
|
||||
* @require usize.max / elements > $Type.sizeof
|
||||
**/
|
||||
macro alloc($Type, usize elements)
|
||||
{
|
||||
$Type* ptr = mem::alloc($Type.sizeof * elements, $alignof($Type));
|
||||
return ptr[:elements];
|
||||
}
|
||||
|
||||
/**
|
||||
* @require (usize.max / elements > $Type.sizeof)
|
||||
**/
|
||||
macro make($Type, usize elements)
|
||||
{
|
||||
$Type* ptr = mem::calloc($sizeof($Type) * elements, $alignof($Type));
|
||||
return ptr[:elements];
|
||||
}
|
||||
@@ -1,52 +1,50 @@
|
||||
module std::mem;
|
||||
module std::core::mem;
|
||||
|
||||
extern func void* _malloc(usize bytes) @extname("malloc");
|
||||
extern func void* _realloc(void* ptr, usize bytes) @extname("realloc");
|
||||
extern func void* _calloc(usize bytes, usize elements) @extname("calloc");
|
||||
extern func void _free(void* ptr) @extname("free");
|
||||
const TEMP_BLOCK_SIZE = 1024;
|
||||
const TEMP_PAGES = 64;
|
||||
|
||||
enum AllocationKind
|
||||
private char[TEMP_BLOCK_SIZE * TEMP_PAGES] allocator_static_storage;
|
||||
private void*[TEMP_PAGES] allocator_static_page_storage;
|
||||
|
||||
SlotAllocator temp_allocator = {
|
||||
.pages = &allocator_static_storage,
|
||||
.page_size = TEMP_BLOCK_SIZE,
|
||||
.page_count = TEMP_PAGES,
|
||||
.bitmask = TEMP_PAGES - 1,
|
||||
.current_page = 0,
|
||||
};
|
||||
|
||||
struct SlotAllocator
|
||||
{
|
||||
ALLOC,
|
||||
REALLOC,
|
||||
FREE,
|
||||
void* pages;
|
||||
usize page_size;
|
||||
usize page_count;
|
||||
usize bitmask;
|
||||
usize current_page;
|
||||
}
|
||||
|
||||
errtype AllocationFailure
|
||||
fn void*! SlotAllocator.alloc(SlotAllocator *allocator, usize size)
|
||||
{
|
||||
OUT_OF_MEMORY
|
||||
}
|
||||
|
||||
define AllocatorFunction = func void!(void *data, void** pointer, usize bytes, usize alignment, AllocationKind kind);
|
||||
|
||||
struct Allocator
|
||||
{
|
||||
AllocatorFunction allocation_function;
|
||||
void *data;
|
||||
}
|
||||
|
||||
func void! system_malloc_function(void *unused, void** pointer, usize bytes, usize alignment, AllocationKind kind) @inline
|
||||
{
|
||||
switch (kind)
|
||||
void* active_page = (char*)(allocator.pages) + allocator.current_page * allocator.page_size;
|
||||
void** page_pointer = (void**)(active_page);
|
||||
if (*page_pointer)
|
||||
{
|
||||
case ALLOC:
|
||||
void* data = _malloc(bytes);
|
||||
if (!data) return AllocationFailure.OUT_OF_MEMORY!;
|
||||
*pointer = data;
|
||||
return;
|
||||
case REALLOC:
|
||||
void* data = _realloc(*pointer, bytes);
|
||||
if (!data) return AllocationFailure.OUT_OF_MEMORY!;
|
||||
*pointer = data;
|
||||
return;
|
||||
case FREE:
|
||||
_free(*pointer);
|
||||
*pointer = null;
|
||||
return;
|
||||
// TODO fix
|
||||
thread_allocator.free(*page_pointer)?;
|
||||
*page_pointer = null;
|
||||
}
|
||||
$unreachable;
|
||||
if (size > allocator.page_size - $sizeof(page_pointer))
|
||||
{
|
||||
void* mem = thread_allocator.alloc(size)?;
|
||||
*page_pointer = mem;
|
||||
allocator.current_page = (allocator.current_page + 1) & (allocator.bitmask);
|
||||
return mem;
|
||||
}
|
||||
allocator.current_page = (allocator.current_page + 1) & (allocator.bitmask);
|
||||
return &page_pointer[1];
|
||||
}
|
||||
|
||||
|
||||
struct RingAllocator
|
||||
{
|
||||
char *data;
|
||||
@@ -55,7 +53,7 @@ struct RingAllocator
|
||||
}
|
||||
|
||||
|
||||
func void* RingAllocator.alloc(RingAllocator *allocator, usize size)
|
||||
fn void* RingAllocator.alloc(RingAllocator *allocator, usize size)
|
||||
{
|
||||
if (size > allocator.size) return null;
|
||||
// Wraparound? If so, start at the beginning.
|
||||
@@ -69,7 +67,7 @@ func void* RingAllocator.alloc(RingAllocator *allocator, usize size)
|
||||
return data;
|
||||
}
|
||||
|
||||
func void* RingAllocator.realloc(RingAllocator *allocator, void* ptr, usize size)
|
||||
fn void* RingAllocator.realloc(RingAllocator *allocator, void* ptr, usize size)
|
||||
{
|
||||
if (size > allocator.size) return null;
|
||||
assert(allocator.data >= ptr && ptr < allocator.data + size, "Realloc on other allocator.");
|
||||
@@ -106,29 +104,3 @@ func void* RingAllocator.realloc(RingAllocator *allocator, void* ptr, usize size
|
||||
return allocator.data;
|
||||
}
|
||||
|
||||
Allocator main_allocator = { &system_malloc_function, null };
|
||||
|
||||
macro malloc($Type)
|
||||
{
|
||||
return ($Type*)(mem::alloc($sizeof($Type)));
|
||||
}
|
||||
|
||||
func void* alloc(usize size, usize elements = 1) @inline
|
||||
{
|
||||
return _malloc(size * elements);
|
||||
}
|
||||
|
||||
func void* calloc(usize size, usize elements = 1) @inline
|
||||
{
|
||||
return _calloc(size, elements);
|
||||
}
|
||||
|
||||
func void* realloc(void *ptr, usize size) @inline
|
||||
{
|
||||
return _realloc(ptr, size);
|
||||
}
|
||||
|
||||
func void free(void* ptr) @inline
|
||||
{
|
||||
_free(ptr);
|
||||
}
|
||||
17
lib/std/core/os/linux.c3
Normal file
17
lib/std/core/os/linux.c3
Normal file
@@ -0,0 +1,17 @@
|
||||
module std::core::os::linux;
|
||||
|
||||
$if (env::OS_TYPE == OsType.LINUX):
|
||||
|
||||
extern fn int* __errno_location();
|
||||
|
||||
fn int errno() @inline
|
||||
{
|
||||
return *__errno_location();
|
||||
}
|
||||
|
||||
fn void errno_set(int err)
|
||||
{
|
||||
*(__errno_location()) = err;
|
||||
}
|
||||
|
||||
$endif;
|
||||
14
lib/std/core/os/macos.c3
Normal file
14
lib/std/core/os/macos.c3
Normal file
@@ -0,0 +1,14 @@
|
||||
module std::core::os::macos;
|
||||
$if (env::OS_TYPE == OsType.MACOSX):
|
||||
|
||||
extern fn int* __error();
|
||||
|
||||
fn int errno() @inline
|
||||
{
|
||||
return *__error();
|
||||
}
|
||||
fn void errno_set(int err)
|
||||
{
|
||||
*(__error()) = err;
|
||||
}
|
||||
$endif;
|
||||
10
lib/std/core/os/windows.c3
Normal file
10
lib/std/core/os/windows.c3
Normal file
@@ -0,0 +1,10 @@
|
||||
module std::core::os::windows;
|
||||
|
||||
$if (env::OS_TYPE == OsType.WIN32):
|
||||
|
||||
extern fn int getLastError() @stdcall @extname("GetLastError");
|
||||
fn int errno() @inline
|
||||
{
|
||||
return getLastError();
|
||||
}
|
||||
$endif;
|
||||
160
lib/std/core/str.c3
Normal file
160
lib/std/core/str.c3
Normal file
@@ -0,0 +1,160 @@
|
||||
module std::core::str;
|
||||
define ZString = distinct char*;
|
||||
define Char32 = uint;
|
||||
define Char16 = ushort;
|
||||
|
||||
private const uint SURROGATE_OFFSET = 0x10000;
|
||||
private const uint SURROGATE_GENERIC_MASK = 0xF800;
|
||||
private const uint SURROGATE_MASK = 0xFC00;
|
||||
private const uint SURROGATE_CODEPOINT_MASK = 0x03FF;
|
||||
private const uint SURROGATE_BITS = 10;
|
||||
private const uint SURROGATE_LOW_VALUE = 0xDC00;
|
||||
private const uint SURROGATE_HIGH_VALUE = 0xD800;
|
||||
|
||||
fn String join(char[][] s, char[] joiner)
|
||||
{
|
||||
if (!s.len) return (String)null;
|
||||
usize total_size = joiner.len * s.len;
|
||||
foreach (char[]* &str : s)
|
||||
{
|
||||
total_size += str.len;
|
||||
}
|
||||
String res = string::new_with_capacity(total_size);
|
||||
res.append(s[0]);
|
||||
foreach (char[]* &str : s[1..])
|
||||
{
|
||||
res.append(joiner);
|
||||
res.append(*str);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
fn ZString copy_zstring(char[] s)
|
||||
{
|
||||
usize len = s.len;
|
||||
char* str = mem::alloc(len + 1);
|
||||
mem::copy(str, s.ptr, len);
|
||||
str[len] = 0;
|
||||
return (ZString)str;
|
||||
}
|
||||
|
||||
fn ZString tcopy_zstring(char[] s)
|
||||
{
|
||||
usize len = s.len;
|
||||
char* str = mem::talloc(len + 1)!!;
|
||||
mem::copy(str, s.ptr, len);
|
||||
str[len] = 0;
|
||||
return (ZString)str;
|
||||
}
|
||||
|
||||
fn bool compare(char[] a, char[] b)
|
||||
{
|
||||
if (a.len != b.len) return false;
|
||||
foreach (i, c : a)
|
||||
{
|
||||
if (c != b[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
fault UnicodeResult
|
||||
{
|
||||
INVALID_UTF8,
|
||||
INVALID_UTF16,
|
||||
CONVERSION_FAILED,
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn usize utf8_codepoints(char[] utf8)
|
||||
{
|
||||
usize len = 0;
|
||||
foreach (char c : utf8)
|
||||
{
|
||||
if (c & 0xC0 != 0x80) len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
fn Char32[]! utf8to32(char[] utf8, Allocator* allocator = mem::current_allocator)
|
||||
{
|
||||
usize codepoints = conv::utf8_codepoints(utf8);
|
||||
Char32* data = allocator.alloc(Char32.sizeof * (codepoints + 1))?;
|
||||
conv::utf8to32_unsafe(utf8, data)?;
|
||||
data[codepoints] = 0;
|
||||
return data[0..codepoints - 1];
|
||||
}
|
||||
|
||||
fn char[] utf32to8(Char32[] utf32, Allocator* allocator = mem::current_allocator)
|
||||
{
|
||||
usize len = conv::utf8len_for_utf32(utf32);
|
||||
char* data = allocator.alloc(len + 1)!!;
|
||||
conv::utf32to8_unsafe(utf32, data);
|
||||
data[len] = 0;
|
||||
return data[0..len - 1];
|
||||
}
|
||||
|
||||
fn Char16[]! utf8to16(char[] utf8, Allocator* allocator = mem::current_allocator)
|
||||
{
|
||||
usize len16 = conv::utf16len_for_utf8(utf8);
|
||||
Char16* data = allocator.alloc((len16 + 1) * Char16.sizeof)?;
|
||||
conv::utf8to16_unsafe(utf8, data)?;
|
||||
data[len16] = 0;
|
||||
return data[0..len16 - 1];
|
||||
}
|
||||
|
||||
|
||||
fn char[]! utf16to8(Char16[] utf16, Allocator* allocator = mem::current_allocator())
|
||||
{
|
||||
usize len = conv::utf8len_for_utf16(utf16);
|
||||
char* data = allocator.alloc(len + 1)?;
|
||||
conv::utf16to8_unsafe(utf16, data)?;
|
||||
return data[0 .. len - 1];
|
||||
}
|
||||
|
||||
fn char[] copy(char[] s)
|
||||
{
|
||||
usize len = s.len;
|
||||
ZString str_copy = copy_zstring(s) @inline;
|
||||
return str_copy[..len];
|
||||
}
|
||||
|
||||
fn char[] tcopy(char[] s)
|
||||
{
|
||||
usize len = s.len;
|
||||
ZString str_copy = tcopy_zstring(s) @inline;
|
||||
return str_copy[..len];
|
||||
}
|
||||
|
||||
fn char[] tconcat(char[] s1, char[] s2)
|
||||
{
|
||||
usize full_len = s1.len + s2.len;
|
||||
char* str = mem::talloc(full_len + 1)!!;
|
||||
usize s1_len = s1.len;
|
||||
mem::copy(str, s1.ptr, s1_len);
|
||||
mem::copy(str + s1_len, s2.ptr, s2.len);
|
||||
str[full_len] = 0;
|
||||
return str[..full_len];
|
||||
}
|
||||
|
||||
fn char[] concat(char[] s1, char[] s2)
|
||||
{
|
||||
usize full_len = s1.len + s2.len;
|
||||
char* str = mem::alloc(full_len + 1);
|
||||
usize s1_len = s1.len;
|
||||
mem::copy(str, s1.ptr, s1_len);
|
||||
mem::copy(str + s1_len, s2.ptr, s2.len);
|
||||
str[full_len] = 0;
|
||||
return str[..full_len];
|
||||
}
|
||||
|
||||
fn usize ZString.len(ZString *str)
|
||||
{
|
||||
usize len = 0;
|
||||
char* ptr = (char*)*str;
|
||||
while (char c = ptr++[0])
|
||||
{
|
||||
if (c & 0xC0 != 0x80) len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
299
lib/std/core/string.c3
Normal file
299
lib/std/core/string.c3
Normal file
@@ -0,0 +1,299 @@
|
||||
module std::core::string;
|
||||
import libc;
|
||||
|
||||
define String = distinct void*;
|
||||
|
||||
private struct StringData
|
||||
{
|
||||
Allocator* allocator;
|
||||
usize len;
|
||||
usize capacity;
|
||||
char[*] chars;
|
||||
}
|
||||
|
||||
const usize MIN_CAPACITY = 16;
|
||||
|
||||
fn String new_with_capacity(usize capacity, Allocator* allocator = mem::current_allocator())
|
||||
{
|
||||
if (capacity < MIN_CAPACITY) capacity = MIN_CAPACITY;
|
||||
StringData* data = allocator.alloc(StringData.sizeof + capacity)!!;
|
||||
data.allocator = allocator;
|
||||
data.len = 0;
|
||||
data.capacity = capacity;
|
||||
return (String)data;
|
||||
}
|
||||
|
||||
fn String new(char[] c)
|
||||
{
|
||||
usize len = c.len;
|
||||
String str = new_with_capacity(len);
|
||||
StringData* data = str.data();
|
||||
if (len)
|
||||
{
|
||||
data.len = len;
|
||||
mem::copy(&data.chars, c.ptr, len);
|
||||
}
|
||||
return (String)data;
|
||||
}
|
||||
|
||||
fn ZString String.zstr(String str)
|
||||
{
|
||||
StringData* data = str.data();
|
||||
if (!data) return (ZString)"";
|
||||
if (data.capacity == data.len)
|
||||
{
|
||||
str.reserve(1);
|
||||
data.chars[data.len] = 0;
|
||||
}
|
||||
else if (data.chars[data.len] != 0)
|
||||
{
|
||||
data.chars[data.len] = 0;
|
||||
}
|
||||
return (ZString)&data.chars[0];
|
||||
}
|
||||
|
||||
fn usize String.len(String this)
|
||||
{
|
||||
if (!this) return 0;
|
||||
return this.data().len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require new_size <= this.len()
|
||||
*/
|
||||
fn void String.chop(String this, usize new_size)
|
||||
{
|
||||
if (!this) return;
|
||||
this.data().len = new_size;
|
||||
}
|
||||
|
||||
fn char[] String.str(String str)
|
||||
{
|
||||
StringData* data = (StringData*)str;
|
||||
if (!data) return char[] {};
|
||||
return data.chars[:data.len];
|
||||
}
|
||||
|
||||
fn void String.append_utf32(String* str, Char32[] chars)
|
||||
{
|
||||
str.reserve(chars.len);
|
||||
foreach (Char32 c : chars)
|
||||
{
|
||||
str.append_char32(c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @require index < str.len()
|
||||
**/
|
||||
fn void String.set(String str, usize index, char c)
|
||||
{
|
||||
str.data().chars[index] = c;
|
||||
}
|
||||
|
||||
fn void String.append_repeat(String* str, char c, usize times)
|
||||
{
|
||||
if (times == 0) return;
|
||||
str.reserve(times);
|
||||
StringData* data = str.data();
|
||||
for (usize i = 0; i < times; i++)
|
||||
{
|
||||
data.chars[data.len++] = c;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @require c < 0x10ffff
|
||||
*/
|
||||
fn void String.append_char32(String* str, Char32 c)
|
||||
{
|
||||
if (c < 0x7f)
|
||||
{
|
||||
str.reserve(1);
|
||||
StringData* data = str.data();
|
||||
data.chars[data.len++] = (char)c;
|
||||
return;
|
||||
}
|
||||
if (c < 0x7ff)
|
||||
{
|
||||
str.reserve(2);
|
||||
StringData* data = str.data();
|
||||
data.chars[data.len++] = (char)(0xC0 | c >> 6);
|
||||
data.chars[data.len++] = (char)(0x80 | (c & 0x3F));
|
||||
return;
|
||||
}
|
||||
if (c < 0xffff)
|
||||
{
|
||||
str.reserve(3);
|
||||
StringData* data = str.data();
|
||||
data.chars[data.len++] = (char)(0xE0 | c >> 12);
|
||||
data.chars[data.len++] = (char)(0x80 | (c >> 6 & 0x3F));
|
||||
data.chars[data.len++] = (char)(0x80 | (c & 0x3F));
|
||||
return;
|
||||
}
|
||||
str.reserve(4);
|
||||
StringData* data = str.data();
|
||||
data.chars[data.len++] = (char)(0xF0 | c >> 18);
|
||||
data.chars[data.len++] = (char)(0x80 | (c >> 12 & 0x3F));
|
||||
data.chars[data.len++] = (char)(0x80 | (c >> 6 & 0x3F));
|
||||
data.chars[data.len++] = (char)(0x80 | (c & 0x3F));
|
||||
}
|
||||
|
||||
fn String String.copy(String* str, Allocator* allocator = null)
|
||||
{
|
||||
if (!str)
|
||||
{
|
||||
if (allocator) return new_with_capacity(0, allocator);
|
||||
return (String)null;
|
||||
}
|
||||
if (!allocator) allocator = mem::current_allocator();
|
||||
StringData* data = str.data();
|
||||
String new_string = new_with_capacity(data.capacity, allocator);
|
||||
mem::copy((char*)new_string.data(), (char*)data, StringData.sizeof + data.len);
|
||||
return new_string;
|
||||
}
|
||||
|
||||
fn ZString String.copy_zstr(String* str, Allocator* allocator = mem::current_allocator())
|
||||
{
|
||||
usize str_len = str.len();
|
||||
if (!str_len)
|
||||
{
|
||||
return (ZString)allocator.calloc(1, 1)!!;
|
||||
}
|
||||
char* zstr = allocator.alloc(str_len + 1)!!;
|
||||
StringData* data = str.data();
|
||||
mem::copy(zstr, &data.chars, str_len);
|
||||
zstr[str_len] = 0;
|
||||
return (ZString)zstr;
|
||||
}
|
||||
|
||||
fn char[] String.copy_str(String* str, Allocator* allocator = mem::current_allocator())
|
||||
{
|
||||
return str.copy_zstr(allocator)[:str.len()];
|
||||
}
|
||||
|
||||
fn bool String.equals(String str, String other_string)
|
||||
{
|
||||
StringData *str1 = str.data();
|
||||
StringData *str2 = other_string.data();
|
||||
if (str1 == str2) return true;
|
||||
if (!str1) return str2.len == 0;
|
||||
if (!str2) return str1.len == 0;
|
||||
usize str1_len = str1.len;
|
||||
if (str1_len != str2.len) return false;
|
||||
for (int i = 0; i < str1_len; i++)
|
||||
{
|
||||
if (str1.chars[i] != str2.chars[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
fn void String.destroy(String* str)
|
||||
{
|
||||
if (!*str) return;
|
||||
StringData* data = str.data();
|
||||
if (!data) return;
|
||||
data.allocator.free(data)!!;
|
||||
*str = (String)null;
|
||||
}
|
||||
|
||||
fn bool String.less(String str, String other_string)
|
||||
{
|
||||
StringData* str1 = str.data();
|
||||
StringData* str2 = other_string.data();
|
||||
if (str1 == str2) return false;
|
||||
if (!str1) return str2.len != 0;
|
||||
if (!str2) return str1.len == 0;
|
||||
usize str1_len = str1.len;
|
||||
usize str2_len = str2.len;
|
||||
if (str1_len != str2_len) return str1_len < str2_len;
|
||||
for (int i = 0; i < str1_len; i++)
|
||||
{
|
||||
if (str1.chars[i] >= str2.chars[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
fn void String.append_chars(String* this, char[] str)
|
||||
{
|
||||
usize other_len = str.len;
|
||||
if (!other_len) return;
|
||||
if (!*this)
|
||||
{
|
||||
*this = new(str);
|
||||
return;
|
||||
}
|
||||
this.reserve(other_len);
|
||||
StringData* data = (StringData*)*this;
|
||||
mem::copy(&data.chars[data.len], str.ptr, other_len);
|
||||
data.len += other_len;
|
||||
}
|
||||
|
||||
fn Char32[] String.copy_utf32(String* this, Allocator* allocator = mem::current_allocator())
|
||||
{
|
||||
return str::utf8to32(this.str(), allocator) @inline!!;
|
||||
}
|
||||
|
||||
fn void String.append_string(String* this, String str)
|
||||
{
|
||||
StringData* other = (StringData*)str;
|
||||
if (!other) return;
|
||||
this.append(str.str());
|
||||
}
|
||||
|
||||
fn void String.append_char(String* str, char c)
|
||||
{
|
||||
if (!*str)
|
||||
{
|
||||
*str = new_with_capacity(MIN_CAPACITY);
|
||||
}
|
||||
str.reserve(1);
|
||||
StringData* data = (StringData*)*str;
|
||||
data.chars[data.len++] = c;
|
||||
}
|
||||
|
||||
|
||||
macro void String.append(String* str, value)
|
||||
{
|
||||
var $Type = $typeof(value);
|
||||
$switch ($Type):
|
||||
$case char:
|
||||
$case ichar:
|
||||
str.append_char(value);
|
||||
$case String:
|
||||
str.append_string(value);
|
||||
$case char[]:
|
||||
str.append_chars(value);
|
||||
$case Char32:
|
||||
str.append_char32(value);
|
||||
$default:
|
||||
$if ($convertible($Type, Char32)):
|
||||
str.append_char32(value);
|
||||
$elif ($convertible($Type, char[])):
|
||||
str.append_chars(value);
|
||||
$else:
|
||||
$assert("Unsupported type for appending");
|
||||
$endif;
|
||||
$endswitch;
|
||||
}
|
||||
|
||||
|
||||
private fn StringData* String.data(String str) @inline
|
||||
{
|
||||
return (StringData*)str;
|
||||
}
|
||||
|
||||
private fn void String.reserve(String* str, usize addition)
|
||||
{
|
||||
StringData* data = str.data();
|
||||
if (!data)
|
||||
{
|
||||
*str = string::new_with_capacity(addition);
|
||||
return;
|
||||
}
|
||||
usize len = data.len + addition;
|
||||
if (data.capacity >= len) return;
|
||||
usize new_capacity = data.capacity * 2;
|
||||
if (new_capacity < MIN_CAPACITY) new_capacity = MIN_CAPACITY;
|
||||
*str = (String)data.allocator.realloc(data, StringData.sizeof + new_capacity)!!;
|
||||
}
|
||||
25
lib/std/core/string_iterator.c3
Normal file
25
lib/std/core/string_iterator.c3
Normal file
@@ -0,0 +1,25 @@
|
||||
module std::core::string::iterator;
|
||||
|
||||
|
||||
|
||||
struct StringIterator
|
||||
{
|
||||
char[] utf8;
|
||||
usize current;
|
||||
}
|
||||
|
||||
fn void StringIterator.reset(StringIterator* this)
|
||||
{
|
||||
this.current = 0;
|
||||
}
|
||||
|
||||
fn Char32! StringIterator.next(StringIterator* this)
|
||||
{
|
||||
usize len = this.utf8.len;
|
||||
usize current = this.current;
|
||||
if (current >= len) return IteratorResult.NO_MORE_ELEMENT!;
|
||||
usize read = (len - current < 4 ? len - current : 4);
|
||||
Char32 res = conv::utf8_to_char32(&this.utf8[current], &read)?;
|
||||
this.current += read;
|
||||
return res;
|
||||
}
|
||||
159
lib/std/core/types.c3
Normal file
159
lib/std/core/types.c3
Normal file
@@ -0,0 +1,159 @@
|
||||
module std::core::types;
|
||||
import libc;
|
||||
|
||||
|
||||
fault ConversionResult
|
||||
{
|
||||
VALUE_OUT_OF_RANGE,
|
||||
VALUE_OUT_OF_UNSIGNED_RANGE,
|
||||
}
|
||||
/**
|
||||
* @require type.kind == SIGNED_INT || type.kind == UNSIGNED_INT || type.kind == ENUM, "Argument was not an integer"
|
||||
**/
|
||||
macro variant_to_int(variant v, $Type)
|
||||
{
|
||||
typeid variant_type = v.type;
|
||||
TypeKind kind = variant_type.kind;
|
||||
if (kind == TypeKind.ENUM)
|
||||
{
|
||||
variant_type = variant_type.inner;
|
||||
kind = variant_type.kind;
|
||||
}
|
||||
bool is_mixed_signed = $Type.kind != variant_type.kind;
|
||||
$Type max = $Type.max;
|
||||
$Type min = $Type.min;
|
||||
switch (variant_type)
|
||||
{
|
||||
case ichar:
|
||||
ichar c = *(char*)v.ptr;
|
||||
if (is_mixed_signed && c < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE!;
|
||||
return ($Type)c;
|
||||
case short:
|
||||
short s = *(short*)v.ptr;
|
||||
if (is_mixed_signed && s < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE!;
|
||||
if (s > max || s < min) return ConversionResult.VALUE_OUT_OF_RANGE!;
|
||||
return ($Type)s;
|
||||
case int:
|
||||
int i = *(int*)v.ptr;
|
||||
if (is_mixed_signed && i < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE!;
|
||||
if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE!;
|
||||
return ($Type)i;
|
||||
case long:
|
||||
long l = *(long*)v.ptr;;
|
||||
if (is_mixed_signed && l < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE!;
|
||||
if (l > max || l < min) return ConversionResult.VALUE_OUT_OF_RANGE!;
|
||||
return ($Type)l;
|
||||
case int128:
|
||||
$if (env::I128_SUPPORT):
|
||||
int128 i = *(int128*)v.ptr;
|
||||
if (is_mixed_signed && i < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE!;
|
||||
if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE!;
|
||||
return ($Type)i;
|
||||
$else:
|
||||
unreachable();
|
||||
$endif;
|
||||
case char:
|
||||
char c = *(char*)v.ptr;
|
||||
if (c > max) return ConversionResult.VALUE_OUT_OF_RANGE!;
|
||||
return ($Type)c;
|
||||
case ushort:
|
||||
ushort s = *(ushort*)v.ptr;;
|
||||
if (s > max || s < min) return ConversionResult.VALUE_OUT_OF_RANGE!;
|
||||
return ($Type)s;
|
||||
case uint:
|
||||
uint i = *(uint*)v.ptr;;
|
||||
if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE!;
|
||||
return ($Type)i;
|
||||
case ulong:
|
||||
ulong l = *(ulong*)v.ptr;;
|
||||
if (l > max || l < min) return ConversionResult.VALUE_OUT_OF_RANGE!;
|
||||
return ($Type)l;
|
||||
case uint128:
|
||||
$if (env::I128_SUPPORT):
|
||||
uint128 i = *(uint128*)v.ptr;
|
||||
if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE!;
|
||||
return ($Type)i;
|
||||
$else:
|
||||
unreachable();
|
||||
$endif;
|
||||
default:
|
||||
unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
macro bool is_numerical($Type)
|
||||
{
|
||||
var $kind = $Type.kind;
|
||||
$if ($kind == TypeKind.DISTINCT):
|
||||
return is_numerical($Type.inner);
|
||||
$else:
|
||||
return $kind == TypeKind.SIGNED_INT || $kind == TypeKind.UNSIGNED_INT || $kind == TypeKind.FLOAT
|
||||
|| $kind == TypeKind.VECTOR;
|
||||
$endif;
|
||||
}
|
||||
|
||||
fn bool TypeKind.is_int(TypeKind kind) @inline
|
||||
{
|
||||
return kind == TypeKind.SIGNED_INT || kind == TypeKind.UNSIGNED_INT;
|
||||
}
|
||||
|
||||
macro bool is_comparable($Type)
|
||||
{
|
||||
var $kind = $Type.kind;
|
||||
$if ($kind == TypeKind.DISTINCT):
|
||||
return is_comparable($Type.inner);
|
||||
$else:
|
||||
return $kind == TypeKind.SIGNED_INT || $kind == TypeKind.UNSIGNED_INT || $kind == TypeKind.FLOAT
|
||||
|| $kind == TypeKind.VECTOR || $kind == TypeKind.BOOL || $kind == TypeKind.POINTER
|
||||
|| $kind == TypeKind.ENUM;
|
||||
$endif;
|
||||
}
|
||||
|
||||
macro bool is_equatable_value(value)
|
||||
{
|
||||
$if ($defined(value.less) || $defined(value.compare_to) || $defined(value.equals)):
|
||||
return true;
|
||||
$else:
|
||||
return is_comparable($typeof(value));
|
||||
$endif;
|
||||
}
|
||||
|
||||
macro bool is_comparable_value(value)
|
||||
{
|
||||
$if ($defined(value.less) || $defined(value.compare_to)):
|
||||
return true;
|
||||
$else:
|
||||
return is_comparable($typeof(value));
|
||||
$endif;
|
||||
}
|
||||
|
||||
enum TypeKind : char
|
||||
{
|
||||
VOID,
|
||||
BOOL,
|
||||
SIGNED_INT,
|
||||
UNSIGNED_INT,
|
||||
FLOAT,
|
||||
TYPEID,
|
||||
ANYERR,
|
||||
ANY,
|
||||
ENUM,
|
||||
FAULT,
|
||||
STRUCT,
|
||||
UNION,
|
||||
BITSTRUCT,
|
||||
FUNC,
|
||||
FAILABLE,
|
||||
ARRAY,
|
||||
SUBARRAY,
|
||||
VECTOR,
|
||||
DISTINCT,
|
||||
POINTER,
|
||||
VARIANT
|
||||
}
|
||||
|
||||
struct TypeEnum
|
||||
{
|
||||
TypeKind type;
|
||||
usize elements;
|
||||
}
|
||||
83
lib/std/enumset.c3
Normal file
83
lib/std/enumset.c3
Normal file
@@ -0,0 +1,83 @@
|
||||
// TODO: ensure the type is an enum first.
|
||||
module std::enumset<Enum>;
|
||||
|
||||
$assert(Enum.elements < 64, "Maximum number of elements for an enum used as enum set is 63");
|
||||
|
||||
$switch ($$C_INT_SIZE):
|
||||
$case 64:
|
||||
private define EnumSetType = ulong;
|
||||
$case 32:
|
||||
$if (Enum.elements < 32):
|
||||
private define EnumSetType = uint;
|
||||
$else:
|
||||
private define EnumSetType = ulong;
|
||||
$endif;
|
||||
$default:
|
||||
$if (Enum.elements < 16):
|
||||
private define EnumSetType = ushort;
|
||||
$elif (Enum.elements < 31):
|
||||
private define EnumSetType = uint;
|
||||
$else:
|
||||
private define EnumSetType = ulong;
|
||||
$endif;
|
||||
$endswitch;
|
||||
|
||||
define EnumSet = distinct EnumSetType;
|
||||
|
||||
fn void EnumSet.add(EnumSet* this, Enum v)
|
||||
{
|
||||
*this = (EnumSet)((EnumSetType)*this | 1u << (EnumSetType)v);
|
||||
}
|
||||
|
||||
fn void EnumSet.clear(EnumSet* this)
|
||||
{
|
||||
*this = 0;
|
||||
}
|
||||
|
||||
fn bool EnumSet.remove(EnumSet* this, Enum v)
|
||||
{
|
||||
EnumSetType old = (EnumSetType)*this;
|
||||
EnumSetType new = old & ~(1u << (EnumSetType)v);
|
||||
*this = (EnumSet)new;
|
||||
return old != new;
|
||||
}
|
||||
|
||||
fn bool EnumSet.has(EnumSet* this, Enum v)
|
||||
{
|
||||
return ((EnumSetType)*this & (1u << (EnumSetType)v)) != 0;
|
||||
}
|
||||
|
||||
fn void EnumSet.add_all(EnumSet* this, EnumSet s)
|
||||
{
|
||||
*this = (EnumSet)((EnumSetType)*this | (EnumSetType)s);
|
||||
}
|
||||
|
||||
fn void EnumSet.retain_all(EnumSet* this, EnumSet s)
|
||||
{
|
||||
*this = (EnumSet)((EnumSetType)*this & (EnumSetType)s);
|
||||
}
|
||||
|
||||
fn void EnumSet.remove_all(EnumSet* this, EnumSet s)
|
||||
{
|
||||
*this = (EnumSet)((EnumSetType)*this & ~(EnumSetType)s);
|
||||
}
|
||||
|
||||
fn EnumSet EnumSet.and_of(EnumSet* this, EnumSet s)
|
||||
{
|
||||
return (EnumSet)((EnumSetType)*this & (EnumSetType)s);
|
||||
}
|
||||
|
||||
fn EnumSet EnumSet.or_of(EnumSet* this, EnumSet s)
|
||||
{
|
||||
return (EnumSet)((EnumSetType)*this | (EnumSetType)s);
|
||||
}
|
||||
|
||||
fn EnumSet EnumSet.diff_of(EnumSet* this, EnumSet s)
|
||||
{
|
||||
return (EnumSet)((EnumSetType)*this & ~(EnumSetType)s);
|
||||
}
|
||||
|
||||
fn EnumSet EnumSet.xor_of(EnumSet* this, EnumSet s)
|
||||
{
|
||||
return (EnumSet)((EnumSetType)*this ^ (EnumSetType)s);
|
||||
}
|
||||
53
lib/std/hash/adler32.c3
Normal file
53
lib/std/hash/adler32.c3
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2021 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::hash::adler32;
|
||||
|
||||
private const uint ADLER_CONST = 65521;
|
||||
|
||||
struct Adler32
|
||||
{
|
||||
uint a;
|
||||
uint b;
|
||||
}
|
||||
|
||||
fn void Adler32.init(Adler32 *this)
|
||||
{
|
||||
*this = { 1, 0 };
|
||||
}
|
||||
|
||||
fn void Adler32.updatec(Adler32* this, char c)
|
||||
{
|
||||
this.a = (this.a + c) % ADLER_CONST;
|
||||
this.b = (this.b + this.a) % ADLER_CONST;
|
||||
}
|
||||
|
||||
fn void Adler32.update(Adler32* this, char[] data)
|
||||
{
|
||||
uint a = this.a;
|
||||
uint b = this.b;
|
||||
foreach (char x : data)
|
||||
{
|
||||
a = (a + x) % ADLER_CONST;
|
||||
b = (b + a) % ADLER_CONST;
|
||||
}
|
||||
*this = { a, b };
|
||||
}
|
||||
|
||||
fn uint Adler32.final(Adler32* this)
|
||||
{
|
||||
return (this.b << 16) | this.a;
|
||||
}
|
||||
|
||||
fn uint encode(char[] data)
|
||||
{
|
||||
uint a = 1;
|
||||
uint b = 0;
|
||||
foreach (char x : data)
|
||||
{
|
||||
a = (a + x) % ADLER_CONST;
|
||||
b = (b + a) % ADLER_CONST;
|
||||
}
|
||||
return (b << 16) | a;
|
||||
}
|
||||
111
lib/std/hash/crc32.c3
Normal file
111
lib/std/hash/crc32.c3
Normal file
@@ -0,0 +1,111 @@
|
||||
// Copyright (c) 2021 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::hash::crc32;
|
||||
|
||||
struct Crc32
|
||||
{
|
||||
uint result;
|
||||
}
|
||||
|
||||
fn void Crc32.init(Crc32* this, uint seed = 0)
|
||||
{
|
||||
this.result = ~seed;
|
||||
}
|
||||
|
||||
fn void Crc32.updatec(Crc32* this, char c)
|
||||
{
|
||||
this.result = (this.result >> 8) ^ CRC32_TABLE[(this.result ^ c) & 0xFF];
|
||||
}
|
||||
|
||||
fn void Crc32.update(Crc32* this, char[] data)
|
||||
{
|
||||
uint result = this.result;
|
||||
foreach (char x : data)
|
||||
{
|
||||
result = (result >> 8) ^ CRC32_TABLE[(result ^ x) & 0xFF];
|
||||
}
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
fn uint Crc32.final(Crc32* this)
|
||||
{
|
||||
return ~this.result;
|
||||
}
|
||||
|
||||
fn uint encode(char[] data)
|
||||
{
|
||||
uint result = ~(uint)(0);
|
||||
foreach (char x : data)
|
||||
{
|
||||
result = (result >> 8) ^ CRC32_TABLE[(result ^ x) & 0xFF];
|
||||
}
|
||||
return ~result;
|
||||
}
|
||||
|
||||
private const uint[256] CRC32_TABLE = {
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
|
||||
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
||||
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
|
||||
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
|
||||
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
|
||||
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
|
||||
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
||||
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
|
||||
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
|
||||
0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
|
||||
0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
|
||||
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
|
||||
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
|
||||
0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
|
||||
0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
|
||||
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
||||
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
|
||||
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
|
||||
0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
|
||||
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
|
||||
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
||||
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
|
||||
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
|
||||
0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
|
||||
0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
|
||||
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
||||
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
|
||||
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
|
||||
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
|
||||
0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
|
||||
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
||||
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
|
||||
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
|
||||
0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
|
||||
0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
|
||||
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
|
||||
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
|
||||
0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
|
||||
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
|
||||
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
||||
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
|
||||
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
|
||||
0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
|
||||
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
|
||||
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
||||
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
|
||||
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
|
||||
0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
|
||||
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
|
||||
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
|
||||
};
|
||||
111
lib/std/hash/crc64.c3
Normal file
111
lib/std/hash/crc64.c3
Normal file
@@ -0,0 +1,111 @@
|
||||
// Copyright (c) 2021 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::hash::crc64;
|
||||
|
||||
struct Crc64
|
||||
{
|
||||
ulong result;
|
||||
}
|
||||
|
||||
fn void Crc64.init(Crc64* this, uint seed = 0)
|
||||
{
|
||||
this.result = seed;
|
||||
}
|
||||
|
||||
fn void Crc64.updatec(Crc64* this, char c)
|
||||
{
|
||||
this.result = (this.result << 8) ^ CRC64_TABLE[(char)((this.result >> 56) ^ c)];
|
||||
}
|
||||
|
||||
fn void Crc64.update(Crc64* this, char[] data)
|
||||
{
|
||||
ulong result = this.result;
|
||||
foreach (char x : data)
|
||||
{
|
||||
result = (result << 8) ^ CRC64_TABLE[(char)((result >> 56) ^ x)];
|
||||
}
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
fn ulong Crc64.final(Crc64* this)
|
||||
{
|
||||
return this.result;
|
||||
}
|
||||
|
||||
fn ulong encode(char[] data)
|
||||
{
|
||||
ulong result = (ulong)(0);
|
||||
foreach (char x : data)
|
||||
{
|
||||
result = (result << 8) ^ CRC64_TABLE[(char)((result >> 56) ^ x)];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private const ulong[256] CRC64_TABLE = {
|
||||
0x0000000000000000, 0x42f0e1eba9ea3693, 0x85e1c3d753d46d26, 0xc711223cfa3e5bb5,
|
||||
0x493366450e42ecdf, 0x0bc387aea7a8da4c, 0xccd2a5925d9681f9, 0x8e224479f47cb76a,
|
||||
0x9266cc8a1c85d9be, 0xd0962d61b56fef2d, 0x17870f5d4f51b498, 0x5577eeb6e6bb820b,
|
||||
0xdb55aacf12c73561, 0x99a54b24bb2d03f2, 0x5eb4691841135847, 0x1c4488f3e8f96ed4,
|
||||
0x663d78ff90e185ef, 0x24cd9914390bb37c, 0xe3dcbb28c335e8c9, 0xa12c5ac36adfde5a,
|
||||
0x2f0e1eba9ea36930, 0x6dfeff5137495fa3, 0xaaefdd6dcd770416, 0xe81f3c86649d3285,
|
||||
0xf45bb4758c645c51, 0xb6ab559e258e6ac2, 0x71ba77a2dfb03177, 0x334a9649765a07e4,
|
||||
0xbd68d2308226b08e, 0xff9833db2bcc861d, 0x388911e7d1f2dda8, 0x7a79f00c7818eb3b,
|
||||
0xcc7af1ff21c30bde, 0x8e8a101488293d4d, 0x499b3228721766f8, 0x0b6bd3c3dbfd506b,
|
||||
0x854997ba2f81e701, 0xc7b97651866bd192, 0x00a8546d7c558a27, 0x4258b586d5bfbcb4,
|
||||
0x5e1c3d753d46d260, 0x1cecdc9e94ace4f3, 0xdbfdfea26e92bf46, 0x990d1f49c77889d5,
|
||||
0x172f5b3033043ebf, 0x55dfbadb9aee082c, 0x92ce98e760d05399, 0xd03e790cc93a650a,
|
||||
0xaa478900b1228e31, 0xe8b768eb18c8b8a2, 0x2fa64ad7e2f6e317, 0x6d56ab3c4b1cd584,
|
||||
0xe374ef45bf6062ee, 0xa1840eae168a547d, 0x66952c92ecb40fc8, 0x2465cd79455e395b,
|
||||
0x3821458aada7578f, 0x7ad1a461044d611c, 0xbdc0865dfe733aa9, 0xff3067b657990c3a,
|
||||
0x711223cfa3e5bb50, 0x33e2c2240a0f8dc3, 0xf4f3e018f031d676, 0xb60301f359dbe0e5,
|
||||
0xda050215ea6c212f, 0x98f5e3fe438617bc, 0x5fe4c1c2b9b84c09, 0x1d14202910527a9a,
|
||||
0x93366450e42ecdf0, 0xd1c685bb4dc4fb63, 0x16d7a787b7faa0d6, 0x5427466c1e109645,
|
||||
0x4863ce9ff6e9f891, 0x0a932f745f03ce02, 0xcd820d48a53d95b7, 0x8f72eca30cd7a324,
|
||||
0x0150a8daf8ab144e, 0x43a04931514122dd, 0x84b16b0dab7f7968, 0xc6418ae602954ffb,
|
||||
0xbc387aea7a8da4c0, 0xfec89b01d3679253, 0x39d9b93d2959c9e6, 0x7b2958d680b3ff75,
|
||||
0xf50b1caf74cf481f, 0xb7fbfd44dd257e8c, 0x70eadf78271b2539, 0x321a3e938ef113aa,
|
||||
0x2e5eb66066087d7e, 0x6cae578bcfe24bed, 0xabbf75b735dc1058, 0xe94f945c9c3626cb,
|
||||
0x676dd025684a91a1, 0x259d31cec1a0a732, 0xe28c13f23b9efc87, 0xa07cf2199274ca14,
|
||||
0x167ff3eacbaf2af1, 0x548f120162451c62, 0x939e303d987b47d7, 0xd16ed1d631917144,
|
||||
0x5f4c95afc5edc62e, 0x1dbc74446c07f0bd, 0xdaad56789639ab08, 0x985db7933fd39d9b,
|
||||
0x84193f60d72af34f, 0xc6e9de8b7ec0c5dc, 0x01f8fcb784fe9e69, 0x43081d5c2d14a8fa,
|
||||
0xcd2a5925d9681f90, 0x8fdab8ce70822903, 0x48cb9af28abc72b6, 0x0a3b7b1923564425,
|
||||
0x70428b155b4eaf1e, 0x32b26afef2a4998d, 0xf5a348c2089ac238, 0xb753a929a170f4ab,
|
||||
0x3971ed50550c43c1, 0x7b810cbbfce67552, 0xbc902e8706d82ee7, 0xfe60cf6caf321874,
|
||||
0xe224479f47cb76a0, 0xa0d4a674ee214033, 0x67c58448141f1b86, 0x253565a3bdf52d15,
|
||||
0xab1721da49899a7f, 0xe9e7c031e063acec, 0x2ef6e20d1a5df759, 0x6c0603e6b3b7c1ca,
|
||||
0xf6fae5c07d3274cd, 0xb40a042bd4d8425e, 0x731b26172ee619eb, 0x31ebc7fc870c2f78,
|
||||
0xbfc9838573709812, 0xfd39626eda9aae81, 0x3a28405220a4f534, 0x78d8a1b9894ec3a7,
|
||||
0x649c294a61b7ad73, 0x266cc8a1c85d9be0, 0xe17dea9d3263c055, 0xa38d0b769b89f6c6,
|
||||
0x2daf4f0f6ff541ac, 0x6f5faee4c61f773f, 0xa84e8cd83c212c8a, 0xeabe6d3395cb1a19,
|
||||
0x90c79d3fedd3f122, 0xd2377cd44439c7b1, 0x15265ee8be079c04, 0x57d6bf0317edaa97,
|
||||
0xd9f4fb7ae3911dfd, 0x9b041a914a7b2b6e, 0x5c1538adb04570db, 0x1ee5d94619af4648,
|
||||
0x02a151b5f156289c, 0x4051b05e58bc1e0f, 0x87409262a28245ba, 0xc5b073890b687329,
|
||||
0x4b9237f0ff14c443, 0x0962d61b56fef2d0, 0xce73f427acc0a965, 0x8c8315cc052a9ff6,
|
||||
0x3a80143f5cf17f13, 0x7870f5d4f51b4980, 0xbf61d7e80f251235, 0xfd913603a6cf24a6,
|
||||
0x73b3727a52b393cc, 0x31439391fb59a55f, 0xf652b1ad0167feea, 0xb4a25046a88dc879,
|
||||
0xa8e6d8b54074a6ad, 0xea16395ee99e903e, 0x2d071b6213a0cb8b, 0x6ff7fa89ba4afd18,
|
||||
0xe1d5bef04e364a72, 0xa3255f1be7dc7ce1, 0x64347d271de22754, 0x26c49cccb40811c7,
|
||||
0x5cbd6cc0cc10fafc, 0x1e4d8d2b65facc6f, 0xd95caf179fc497da, 0x9bac4efc362ea149,
|
||||
0x158e0a85c2521623, 0x577eeb6e6bb820b0, 0x906fc95291867b05, 0xd29f28b9386c4d96,
|
||||
0xcedba04ad0952342, 0x8c2b41a1797f15d1, 0x4b3a639d83414e64, 0x09ca82762aab78f7,
|
||||
0x87e8c60fded7cf9d, 0xc51827e4773df90e, 0x020905d88d03a2bb, 0x40f9e43324e99428,
|
||||
0x2cffe7d5975e55e2, 0x6e0f063e3eb46371, 0xa91e2402c48a38c4, 0xebeec5e96d600e57,
|
||||
0x65cc8190991cb93d, 0x273c607b30f68fae, 0xe02d4247cac8d41b, 0xa2dda3ac6322e288,
|
||||
0xbe992b5f8bdb8c5c, 0xfc69cab42231bacf, 0x3b78e888d80fe17a, 0x7988096371e5d7e9,
|
||||
0xf7aa4d1a85996083, 0xb55aacf12c735610, 0x724b8ecdd64d0da5, 0x30bb6f267fa73b36,
|
||||
0x4ac29f2a07bfd00d, 0x08327ec1ae55e69e, 0xcf235cfd546bbd2b, 0x8dd3bd16fd818bb8,
|
||||
0x03f1f96f09fd3cd2, 0x41011884a0170a41, 0x86103ab85a2951f4, 0xc4e0db53f3c36767,
|
||||
0xd8a453a01b3a09b3, 0x9a54b24bb2d03f20, 0x5d45907748ee6495, 0x1fb5719ce1045206,
|
||||
0x919735e51578e56c, 0xd367d40ebc92d3ff, 0x1476f63246ac884a, 0x568617d9ef46bed9,
|
||||
0xe085162ab69d5e3c, 0xa275f7c11f7768af, 0x6564d5fde549331a, 0x279434164ca30589,
|
||||
0xa9b6706fb8dfb2e3, 0xeb46918411358470, 0x2c57b3b8eb0bdfc5, 0x6ea7525342e1e956,
|
||||
0x72e3daa0aa188782, 0x30133b4b03f2b111, 0xf7021977f9cceaa4, 0xb5f2f89c5026dc37,
|
||||
0x3bd0bce5a45a6b5d, 0x79205d0e0db05dce, 0xbe317f32f78e067b, 0xfcc19ed95e6430e8,
|
||||
0x86b86ed5267cdbd3, 0xc4488f3e8f96ed40, 0x0359ad0275a8b6f5, 0x41a94ce9dc428066,
|
||||
0xcf8b0890283e370c, 0x8d7be97b81d4019f, 0x4a6acb477bea5a2a, 0x089a2aacd2006cb9,
|
||||
0x14dea25f3af9026d, 0x562e43b4931334fe, 0x913f6188692d6f4b, 0xd3cf8063c0c759d8,
|
||||
0x5dedc41a34bbeeb2, 0x1f1d25f19d51d821, 0xd80c07cd676f8394, 0x9afce626ce85b507,
|
||||
};
|
||||
211
lib/std/io.c3
Normal file
211
lib/std/io.c3
Normal file
@@ -0,0 +1,211 @@
|
||||
// Copyright (c) 2021-2022 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::io;
|
||||
import libc;
|
||||
|
||||
struct File
|
||||
{
|
||||
CFile file;
|
||||
}
|
||||
|
||||
|
||||
fn int putchar(char c) @inline
|
||||
{
|
||||
return libc::putchar(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [&in] message
|
||||
* @return `number of bytes printed.`
|
||||
*/
|
||||
fn int print(char* message)
|
||||
{
|
||||
char* pointer = message;
|
||||
while (*pointer != '\0')
|
||||
{
|
||||
if (!putchar(*pointer)) return 0;
|
||||
pointer++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [&in] message
|
||||
* @return `number of bytes printed.`
|
||||
*/
|
||||
fn int println(char *message = "") @inline
|
||||
{
|
||||
return libc::puts(message);
|
||||
}
|
||||
|
||||
fn void! File.open(File* file, char[] filename, char[] mode)
|
||||
{
|
||||
char* filename_copy = mem::talloc(filename.len + 1)!!;
|
||||
char* mode_copy = mem::talloc(mode.len + 1)!!;
|
||||
|
||||
mem::copy(filename_copy, (char*)(filename), filename.len);
|
||||
mem::copy(mode_copy, (char*)(mode), mode.len);
|
||||
filename_copy[filename.len] = 0;
|
||||
mode_copy[filename.len] = 0;
|
||||
file.file = libc::fopen(filename_copy, mode_copy);
|
||||
if (!file.file) return IoError.FILE_NOT_FOUND!;
|
||||
}
|
||||
|
||||
enum Seek
|
||||
{
|
||||
SET,
|
||||
CURSOR,
|
||||
END
|
||||
}
|
||||
|
||||
fault IoError
|
||||
{
|
||||
FILE_NOT_FOUND,
|
||||
FILE_NOT_SEEKABLE,
|
||||
FILE_NOT_VALID,
|
||||
FILE_INVALID_POSITION,
|
||||
FILE_OVERFLOW,
|
||||
FILE_IS_PIPE,
|
||||
FILE_EOF,
|
||||
FILE_INCOMPLETE_WRITE,
|
||||
INTERRUPTED,
|
||||
UNKNOWN_ERROR,
|
||||
}
|
||||
|
||||
/**
|
||||
* @require file.file != null
|
||||
**/
|
||||
fn void! File.seek(File *file, long offset, Seek seekMode = Seek.SET)
|
||||
{
|
||||
if (libc::fseek(file.file, (SeekIndex)(offset), (int)(seekMode)))
|
||||
{
|
||||
switch (libc::errno())
|
||||
{
|
||||
case errno::EBADF: return IoError.FILE_NOT_SEEKABLE!;
|
||||
case errno::EINVAL: return IoError.FILE_INVALID_POSITION!;
|
||||
case errno::EOVERFLOW: return IoError.FILE_OVERFLOW!;
|
||||
case errno::ESPIPE: return IoError.FILE_IS_PIPE!;
|
||||
default: return IoError.UNKNOWN_ERROR!;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @require file && file.file != null
|
||||
*/
|
||||
fn void! File.putc(File *file, char c)
|
||||
{
|
||||
if (!libc::fputc(c, file.file)) return IoError.FILE_EOF!;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require file != null
|
||||
*/
|
||||
fn void! File.close(File *file) @inline
|
||||
{
|
||||
if (file.file && libc::fclose(file.file))
|
||||
{
|
||||
switch (libc::errno())
|
||||
{
|
||||
case errno::ECONNRESET:
|
||||
case errno::EBADF: return IoError.FILE_NOT_VALID!;
|
||||
case errno::EINTR: return IoError.INTERRUPTED!;
|
||||
case errno::EDQUOT:
|
||||
case errno::EFAULT:
|
||||
case errno::EAGAIN:
|
||||
case errno::EFBIG:
|
||||
case errno::ENETDOWN:
|
||||
case errno::ENETUNREACH:
|
||||
case errno::ENOSPC:
|
||||
case errno::EIO: return IoError.FILE_INCOMPLETE_WRITE!;
|
||||
default: return IoError.UNKNOWN_ERROR!;
|
||||
}
|
||||
}
|
||||
file.file = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require file && file.file
|
||||
*/
|
||||
fn bool File.eof(File* file) @inline
|
||||
{
|
||||
return libc::feof(file.file) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require file && file.file
|
||||
*/
|
||||
fn usize File.read(File* file, void* buffer, usize items, usize element_size = 1)
|
||||
{
|
||||
return libc::fread(buffer, element_size, items, file.file);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [&in] file
|
||||
* @param [&out] buffer
|
||||
* @param items
|
||||
* @param element_size
|
||||
* @require file.file `File must be initialized`
|
||||
* @require element_size > 1
|
||||
*/
|
||||
fn usize File.write(File* file, void* buffer, usize items, usize element_size = 1)
|
||||
{
|
||||
return libc::fwrite(buffer, element_size, items, file.file);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [&in] file
|
||||
* @require file.file `File must be initialized`
|
||||
*/
|
||||
fn usize! File.println(File* file, char[] string)
|
||||
{
|
||||
usize len = string.len;
|
||||
if (len != libc::fwrite(string.ptr, 1, len, file.file)) return IoError.UNKNOWN_ERROR!;
|
||||
if (!libc::putc('\n', file.file)) return IoError.UNKNOWN_ERROR!;
|
||||
return len + 1;
|
||||
}
|
||||
|
||||
fn File stdout()
|
||||
{
|
||||
return { libc::stdout() };
|
||||
}
|
||||
|
||||
fn File stderr()
|
||||
{
|
||||
return { libc::stderr() };
|
||||
}
|
||||
|
||||
fn File stdin()
|
||||
{
|
||||
return { libc::stdin() };
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
|
||||
error FileError
|
||||
{
|
||||
ulong errno;
|
||||
}
|
||||
|
||||
fn FileError errorFromErrno()
|
||||
{
|
||||
return FileError { };
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
pubic fn void! File.clearerr(File *file) @inline
|
||||
{
|
||||
clearerr(file->file);
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn void File.error(File *file) @inline
|
||||
{
|
||||
int err = ferror
|
||||
}
|
||||
*/
|
||||
902
lib/std/io_printf.c3
Normal file
902
lib/std/io_printf.c3
Normal file
@@ -0,0 +1,902 @@
|
||||
module std::io;
|
||||
import libc;
|
||||
|
||||
const int PRINTF_NTOA_BUFFER_SIZE = 256;
|
||||
const int PRINTF_FTOA_BUFFER_SIZE = 256;
|
||||
const float PRINTF_MAX_FLOAT = 1e9;
|
||||
const uint PRINTF_DEFAULT_FLOAT_PRECISION = 6;
|
||||
|
||||
fault PrintFault
|
||||
{
|
||||
BUFFER_EXCEEDED,
|
||||
INTERNAL_BUFFER_EXCEEDED,
|
||||
INVALID_FORMAT_STRING,
|
||||
MISSING_ARG,
|
||||
}
|
||||
bitstruct PrintFlags : uint
|
||||
{
|
||||
bool zeropad : 0;
|
||||
bool left : 1;
|
||||
bool plus : 2;
|
||||
bool space : 3;
|
||||
bool hash : 4;
|
||||
bool uppercase : 5;
|
||||
bool precision : 6;
|
||||
bool adapt_exp : 7;
|
||||
}
|
||||
|
||||
struct PrintParam
|
||||
{
|
||||
OutputFn outfn;
|
||||
void* buffer;
|
||||
PrintFlags flags;
|
||||
uint width;
|
||||
uint prec;
|
||||
usize idx;
|
||||
}
|
||||
|
||||
define OutputFn = fn void!(char c, void* buffer, usize buffer_idx);
|
||||
|
||||
fn void! PrintParam.out(PrintParam* param, char c)
|
||||
{
|
||||
|
||||
param.outfn(c, param.buffer, param.idx++)?;
|
||||
}
|
||||
|
||||
private fn void! out_str(PrintParam* param, variant arg)
|
||||
{
|
||||
switch (arg.type.kind)
|
||||
{
|
||||
case TYPEID:
|
||||
return out_substr(param, "<typeid>");
|
||||
case VOID:
|
||||
return out_substr(param, "void");
|
||||
case ANYERR:
|
||||
case FAULT:
|
||||
return out_substr(param, (*(anyerr*)arg.ptr).nameof);
|
||||
case VARIANT:
|
||||
return out_substr(param, "<variant>");
|
||||
case ENUM:
|
||||
return out_substr(param, arg.type.names[types::variant_to_int(arg, usize)!!]);
|
||||
case STRUCT:
|
||||
return out_substr(param, "<struct>");
|
||||
case UNION:
|
||||
return out_substr(param, "<union>");
|
||||
case BITSTRUCT:
|
||||
return out_substr(param, "<bitstruct>");
|
||||
case FUNC:
|
||||
return out_substr(param, "<func>");
|
||||
case FAILABLE:
|
||||
unreachable();
|
||||
case DISTINCT:
|
||||
if (arg.type == String.typeid)
|
||||
{
|
||||
return out_substr(param, ((String*)arg).str());
|
||||
}
|
||||
return out_str(param, variant { arg.ptr, arg.type.inner });
|
||||
case POINTER:
|
||||
typeid inner = arg.type.inner;
|
||||
if (inner.kind == TypeKind.ARRAY && inner.inner == char.typeid)
|
||||
{
|
||||
char *ptr = *(char**)arg.ptr;
|
||||
return out_substr(param, ptr[:inner.len]);
|
||||
}
|
||||
return ntoa_variant(param, arg, 16);
|
||||
case SIGNED_INT:
|
||||
case UNSIGNED_INT:
|
||||
return ntoa_variant(param, arg, 10);
|
||||
case FLOAT:
|
||||
return ftoa(param, float_from_variant(arg));
|
||||
case ARRAY:
|
||||
// this is SomeType[*] so grab the "SomeType"
|
||||
typeid inner = arg.type.inner;
|
||||
usize size = inner.sizeof;
|
||||
usize len = arg.type.len;
|
||||
// Pretend this is a char[]
|
||||
void* ptr = (void*)arg.ptr;
|
||||
param.out('[')?;
|
||||
for (usize i = 0; i < len; i++)
|
||||
{
|
||||
if (i != 0) out_substr(param, ", ")?;
|
||||
out_str(param, variant { ptr, inner })?;
|
||||
ptr += size;
|
||||
}
|
||||
return param.out(']');
|
||||
case VECTOR:
|
||||
// this is SomeType[*] so grab the "SomeType"
|
||||
typeid inner = arg.type.inner;
|
||||
usize size = inner.sizeof;
|
||||
usize len = arg.type.len;
|
||||
// Pretend this is a char[]
|
||||
void* ptr = (void*)arg.ptr;
|
||||
out_substr(param, "[<")?;
|
||||
for (usize i = 0; i < len; i++)
|
||||
{
|
||||
if (i != 0) out_substr(param, ", ")?;
|
||||
out_str(param, variant { ptr, inner })?;
|
||||
ptr += size;
|
||||
}
|
||||
return out_substr(param, ">]");
|
||||
case SUBARRAY:
|
||||
// this is SomeType[] so grab the "SomeType"
|
||||
typeid inner = arg.type.inner;
|
||||
if (inner == char.typeid)
|
||||
{
|
||||
return out_substr(param, *(char[]*)arg);
|
||||
}
|
||||
usize size = inner.sizeof;
|
||||
// Pretend this is a char[]
|
||||
char[]* temp = (void*)arg.ptr;
|
||||
void* ptr = (void*)temp.ptr;
|
||||
usize len = temp.len;
|
||||
param.out('[')?;
|
||||
for (usize i = 0; i < len; i++)
|
||||
{
|
||||
if (i != 0) out_substr(param, ", ")?;
|
||||
out_str(param, variant { ptr, inner })?;
|
||||
ptr += size;
|
||||
}
|
||||
param.out(']')?;
|
||||
case BOOL:
|
||||
if (*(bool*)arg.ptr)
|
||||
{
|
||||
return out_substr(param, "true");
|
||||
}
|
||||
else
|
||||
{
|
||||
return out_substr(param, "false");
|
||||
}
|
||||
default:
|
||||
return out_substr(param, "Invalid type");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fn uint simple_atoi(char* buf, usize maxlen, usize* len_ptr) @inline
|
||||
{
|
||||
uint i = 0;
|
||||
usize len = *len_ptr;
|
||||
while (len < maxlen)
|
||||
{
|
||||
char c = buf[len];
|
||||
if (c < '0' || c > '9') break;
|
||||
i = i * 10 + c - '0';
|
||||
len++;
|
||||
}
|
||||
*len_ptr = len;
|
||||
return i;
|
||||
}
|
||||
|
||||
fault FormattingFault
|
||||
{
|
||||
UNTERMINATED_FORMAT,
|
||||
MISSING_ARG,
|
||||
INVALID_WIDTH_ARG,
|
||||
INVALID_FORMAT_TYPE,
|
||||
}
|
||||
|
||||
private fn void! printf_advance_format(usize format_len, usize *index_ptr) @inline
|
||||
{
|
||||
usize val = ++(*index_ptr);
|
||||
if (val >= format_len) return FormattingFault.UNTERMINATED_FORMAT!;
|
||||
}
|
||||
|
||||
private fn variant! next_variant(variant* args_ptr, usize args_len, usize* arg_index_ptr) @inline
|
||||
{
|
||||
if (*arg_index_ptr >= args_len) return FormattingFault.MISSING_ARG!;
|
||||
return args_ptr[(*arg_index_ptr)++];
|
||||
}
|
||||
|
||||
private fn int! printf_parse_format_field(variant* args_ptr, usize args_len, usize* args_index_ptr, char* format_ptr, usize format_len, usize* index_ptr) @inline
|
||||
{
|
||||
char c = format_ptr[*index_ptr];
|
||||
if (c >= '0' && c <= '9') return simple_atoi(format_ptr, format_len, index_ptr);
|
||||
if (c != '*') return 0;
|
||||
printf_advance_format(format_len, index_ptr)?;
|
||||
variant val = next_variant(args_ptr, args_len, args_index_ptr)?;
|
||||
if (!val.type.kind.is_int()) return FormattingFault.INVALID_WIDTH_ARG!;
|
||||
uint! intval = types::variant_to_int(val, int);
|
||||
if (catch intval) return FormattingFault.INVALID_WIDTH_ARG!;
|
||||
return intval;
|
||||
}
|
||||
|
||||
|
||||
private fn void! out_buffer_fn(char c, char[] buffer, usize buffer_idx)
|
||||
{
|
||||
if (buffer_idx >= buffer.len) return PrintFault.BUFFER_EXCEEDED!;
|
||||
buffer[buffer_idx] = c;
|
||||
}
|
||||
|
||||
private fn void! out_null_fn(char c @unused, void* data @unused, usize idx @unused)
|
||||
{
|
||||
}
|
||||
|
||||
private fn void! out_putchar_fn(char c, void* data @unused, usize idx @unused)
|
||||
{
|
||||
libc::putchar(c);
|
||||
}
|
||||
|
||||
private fn void! out_fputchar_fn(char c, void* data, usize idx @unused)
|
||||
{
|
||||
File* f = data;
|
||||
f.putc(c)?;
|
||||
}
|
||||
|
||||
private fn void! out_string_append_fn(char c, void* data, usize idx @unused)
|
||||
{
|
||||
String* s = data;
|
||||
s.append_char(c);
|
||||
}
|
||||
|
||||
private fn void! PrintParam.out_reverse(PrintParam* param, char[] buf)
|
||||
{
|
||||
usize buffer_start_idx = param.idx;
|
||||
usize len = buf.len;
|
||||
// pad spaces up to given width
|
||||
if (!param.flags.left && !param.flags.zeropad)
|
||||
{
|
||||
for (usize i = len; i < param.width; i++)
|
||||
{
|
||||
param.out(' ')?;
|
||||
}
|
||||
}
|
||||
// reverse string
|
||||
while (len) param.out(buf[--len])?;
|
||||
|
||||
// append pad spaces up to given width
|
||||
return param.left_adjust(param.idx - buffer_start_idx);
|
||||
}
|
||||
|
||||
private fn void! out_char(PrintParam* param, variant arg)
|
||||
{
|
||||
uint l = 1;
|
||||
// pre padding
|
||||
param.right_adjust(l)?;
|
||||
// char output
|
||||
Char32 c = types::variant_to_int(arg, uint) ?? 0xFFFD;
|
||||
switch (true)
|
||||
{
|
||||
case c < 0x7f:
|
||||
param.out((char)c)?;
|
||||
case c < 0x7ff:
|
||||
param.out((char)(0xC0 | c >> 6))?;
|
||||
param.out((char)(0x80 | (c & 0x3F)))?;
|
||||
case c < 0xffff:
|
||||
param.out((char)(0xE0 | c >> 12))?;
|
||||
param.out((char)(0x80 | (c >> 6 & 0x3F)))?;
|
||||
param.out((char)(0x80 | (c & 0x3F)))?;
|
||||
default:
|
||||
param.out((char)(0xF0 | c >> 18))?;
|
||||
param.out((char)(0x80 | (c >> 12 & 0x3F)))?;
|
||||
param.out((char)(0x80 | (c >> 6 & 0x3F)))?;
|
||||
param.out((char)(0x80 | (c & 0x3F)))?;
|
||||
}
|
||||
return param.left_adjust(l);
|
||||
}
|
||||
|
||||
private fn void! ntoa_format(PrintParam* param, char[] buf, usize len, bool negative, uint base)
|
||||
{
|
||||
// pad leading zeros
|
||||
if (!param.flags.left)
|
||||
{
|
||||
if (param.width && param.flags.zeropad && (negative || param.flags.plus || param.flags.space)) param.width--;
|
||||
while (len < param.prec)
|
||||
{
|
||||
if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
|
||||
buf[len++] = '0';
|
||||
}
|
||||
while (param.flags.zeropad && len < param.width)
|
||||
{
|
||||
if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
// handle hash
|
||||
if (param.flags.hash && base != 10)
|
||||
{
|
||||
if (!param.flags.precision && len && len == param.prec && len == param.width)
|
||||
{
|
||||
len--;
|
||||
if (len) len--;
|
||||
}
|
||||
if (base != 10)
|
||||
{
|
||||
if (len + 1 >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
|
||||
switch (base)
|
||||
{
|
||||
case 16:
|
||||
buf[len++] = param.flags.uppercase ? 'X' : 'x';
|
||||
case 8:
|
||||
buf[len++] = param.flags.uppercase ? 'O' : 'o';
|
||||
case 2:
|
||||
buf[len++] = param.flags.uppercase ? 'B' : 'b';
|
||||
default:
|
||||
unreachable();
|
||||
}
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
switch (true)
|
||||
{
|
||||
case negative:
|
||||
if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
|
||||
buf[len++] = '-';
|
||||
case param.flags.plus:
|
||||
if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
|
||||
buf[len++] = '+';
|
||||
case param.flags.space:
|
||||
if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
|
||||
buf[len++] = ' ';
|
||||
}
|
||||
if (!len) return;
|
||||
return param.out_reverse(buf[:len]);
|
||||
}
|
||||
|
||||
$if (env::I128_SUPPORT):
|
||||
define NtoaType = uint128;
|
||||
$else:
|
||||
define NtoaType = ulong;
|
||||
$endif;
|
||||
|
||||
private fn void! ntoa_variant(PrintParam* param, variant arg, uint base)
|
||||
{
|
||||
bool is_neg;
|
||||
NtoaType val = int_from_variant(arg, &is_neg);
|
||||
return ntoa(param, val, is_neg, base) @inline;
|
||||
}
|
||||
|
||||
private fn void! ntoa(PrintParam* param, NtoaType value, bool negative, uint base)
|
||||
{
|
||||
char[PRINTF_NTOA_BUFFER_SIZE] buf = void;
|
||||
usize len = 0;
|
||||
|
||||
// no hash for 0 values
|
||||
if (!value) param.flags.hash = false;
|
||||
|
||||
// write if precision != 0 or value is != 0
|
||||
if (!param.flags.precision || value)
|
||||
{
|
||||
char past_10 = (param.flags.uppercase ? 'A' : 'a') - 10;
|
||||
do
|
||||
{
|
||||
if (len >= PRINTF_NTOA_BUFFER_SIZE) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
|
||||
char digit = (char)(value % base);
|
||||
buf[len++] = digit + (digit < 10 ? '0' : past_10);
|
||||
value /= base;
|
||||
}
|
||||
while (value);
|
||||
}
|
||||
return ntoa_format(param, buf[:PRINTF_NTOA_BUFFER_SIZE], len, negative, base);
|
||||
}
|
||||
|
||||
|
||||
define FloatType = double;
|
||||
|
||||
// internal ftoa for fixed decimal floating point
|
||||
private fn void! ftoa(PrintParam* param, FloatType value)
|
||||
{
|
||||
char[PRINTF_FTOA_BUFFER_SIZE] buf = void;
|
||||
usize len = 0;
|
||||
const FloatType[] POW10 = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
|
||||
FloatType diff = 0.0;
|
||||
|
||||
// powers of 10
|
||||
|
||||
// test for special values
|
||||
if (value != value)
|
||||
{
|
||||
return param.out_reverse("nan");
|
||||
}
|
||||
if (value < -FloatType.max)
|
||||
{
|
||||
return param.out_reverse("fni-");
|
||||
}
|
||||
if (value > FloatType.max)
|
||||
{
|
||||
if (param.flags.plus)
|
||||
{
|
||||
return param.out_reverse("fni+");
|
||||
}
|
||||
return param.out_reverse("fni");
|
||||
}
|
||||
|
||||
// test for very large values
|
||||
// standard printf behavior is to print EVERY whole number digit -- which could be 100s of characters overflowing your buffers == bad
|
||||
if (value > PRINTF_MAX_FLOAT || value < -PRINTF_MAX_FLOAT)
|
||||
{
|
||||
return etoa(param, value);
|
||||
}
|
||||
|
||||
// test for negative
|
||||
bool negative = value < 0;
|
||||
if (negative) value = 0 - value;
|
||||
|
||||
// set default precision, if not set explicitly
|
||||
if (!param.flags.precision) param.prec = PRINTF_DEFAULT_FLOAT_PRECISION;
|
||||
|
||||
// limit precision to 9, cause a prec >= 10 can lead to overflow errors
|
||||
while (param.prec > 9)
|
||||
{
|
||||
if (len >= PRINTF_FTOA_BUFFER_SIZE) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
|
||||
buf[len++] = '0';
|
||||
param.prec--;
|
||||
}
|
||||
|
||||
// Safe due to 1e9 limit.
|
||||
int whole = (int)value;
|
||||
FloatType tmp = (value - whole) * POW10[param.prec];
|
||||
ulong frac = (ulong)tmp;
|
||||
diff = tmp - frac;
|
||||
|
||||
switch (true)
|
||||
{
|
||||
case diff > 0.5:
|
||||
++frac;
|
||||
// handle rollover, e.g. case 0.99 with prec 1 is 1.0
|
||||
if (frac >= POW10[param.prec])
|
||||
{
|
||||
frac = 0;
|
||||
++whole;
|
||||
}
|
||||
case diff < 0.5:
|
||||
break;
|
||||
case !frac && (frac & 1):
|
||||
// if halfway, round up if odd OR if last digit is 0
|
||||
++frac;
|
||||
}
|
||||
if (!param.prec)
|
||||
{
|
||||
diff = value - (FloatType)whole;
|
||||
if ((!(diff < 0.5) || diff > 0.5) && (whole & 1))
|
||||
{
|
||||
// exactly 0.5 and ODD, then round up
|
||||
// 1.5 -> 2, but 2.5 -> 2
|
||||
++whole;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint count = param.prec;
|
||||
// now do fractional part, as an unsigned number
|
||||
do
|
||||
{
|
||||
if (len >= PRINTF_FTOA_BUFFER_SIZE) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
|
||||
--count;
|
||||
buf[len++] = (char)(48 + (frac % 10));
|
||||
}
|
||||
while (frac /= 10);
|
||||
// add extra 0s
|
||||
while (count-- > 0)
|
||||
{
|
||||
if (len >= PRINTF_FTOA_BUFFER_SIZE) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
|
||||
buf[len++] = '0';
|
||||
}
|
||||
if (len >= PRINTF_FTOA_BUFFER_SIZE) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
|
||||
// add decimal
|
||||
buf[len++] = '.';
|
||||
}
|
||||
|
||||
// do whole part, number is reversed
|
||||
do
|
||||
{
|
||||
if (len >= PRINTF_FTOA_BUFFER_SIZE) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
|
||||
buf[len++] = (char)(48 + (whole % 10));
|
||||
}
|
||||
while (whole /= 10);
|
||||
|
||||
// pad leading zeros
|
||||
if (!param.flags.left && param.flags.zeropad)
|
||||
{
|
||||
if (param.width && (negative || param.flags.plus || param.flags.space)) param.width--;
|
||||
while (len < param.width)
|
||||
{
|
||||
if (len >= PRINTF_FTOA_BUFFER_SIZE) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
char next = {|
|
||||
if (negative) return '-';
|
||||
if (param.flags.plus) return '+';
|
||||
if (param.flags.space) return ' ';
|
||||
return 0;
|
||||
|};
|
||||
if (next)
|
||||
{
|
||||
if (len >= PRINTF_FTOA_BUFFER_SIZE) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
|
||||
buf[len++] = next;
|
||||
}
|
||||
return param.out_reverse(buf[:len]);
|
||||
}
|
||||
|
||||
union ConvUnion
|
||||
{
|
||||
ulong u;
|
||||
double f;
|
||||
}
|
||||
|
||||
private fn void! etoa(PrintParam* param, FloatType value)
|
||||
{
|
||||
// check for NaN and special values
|
||||
if (value != value || value < FloatType.min || value > FloatType.max)
|
||||
{
|
||||
return ftoa(param, value);
|
||||
}
|
||||
|
||||
// determine the sign
|
||||
bool negative = value < 0;
|
||||
if (negative) value = -value;
|
||||
|
||||
// default precision
|
||||
if (!param.flags.precision)
|
||||
{
|
||||
param.prec = PRINTF_DEFAULT_FLOAT_PRECISION;
|
||||
}
|
||||
|
||||
// determine the decimal exponent
|
||||
// based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c)
|
||||
ConvUnion conv;
|
||||
|
||||
conv.f = (double)value;
|
||||
int exp2 = (int)(conv.u >> 52 & 0x7FF) - 1023; // effectively log2
|
||||
conv.u = (conv.u & (1u64 << 52 - 1)) | (1023u64 << 52); // drop the exponent so conv.F is now in [1,2)
|
||||
// now approximate log10 from the log2 integer part and an expansion of ln around 1.5
|
||||
int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.f - 1.5) * 0.289529654602168);
|
||||
// now we want to compute 10^expval but we want to be sure it won't overflow
|
||||
exp2 = (int)(expval * 3.321928094887362 + 0.5);
|
||||
double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453;
|
||||
double z2 = z * z;
|
||||
conv.u = (ulong)(exp2 + 1023) << 52;
|
||||
// compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex
|
||||
conv.f *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14)))));
|
||||
// correct for rounding errors
|
||||
if (value < conv.f)
|
||||
{
|
||||
expval--;
|
||||
conv.f /= 10;
|
||||
}
|
||||
|
||||
// the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters
|
||||
uint minwidth = ((expval < 100) && (expval > -100)) ? 4 : 5;
|
||||
|
||||
// in "%g" mode, "prec" is the number of *significant figures* not decimals
|
||||
if (param.flags.adapt_exp)
|
||||
{
|
||||
// do we want to fall-back to "%f" mode?
|
||||
if (value >= 1e-4 && value < 1e6)
|
||||
{
|
||||
param.prec = param.prec > expval ? param.prec - expval - 1 : 0;
|
||||
param.flags.precision = true; // make sure ftoa respects precision
|
||||
// no characters in exponent
|
||||
minwidth = 0;
|
||||
expval = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we use one sigfig for the whole part
|
||||
if (param.prec > 0 && param.flags.precision) param.prec--;
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust width
|
||||
uint fwidth = param.width > minwidth ? param.width - minwidth : 0;
|
||||
|
||||
// if we're padding on the right, DON'T pad the floating part
|
||||
if (param.flags.left && minwidth) fwidth = 0;
|
||||
|
||||
// rescale the float value
|
||||
if (expval) value /= conv.f;
|
||||
|
||||
// output the floating part
|
||||
usize start_idx = param.idx;
|
||||
PrintFlags old = param.flags;
|
||||
param.flags.adapt_exp = false;
|
||||
param.width = fwidth;
|
||||
ftoa(param, negative ? -value : value)?;
|
||||
param.flags = old;
|
||||
|
||||
// output the exponent part
|
||||
if (minwidth)
|
||||
{
|
||||
// output the exponential symbol
|
||||
param.out(param.flags.uppercase ? 'E' : 'e')?;
|
||||
// output the exponent value
|
||||
param.flags = { .zeropad = true, .plus = true };
|
||||
param.width = minwidth - 1;
|
||||
param.prec = 0;
|
||||
ntoa(param, (NtoaType)(expval < 0 ? -expval : expval), expval < 0, 10)?;
|
||||
param.flags = old;
|
||||
// might need to right-pad spaces
|
||||
param.left_adjust(param.idx - start_idx)?;
|
||||
}
|
||||
}
|
||||
|
||||
private fn FloatType float_from_variant(variant arg)
|
||||
{
|
||||
$if (env::I128_SUPPORT):
|
||||
switch (arg)
|
||||
{
|
||||
case int128:
|
||||
return *arg;
|
||||
case uint128:
|
||||
return *arg;
|
||||
}
|
||||
$endif;
|
||||
|
||||
if (arg.type.kind == TypeKind.POINTER)
|
||||
{
|
||||
return (FloatType)(uptr)(void*)arg.ptr;
|
||||
}
|
||||
switch (arg)
|
||||
{
|
||||
case bool:
|
||||
return (FloatType)*arg;
|
||||
case ichar:
|
||||
return *arg;
|
||||
case short:
|
||||
return *arg;
|
||||
case int:
|
||||
return *arg;
|
||||
case long:
|
||||
return *arg;
|
||||
case char:
|
||||
return *arg;
|
||||
case ushort:
|
||||
return *arg;
|
||||
case uint:
|
||||
return *arg;
|
||||
case ulong:
|
||||
return *arg;
|
||||
case float:
|
||||
return (FloatType)*arg;
|
||||
case double:
|
||||
return (FloatType)*arg;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private fn NtoaType int_from_variant(variant arg, bool *is_neg)
|
||||
{
|
||||
*is_neg = false;
|
||||
$if (NtoaType.typeid == uint128.typeid):
|
||||
switch (arg)
|
||||
{
|
||||
case int128:
|
||||
int128 val = *arg;
|
||||
return (*is_neg = val < 0) ? -val : val;
|
||||
case uint128:
|
||||
return *arg;
|
||||
}
|
||||
$endif;
|
||||
|
||||
if (arg.type.kind == TypeKind.POINTER)
|
||||
{
|
||||
return (NtoaType)(uptr)(void*)arg.ptr;
|
||||
}
|
||||
switch (arg)
|
||||
{
|
||||
case bool:
|
||||
return (NtoaType)*arg;
|
||||
case ichar:
|
||||
int val = *arg;
|
||||
return (NtoaType)((*is_neg = val < 0) ? -val : val);
|
||||
case short:
|
||||
int val = *arg;
|
||||
return (NtoaType)((*is_neg = val < 0) ? -val : val);
|
||||
case int:
|
||||
int val = *arg;
|
||||
return (NtoaType)((*is_neg = val < 0) ? -val : val);
|
||||
case long:
|
||||
long val = *arg;
|
||||
return (NtoaType)((*is_neg = val < 0) ? -val : val);
|
||||
case char:
|
||||
return *arg;
|
||||
case ushort:
|
||||
return *arg;
|
||||
case uint:
|
||||
return *arg;
|
||||
case ulong:
|
||||
return *arg;
|
||||
case float:
|
||||
float f = *arg;
|
||||
return (NtoaType)((*is_neg = f < 0) ? -f : f);
|
||||
case double:
|
||||
double d = *arg;
|
||||
return (NtoaType)((*is_neg = d < 0) ? -d : d);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn usize! printf(char[] format, args...) @maydiscard
|
||||
{
|
||||
return vsnprintf(&out_putchar_fn, null, format, args);
|
||||
}
|
||||
|
||||
fn usize! String.printf(String* str, char[] format, args...) @maydiscard
|
||||
{
|
||||
return vsnprintf(&out_string_append_fn, str, format, args);
|
||||
}
|
||||
|
||||
fn usize! File.printf(File file, char[] format, args...) @maydiscard
|
||||
{
|
||||
return vsnprintf(&out_putchar_fn, &file, format, args);
|
||||
}
|
||||
|
||||
private fn void! PrintParam.left_adjust(PrintParam* param, usize len)
|
||||
{
|
||||
if (!param.flags.left) return;
|
||||
for (usize l = len; l < param.width; l++) param.out(' ')?;
|
||||
}
|
||||
|
||||
private fn void! PrintParam.right_adjust(PrintParam* param, usize len)
|
||||
{
|
||||
if (param.flags.left) return;
|
||||
for (usize l = len; l < param.width; l++) param.out(' ')?;
|
||||
}
|
||||
|
||||
private fn void! out_substr(PrintParam* param, char[] str)
|
||||
{
|
||||
usize l = conv::utf8_codepoints(str);
|
||||
uint prec = param.prec;
|
||||
if (param.flags.precision && l < prec) l = prec;
|
||||
param.right_adjust(' ')?;
|
||||
usize index = 0;
|
||||
usize chars = str.len;
|
||||
char* ptr = str.ptr;
|
||||
while (index < chars)
|
||||
{
|
||||
char c = ptr[index];
|
||||
// Break if we have precision set and we ran out...
|
||||
if (c & 0xC0 != 0x80 && param.flags.precision && !prec--) break;
|
||||
param.out(c)?;
|
||||
index++;
|
||||
}
|
||||
return param.left_adjust(l);
|
||||
}
|
||||
|
||||
private fn usize! vsnprintf(OutputFn out, void* data, char[] format, variant[] variants)
|
||||
{
|
||||
if (!out)
|
||||
{
|
||||
// use null output function
|
||||
out = &out_null_fn;
|
||||
}
|
||||
PrintParam param = { .outfn = out, .buffer = data };
|
||||
usize format_len = format.len;
|
||||
usize variant_index = 0;
|
||||
for (usize i = 0; i < format_len; i++)
|
||||
{
|
||||
// format specifier? %[flags][width][.precision][length]
|
||||
char c = format[i];
|
||||
if (c != '%')
|
||||
{
|
||||
// no
|
||||
param.out(c)?;
|
||||
continue;
|
||||
}
|
||||
i++;
|
||||
if (i >= format_len) return PrintFault.INVALID_FORMAT_STRING!;
|
||||
c = format[i];
|
||||
if (c == '%')
|
||||
{
|
||||
param.out(c)?;
|
||||
continue;
|
||||
}
|
||||
// evaluate flags
|
||||
param.flags = {};
|
||||
while FLAG_EVAL: (true)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '0': param.flags.zeropad = true;
|
||||
case '-': param.flags.left = true;
|
||||
case '+': param.flags.plus = true;
|
||||
case ' ': param.flags.space = true;
|
||||
case '#': param.flags.hash = true;
|
||||
default: break FLAG_EVAL;
|
||||
}
|
||||
if (++i >= format_len) return PrintFault.INVALID_FORMAT_STRING!;
|
||||
c = format[i];
|
||||
}
|
||||
// evaluate width field
|
||||
int w = printf_parse_format_field(variants.ptr, variants.len, &variant_index, format.ptr, format.len, &i)?;
|
||||
c = format[i];
|
||||
if (w < 0)
|
||||
{
|
||||
param.flags.left = true;
|
||||
w = -w;
|
||||
}
|
||||
param.width = w;
|
||||
// evaluate precision field
|
||||
param.prec = 0;
|
||||
if (c == '.')
|
||||
{
|
||||
param.flags.precision = true;
|
||||
if (++i >= format_len) return PrintFault.INVALID_FORMAT_STRING!;
|
||||
int prec = printf_parse_format_field(variants.ptr, variants.len, &variant_index, format.ptr, format.len, &i)?;
|
||||
param.prec = prec < 0 ? 0 : prec;
|
||||
c = format[i];
|
||||
}
|
||||
|
||||
// evaluate specifier
|
||||
uint base = 0;
|
||||
if (variant_index >= variants.len) return PrintFault.MISSING_ARG!;
|
||||
variant current = variants[variant_index++];
|
||||
switch (c)
|
||||
{
|
||||
case 'd':
|
||||
base = 10;
|
||||
param.flags.hash = false;
|
||||
case 'X' :
|
||||
param.flags.uppercase = true;
|
||||
nextcase;
|
||||
case 'x' :
|
||||
base = 16;
|
||||
case 'O':
|
||||
param.flags.uppercase = true;
|
||||
nextcase;
|
||||
case 'o' :
|
||||
base = 8;
|
||||
case 'B':
|
||||
param.flags.uppercase = true;
|
||||
nextcase;
|
||||
case 'b' :
|
||||
base = 2;
|
||||
case 'F' :
|
||||
param.flags.uppercase = true;
|
||||
nextcase;
|
||||
case 'f':
|
||||
ftoa(¶m, float_from_variant(current))?;
|
||||
continue;
|
||||
case 'E':
|
||||
param.flags.uppercase = true;
|
||||
nextcase;
|
||||
case 'e':
|
||||
etoa(¶m, float_from_variant(current))?;
|
||||
continue;
|
||||
case 'G':
|
||||
param.flags.uppercase = true;
|
||||
nextcase;
|
||||
case 'g':
|
||||
param.flags.adapt_exp = true;
|
||||
etoa(¶m, float_from_variant(current))?;
|
||||
continue;
|
||||
case 'c':
|
||||
out_char(¶m, current)?;
|
||||
continue;
|
||||
case 's':
|
||||
out_str(¶m, current)?;
|
||||
continue;
|
||||
case 'p':
|
||||
param.width = (uint)(void*.sizeof * 2);
|
||||
param.flags.zeropad = true;
|
||||
param.flags.hash = true;
|
||||
base = 16;
|
||||
default:
|
||||
return PrintFault.INVALID_FORMAT_STRING!;
|
||||
}
|
||||
if (base != 10)
|
||||
{
|
||||
param.flags.plus = false;
|
||||
param.flags.space = false;
|
||||
}
|
||||
// ignore '0' flag when precision is given
|
||||
if (param.flags.precision) param.flags.zeropad = false;
|
||||
|
||||
bool is_neg;
|
||||
NtoaType v = int_from_variant(current, &is_neg);
|
||||
|
||||
ntoa(¶m, v, is_neg, base)?;
|
||||
}
|
||||
// termination
|
||||
// out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen);
|
||||
|
||||
// return written chars without terminating \0
|
||||
return param.idx;
|
||||
}
|
||||
|
||||
354
lib/std/libc.c3
Normal file
354
lib/std/libc.c3
Normal file
@@ -0,0 +1,354 @@
|
||||
// Copyright (c) 2021 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 libc;
|
||||
// stdlib
|
||||
|
||||
|
||||
// Constants need to be per os/arch
|
||||
const int EXIT_FAILURE = 1;
|
||||
const int EXIT_SUCCESS = 0;
|
||||
const int RAND_MAX = 0x7fffffff;
|
||||
|
||||
struct DivResult
|
||||
{
|
||||
int quot;
|
||||
int rem;
|
||||
}
|
||||
|
||||
struct LongDivResult
|
||||
{
|
||||
long quot;
|
||||
long rem;
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn Errno errno()
|
||||
{
|
||||
$if (env::OS_TYPE == OsType.WIN32):
|
||||
return (Errno)windows::errno();
|
||||
$elif (env::OS_TYPE == OsType.MACOSX):
|
||||
return (Errno)macos::errno();
|
||||
$elif (env::OS_TYPE == OsType.LINUX):
|
||||
return (Errno)linux::errno();
|
||||
$else:
|
||||
return errno::ENOTRECOVERABLE;
|
||||
$endif;
|
||||
}
|
||||
|
||||
|
||||
define TerminateFunction = fn void();
|
||||
define CompareFunction = fn int(void*, void*);
|
||||
extern fn double atof(char* str);
|
||||
extern fn int atoi(char* str);
|
||||
extern fn CLongLong atoll(char* str);
|
||||
extern fn double strtod(char* str, char** endptr);
|
||||
extern fn CLong strtol(char* str, char** endptr, int base);
|
||||
extern fn CULong stroul(char* str, char** endptr, int base);
|
||||
extern fn void abort();
|
||||
extern fn void atexit(TerminateFunction f);
|
||||
extern fn void exit(int status);
|
||||
extern fn char* getenv(char* name);
|
||||
extern fn int system(char* str);
|
||||
extern fn void bsearch(void* key, void *base, usize items, usize size, CompareFunction compare);
|
||||
extern fn void qsort(void* base, usize items, usize size, CompareFunction compare);
|
||||
extern fn int abs(int x);
|
||||
extern fn DivResult div(int numer, int denom);
|
||||
extern fn long labs(long x);
|
||||
extern fn LongDivResult ldiv(long number, long denom);
|
||||
extern fn int rand();
|
||||
extern fn void srand(uint seed);
|
||||
|
||||
// MB functions omitted
|
||||
|
||||
// string
|
||||
extern fn void* memchr(void* str, int c, usize n);
|
||||
extern fn int memcmp(void* str1, void* str2, usize n);
|
||||
extern fn void* memcpy(void* dest, void* src, usize n);
|
||||
extern fn void* memmove(void* dest, void* src, usize n);
|
||||
extern fn void* memset(void* dest, usize n);
|
||||
extern fn char* strcat(char* dest, char* src);
|
||||
extern fn char* strncat(char* dest, char* src, usize n);
|
||||
extern fn char* strchr(char* str, int c);
|
||||
extern fn int strcmp(char* str1, char* str2);
|
||||
extern fn int strncmp(char* str1, char* str2, usize n);
|
||||
extern fn int strcoll(char* str1, char* str2);
|
||||
extern fn char* strcpy(char* dst, char* src);
|
||||
extern fn char* strncpy(char* dst, char* src, usize n);
|
||||
extern fn usize strcspn(char* str1, char* str2);
|
||||
extern fn char* strerror(int errn);
|
||||
extern fn usize strlen(char* str);
|
||||
extern fn char* strpbrk(char* str1, char* str2);
|
||||
extern fn usize strspn(char* str1, char* str2);
|
||||
extern fn char* strstr(char* haystack, char* needle);
|
||||
extern fn char* strtok(char* str, char* delim);
|
||||
extern fn usize strxfrm(char* dest, char* src, usize n);
|
||||
|
||||
// malloc
|
||||
extern fn void* malloc(usize size);
|
||||
extern fn void* calloc(usize count, usize size);
|
||||
extern fn void* free(void*);
|
||||
extern fn void* realloc(void* ptr, usize size);
|
||||
|
||||
// stdio
|
||||
|
||||
define Fpos = long;
|
||||
define CFile = void*;
|
||||
$switch (env::OS_TYPE):
|
||||
$case OsType.LINUX:
|
||||
extern CFile __stdin @extname("stdin");
|
||||
extern CFile __stdout @extname("stdout");
|
||||
extern CFile __stderr @extname("stderr");
|
||||
macro CFile stdin() { return __stdin; }
|
||||
macro CFile stdout() { return __stdout; }
|
||||
macro CFile stderr() { return __stderr; }
|
||||
$case OsType.MACOSX:
|
||||
extern CFile __stdinp;
|
||||
extern CFile __stdoutp;
|
||||
extern CFile __stderrp;
|
||||
macro CFile stdin() { return __stdinp; }
|
||||
macro CFile stdout() { return __stdoutp; }
|
||||
macro CFile stderr() { return __stderrp; }
|
||||
$case OsType.WIN32:
|
||||
extern fn CFile __acrt_iob_func(CInt c);
|
||||
macro CFile stdin() { return __acrt_iob_func(0); }
|
||||
macro CFile stdout() { return __acrt_iob_func(1); }
|
||||
macro CFile stderr() { return __acrt_iob_func(2); }
|
||||
$default:
|
||||
macro CFile stdin() { return (CFile*)(uptr)0; }
|
||||
macro CFile stdout() { return (CFile*)(uptr)1; }
|
||||
macro CFile stderr() { return (CFile*)(uptr)2; }
|
||||
$endswitch;
|
||||
|
||||
// The following needs to be set per arch+os
|
||||
// For now I have simply pulled the defaults from MacOS
|
||||
const int SEEK_SET = 0;
|
||||
const int SEEK_CUR = 1;
|
||||
const int SEEK_END = 2;
|
||||
const int _IOFBF = 0; // Fully buffered
|
||||
const int _IOLBF = 1; // Line buffered
|
||||
const int _IONBF = 2; // Unbuffered
|
||||
const int BUFSIZ = 1024;
|
||||
const int EOF = -1;
|
||||
const int FOPEN_MAX = 20;
|
||||
const int FILENAME_MAX = 1024;
|
||||
|
||||
define Errno = distinct CInt;
|
||||
define SeekIndex = CLong;
|
||||
|
||||
extern fn int fclose(CFile stream);
|
||||
extern fn void clearerr(CFile stream);
|
||||
extern fn int feof(CFile stream);
|
||||
extern fn int ferror(CFile stream);
|
||||
extern fn int fflush(CFile stream);
|
||||
extern fn int fgetpos(CFile stream, Fpos* pos);
|
||||
extern fn CFile fopen(char* filename, char* mode);
|
||||
extern fn usize fread(void* ptr, usize size, usize nmemb, CFile stream);
|
||||
extern fn CFile freopen(char* filename, char* mode, CFile stream);
|
||||
extern fn int fseek(CFile stream, SeekIndex offset, int whence);
|
||||
extern fn int fsetpos(CFile stream, Fpos* pos);
|
||||
extern fn SeekIndex ftell(CFile stream);
|
||||
extern fn usize fwrite(void* ptr, usize size, usize nmemb, CFile stream);
|
||||
extern fn int remove(char* filename);
|
||||
extern fn int rename(char* old_name, char* new_name);
|
||||
extern fn void rewind(CFile stream);
|
||||
extern fn void setbuf(CFile stream, char* buffer);
|
||||
extern fn void setvbuf(CFile stream, char* buffer, int mode, usize size);
|
||||
extern fn CFile tmpnam(char* str);
|
||||
extern fn int fprintf(CFile stream, char* format, ...);
|
||||
extern fn int printf(char* format, ...);
|
||||
extern fn int sprintf(char* str, char* format, ...);
|
||||
extern fn int snprintf(char* str, usize size, char* format, ...);
|
||||
extern fn int fscanf(CFile stream, char* format, ...);
|
||||
extern fn int scanf(char* format, ...);
|
||||
extern fn int sscanf(char* str, char* format, ...);
|
||||
extern fn int fgetc(CFile stream);
|
||||
extern fn char* fgets(char* str, int n, CFile stream);
|
||||
extern fn int fputc(int c, CFile stream);
|
||||
extern fn int getc(CFile stream);
|
||||
extern fn int getchar();
|
||||
extern fn int putc(char c, CFile stream);
|
||||
extern fn int putchar(int c);
|
||||
extern fn int puts(char* str);
|
||||
extern fn int ungetc(int c, CFile stream);
|
||||
extern fn void perror(char* str);
|
||||
|
||||
// vsprintf vprintf not supported
|
||||
|
||||
// time.h
|
||||
|
||||
define TimeOffset = CLong;
|
||||
|
||||
struct Tm
|
||||
{
|
||||
int tm_sec; /* seconds after the minute [0-60] */
|
||||
int tm_min; /* minutes after the hour [0-59] */
|
||||
int tm_hour; /* hours since midnight [0-23] */
|
||||
int tm_mday; /* day of the month [1-31] */
|
||||
int tm_mon; /* months since January [0-11] */
|
||||
int tm_year; /* years since 1900 */
|
||||
int tm_wday; /* days since Sunday [0-6] */
|
||||
int tm_yday; /* days since January 1 [0-365] */
|
||||
int tm_isdst; /* Daylight Savings Time flag */
|
||||
TimeOffset tm_gmtoff; /* offset from UTC in seconds */
|
||||
char *tm_zone; /* timezone abbreviation */
|
||||
}
|
||||
|
||||
// Likely wrong, must be per platform.
|
||||
const CLOCKS_PER_SEC = 1000000;
|
||||
|
||||
// Time also needs to be per platform
|
||||
define Time = long;
|
||||
define Clock = ulong;
|
||||
|
||||
extern fn char* asctime(Tm *timeptr);
|
||||
extern fn Clock clock();
|
||||
extern fn char* ctime(Time *timer);
|
||||
extern fn double difftime(Time time1, Time time2);
|
||||
extern fn Tm* gmtime(Time *timer);
|
||||
extern fn Tm* localtime(Time *timer);
|
||||
extern fn Time mktime(Tm *timeptr);
|
||||
extern fn usize strftime(char* str, usize maxsize, char* format, Tm *timeptr);
|
||||
extern fn Time time(Time *timer);
|
||||
|
||||
// signal
|
||||
define SignalFunction = fn void(int);
|
||||
extern fn SignalFunction signal(int sig, SignalFunction function);
|
||||
// Incomplete
|
||||
|
||||
module libc::errno;
|
||||
|
||||
const Errno EPERM = 1; /* Operation not permitted */
|
||||
const Errno ENOENT = 2; /* No such file or directory */
|
||||
const Errno ESRCH = 3; /* No such process */
|
||||
const Errno EINTR = 4; /* Interrupted system call */
|
||||
const Errno EIO = 5; /* I/O error */
|
||||
const Errno ENXIO = 6; /* No such device or address */
|
||||
const Errno E2BIG = 7; /* Argument list too long */
|
||||
const Errno ENOEXEC = 8; /* Exec format error */
|
||||
const Errno EBADF = 9; /* Bad file number */
|
||||
const Errno ECHILD = 10; /* No child processes */
|
||||
const Errno EAGAIN = 11; /* Try again */
|
||||
const Errno ENOMEM = 12; /* Out of memory */
|
||||
const Errno EACCES = 13; /* Permission denied */
|
||||
const Errno EFAULT = 14; /* Bad address */
|
||||
const Errno ENOTBLK = 15; /* Block device required */
|
||||
const Errno EBUSY = 16; /* Device or resource busy */
|
||||
const Errno EEXIST = 17; /* File exists */
|
||||
const Errno EXDEV = 18; /* Cross-device link */
|
||||
const Errno ENODEV = 19; /* No such device */
|
||||
const Errno ENOTDIR = 20; /* Not a directory */
|
||||
const Errno EISDIR = 21; /* Is a directory */
|
||||
const Errno EINVAL = 22; /* Invalid argument */
|
||||
const Errno ENFILE = 23; /* File table overflow */
|
||||
const Errno EMFILE = 24; /* Too many open files */
|
||||
const Errno ENOTTY = 25; /* Not a typewriter */
|
||||
const Errno ETXTBSY = 26; /* Text file busy */
|
||||
const Errno EFBIG = 27; /* File too large */
|
||||
const Errno ENOSPC = 28; /* No space left on device */
|
||||
const Errno ESPIPE = 29; /* Illegal seek */
|
||||
const Errno EROFS = 30; /* Read-only file system */
|
||||
const Errno EMLINK = 31; /* Too many links */
|
||||
const Errno EPIPE = 32; /* Broken pipe */
|
||||
const Errno EDOM = 33; /* Math argument out of domain of func */
|
||||
const Errno ERANGE = 34; /* Math result not representable */
|
||||
const Errno EDEADLK = 35; /* Resource deadlock would occur */
|
||||
const Errno ENAMETOOLONG = 36; /* File name too long */
|
||||
const Errno ENOLCK = 37; /* No record locks available */
|
||||
const Errno ENOSYS = 38; /* Function not implemented */
|
||||
const Errno ENOTEMPTY = 39; /* Directory not empty */
|
||||
const Errno ELOOP = 40; /* Too many symbolic links encountered */
|
||||
|
||||
const Errno ENOMSG = 42; /* No message of desired type */
|
||||
const Errno EIDRM = 43; /* Identifier removed */
|
||||
const Errno ECHRNG = 44; /* Channel number out of range */
|
||||
const Errno EL2NSYNC = 45; /* Level 2 not synchronized */
|
||||
const Errno EL3HLT = 46; /* Level 3 halted */
|
||||
const Errno EL3RST = 47; /* Level 3 reset */
|
||||
const Errno ELNRNG = 48; /* Link number out of range */
|
||||
const Errno EUNATCH = 49; /* Protocol driver not attached */
|
||||
const Errno ENOCSI = 50; /* No CSI structure available */
|
||||
const Errno EL2HLT = 51; /* Level 2 halted */
|
||||
const Errno EBADE = 52; /* Invalid exchange */
|
||||
const Errno EBADR = 53; /* Invalid request descriptor */
|
||||
const Errno EXFULL = 54; /* Exchange full */
|
||||
const Errno ENOANO = 55; /* No anode */
|
||||
const Errno EBADRQC = 56; /* Invalid request code */
|
||||
const Errno EBADSLT = 57; /* Invalid slot */
|
||||
|
||||
const Errno EBFONT = 59; /* Bad font file format */
|
||||
const Errno ENOSTR = 60; /* Device not a stream */
|
||||
const Errno ENODATA = 61; /* No data available */
|
||||
const Errno ETIME = 62; /* Timer expired */
|
||||
const Errno ENOSR = 63; /* Out of streams resources */
|
||||
const Errno ENONET = 64; /* Machine is not on the network */
|
||||
const Errno ENOPKG = 65; /* Package not installed */
|
||||
const Errno EREMOTE = 66; /* Object is remote */
|
||||
const Errno ENOLINK = 67; /* Link has been severed */
|
||||
const Errno EADV = 68; /* Advertise error */
|
||||
const Errno ESRMNT = 69; /* Srmount error */
|
||||
const Errno ECOMM = 70; /* Communication error on send */
|
||||
const Errno EPROTO = 71; /* Protocol error */
|
||||
const Errno EMULTIHOP = 72; /* Multihop attempted */
|
||||
const Errno EDOTDOT = 73; /* RFS specific error */
|
||||
const Errno EBADMSG = 74; /* Not a data message */
|
||||
const Errno EOVERFLOW = 75; /* Value too large for defined data type */
|
||||
const Errno ENOTUNIQ = 76; /* Name not unique on network */
|
||||
const Errno EBADFD = 77; /* File descriptor in bad state */
|
||||
const Errno EREMCHG = 78; /* Remote address changed */
|
||||
const Errno ELIBACC = 79; /* Can not access a needed shared library */
|
||||
const Errno ELIBBAD = 80; /* Accessing a corrupted shared library */
|
||||
const Errno ELIBSCN = 81; /* .lib section in a.out corrupted */
|
||||
const Errno ELIBMAX = 82; /* Attempting to link in too many shared libraries */
|
||||
const Errno ELIBEXEC = 83; /* Cannot exec a shared library directly */
|
||||
const Errno EILSEQ = 84; /* Illegal byte sequence */
|
||||
const Errno ERESTART = 85; /* Interrupted system call should be restarted */
|
||||
const Errno ESTRPIPE = 86; /* Streams pipe error */
|
||||
const Errno EUSERS = 87; /* Too many users */
|
||||
const Errno ENOTSOCK = 88; /* Socket operation on non-socket */
|
||||
const Errno EDESTADDRREQ = 89; /* Destination address required */
|
||||
const Errno EMSGSIZE = 90; /* Message too long */
|
||||
const Errno EPROTOTYPE = 91; /* Protocol wrong type for socket */
|
||||
const Errno ENOPROTOOPT = 92; /* Protocol not available */
|
||||
const Errno EPROTONOSUPPORT = 93; /* Protocol not supported */
|
||||
const Errno ESOCKTNOSUPPORT = 94; /* Socket type not supported */
|
||||
const Errno EOPNOTSUPP = 95; /* Operation not supported on transport endpoint */
|
||||
const Errno EPFNOSUPPORT = 96; /* Protocol family not supported */
|
||||
const Errno EAFNOSUPPORT = 97; /* Address family not supported by protocol */
|
||||
const Errno EADDRINUSE = 98; /* Address already in use */
|
||||
const Errno EADDRNOTAVAIL = 99; /* Cannot assign requested address */
|
||||
const Errno ENETDOWN = 100; /* Network is down */
|
||||
const Errno ENETUNREACH = 101; /* Network is unreachable */
|
||||
const Errno ENETRESET = 102; /* Network dropped connection because of reset */
|
||||
const Errno ECONNABORTED = 103; /* Software caused connection abort */
|
||||
const Errno ECONNRESET = 104; /* Connection reset by peer */
|
||||
const Errno ENOBUFS = 105; /* No buffer space available */
|
||||
const Errno EISCONN = 106; /* Transport endpoint is already connected */
|
||||
const Errno ENOTCONN = 107; /* Transport endpoint is not connected */
|
||||
const Errno ESHUTDOWN = 108; /* Cannot send after transport endpoint shutdown */
|
||||
const Errno ETOOMANYREFS = 109; /* Too many references: cannot splice */
|
||||
const Errno ETIMEDOUT = 110; /* Connection timed out */
|
||||
const Errno ECONNREFUSED = 111; /* Connection refused */
|
||||
const Errno EHOSTDOWN = 112; /* Host is down */
|
||||
const Errno EHOSTUNREACH = 113; /* No route to host */
|
||||
const Errno EALREADY = 114; /* Operation already in progress */
|
||||
const Errno EINPROGRESS = 115; /* Operation now in progress */
|
||||
const Errno ESTALE = 116; /* Stale NFS file handle */
|
||||
const Errno EUCLEAN = 117; /* Structure needs cleaning */
|
||||
const Errno ENOTNAM = 118; /* Not a XENIX named type file */
|
||||
const Errno ENAVAIL = 119; /* No XENIX semaphores available */
|
||||
const Errno EISNAM = 120; /* Is a named type file */
|
||||
const Errno EREMOTEIO = 121; /* Remote I/O error */
|
||||
const Errno EDQUOT = 122; /* Quota exceeded */
|
||||
|
||||
const Errno ENOMEDIUM = 123; /* No medium found */
|
||||
const Errno EMEDIUMTYPE = 124; /* Wrong medium type */
|
||||
const Errno ECANCELED = 125; /* Operation Canceled */
|
||||
const Errno ENOKEY = 126; /* Required key not available */
|
||||
const Errno EKEYEXPIRED = 127; /* Key has expired */
|
||||
const Errno EKEYREVOKED = 128; /* Key has been revoked */
|
||||
const Errno EKEYREJECTED = 129; /* Key was rejected by service */
|
||||
|
||||
const Errno EOWNERDEAD = 130; /* Owner died */
|
||||
const Errno ENOTRECOVERABLE = 131; /* State not recoverable */
|
||||
@@ -1,5 +1,7 @@
|
||||
// Copyright (c) 2021 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::array::linkedlist<Type>;
|
||||
import std::mem;
|
||||
|
||||
private struct Node
|
||||
{
|
||||
@@ -15,15 +17,15 @@ struct LinkedList
|
||||
Node *last;
|
||||
}
|
||||
|
||||
func void LinkedList.push(LinkedList *list, Type value)
|
||||
fn void LinkedList.push(LinkedList *list, Type value)
|
||||
{
|
||||
list.linkLast(value);
|
||||
}
|
||||
|
||||
private func void LinkedList.linkFirst(LinkedList *list, Type value)
|
||||
private fn void LinkedList.linkFirst(LinkedList *list, Type value)
|
||||
{
|
||||
Node *first = list.first;
|
||||
Node *new_node = @mem::malloc(Node);
|
||||
Node *new_node = mem::malloc(Node);
|
||||
*new_node = { .next = first, .value = value };
|
||||
list.first = new_node;
|
||||
if (!first)
|
||||
@@ -37,10 +39,10 @@ private func void LinkedList.linkFirst(LinkedList *list, Type value)
|
||||
list.size++;
|
||||
}
|
||||
|
||||
private func void LinkedList.linkLast(LinkedList *list, Type value)
|
||||
private fn void LinkedList.linkLast(LinkedList *list, Type value)
|
||||
{
|
||||
Node *last = list.last;
|
||||
Node *new_node = mem::alloc($sizeof(Node));
|
||||
Node *new_node = mem::alloc(Node.sizeof);
|
||||
*new_node = { .prev = last, .value = value };
|
||||
list.last = new_node;
|
||||
if (!last)
|
||||
@@ -54,7 +56,7 @@ private func void LinkedList.linkLast(LinkedList *list, Type value)
|
||||
list.size++;
|
||||
}
|
||||
|
||||
func void LinkedList.free(LinkedList *list)
|
||||
fn void LinkedList.free(LinkedList *list)
|
||||
{
|
||||
for (Node* node = list.first; node != null;)
|
||||
{
|
||||
@@ -67,12 +69,12 @@ func void LinkedList.free(LinkedList *list)
|
||||
list.size = 0;
|
||||
}
|
||||
|
||||
func usize LinkedList.len(LinkedList* list) @inline
|
||||
fn usize LinkedList.len(LinkedList* list) @inline
|
||||
{
|
||||
return list.size;
|
||||
}
|
||||
|
||||
func Type LinkedList.get(LinkedList* list, usize index)
|
||||
fn Type LinkedList.get(LinkedList* list, usize index)
|
||||
{
|
||||
Node* node = list.first;
|
||||
while (index--)
|
||||
@@ -84,10 +86,10 @@ func Type LinkedList.get(LinkedList* list, usize index)
|
||||
/**
|
||||
* @require succ != null
|
||||
**/
|
||||
private func void LinkedList.linkBefore(LinkedList *list, Node *succ, Type value)
|
||||
private fn void LinkedList.linkBefore(LinkedList *list, Node *succ, Type value)
|
||||
{
|
||||
Node* pred = succ.prev;
|
||||
Node* new_node = @mem::malloc(Node);
|
||||
Node* new_node = mem::malloc(Node);
|
||||
*new_node = { .prev = pred, .next = succ, .value = value };
|
||||
succ.prev = new_node;
|
||||
if (!pred)
|
||||
@@ -104,7 +106,7 @@ private func void LinkedList.linkBefore(LinkedList *list, Node *succ, Type value
|
||||
/**
|
||||
* @require f == list.first && f != null
|
||||
**/
|
||||
private func void unlinkFirst(LinkedList* list, Node* f)
|
||||
private fn void unlinkFirst(LinkedList* list, Node* f)
|
||||
{
|
||||
Node* next = f.next;
|
||||
mem::free(f);
|
||||
@@ -123,7 +125,7 @@ private func void unlinkFirst(LinkedList* list, Node* f)
|
||||
/**
|
||||
* @require l == list.last && l != null
|
||||
**/
|
||||
private func void LinkedList.unlinkLast(LinkedList *list, Node* l)
|
||||
private fn void LinkedList.unlinkLast(LinkedList *list, Node* l)
|
||||
{
|
||||
Node* prev = l.prev;
|
||||
list.last = prev;
|
||||
@@ -142,7 +144,7 @@ private func void LinkedList.unlinkLast(LinkedList *list, Node* l)
|
||||
/**
|
||||
* @require x != null
|
||||
**/
|
||||
private func void LinkedList.unlink(LinkedList* list, Node* x)
|
||||
private fn void LinkedList.unlink(LinkedList* list, Node* x)
|
||||
{
|
||||
Node* next = x.next;
|
||||
Node* prev = x.prev;
|
||||
133
lib/std/list.c3
Normal file
133
lib/std/list.c3
Normal file
@@ -0,0 +1,133 @@
|
||||
// Copyright (c) 2021 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::array::list<Type>;
|
||||
|
||||
struct List
|
||||
{
|
||||
usize size;
|
||||
usize capacity;
|
||||
Type *entries;
|
||||
}
|
||||
|
||||
private fn void List.ensure_capacity(List *list) @inline
|
||||
{
|
||||
if (list.capacity == list.size)
|
||||
{
|
||||
list.capacity = list.capacity ? 2 * list.capacity : 16;
|
||||
list.entries = mem::realloc(list.entries, Type.sizeof * list.capacity);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn void List.push(List *list, Type element) @inline
|
||||
{
|
||||
list.append(element);
|
||||
}
|
||||
|
||||
fn void List.append(List* list, Type element)
|
||||
{
|
||||
list.ensure_capacity();
|
||||
list.entries[list.size++] = element;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require list.size > 0
|
||||
*/
|
||||
fn Type List.pop(List* list)
|
||||
{
|
||||
return list.entries[--list.size];
|
||||
}
|
||||
|
||||
/**
|
||||
* @require list.size > 0
|
||||
*/
|
||||
fn Type List.pop_first(List *list)
|
||||
{
|
||||
Type value = list.entries[0];
|
||||
list.remove_at(0);
|
||||
return value;
|
||||
}
|
||||
|
||||
fn void List.remove_at(List *list, usize index)
|
||||
{
|
||||
for (usize i = index + 1; i < list.size; i++)
|
||||
{
|
||||
list.entries[i - 1] = list.entries[i];
|
||||
}
|
||||
list.size--;
|
||||
}
|
||||
|
||||
fn void List.push_front(List *list, Type type) @inline
|
||||
{
|
||||
list.insert_at(0, type);
|
||||
}
|
||||
|
||||
fn void List.insert_at(List* list, usize index, Type type)
|
||||
{
|
||||
list.ensure_capacity();
|
||||
for (usize i = list.size; i > index; i--)
|
||||
{
|
||||
list.entries[i] = list.entries[i - 1];
|
||||
}
|
||||
list.size++;
|
||||
list.entries[index] = type;
|
||||
}
|
||||
|
||||
fn void List.remove_last(List* list)
|
||||
{
|
||||
list.size--;
|
||||
}
|
||||
|
||||
fn void List.remove_first(List *list)
|
||||
{
|
||||
list.remove_at(0);
|
||||
}
|
||||
|
||||
fn Type* List.first(List *list)
|
||||
{
|
||||
return list.size ? &list.entries[0] : null;
|
||||
}
|
||||
|
||||
fn Type* List.last(List *list)
|
||||
{
|
||||
return list.size ? &list.entries[list.size - 1] : null;
|
||||
}
|
||||
|
||||
fn bool List.is_empty(List *list)
|
||||
{
|
||||
return !list.size;
|
||||
}
|
||||
|
||||
fn usize List.len(List *list) @operator(len)
|
||||
{
|
||||
return list.size;
|
||||
}
|
||||
|
||||
fn Type List.get(List *list, usize index)
|
||||
{
|
||||
return list.entries[index];
|
||||
}
|
||||
|
||||
fn void List.free(List *list)
|
||||
{
|
||||
mem::free(list.entries);
|
||||
list.capacity = 0;
|
||||
list.size = 0;
|
||||
list.entries = null;
|
||||
}
|
||||
|
||||
fn void List.swap(List *list, usize i, usize j)
|
||||
{
|
||||
@swap(list.entries[i], list.entries[j]);
|
||||
}
|
||||
|
||||
macro Type List.@item_at(List &list, usize index) @operator(elementat)
|
||||
{
|
||||
return list.entries[index];
|
||||
}
|
||||
|
||||
macro Type* List.@item_ref(List &list, usize index) @operator(elementref)
|
||||
{
|
||||
return &list.entries[index];
|
||||
}
|
||||
139
lib/std/math.c3
Normal file
139
lib/std/math.c3
Normal file
@@ -0,0 +1,139 @@
|
||||
// Copyright (c) 2021 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::math;
|
||||
|
||||
// TODO Define these using quad precision.
|
||||
const E = 2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427427466;
|
||||
const LOG2E = 1.44269504088896340735992468100189214; // log2(e)
|
||||
const LOG10E = 0.434294481903251827651128918916605082; // log10(e)
|
||||
const LN2 = 0.693147180559945309417232121458176568; // ln(2)
|
||||
const LN10 = 2.30258509299404568401799145468436421; // ln(10)
|
||||
const PI = 3.14159265358979323846264338327950288419716939937510; // pi
|
||||
const PI_2 = 1.57079632679489661923132169163975144; // pi / 2
|
||||
const PI_4 = 0.785398163397448309615660845819875721; // pi / 4
|
||||
const DIV_PI = 0.318309886183790671537767526745028724; // 1 / pi
|
||||
const DIV_2_PI = 0.636619772367581343075535053490057448; // 2 / pi
|
||||
const DIV_2_SQRTPI = 1.12837916709551257389615890312154517; // 2/sqrt(pi)
|
||||
const SQRT2 = 1.41421356237309504880168872420969808; // sqrt(2)
|
||||
const double DIV_1_SQRT2 = 0.707106781186547524400844362104849039; // 1 / sqrt(2)
|
||||
|
||||
const HALF_MAX = 6.5504e+4;
|
||||
const HALF_MIN = 6.103515625e-5;
|
||||
const HALF_DENORM_MIN = 5.9604644775390625e-8;
|
||||
const HALF_DIG = 3;
|
||||
const HALF_DEC_DIGITS = 5;
|
||||
const HALF_MANT_DIG = 11;
|
||||
const HALF_MAX_10_EXP = 4;
|
||||
const HALF_MIN_10_EXP = -4;
|
||||
const HALF_MAX_EXP = 16;
|
||||
const HALF_MIN_EXP = -13;
|
||||
const HALF_EPSILON = 9.765625e-4;
|
||||
|
||||
const FLOAT_MAX = 0x1.fffffep+127;
|
||||
const FLOAT_MIN = 1.17549435e-38;
|
||||
const FLOAT_DENORM_MIN = 1.40129846432481707092e-45;
|
||||
const FLOAT_DIG = 6;
|
||||
const FLOAT_DEC_DIGITS = 9;
|
||||
const FLOAT_MANT_DIG = 24;
|
||||
const FLOAT_MAX_10_EXP = 38;
|
||||
const FLOAT_MIN_10_EXP = -37;
|
||||
const FLOAT_MAX_EXP = 128;
|
||||
const FLOAT_MIN_EXP = -125;
|
||||
const FLOAT_EPSILON = 1.1920928955078125e-07;
|
||||
|
||||
const DOUBLE_MAX = 1.79769313486231570815e+308;
|
||||
const DOUBLE_MIN = 2.2250738585072014e-308;
|
||||
const DOUBLE_DENORM_MIN = 4.94065645841246544177e-324;
|
||||
const DOUBLE_DIG = 15;
|
||||
const DOUBLE_DEC_DIGITS = 17;
|
||||
const DOUBLE_MANT_DIG = 53;
|
||||
const DOUBLE_MAX_10_EXP = 308;
|
||||
const DOUBLE_MIN_10_EXP = -307;
|
||||
const DOUBLE_MAX_EXP = 1024;
|
||||
const DOUBLE_MIN_EXP = -1021;
|
||||
const DOUBLE_EPSILON = 2.22044604925031308085e-16;
|
||||
/*
|
||||
const QUAD_MAX = 1.18973149535723176508575932662800702e+4932;
|
||||
const QUAD_MIN = 3.36210314311209350626267781732175260e-4932;
|
||||
const QUAD_DENORM_MIN = 6.47517511943802511092443895822764655e-4966;
|
||||
const QUAD_DIG = 33;
|
||||
const QUAD_DEC_DIGITS = 36;
|
||||
const QUAD_MANT_DIG = 113;
|
||||
const QUAD_MAX_10_EXP = 4932;
|
||||
const QUAD_MIN_10_EXP = -4931;
|
||||
const QUAD_MAX_EXP = 16384;
|
||||
const QUAD_MIN_EXP = -16481;
|
||||
const QUAD_EPSILON = 1.92592994438723585305597794258492732e-34;
|
||||
*/
|
||||
|
||||
macro max(x, y) @builtin
|
||||
{
|
||||
return x > y ? x : y;
|
||||
}
|
||||
|
||||
macro min(x, y) @builtin
|
||||
{
|
||||
return x < y ? x : y;
|
||||
}
|
||||
|
||||
fn double log10(double x) @inline
|
||||
{
|
||||
return $$log10(x);
|
||||
}
|
||||
|
||||
fn double log2(double x) @inline
|
||||
{
|
||||
return $$log2(x);
|
||||
}
|
||||
|
||||
fn double log(double x) @inline
|
||||
{
|
||||
return $$log(x);
|
||||
}
|
||||
|
||||
fn double cos(double x) @inline
|
||||
{
|
||||
return $$cos(x);
|
||||
}
|
||||
|
||||
fn double sin(double x) @inline
|
||||
{
|
||||
return $$sin(x);
|
||||
}
|
||||
|
||||
fn double exp(double x) @inline
|
||||
{
|
||||
return $$exp(x);
|
||||
}
|
||||
|
||||
fn double pow(double x, double y) @inline
|
||||
{
|
||||
return $$pow(x, y);
|
||||
}
|
||||
|
||||
fn double fabs(double x) @inline
|
||||
{
|
||||
return $$fabs(x);
|
||||
}
|
||||
|
||||
fn double trunc(double x) @inline
|
||||
{
|
||||
return $$trunc(x);
|
||||
}
|
||||
|
||||
fn double ceil(double x) @inline
|
||||
{
|
||||
return $$ceil(x);
|
||||
}
|
||||
|
||||
/**
|
||||
* @checked x & 1
|
||||
*/
|
||||
macro bool is_power_of_2(x)
|
||||
{
|
||||
return x != 0 && (x & (x - 1)) == 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
391
lib/std/math.matrix.c3
Normal file
391
lib/std/math.matrix.c3
Normal file
@@ -0,0 +1,391 @@
|
||||
module std::math::matrix;
|
||||
|
||||
fault MatrixError {
|
||||
MATRIX_INVERSE_DOESNT_EXIST,
|
||||
}
|
||||
|
||||
struct Matrix2x2 {
|
||||
union {
|
||||
struct {
|
||||
float m00, m01;
|
||||
float m10, m11;
|
||||
}
|
||||
float[4] m;
|
||||
}
|
||||
}
|
||||
|
||||
struct Matrix3x3 {
|
||||
union {
|
||||
struct {
|
||||
float m00; float m01; float m02;
|
||||
float m10; float m11; float m12;
|
||||
float m20; float m21; float m22;
|
||||
}
|
||||
float[9] m;
|
||||
}
|
||||
}
|
||||
|
||||
struct Matrix4x4 {
|
||||
union {
|
||||
float[16] m;
|
||||
struct {
|
||||
float m00, m01, m02, m03;
|
||||
float m10, m11, m12, m13;
|
||||
float m20, m21, m22, m23;
|
||||
float m30, m31, m32, m33;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn float[<2>] Matrix2x2.apply(Matrix2x2* mat, float[<2>] vec) {
|
||||
return float[<2>] {
|
||||
mat.m00 * vec[0] + mat.m01 * vec[1],
|
||||
mat.m10 * vec[0] + mat.m11 * vec[1],
|
||||
};
|
||||
}
|
||||
|
||||
fn float[<3>] Matrix3x3.apply(Matrix3x3* mat, float[<3>] vec) {
|
||||
return float[<3>] {
|
||||
mat.m00 * vec[0] + mat.m01 * vec[1] + mat.m02 * vec[2],
|
||||
mat.m10 * vec[0] + mat.m11 * vec[1] + mat.m12 * vec[2],
|
||||
mat.m20 * vec[0] + mat.m21 * vec[1] + mat.m22 * vec[2],
|
||||
};
|
||||
}
|
||||
|
||||
fn float[<4>] Matrix4x4.apply(Matrix4x4* mat, float[<4>] vec) {
|
||||
return float[<4>] {
|
||||
mat.m00 * vec[0] + mat.m01 * vec[1] + mat.m02 * vec[2] + mat.m03 * vec[3],
|
||||
mat.m10 * vec[0] + mat.m11 * vec[1] + mat.m12 * vec[2] + mat.m13 * vec[3],
|
||||
mat.m20 * vec[0] + mat.m21 * vec[1] + mat.m22 * vec[2] + mat.m23 * vec[3],
|
||||
mat.m30 * vec[0] + mat.m31 * vec[1] + mat.m32 * vec[2] + mat.m33 * vec[3],
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
fn Matrix2x2 Matrix2x2.mul(Matrix2x2* a, Matrix2x2 b) {
|
||||
return Matrix2x2 { .m = {
|
||||
a.m00 * b.m00 + a.m01 * b.m10, a.m00 * b.m01 + a.m01 * b.m11,
|
||||
a.m10 * b.m01 + a.m11 * b.m11, a.m10 * b.m01 + a.m11 * b.m11,
|
||||
} };
|
||||
}
|
||||
|
||||
fn Matrix3x3 Matrix3x3.mul(Matrix3x3* a, Matrix3x3 b) {
|
||||
return Matrix3x3 { .m = {
|
||||
a.m00 * b.m00 + a.m01 * b.m10 + a.m02 * b.m20,
|
||||
a.m00 * b.m01 + a.m01 * b.m11 + a.m02 * b.m21,
|
||||
a.m00 * b.m02 + a.m01 * b.m12 + a.m02 * b.m22,
|
||||
|
||||
a.m10 * b.m00 + a.m11 * b.m10 + a.m12 * b.m20,
|
||||
a.m10 * b.m01 + a.m11 * b.m11 + a.m12 * b.m21,
|
||||
a.m10 * b.m02 + a.m11 * b.m12 + a.m12 * b.m22,
|
||||
|
||||
a.m20 * b.m00 + a.m21 * b.m10 + a.m22 * b.m20,
|
||||
a.m20 * b.m01 + a.m21 * b.m11 + a.m22 * b.m21,
|
||||
a.m20 * b.m02 + a.m21 * b.m12 + a.m22 * b.m22,
|
||||
} };
|
||||
}
|
||||
|
||||
fn Matrix4x4 Matrix4x4.mul(Matrix4x4* a, Matrix4x4 b) {
|
||||
return Matrix4x4 { .m = {
|
||||
a.m00 * b.m00 + a.m01 * b.m10 + a.m02 * b.m20 + a.m03 * b.m30,
|
||||
a.m00 * b.m01 + a.m01 * b.m11 + a.m02 * b.m21 + a.m03 * b.m31,
|
||||
a.m00 * b.m02 + a.m01 * b.m12 + a.m02 * b.m22 + a.m03 * b.m32,
|
||||
a.m00 * b.m03 + a.m01 * b.m13 + a.m02 * b.m23 + a.m03 * b.m33,
|
||||
|
||||
a.m10 * b.m00 + a.m11 * b.m10 + a.m12 * b.m20 + a.m13 * b.m30,
|
||||
a.m10 * b.m01 + a.m11 * b.m11 + a.m12 * b.m21 + a.m13 * b.m31,
|
||||
a.m10 * b.m02 + a.m11 * b.m12 + a.m12 * b.m22 + a.m13 * b.m32,
|
||||
a.m10 * b.m03 + a.m11 * b.m13 + a.m12 * b.m23 + a.m13 * b.m33,
|
||||
|
||||
a.m20 * b.m00 + a.m21 * b.m10 + a.m22 * b.m20 + a.m23 * b.m30,
|
||||
a.m20 * b.m01 + a.m21 * b.m11 + a.m22 * b.m21 + a.m23 * b.m31,
|
||||
a.m20 * b.m02 + a.m21 * b.m12 + a.m22 * b.m22 + a.m23 * b.m32,
|
||||
a.m20 * b.m03 + a.m21 * b.m13 + a.m22 * b.m23 + a.m23 * b.m33,
|
||||
|
||||
a.m30 * b.m00 + a.m31 * b.m10 + a.m32 * b.m20 + a.m33 * b.m30,
|
||||
a.m30 * b.m01 + a.m31 * b.m11 + a.m32 * b.m21 + a.m33 * b.m31,
|
||||
a.m30 * b.m02 + a.m31 * b.m12 + a.m32 * b.m22 + a.m33 * b.m32,
|
||||
a.m30 * b.m03 + a.m31 * b.m13 + a.m32 * b.m23 + a.m33 * b.m33,
|
||||
} };
|
||||
}
|
||||
|
||||
|
||||
fn Matrix2x2 Matrix2x2.component_mul(Matrix2x2* mat, float s) {
|
||||
return Matrix2x2 { .m = {
|
||||
mat.m00 * s, mat.m01 * s,
|
||||
mat.m10 * s, mat.m11 * s,
|
||||
} };
|
||||
}
|
||||
|
||||
fn Matrix3x3 Matrix3x3.component_mul(Matrix3x3* mat, float s) {
|
||||
return Matrix3x3 { .m = {
|
||||
mat.m00 * s, mat.m01 * s, mat.m02 * s,
|
||||
mat.m10 * s, mat.m11 * s, mat.m12 * s,
|
||||
mat.m20 * s, mat.m21 * s, mat.m22 * s,
|
||||
} };
|
||||
}
|
||||
|
||||
fn Matrix4x4 Matrix4x4.component_mul(Matrix4x4* mat, float s) {
|
||||
return Matrix4x4 { .m = {
|
||||
mat.m00 * s, mat.m01 * s, mat.m02 * s, mat.m03 * s,
|
||||
mat.m10 * s, mat.m11 * s, mat.m12 * s, mat.m13 * s,
|
||||
mat.m20 * s, mat.m21 * s, mat.m22 * s, mat.m23 * s,
|
||||
mat.m30 * s, mat.m31 * s, mat.m32 * s, mat.m33 * s,
|
||||
} };
|
||||
}
|
||||
|
||||
|
||||
fn Matrix2x2 Matrix2x2.transpose(Matrix2x2* mat) {
|
||||
return Matrix2x2 { .m = { mat.m00, mat.m10, mat.m01, mat.m11 } };
|
||||
}
|
||||
|
||||
fn Matrix3x3 Matrix3x3.transpose(Matrix3x3* mat) {
|
||||
return Matrix3x3 { .m = {
|
||||
mat.m00, mat.m10, mat.m20,
|
||||
mat.m01, mat.m11, mat.m21,
|
||||
mat.m02, mat.m12, mat.m22,
|
||||
} };
|
||||
}
|
||||
|
||||
fn Matrix4x4 Matrix4x4.transpose(Matrix4x4* mat) {
|
||||
return Matrix4x4 { .m = {
|
||||
mat.m00, mat.m10, mat.m20, mat.m30,
|
||||
mat.m01, mat.m11, mat.m21, mat.m31,
|
||||
mat.m02, mat.m12, mat.m22, mat.m32,
|
||||
mat.m03, mat.m13, mat.m23, mat.m33,
|
||||
} };
|
||||
}
|
||||
|
||||
|
||||
fn float Matrix2x2.determinant(Matrix2x2* mat) {
|
||||
return mat.m00 * mat.m11 - mat.m01 * mat.m10;
|
||||
}
|
||||
|
||||
fn float Matrix3x3.determinant(Matrix3x3* mat) {
|
||||
return
|
||||
mat.m00 * (mat.m11 * mat.m22 - mat.m21 * mat.m12) -
|
||||
mat.m01 * (mat.m10 * mat.m22 - mat.m20 * mat.m12) +
|
||||
mat.m02 * (mat.m10 * mat.m21 - mat.m20 * mat.m11);
|
||||
}
|
||||
|
||||
fn float Matrix4x4.determinant(Matrix4x4* mat) {
|
||||
return
|
||||
mat.m00 * (mat.m11 * (mat.m22 * mat.m33 - mat.m32 * mat.m23) -
|
||||
mat.m12 * (mat.m21 * mat.m33 - mat.m31 * mat.m23) +
|
||||
mat.m13 * (mat.m21 * mat.m32 - mat.m31 * mat.m22) ) -
|
||||
mat.m01 * (mat.m10 * (mat.m22 * mat.m33 - mat.m32 * mat.m23) -
|
||||
mat.m12 * (mat.m20 * mat.m33 - mat.m30 * mat.m23) +
|
||||
mat.m13 * (mat.m20 * mat.m32 - mat.m30 * mat.m22) ) +
|
||||
mat.m02 * (mat.m10 * (mat.m21 * mat.m33 - mat.m31 * mat.m23) -
|
||||
mat.m11 * (mat.m20 * mat.m33 - mat.m30 * mat.m23) +
|
||||
mat.m13 * (mat.m20 * mat.m31 - mat.m30 * mat.m21) ) -
|
||||
mat.m03 * (mat.m10 * (mat.m21 * mat.m32 - mat.m31 * mat.m22) -
|
||||
mat.m11 * (mat.m20 * mat.m32 - mat.m30 * mat.m22) +
|
||||
mat.m12 * (mat.m20 * mat.m31 - mat.m30 * mat.m21) )
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
fn Matrix2x2 Matrix2x2.adjoint(Matrix2x2* mat) {
|
||||
return Matrix2x2 { .m = { mat.m00, -mat.m01, -mat.m10, mat.m11 } };
|
||||
}
|
||||
|
||||
fn Matrix3x3 Matrix3x3.adjoint(Matrix3x3* mat) {
|
||||
return Matrix3x3 { .m = {
|
||||
(mat.m11 * mat.m22 - mat.m21 * mat.m12),
|
||||
-(mat.m10 * mat.m22 - mat.m20 * mat.m12),
|
||||
(mat.m10 * mat.m21 - mat.m20 * mat.m11),
|
||||
|
||||
-(mat.m01 * mat.m22 - mat.m21 * mat.m02),
|
||||
(mat.m00 * mat.m22 - mat.m20 * mat.m02),
|
||||
-(mat.m00 * mat.m21 - mat.m20 * mat.m01),
|
||||
|
||||
(mat.m01 * mat.m12 - mat.m11 * mat.m02),
|
||||
-(mat.m00 * mat.m12 - mat.m10 * mat.m02),
|
||||
(mat.m00 * mat.m11 - mat.m10 * mat.m01),
|
||||
} };
|
||||
}
|
||||
|
||||
fn Matrix4x4 Matrix4x4.adjoint(Matrix4x4* mat) {
|
||||
return Matrix4x4 { .m = {
|
||||
(mat.m11 * (mat.m22 * mat.m33 - mat.m32 * mat.m23) -
|
||||
mat.m12 * (mat.m21 * mat.m33 - mat.m31 * mat.m23) +
|
||||
mat.m13 * (mat.m21 * mat.m32 - mat.m31 * mat.m22)),
|
||||
-(mat.m10 * (mat.m22 * mat.m33 - mat.m32 * mat.m23) -
|
||||
mat.m12 * (mat.m20 * mat.m33 - mat.m30 * mat.m23) +
|
||||
mat.m13 * (mat.m20 * mat.m32 - mat.m30 * mat.m22)),
|
||||
(mat.m10 * (mat.m21 * mat.m33 - mat.m31 * mat.m23) -
|
||||
mat.m11 * (mat.m20 * mat.m33 - mat.m30 * mat.m23) +
|
||||
mat.m13 * (mat.m20 * mat.m31 - mat.m30 * mat.m21)),
|
||||
-(mat.m10 * (mat.m21 * mat.m32 - mat.m31 * mat.m22) -
|
||||
mat.m11 * (mat.m20 * mat.m32 - mat.m30 * mat.m22) +
|
||||
mat.m12 * (mat.m20 * mat.m31 - mat.m30 * mat.m21)),
|
||||
|
||||
-(mat.m01 * (mat.m22 * mat.m33 - mat.m32 * mat.m23) -
|
||||
mat.m02 * (mat.m21 * mat.m33 - mat.m31 * mat.m23) +
|
||||
mat.m03 * (mat.m21 * mat.m32 - mat.m31 * mat.m22)),
|
||||
(mat.m00 * (mat.m22 * mat.m33 - mat.m32 * mat.m23) -
|
||||
mat.m02 * (mat.m20 * mat.m33 - mat.m30 * mat.m23) +
|
||||
mat.m03 * (mat.m20 * mat.m32 - mat.m30 * mat.m22)),
|
||||
-(mat.m00 * (mat.m21 * mat.m33 - mat.m31 * mat.m23) -
|
||||
mat.m01 * (mat.m20 * mat.m33 - mat.m30 * mat.m23) +
|
||||
mat.m03 * (mat.m20 * mat.m31 - mat.m30 * mat.m21)),
|
||||
(mat.m00 * (mat.m21 * mat.m32 - mat.m31 * mat.m22) -
|
||||
mat.m01 * (mat.m20 * mat.m32 - mat.m30 * mat.m22) +
|
||||
mat.m02 * (mat.m20 * mat.m31 - mat.m30 * mat.m21)),
|
||||
|
||||
(mat.m01 * (mat.m12 * mat.m33 - mat.m32 * mat.m13) -
|
||||
mat.m02 * (mat.m11 * mat.m33 - mat.m31 * mat.m13) +
|
||||
mat.m03 * (mat.m11 * mat.m32 - mat.m31 * mat.m12)),
|
||||
-(mat.m00 * (mat.m12 * mat.m33 - mat.m32 * mat.m13) -
|
||||
mat.m02 * (mat.m10 * mat.m33 - mat.m30 * mat.m13) +
|
||||
mat.m03 * (mat.m10 * mat.m32 - mat.m30 * mat.m12)),
|
||||
(mat.m00 * (mat.m11 * mat.m33 - mat.m31 * mat.m13) -
|
||||
mat.m01 * (mat.m10 * mat.m33 - mat.m30 * mat.m13) +
|
||||
mat.m03 * (mat.m10 * mat.m31 - mat.m30 * mat.m11)),
|
||||
-(mat.m00 * (mat.m11 * mat.m32 - mat.m31 * mat.m12) -
|
||||
mat.m01 * (mat.m10 * mat.m32 - mat.m30 * mat.m12) +
|
||||
mat.m02 * (mat.m10 * mat.m31 - mat.m30 * mat.m11)),
|
||||
|
||||
-(mat.m01 * (mat.m12 * mat.m23 - mat.m22 * mat.m13) -
|
||||
mat.m02 * (mat.m11 * mat.m23 - mat.m21 * mat.m13) +
|
||||
mat.m03 * (mat.m11 * mat.m22 - mat.m21 * mat.m12)),
|
||||
(mat.m00 * (mat.m12 * mat.m23 - mat.m22 * mat.m13) -
|
||||
mat.m02 * (mat.m10 * mat.m23 - mat.m20 * mat.m13) +
|
||||
mat.m03 * (mat.m10 * mat.m22 - mat.m20 * mat.m12)),
|
||||
-(mat.m00 * (mat.m11 * mat.m23 - mat.m21 * mat.m13) -
|
||||
mat.m01 * (mat.m10 * mat.m23 - mat.m20 * mat.m13) +
|
||||
mat.m03 * (mat.m10 * mat.m21 - mat.m20 * mat.m11)),
|
||||
(mat.m00 * (mat.m11 * mat.m22 - mat.m21 * mat.m12) -
|
||||
mat.m01 * (mat.m10 * mat.m22 - mat.m20 * mat.m12) +
|
||||
mat.m02 * (mat.m10 * mat.m21 - mat.m20 * mat.m11)),
|
||||
} };
|
||||
}
|
||||
|
||||
|
||||
fn Matrix2x2! Matrix2x2.inverse(Matrix2x2* m) {
|
||||
float det = m.determinant();
|
||||
if (det == 0) return MatrixError.MATRIX_INVERSE_DOESNT_EXIST!;
|
||||
Matrix2x2 adj = m.adjoint();
|
||||
return adj.component_mul(1 / det).transpose();
|
||||
}
|
||||
|
||||
fn Matrix3x3! Matrix3x3.inverse(Matrix3x3* m) {
|
||||
float det = m.determinant();
|
||||
if (det == 0) return MatrixError.MATRIX_INVERSE_DOESNT_EXIST!;
|
||||
Matrix3x3 adj = m.adjoint();
|
||||
return adj.component_mul(1 / det).transpose();
|
||||
}
|
||||
|
||||
fn Matrix4x4! Matrix4x4.inverse(Matrix4x4* m) {
|
||||
float det = m.determinant();
|
||||
if (det == 0) return MatrixError.MATRIX_INVERSE_DOESNT_EXIST!;
|
||||
Matrix4x4 adj = m.adjoint();
|
||||
return adj.component_mul(1 / det).transpose();
|
||||
}
|
||||
|
||||
|
||||
fn Matrix3x3 Matrix3x3.translate(Matrix3x3* m, float[<2>] v) {
|
||||
return m.mul(Matrix3x3 { .m = {
|
||||
1.f, 0.f, v[0],
|
||||
0.f, 1.f, v[1],
|
||||
0.f, 0.f, 1.f,
|
||||
} });
|
||||
}
|
||||
|
||||
fn Matrix4x4 Matrix4x4.translate(Matrix4x4* m, float[<3>] v) {
|
||||
return m.mul(Matrix4x4 { .m = {
|
||||
1.f, 0.f, 0.f, v[0],
|
||||
0.f, 1.f, 0.f, v[1],
|
||||
0.f, 0.f, 1.f, v[2],
|
||||
0.f, 0.f, 0.f, 1.f,
|
||||
} });
|
||||
}
|
||||
|
||||
// r in radians
|
||||
fn Matrix3x3 Matrix3x3.rotate(Matrix3x3* m, float r) {
|
||||
return m.mul(Matrix3x3 { .m = {
|
||||
(float)math::cos(r), (float)-math::sin(r), 0.f,
|
||||
(float)math::sin(r), (float) math::cos(r), 0.f,
|
||||
0.f, 0.f, 1.f,
|
||||
} });
|
||||
}
|
||||
|
||||
// r in radians
|
||||
fn Matrix4x4 Matrix4x4.rotateZ(Matrix4x4* m, float r) {
|
||||
return m.mul(Matrix4x4 { .m = {
|
||||
(float)math::cos(r), (float)-math::sin(r), 0.f, 0.f,
|
||||
(float)math::sin(r), (float) math::cos(r), 0.f, 0.f,
|
||||
0.f, 0.f, 1.f, 0.f,
|
||||
0.f, 0.f, 0.f, 1.f,
|
||||
} });
|
||||
}
|
||||
|
||||
// r in radians
|
||||
fn Matrix4x4 Matrix4x4.rotateY(Matrix4x4* m, float r) {
|
||||
return m.mul(Matrix4x4 { .m = {
|
||||
(float)math::cos(r), 0.f, (float)-math::sin(r), 0.f,
|
||||
0.f, 1.f, 0.f, 0.f,
|
||||
(float)math::sin(r), 0.f, (float) math::cos(r), 0.f,
|
||||
0.f, 0.f, 0.f, 1.f,
|
||||
} });
|
||||
}
|
||||
|
||||
// r in radians
|
||||
fn Matrix4x4 Matrix4x4.rotateX(Matrix4x4* m, float r) {
|
||||
return m.mul(Matrix4x4 { .m = {
|
||||
1.f, 0.f, 0.f, 0.f,
|
||||
0.f, (float)math::cos(r), (float)-math::sin(r), 0.f,
|
||||
0.f, (float)math::sin(r), (float) math::cos(r), 0.f,
|
||||
0.f, 0.f, 0.f, 1.f,
|
||||
} });
|
||||
}
|
||||
|
||||
|
||||
fn Matrix3x3 Matrix3x3.scale(Matrix3x3* m, float[<2>] v) {
|
||||
return m.mul(Matrix3x3 { .m = {
|
||||
v[0], 0.f, 0.f,
|
||||
0.f, v[1], 0.f,
|
||||
0.f, 0.f, 1.f,
|
||||
} });
|
||||
}
|
||||
|
||||
fn Matrix4x4 Matrix4x4.scale(Matrix4x4* m, float[<3>] v) {
|
||||
return m.mul(Matrix4x4 { .m = {
|
||||
v[0], 0.f, 0.f, 0.f,
|
||||
0.f, v[1], 0.f, 0.f,
|
||||
0.f, 0.f, v[2], 0.f,
|
||||
0.f, 0.f, 0.f, 1.f,
|
||||
} });
|
||||
}
|
||||
|
||||
|
||||
fn Matrix4x4 ortho(float left, float right, float top, float bottom, float near, float far) {
|
||||
float width = right - left;
|
||||
float height = top - bottom;
|
||||
float depth = far - near;
|
||||
return Matrix4x4 {
|
||||
.m = {
|
||||
2.f / width, 0.f, 0.f, 0.f,
|
||||
0.f, 2.f / height, 0.f, 0.f,
|
||||
0.f, 0.f, -2.f / depth, 0.f,
|
||||
-(right + left) / width, -(top + bottom) / height, -(far + near) / depth, 1.f,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// fov in radians
|
||||
fn Matrix4x4 perspective(float fov, float aspect_ratio, float near, float far) {
|
||||
float top = ((float)math::sin(fov / 2) / (float)math::cos(fov / 2)) * near;
|
||||
float right = top * aspect_ratio;
|
||||
float depth = far - near;
|
||||
return Matrix4x4 {
|
||||
.m = {
|
||||
1.f / right, 0.f, 0.f, 0.f,
|
||||
0.f, 1.f / top, 0.f, 0.f,
|
||||
0.f, 0.f, -2.f / depth, 0.f,
|
||||
0.f, 0.f, -(far + near) / depth, 1.f,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
47
lib/std/math.simple_random.c3
Normal file
47
lib/std/math.simple_random.c3
Normal file
@@ -0,0 +1,47 @@
|
||||
module math;
|
||||
|
||||
struct SimpleRandom
|
||||
{
|
||||
long seed;
|
||||
}
|
||||
|
||||
private const long SIMPLE_RANDOM_MULTIPLIER = 0x5DEECE66Di64;
|
||||
private const long SIMPLE_RANDOM_ADDEND = 0xB;
|
||||
private const long SIMPLE_RANDOM_MASK = (1i64 << 48) - 1;
|
||||
|
||||
private fn long simple_random_initial_scramble(long seed)
|
||||
{
|
||||
return (seed ^ SIMPLE_RANDOM_MULTIPLIER) & SIMPLE_RANDOM_MASK;
|
||||
}
|
||||
|
||||
private fn int SimpleRandom.next(SimpleRandom* r, int bits)
|
||||
{
|
||||
long nextseed = (r.seed * SIMPLE_RANDOM_MULTIPLIER + SIMPLE_RANDOM_ADDEND) & SIMPLE_RANDOM_MASK;
|
||||
r.seed = nextseed;
|
||||
return (int)nextseed >> (48 - bits);
|
||||
}
|
||||
|
||||
fn void SimpleRandom.set_seed(SimpleRandom* r, long seed)
|
||||
{
|
||||
r.seed = simple_random_initial_scramble(seed);
|
||||
}
|
||||
|
||||
fn int SimpleRandom.next_int(SimpleRandom* r)
|
||||
{
|
||||
return r.next(32) @inline;
|
||||
}
|
||||
|
||||
fn bool SimpleRandom.next_bool(SimpleRandom* r)
|
||||
{
|
||||
return r.next(1) != 0;
|
||||
}
|
||||
|
||||
fn float SimpleRandom.next_float(SimpleRandom* r)
|
||||
{
|
||||
return r.next(24) / (float)(1 << 24);
|
||||
}
|
||||
|
||||
fn double SimpleRandom.next_double(SimpleRandom* r)
|
||||
{
|
||||
return (((long)(r.next(26)) << 27) + r.next(27)) * 0x1.0p-53;
|
||||
}
|
||||
105
lib/std/priorityqueue.c3
Normal file
105
lib/std/priorityqueue.c3
Normal file
@@ -0,0 +1,105 @@
|
||||
// priorityqueue.c3
|
||||
// A priority queue using a classic binary heap for C3.
|
||||
//
|
||||
// Copyright (c) 2022 David Kopec
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
module std::priorityqueue<Type>;
|
||||
import std::array::list;
|
||||
|
||||
define Heap = List<Type>;
|
||||
|
||||
struct PriorityQueue
|
||||
{
|
||||
Heap heap;
|
||||
bool max; // true if max-heap, false if min-heap
|
||||
}
|
||||
|
||||
fn void PriorityQueue.push(PriorityQueue* pq, Type element)
|
||||
{
|
||||
pq.heap.push(element);
|
||||
usize i = pq.heap.len() - 1;
|
||||
while (i > 0)
|
||||
{
|
||||
usize parent = (i - 1) / 2;
|
||||
if ((pq.max && greater(pq.heap.get(i), pq.heap.get(parent))) || (!pq.max && less(pq.heap.get(i), pq.heap.get(parent))))
|
||||
{
|
||||
pq.heap.swap(i, parent);
|
||||
i = parent;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @require pq != null
|
||||
*/
|
||||
fn Type! PriorityQueue.pop(PriorityQueue* pq)
|
||||
{
|
||||
usize i = 0;
|
||||
usize len = pq.heap.len() @inline;
|
||||
if (!len) return IteratorResult.NO_MORE_ELEMENT!;
|
||||
usize newCount = len - 1;
|
||||
pq.heap.swap(0, newCount);
|
||||
while ((2 * i + 1) < newCount)
|
||||
{
|
||||
usize j = 2 * i + 1;
|
||||
if (((j + 1) < newCount) &&
|
||||
((pq.max && greater(pq.heap.get(j + 1), pq.heap[j]))
|
||||
|| (!pq.max && less(pq.heap.get(j + 1), pq.heap.get(j)))))
|
||||
{
|
||||
j++;
|
||||
}
|
||||
if ((pq.max && less(pq.heap.get(i), pq.heap.get(j))) || (!pq.max && greater(pq.heap.get(i), pq.heap.get(j))))
|
||||
{
|
||||
pq.heap.swap(i, j);
|
||||
i = j;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return pq.heap.pop();
|
||||
}
|
||||
|
||||
/**
|
||||
* @require pq != null
|
||||
*/
|
||||
fn Type! PriorityQueue.peek(PriorityQueue* pq)
|
||||
{
|
||||
if (!pq.len()) return IteratorResult.NO_MORE_ELEMENT!;
|
||||
return pq.heap.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @require pq != null
|
||||
*/
|
||||
fn void PriorityQueue.free(PriorityQueue* pq)
|
||||
{
|
||||
pq.heap.free();
|
||||
}
|
||||
|
||||
/**
|
||||
* @require pq != null
|
||||
*/
|
||||
fn usize PriorityQueue.len(PriorityQueue* pq) @operator(len)
|
||||
{
|
||||
return pq.heap.len();
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
// Copyright (c) 2021 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::runtime;
|
||||
|
||||
struct VirtualAny
|
||||
@@ -23,10 +26,5 @@ struct VarArrayHeader
|
||||
usize size;
|
||||
usize capacity;
|
||||
void *allocator;
|
||||
|
||||
}
|
||||
|
||||
struct VarArrayContainer
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,377 +0,0 @@
|
||||
|
||||
name = C3
|
||||
file_extensions [] = c3;
|
||||
|
||||
################################################################
|
||||
## Constants
|
||||
################################################################
|
||||
|
||||
__CONSTANT \= (_*[A-Z][A-Za-z0-9_]*)
|
||||
__IDENT \= _*[a-z][A-Za-z0-9_]*
|
||||
__TYPE \= _*[A-Z][A-Za-z0-9_]*[a-z][A-Za-z0-9_]*
|
||||
__SCOPE \= ([a-z]+::)*
|
||||
__USERTYPE \= _*[A-Z][A-Za-z0-9_]*[a-z][A-Za-z0-9_]*
|
||||
__BUILTIN_TYPE \= void|float|half|double|quad|long|ulong|int|short|char|uint|ushort|ichar|usize|isize|iptr|uptr|iptrdiff|uptrdiff
|
||||
################################################################
|
||||
## Styles
|
||||
################################################################
|
||||
|
||||
styles [] {
|
||||
|
||||
.comment : style {
|
||||
color = #5F5A60
|
||||
italic = true
|
||||
ace_scope = comment
|
||||
textmate_scope = comment
|
||||
pygments_scope = Comment
|
||||
}
|
||||
|
||||
.type : style {
|
||||
color = #AE81FF
|
||||
pygments_scope = Name.Class
|
||||
textmate_scope = entity.name.type
|
||||
}
|
||||
|
||||
.string : style {
|
||||
color = #E6DB74
|
||||
pygments_scope = String.Double
|
||||
textmate_scope = string.quoted.double
|
||||
}
|
||||
|
||||
.escaped_text : style {
|
||||
color = #AE81FF
|
||||
pygments_scope = String.Escape
|
||||
}
|
||||
.function_decl : style {
|
||||
color = #A6E22E
|
||||
pygments_scope = Name.Entity
|
||||
}
|
||||
|
||||
.declare : style {
|
||||
color = #66D9EF
|
||||
pygments_scope = Keyword.Declaration
|
||||
}
|
||||
|
||||
|
||||
.function_call : style {
|
||||
color = #66D9EF
|
||||
pygments_scope = Name.Function
|
||||
}
|
||||
|
||||
.type_builtin : style {
|
||||
color = #f92672
|
||||
ace_scope = keyword
|
||||
textmate_scope = keyword
|
||||
pygments_scope = Keyword.Type
|
||||
}
|
||||
|
||||
.keyword_constant : style
|
||||
{
|
||||
color = #f92672
|
||||
ace_scope = keyword
|
||||
textmate_scope = keyword
|
||||
pygments_scope = Keyword.Constant
|
||||
}
|
||||
|
||||
.keyword : style {
|
||||
color = #f92672
|
||||
ace_scope = keyword
|
||||
textmate_scope = keyword
|
||||
pygments_scope = Keyword
|
||||
}
|
||||
|
||||
.constant : style {
|
||||
color = #AE81FF
|
||||
textmate_scope = constant
|
||||
pygments_scope = Name.Constant
|
||||
}
|
||||
|
||||
|
||||
|
||||
.numeric : style {
|
||||
color = #AE81FF
|
||||
ace_scope = constant.numeric
|
||||
textmate_scope = constant.numeric
|
||||
pygments_scope = Number
|
||||
}
|
||||
|
||||
.punctuation : style {
|
||||
color = #FD971F
|
||||
ace_scope = punctuation
|
||||
textmate_scope = punctuation
|
||||
pygments_scope = Punctuation
|
||||
}
|
||||
|
||||
.compile_time : style {
|
||||
color = #908B25
|
||||
pygments_scope = Keyword.Pseudo
|
||||
}
|
||||
|
||||
.variable : style {
|
||||
color = #f8f8f2
|
||||
background_color = #272822
|
||||
pygments_scope = Name
|
||||
}
|
||||
|
||||
|
||||
.text : style {
|
||||
color = #f8f8f2
|
||||
background_color = #272822
|
||||
ace_scope = text
|
||||
textmate_scope = text
|
||||
pygments_scope = String
|
||||
}
|
||||
|
||||
.illegal : style {
|
||||
color = white
|
||||
background_color = red
|
||||
ace_scope = invalid
|
||||
textmate_scope = invalid
|
||||
pygments_scope = Generic.Error
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#################################################
|
||||
## Parse contexts
|
||||
#################################################
|
||||
|
||||
contexts [] {
|
||||
|
||||
top_level : context {
|
||||
: include "parens";
|
||||
: include "comment";
|
||||
: include "constants";
|
||||
: include "ct_keywords";
|
||||
: include "decls";
|
||||
: include "path";
|
||||
: include "type";
|
||||
: include "keywords";
|
||||
: include "storage";
|
||||
: include "call";
|
||||
: include "identifier";
|
||||
: include "kw_operators";
|
||||
: include "operators";
|
||||
: pattern {
|
||||
regex \= ([\.\;])
|
||||
styles [] = .punctuation;
|
||||
}
|
||||
: pattern {
|
||||
regex \= ([\@])
|
||||
styles [] = .keyword;
|
||||
}
|
||||
}
|
||||
|
||||
builtin_constants : context {
|
||||
: pattern {
|
||||
regex \= (true|false|null)
|
||||
styles [] = .keyword_constant;
|
||||
}
|
||||
}
|
||||
constants : context {
|
||||
: pattern {
|
||||
regex \= ($${__CONSTANT})
|
||||
styles [] = .constant;
|
||||
}
|
||||
}
|
||||
type : context {
|
||||
: pattern {
|
||||
regex \= ($${__SCOPE})?($${__USERTYPE})
|
||||
styles [] = .type;
|
||||
}
|
||||
: pattern {
|
||||
regex \= ($${__BUILTIN_TYPE})
|
||||
styles [] = .type_builtin;
|
||||
}
|
||||
}
|
||||
path : context {
|
||||
: pattern {
|
||||
regex \= ([a-z][a-z_0-9]*)(\s*)(::)
|
||||
styles [] = .text, .text, .keyword;
|
||||
}
|
||||
}
|
||||
|
||||
call : context {
|
||||
: pattern {
|
||||
regex \= ($${__IDENT}\s*)(\()
|
||||
styles [] = .function_call, .text;
|
||||
}
|
||||
}
|
||||
|
||||
keywords : context {
|
||||
: pattern {
|
||||
regex \= (import|for|foreach|return|else|if|default|switch|while|do|module|assert|distinct|break|nextcase|case|continue|defer)
|
||||
styles [] = .keyword;
|
||||
}
|
||||
}
|
||||
ct_keywords : context {
|
||||
: pattern {
|
||||
regex \= (\$[a-zA-Z][a-z_A-Z0-9]*)
|
||||
styles [] = .compile_time;
|
||||
}
|
||||
}
|
||||
storage : context {
|
||||
: pattern {
|
||||
regex \= (const|extern|static|private)
|
||||
styles [] = .keyword;
|
||||
}
|
||||
}
|
||||
identifier : context {
|
||||
: pattern {
|
||||
regex \= ($${__IDENT})
|
||||
styles [] = .variable;
|
||||
}
|
||||
}
|
||||
|
||||
operators : context {
|
||||
: pattern {
|
||||
regex \= ([\*\=\/\%\<\>\,\:\^\&\!\|\~])
|
||||
styles [] = .text;
|
||||
}
|
||||
}
|
||||
kw_operators : context {
|
||||
: pattern {
|
||||
regex \= ([\+\-])
|
||||
styles [] = .text;
|
||||
}
|
||||
}
|
||||
|
||||
parens : context {
|
||||
: pattern {
|
||||
regex \= ([\[\]\(\)\{\}])
|
||||
styles [] = .text;
|
||||
}
|
||||
}
|
||||
|
||||
decls : context
|
||||
{
|
||||
: pattern {
|
||||
regex \= (func\s+)($${__SCOPE})?($${__USERTYPE})?($${__BUILTIN_TYPE})?(\s+$${__IDENT})
|
||||
styles [] = .declare, .text, .text, .type, .type_builtin, .function_decl;
|
||||
}
|
||||
: pattern {
|
||||
regex \= (func\s+)($${__SCOPE})?($${__USERTYPE})?($${__BUILTIN_TYPE})?(\s+$${__IDENT})
|
||||
styles [] = .declare, .text, .text, .type, .type_builtin, .function_decl;
|
||||
}
|
||||
: pattern {
|
||||
regex \= (enum|struct|errtype|union)(\s+)($${__USERTYPE})
|
||||
styles[] = .declare, .text, .function_decl;
|
||||
}
|
||||
: pattern {
|
||||
regex \= (struct|union|define)
|
||||
styles[] = .declare;
|
||||
}
|
||||
}
|
||||
|
||||
nested_comment : context {
|
||||
: inline_push {
|
||||
regex \= (/\*)
|
||||
styles [] = .comment;
|
||||
: pop {
|
||||
regex \= (.*\*/)
|
||||
styles [] = .comment;
|
||||
}
|
||||
: include "nested_comment";
|
||||
}
|
||||
}
|
||||
|
||||
comment : context {
|
||||
: pattern {
|
||||
regex \= (//.*)
|
||||
styles [] = .comment;
|
||||
}
|
||||
: include "nested_comment";
|
||||
}
|
||||
|
||||
|
||||
main : context {
|
||||
|
||||
|
||||
: include "top_level";
|
||||
: pattern {
|
||||
regex \= (define|extern|if|module|import|func|struct|while|do|return|union|errtype)
|
||||
styles [] = .keyword;
|
||||
}
|
||||
|
||||
: include "numeric" ;
|
||||
|
||||
: inline_push {
|
||||
regex \= (\{)
|
||||
styles [] = .punctuation;
|
||||
: pop {
|
||||
regex \= (\})
|
||||
styles [] = .punctuation;
|
||||
}
|
||||
: include "main" ;
|
||||
}
|
||||
|
||||
: pattern {
|
||||
regex \= (;)
|
||||
styles [] = .punctuation;
|
||||
}
|
||||
|
||||
: inline_push {
|
||||
regex \= (\")
|
||||
styles [] = .punctuation;
|
||||
: pop {
|
||||
regex \= (\")
|
||||
styles [] = .punctuation;
|
||||
}
|
||||
: pattern {
|
||||
regex \= (\\(?:\\|"))
|
||||
styles [] = .escaped_text;
|
||||
}
|
||||
: pattern {
|
||||
regex \= ([^"\\]+)
|
||||
styles [] = .string;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
: include "multi_line_comment" ;
|
||||
|
||||
: pattern {
|
||||
regex \= (//.*)
|
||||
styles [] = .comment;
|
||||
}
|
||||
|
||||
: pattern {
|
||||
regex \= ([^\s])
|
||||
styles [] = .illegal;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#################################################
|
||||
## End of Contexts
|
||||
#################################################
|
||||
|
||||
###########################################
|
||||
## Numeric Context
|
||||
###########################################
|
||||
|
||||
numeric : context {
|
||||
: pattern {
|
||||
regex \= (\b\d+)
|
||||
styles [] = .numeric;
|
||||
}
|
||||
}
|
||||
|
||||
###########################################
|
||||
## Multi Line Comment Context
|
||||
###########################################
|
||||
|
||||
multi_line_comment : context {
|
||||
description = multiline
|
||||
: inline_push {
|
||||
regex \= (/\*)
|
||||
styles [] = .comment;
|
||||
default_style = .comment
|
||||
: pop {
|
||||
regex \= (\*/)
|
||||
styles [] = .comment;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
|
||||
This .nanorc file adds syntax highlighting support for C3 to nano.
|
||||
|
||||
It can either be installed under `/usr/share/nano` or included into `~/.nanorc`.
|
||||
@@ -1,43 +0,0 @@
|
||||
## C3 syntax highlighting support for nano
|
||||
## https://github.com/c3lang/c3c
|
||||
|
||||
syntax c3 "\.(c3|c3t)$"
|
||||
comment "//"
|
||||
|
||||
# Default color
|
||||
color white ".*"
|
||||
|
||||
# Constants
|
||||
#color brightred "\<[A-Z_][0-9A-Z_]+\>"
|
||||
|
||||
# Function names
|
||||
color magenta "\<[A-Za-z_]+\>\("
|
||||
color normal "\(|\)"
|
||||
|
||||
# Types
|
||||
color green "\<(virtual|anyerr|void|bool|quad|double|float|long|ulong|int|uint|short|ushort|ichar|char|isize|usize|iptr|uptr|iptrdiff|uptrdiff|half)\>"
|
||||
|
||||
# Keywords
|
||||
color yellow "\<(alias|as|asm|assert|attribute|break|case|catch|const|continue|default|defer|define|do|else|enum|extern|errtype|false|for|foreach|func|generic|if|import|interface|macro|module|nextcase|null|private|return|static|struct|switch|true|try|typeid|typeof|union|while|var|volatile|yield)\>"
|
||||
|
||||
# $ Statements
|
||||
color brightyellow "\$\<(assert|case|default|elif|else|endif|endswitch|for|if|switch|unreachable)\>"
|
||||
|
||||
# @ Attributes
|
||||
color brightred "@\<[A-Za-z_]+\>"
|
||||
|
||||
# Strings
|
||||
color brightblack "\"[^"]*\""
|
||||
|
||||
# Everything down from here should stay in the current order
|
||||
|
||||
# Comments
|
||||
color cyan "//.*"
|
||||
color cyan start="/\+" end="\+/"
|
||||
color cyan start="/\*" end="\*/"
|
||||
|
||||
# Reminders
|
||||
color brightwhite,red "\<(FIXME|TODO|XXX)\>"
|
||||
|
||||
# Trailing whitespace
|
||||
color ,green "[[:space:]]+$"
|
||||
@@ -1,41 +1,40 @@
|
||||
module base64;
|
||||
// Based on the C2 version.
|
||||
|
||||
error InvalidCharacter
|
||||
{
|
||||
int index;
|
||||
char c;
|
||||
}
|
||||
|
||||
fault DecodingError
|
||||
{
|
||||
INVALID_CHARACTER
|
||||
}
|
||||
const char[64] LUT_ENC = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
|
||||
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
|
||||
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
|
||||
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
|
||||
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
||||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
|
||||
'w', 'x', 'y', 'z', '0', '1', '2', '3',
|
||||
'4', '5', '6', '7', '8', '9', '+', '/',
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
|
||||
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
|
||||
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
|
||||
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
|
||||
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
||||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
|
||||
'w', 'x', 'y', 'z', '0', '1', '2', '3',
|
||||
'4', '5', '6', '7', '8', '9', '+', '/',
|
||||
};
|
||||
|
||||
const char ERR = 0xFF;
|
||||
|
||||
const char[256] LUT_DEC =
|
||||
{
|
||||
[0..255] = ERR,
|
||||
['A'] = 0, ['B'] = 1, ['C'] = 2, ['D'] = 3, ['E'] = 4,
|
||||
['F'] = 5, ['G'] = 6, ['H'] = 7, ['I'] = 8, ['J'] = 9,
|
||||
['K'] = 10, ['L'] = 11, ['M'] = 12, ['N'] = 13, ['O'] = 14,
|
||||
['P'] = 15, ['Q'] = 16, ['R'] = 17, ['S'] = 18, ['T'] = 19,
|
||||
['U'] = 20, ['V'] = 21, ['W'] = 22, ['X'] = 23, ['Y'] = 24,
|
||||
['Z'] = 25, ['a'] = 26, ['b'] = 27, ['c'] = 28, ['d'] = 29,
|
||||
['e'] = 30, ['f'] = 31, ['g'] = 32, ['h'] = 33, ['i'] = 34,
|
||||
['j'] = 35, ['k'] = 36, ['l'] = 37, ['m'] = 38, ['n'] = 39,
|
||||
['o'] = 40, ['p'] = 41, ['q'] = 42, ['r'] = 43, ['s'] = 44,
|
||||
['t'] = 45, ['u'] = 46, ['v'] = 47, ['w'] = 48, ['x'] = 49,
|
||||
['y'] = 50, ['z'] = 51, ['0'] = 52, ['1'] = 53, ['2'] = 54,
|
||||
['3'] = 55, ['4'] = 56, ['5'] = 57, ['6'] = 58, ['7'] = 59,
|
||||
['8'] = 60, ['9'] = 61, ['+'] = 62, ['/'] = 63
|
||||
[0..255] = ERR,
|
||||
['A'] = 0, ['B'] = 1, ['C'] = 2, ['D'] = 3, ['E'] = 4,
|
||||
['F'] = 5, ['G'] = 6, ['H'] = 7, ['I'] = 8, ['J'] = 9,
|
||||
['K'] = 10, ['L'] = 11, ['M'] = 12, ['N'] = 13, ['O'] = 14,
|
||||
['P'] = 15, ['Q'] = 16, ['R'] = 17, ['S'] = 18, ['T'] = 19,
|
||||
['U'] = 20, ['V'] = 21, ['W'] = 22, ['X'] = 23, ['Y'] = 24,
|
||||
['Z'] = 25, ['a'] = 26, ['b'] = 27, ['c'] = 28, ['d'] = 29,
|
||||
['e'] = 30, ['f'] = 31, ['g'] = 32, ['h'] = 33, ['i'] = 34,
|
||||
['j'] = 35, ['k'] = 36, ['l'] = 37, ['m'] = 38, ['n'] = 39,
|
||||
['o'] = 40, ['p'] = 41, ['q'] = 42, ['r'] = 43, ['s'] = 44,
|
||||
['t'] = 45, ['u'] = 46, ['v'] = 47, ['w'] = 48, ['x'] = 49,
|
||||
['y'] = 50, ['z'] = 51, ['0'] = 52, ['1'] = 53, ['2'] = 54,
|
||||
['3'] = 55, ['4'] = 56, ['5'] = 57, ['6'] = 58, ['7'] = 59,
|
||||
['8'] = 60, ['9'] = 61, ['+'] = 62, ['/'] = 63
|
||||
};
|
||||
|
||||
|
||||
@@ -43,86 +42,93 @@ const char PAD = '=';
|
||||
const char FIRST = '+';
|
||||
const char LAST = 'z';
|
||||
|
||||
public func void encode(char[] in, char *out)
|
||||
fn void encode(char[] in, char *out)
|
||||
{
|
||||
int j = 0;
|
||||
char c = LUT_ENC[1];
|
||||
for (int i = 0; i < in.len(); i++)
|
||||
char c = LUT_ENC[1];
|
||||
for (int i = 0; i < in.len; i++)
|
||||
{
|
||||
switch (i % 3)
|
||||
{
|
||||
case 0:
|
||||
out[j++] = LUT_ENC[(in[i] >> 2) & 0x3F];
|
||||
case 1:
|
||||
out[j++] = LUT_ENC[(in[i - 1] & 0x3) << 4 + ((in[i] >> 4) & 0xF)];
|
||||
case 2:
|
||||
out[j++] = LUT_ENC[(in[i - 1] & 0xF) << 2 + ((in[i] >> 6) & 0x3)];
|
||||
out[j++] = LUT_ENC[in[i] & 0x3F];
|
||||
}
|
||||
switch (i % 3)
|
||||
{
|
||||
case 0:
|
||||
out[j++] = LUT_ENC[(in[i] >> 2) & 0x3F];
|
||||
case 1:
|
||||
out[j++] = LUT_ENC[(in[i - 1] & 0x3) << 4 + ((in[i] >> 4) & 0xF)];
|
||||
case 2:
|
||||
out[j++] = LUT_ENC[(in[i - 1] & 0xF) << 2 + ((in[i] >> 6) & 0x3)];
|
||||
out[j++] = LUT_ENC[in[i] & 0x3F];
|
||||
}
|
||||
}
|
||||
|
||||
// move back
|
||||
usize last = in.len() - 1;
|
||||
// check the last and add padding
|
||||
switch (last % 3)
|
||||
{
|
||||
case 0:
|
||||
out[j++] = LUT_ENC[(in[last] & 0x3) << 4];
|
||||
out[j++] = PAD;
|
||||
out[j++] = PAD;
|
||||
case 1:
|
||||
out[j++] = LUT_ENC[(in[last] & 0xF) << 2];
|
||||
out[j++] = PAD;
|
||||
}
|
||||
// move back
|
||||
usize last = in.len - 1;
|
||||
// check the last and add padding
|
||||
switch (last % 3)
|
||||
{
|
||||
case 0:
|
||||
out[j++] = LUT_ENC[(in[last] & 0x3) << 4];
|
||||
out[j++] = PAD;
|
||||
out[j++] = PAD;
|
||||
case 1:
|
||||
out[j++] = LUT_ENC[(in[last] & 0xF) << 2];
|
||||
out[j++] = PAD;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public func int! decode(char[] in, char* out)
|
||||
fn int! decode(char[] in, char* out, int* invalid_char_index = null)
|
||||
{
|
||||
int j = 0;
|
||||
int j = 0;
|
||||
|
||||
for (int i = 0; i < in.len(); i++)
|
||||
{
|
||||
char value = in[i];
|
||||
if (value == PAD) return j;
|
||||
for (int i = 0; i < in.len; i++)
|
||||
{
|
||||
char value = in[i];
|
||||
if (value == PAD) return j;
|
||||
|
||||
char c = LUT_DEC[in[i]];
|
||||
if (c == ERR) return InvalidCharacter({i, value})!;
|
||||
char c = LUT_DEC[in[i]];
|
||||
if (c == ERR)
|
||||
{
|
||||
if (invalid_char_index) *invalid_char_index = i;
|
||||
return DecodingError.INVALID_CHARACTER!;
|
||||
}
|
||||
|
||||
switch (i % 4)
|
||||
{
|
||||
case 0:
|
||||
out[j] = c << 2;
|
||||
case 1:
|
||||
out[j++] += c >> 4 & 0x3;
|
||||
// if not last char with padding
|
||||
if (i < (in.len() - 3) || in[(long)(in.len()) - 2] != PAD)
|
||||
{
|
||||
out[j] = (c & 0xF) << 4;
|
||||
}
|
||||
case 2:
|
||||
out[j++] += c >> 2 & 0xF;
|
||||
if (i < (in.len() - 2) || in[(long)(in.len()) - 1] != PAD)
|
||||
{
|
||||
out[j] = (c & 0x3) << 6;
|
||||
}
|
||||
case 3:
|
||||
out[j++] += c;
|
||||
}
|
||||
|
||||
}
|
||||
return j;
|
||||
switch (i % 4)
|
||||
{
|
||||
case 0:
|
||||
out[j] = c << 2;
|
||||
case 1:
|
||||
out[j++] += c >> 4 & 0x3;
|
||||
// if not last char with padding
|
||||
if (i < (in.len - 3) || in[(long)(in.len) - 2] != PAD)
|
||||
{
|
||||
out[j] = (c & 0xF) << 4;
|
||||
}
|
||||
case 2:
|
||||
out[j++] += c >> 2 & 0xF;
|
||||
if (i < (in.len - 2) || in[(long)(in.len) - 1] != PAD)
|
||||
{
|
||||
out[j] = (c & 0x3) << 6;
|
||||
}
|
||||
case 3:
|
||||
out[j++] += c;
|
||||
}
|
||||
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
extern func void printf(char *fmt, ...);
|
||||
extern fn void printf(char *fmt, ...);
|
||||
|
||||
public func void main()
|
||||
fn void main()
|
||||
{
|
||||
char *helloworld = "Hello World\n";
|
||||
char[1000] buffer;
|
||||
encode(helloworld[0..12], &buffer);
|
||||
printf("Result: %s\n", &buffer);
|
||||
char *to_decode = "aGVsbG8gd29ybGRcMA==";
|
||||
decode(to_decode[0..19], &buffer);
|
||||
printf("Result: %s\n", &buffer);
|
||||
char *helloworld = "Hello World\n";
|
||||
char[1000] buffer;
|
||||
encode(helloworld[0..12], &buffer);
|
||||
printf("Result: %s\n", &buffer);
|
||||
char *to_decode = "aGVsbG8gd29ybGRcMA==";
|
||||
char[*] result = b64"aGVsbG8gd29ybGRcMA==";
|
||||
decode(to_decode[0..19], &buffer);
|
||||
printf("Result: %s\n", &buffer);
|
||||
printf("Result direct: %.*s\n", 13, &result);
|
||||
}
|
||||
25
resources/examples/binarydigits.c3
Normal file
25
resources/examples/binarydigits.c3
Normal file
@@ -0,0 +1,25 @@
|
||||
module binarydigits;
|
||||
import std::math;
|
||||
import std::io;
|
||||
fn void main()
|
||||
{
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
String s = bin(i);
|
||||
defer s.destroy();
|
||||
io::printf("%s\n", s);
|
||||
}
|
||||
}
|
||||
|
||||
fn String bin(int x)
|
||||
{
|
||||
int bits = 1 + (int)(x == 0 ? 0 : math::log10((double)(x)) / math::log10(2));
|
||||
String str;
|
||||
str.append_repeat('0', bits);
|
||||
for (int i = 0; i < bits; i++)
|
||||
{
|
||||
str.set((usize)(bits - i - 1), x & 1 ? '1' : '0');
|
||||
x >>= 1;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
141
resources/examples/contextfree/boolerr.c3
Normal file
141
resources/examples/contextfree/boolerr.c3
Normal file
@@ -0,0 +1,141 @@
|
||||
module test;
|
||||
import libc;
|
||||
import std::io;
|
||||
|
||||
struct Doc { Head *head; }
|
||||
struct Head { String* title; }
|
||||
|
||||
struct Summary
|
||||
{
|
||||
String* title;
|
||||
bool ok;
|
||||
}
|
||||
|
||||
private struct StringData
|
||||
{
|
||||
Allocator allocator;
|
||||
usize len;
|
||||
usize capacity;
|
||||
char[*] chars;
|
||||
}
|
||||
|
||||
fn void Summary.print(Summary *s, File out)
|
||||
{
|
||||
char[] title = s.title ? s.title.str() : "missing";
|
||||
out.printf("Summary({ .title = %s, .ok = %s})", title, s.ok);
|
||||
}
|
||||
|
||||
fn bool contains(char[] haystack, char[] needle)
|
||||
{
|
||||
usize len = haystack.len;
|
||||
usize needle_len = needle.len;
|
||||
if (len < needle_len) return false;
|
||||
if (!needle_len) return true;
|
||||
len -= needle_len - 1;
|
||||
for (usize i = 0; i < len; i++)
|
||||
{
|
||||
if (libc::memcmp(&haystack[i], needle.ptr, needle_len) == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
macro @dupe(value)
|
||||
{
|
||||
$typeof(&value) temp = mem::alloc_checked($sizeof(value))?;
|
||||
*temp = value;
|
||||
return temp;
|
||||
}
|
||||
|
||||
fault ReadError
|
||||
{
|
||||
BAD_READ,
|
||||
}
|
||||
|
||||
fn Doc! readDoc(char[] url)
|
||||
{
|
||||
if (contains(url, "fail")) return ReadError.BAD_READ!;
|
||||
if (contains(url, "head-missing")) return { .head = null };
|
||||
if (contains(url, "title-missing")) return { @dupe(Head { .title = null }) };
|
||||
if (contains(url, "title-empty")) return { @dupe(Head { .title = @dupe((String)null) }) };
|
||||
String str;
|
||||
str.printf("Title of %s", url);
|
||||
return { @dupe(Head { .title = @dupe(str) }) };
|
||||
}
|
||||
|
||||
fn Summary buildSummary(Doc doc)
|
||||
{
|
||||
return Summary {
|
||||
.title = doc.head ? doc.head.title : null,
|
||||
.ok = true,
|
||||
};
|
||||
}
|
||||
|
||||
fn Summary readAndBuildSummary(char[] url)
|
||||
{
|
||||
return buildSummary(readDoc(url)) ?? Summary { .title = null, .ok = false };
|
||||
/*
|
||||
// or
|
||||
Summary summary = buildSummary(readDoc(url));
|
||||
if (catch summary) return Summary { .title = null, .ok = false };
|
||||
return summary;
|
||||
// or
|
||||
Summary summary = buildSummary(readDoc(url));
|
||||
if (try summary) return summary;
|
||||
return Summary { .title = null, .ok = false };
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
fault TitleResult
|
||||
{
|
||||
TITLE_MISSING
|
||||
}
|
||||
|
||||
fn bool! isTitleNonEmpty(Doc doc)
|
||||
{
|
||||
if (!doc.head) return TitleResult.TITLE_MISSING!;
|
||||
String* head = doc.head.title;
|
||||
if (!head) return TitleResult.TITLE_MISSING!;
|
||||
return head.len() > 0;
|
||||
}
|
||||
|
||||
|
||||
fn bool! readWhetherTitleNonEmpty(char[] url)
|
||||
{
|
||||
return isTitleNonEmpty(readDoc(url));
|
||||
}
|
||||
|
||||
fn char[] bool_to_string(bool b)
|
||||
{
|
||||
return b ? "true" : "false";
|
||||
}
|
||||
|
||||
|
||||
fn void main()
|
||||
{
|
||||
const char[][] URLS = { "good", "title-empty", "title-missing", "head-missing", "fail" };
|
||||
DynamicArenaAllocator dynamic_arena;
|
||||
dynamic_arena.init(1024);
|
||||
foreach (char[] url : URLS)
|
||||
{
|
||||
mem::@with_allocator(&dynamic_arena)
|
||||
{
|
||||
io::printf(`Checking "https://%s/":` "\n", url);
|
||||
Summary summary = readAndBuildSummary(url);
|
||||
io::printf(" Summary: ");
|
||||
summary.print(io::stdout());
|
||||
io::println("");
|
||||
char[] title_sure = summary.title ? summary.title.str() : "";
|
||||
io::printf(" Title: %s\n", title_sure);
|
||||
bool! has_title = readWhetherTitleNonEmpty(url);
|
||||
// This looks a bit less than elegant, but as you see it's mostly due to having to
|
||||
// use printf here.
|
||||
io::printf(" Has title: %s vs %s\n", bool_to_string(has_title) ?? catch(has_title).nameof, has_title ?? false);
|
||||
};
|
||||
dynamic_arena.reset();
|
||||
}
|
||||
dynamic_arena.destroy();
|
||||
}
|
||||
28
resources/examples/contextfree/dynscope.c3
Normal file
28
resources/examples/contextfree/dynscope.c3
Normal file
@@ -0,0 +1,28 @@
|
||||
module foo;
|
||||
import std::io;
|
||||
|
||||
tlocal char[] context_user = "safe";
|
||||
|
||||
macro long perform(task)
|
||||
{
|
||||
io::printf("%s: %s\n", context_user, task);
|
||||
return task.len;
|
||||
}
|
||||
|
||||
macro @with_mode(char[] user, #action, arg)
|
||||
{
|
||||
@scope(context_user)
|
||||
{
|
||||
context_user = user;
|
||||
return #action(arg);
|
||||
};
|
||||
}
|
||||
|
||||
fn void main()
|
||||
{
|
||||
long result = perform("something!");
|
||||
result += @with_mode("faster", perform, "reliable");
|
||||
result += perform(char[][] {"again", "more"});
|
||||
result += perform(int[<2>] { 56, 99 });
|
||||
io::printf("Result: %d\n", result);
|
||||
}
|
||||
93
resources/examples/contextfree/guess_number.c3
Normal file
93
resources/examples/contextfree/guess_number.c3
Normal file
@@ -0,0 +1,93 @@
|
||||
module guess_number;
|
||||
import std::io;
|
||||
import libc;
|
||||
|
||||
extern fn isize getline(char** linep, usize* linecapp, CFile stream);
|
||||
|
||||
struct Game
|
||||
{
|
||||
int answer;
|
||||
bool done;
|
||||
int guesses;
|
||||
int high;
|
||||
}
|
||||
|
||||
fault InputResult
|
||||
{
|
||||
NOT_AN_INT,
|
||||
FAILED_TO_READ,
|
||||
}
|
||||
|
||||
int err_count = 0;
|
||||
|
||||
fn int! askGuess(int high)
|
||||
{
|
||||
libc::printf("Guess a number between 1 and %d: ", high);
|
||||
char[] text = readLine()?;
|
||||
char* end = null;
|
||||
int value = (int)libc::strtol(text.ptr, &end, 10);
|
||||
if (end && end[0] >= ' ') return InputResult.NOT_AN_INT!;
|
||||
return value;
|
||||
}
|
||||
|
||||
fn char[]! readLine()
|
||||
{
|
||||
char* chars = mem::talloc(1024)?;
|
||||
isize loaded = getline(&chars, &&(usize)1023, libc::stdin());
|
||||
if (loaded < 0) return InputResult.FAILED_TO_READ!;
|
||||
chars[loaded] = 0;
|
||||
return chars[0..(loaded - 1)];
|
||||
}
|
||||
|
||||
fn int! askGuessMulti(int high)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
int! result = askGuess(high);
|
||||
if (catch(result) == InputResult.NOT_AN_INT)
|
||||
{
|
||||
libc::printf("I didn't understand that.\n");
|
||||
err_count++;
|
||||
continue;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
unreachable();
|
||||
}
|
||||
|
||||
fn void! Game.play(Game *game)
|
||||
{
|
||||
while (!game.done)
|
||||
{
|
||||
int guess = askGuessMulti(game.high)?;
|
||||
game.report(guess);
|
||||
game.update(guess);
|
||||
}
|
||||
}
|
||||
|
||||
fn void Game.report(Game *game, int guess)
|
||||
{
|
||||
char[] desc = {|
|
||||
if (guess < game.answer) return "too low";
|
||||
if (guess > game.answer) return "too high";
|
||||
return "the answer";
|
||||
|};
|
||||
libc::printf("%d is %.*s.\n", guess, (int)desc.len, desc.ptr);
|
||||
}
|
||||
|
||||
fn void Game.update(Game *game, int guess)
|
||||
{
|
||||
if (guess == game.answer) game.done = true;
|
||||
game.guesses++;
|
||||
}
|
||||
|
||||
fn void! main()
|
||||
{
|
||||
libc::srand((int)libc::clock());
|
||||
int high = 100;
|
||||
int answer = libc::rand() % high + 1;
|
||||
Game game = { .answer = answer, .high = high };
|
||||
game.play();
|
||||
libc::printf("Finished in %d guesses.\n", game.guesses);
|
||||
libc::printf("Total input errors: %d.\n", err_count);
|
||||
}
|
||||
27
resources/examples/contextfree/multi.c3
Normal file
27
resources/examples/contextfree/multi.c3
Normal file
@@ -0,0 +1,27 @@
|
||||
module test;
|
||||
import std::io;
|
||||
|
||||
fn void main()
|
||||
{
|
||||
/*
|
||||
Here's a comment.
|
||||
/*
|
||||
And a nested comment.
|
||||
*/
|
||||
*/
|
||||
char[] text = `
|
||||
function hello() {
|
||||
console.log("name`"\t"`age");
|
||||
}
|
||||
|
||||
hello();
|
||||
`;
|
||||
io::println(text);
|
||||
|
||||
// Binary
|
||||
const DATA = x"4749463839610100010080"
|
||||
x"0100ffffff00000021f904"
|
||||
x"010a0001002c0000000001"
|
||||
x"0001000002024c01003b";
|
||||
io::printf("%d\n", DATA.len);
|
||||
}
|
||||
16
resources/examples/factorial_macro.c3
Normal file
16
resources/examples/factorial_macro.c3
Normal file
@@ -0,0 +1,16 @@
|
||||
macro int factorial($n)
|
||||
{
|
||||
$if ($n == 0):
|
||||
return 1;
|
||||
$else:
|
||||
return $n * factorial($n - 1);
|
||||
$endif;
|
||||
}
|
||||
|
||||
extern fn void printf(char *fmt, ...);
|
||||
|
||||
fn void main()
|
||||
{
|
||||
int x = factorial(12);
|
||||
printf("12! = %d\n", x);
|
||||
}
|
||||
76
resources/examples/fannkuch-redux.c3
Normal file
76
resources/examples/fannkuch-redux.c3
Normal file
@@ -0,0 +1,76 @@
|
||||
module fannkuch;
|
||||
import std::array;
|
||||
import std::io;
|
||||
import std::math;
|
||||
import libc;
|
||||
|
||||
fn int fannkuchredux(int n)
|
||||
{
|
||||
int* perm = array::alloc(int, n);
|
||||
int* perm1 = array::alloc(int, n);
|
||||
int* count = array::alloc(int, n);
|
||||
int max_flips_count;
|
||||
int perm_count;
|
||||
int checksum;
|
||||
|
||||
for (int i = 0; i < n; i++) perm1[i] = i;
|
||||
|
||||
int r = n;
|
||||
|
||||
while (1)
|
||||
{
|
||||
for (; r != 1; r--) count[r - 1] = r;
|
||||
|
||||
for (int i = 0; i < n; i++) perm[i] = perm1[i];
|
||||
|
||||
int flips_count = 0;
|
||||
int k;
|
||||
|
||||
while (!((k = perm[0]) == 0))
|
||||
{
|
||||
int k2 = (k + 1) >> 1;
|
||||
for (int i = 0; i < k2; i++)
|
||||
{
|
||||
int temp = perm[i];
|
||||
perm[i] = perm[k - i];
|
||||
perm[k - i] = temp;
|
||||
}
|
||||
flips_count++;
|
||||
}
|
||||
|
||||
max_flips_count = max(max_flips_count, flips_count);
|
||||
checksum += perm_count % 2 == 0 ? flips_count : -flips_count;
|
||||
|
||||
/* Use incremental change to generate another permutation */
|
||||
while (1)
|
||||
{
|
||||
if (r == n)
|
||||
{
|
||||
io::printf("%d\n", checksum);
|
||||
return max_flips_count;
|
||||
}
|
||||
|
||||
int perm0 = perm1[0];
|
||||
int i = 0;
|
||||
while (i < r)
|
||||
{
|
||||
int j = i + 1;
|
||||
perm1[i] = perm1[j];
|
||||
i = j;
|
||||
}
|
||||
perm1[r] = perm0;
|
||||
count[r] = count[r] - 1;
|
||||
if (count[r] > 0) break;
|
||||
r++;
|
||||
}
|
||||
perm_count++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn int main(int argc, char** argv)
|
||||
{
|
||||
int n = argc > 1 ? libc::atoi(argv[1]) : 7;
|
||||
io::printf("Pfannkuchen(%d) = %d\n", n, fannkuchredux(n));
|
||||
return 0;
|
||||
}
|
||||
104
resources/examples/fasta.c3
Normal file
104
resources/examples/fasta.c3
Normal file
@@ -0,0 +1,104 @@
|
||||
module fasta;
|
||||
import std::io;
|
||||
import libc;
|
||||
|
||||
const IM = 139968;
|
||||
const IA = 3877;
|
||||
const IC = 29573;
|
||||
const SEED = 42;
|
||||
|
||||
uint seed = SEED;
|
||||
|
||||
fn float fasta_rand(float max_val)
|
||||
{
|
||||
seed = (seed * IA + IC) % IM;
|
||||
return max_val * seed / IM;
|
||||
}
|
||||
|
||||
private char[] alu =
|
||||
"GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG"
|
||||
"GAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA"
|
||||
"CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT"
|
||||
"ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA"
|
||||
"GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG"
|
||||
"AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC"
|
||||
"AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA";
|
||||
|
||||
|
||||
char[] iub = "acgtBDHKMNRSVWY";
|
||||
double[] iub_p = {
|
||||
0.27,
|
||||
0.12,
|
||||
0.12,
|
||||
0.27,
|
||||
0.02,
|
||||
0.02,
|
||||
0.02,
|
||||
0.02,
|
||||
0.02,
|
||||
0.02,
|
||||
0.02,
|
||||
0.02,
|
||||
0.02,
|
||||
0.02,
|
||||
0.02 };
|
||||
|
||||
char[] homosapiens = "acgt";
|
||||
double[] homosapiens_p = {
|
||||
0.3029549426680,
|
||||
0.1979883004921,
|
||||
0.1975473066391,
|
||||
0.3015094502008
|
||||
};
|
||||
|
||||
const LINELEN = 60;
|
||||
|
||||
// slowest character-at-a-time output
|
||||
fn void repeat_fasta(char[] seq, int n)
|
||||
{
|
||||
usize len = seq.len;
|
||||
int i = void;
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
io::putchar(seq[i % len]);
|
||||
if (i % LINELEN == LINELEN - 1) io::putchar('\n');
|
||||
}
|
||||
if (i % LINELEN != 0) io::putchar('\n');
|
||||
}
|
||||
|
||||
fn void random_fasta(char[] symb, double[] probability, int n)
|
||||
{
|
||||
assert(symb.len == probability.len);
|
||||
int len = probability.len;
|
||||
int i = void;
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
double v = fasta_rand(1.0);
|
||||
/* slowest idiomatic linear lookup. Fast if len is short though. */
|
||||
int j = void;
|
||||
for (j = 0; j < len - 1; j++)
|
||||
{
|
||||
v -= probability[j];
|
||||
if (v < 0) break;
|
||||
}
|
||||
io::putchar(symb[j]);
|
||||
if (i % LINELEN == LINELEN - 1) io::putchar('\n');
|
||||
}
|
||||
if (i % LINELEN != 0) io::putchar('\n');
|
||||
}
|
||||
|
||||
fn void main(int argc, char **argv)
|
||||
{
|
||||
int n = 1000;
|
||||
if (argc > 1) n = libc::atoi(argv[1]);
|
||||
|
||||
io::printf(">ONE Homo sapiens alu\n");
|
||||
repeat_fasta(alu, n * 2);
|
||||
|
||||
io::printf(">TWO IUB ambiguity codes\n");
|
||||
random_fasta(iub, iub_p, n * 3);
|
||||
|
||||
io::printf(">THREE Homo sapiens frequency\n");
|
||||
random_fasta(homosapiens, homosapiens_p, n * 5);
|
||||
|
||||
}
|
||||
@@ -1,86 +1,82 @@
|
||||
module game_of_life;
|
||||
import std::io;
|
||||
import libc;
|
||||
|
||||
extern func void printf(char *fmt, ...);
|
||||
extern func int atoi(char *val);
|
||||
extern void *__stdoutp;
|
||||
extern func void fflush(void *std);
|
||||
extern func int rand();
|
||||
extern func void* malloc(usize size);
|
||||
extern func void usleep(int time);
|
||||
extern fn void usleep(int time);
|
||||
|
||||
|
||||
struct GameBoard
|
||||
{
|
||||
int h;
|
||||
int w;
|
||||
char* world;
|
||||
char* temp;
|
||||
int h;
|
||||
int w;
|
||||
char* world;
|
||||
char* temp;
|
||||
}
|
||||
|
||||
func void GameBoard.show(GameBoard *board)
|
||||
fn void GameBoard.show(GameBoard *board)
|
||||
{
|
||||
|
||||
printf("\e[H");
|
||||
io::printf("\e[H");
|
||||
char* current = board.world;
|
||||
for (int y = 0; y < board.h; y++)
|
||||
{
|
||||
for (int x = 0; x < board.w; x++)
|
||||
{
|
||||
printf(*current ? "\e[07m \e[m" : " ");
|
||||
current++;
|
||||
}
|
||||
printf("\e[E");
|
||||
for (int x = 0; x < board.w; x++)
|
||||
{
|
||||
io::printf(*current ? "\e[07m \e[m" : " ");
|
||||
current++;
|
||||
}
|
||||
io::printf("\e[E");
|
||||
}
|
||||
fflush(__stdoutp);
|
||||
libc::fflush(libc::stdout());
|
||||
}
|
||||
|
||||
func void GameBoard.evolve(GameBoard *board)
|
||||
fn void GameBoard.evolve(GameBoard *board)
|
||||
{
|
||||
for (int y = 0; y < board.h; y++)
|
||||
{
|
||||
for (int x = 0; x < board.w; x++)
|
||||
{
|
||||
int n = 0;
|
||||
for (int y1 = y - 1; y1 <= y + 1; y1++)
|
||||
{
|
||||
for (int x1 = x - 1; x1 <= x + 1; x1++)
|
||||
{
|
||||
int actualX = (x1 + board.w) % board.w;
|
||||
int actualY = (y1 + board.h) % board.h;
|
||||
if (board.world[actualX + actualY * board.w]) n++;
|
||||
}
|
||||
}
|
||||
if (board.world[x + y * board.w]) n--;
|
||||
board.temp[x + y * board.w] = (char)(n == 3 || (n == 2 && board.world[x + y * board.w]));
|
||||
}
|
||||
for (int x = 0; x < board.w; x++)
|
||||
{
|
||||
int n = 0;
|
||||
for (int y1 = y - 1; y1 <= y + 1; y1++)
|
||||
{
|
||||
for (int x1 = x - 1; x1 <= x + 1; x1++)
|
||||
{
|
||||
int actualX = (x1 + board.w) % board.w;
|
||||
int actualY = (y1 + board.h) % board.h;
|
||||
if (board.world[actualX + actualY * board.w]) n++;
|
||||
}
|
||||
}
|
||||
if (board.world[x + y * board.w]) n--;
|
||||
board.temp[x + y * board.w] = (char)(n == 3 || (n == 2 && board.world[x + y * board.w]));
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < board.w * board.h; i++)
|
||||
{
|
||||
board.world[i] = board.temp[i];
|
||||
board.world[i] = board.temp[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func int main(int c, char** v)
|
||||
fn int main(int c, char** v)
|
||||
{
|
||||
int w = 0;
|
||||
int h = 0;
|
||||
if (c > 1) w = atoi(v[1]);
|
||||
if (c > 2) h = atoi(v[2]);
|
||||
if (c > 1) w = libc::atoi(v[1]);
|
||||
if (c > 2) h = libc::atoi(v[2]);
|
||||
if (w <= 0) w = 30;
|
||||
if (h <= 0) h = 30;
|
||||
|
||||
GameBoard board;
|
||||
board.w = w;
|
||||
board.h = h;
|
||||
board.world = malloc((ulong)(h * w));
|
||||
board.temp = malloc((ulong)(h * w));
|
||||
GameBoard board;
|
||||
board.w = w;
|
||||
board.h = h;
|
||||
board.world = mem::alloc((ulong)(h * w));
|
||||
board.temp = mem::alloc((ulong)(h * w));
|
||||
|
||||
for (int i = h * w - 1; i >= 0; i--)
|
||||
{
|
||||
board.world[i] = rand() % 10 == 0 ? 1 : 0;
|
||||
}
|
||||
for (int j = 0; j < 1000; j++)
|
||||
for (int i = h * w - 1; i >= 0; i--)
|
||||
{
|
||||
board.world[i] = libc::rand() % 10 == 0 ? 1 : 0;
|
||||
}
|
||||
for (int j = 0; j < 1000; j++)
|
||||
{
|
||||
board.show();
|
||||
board.evolve();
|
||||
|
||||
@@ -1,24 +1,23 @@
|
||||
module hash;
|
||||
import libc;
|
||||
|
||||
// Code adapted from Odin's hash.odin
|
||||
// The code below should not be considered *correct*
|
||||
// They are merely done to illustrate the language syntax.
|
||||
|
||||
extern func void printf(char*, ...);
|
||||
|
||||
public func void main()
|
||||
fn void main()
|
||||
{
|
||||
char* y = "Hello World!";
|
||||
printf("Adler32 of %s is %x\n", y, adler32(y[0..11]));
|
||||
printf("CRC32 of %s is %x\n", y, crc32(y[0..11]));
|
||||
printf("CRC64 of %s is %llx\n", y, crc64(y[0..11]));
|
||||
printf("FNV32 of %s is %x\n", y, fnv32(y[0..11]));
|
||||
printf("FNV32a of %s is %x\n", y, fnv32a(y[0..11]));
|
||||
printf("FNV64 of %s is %llx\n", y, fnv64(y[0..11]));
|
||||
printf("FNV64a of %s is %llx\n", y, fnv64a(y[0..11]));
|
||||
char[] y = "Hello World!";
|
||||
libc::printf("Adler32 of %s is %x, expected 1c49043e\n", (char*)(y), adler32(y));
|
||||
libc::printf("CRC32B of %s is %x, expected 1c291ca3\n", (char*)(y), crc32(y));
|
||||
libc::printf("CRC64 of %s is %llx, expected fad9a77c67077205\n", (char*)(y), crc64(y));
|
||||
libc::printf("FNV32 of %s is %x, expected 12a9a41c\n", (char*)(y), fnv32(y));
|
||||
libc::printf("FNV32a of %s is %x, expected b1ea4872\n", (char*)(y), fnv32a(y));
|
||||
libc::printf("FNV64 of %s is %llx, expected 8e59dd02f68c387c\n", (char*)(y), fnv64(y));
|
||||
libc::printf("FNV64a of %s is %llx, expected 8c0ec8d1fb9e6e32\n", (char*)(y), fnv64a(y));
|
||||
}
|
||||
|
||||
public func uint adler32(char[] data)
|
||||
fn uint adler32(char[] data)
|
||||
{
|
||||
const uint ADLER_CONST = 65521;
|
||||
uint a = 1;
|
||||
@@ -31,7 +30,7 @@ public func uint adler32(char[] data)
|
||||
return (b << 16) | a;
|
||||
}
|
||||
|
||||
public func uint crc32(char[] data)
|
||||
fn uint crc32(char[] data)
|
||||
{
|
||||
uint result = ~(uint)(0);
|
||||
foreach (char x : data)
|
||||
@@ -41,18 +40,18 @@ public func uint crc32(char[] data)
|
||||
return ~result;
|
||||
}
|
||||
|
||||
public func ulong crc64(char[] data)
|
||||
fn ulong crc64(char[] data)
|
||||
{
|
||||
ulong result = 0;
|
||||
ulong result = (ulong)(0);
|
||||
foreach (char x : data)
|
||||
{
|
||||
result = (result >> 8) ^ CRC64_TABLE[(char)(result ^ x)];
|
||||
result = (result << 8) ^ CRC64_TABLE[(char)((result >> 56) ^ x)];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public func uint fnv32(char[] data)
|
||||
fn uint fnv32(char[] data)
|
||||
{
|
||||
uint h = 0x811c9dc5;
|
||||
foreach (char x : data)
|
||||
@@ -62,7 +61,7 @@ public func uint fnv32(char[] data)
|
||||
return h;
|
||||
}
|
||||
|
||||
public func ulong fnv64(char[] data)
|
||||
fn ulong fnv64(char[] data)
|
||||
{
|
||||
ulong h = 0xcbf29ce484222325;
|
||||
foreach (char x : data)
|
||||
@@ -72,7 +71,7 @@ public func ulong fnv64(char[] data)
|
||||
return h;
|
||||
}
|
||||
|
||||
public func uint fnv32a(char[] data)
|
||||
fn uint fnv32a(char[] data)
|
||||
{
|
||||
uint h = 0x811c9dc5;
|
||||
foreach (char x : data)
|
||||
@@ -82,7 +81,7 @@ public func uint fnv32a(char[] data)
|
||||
return h;
|
||||
}
|
||||
|
||||
public func ulong fnv64a(char[] data)
|
||||
fn ulong fnv64a(char[] data)
|
||||
{
|
||||
ulong h = 0xcbf29ce484222325;
|
||||
foreach (char x : data)
|
||||
@@ -92,7 +91,7 @@ public func ulong fnv64a(char[] data)
|
||||
return h;
|
||||
}
|
||||
|
||||
const uint[256] CRC32_TABLE = {
|
||||
private const uint[256] CRC32_TABLE = {
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
|
||||
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
||||
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||
@@ -159,133 +158,69 @@ const uint[256] CRC32_TABLE = {
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
|
||||
};
|
||||
|
||||
const ulong[256] CRC64_TABLE = {
|
||||
0x0000000000000000, 0x7ad870c830358979,
|
||||
0xf5b0e190606b12f2, 0x8f689158505e9b8b,
|
||||
0xc038e5739841b68f, 0xbae095bba8743ff6,
|
||||
0x358804e3f82aa47d, 0x4f50742bc81f2d04,
|
||||
0xab28ecb46814fe75, 0xd1f09c7c5821770c,
|
||||
0x5e980d24087fec87, 0x24407dec384a65fe,
|
||||
0x6b1009c7f05548fa, 0x11c8790fc060c183,
|
||||
0x9ea0e857903e5a08, 0xe478989fa00bd371,
|
||||
0x7d08ff3b88be6f81, 0x07d08ff3b88be6f8,
|
||||
0x88b81eabe8d57d73, 0xf2606e63d8e0f40a,
|
||||
0xbd301a4810ffd90e, 0xc7e86a8020ca5077,
|
||||
0x4880fbd87094cbfc, 0x32588b1040a14285,
|
||||
0xd620138fe0aa91f4, 0xacf86347d09f188d,
|
||||
0x2390f21f80c18306, 0x594882d7b0f40a7f,
|
||||
0x1618f6fc78eb277b, 0x6cc0863448deae02,
|
||||
0xe3a8176c18803589, 0x997067a428b5bcf0,
|
||||
0xfa11fe77117cdf02, 0x80c98ebf2149567b,
|
||||
0x0fa11fe77117cdf0, 0x75796f2f41224489,
|
||||
0x3a291b04893d698d, 0x40f16bccb908e0f4,
|
||||
0xcf99fa94e9567b7f, 0xb5418a5cd963f206,
|
||||
0x513912c379682177, 0x2be1620b495da80e,
|
||||
0xa489f35319033385, 0xde51839b2936bafc,
|
||||
0x9101f7b0e12997f8, 0xebd98778d11c1e81,
|
||||
0x64b116208142850a, 0x1e6966e8b1770c73,
|
||||
0x8719014c99c2b083, 0xfdc17184a9f739fa,
|
||||
0x72a9e0dcf9a9a271, 0x08719014c99c2b08,
|
||||
0x4721e43f0183060c, 0x3df994f731b68f75,
|
||||
0xb29105af61e814fe, 0xc849756751dd9d87,
|
||||
0x2c31edf8f1d64ef6, 0x56e99d30c1e3c78f,
|
||||
0xd9810c6891bd5c04, 0xa3597ca0a188d57d,
|
||||
0xec09088b6997f879, 0x96d1784359a27100,
|
||||
0x19b9e91b09fcea8b, 0x636199d339c963f2,
|
||||
0xdf7adabd7a6e2d6f, 0xa5a2aa754a5ba416,
|
||||
0x2aca3b2d1a053f9d, 0x50124be52a30b6e4,
|
||||
0x1f423fcee22f9be0, 0x659a4f06d21a1299,
|
||||
0xeaf2de5e82448912, 0x902aae96b271006b,
|
||||
0x74523609127ad31a, 0x0e8a46c1224f5a63,
|
||||
0x81e2d7997211c1e8, 0xfb3aa75142244891,
|
||||
0xb46ad37a8a3b6595, 0xceb2a3b2ba0eecec,
|
||||
0x41da32eaea507767, 0x3b024222da65fe1e,
|
||||
0xa2722586f2d042ee, 0xd8aa554ec2e5cb97,
|
||||
0x57c2c41692bb501c, 0x2d1ab4dea28ed965,
|
||||
0x624ac0f56a91f461, 0x1892b03d5aa47d18,
|
||||
0x97fa21650afae693, 0xed2251ad3acf6fea,
|
||||
0x095ac9329ac4bc9b, 0x7382b9faaaf135e2,
|
||||
0xfcea28a2faafae69, 0x8632586aca9a2710,
|
||||
0xc9622c4102850a14, 0xb3ba5c8932b0836d,
|
||||
0x3cd2cdd162ee18e6, 0x460abd1952db919f,
|
||||
0x256b24ca6b12f26d, 0x5fb354025b277b14,
|
||||
0xd0dbc55a0b79e09f, 0xaa03b5923b4c69e6,
|
||||
0xe553c1b9f35344e2, 0x9f8bb171c366cd9b,
|
||||
0x10e3202993385610, 0x6a3b50e1a30ddf69,
|
||||
0x8e43c87e03060c18, 0xf49bb8b633338561,
|
||||
0x7bf329ee636d1eea, 0x012b592653589793,
|
||||
0x4e7b2d0d9b47ba97, 0x34a35dc5ab7233ee,
|
||||
0xbbcbcc9dfb2ca865, 0xc113bc55cb19211c,
|
||||
0x5863dbf1e3ac9dec, 0x22bbab39d3991495,
|
||||
0xadd33a6183c78f1e, 0xd70b4aa9b3f20667,
|
||||
0x985b3e827bed2b63, 0xe2834e4a4bd8a21a,
|
||||
0x6debdf121b863991, 0x1733afda2bb3b0e8,
|
||||
0xf34b37458bb86399, 0x8993478dbb8deae0,
|
||||
0x06fbd6d5ebd3716b, 0x7c23a61ddbe6f812,
|
||||
0x3373d23613f9d516, 0x49aba2fe23cc5c6f,
|
||||
0xc6c333a67392c7e4, 0xbc1b436e43a74e9d,
|
||||
0x95ac9329ac4bc9b5, 0xef74e3e19c7e40cc,
|
||||
0x601c72b9cc20db47, 0x1ac40271fc15523e,
|
||||
0x5594765a340a7f3a, 0x2f4c0692043ff643,
|
||||
0xa02497ca54616dc8, 0xdafce7026454e4b1,
|
||||
0x3e847f9dc45f37c0, 0x445c0f55f46abeb9,
|
||||
0xcb349e0da4342532, 0xb1eceec59401ac4b,
|
||||
0xfebc9aee5c1e814f, 0x8464ea266c2b0836,
|
||||
0x0b0c7b7e3c7593bd, 0x71d40bb60c401ac4,
|
||||
0xe8a46c1224f5a634, 0x927c1cda14c02f4d,
|
||||
0x1d148d82449eb4c6, 0x67ccfd4a74ab3dbf,
|
||||
0x289c8961bcb410bb, 0x5244f9a98c8199c2,
|
||||
0xdd2c68f1dcdf0249, 0xa7f41839ecea8b30,
|
||||
0x438c80a64ce15841, 0x3954f06e7cd4d138,
|
||||
0xb63c61362c8a4ab3, 0xcce411fe1cbfc3ca,
|
||||
0x83b465d5d4a0eece, 0xf96c151de49567b7,
|
||||
0x76048445b4cbfc3c, 0x0cdcf48d84fe7545,
|
||||
0x6fbd6d5ebd3716b7, 0x15651d968d029fce,
|
||||
0x9a0d8ccedd5c0445, 0xe0d5fc06ed698d3c,
|
||||
0xaf85882d2576a038, 0xd55df8e515432941,
|
||||
0x5a3569bd451db2ca, 0x20ed197575283bb3,
|
||||
0xc49581ead523e8c2, 0xbe4df122e51661bb,
|
||||
0x3125607ab548fa30, 0x4bfd10b2857d7349,
|
||||
0x04ad64994d625e4d, 0x7e7514517d57d734,
|
||||
0xf11d85092d094cbf, 0x8bc5f5c11d3cc5c6,
|
||||
0x12b5926535897936, 0x686de2ad05bcf04f,
|
||||
0xe70573f555e26bc4, 0x9ddd033d65d7e2bd,
|
||||
0xd28d7716adc8cfb9, 0xa85507de9dfd46c0,
|
||||
0x273d9686cda3dd4b, 0x5de5e64efd965432,
|
||||
0xb99d7ed15d9d8743, 0xc3450e196da80e3a,
|
||||
0x4c2d9f413df695b1, 0x36f5ef890dc31cc8,
|
||||
0x79a59ba2c5dc31cc, 0x037deb6af5e9b8b5,
|
||||
0x8c157a32a5b7233e, 0xf6cd0afa9582aa47,
|
||||
0x4ad64994d625e4da, 0x300e395ce6106da3,
|
||||
0xbf66a804b64ef628, 0xc5bed8cc867b7f51,
|
||||
0x8aeeace74e645255, 0xf036dc2f7e51db2c,
|
||||
0x7f5e4d772e0f40a7, 0x05863dbf1e3ac9de,
|
||||
0xe1fea520be311aaf, 0x9b26d5e88e0493d6,
|
||||
0x144e44b0de5a085d, 0x6e963478ee6f8124,
|
||||
0x21c640532670ac20, 0x5b1e309b16452559,
|
||||
0xd476a1c3461bbed2, 0xaeaed10b762e37ab,
|
||||
0x37deb6af5e9b8b5b, 0x4d06c6676eae0222,
|
||||
0xc26e573f3ef099a9, 0xb8b627f70ec510d0,
|
||||
0xf7e653dcc6da3dd4, 0x8d3e2314f6efb4ad,
|
||||
0x0256b24ca6b12f26, 0x788ec2849684a65f,
|
||||
0x9cf65a1b368f752e, 0xe62e2ad306bafc57,
|
||||
0x6946bb8b56e467dc, 0x139ecb4366d1eea5,
|
||||
0x5ccebf68aecec3a1, 0x2616cfa09efb4ad8,
|
||||
0xa97e5ef8cea5d153, 0xd3a62e30fe90582a,
|
||||
0xb0c7b7e3c7593bd8, 0xca1fc72bf76cb2a1,
|
||||
0x45775673a732292a, 0x3faf26bb9707a053,
|
||||
0x70ff52905f188d57, 0x0a2722586f2d042e,
|
||||
0x854fb3003f739fa5, 0xff97c3c80f4616dc,
|
||||
0x1bef5b57af4dc5ad, 0x61372b9f9f784cd4,
|
||||
0xee5fbac7cf26d75f, 0x9487ca0fff135e26,
|
||||
0xdbd7be24370c7322, 0xa10fceec0739fa5b,
|
||||
0x2e675fb4576761d0, 0x54bf2f7c6752e8a9,
|
||||
0xcdcf48d84fe75459, 0xb71738107fd2dd20,
|
||||
0x387fa9482f8c46ab, 0x42a7d9801fb9cfd2,
|
||||
0x0df7adabd7a6e2d6, 0x772fdd63e7936baf,
|
||||
0xf8474c3bb7cdf024, 0x829f3cf387f8795d,
|
||||
0x66e7a46c27f3aa2c, 0x1c3fd4a417c62355,
|
||||
0x935745fc4798b8de, 0xe98f353477ad31a7,
|
||||
0xa6df411fbfb21ca3, 0xdc0731d78f8795da,
|
||||
0x536fa08fdfd90e51, 0x29b7d047efec8728,
|
||||
private const ulong[256] CRC64_TABLE = {
|
||||
0x0000000000000000, 0x42f0e1eba9ea3693, 0x85e1c3d753d46d26, 0xc711223cfa3e5bb5,
|
||||
0x493366450e42ecdf, 0x0bc387aea7a8da4c, 0xccd2a5925d9681f9, 0x8e224479f47cb76a,
|
||||
0x9266cc8a1c85d9be, 0xd0962d61b56fef2d, 0x17870f5d4f51b498, 0x5577eeb6e6bb820b,
|
||||
0xdb55aacf12c73561, 0x99a54b24bb2d03f2, 0x5eb4691841135847, 0x1c4488f3e8f96ed4,
|
||||
0x663d78ff90e185ef, 0x24cd9914390bb37c, 0xe3dcbb28c335e8c9, 0xa12c5ac36adfde5a,
|
||||
0x2f0e1eba9ea36930, 0x6dfeff5137495fa3, 0xaaefdd6dcd770416, 0xe81f3c86649d3285,
|
||||
0xf45bb4758c645c51, 0xb6ab559e258e6ac2, 0x71ba77a2dfb03177, 0x334a9649765a07e4,
|
||||
0xbd68d2308226b08e, 0xff9833db2bcc861d, 0x388911e7d1f2dda8, 0x7a79f00c7818eb3b,
|
||||
0xcc7af1ff21c30bde, 0x8e8a101488293d4d, 0x499b3228721766f8, 0x0b6bd3c3dbfd506b,
|
||||
0x854997ba2f81e701, 0xc7b97651866bd192, 0x00a8546d7c558a27, 0x4258b586d5bfbcb4,
|
||||
0x5e1c3d753d46d260, 0x1cecdc9e94ace4f3, 0xdbfdfea26e92bf46, 0x990d1f49c77889d5,
|
||||
0x172f5b3033043ebf, 0x55dfbadb9aee082c, 0x92ce98e760d05399, 0xd03e790cc93a650a,
|
||||
0xaa478900b1228e31, 0xe8b768eb18c8b8a2, 0x2fa64ad7e2f6e317, 0x6d56ab3c4b1cd584,
|
||||
0xe374ef45bf6062ee, 0xa1840eae168a547d, 0x66952c92ecb40fc8, 0x2465cd79455e395b,
|
||||
0x3821458aada7578f, 0x7ad1a461044d611c, 0xbdc0865dfe733aa9, 0xff3067b657990c3a,
|
||||
0x711223cfa3e5bb50, 0x33e2c2240a0f8dc3, 0xf4f3e018f031d676, 0xb60301f359dbe0e5,
|
||||
0xda050215ea6c212f, 0x98f5e3fe438617bc, 0x5fe4c1c2b9b84c09, 0x1d14202910527a9a,
|
||||
0x93366450e42ecdf0, 0xd1c685bb4dc4fb63, 0x16d7a787b7faa0d6, 0x5427466c1e109645,
|
||||
0x4863ce9ff6e9f891, 0x0a932f745f03ce02, 0xcd820d48a53d95b7, 0x8f72eca30cd7a324,
|
||||
0x0150a8daf8ab144e, 0x43a04931514122dd, 0x84b16b0dab7f7968, 0xc6418ae602954ffb,
|
||||
0xbc387aea7a8da4c0, 0xfec89b01d3679253, 0x39d9b93d2959c9e6, 0x7b2958d680b3ff75,
|
||||
0xf50b1caf74cf481f, 0xb7fbfd44dd257e8c, 0x70eadf78271b2539, 0x321a3e938ef113aa,
|
||||
0x2e5eb66066087d7e, 0x6cae578bcfe24bed, 0xabbf75b735dc1058, 0xe94f945c9c3626cb,
|
||||
0x676dd025684a91a1, 0x259d31cec1a0a732, 0xe28c13f23b9efc87, 0xa07cf2199274ca14,
|
||||
0x167ff3eacbaf2af1, 0x548f120162451c62, 0x939e303d987b47d7, 0xd16ed1d631917144,
|
||||
0x5f4c95afc5edc62e, 0x1dbc74446c07f0bd, 0xdaad56789639ab08, 0x985db7933fd39d9b,
|
||||
0x84193f60d72af34f, 0xc6e9de8b7ec0c5dc, 0x01f8fcb784fe9e69, 0x43081d5c2d14a8fa,
|
||||
0xcd2a5925d9681f90, 0x8fdab8ce70822903, 0x48cb9af28abc72b6, 0x0a3b7b1923564425,
|
||||
0x70428b155b4eaf1e, 0x32b26afef2a4998d, 0xf5a348c2089ac238, 0xb753a929a170f4ab,
|
||||
0x3971ed50550c43c1, 0x7b810cbbfce67552, 0xbc902e8706d82ee7, 0xfe60cf6caf321874,
|
||||
0xe224479f47cb76a0, 0xa0d4a674ee214033, 0x67c58448141f1b86, 0x253565a3bdf52d15,
|
||||
0xab1721da49899a7f, 0xe9e7c031e063acec, 0x2ef6e20d1a5df759, 0x6c0603e6b3b7c1ca,
|
||||
0xf6fae5c07d3274cd, 0xb40a042bd4d8425e, 0x731b26172ee619eb, 0x31ebc7fc870c2f78,
|
||||
0xbfc9838573709812, 0xfd39626eda9aae81, 0x3a28405220a4f534, 0x78d8a1b9894ec3a7,
|
||||
0x649c294a61b7ad73, 0x266cc8a1c85d9be0, 0xe17dea9d3263c055, 0xa38d0b769b89f6c6,
|
||||
0x2daf4f0f6ff541ac, 0x6f5faee4c61f773f, 0xa84e8cd83c212c8a, 0xeabe6d3395cb1a19,
|
||||
0x90c79d3fedd3f122, 0xd2377cd44439c7b1, 0x15265ee8be079c04, 0x57d6bf0317edaa97,
|
||||
0xd9f4fb7ae3911dfd, 0x9b041a914a7b2b6e, 0x5c1538adb04570db, 0x1ee5d94619af4648,
|
||||
0x02a151b5f156289c, 0x4051b05e58bc1e0f, 0x87409262a28245ba, 0xc5b073890b687329,
|
||||
0x4b9237f0ff14c443, 0x0962d61b56fef2d0, 0xce73f427acc0a965, 0x8c8315cc052a9ff6,
|
||||
0x3a80143f5cf17f13, 0x7870f5d4f51b4980, 0xbf61d7e80f251235, 0xfd913603a6cf24a6,
|
||||
0x73b3727a52b393cc, 0x31439391fb59a55f, 0xf652b1ad0167feea, 0xb4a25046a88dc879,
|
||||
0xa8e6d8b54074a6ad, 0xea16395ee99e903e, 0x2d071b6213a0cb8b, 0x6ff7fa89ba4afd18,
|
||||
0xe1d5bef04e364a72, 0xa3255f1be7dc7ce1, 0x64347d271de22754, 0x26c49cccb40811c7,
|
||||
0x5cbd6cc0cc10fafc, 0x1e4d8d2b65facc6f, 0xd95caf179fc497da, 0x9bac4efc362ea149,
|
||||
0x158e0a85c2521623, 0x577eeb6e6bb820b0, 0x906fc95291867b05, 0xd29f28b9386c4d96,
|
||||
0xcedba04ad0952342, 0x8c2b41a1797f15d1, 0x4b3a639d83414e64, 0x09ca82762aab78f7,
|
||||
0x87e8c60fded7cf9d, 0xc51827e4773df90e, 0x020905d88d03a2bb, 0x40f9e43324e99428,
|
||||
0x2cffe7d5975e55e2, 0x6e0f063e3eb46371, 0xa91e2402c48a38c4, 0xebeec5e96d600e57,
|
||||
0x65cc8190991cb93d, 0x273c607b30f68fae, 0xe02d4247cac8d41b, 0xa2dda3ac6322e288,
|
||||
0xbe992b5f8bdb8c5c, 0xfc69cab42231bacf, 0x3b78e888d80fe17a, 0x7988096371e5d7e9,
|
||||
0xf7aa4d1a85996083, 0xb55aacf12c735610, 0x724b8ecdd64d0da5, 0x30bb6f267fa73b36,
|
||||
0x4ac29f2a07bfd00d, 0x08327ec1ae55e69e, 0xcf235cfd546bbd2b, 0x8dd3bd16fd818bb8,
|
||||
0x03f1f96f09fd3cd2, 0x41011884a0170a41, 0x86103ab85a2951f4, 0xc4e0db53f3c36767,
|
||||
0xd8a453a01b3a09b3, 0x9a54b24bb2d03f20, 0x5d45907748ee6495, 0x1fb5719ce1045206,
|
||||
0x919735e51578e56c, 0xd367d40ebc92d3ff, 0x1476f63246ac884a, 0x568617d9ef46bed9,
|
||||
0xe085162ab69d5e3c, 0xa275f7c11f7768af, 0x6564d5fde549331a, 0x279434164ca30589,
|
||||
0xa9b6706fb8dfb2e3, 0xeb46918411358470, 0x2c57b3b8eb0bdfc5, 0x6ea7525342e1e956,
|
||||
0x72e3daa0aa188782, 0x30133b4b03f2b111, 0xf7021977f9cceaa4, 0xb5f2f89c5026dc37,
|
||||
0x3bd0bce5a45a6b5d, 0x79205d0e0db05dce, 0xbe317f32f78e067b, 0xfcc19ed95e6430e8,
|
||||
0x86b86ed5267cdbd3, 0xc4488f3e8f96ed40, 0x0359ad0275a8b6f5, 0x41a94ce9dc428066,
|
||||
0xcf8b0890283e370c, 0x8d7be97b81d4019f, 0x4a6acb477bea5a2a, 0x089a2aacd2006cb9,
|
||||
0x14dea25f3af9026d, 0x562e43b4931334fe, 0x913f6188692d6f4b, 0xd3cf8063c0c759d8,
|
||||
0x5dedc41a34bbeeb2, 0x1f1d25f19d51d821, 0xd80c07cd676f8394, 0x9afce626ce85b507,
|
||||
};
|
||||
|
||||
26
resources/examples/levenshtein.c3
Normal file
26
resources/examples/levenshtein.c3
Normal file
@@ -0,0 +1,26 @@
|
||||
module levenshtein;
|
||||
import std::math;
|
||||
|
||||
// This levenshtein exercises C3 subarrays.
|
||||
fn int levenshtein(char[] s, char[] t)
|
||||
{
|
||||
// if either string is empty, difference is inserting all chars
|
||||
// from the other
|
||||
if (!s.len) return t.len;
|
||||
if (!t.len) return s.len;
|
||||
|
||||
// if last letters are the same, the difference is whatever is
|
||||
// required to edit the rest of the strings
|
||||
if (s[^1] == t[^1]) return levenshtein(s[0..^2], t[0..^2]);
|
||||
|
||||
// else try:
|
||||
// changing last letter of s to that of t; or
|
||||
// remove last letter of s; or
|
||||
// remove last letter of t,
|
||||
// any of which is 1 edit plus editing the rest of the strings
|
||||
int a = levenshtein(s[0..^2], t[0..^2]);
|
||||
int b = levenshtein(s, t[0..^2]);
|
||||
int c = levenshtein(s[0..^2], t);
|
||||
|
||||
return min(min(a, b), c) + 1;
|
||||
}
|
||||
58
resources/examples/mandelbrot.c3
Normal file
58
resources/examples/mandelbrot.c3
Normal file
@@ -0,0 +1,58 @@
|
||||
module mandelbrot;
|
||||
|
||||
extern fn int atoi(char *s);
|
||||
extern fn int printf(char *s, ...);
|
||||
extern fn void putchar(int c);
|
||||
|
||||
fn void main(int argc, char **argv)
|
||||
{
|
||||
int w = atoi(argv[1]);
|
||||
int h = w;
|
||||
|
||||
const LIMIT = 2.0;
|
||||
const SQUARE_LIMIT = LIMIT * LIMIT;
|
||||
|
||||
printf("P4\n%d %d\n", w, h);
|
||||
|
||||
int iter = 50;
|
||||
int bit_num = 0;
|
||||
char byte_acc = 0;
|
||||
for (double y = 0; y < h; y++)
|
||||
{
|
||||
for (double x = 0; x < w; x++)
|
||||
{
|
||||
double zr;
|
||||
double zi;
|
||||
double ti;
|
||||
double tr;
|
||||
double cr = (2.0 * x / w - 1.5);
|
||||
double ci = (2.0 * y / h - 1.0);
|
||||
for (int i = 0; i < iter && (tr + ti <= SQUARE_LIMIT); i++)
|
||||
{
|
||||
zi = 2.0 * zr * zi + ci;
|
||||
zr = tr - ti + cr;
|
||||
tr = zr * zr;
|
||||
ti = zi * zi;
|
||||
}
|
||||
|
||||
byte_acc <<= 1;
|
||||
if (tr + ti <= SQUARE_LIMIT) byte_acc |= 0x01;
|
||||
|
||||
++bit_num;
|
||||
|
||||
if (bit_num == 8)
|
||||
{
|
||||
putchar(byte_acc);
|
||||
byte_acc = 0;
|
||||
bit_num = 0;
|
||||
}
|
||||
else if (x == w - 1)
|
||||
{
|
||||
byte_acc <<= (8 - w % 8);
|
||||
putchar(byte_acc);
|
||||
byte_acc = 0;
|
||||
bit_num = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
161
resources/examples/nbodies.c3
Normal file
161
resources/examples/nbodies.c3
Normal file
@@ -0,0 +1,161 @@
|
||||
module nbodies;
|
||||
|
||||
const PI = 3.141592653589793;
|
||||
const SOLAR_MASS = 4 * PI * PI;
|
||||
const DAYS_PER_YEAR = 365.24;
|
||||
const DT = 1e-2;
|
||||
const RECIP_DT = (1.0/DT);
|
||||
|
||||
struct Planet
|
||||
{
|
||||
double x, y, z;
|
||||
double vx, vy, vz;
|
||||
double mass;
|
||||
}
|
||||
|
||||
fn void advance(Planet[] bodies) @noinline
|
||||
{
|
||||
usize nbodies = bodies.len;
|
||||
foreach (i, Planet* &b : bodies)
|
||||
{
|
||||
for (usize j = i + 1; j < nbodies; j++)
|
||||
{
|
||||
Planet* b2 = &bodies[j];
|
||||
double dx = b.x - b2.x;
|
||||
double dy = b.y - b2.y;
|
||||
double dz = b.z - b2.z;
|
||||
double inv_distance = 1.0/sqrt(dx * dx + dy * dy + dz * dz);
|
||||
double mag = inv_distance * inv_distance * inv_distance;
|
||||
b.vx -= dx * b2.mass * mag;
|
||||
b.vy -= dy * b2.mass * mag;
|
||||
b.vz -= dz * b2.mass * mag;
|
||||
b2.vx += dx * b.mass * mag;
|
||||
b2.vy += dy * b.mass * mag;
|
||||
b2.vz += dz * b.mass * mag;
|
||||
}
|
||||
}
|
||||
foreach (&b : bodies)
|
||||
{
|
||||
b.x += b.vx;
|
||||
b.y += b.vy;
|
||||
b.z += b.vz;
|
||||
}
|
||||
}
|
||||
|
||||
fn double energy(Planet[] bodies)
|
||||
{
|
||||
double e;
|
||||
usize nbodies = bodies.len;
|
||||
|
||||
foreach (i, Planet* &b : bodies)
|
||||
{
|
||||
e += 0.5 * b.mass * (b.vx * b.vx + b.vy * b.vy + b.vz * b.vz);
|
||||
for (usize j = i + 1; j < nbodies; j++)
|
||||
{
|
||||
Planet* b2 = &bodies[j];
|
||||
double dx = b.x - b2.x;
|
||||
double dy = b.y - b2.y;
|
||||
double dz = b.z - b2.z;
|
||||
double distance = sqrt(dx * dx + dy * dy + dz * dz);
|
||||
e -= (b.mass * b2.mass) / distance;
|
||||
}
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
fn void offset_momentum(Planet[] bodies)
|
||||
{
|
||||
double px;
|
||||
double py;
|
||||
double pz;
|
||||
foreach (&b : bodies)
|
||||
{
|
||||
px += b.vx * b.mass;
|
||||
py += b.vy * b.mass;
|
||||
pz += b.vz * b.mass;
|
||||
}
|
||||
bodies[0].vx = - px / SOLAR_MASS;
|
||||
bodies[0].vy = - py / SOLAR_MASS;
|
||||
bodies[0].vz = - pz / SOLAR_MASS;
|
||||
}
|
||||
|
||||
Planet[*] planet_bodies = {
|
||||
{ /* sun */
|
||||
0, 0, 0, 0, 0, 0, SOLAR_MASS
|
||||
},
|
||||
{ /* jupiter */
|
||||
4.84143144246472090e+00,
|
||||
-1.16032004402742839e+00,
|
||||
-1.03622044471123109e-01,
|
||||
1.66007664274403694e-03 * DAYS_PER_YEAR,
|
||||
7.69901118419740425e-03 * DAYS_PER_YEAR,
|
||||
-6.90460016972063023e-05 * DAYS_PER_YEAR,
|
||||
9.54791938424326609e-04 * SOLAR_MASS
|
||||
},
|
||||
{ /* saturn */
|
||||
8.34336671824457987e+00,
|
||||
4.12479856412430479e+00,
|
||||
-4.03523417114321381e-01,
|
||||
-2.76742510726862411e-03 * DAYS_PER_YEAR,
|
||||
4.99852801234917238e-03 * DAYS_PER_YEAR,
|
||||
2.30417297573763929e-05 * DAYS_PER_YEAR,
|
||||
2.85885980666130812e-04 * SOLAR_MASS
|
||||
},
|
||||
{ /* uranus */
|
||||
1.28943695621391310e+01,
|
||||
-1.51111514016986312e+01,
|
||||
-2.23307578892655734e-01,
|
||||
2.96460137564761618e-03 * DAYS_PER_YEAR,
|
||||
2.37847173959480950e-03 * DAYS_PER_YEAR,
|
||||
-2.96589568540237556e-05 * DAYS_PER_YEAR,
|
||||
4.36624404335156298e-05 * SOLAR_MASS
|
||||
},
|
||||
{ /* neptune */
|
||||
1.53796971148509165e+01,
|
||||
-2.59193146099879641e+01,
|
||||
1.79258772950371181e-01,
|
||||
2.68067772490389322e-03 * DAYS_PER_YEAR,
|
||||
1.62824170038242295e-03 * DAYS_PER_YEAR,
|
||||
-9.51592254519715870e-05 * DAYS_PER_YEAR,
|
||||
5.15138902046611451e-05 * SOLAR_MASS
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Rescale certain properties of bodies. That allows doing
|
||||
* consequential advance()'s as if dt were equal to 1.0.
|
||||
*
|
||||
* When all advances done, rescale bodies back to obtain correct energy.
|
||||
*/
|
||||
fn void scale_bodies(Planet[] bodies, double scale)
|
||||
{
|
||||
foreach (&b : bodies)
|
||||
{
|
||||
b.mass *= scale * scale;
|
||||
b.vx *= scale;
|
||||
b.vy *= scale;
|
||||
b.vz *= scale;
|
||||
}
|
||||
}
|
||||
|
||||
extern fn int atoi(char *s);
|
||||
extern fn int printf(char *s, ...);
|
||||
extern fn double sqrt(double);
|
||||
|
||||
fn int main(int argc, char ** argv)
|
||||
{
|
||||
int n = atoi(argv[1]);
|
||||
|
||||
Planet[] bodies = &planet_bodies;
|
||||
offset_momentum(bodies);
|
||||
printf ("%.9f\n", energy(bodies));
|
||||
scale_bodies(bodies, DT);
|
||||
for (int i = 1; i <= n; i++)
|
||||
{
|
||||
advance(bodies);
|
||||
}
|
||||
scale_bodies(bodies, RECIP_DT);
|
||||
printf ("%.9f\n", energy(bodies));
|
||||
return 0;
|
||||
}
|
||||
@@ -10,7 +10,7 @@ module acorn::arr;
|
||||
|
||||
|
||||
/* Return a new Array, allocating len slots for Values. */
|
||||
func Value new(Value th, Value *dest, Value type, AuintIdx len)
|
||||
fn Value new(Value th, Value *dest, Value type, AuintIdx len)
|
||||
{
|
||||
// Create an array object
|
||||
ArrInfo* val = (ArrInfo*)(mem::new(th as ArrEnc as sizeof(ArrInfo));
|
||||
@@ -24,7 +24,7 @@ func Value new(Value th, Value *dest, Value type, AuintIdx len)
|
||||
}
|
||||
|
||||
/* Return a new Array as allocating len slots for Values. */
|
||||
func Value newClosure(Value *th, Value *dest, Value type, AuintIdx len)
|
||||
fn Value newClosure(Value *th, Value *dest, Value type, AuintIdx len)
|
||||
{
|
||||
// Create an array object
|
||||
ArrInfo* val = (sizeof(ArrInfo), ArrInfo*)(mem::new(th as ArrEnc);
|
||||
@@ -38,25 +38,25 @@ func Value newClosure(Value *th, Value *dest, Value type, AuintIdx len)
|
||||
}
|
||||
|
||||
/* Return 1 if the value is an Array as otherwise 0 */
|
||||
func int Value.isArr(Value* val)
|
||||
fn int Value.isArr(Value* val)
|
||||
{
|
||||
return val.isEnc(ArrEnc);
|
||||
}
|
||||
|
||||
/* Return 1 if the value is an Array, otherwise 0 */
|
||||
func int Value.isClosure(Value* val)
|
||||
fn int Value.isClosure(Value* val)
|
||||
{
|
||||
return val.isEnc(ArrEnc) && arr_info(val)->flags1 & TypeClo;
|
||||
}
|
||||
|
||||
private func ArrInfo.fill(ArrInfo* a, AuintIdx start, AuintIdx end, Value value) @inline
|
||||
private fn ArrInfo.fill(ArrInfo* a, AuintIdx start, AuintIdx end, Value value) @inline
|
||||
{
|
||||
for (AuintIdx i = start; i < end; i++) a.arr[i] = value;
|
||||
}
|
||||
|
||||
/* Ensure array has room for len Values, allocating memory as needed.
|
||||
* Allocated space will not shrink. Changes nothing about array's contents. */
|
||||
func void makeRoom(Value th, Value arr, AuintIdx len)
|
||||
fn void makeRoom(Value th, Value arr, AuintIdx len)
|
||||
{
|
||||
ArrInfo* a = arr_info(arr);
|
||||
if (len > a.avail)
|
||||
@@ -71,7 +71,7 @@ func void makeRoom(Value th, Value arr, AuintIdx len)
|
||||
* Set the number of elements in the array, growing it if needed.
|
||||
* If less than current number array size, array is not shrunk.
|
||||
*/
|
||||
func void setSize(Value th, Value arr, AuintIdx len)
|
||||
fn void setSize(Value th, Value arr, AuintIdx len)
|
||||
{
|
||||
ArrInfo* a = arr_info(arr);
|
||||
AuintIdx size = arr_size(arr);
|
||||
@@ -84,7 +84,7 @@ func void setSize(Value th, Value arr, AuintIdx len)
|
||||
* or expanding as needed. Growth space is initialized to aNull.
|
||||
* @require val.isArr()
|
||||
*/
|
||||
func void forceSize(Value th, Value val, AuintIdx len)
|
||||
fn void forceSize(Value th, Value val, AuintIdx len)
|
||||
{
|
||||
ArrInfo *arr = arr_info(val);
|
||||
|
||||
@@ -105,7 +105,7 @@ func void forceSize(Value th, Value val, AuintIdx len)
|
||||
* Retrieve the value in array at specified position.
|
||||
* @require arr.isArr()
|
||||
*/
|
||||
func Value get(Value th, Value arr, AuintIdx pos)
|
||||
fn Value get(Value th, Value arr, AuintIdx pos)
|
||||
{
|
||||
ArrInfo* a = arr_info(arr);
|
||||
return pos >= a.size ? aNull : a.arr[pos];
|
||||
@@ -116,7 +116,7 @@ func Value get(Value th, Value arr, AuintIdx pos)
|
||||
* This can expand the size of the array.
|
||||
* @require arr.isArr()
|
||||
*/
|
||||
func void set(Value th, Value arr, AuintIdx pos, Value val)
|
||||
fn void set(Value th, Value arr, AuintIdx pos, Value val)
|
||||
{
|
||||
ArrInfo* a = arr_info(arr);
|
||||
|
||||
@@ -135,7 +135,7 @@ func void set(Value th, Value arr, AuintIdx pos, Value val)
|
||||
* Append val to the end of the array (increasing array's size).
|
||||
* @require arr.isArr()
|
||||
*/
|
||||
func void add(Value th, Value arr, Value val)
|
||||
fn void add(Value th, Value arr, Value val)
|
||||
{
|
||||
ArrInfo *a = arr_info(arr);
|
||||
AuintIdx sz = arr_size(arr);
|
||||
@@ -154,7 +154,7 @@ func void add(Value th, Value arr, Value val)
|
||||
* This can expand the size of the array.
|
||||
* @require arr.isArr()
|
||||
*/
|
||||
func void repeat(Value th, Value arr, AuintIdx pos, AuintIdx n, Value val)
|
||||
fn void repeat(Value th, Value arr, AuintIdx pos, AuintIdx n, Value val)
|
||||
{
|
||||
ArrInfo* a = arr_info(arr);
|
||||
|
||||
@@ -177,7 +177,7 @@ func void repeat(Value th, Value arr, AuintIdx pos, AuintIdx n, Value val)
|
||||
* All values after these are preserved, essentially shrinking the array.
|
||||
* @require arr.isArr()
|
||||
*/
|
||||
func void del(Value th, Value arr, AuintIdx pos, AuintIdx n)
|
||||
fn void del(Value th, Value arr, AuintIdx pos, AuintIdx n)
|
||||
{
|
||||
ArrInfo *a = arr_info(arr);
|
||||
|
||||
@@ -200,7 +200,7 @@ func void del(Value th, Value arr, AuintIdx pos, AuintIdx n)
|
||||
* Insert n copies of val into the array starting at pos, expanding the array's size.
|
||||
* @require arr.isArr()
|
||||
*/
|
||||
func void ins(Value th, Value arr, AuintIdx pos, AuintIdx n, Value val)
|
||||
fn void ins(Value th, Value arr, AuintIdx pos, AuintIdx n, Value val)
|
||||
{
|
||||
ArrInfo *a = arr_info(arr);
|
||||
|
||||
@@ -223,7 +223,7 @@ func void ins(Value th, Value arr, AuintIdx pos, AuintIdx n, Value val)
|
||||
* This can increase or decrease the size of the array. arr and arr2 may be the same array.
|
||||
* @require arr.isArr()
|
||||
*/
|
||||
func void sub(Value th, Value arr, AuintIdx pos, AuintIdx n, Value arr2, AuintIdx pos2, AuintIdx n2)
|
||||
fn void sub(Value th, Value arr, AuintIdx pos, AuintIdx n, Value arr2, AuintIdx pos2, AuintIdx n2)
|
||||
{
|
||||
ArrInfo *a = arr_info(arr);
|
||||
|
||||
@@ -250,7 +250,7 @@ func void sub(Value th, Value arr, AuintIdx pos, AuintIdx n, Value arr2, AuintId
|
||||
}
|
||||
|
||||
/* Serialize an array's contents to indented text */
|
||||
func void serialize(Value th, Value str, int indent, Value arr)
|
||||
fn void serialize(Value th, Value str, int indent, Value arr)
|
||||
{
|
||||
// TODO
|
||||
ArrInfo *a = arr_info(arr);
|
||||
|
||||
@@ -12,7 +12,7 @@ module acorn::mem;
|
||||
* - If ptr==NULL, it allocates a new uninitialized memory block
|
||||
* - Otherwise it changes the size of the memory block (and may move its location)
|
||||
* It returns the location of the new block or NULL (if freed). */
|
||||
func void* gcrealloc(Value th, void *block, Auint osize, Auint nsize)
|
||||
fn void* gcrealloc(Value th, void *block, Auint osize, Auint nsize)
|
||||
{
|
||||
// Check consistency of block and osize (both must be null or specified)
|
||||
Auint realosize = block ? osize : 0;
|
||||
@@ -51,7 +51,7 @@ func void* gcrealloc(Value th, void *block, Auint osize, Auint nsize)
|
||||
return newblock;
|
||||
}
|
||||
|
||||
func void* gcreallocv(Value th, void* block, Auint osize, Auint nsize, Auint esize)
|
||||
fn void* gcreallocv(Value th, void* block, Auint osize, Auint nsize, Auint esize)
|
||||
{
|
||||
// Ensure we are not asking for more memory than available in address space
|
||||
// If we do not do this, calculating the needed memory will overflow
|
||||
@@ -68,7 +68,7 @@ func void* gcreallocv(Value th, void* block, Auint osize, Auint nsize, Auint esi
|
||||
* - Otherwise it changes the size of the memory block (and may move its location)
|
||||
* It returns the location of the new block or NULL (if freed).
|
||||
**/
|
||||
func void* frealloc(void* block, Auint size)
|
||||
fn void* frealloc(void* block, Auint size)
|
||||
{
|
||||
if (!size)
|
||||
{
|
||||
@@ -113,7 +113,7 @@ MemInfo* new(Value th as int enc, Auint sz)
|
||||
* Create a new pointer object (with given encoding and size).
|
||||
* Caller must add itself to its own private list
|
||||
*/
|
||||
func MemInfo* newnolink(Value th, int enc, Auint sz)
|
||||
fn MemInfo* newnolink(Value th, int enc, Auint sz)
|
||||
{
|
||||
// Perform garbage collection before a memory allocation
|
||||
$if (defined(AVM_GCHARDMEMTEST))
|
||||
@@ -134,7 +134,7 @@ func MemInfo* newnolink(Value th, int enc, Auint sz)
|
||||
}
|
||||
|
||||
/* double size of vector array, up to limits */
|
||||
func void growaux_(Value th, void *block, AuintIdx *size, AuintIdx size_elems, AuintIdx limit)
|
||||
fn void growaux_(Value th, void *block, AuintIdx *size, AuintIdx size_elems, AuintIdx limit)
|
||||
{
|
||||
void* newblock;
|
||||
AuintIdx newsize = void;
|
||||
|
||||
@@ -25,7 +25,7 @@ import acorn::sym;
|
||||
***************************************/
|
||||
|
||||
/** Size of the method's stack area: base to top */
|
||||
func AintIdx stkSz(Value th) @inline
|
||||
fn AintIdx stkSz(Value th) @inline
|
||||
{
|
||||
return th(th).stk_top - th(th).curmethod.begin;
|
||||
}
|
||||
@@ -35,7 +35,7 @@ func AintIdx stkSz(Value th) @inline
|
||||
|
||||
/** Point to current method's stack value at position i.
|
||||
* For a method: i=0 is self, i=1 is first parameter, etc. */
|
||||
func void Value.at(Value* th, AintIdx i) @inline
|
||||
fn void Value.at(Value* th, AintIdx i) @inline
|
||||
{
|
||||
@assert_exp(i >= 0 && i < stkSz(th), "invalid stack index");
|
||||
return &th(*th).curmethod.begin[i];
|
||||
@@ -47,20 +47,20 @@ func void Value.at(Value* th, AintIdx i) @inline
|
||||
|
||||
/* Retrieve the stack value at the index. Be sure 0<= idx < top.
|
||||
* Good for getting method's parameters: 0=self, 1=parm 1, etc. */
|
||||
func Value Value.getLocal(Value *th, AintIdx idx)
|
||||
fn Value Value.getLocal(Value *th, AintIdx idx)
|
||||
{
|
||||
return *th.at(idx);
|
||||
}
|
||||
|
||||
/* Put the value on the stack at the designated position. Be sure 0<= idx < top. */
|
||||
func void Value.setLocal(Value th, AintIdx idx, Value val)
|
||||
fn void Value.setLocal(Value th, AintIdx idx, Value val)
|
||||
{
|
||||
*th.at(idx) = val;
|
||||
mem::markChk(th, th, val);
|
||||
}
|
||||
|
||||
/* Copy the stack value at fromidx into toidx */
|
||||
func void Value.copyLocal(Value* th, AintIdx toidx, AintIdx fromidx)
|
||||
fn void Value.copyLocal(Value* th, AintIdx toidx, AintIdx fromidx)
|
||||
{
|
||||
*th.at(toidx) = *th.at(fromidx);
|
||||
}
|
||||
@@ -69,7 +69,7 @@ func void Value.copyLocal(Value* th, AintIdx toidx, AintIdx fromidx)
|
||||
* Remove the value at index (shifting down all values above it to top)
|
||||
* @require stkSz(th) > 0
|
||||
*/
|
||||
func void Value.deleteLocal(Value* th, AintIdx idx)
|
||||
fn void Value.deleteLocal(Value* th, AintIdx idx)
|
||||
{
|
||||
Value* p = th.at(idx);
|
||||
memmove(p, p + 1, sizeof(Value)*(stkSz(th) - idx - 1));
|
||||
@@ -80,7 +80,7 @@ func void Value.deleteLocal(Value* th, AintIdx idx)
|
||||
* Insert the popped value into index (shifting up all values above it)
|
||||
* @require stkSz(th) > 0
|
||||
*/
|
||||
func void Value.insertLocal(Value *th, AintIdx idx)
|
||||
fn void Value.insertLocal(Value *th, AintIdx idx)
|
||||
{
|
||||
Value *p = th.at(idx);
|
||||
Value val = *(th(*th).stk_top - 1);
|
||||
@@ -94,7 +94,7 @@ func void Value.insertLocal(Value *th, AintIdx idx)
|
||||
***************************************/
|
||||
|
||||
/* Push a value on the stack's top */
|
||||
func Value Value.pushValue(Value* th, Value val)
|
||||
fn Value Value.pushValue(Value* th, Value val)
|
||||
{
|
||||
stkCanIncTop(th); /* Check if there is room */
|
||||
*th(*th).stk_top++ = val;
|
||||
@@ -103,14 +103,14 @@ func Value Value.pushValue(Value* th, Value val)
|
||||
}
|
||||
|
||||
/* Push and return the corresponding Symbol value for a 0-terminated c-string */
|
||||
func Value Value.pushSym(Value* th, string str)
|
||||
fn Value Value.pushSym(Value* th, string str)
|
||||
{
|
||||
stkCanIncTop(th); /* Check if there is room */
|
||||
return sym::newSym(*th, th(*th).stk_top++, str);
|
||||
}
|
||||
|
||||
/* Push and return the corresponding Symbol value for a byte sequence of specified length */
|
||||
func Value Value.pushSyml(Value th, string str)
|
||||
fn Value Value.pushSyml(Value th, string str)
|
||||
{
|
||||
stkCanIncTop(th); /* Check if there is room */
|
||||
return sym::newSym(*th, th(*th).stk_top++, str);
|
||||
@@ -319,7 +319,7 @@ void popSetActProp(Value th, AintIdx selfidx, const char *mbrnm) {
|
||||
}
|
||||
|
||||
/* Push a copy of a stack's value at index onto the stack's top */
|
||||
func Value Value.pushLocal(Value* th, AintIdx idx)
|
||||
fn Value Value.pushLocal(Value* th, AintIdx idx)
|
||||
{
|
||||
stkCanIncTop(th); /* Check if there is room */
|
||||
return *th(*th).stk_top++ = th.getLocal(idx);
|
||||
@@ -329,7 +329,7 @@ func Value Value.pushLocal(Value* th, AintIdx idx)
|
||||
* Pop a value off the top of the stack
|
||||
* @require stkSz(th) > 0
|
||||
*/
|
||||
func Value Value.popValue()
|
||||
fn Value Value.popValue()
|
||||
{
|
||||
return *--th(*th).stk_top;
|
||||
}
|
||||
@@ -338,7 +338,7 @@ func Value Value.popValue()
|
||||
* Pops the top value and writes it at idx. Often used to set return value
|
||||
* @require stkSz(th) > 0, idx >= 0, idx < stkSz(th) - 1
|
||||
*/
|
||||
func void Value.popLocal(Value* th, AintIdx idx)
|
||||
fn void Value.popLocal(Value* th, AintIdx idx)
|
||||
{
|
||||
th.setLocal(idx, *(th(*th).stk_top - 1));
|
||||
// Pop after value is safely in Global
|
||||
@@ -349,7 +349,7 @@ func void Value.popLocal(Value* th, AintIdx idx)
|
||||
* Retrieve the stack value at the index from top. Be sure 0<= idx < top.
|
||||
* @require idx >= 0, idx < stkSz(th)
|
||||
*/
|
||||
func Value Value.getFromTop(Value* th, AintIdx idx)
|
||||
fn Value Value.getFromTop(Value* th, AintIdx idx)
|
||||
{
|
||||
return *th.at(stkSz(th) - idx - 1);
|
||||
}
|
||||
@@ -357,7 +357,7 @@ func Value Value.getFromTop(Value* th, AintIdx idx)
|
||||
/**
|
||||
* Return number of values on the current method's stack
|
||||
*/
|
||||
func AuintIdx Value.getTop(Value* th)
|
||||
fn AuintIdx Value.getTop(Value* th)
|
||||
{
|
||||
return (AuintIdx)(stkSz(th));
|
||||
}
|
||||
@@ -367,7 +367,7 @@ func AuintIdx Value.getTop(Value* th)
|
||||
* This can shrink the stack or grow it (padding with 'null's).
|
||||
* A negative index removes that number of values off the top.
|
||||
*/
|
||||
func void Value.setTop(Value* th as AintIdx idx)
|
||||
fn void Value.setTop(Value* th as AintIdx idx)
|
||||
{
|
||||
// TODO
|
||||
Value *base = th(*th).curmethod.begin;
|
||||
@@ -388,14 +388,14 @@ func void Value.setTop(Value* th as AintIdx idx)
|
||||
}
|
||||
|
||||
/* ****************************************
|
||||
GLOBAL VARIABLE ACCESS
|
||||
VARIABLE ACCESS
|
||||
***************************************/
|
||||
|
||||
/**
|
||||
* Push and return the symbolically-named global variable's value
|
||||
* Push and return the symbolically-named variable's value
|
||||
* @require vm(*th).global.isTbl()
|
||||
**/
|
||||
func Value Value.pushGloVar(Value* th, string var)
|
||||
fn Value Value.pushGloVar(Value* th, string var)
|
||||
{
|
||||
// Check if there is room
|
||||
stkCanIncTop(th);
|
||||
@@ -405,10 +405,10 @@ func Value Value.pushGloVar(Value* th, string var)
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter the symbolically-named global variable to have the value popped off the local stack
|
||||
* Alter the symbolically-named variable to have the value popped off the local stack
|
||||
* @require stkSz(th) > 0, vm(th).global.isTbl()
|
||||
**/
|
||||
func void Value.popGloVar(Value* th, string var)
|
||||
fn void Value.popGloVar(Value* th, string var)
|
||||
{
|
||||
// Check if there is room
|
||||
stkCanIncTop(th);
|
||||
@@ -417,7 +417,7 @@ func void Value.popGloVar(Value* th, string var)
|
||||
th(*th).stk_top -= 2; // Pop key & value after value is safely in Global
|
||||
}
|
||||
|
||||
/* Push the value of the current process thread's global variable table. */
|
||||
/* Push the value of the current process thread's variable table. */
|
||||
Value pushGlobal(Value th)
|
||||
{
|
||||
stkCanIncTop(th); /* Check if there is room */
|
||||
@@ -428,7 +428,7 @@ Value pushGlobal(Value th)
|
||||
* Internal function to re-allocate stack's size
|
||||
* @require newsize <= STACK_MAXSIZE || newsize == STACK_ERRORSIZE
|
||||
**/
|
||||
func void realloc(Value th, int newsize)
|
||||
fn void realloc(Value th, int newsize)
|
||||
{
|
||||
// Incremental GC before memory allocation events
|
||||
mem::gccheck(th);
|
||||
|
||||
@@ -381,7 +381,7 @@ void genAssign(CompInfo *comp, Value lval, Value rval) {
|
||||
if (opcode)
|
||||
genDoProp(comp, lval, opcode, rval, 1);
|
||||
else {
|
||||
// Handle parallel, local, closure, global variable assignments where rval is loaded first
|
||||
// Handle parallel, local, closure, variable assignments where rval is loaded first
|
||||
int nlvals = lvalop==vmlit(SymComma)? arr_size(lval)-1 : 1;
|
||||
bool varrvals = false;
|
||||
AuintIdx rvalreg;
|
||||
@@ -445,7 +445,7 @@ void genAssign(CompInfo *comp, Value lval, Value rval) {
|
||||
genAddInstr(comp, BCINS_ABC(OpLoadReg, localreg, rvalreg, 0));
|
||||
else if ((localreg = findClosureVar(comp, symnm))!=-1)
|
||||
genAddInstr(comp, BCINS_ABC(OpSetClosure, localreg, rvalreg, 0));
|
||||
// Load into a global variable
|
||||
// Load into a variable
|
||||
} else if (vmlit(SymGlobal) == lvalop)
|
||||
genAddInstr(comp, BCINS_ABx(OpSetGlobal, rvalreg, genAddLit(comp, astGet(th, lval, 1))));
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ module acorn::lex;
|
||||
/**
|
||||
* Crude algorithm for determining if character is a Unicode letter
|
||||
*/
|
||||
func bool isualpha(Auchar c) @inline
|
||||
fn bool isualpha(Auchar c) @inline
|
||||
{
|
||||
return c > 0xA0 || isalpha(c);
|
||||
}
|
||||
@@ -20,7 +20,7 @@ func bool isualpha(Auchar c) @inline
|
||||
/**
|
||||
* Algorithm for determining if character is a digit 0-9
|
||||
*/
|
||||
func bool isudigit(Auchar c) @inline
|
||||
fn bool isudigit(Auchar c) @inline
|
||||
{
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
@@ -28,7 +28,7 @@ func bool isudigit(Auchar c) @inline
|
||||
/**
|
||||
* Return a new LexInfo value, lexer context for a source program
|
||||
*/
|
||||
func Value new(Value th, Value *dest, Value src, Value url)
|
||||
fn Value new(Value th, Value *dest, Value src, Value url)
|
||||
{
|
||||
LexInfo *lex;
|
||||
|
||||
@@ -60,7 +60,7 @@ func Value new(Value th, Value *dest, Value src, Value url)
|
||||
}
|
||||
|
||||
/** Return the current unicode character whose UTF-8 bytes start at lex->bytepos */
|
||||
func Auchar LexInfo.thischar(LexInfo* lex)
|
||||
fn Auchar LexInfo.thischar(LexInfo* lex)
|
||||
{
|
||||
byte *src = &toStr(lex.source)[lex.bytepos];
|
||||
int nbytes;
|
||||
@@ -83,7 +83,7 @@ func Auchar LexInfo.thischar(LexInfo* lex)
|
||||
}
|
||||
|
||||
/** Return the current unicode character whose UTF-8 bytes start at lex->bytepos */
|
||||
func Auchar LexInfo.nextchar(LexInfo* lex)
|
||||
fn Auchar LexInfo.nextchar(LexInfo* lex)
|
||||
{
|
||||
const char *src = &toStr(lex->source)[lex->bytepos];
|
||||
int nbytes;
|
||||
@@ -114,7 +114,7 @@ func Auchar LexInfo.nextchar(LexInfo* lex)
|
||||
}
|
||||
|
||||
/** Skip lex->bytepos past the unicode character whose UTF-8 bytes start at lex->bytepos */
|
||||
func void LexInfo.skipchar(LexInfo* lex)
|
||||
fn void LexInfo.skipchar(LexInfo* lex)
|
||||
{
|
||||
const char *src = &toStr(lex->source)[lex->bytepos];
|
||||
int nbytes;
|
||||
@@ -137,7 +137,7 @@ func void LexInfo.skipchar(LexInfo* lex)
|
||||
|
||||
/** Scan past non-tokenized white space.
|
||||
* Handle line indentation and continuation */
|
||||
func bool LexInfo.scanWhite(LexInfo *lex)
|
||||
fn bool LexInfo.scanWhite(LexInfo *lex)
|
||||
{
|
||||
Value th = lex.th; // for vmlit
|
||||
|
||||
@@ -160,9 +160,10 @@ func bool LexInfo.scanWhite(LexInfo *lex)
|
||||
// Skip past spaces and tabs
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
lex_skipchar(lex);
|
||||
break;
|
||||
case '\r':
|
||||
UNREACHABLE
|
||||
|
||||
// Skip past new line
|
||||
case '\n':
|
||||
@@ -628,7 +629,7 @@ bool lexScanOp(LexInfo *lex) {
|
||||
}
|
||||
|
||||
/* Get the next token */
|
||||
func void LexInfo.getNextToken(LexInfo *lex)
|
||||
fn void LexInfo.getNextToken(LexInfo *lex)
|
||||
{
|
||||
|
||||
// Scan until we find a token
|
||||
|
||||
@@ -2,7 +2,7 @@ module acornvm::compiler;
|
||||
|
||||
|
||||
/* Return a new CompInfo value, compiler state for an Acorn method */
|
||||
func Value new_compiler(Value th, Value *dest, Value src, Value url)
|
||||
fn Value new_compiler(Value th, Value *dest, Value src, Value url)
|
||||
{
|
||||
CompInfo *comp;
|
||||
|
||||
@@ -53,7 +53,7 @@ func Value new_compiler(Value th, Value *dest, Value src, Value url)
|
||||
- pgmsrc: CompInfo or Text string containing the program source
|
||||
- baseurl: a symbol or null
|
||||
It returns the compiled byte-code method. */
|
||||
func int acn_newmethod(Value th)
|
||||
fn int acn_newmethod(Value th)
|
||||
{
|
||||
// Retrieve pgmsrc and baseurl from parameters
|
||||
Value pgmsrc as baseurl;
|
||||
|
||||
@@ -29,7 +29,7 @@ int genAddUrlLit(CompInfo *comp, Value val) {
|
||||
}
|
||||
|
||||
/* Add a method literal and return its index */
|
||||
func int CompInfo.genAddMethodLit(CompInfo *comp, Value val)
|
||||
fn int CompInfo.genAddMethodLit(CompInfo *comp, Value val)
|
||||
{
|
||||
BMethodInfo* f = comp.method;
|
||||
mem_growvector(comp->th, f->lits, f->nbrlits, f->litsz, Value, INT_MAX);
|
||||
@@ -50,7 +50,7 @@ int findBlockVar(Value th, Value locvars, Value varnm)
|
||||
}
|
||||
|
||||
/* Look for local variable. Returns idx if found, -1 otherwise. */
|
||||
func int CompInfo.findLocalVar(CompInfo *comp, Value varnm) throws SearchError
|
||||
fn int CompInfo.findLocalVar(CompInfo *comp, Value varnm) throws SearchError
|
||||
{
|
||||
assert(varnm.isSym());
|
||||
|
||||
@@ -72,7 +72,7 @@ func int CompInfo.findLocalVar(CompInfo *comp, Value varnm) throws SearchError
|
||||
}
|
||||
|
||||
/* Look for closure variable. Returns idx if found, -1 otherwise. */
|
||||
func int CompInfo.findClosureVar(CompInfo *comp, Value varnm)
|
||||
fn int CompInfo.findClosureVar(CompInfo *comp, Value varnm)
|
||||
{
|
||||
assert(varnm.isSym());
|
||||
|
||||
@@ -112,7 +112,7 @@ void CompInfo.declareLocal(CompInfo *comp, Value varnm)
|
||||
|
||||
/** Create and return new Closure AST segment
|
||||
Modifies comp->clovarseg and -> newcloseg */
|
||||
func Value parseNewClo(CompInfo* comp, Value astseg)
|
||||
fn Value parseNewClo(CompInfo* comp, Value astseg)
|
||||
{
|
||||
Value th = comp->th;
|
||||
// ('Closure', clovars, ('callprop', Closure, New, getmethod, setmethod))
|
||||
@@ -143,7 +143,7 @@ void parseValue(CompInfo* comp, Value astseg)
|
||||
astAddSeg2(th, astseg, vmlit(SYM_EXT), anInt(genAddUrlLit(comp, comp->lex->token)));
|
||||
lexGetNextToken(comp->lex);
|
||||
}
|
||||
// Local or global variable / name token
|
||||
// Local or variable / name token
|
||||
else if (comp->lex->toktype == Name_Token) {
|
||||
Value symnm = pushValue(th, comp->lex->token);
|
||||
lexGetNextToken(comp->lex);
|
||||
@@ -240,7 +240,7 @@ void parseValue(CompInfo* comp, Value astseg)
|
||||
Value symnm = comp->lex->token;
|
||||
const char first = (toStr(symnm))[0];
|
||||
if (first=='$' || (first>='A' && first<='Z'))
|
||||
lexLog(comp->lex, "A global name may not be a closure variable");
|
||||
lexLog(comp->lex, "A name may not be a closure variable");
|
||||
arrAdd(th, comp->clovarseg, symnm);
|
||||
lexGetNextToken(comp->lex);
|
||||
|
||||
@@ -289,7 +289,7 @@ void parseValue(CompInfo* comp, Value astseg)
|
||||
}
|
||||
|
||||
/** Add a list of parameters to a AST propseg */
|
||||
func void CompInfo.parseParams(CompInfo* comp, Value propseg, const char *closeparen)
|
||||
fn void CompInfo.parseParams(CompInfo* comp, Value propseg, const char *closeparen)
|
||||
{
|
||||
bool saveforcelocal = comp->forcelocal;
|
||||
comp->forcelocal = false;
|
||||
@@ -434,7 +434,7 @@ void parsePrefixExp(CompInfo* comp, Value astseg) {
|
||||
}
|
||||
|
||||
/** Parse the '**' operator */
|
||||
func void CompInfo.parsePowerExp(CompInfo* comp, Value astseg)
|
||||
fn void CompInfo.parsePowerExp(CompInfo* comp, Value astseg)
|
||||
{
|
||||
Value th = comp.th;
|
||||
comp.parsePrefixExp(astseg);
|
||||
@@ -448,7 +448,7 @@ func void CompInfo.parsePowerExp(CompInfo* comp, Value astseg)
|
||||
}
|
||||
|
||||
/** Parse the '*', '/' or '%' binary operator */
|
||||
func void CompInfo.parseMultDivExp(CompInfo* comp inline, Value astseg)
|
||||
fn void CompInfo.parseMultDivExp(CompInfo* comp inline, Value astseg)
|
||||
{
|
||||
Value th = comp.th;
|
||||
parsePowerExp(astseg);
|
||||
@@ -461,7 +461,7 @@ func void CompInfo.parseMultDivExp(CompInfo* comp inline, Value astseg)
|
||||
}
|
||||
|
||||
/** Parse the '+' or '-' binary operator */
|
||||
func void CompInfo.parseAddSubExp(CompInfo* comp, Value astseg)
|
||||
fn void CompInfo.parseAddSubExp(CompInfo* comp, Value astseg)
|
||||
{
|
||||
Value th = comp.th;
|
||||
comp.parseMultDivExp(astseg);
|
||||
@@ -474,7 +474,7 @@ func void CompInfo.parseAddSubExp(CompInfo* comp, Value astseg)
|
||||
}
|
||||
|
||||
/** Parse the range .. constructor operator */
|
||||
func void CompInfo.parseRangeExp(CompInfo* comp, Value astseg)
|
||||
fn void CompInfo.parseRangeExp(CompInfo* comp, Value astseg)
|
||||
{
|
||||
Value th = comp.th;
|
||||
comp.parseAddSubExp(astseg);
|
||||
@@ -494,7 +494,7 @@ func void CompInfo.parseRangeExp(CompInfo* comp, Value astseg)
|
||||
}
|
||||
|
||||
/** Parse the comparison operators */
|
||||
func void CompInfo.parseCompExp(CompInfo* comp, Value astseg) {
|
||||
fn void CompInfo.parseCompExp(CompInfo* comp, Value astseg) {
|
||||
Value th = comp.th;
|
||||
comp.parseRangeExp(astseg);
|
||||
Value op = comp.lex->token;
|
||||
@@ -514,7 +514,7 @@ func void CompInfo.parseCompExp(CompInfo* comp, Value astseg) {
|
||||
}
|
||||
|
||||
/* Parse 'not' conditional logic operator */
|
||||
func void CompInfo.parseNotExp(CompInfo* comp, Value astseg)
|
||||
fn void CompInfo.parseNotExp(CompInfo* comp, Value astseg)
|
||||
{
|
||||
Value th = comp.th;
|
||||
bool takenot = false;
|
||||
@@ -530,13 +530,13 @@ func void CompInfo.parseNotExp(CompInfo* comp, Value astseg)
|
||||
}
|
||||
}
|
||||
|
||||
func bool CompInfo.matchNext(CompInfo *comp, string s) @inline
|
||||
fn bool CompInfo.matchNext(CompInfo *comp, string s) @inline
|
||||
{
|
||||
return comp.lex.matchNext(s);
|
||||
}
|
||||
|
||||
/* Parse 'and' conditional logic operator */
|
||||
func void CompInfo.parseAndExp(CompInfo* comp, Value astseg)
|
||||
fn void CompInfo.parseAndExp(CompInfo* comp, Value astseg)
|
||||
{
|
||||
Value th = comp.th;
|
||||
comp.parseNotExp(astseg);
|
||||
@@ -985,7 +985,7 @@ void parseProgram(CompInfo* comp) {
|
||||
Value symnm = comp->lex->token;
|
||||
const char first = (toStr(symnm))[0];
|
||||
if (first=='$' || (first>='A' && first<='Z'))
|
||||
lexLog(comp->lex, "A global name may not be a method parameter");
|
||||
lexLog(comp->lex, "A name may not be a method parameter");
|
||||
else {
|
||||
if (findLocalVar(comp, symnm)==-1) {
|
||||
arrAdd(th, comp->locvarseg, symnm);
|
||||
|
||||
@@ -16,19 +16,19 @@ import acorn::arr;
|
||||
* **********************/
|
||||
|
||||
/** Append a value to AST segment - growing as needed */
|
||||
func void addValue(Value th, Value astseg, Value val) @inline
|
||||
fn void addValue(Value th, Value astseg, Value val) @inline
|
||||
{
|
||||
arr::add(th, astseg, val);
|
||||
}
|
||||
|
||||
/** Get a value within the AST segment */
|
||||
func Value get(Value th, Value astseg, AuintIdx idx) @inline
|
||||
fn Value get(Value th, Value astseg, AuintIdx idx) @inline
|
||||
{
|
||||
return arr::get(th, astseg, idx);
|
||||
}
|
||||
|
||||
/** Set a value within the AST segment */
|
||||
func void set(Value th, Value astseg, AuintIdx idx, Value val)
|
||||
fn void set(Value th, Value astseg, AuintIdx idx, Value val)
|
||||
{
|
||||
arr::set(th, astseg, idx, val);
|
||||
}
|
||||
@@ -123,7 +123,7 @@ void popNew(Value th, Value oldseg, Value newseg)
|
||||
}
|
||||
|
||||
/** Return true if ast segment can be assigned a value: variable or settable property/method */
|
||||
func bool isLval(Value th, Value astseg)
|
||||
fn bool isLval(Value th, Value astseg)
|
||||
{
|
||||
if (!astseg.isArr()) return false;
|
||||
Value op = get(th, astseg, 0);
|
||||
|
||||
@@ -8,7 +8,7 @@ macro @hash_binmod(s, size)
|
||||
}
|
||||
|
||||
/** Resize the symbol table */
|
||||
func void resizeTable(Value th as Auint newsize)
|
||||
fn void resizeTable(Value th as Auint newsize)
|
||||
{
|
||||
SymTable* sym_tbl = &vm(th)->sym_table;
|
||||
Auint i;
|
||||
@@ -48,7 +48,7 @@ func void resizeTable(Value th as Auint newsize)
|
||||
}
|
||||
|
||||
/** Initialize the symbol table that hash indexes all symbols */
|
||||
func void init(Value th)
|
||||
fn void init(Value th)
|
||||
{
|
||||
SymTable* sym_tbl = &vm(th).sym_table;
|
||||
sym_tbl.nbrAvail = 0;
|
||||
@@ -67,7 +67,7 @@ void free(Value th)
|
||||
|
||||
/* If symbol exists in symbol table, reuse it. Otherwise, add it.
|
||||
Anchor (store) symbol value in dest and return it. */
|
||||
func Value newSym(Value th, Value* dest, string str, AuintIdx len)
|
||||
fn Value newSym(Value th, Value* dest, string str, AuintIdx len)
|
||||
{
|
||||
SymInfo* sym;
|
||||
SymTable* sym_tbl = &vm(th)->sym_table;
|
||||
@@ -101,7 +101,7 @@ func Value newSym(Value th, Value* dest, string str, AuintIdx len)
|
||||
}
|
||||
|
||||
/* Return 1 if the value is a Symbol, otherwise 0 */
|
||||
func int Value.isSym(Value *sym) @inline
|
||||
fn int Value.isSym(Value *sym) @inline
|
||||
{
|
||||
return sym.isEnc(SymEnc);
|
||||
}
|
||||
@@ -120,7 +120,7 @@ int isGlobal(Value sym)
|
||||
* This can be used to sequentially iterate through the symbol table.
|
||||
* Results may be inaccurate if the symbol table is changed during iteration.
|
||||
*/
|
||||
func Value next(Value th, Value key)
|
||||
fn Value next(Value th, Value key)
|
||||
{
|
||||
SymTable *sym_tbl = &th(th)->vm->sym_table;
|
||||
SymInfo *sym;
|
||||
|
||||
@@ -48,7 +48,7 @@ typedef void* as distinct Value
|
||||
/** Prototype for a C method callable by the VM.
|
||||
It is passed the thread, through which it obtains parameters via the data stack.
|
||||
When done, it returns how many return values it has placed on the stack. */
|
||||
typedef func int(Value) as AcMethodp;
|
||||
typedef fn int(Value) as AcMethodp;
|
||||
|
||||
/** Quick, exact equivalence check between two values ('===')
|
||||
* Great for null, false, true, integers and symbols.
|
||||
@@ -73,7 +73,7 @@ const int VAL_MASK = 0x3;
|
||||
const int VAL_SHIFT = 2;
|
||||
|
||||
|
||||
func bool Value.isEnc(Value *value, EncType type) @inline
|
||||
fn bool Value.isEnc(Value *value, EncType type) @inline
|
||||
{
|
||||
return value.isPtr() && @cast(value as MemInfo*).enctyp == type;
|
||||
}
|
||||
@@ -93,7 +93,7 @@ macro isType(v, ValBits e)
|
||||
|
||||
|
||||
/** Is v an Integer? */
|
||||
func bool Value.isInt(Value *v)
|
||||
fn bool Value.isInt(Value *v)
|
||||
{
|
||||
return @isType(*v as INT);
|
||||
}
|
||||
@@ -116,7 +116,7 @@ macro toAint(v)
|
||||
// Float value functions
|
||||
|
||||
/** Is v a Float? */
|
||||
func Value.isFloat(Value *v)
|
||||
fn Value.isFloat(Value *v)
|
||||
{
|
||||
return @isType(*v as FLOAT);
|
||||
}
|
||||
@@ -157,7 +157,7 @@ macro aTrue()
|
||||
* Is value null?
|
||||
* @require value != null
|
||||
*/
|
||||
func bool Value.isNull(Value *value) @inline
|
||||
fn bool Value.isNull(Value *value) @inline
|
||||
{
|
||||
return *v == aNull;
|
||||
}
|
||||
@@ -166,7 +166,7 @@ func bool Value.isNull(Value *value) @inline
|
||||
* Is value false or null?
|
||||
* @require value != null
|
||||
*/
|
||||
func bool Value.isFalse(Value *value) @inline
|
||||
fn bool Value.isFalse(Value *value) @inline
|
||||
{
|
||||
return *v == aFalse || *v == aNull;
|
||||
}
|
||||
@@ -174,7 +174,7 @@ func bool Value.isFalse(Value *value) @inline
|
||||
/**
|
||||
* Is value true or false?
|
||||
*/
|
||||
func bool Value.isBool(Value *value) @inline
|
||||
fn bool Value.isBool(Value *value) @inline
|
||||
{
|
||||
return *v >= aFalse;
|
||||
}
|
||||
@@ -183,7 +183,7 @@ func bool Value.isBool(Value *value) @inline
|
||||
// Pointer functions.
|
||||
|
||||
/** Is value a pointer? */
|
||||
func bool Value.isPtr(Value *value) @inline
|
||||
fn bool Value.isPtr(Value *value) @inline
|
||||
{
|
||||
return @isType(*v as POINTER);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ void core_init(Value th); // Initialize all core types
|
||||
* different encoding types.
|
||||
* - The symbol table, which is shared across everywhere
|
||||
* - The main thread, which is the recursive root for garbage collection.
|
||||
* The thread manages the global namespace, including all registered
|
||||
* The thread manages the namespace, including all registered
|
||||
* core types (including the Acorn compiler and resource types).
|
||||
*
|
||||
* See newVm() for more detailed information on VM initialization.
|
||||
@@ -34,12 +34,12 @@ struct VmInfo
|
||||
ulong pcgrng_state; //!< PCG random-number generator state
|
||||
ulong pcgrng_inc; //!< PCG random-number generator inc value
|
||||
|
||||
Value global; //!< VM's "built in" Global hash table
|
||||
Value global; //!< VM's "built in" hash table
|
||||
|
||||
Value main_thread; //!< VM's main thread
|
||||
ThreadInfo main_thr; //!< State space for main thread
|
||||
|
||||
SymTable sym_table; //!< global symbol table
|
||||
SymTable sym_table; //!< symbol table
|
||||
AuintIdx hashseed; //!< randomized seed for hashing strings
|
||||
Value literals; //!< array of all built-in symbol and type literals
|
||||
Value stdidx; //!< Table to convert std symbol to index
|
||||
@@ -252,10 +252,10 @@ macro memcpy_Auint(i, val)
|
||||
* and which to discard.
|
||||
* - All value encodings are initialized next, including the single symbol table
|
||||
* used across the VM.
|
||||
* - The main thread is started up, initializing its global namespace.
|
||||
* - The main thread is started up, initializing its namespace.
|
||||
* - All core types are progressively loaded, establishing the default types for
|
||||
* each encoding. This includes the resource types and Acorn compiler. */
|
||||
func Value new(void)
|
||||
fn Value new(void)
|
||||
{
|
||||
logInfo(AVM_RELEASE " started.");
|
||||
|
||||
@@ -290,13 +290,13 @@ func Value new(void)
|
||||
memcpy_Auint(3, &newVM) // public function
|
||||
vm->hashseed = tblCalcStrHash(seedstr, sizeof(seedstr), (AuintIdx) timehash);
|
||||
|
||||
// Initialize vm-wide symbol table, global table and literals
|
||||
// Initialize vm-wide symbol table, table and literals
|
||||
sym_init(th); // Initialize hash table for symbols
|
||||
newTbl(th, &vm->global, aNull, GLOBAL_NEWSIZE); // Create global hash table
|
||||
newTbl(th, &vm->global, aNull, GLOBAL_NEWSIZE); // Create hash table
|
||||
mem_markChk(th, vm, vm->global);
|
||||
vm_litinit(th); // Load reserved and standard symbols into literal list
|
||||
core_init(th); // Load up global table and literal list with core types
|
||||
setType(th, vm->global, vmlit(TypeIndexm)); // Fix up type info for global table
|
||||
core_init(th); // Load up table and literal list with core types
|
||||
setType(th, vm->global, vmlit(TypeIndexm)); // Fix up type info for table
|
||||
|
||||
// Initialize byte-code standard methods and the Acorn compiler
|
||||
vm_stdinit(th);
|
||||
@@ -352,7 +352,7 @@ float vmEndTimer(int64_t starttime)
|
||||
}
|
||||
$else
|
||||
{
|
||||
func int64_t vmStartTimer()
|
||||
fn int64_t vmStartTimer()
|
||||
{
|
||||
TimeVal start;
|
||||
start.gettimeofday();
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
module binarydigits;
|
||||
|
||||
func int main()
|
||||
{
|
||||
fot (int i = 0; i < 20; i++)
|
||||
{
|
||||
printf("%s\n", bin(i));
|
||||
}
|
||||
}
|
||||
|
||||
func string bin(int x)
|
||||
{
|
||||
int bits = (x == 0) ? 1 : log10((double)(x)) / log10(2);
|
||||
string ret = str.make_repeat('0' as bits);
|
||||
for (int i = 0; i < bits; i++)
|
||||
{
|
||||
ret[bits - i - 1] = x & 1 ? '1' : '0';
|
||||
x >>= 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
module functions;
|
||||
|
||||
module vararray(Type)
|
||||
|
||||
struct VarArray
|
||||
{
|
||||
uint capacity;
|
||||
uint size;
|
||||
Type* type;
|
||||
}
|
||||
|
||||
VarArray* make(uint size = startingSize)
|
||||
{
|
||||
VarArray *array = malloc(VarArray.size);
|
||||
array.capacity = startingSize;
|
||||
array.size = 0;
|
||||
array.type = startingSize > 0 ? malloc(Type.size * startingSize) : null;
|
||||
return array;
|
||||
}
|
||||
|
||||
generic Type[].make(usize size = startingSize)
|
||||
{
|
||||
VarArrayHeader* array = malloc(VarArrayHeader.size + Type.size * startingSize);
|
||||
array.capacity = startingSize;
|
||||
array.size = 0;
|
||||
return (Type[])(array[1]);
|
||||
}
|
||||
|
||||
macro Type Type[].@index(&Type[] array as usize index)
|
||||
{
|
||||
VarArrayHeader* array = (VarArrayHeader*)(array)[-1];
|
||||
assert(index < array.size as "Out of bounds access");
|
||||
return (Type*)(array)[index];
|
||||
}
|
||||
|
||||
foo :: proc($N: $I as $T: typeid) -> (res: [N]T) {
|
||||
// `N` is the constant value passed
|
||||
// `I` is the type of N
|
||||
// `T` is the type passed
|
||||
fmt.printf("Generating an array of type %v from the value %v of type %v\n",
|
||||
typeid_of(type_of(res)), N, typeid_of(I));
|
||||
for i in 0..<N {
|
||||
res[i] = i*i;
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -4,7 +4,7 @@ module globals;
|
||||
const string CLICK_ME = "Click Me";
|
||||
var uint counter = 0;
|
||||
|
||||
func void clickedme(GtkButton *o, void *d)
|
||||
fn void clickedme(GtkButton *o, void *d)
|
||||
{
|
||||
(GtkLabel*)(d).set_text(string.format("You clicked me %d times", ++counter));
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import curl;
|
||||
|
||||
func int main(void)
|
||||
fn int main(void)
|
||||
{
|
||||
Curl curl;
|
||||
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
module levenshtein;
|
||||
|
||||
func int levenshtein(String s, String t)
|
||||
{
|
||||
// if either string is empty, difference is inserting all chars
|
||||
// from the other
|
||||
if (!s.len()) return t.len();
|
||||
if (!t.len()) return s.len();
|
||||
|
||||
// if last letters are the same, the difference is whatever is
|
||||
// required to edit the rest of the strings
|
||||
if (s[^1] == t[^1]) return levenshtein(s[0..^2], t[0..^2]);
|
||||
|
||||
// else try:
|
||||
// changing last letter of s to that of t; or
|
||||
// remove last letter of s; or
|
||||
// remove last letter of t,
|
||||
// any of which is 1 edit plus editing the rest of the strings
|
||||
int a = levenshtein(s[0..^2], t[0..^2]);
|
||||
int b = levenshtein(s, t[0..^2]);
|
||||
int c = levenshtein(s[0..^2], t);
|
||||
|
||||
return @max(@max(a, b), c) + 1;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
module madlibs;
|
||||
import regex, stdio;
|
||||
|
||||
func void main()
|
||||
fn void main()
|
||||
{
|
||||
println("Enter a story template, terminated by an empty line:");
|
||||
String story = "";
|
||||
@@ -14,7 +14,7 @@ func void main()
|
||||
|
||||
Regex r;
|
||||
|
||||
r.initWithOptions("<.+?>", RegexOpt.GLOBAL) else @unreachable;
|
||||
r.initWithOptions("<.+?>", RegexOpt.GLOBAL) else unreachable;
|
||||
defer r.destroy();
|
||||
|
||||
foreach (RegexMatch* match : r.match(story))
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
module map(Key, Type);
|
||||
module std::container::map <Key, Type>;
|
||||
|
||||
fault MapResult
|
||||
{
|
||||
KEY_NOT_FOUND
|
||||
}
|
||||
|
||||
public struct Entry
|
||||
{
|
||||
Key key;
|
||||
Type* value;
|
||||
Type value;
|
||||
usize hash;
|
||||
Entry* next;
|
||||
}
|
||||
@@ -13,34 +18,37 @@ public struct Map
|
||||
usize size;
|
||||
void* map;
|
||||
uint mod;
|
||||
Allocator allocator;
|
||||
}
|
||||
|
||||
public func Map* Map.init(Map *map)
|
||||
/**
|
||||
* @require map != null
|
||||
**/
|
||||
public fn void Map.init(Map *map, Allocator allocator)
|
||||
{
|
||||
*map = { };
|
||||
return map;
|
||||
map.allocator = allocator;
|
||||
}
|
||||
|
||||
public func Type* Map.valueForKey(Map *map, Key key)
|
||||
public fn Type! Map.valueForKey(Map *map, Key key)
|
||||
{
|
||||
if (!map.map) return nil;
|
||||
if (!map.map) return null;
|
||||
usize hash = key.hash();
|
||||
usize pos = hash & map.mod;
|
||||
Entry* entry = &map.map[pop];
|
||||
if () return nil;
|
||||
if (!entry) return MapResult.KEY_NOT_FOUND!;
|
||||
while (entry)
|
||||
{
|
||||
if (entry.hash == hash && entry.key == key) return entry.value;
|
||||
entry = entry.next;
|
||||
}
|
||||
return nil;
|
||||
return MapResult.KEY_NOT_FOUND!;
|
||||
}
|
||||
|
||||
public func Type *Map.setValueForKey(Map *map, Key key, Type *value)
|
||||
public fn Type *Map.set(Map *map, Key key, Type value)
|
||||
{
|
||||
if (!map.map)
|
||||
{
|
||||
map.map = @calloc(Entry, 16);
|
||||
map.map = allocator.calloc(Entry, 16);
|
||||
map.mod = 0x0F;
|
||||
}
|
||||
|
||||
@@ -66,42 +74,14 @@ public func Type *Map.setValueForKey(Map *map, Key key, Type *value)
|
||||
{
|
||||
entry = entry.next;
|
||||
}
|
||||
entry.next = @malloc(Entry);
|
||||
entry.next = allocator.alloc(Entry);
|
||||
entry = entry.next;
|
||||
}
|
||||
}
|
||||
|
||||
public func usize Map.size(Vector *vector)
|
||||
public fn usize Map.size(Map* map)
|
||||
{
|
||||
return vector.array.size;
|
||||
return map.size;
|
||||
}
|
||||
|
||||
public func void Map.removeLast(Vector *vector)
|
||||
{
|
||||
vector.array.pop();
|
||||
}
|
||||
|
||||
public macro Vector.foreach(Vector *vector, macro void(Type value) body)
|
||||
{
|
||||
for (usize i = 0, i < vector.array.size; i++)
|
||||
{
|
||||
@body(vector.array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
test
|
||||
{
|
||||
define IntVector = Vector(int);
|
||||
IntVector vector = vector.init();
|
||||
vector.add(1);
|
||||
vector.add(2);
|
||||
for (int i : vector)
|
||||
{
|
||||
printDigit(i);
|
||||
}
|
||||
@vector.foreach(int i)
|
||||
{
|
||||
printDigit(i);
|
||||
}
|
||||
vector.destroy();
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
module test;
|
||||
|
||||
|
||||
public macro retry(#function, int retries = 3)
|
||||
{
|
||||
error e;
|
||||
while (1)
|
||||
{
|
||||
auto! result = #function;
|
||||
try (result) return result;
|
||||
catch (e = result);
|
||||
} while (retries-- > 0)
|
||||
return e!;
|
||||
}
|
||||
|
||||
func void main()
|
||||
{
|
||||
int! result = @retry(eventually_succeed());
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
public test;
|
||||
|
||||
/**
|
||||
* @require parse(a = b), parse(b = a)
|
||||
*/
|
||||
public macro void swap(&a, &b)
|
||||
{
|
||||
typeof(a) temp = a;
|
||||
a = b;
|
||||
b = temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require parse(a = b), parse(b = a)
|
||||
*/
|
||||
public macro void swap2(auto &a, auto &b)
|
||||
{
|
||||
auto temp = a;
|
||||
a = b;
|
||||
b = temp;
|
||||
}
|
||||
@@ -1,13 +1,12 @@
|
||||
module test;
|
||||
import std::time;
|
||||
import std::io;
|
||||
|
||||
public macro timeit(#call)
|
||||
{
|
||||
Time t = time::current();
|
||||
typeof(#call) result = #call;
|
||||
TimeDiff diff = time::current() - t;
|
||||
io::printf("'%s' took %f ms\n", $stringify(#call), diff * 1000);
|
||||
libc::printf("'%s' took %f ms\n", $stringify(#call), diff * 1000);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ const uint MaxDepth = 8;
|
||||
|
||||
$if (DEBUG_NODES):
|
||||
|
||||
func void Blocks.dump(Blocks* b)
|
||||
fn void Blocks.dump(Blocks* b)
|
||||
{
|
||||
printf("Nodes (%u/%u) (%u bytes)\n", b.nodeCount, b.maxNodes, b.nodeCount * sizeof(Node));
|
||||
for (uint i = 0; i < b.nodeCount; i++)
|
||||
@@ -82,7 +82,7 @@ $endif;
|
||||
/**
|
||||
* @ensure const(a), const(b)
|
||||
*/
|
||||
func bool same(char* a, char* b)
|
||||
fn bool same(char* a, char* b)
|
||||
{
|
||||
uint i = 0;
|
||||
while (a[i] == b[i])
|
||||
@@ -110,7 +110,7 @@ struct Parser
|
||||
/**
|
||||
* @ensure const(input)
|
||||
*/
|
||||
func void! Parser.parse(Parser* p, char* input, char* diagMsg, Blocks* blocks)
|
||||
fn void! Parser.parse(Parser* p, char* input, char* diagMsg, Blocks* blocks)
|
||||
{
|
||||
p.tokenizer.init(input);
|
||||
p.tok.init();
|
||||
@@ -127,7 +127,7 @@ func void! Parser.parse(Parser* p, char* input, char* diagMsg, Blocks* blocks)
|
||||
try p.parseTopLevel();
|
||||
}
|
||||
|
||||
func void! Parser.parseTopLevel(Parser* p)
|
||||
fn void! Parser.parseTopLevel(Parser* p)
|
||||
{
|
||||
// key = value
|
||||
// | [[array]]
|
||||
@@ -149,22 +149,22 @@ func void! Parser.parseTopLevel(Parser* p)
|
||||
}
|
||||
}
|
||||
|
||||
func uint getRawValue(uint raw) @(inline)
|
||||
fn uint getRawValue(uint raw) @(inline)
|
||||
{
|
||||
return raw & ~RawValueMask;
|
||||
}
|
||||
|
||||
func ValueType getRawType(uint raw) @(inline)
|
||||
fn ValueType getRawType(uint raw) @(inline)
|
||||
{
|
||||
return (ValueType)((raw >> ValueTypeOffset) & 0x3);
|
||||
}
|
||||
|
||||
func uint addType(uint raw, ValueType t) @(inline)
|
||||
fn uint addType(uint raw, ValueType t) @(inline)
|
||||
{
|
||||
return raw | (t << ValueTypeOffset);
|
||||
}
|
||||
|
||||
func void! Parser.parseKeyValue(Parser* p)
|
||||
fn void! Parser.parseKeyValue(Parser* p)
|
||||
{
|
||||
//printf("parseKeyValue()\n");
|
||||
char[MaxText] key;
|
||||
@@ -187,7 +187,7 @@ func void! Parser.parseKeyValue(Parser* p)
|
||||
p.lastChild[p.numParents] = node;
|
||||
}
|
||||
|
||||
func void! Parser.parseTable(Parser* p)
|
||||
fn void! Parser.parseTable(Parser* p)
|
||||
{
|
||||
//printf("parseTable()\n");
|
||||
try p.consumeToken();
|
||||
@@ -211,7 +211,7 @@ func void! Parser.parseTable(Parser* p)
|
||||
p.expectAndConsume(TokenKind.Rbrace);
|
||||
}
|
||||
|
||||
func void Parser.parseTableArray(Parser* p)
|
||||
fn void Parser.parseTableArray(Parser* p)
|
||||
{
|
||||
//printf("parseTableArray()\n");
|
||||
p.consumeToken();
|
||||
@@ -234,7 +234,7 @@ func void Parser.parseTableArray(Parser* p)
|
||||
p.expectAndConsume(TokenKind.Rbrace2);
|
||||
}
|
||||
|
||||
func u32 Parser.parseValue(Parser* p) {
|
||||
fn u32 Parser.parseValue(Parser* p) {
|
||||
//printf("parseValue()\n");
|
||||
u32 value = 0;
|
||||
switch (p.tok.kind) {
|
||||
@@ -266,7 +266,7 @@ func u32 Parser.parseValue(Parser* p) {
|
||||
return value;
|
||||
}
|
||||
|
||||
func u32 Parser.parseArrayValues(Parser* p) {
|
||||
fn u32 Parser.parseArrayValues(Parser* p) {
|
||||
//printf("parseArrayValues()\n");
|
||||
p.consumeToken();
|
||||
u32 value = p.parseValue() | ValueIsArray;
|
||||
@@ -280,7 +280,7 @@ func u32 Parser.parseArrayValues(Parser* p) {
|
||||
return value;
|
||||
}
|
||||
|
||||
func u32 Parser.addTable(Parser* p, const char* name, u32 depth, bool isTop, NodeKind kind) {
|
||||
fn u32 Parser.addTable(Parser* p, const char* name, u32 depth, bool isTop, NodeKind kind) {
|
||||
//printf("addTable %s\n", name);
|
||||
Blocks* blocks = p.blocks;
|
||||
if (!isTop && p.numParents > depth && same(blocks.getName(p.parents[depth]), name)) {
|
||||
@@ -342,18 +342,18 @@ func u32 Parser.addTable(Parser* p, const char* name, u32 depth, bool isTop, Nod
|
||||
return 0;
|
||||
}
|
||||
|
||||
func Location! Parser.consumeToken(Parser* p)
|
||||
fn Location! Parser.consumeToken(Parser* p)
|
||||
{
|
||||
Location prev = p.tok.loc;
|
||||
try p.tokenizer.lex(&p.tok);
|
||||
return prev;
|
||||
}
|
||||
|
||||
func Token* Parser.nextToken(Parser* p) {
|
||||
fn Token* Parser.nextToken(Parser* p) {
|
||||
return p.tokenizer.lookahead();
|
||||
}
|
||||
|
||||
func void! Parser.expectAndConsume(Parser* p, TokenKind k) {
|
||||
fn void! Parser.expectAndConsume(Parser* p, TokenKind k) {
|
||||
if (p.tok.isNot(k))
|
||||
{
|
||||
sprintf(p.errorMsg, "expected '%s' at %s", token2str(k), p.tok.loc.str());
|
||||
@@ -362,7 +362,7 @@ func void! Parser.expectAndConsume(Parser* p, TokenKind k) {
|
||||
try p.consumeToken();
|
||||
}
|
||||
|
||||
func void Parser.expect(Parser* p, TokenKind k)
|
||||
fn void Parser.expect(Parser* p, TokenKind k)
|
||||
{
|
||||
if (p.tok.isNot(k))
|
||||
{
|
||||
@@ -373,13 +373,13 @@ func void Parser.expect(Parser* p, TokenKind k)
|
||||
|
||||
const u32 MaxDiag = 128;
|
||||
|
||||
public struct TomlReader @opaque
|
||||
public struct TomlReader
|
||||
{
|
||||
char[MaxDiag] message;
|
||||
Blocks* blocks;
|
||||
}
|
||||
|
||||
public func TomlReader* new_toml()
|
||||
public fn TomlReader* new_toml()
|
||||
{
|
||||
TomlReader* r = @malloc(TomlReader);
|
||||
r.blocks = @malloc(Blocks);
|
||||
@@ -387,21 +387,21 @@ public func TomlReader* new_toml()
|
||||
return r;
|
||||
}
|
||||
|
||||
public func void TomlReader.destroy(TomlReader* r)
|
||||
public fn void TomlReader.destroy(TomlReader* r)
|
||||
{
|
||||
r.blocks.destroy();
|
||||
free(r.blocks);
|
||||
free(r);
|
||||
}
|
||||
|
||||
public func const char* TomlReader.getMsg(const TomlReader* r)
|
||||
public fn const char* TomlReader.getMsg(const TomlReader* r)
|
||||
{
|
||||
return r.message;
|
||||
}
|
||||
|
||||
error EmptyFileError;
|
||||
|
||||
public func void! TomlReader.parse(TomlReader* r, string filename)
|
||||
public fn void! TomlReader.parse(TomlReader* r, string filename)
|
||||
{
|
||||
Reader file;
|
||||
|
||||
@@ -427,7 +427,7 @@ $endif
|
||||
// --------------------------------------------------------------
|
||||
// Getters+iters
|
||||
|
||||
func const Node* Reader.findNode(const Reader* r, const char* key)
|
||||
fn const Node* Reader.findNode(const Reader* r, const char* key)
|
||||
{
|
||||
char[MaxText] name;
|
||||
const char* cp = key;
|
||||
@@ -459,7 +459,7 @@ func const Node* Reader.findNode(const Reader* r, const char* key)
|
||||
return nil;
|
||||
}
|
||||
|
||||
public func const char* Reader.getValue(const Reader* r, const char* key) {
|
||||
public fn const char* Reader.getValue(const Reader* r, const char* key) {
|
||||
const Node* node = r.findNode(key);
|
||||
if (!node) return nil;
|
||||
if (getKind(node.nameOffset) != NodeKind.Value) return nil;
|
||||
@@ -468,7 +468,7 @@ public func const char* Reader.getValue(const Reader* r, const char* key) {
|
||||
return &r.blocks.values[getRawValue(node.rawValue)];
|
||||
}
|
||||
|
||||
public func bool Reader.getNumber(const Reader* r, const char* key, u32* result) {
|
||||
public fn bool Reader.getNumber(const Reader* r, const char* key, u32* result) {
|
||||
const Node* node = r.findNode(key);
|
||||
if (!node) return false;
|
||||
if (getKind(node.nameOffset) != NodeKind.Value) return false;
|
||||
@@ -478,7 +478,7 @@ public func bool Reader.getNumber(const Reader* r, const char* key, u32* result)
|
||||
return true;
|
||||
}
|
||||
|
||||
public func bool Reader.getBool(const Reader* r, const char* key, bool* result) {
|
||||
public fn bool Reader.getBool(const Reader* r, const char* key, bool* result) {
|
||||
const Node* node = r.findNode(key);
|
||||
if (!node) return false;
|
||||
if (getKind(node.nameOffset) != NodeKind.Value) return false;
|
||||
@@ -493,18 +493,18 @@ public type NodeIter struct {
|
||||
const Node* node;
|
||||
}
|
||||
|
||||
public func bool NodeIter.done(const NodeIter* i) {
|
||||
public fn bool NodeIter.done(const NodeIter* i) {
|
||||
return i.node == nil;
|
||||
}
|
||||
|
||||
public func void NodeIter.next(NodeIter* i) {
|
||||
public fn void NodeIter.next(NodeIter* i) {
|
||||
if (i.node == nil) return;
|
||||
u32 next = i.node.nextNode;
|
||||
if (next == 0) i.node = nil;
|
||||
else i.node = &i.blocks.nodes[next];
|
||||
}
|
||||
|
||||
public func const char* NodeIter.getValue(const NodeIter* i, const char* key) {
|
||||
public fn const char* NodeIter.getValue(const NodeIter* i, const char* key) {
|
||||
const Node* child = i.blocks.findNode(key, i.node);
|
||||
if (!child) return nil;
|
||||
if (getKind(child.nameOffset) != NodeKind.Value) return nil;
|
||||
@@ -513,7 +513,7 @@ public func const char* NodeIter.getValue(const NodeIter* i, const char* key) {
|
||||
return &i.blocks.values[getRawValue(child.rawValue)];
|
||||
}
|
||||
|
||||
public func bool NodeIter.getNumber(const NodeIter* i, const char* key, u32* result) {
|
||||
public fn bool NodeIter.getNumber(const NodeIter* i, const char* key, u32* result) {
|
||||
const Node* child = i.blocks.findNode(key, i.node);
|
||||
if (!child) return false;
|
||||
if (getKind(child.nameOffset) != NodeKind.Value) return false;
|
||||
@@ -523,7 +523,7 @@ public func bool NodeIter.getNumber(const NodeIter* i, const char* key, u32* res
|
||||
return true;
|
||||
}
|
||||
|
||||
public func bool NodeIter.getBool(const NodeIter* i, const char* key, bool* result) {
|
||||
public fn bool NodeIter.getBool(const NodeIter* i, const char* key, bool* result) {
|
||||
const Node* child = i.blocks.findNode(key, i.node);
|
||||
if (!child) return false;
|
||||
if (getKind(child.nameOffset) != NodeKind.Value) return false;
|
||||
@@ -533,7 +533,7 @@ public func bool NodeIter.getBool(const NodeIter* i, const char* key, bool* resu
|
||||
return true;
|
||||
}
|
||||
|
||||
public func NodeIter Reader.getNodeIter(const Reader* r, const char* key) {
|
||||
public fn NodeIter Reader.getNodeIter(const Reader* r, const char* key) {
|
||||
const Node* node = r.findNode(key);
|
||||
if (node && getKind(node.nameOffset) == NodeKind.TableArray) {
|
||||
node = &r.blocks.nodes[node.child];
|
||||
@@ -548,26 +548,26 @@ public type ValueIter struct {
|
||||
bool isArray;
|
||||
}
|
||||
|
||||
func ValueIter ValueIter.create(const char* values, bool isArray) {
|
||||
fn ValueIter ValueIter.create(const char* values, bool isArray) {
|
||||
ValueIter iter = { values, isArray }
|
||||
return iter;
|
||||
}
|
||||
|
||||
public func bool ValueIter.done(const ValueIter* i) {
|
||||
public fn bool ValueIter.done(const ValueIter* i) {
|
||||
return i.values[0] == 0;
|
||||
}
|
||||
|
||||
public func void ValueIter.next(ValueIter* i) {
|
||||
public fn void ValueIter.next(ValueIter* i) {
|
||||
if (i.values[0] == 0) return;
|
||||
while (i.values[0] != 0) i.values++;
|
||||
if (i.isArray) i.values++; // skip 0-terminator
|
||||
}
|
||||
|
||||
public func const char* ValueIter.getValue(const ValueIter* i) {
|
||||
public fn const char* ValueIter.getValue(const ValueIter* i) {
|
||||
return i.values;
|
||||
}
|
||||
|
||||
public func ValueIter Reader.getValueIter(const Reader* r, const char* key) {
|
||||
public fn ValueIter Reader.getValueIter(const Reader* r, const char* key) {
|
||||
const Node* node = r.findNode(key);
|
||||
if (node) {
|
||||
switch (getKind(node.nameOffset)) {
|
||||
@@ -608,7 +608,7 @@ const u32 ValueIsArray = (1 << 31);
|
||||
const u32 ValueTypeOffset = 29;
|
||||
const u32 RawValueMask = (0x7 << 29);
|
||||
|
||||
func const char* type2str(ValueType t) {
|
||||
fn const char* type2str(ValueType t) {
|
||||
switch (t) {
|
||||
case ValueType.Text: return "T";
|
||||
case ValueType.Number: return "N";
|
||||
@@ -643,7 +643,7 @@ public type Blocks struct {
|
||||
u32 valuesSize;
|
||||
} @(opaque)
|
||||
|
||||
func void Blocks.init(Blocks* b) {
|
||||
fn void Blocks.init(Blocks* b) {
|
||||
memset(b, 0, sizeof(Blocks));
|
||||
b.nodes = calloc(MaxNodes, sizeof(Node));
|
||||
|
||||
@@ -662,13 +662,13 @@ func void Blocks.init(Blocks* b) {
|
||||
memset(b.namesCache, 0, sizeof(u32)*NamesCacheSize);
|
||||
}
|
||||
|
||||
func void Blocks.destroy(Blocks* b) {
|
||||
fn void Blocks.destroy(Blocks* b) {
|
||||
free(b.values);
|
||||
free(b.names);
|
||||
free(b.nodes);
|
||||
}
|
||||
|
||||
func u32 Blocks.searchNameCache(Blocks* b, const char* name) {
|
||||
fn u32 Blocks.searchNameCache(Blocks* b, const char* name) {
|
||||
for (u32 i=0; i<NamesCacheSize; ++i) {
|
||||
u32 off = b.namesCache[i];
|
||||
if (off && same(&b.names[off], name)) return off;
|
||||
@@ -676,12 +676,12 @@ func u32 Blocks.searchNameCache(Blocks* b, const char* name) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
func const char* Blocks.getName(const Blocks* b, const Node* node) {
|
||||
fn const char* Blocks.getName(const Blocks* b, const Node* node) {
|
||||
return &b.names[getValue(node.nameOffset)];
|
||||
}
|
||||
|
||||
|
||||
func u32 Blocks.addNode(Blocks* b, const char* name, NodeKind k) {
|
||||
fn u32 Blocks.addNode(Blocks* b, const char* name, NodeKind k) {
|
||||
if (b.nodeCount == MaxNodes) {
|
||||
// TODO jmp?
|
||||
printf("node limit reached\n");
|
||||
@@ -712,7 +712,7 @@ func u32 Blocks.addNode(Blocks* b, const char* name, NodeKind k) {
|
||||
return off;
|
||||
}
|
||||
|
||||
func u32 Blocks.addValue(Blocks* b, const char* value) {
|
||||
fn u32 Blocks.addValue(Blocks* b, const char* value) {
|
||||
if (value[0] == 0) return 0;
|
||||
u32 off = b.valuesOffset;
|
||||
u32 len = cast<u32>(strlen(value)) + 1;
|
||||
@@ -721,12 +721,12 @@ func u32 Blocks.addValue(Blocks* b, const char* value) {
|
||||
return off;
|
||||
}
|
||||
|
||||
func void Blocks.addNull(Blocks* b) {
|
||||
fn void Blocks.addNull(Blocks* b) {
|
||||
b.values[b.valuesOffset] = 0;
|
||||
b.valuesOffset++;
|
||||
}
|
||||
|
||||
func Node* Blocks.findNode(const Blocks* b, const char* name, const Node* parent) {
|
||||
fn Node* Blocks.findNode(const Blocks* b, const char* name, const Node* parent) {
|
||||
if (b.nodeCount == 0) return nil;
|
||||
Node* node = &b.nodes[0];
|
||||
if (parent) {
|
||||
@@ -746,14 +746,14 @@ func Node* Blocks.findNode(const Blocks* b, const char* name, const Node* parent
|
||||
|
||||
const u32 NodeKindOffset = 29;
|
||||
|
||||
func u32 addKind(u32 value, NodeKind k) @(inline) {
|
||||
fn u32 addKind(u32 value, NodeKind k) @(inline) {
|
||||
return value | (k << NodeKindOffset);
|
||||
}
|
||||
|
||||
func NodeKind getKind(u32 value) @(inline) {
|
||||
fn NodeKind getKind(u32 value) @(inline) {
|
||||
return cast<NodeKind>(value >> NodeKindOffset);
|
||||
}
|
||||
|
||||
func u32 getValue(u32 value) @(inline) {
|
||||
fn u32 getValue(u32 value) @(inline) {
|
||||
return value & ~(0x7 << NodeKindOffset);
|
||||
}
|
||||
|
||||
@@ -25,13 +25,13 @@ enum TokenKind : char (String name)
|
||||
ERROR("error"),
|
||||
}
|
||||
|
||||
func void Location.init(Location* l, uint line = 0, uint col = 0)
|
||||
fn void Location.init(Location* l, uint line = 0, uint col = 0)
|
||||
{
|
||||
l.line = line;
|
||||
l.column = col;
|
||||
}
|
||||
|
||||
func string Location.str(Location* l)
|
||||
fn string Location.str(Location* l)
|
||||
{
|
||||
static char[32] msg;
|
||||
sprintf(msg, "line %u:%u", l.line, l.column);
|
||||
@@ -50,7 +50,7 @@ struct Token
|
||||
}
|
||||
}
|
||||
|
||||
func void Token.init(Token* t)
|
||||
fn void Token.init(Token* t)
|
||||
{
|
||||
t.loc.init(0, 0);
|
||||
t.kind = TokenKind.EOF;
|
||||
@@ -58,28 +58,28 @@ func void Token.init(Token* t)
|
||||
t.number = 0;
|
||||
}
|
||||
|
||||
func void Token.clear(Token* t)
|
||||
fn void Token.clear(Token* t)
|
||||
{
|
||||
t.text = nil;
|
||||
t.number = 0;
|
||||
}
|
||||
|
||||
func void Token.setLocation(Token* t, Location l)
|
||||
fn void Token.setLocation(Token* t, Location l)
|
||||
{
|
||||
t.loc = l;
|
||||
}
|
||||
|
||||
func bool Token.is(Token* t, TokenKind k)
|
||||
fn bool Token.is(Token* t, TokenKind k)
|
||||
{
|
||||
return t.kind == k;
|
||||
}
|
||||
|
||||
func bool Token.isNot(Token* t, TokenKind k)
|
||||
fn bool Token.isNot(Token* t, TokenKind k)
|
||||
{
|
||||
return t.kind != k;
|
||||
}
|
||||
|
||||
func string Token.getName(Token* t)
|
||||
fn string Token.getName(Token* t)
|
||||
{
|
||||
return t.kind.name;
|
||||
}
|
||||
@@ -94,7 +94,7 @@ struct Tokenizer
|
||||
bool haveNext;
|
||||
}
|
||||
|
||||
func void Tokenizer.init(Tokenizer* t, char* input)
|
||||
fn void Tokenizer.init(Tokenizer* t, char* input)
|
||||
{
|
||||
t.dataStart = input;
|
||||
t.current = input;
|
||||
@@ -109,7 +109,7 @@ error LexError
|
||||
string error_message;
|
||||
}
|
||||
|
||||
func void! Tokenizer.lex(Tokenizer* t, Token* result)
|
||||
fn void! Tokenizer.lex(Tokenizer* t, Token* result)
|
||||
{
|
||||
if (t.haveNext)
|
||||
{
|
||||
@@ -221,7 +221,7 @@ func void! Tokenizer.lex(Tokenizer* t, Token* result)
|
||||
}
|
||||
}
|
||||
|
||||
func Token*! Tokenizer.lookahead(Tokenizer* t)
|
||||
fn Token*! Tokenizer.lookahead(Tokenizer* t)
|
||||
{
|
||||
if (!t.haveNext)
|
||||
{
|
||||
@@ -231,13 +231,13 @@ func Token*! Tokenizer.lookahead(Tokenizer* t)
|
||||
return &t.nextToken;
|
||||
}
|
||||
|
||||
func void Tokenizer.advance(Tokenizer* t, uint amount)
|
||||
fn void Tokenizer.advance(Tokenizer* t, uint amount)
|
||||
{
|
||||
t.loc.column += amount;
|
||||
t.current += amount;
|
||||
}
|
||||
|
||||
func void Tokenizer.parseComment(Tokenizer* t)
|
||||
fn void Tokenizer.parseComment(Tokenizer* t)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
@@ -258,7 +258,7 @@ func void Tokenizer.parseComment(Tokenizer* t)
|
||||
}
|
||||
}
|
||||
|
||||
func void Tokenizer.parseText(Tokenizer* t, Token* result)
|
||||
fn void Tokenizer.parseText(Tokenizer* t, Token* result)
|
||||
{
|
||||
// TODO handle literal strings ' .. ' -> no escaping
|
||||
// TODO handle escape chars for normal strings " .. \" \r \n "
|
||||
@@ -277,7 +277,7 @@ func void Tokenizer.parseText(Tokenizer* t, Token* result)
|
||||
t.advance(1);
|
||||
}
|
||||
|
||||
func void! Tokenizer.parseMultiText(Tokenizer* t, Token* result)
|
||||
fn void! Tokenizer.parseMultiText(Tokenizer* t, Token* result)
|
||||
{
|
||||
t.advance(3);
|
||||
if (t.current[0] == '\n')
|
||||
@@ -317,7 +317,7 @@ func void! Tokenizer.parseMultiText(Tokenizer* t, Token* result)
|
||||
t.advance(3);
|
||||
}
|
||||
|
||||
func void Tokenizer.parseNumber(Tokenizer* t, Token* result)
|
||||
fn void Tokenizer.parseNumber(Tokenizer* t, Token* result)
|
||||
{
|
||||
// TODO handle prefix +/-
|
||||
// handle hexadecimal/ocal/binary number
|
||||
@@ -333,7 +333,7 @@ func void Tokenizer.parseNumber(Tokenizer* t, Token* result)
|
||||
}
|
||||
}
|
||||
|
||||
func bool isKeyChar(u8 c)
|
||||
fn bool isKeyChar(u8 c)
|
||||
{
|
||||
if (c >= 128) return true;
|
||||
if (isalpha(c)) return true;
|
||||
@@ -342,7 +342,7 @@ func bool isKeyChar(u8 c)
|
||||
return false;
|
||||
}
|
||||
|
||||
func void Tokenizer.parseKey(Tokenizer* t, Token* result)
|
||||
fn void Tokenizer.parseKey(Tokenizer* t, Token* result)
|
||||
{
|
||||
char* start = t.current;
|
||||
while (t.current[0] && isKeyChar((char)(t.current[0]))) t.current++;
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
module vector(Type);
|
||||
|
||||
public struct Vector
|
||||
{
|
||||
Type[] array;
|
||||
}
|
||||
|
||||
public func void Vector.init()
|
||||
{
|
||||
array = nil;
|
||||
}
|
||||
|
||||
public func void Vector.add(Vector *vector, Type type)
|
||||
{
|
||||
vector.array += type;
|
||||
}
|
||||
|
||||
public func usize Vector.size(Vector *vector)
|
||||
{
|
||||
return vector.array.size;
|
||||
}
|
||||
|
||||
public func void Vector.removeLast(Vector *vector)
|
||||
{
|
||||
vector.array.pop();
|
||||
}
|
||||
|
||||
public func void Vector.removefirst(Vector *vector)
|
||||
{
|
||||
vector.array.removeAt(0);
|
||||
}
|
||||
|
||||
public func void Type *Vector.first(Vector *vector)
|
||||
{
|
||||
return &vector.array.first;
|
||||
}
|
||||
|
||||
public func void Type *Vector.last(Vector *vector)
|
||||
{
|
||||
return &vector.array.last();
|
||||
}
|
||||
|
||||
public func bool Vector.empty(Vector *vector)
|
||||
{
|
||||
return !vector.array.size;
|
||||
}
|
||||
|
||||
public macro Vector.foreach(Vector *vector, macro void(Type value) body)
|
||||
{
|
||||
for (usize i = 0, i < vector.array.size; i++)
|
||||
{
|
||||
@body(vector.array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
test
|
||||
{
|
||||
define IntVector = Vector(int);
|
||||
IntVector *vector = @calloc(IntVector);
|
||||
vector.add(1);
|
||||
vector.add(2);
|
||||
for (int i : vector)
|
||||
{
|
||||
printDigit(i);
|
||||
}
|
||||
@vector.foreach(int i)
|
||||
{
|
||||
printDigit(i);
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
module comparable;
|
||||
import std::math;
|
||||
|
||||
interface Geometry
|
||||
{
|
||||
func double area();
|
||||
func double perim();
|
||||
}
|
||||
|
||||
struct Rect
|
||||
{
|
||||
double width, height;
|
||||
}
|
||||
|
||||
struct Circle
|
||||
{
|
||||
double radius;
|
||||
}
|
||||
|
||||
func double Rect.area(Rect *r)
|
||||
{
|
||||
return r.width * r.height;
|
||||
}
|
||||
|
||||
func double Rect.perim(Rect *r)
|
||||
{
|
||||
return 2 * r.width + 2 * r.height;
|
||||
}
|
||||
|
||||
func double Circle.area(Circle *c)
|
||||
{
|
||||
return math::PI * c.radius * c.radius
|
||||
}
|
||||
|
||||
func double Circle.perim(Circle *c)
|
||||
{
|
||||
return math::PI * c.radius * 2;
|
||||
}
|
||||
|
||||
func void measure(virtual Geometry g)
|
||||
{
|
||||
printf("area: %f, perimeter: %f\n", g.area(), g.perim());
|
||||
}
|
||||
|
||||
func void main()
|
||||
{
|
||||
Rect r = { 3, 4 };
|
||||
Circle c = { 5 };
|
||||
measure(&r);
|
||||
measure(&c);
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
module std::io;
|
||||
|
||||
interface File : Closable, Readable, Seekable
|
||||
{
|
||||
FileInfo[]! readdir(int count);
|
||||
FileInfo! stat();
|
||||
}
|
||||
|
||||
|
||||
interface File
|
||||
{
|
||||
inline Closable;
|
||||
inline Readable;
|
||||
inline Seekable;
|
||||
FileInfo[]! readdir(int count);
|
||||
FileInfo! stat();
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import gtk;
|
||||
const string CLICK_ME = "Click Me";
|
||||
uint counter = 0;
|
||||
|
||||
func void clickedme(GtkButton *o, void *d)
|
||||
fn void clickedme(GtkButton *o, void *d)
|
||||
{
|
||||
(GtkLabel*)(d).set_text(string.format("You clicked me %d times", ++counter));
|
||||
}
|
||||
|
||||
313
resources/examples/raylib/raylib_arkanoid.c3
Normal file
313
resources/examples/raylib/raylib_arkanoid.c3
Normal file
@@ -0,0 +1,313 @@
|
||||
module arkanoid;
|
||||
|
||||
/**
|
||||
*
|
||||
* raylib - classic game: arkanoid
|
||||
*
|
||||
* Sample game developed by Marc Palau and Ramon Santamaria
|
||||
* converted to C3 by Christoffer Lerno
|
||||
*
|
||||
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
|
||||
*/
|
||||
|
||||
const int SCREEN_WIDTH = 800;
|
||||
const int SCREEN_HEIGHT = 450;
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Some Defines
|
||||
//----------------------------------------------------------------------------------
|
||||
const PLAYER_MAX_LIFE = 5;
|
||||
const LINES_OF_BRICKS = 5;
|
||||
const BRICKS_PER_LINE = 20;
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Types and Structures Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
enum GameScreen
|
||||
{
|
||||
LOGO,
|
||||
TITLE,
|
||||
GAMEPLAY,
|
||||
ENDING
|
||||
}
|
||||
|
||||
struct Player
|
||||
{
|
||||
Vector2 position;
|
||||
Vector2 size;
|
||||
int life;
|
||||
}
|
||||
|
||||
struct Ball
|
||||
{
|
||||
Vector2 position;
|
||||
Vector2 speed;
|
||||
int radius;
|
||||
bool active;
|
||||
}
|
||||
|
||||
struct Brick
|
||||
{
|
||||
Vector2 position;
|
||||
bool active;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Global Variables Declaration
|
||||
//------------------------------------------------------------------------------------
|
||||
|
||||
bool game_over = false;
|
||||
bool pause = false;
|
||||
|
||||
Player player;
|
||||
Ball ball;
|
||||
Brick[BRICKS_PER_LINE][LINES_OF_BRICKS] brick;
|
||||
Vector2 brick_size;
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Program main entry point
|
||||
//------------------------------------------------------------------------------------
|
||||
fn void main()
|
||||
{
|
||||
// Initialization (Note windowTitle is unused on Android)
|
||||
//---------------------------------------------------------
|
||||
raylib::init_window(SCREEN_WIDTH, SCREEN_HEIGHT, "classic game: arkanoid");
|
||||
|
||||
init_game();
|
||||
|
||||
raylib::set_target_fps(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Main game loop
|
||||
while (!raylib::window_should_close()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update and Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
update_draw_frame();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
unload_game(); // Unload loaded data (textures, sounds, models...)
|
||||
|
||||
raylib::close_window(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Module Functions Definitions (local)
|
||||
//------------------------------------------------------------------------------------
|
||||
|
||||
// Initialize game variables
|
||||
fn void init_game()
|
||||
{
|
||||
brick_size = { raylib::get_screen_width() / BRICKS_PER_LINE, 40 };
|
||||
|
||||
// Initialize player
|
||||
player.position = { SCREEN_WIDTH/2, SCREEN_HEIGHT * 7 / 8 };
|
||||
player.size = { SCREEN_WIDTH / 10, 20 };
|
||||
player.life = PLAYER_MAX_LIFE;
|
||||
|
||||
// Initialize ball
|
||||
ball.position = { SCREEN_WIDTH / 2, SCREEN_HEIGHT * 7 / 8 - 30 };
|
||||
ball.speed = { 0, 0 };
|
||||
ball.radius = 7;
|
||||
ball.active = false;
|
||||
|
||||
// Initialize bricks
|
||||
int initial_down_position = 50;
|
||||
|
||||
for (int i = 0; i < LINES_OF_BRICKS; i++)
|
||||
{
|
||||
for (int j = 0; j < BRICKS_PER_LINE; j++)
|
||||
{
|
||||
brick[i][j].position = { j * brick_size.x + brick_size.x / 2, i * brick_size.y + initial_down_position };
|
||||
brick[i][j].active = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update game (one frame)
|
||||
fn void update_game()
|
||||
{
|
||||
if (game_over)
|
||||
{
|
||||
if (raylib::is_key_pressed(keyboard::ENTER))
|
||||
{
|
||||
init_game();
|
||||
game_over = false;
|
||||
}
|
||||
}
|
||||
if (raylib::is_key_pressed((KeyboardKey)'P')) pause = !pause;
|
||||
|
||||
if (pause) return;
|
||||
// Player movement logic
|
||||
if (raylib::is_key_down(keyboard::LEFT)) player.position.x -= 5;
|
||||
if ((player.position.x - player.size.x/2) <= 0) player.position.x = player.size.x/2;
|
||||
if (raylib::is_key_down(keyboard::RIGHT)) player.position.x += 5;
|
||||
if ((player.position.x + player.size.x/2) >= SCREEN_WIDTH) player.position.x = SCREEN_WIDTH - player.size.x/2;
|
||||
|
||||
// Ball launching logic
|
||||
if (!ball.active)
|
||||
{
|
||||
if (raylib::is_key_pressed(keyboard::SPACE))
|
||||
{
|
||||
ball.active = true;
|
||||
ball.speed = { 0, -5 };
|
||||
}
|
||||
}
|
||||
|
||||
// Ball movement logic
|
||||
if (ball.active)
|
||||
{
|
||||
ball.position.x += ball.speed.x;
|
||||
ball.position.y += ball.speed.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
ball.position = { player.position.x, SCREEN_HEIGHT * 7 / 8 - 30 };
|
||||
}
|
||||
|
||||
// Collision logic: ball vs walls
|
||||
if (((ball.position.x + ball.radius) >= SCREEN_WIDTH) || ((ball.position.x - ball.radius) <= 0)) ball.speed.x *= -1;
|
||||
if ((ball.position.y - ball.radius) <= 0) ball.speed.y *= -1;
|
||||
if ((ball.position.y + ball.radius) >= SCREEN_HEIGHT)
|
||||
{
|
||||
ball.speed = { 0, 0 };
|
||||
ball.active = false;
|
||||
|
||||
player.life--;
|
||||
}
|
||||
|
||||
// Collision logic: ball vs player
|
||||
if (raylib::check_collision_circle_rec(ball.position, ball.radius,
|
||||
Rectangle{ player.position.x - player.size.x / 2, player.position.y - player.size.y / 2, player.size.x, player.size.y}))
|
||||
{
|
||||
if (ball.speed.y > 0)
|
||||
{
|
||||
ball.speed.y *= -1;
|
||||
ball.speed.x = (ball.position.x - player.position.x) / (player.size.x / 2) * 5;
|
||||
}
|
||||
}
|
||||
|
||||
// Collision logic: ball vs bricks
|
||||
for (int i = 0; i < LINES_OF_BRICKS; i++)
|
||||
{
|
||||
for (int j = 0; j < BRICKS_PER_LINE; j++)
|
||||
{
|
||||
if (brick[i][j].active)
|
||||
{
|
||||
// Hit below
|
||||
if (((ball.position.y - ball.radius) <= (brick[i][j].position.y + brick_size.y / 2)) &&
|
||||
((ball.position.y - ball.radius) > (brick[i][j].position.y + brick_size.y / 2 + ball.speed.y)) &&
|
||||
((math::fabs((double)ball.position.x - brick[i][j].position.x)) < (double)(brick_size.x / 2 + ball.radius * 2 / 3)) && (ball.speed.y < 0))
|
||||
{
|
||||
brick[i][j].active = false;
|
||||
ball.speed.y *= -1;
|
||||
}
|
||||
// Hit above
|
||||
else if (((ball.position.y + ball.radius) >= (brick[i][j].position.y - brick_size.y/2)) &&
|
||||
((ball.position.y + ball.radius) < (brick[i][j].position.y - brick_size.y/2 + ball.speed.y)) &&
|
||||
((math::fabs((double)ball.position.x - brick[i][j].position.x)) < (double)(brick_size.x/2 + ball.radius*2/3)) && (ball.speed.y > 0))
|
||||
{
|
||||
brick[i][j].active = false;
|
||||
ball.speed.y *= -1;
|
||||
}
|
||||
// Hit left
|
||||
else if (((ball.position.x + ball.radius) >= (brick[i][j].position.x - brick_size.x/2)) &&
|
||||
((ball.position.x + ball.radius) < (brick[i][j].position.x - brick_size.x/2 + ball.speed.x)) &&
|
||||
((math::fabs((double)ball.position.y - brick[i][j].position.y)) < (double)(brick_size.y/2 + ball.radius*2/3)) && (ball.speed.x > 0))
|
||||
{
|
||||
brick[i][j].active = false;
|
||||
ball.speed.x *= -1;
|
||||
}
|
||||
// Hit right
|
||||
else if (((ball.position.x - ball.radius) <= (brick[i][j].position.x + brick_size.x/2)) &&
|
||||
((ball.position.x - ball.radius) > (brick[i][j].position.x + brick_size.x/2 + ball.speed.x)) &&
|
||||
((math::fabs((double)ball.position.y - brick[i][j].position.y)) < (double)(brick_size.y/2 + ball.radius*2/3)) && (ball.speed.x < 0))
|
||||
{
|
||||
brick[i][j].active = false;
|
||||
ball.speed.x *= -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Game over logic
|
||||
if (player.life <= 0)
|
||||
{
|
||||
game_over = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
game_over = true;
|
||||
for (int i = 0; i < LINES_OF_BRICKS; i++)
|
||||
{
|
||||
for (int j = 0; j < BRICKS_PER_LINE; j++)
|
||||
{
|
||||
if (brick[i][j].active) game_over = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw game (one frame)
|
||||
fn void draw_game()
|
||||
{
|
||||
raylib::begin_drawing();
|
||||
|
||||
raylib::clear_background(raylib::RAYWHITE);
|
||||
|
||||
if (!game_over)
|
||||
{
|
||||
// Draw player bar
|
||||
raylib::draw_rectangle((int)(player.position.x - player.size.x/2), (int)(player.position.y - player.size.y/2), (int)player.size.x, (int)player.size.y, raylib::BLACK);
|
||||
|
||||
// Draw player lives
|
||||
for (int i = 0; i < player.life; i++) raylib::draw_rectangle(20 + 40*i, SCREEN_HEIGHT - 30, 35, 10, raylib::LIGHTGRAY);
|
||||
|
||||
// Draw ball
|
||||
raylib::draw_circle_v(ball.position, ball.radius, raylib::MAROON);
|
||||
|
||||
// Draw bricks
|
||||
for (int i = 0; i < LINES_OF_BRICKS; i++)
|
||||
{
|
||||
for (int j = 0; j < BRICKS_PER_LINE; j++)
|
||||
{
|
||||
if (brick[i][j].active)
|
||||
{
|
||||
if ((i + j) % 2 == 0)
|
||||
{
|
||||
raylib::draw_rectangle((int)(brick[i][j].position.x - brick_size.x/2), (int)(brick[i][j].position.y - brick_size.y/2), (int)brick_size.x, (int)brick_size.y, raylib::GRAY);
|
||||
}
|
||||
else
|
||||
{
|
||||
raylib::draw_rectangle((int)(brick[i][j].position.x - brick_size.x/2), (int)(brick[i][j].position.y - brick_size.y/2), (int)brick_size.x, (int)brick_size.y, raylib::DARKGRAY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pause) raylib::draw_text("GAME PAUSED", SCREEN_WIDTH/2 - raylib::measure_text("GAME PAUSED", 40)/2, SCREEN_HEIGHT/2 - 40, 40, raylib::GRAY);
|
||||
}
|
||||
else
|
||||
{
|
||||
raylib::draw_text("PRESS [ENTER] TO PLAY AGAIN", raylib::get_screen_width()/2 - raylib::measure_text("PRESS [ENTER] TO PLAY AGAIN", 20)/2, raylib::get_screen_height()/2 - 50, 20, raylib::GRAY);
|
||||
}
|
||||
|
||||
raylib::end_drawing();
|
||||
}
|
||||
|
||||
// Unload game variables
|
||||
fn void unload_game()
|
||||
{
|
||||
// TODO: Unload all dynamic loaded data (textures, sounds, models...)
|
||||
}
|
||||
|
||||
// Update and Draw (one frame)
|
||||
fn void update_draw_frame()
|
||||
{
|
||||
update_game();
|
||||
draw_game();
|
||||
}
|
||||
251
resources/examples/raylib/raylib_snake.c3
Normal file
251
resources/examples/raylib/raylib_snake.c3
Normal file
@@ -0,0 +1,251 @@
|
||||
module snake;
|
||||
/**
|
||||
*
|
||||
* raylib - classic game: snake
|
||||
*
|
||||
* Sample game developed by Ian Eito, Albert Martos and Ramon Santamaria,
|
||||
* converted to C3 and modified by Christoffer Lerno
|
||||
*
|
||||
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
*/
|
||||
|
||||
const SNAKE_LENGTH = 256;
|
||||
const SQUARE_SIZE = 32;
|
||||
const int SCREEN_WIDTH = 800;
|
||||
const int SCREEN_HEIGHT = 450;
|
||||
|
||||
enum SnakeDirection
|
||||
{
|
||||
RIGHT,
|
||||
DOWN,
|
||||
LEFT,
|
||||
UP
|
||||
}
|
||||
struct Snake
|
||||
{
|
||||
Vector2 position;
|
||||
Vector2 size;
|
||||
Color color;
|
||||
}
|
||||
|
||||
struct Food
|
||||
{
|
||||
Vector2 position;
|
||||
Vector2 size;
|
||||
bool active;
|
||||
Color color;
|
||||
}
|
||||
|
||||
|
||||
int frames_counter = 0;
|
||||
bool game_over = false;
|
||||
bool pause = false;
|
||||
|
||||
Food fruit;
|
||||
SnakeDirection snake_direction;
|
||||
Snake[SNAKE_LENGTH] snake;
|
||||
Vector2[SNAKE_LENGTH] snake_position;
|
||||
bool allow_move = false;
|
||||
Vector2 offset;
|
||||
int counter_tail = 0;
|
||||
|
||||
fn void main()
|
||||
{
|
||||
raylib::init_window(SCREEN_WIDTH, SCREEN_HEIGHT, "classic game: snake");
|
||||
init_game();
|
||||
raylib::set_target_fps(60);
|
||||
|
||||
while (!raylib::window_should_close()) // Detect window close button or ESC key
|
||||
{
|
||||
update_draw_frame();
|
||||
}
|
||||
|
||||
unload_game();
|
||||
|
||||
raylib::close_window();
|
||||
}
|
||||
|
||||
// Initialize game variables
|
||||
fn void init_game()
|
||||
{
|
||||
frames_counter = 0;
|
||||
game_over = false;
|
||||
pause = false;
|
||||
|
||||
counter_tail = 1;
|
||||
allow_move = false;
|
||||
snake_direction = SnakeDirection.RIGHT;
|
||||
offset.x = SCREEN_WIDTH % SQUARE_SIZE;
|
||||
offset.y = SCREEN_HEIGHT % SQUARE_SIZE;
|
||||
|
||||
for (int i = 0; i < SNAKE_LENGTH; i++)
|
||||
{
|
||||
snake[i].position = { offset.x / 2, offset.y / 2 };
|
||||
snake[i].size = { SQUARE_SIZE, SQUARE_SIZE };
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
snake[i].color = raylib::DARKBLUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
snake[i].color = raylib::BLUE;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < SNAKE_LENGTH; i++)
|
||||
{
|
||||
snake_position[i] = { 0.0f, 0.0f };
|
||||
}
|
||||
|
||||
fruit.size = { SQUARE_SIZE, SQUARE_SIZE };
|
||||
fruit.color = raylib::SKYBLUE;
|
||||
fruit.active = false;
|
||||
}
|
||||
|
||||
|
||||
fn void update_game()
|
||||
{
|
||||
if (game_over)
|
||||
{
|
||||
if (raylib::is_key_pressed(keyboard::ENTER))
|
||||
{
|
||||
init_game();
|
||||
game_over = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (raylib::is_key_pressed((KeyboardKey)'P')) pause = !pause;
|
||||
|
||||
if (pause) return;
|
||||
|
||||
if (raylib::is_key_pressed(keyboard::RIGHT) && allow_move)
|
||||
{
|
||||
snake_direction = (SnakeDirection)((snake_direction + 1) % 4);
|
||||
allow_move = false;
|
||||
}
|
||||
if (raylib::is_key_pressed(keyboard::LEFT) && allow_move)
|
||||
{
|
||||
snake_direction = (SnakeDirection)((snake_direction + 3) % 4);
|
||||
allow_move = false;
|
||||
}
|
||||
|
||||
// Snake movement
|
||||
for (int i = 0; i < counter_tail; i++) snake_position[i] = snake[i].position;
|
||||
|
||||
if (frames_counter++ % 5 != 0) return;
|
||||
|
||||
allow_move = true;
|
||||
switch (snake_direction)
|
||||
{
|
||||
case RIGHT:
|
||||
snake[0].position.x += SQUARE_SIZE;
|
||||
snake[0].position.y += 0;
|
||||
case UP:
|
||||
snake[0].position.x += 0;
|
||||
snake[0].position.y += -SQUARE_SIZE;
|
||||
case DOWN:
|
||||
snake[0].position.x += 0;
|
||||
snake[0].position.y += SQUARE_SIZE;
|
||||
case LEFT:
|
||||
snake[0].position.x += -SQUARE_SIZE;
|
||||
snake[0].position.y += 0;
|
||||
default:
|
||||
unreachable();
|
||||
}
|
||||
for (int i = 1; i < counter_tail; i++)
|
||||
{
|
||||
snake[i].position = snake_position[i - 1];
|
||||
}
|
||||
|
||||
// Wall behaviour
|
||||
if (((snake[0].position.x) > (SCREEN_WIDTH - offset.x)) ||
|
||||
((snake[0].position.y) > (SCREEN_HEIGHT - offset.y)) ||
|
||||
(snake[0].position.x < 0) || (snake[0].position.y < 0))
|
||||
{
|
||||
game_over = true;
|
||||
}
|
||||
|
||||
// Collision with yourself
|
||||
for (int i = 1; i < counter_tail; i++)
|
||||
{
|
||||
if ((snake[0].position.x == snake[i].position.x) && (snake[0].position.y == snake[i].position.y)) game_over = true;
|
||||
}
|
||||
|
||||
// Fruit position calculation
|
||||
if (!fruit.active)
|
||||
{
|
||||
fruit.active = true;
|
||||
fruit.position = { raylib::get_random_value(0, (SCREEN_WIDTH / SQUARE_SIZE) - 1) * SQUARE_SIZE + offset.x/2, raylib::get_random_value(0, (SCREEN_HEIGHT / SQUARE_SIZE) - 1) * SQUARE_SIZE + offset.y / 2 };
|
||||
|
||||
for (int i = 0; i < counter_tail; i++)
|
||||
{
|
||||
while ((fruit.position.x == snake[i].position.x) && (fruit.position.y == snake[i].position.y))
|
||||
{
|
||||
fruit.position = { raylib::get_random_value(0, (SCREEN_WIDTH / SQUARE_SIZE) - 1) * SQUARE_SIZE + offset.x/2, raylib::get_random_value(0, (SCREEN_HEIGHT / SQUARE_SIZE) - 1) * SQUARE_SIZE + offset.y / 2 };
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Collision
|
||||
if ((snake[0].position.x < (fruit.position.x + fruit.size.x) && (snake[0].position.x + snake[0].size.x) > fruit.position.x) &&
|
||||
(snake[0].position.y < (fruit.position.y + fruit.size.y) && (snake[0].position.y + snake[0].size.y) > fruit.position.y))
|
||||
{
|
||||
snake[counter_tail].position = snake_position[counter_tail - 1];
|
||||
counter_tail += 1;
|
||||
fruit.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw game (one frame)
|
||||
fn void draw_game()
|
||||
{
|
||||
raylib::begin_drawing();
|
||||
|
||||
raylib::clear_background(raylib::RAYWHITE);
|
||||
|
||||
if (!game_over)
|
||||
{
|
||||
// Draw grid lines
|
||||
for (int i = 0; i < SCREEN_WIDTH / SQUARE_SIZE + 1; i++)
|
||||
{
|
||||
raylib::draw_line_v({SQUARE_SIZE * i + offset.x/2, offset.y/2}, {SQUARE_SIZE * i + offset.x/2, SCREEN_HEIGHT - offset.y/2}, raylib::LIGHTGRAY);
|
||||
}
|
||||
|
||||
for (int i = 0; i < SCREEN_HEIGHT/SQUARE_SIZE + 1; i++)
|
||||
{
|
||||
raylib::draw_line_v({offset.x/2, SQUARE_SIZE * i + offset.y / 2 }, { SCREEN_WIDTH - offset.x/2, SQUARE_SIZE * i + offset.y / 2 }, raylib::LIGHTGRAY);
|
||||
}
|
||||
|
||||
// Draw snake
|
||||
for (int i = 0; i < counter_tail; i++) raylib::draw_rectangle_v(snake[i].position, snake[i].size, snake[i].color);
|
||||
|
||||
// Draw fruit to pick
|
||||
raylib::draw_rectangle_v(fruit.position, fruit.size, fruit.color);
|
||||
|
||||
if (pause) raylib::draw_text("GAME PAUSED", SCREEN_WIDTH/2 - raylib::measure_text("GAME PAUSED", 40)/2, SCREEN_HEIGHT / 2 - 40, 40, raylib::GRAY);
|
||||
}
|
||||
else
|
||||
{
|
||||
raylib::draw_text("PRESS [ENTER] TO PLAY AGAIN", raylib::get_screen_width()/2 - raylib::measure_text("PRESS [ENTER] TO PLAY AGAIN", 20)/2, raylib::get_screen_height()/2 - 50, 20, raylib::GRAY);
|
||||
}
|
||||
|
||||
raylib::end_drawing();
|
||||
}
|
||||
|
||||
// Unload game variables
|
||||
fn void unload_game()
|
||||
{
|
||||
// TODO: Unload all dynamic loaded data (textures, sounds, models...)
|
||||
}
|
||||
|
||||
// Update and Draw (one frame)
|
||||
fn void update_draw_frame()
|
||||
{
|
||||
update_game();
|
||||
draw_game();
|
||||
}
|
||||
|
||||
793
resources/examples/raylib/raylib_tetris.c3
Normal file
793
resources/examples/raylib/raylib_tetris.c3
Normal file
@@ -0,0 +1,793 @@
|
||||
module tetris;
|
||||
/**
|
||||
* raylib - classic game: tetris
|
||||
*
|
||||
* Sample game developed by Marc Palau and Ramon Santamaria,
|
||||
* converted to C3 by Christoffer Lerno.
|
||||
*
|
||||
* This game has been created using raylib v1.3 (www.raylib.com)
|
||||
*
|
||||
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Some Defines
|
||||
//----------------------------------------------------------------------------------
|
||||
const SQUARE_SIZE = 20;
|
||||
const GRID_HORIZONTAL_SIZE = 12;
|
||||
const GRID_VERTICAL_SIZE = 20;
|
||||
|
||||
const LATERAL_SPEED = 10;
|
||||
const TURNING_SPEED = 12;
|
||||
const FAST_FALL_AWAIT_COUNTER = 30;
|
||||
const FADING_TIME = 33;
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Types and Structures Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
enum GridSquare { EMPTY, MOVING, FULL, BLOCK, FADING }
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Global Variables Declaration
|
||||
//------------------------------------------------------------------------------------
|
||||
const int SCREEN_WIDTH = 800;
|
||||
const int SCREEN_HEIGHT = 450;
|
||||
|
||||
bool game_over = false;
|
||||
bool pause = false;
|
||||
|
||||
// Matrices
|
||||
GridSquare[GRID_VERTICAL_SIZE][GRID_HORIZONTAL_SIZE] grid;
|
||||
GridSquare[4][4] piece;
|
||||
GridSquare[4][4] incoming_piece;
|
||||
|
||||
struct IntVec
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
}
|
||||
// These variables keep track of the active piece position
|
||||
int piece_position_x = 0;
|
||||
int piece_position_y = 0;
|
||||
|
||||
// Game parameters
|
||||
Color fading_color;
|
||||
//int fallingSpeed; // In frames
|
||||
|
||||
bool begin_play = true; // This var is only true at the begining of the game, used for the first matrix creations
|
||||
bool piece_active = false;
|
||||
bool detection = false;
|
||||
bool line_to_delete = false;
|
||||
|
||||
// Statistics
|
||||
int level = 1;
|
||||
int lines = 0;
|
||||
|
||||
// Counters
|
||||
int gravity_movement_counter = 0;
|
||||
int lateral_movement_counter = 0;
|
||||
int turn_movement_counter = 0;
|
||||
int fast_fall_movement_counter = 0;
|
||||
|
||||
int fade_line_counter = 0;
|
||||
|
||||
// Based on level
|
||||
int gravity_speed = 30;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Program main entry point
|
||||
//------------------------------------------------------------------------------------
|
||||
fn void main()
|
||||
{
|
||||
// Initialization (Note windowTitle is unused on Android)
|
||||
//---------------------------------------------------------
|
||||
raylib::init_window(SCREEN_WIDTH, SCREEN_HEIGHT, "classic game: tetris");
|
||||
|
||||
init_game();
|
||||
|
||||
raylib::set_target_fps(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Main game loop
|
||||
while (!raylib::window_should_close()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update and Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
update_draw_frame();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
unload_game(); // Unload loaded data (textures, sounds, models...)
|
||||
|
||||
raylib::close_window(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Game Module Functions Definition
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Initialize game variables
|
||||
fn void init_game()
|
||||
{
|
||||
// Initialize game statistics
|
||||
level = 1;
|
||||
lines = 0;
|
||||
|
||||
fading_color = raylib::GRAY;
|
||||
|
||||
piece_position_x = 0;
|
||||
piece_position_y = 0;
|
||||
|
||||
pause = false;
|
||||
|
||||
begin_play = true;
|
||||
piece_active = false;
|
||||
detection = false;
|
||||
line_to_delete = false;
|
||||
|
||||
// Counters
|
||||
gravity_movement_counter = 0;
|
||||
lateral_movement_counter = 0;
|
||||
turn_movement_counter = 0;
|
||||
fast_fall_movement_counter = 0;
|
||||
|
||||
fade_line_counter = 0;
|
||||
gravity_speed = 30;
|
||||
|
||||
// Initialize grid matrices
|
||||
for (int i = 0; i < GRID_HORIZONTAL_SIZE; i++)
|
||||
{
|
||||
for (int j = 0; j < GRID_VERTICAL_SIZE; j++)
|
||||
{
|
||||
if ((j == GRID_VERTICAL_SIZE - 1) || (i == 0) || (i == GRID_HORIZONTAL_SIZE - 1))
|
||||
{
|
||||
grid[i][j] = BLOCK;
|
||||
}
|
||||
else
|
||||
{
|
||||
grid[i][j] = EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize incoming piece matrices
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
for (int j = 0; j< 4; j++)
|
||||
{
|
||||
incoming_piece[i][j] = EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update game (one frame)
|
||||
fn void update_game()
|
||||
{
|
||||
if (game_over)
|
||||
{
|
||||
if (raylib::is_key_pressed(keyboard::ENTER))
|
||||
{
|
||||
init_game();
|
||||
game_over = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (raylib::is_key_pressed((KeyboardKey)'P')) pause = !pause;
|
||||
|
||||
if (pause) return;
|
||||
if (line_to_delete)
|
||||
{
|
||||
// Animation when deleting lines
|
||||
fade_line_counter++;
|
||||
|
||||
fading_color = fade_line_counter % 8 < 4 ? raylib::MAROON : raylib::GRAY;
|
||||
|
||||
if (fade_line_counter >= FADING_TIME)
|
||||
{
|
||||
lines += delete_complete_lines();
|
||||
fade_line_counter = 0;
|
||||
line_to_delete = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!piece_active)
|
||||
{
|
||||
// Get another piece
|
||||
piece_active = create_piece();
|
||||
|
||||
// We leave a little time before starting the fast falling down
|
||||
fast_fall_movement_counter = 0;
|
||||
}
|
||||
else // Piece falling
|
||||
{
|
||||
// Counters update
|
||||
fast_fall_movement_counter++;
|
||||
gravity_movement_counter++;
|
||||
lateral_movement_counter++;
|
||||
turn_movement_counter++;
|
||||
|
||||
// We make sure to move if we've pressed the key this frame
|
||||
if (raylib::is_key_pressed(keyboard::LEFT) || raylib::is_key_pressed(keyboard::RIGHT)) lateral_movement_counter = LATERAL_SPEED;
|
||||
if (raylib::is_key_pressed(keyboard::UP)) turn_movement_counter = TURNING_SPEED;
|
||||
|
||||
// Fall down
|
||||
if (raylib::is_key_down(keyboard::DOWN) && (fast_fall_movement_counter >= FAST_FALL_AWAIT_COUNTER))
|
||||
{
|
||||
// We make sure the piece is going to fall this frame
|
||||
gravity_movement_counter += gravity_speed;
|
||||
}
|
||||
|
||||
if (gravity_movement_counter >= gravity_speed)
|
||||
{
|
||||
// Basic falling movement
|
||||
if (check_detection()) detection = true;
|
||||
|
||||
// Check if the piece has collided with another piece or with the boundings
|
||||
resolve_falling_movement(&detection, &piece_active);
|
||||
|
||||
// Check if we fullfilled a line and if so, erase the line and pull down the the lines above
|
||||
check_completion(&line_to_delete);
|
||||
|
||||
gravity_movement_counter = 0;
|
||||
}
|
||||
|
||||
// Move laterally at player's will
|
||||
if (lateral_movement_counter >= LATERAL_SPEED)
|
||||
{
|
||||
// Update the lateral movement and if success, reset the lateral counter
|
||||
if (!resolve_lateral_movement()) lateral_movement_counter = 0;
|
||||
}
|
||||
|
||||
// Turn the piece at player's will
|
||||
if (turn_movement_counter >= TURNING_SPEED)
|
||||
{
|
||||
// Update the turning movement and reset the turning counter
|
||||
if (resolve_turn_movement()) turn_movement_counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Game over logic
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
|
||||
{
|
||||
if (grid[i][j] == GridSquare.FULL)
|
||||
{
|
||||
game_over = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw game (one frame)
|
||||
fn void draw_game()
|
||||
{
|
||||
raylib::begin_drawing();
|
||||
|
||||
raylib::clear_background(raylib::RAYWHITE);
|
||||
|
||||
if (game_over)
|
||||
{
|
||||
raylib::draw_text("PRESS [ENTER] TO PLAY AGAIN", raylib::get_screen_width() / 2 - raylib::measure_text("PRESS [ENTER] TO PLAY AGAIN", 20) / 2, raylib::get_screen_height() / 2 - 50, 20, raylib::GRAY);
|
||||
raylib::end_drawing();
|
||||
return;
|
||||
}
|
||||
|
||||
// Draw gameplay area
|
||||
IntVec offset = {
|
||||
SCREEN_WIDTH / 2 - (GRID_HORIZONTAL_SIZE * SQUARE_SIZE / 2) - 50,
|
||||
SCREEN_HEIGHT / 2 - ((GRID_VERTICAL_SIZE - 1) * SQUARE_SIZE / 2) + SQUARE_SIZE * 2
|
||||
};
|
||||
offset.y -= 50; // NOTE: Harcoded position!
|
||||
|
||||
int controller = offset.x;
|
||||
|
||||
for (int j = 0; j < GRID_VERTICAL_SIZE; j++)
|
||||
{
|
||||
for (int i = 0; i < GRID_HORIZONTAL_SIZE; i++)
|
||||
{
|
||||
// Draw each square of the grid
|
||||
switch (grid[i][j])
|
||||
{
|
||||
case EMPTY:
|
||||
raylib::draw_line(offset.x, offset.y, offset.x + SQUARE_SIZE, offset.y, raylib::LIGHTGRAY );
|
||||
raylib::draw_line(offset.x, offset.y, offset.x, offset.y + SQUARE_SIZE, raylib::LIGHTGRAY );
|
||||
raylib::draw_line(offset.x + SQUARE_SIZE, offset.y, offset.x + SQUARE_SIZE, offset.y + SQUARE_SIZE, raylib::LIGHTGRAY );
|
||||
raylib::draw_line(offset.x, offset.y + SQUARE_SIZE, offset.x + SQUARE_SIZE, offset.y + SQUARE_SIZE, raylib::LIGHTGRAY );
|
||||
offset.x += SQUARE_SIZE;
|
||||
case FULL:
|
||||
raylib::draw_rectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, raylib::GRAY);
|
||||
offset.x += SQUARE_SIZE;
|
||||
case MOVING:
|
||||
raylib::draw_rectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, raylib::DARKGRAY);
|
||||
offset.x += SQUARE_SIZE;
|
||||
case BLOCK:
|
||||
raylib::draw_rectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, raylib::LIGHTGRAY);
|
||||
offset.x += SQUARE_SIZE;
|
||||
case FADING:
|
||||
raylib::draw_rectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, fading_color);
|
||||
offset.x += SQUARE_SIZE;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
offset.x = controller;
|
||||
offset.y += SQUARE_SIZE;
|
||||
}
|
||||
|
||||
// Draw incoming piece (hardcoded)
|
||||
offset.x = 500;
|
||||
offset.y = 45;
|
||||
|
||||
controller = offset.x;
|
||||
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
switch (incoming_piece[i][j])
|
||||
{
|
||||
case EMPTY:
|
||||
raylib::draw_line(offset.x, offset.y, offset.x + SQUARE_SIZE, offset.y, raylib::LIGHTGRAY);
|
||||
raylib::draw_line(offset.x, offset.y, offset.x, offset.y + SQUARE_SIZE, raylib::LIGHTGRAY);
|
||||
raylib::draw_line(offset.x + SQUARE_SIZE, offset.y, offset.x + SQUARE_SIZE, offset.y + SQUARE_SIZE, raylib::LIGHTGRAY);
|
||||
raylib::draw_line(offset.x, offset.y + SQUARE_SIZE, offset.x + SQUARE_SIZE, offset.y + SQUARE_SIZE, raylib::LIGHTGRAY);
|
||||
offset.x += SQUARE_SIZE;
|
||||
case MOVING:
|
||||
raylib::draw_rectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, raylib::GRAY);
|
||||
offset.x += SQUARE_SIZE;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
offset.x = controller;
|
||||
offset.y += SQUARE_SIZE;
|
||||
}
|
||||
|
||||
raylib::draw_text("INCOMING:", offset.x, offset.y - 100, 10, raylib::GRAY);
|
||||
raylib::draw_text(raylib::text_format("LINES: %04i", lines), offset.x, offset.y + 20, 10, raylib::GRAY);
|
||||
|
||||
if (pause)
|
||||
{
|
||||
raylib::draw_text("GAME PAUSED", SCREEN_WIDTH / 2 - raylib::measure_text("GAME PAUSED", 40)/2, SCREEN_HEIGHT/2 - 40, 40, raylib::GRAY);
|
||||
}
|
||||
raylib::end_drawing();
|
||||
}
|
||||
|
||||
// Unload game variables
|
||||
fn void unload_game()
|
||||
{
|
||||
// TODO: Unload all dynamic loaded data (textures, sounds, models...)
|
||||
}
|
||||
|
||||
// Update and Draw (one frame)
|
||||
fn void update_draw_frame()
|
||||
{
|
||||
update_game();
|
||||
draw_game();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Additional module functions
|
||||
//--------------------------------------------------------------------------------------
|
||||
fn bool create_piece()
|
||||
{
|
||||
piece_position_x = (int)((GRID_HORIZONTAL_SIZE - 4)/2);
|
||||
piece_position_y = 0;
|
||||
|
||||
// If the game is starting and you are going to create the first piece, we create an extra one
|
||||
if (begin_play)
|
||||
{
|
||||
get_random_piece();
|
||||
begin_play = false;
|
||||
}
|
||||
|
||||
// We assign the incoming piece to the actual piece
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
for (int j = 0; j< 4; j++)
|
||||
{
|
||||
piece[i][j] = incoming_piece[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
// We assign a random piece to the incoming one
|
||||
get_random_piece();
|
||||
|
||||
// Assign the piece to the grid
|
||||
for (int i = piece_position_x; i < piece_position_x + 4; i++)
|
||||
{
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
if (piece[i - (int)piece_position_x][j] == GridSquare.MOVING) grid[i][j] = MOVING;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
fn void get_random_piece()
|
||||
{
|
||||
int random = raylib::get_random_value(0, 6);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
incoming_piece[i][j] = EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
switch (random)
|
||||
{
|
||||
case 0:
|
||||
incoming_piece[1][1] = MOVING;
|
||||
incoming_piece[2][1] = MOVING;
|
||||
incoming_piece[1][2] = MOVING;
|
||||
incoming_piece[2][2] = MOVING; //Cube
|
||||
case 1:
|
||||
incoming_piece[1][0] = MOVING;
|
||||
incoming_piece[1][1] = MOVING;
|
||||
incoming_piece[1][2] = MOVING;
|
||||
incoming_piece[2][2] = MOVING; //L
|
||||
case 2:
|
||||
incoming_piece[1][2] = MOVING;
|
||||
incoming_piece[2][0] = MOVING;
|
||||
incoming_piece[2][1] = MOVING;
|
||||
incoming_piece[2][2] = MOVING; //L inversa
|
||||
case 3:
|
||||
incoming_piece[0][1] = MOVING;
|
||||
incoming_piece[1][1] = MOVING;
|
||||
incoming_piece[2][1] = MOVING;
|
||||
incoming_piece[3][1] = MOVING; //Recta
|
||||
case 4:
|
||||
incoming_piece[1][0] = MOVING;
|
||||
incoming_piece[1][1] = MOVING;
|
||||
incoming_piece[1][2] = MOVING;
|
||||
incoming_piece[2][1] = MOVING; //Creu tallada
|
||||
case 5:
|
||||
incoming_piece[1][1] = MOVING;
|
||||
incoming_piece[2][1] = MOVING;
|
||||
incoming_piece[2][2] = MOVING;
|
||||
incoming_piece[3][2] = MOVING; //S
|
||||
case 6:
|
||||
incoming_piece[1][2] = MOVING;
|
||||
incoming_piece[2][2] = MOVING;
|
||||
incoming_piece[2][1] = MOVING;
|
||||
incoming_piece[3][1] = MOVING; //S inversa
|
||||
default:
|
||||
unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
fn void resolve_falling_movement(bool* detection_ref, bool* piece_active_ref)
|
||||
{
|
||||
// If we finished moving this piece, we stop it
|
||||
if (*detection_ref)
|
||||
{
|
||||
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
|
||||
{
|
||||
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
|
||||
{
|
||||
if (grid[i][j] == GridSquare.MOVING)
|
||||
{
|
||||
grid[i][j] = FULL;
|
||||
*detection_ref = false;
|
||||
*piece_active_ref = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else // We move down the piece
|
||||
{
|
||||
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
|
||||
{
|
||||
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
|
||||
{
|
||||
if (grid[i][j] == GridSquare.MOVING)
|
||||
{
|
||||
grid[i][j+1] = MOVING;
|
||||
grid[i][j] = EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
piece_position_y++;
|
||||
}
|
||||
}
|
||||
|
||||
fn bool resolve_lateral_movement()
|
||||
{
|
||||
bool collision = false;
|
||||
|
||||
// Piece movement
|
||||
if (raylib::is_key_down(keyboard::LEFT)) // Move left
|
||||
{
|
||||
// Check if is possible to move to left
|
||||
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
|
||||
{
|
||||
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
|
||||
{
|
||||
if (grid[i][j] == GridSquare.MOVING)
|
||||
{
|
||||
// Check if we are touching the left wall or we have a full square at the left
|
||||
if ((i-1 == 0) || (grid[i-1][j] == GridSquare.FULL)) collision = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If able, move left
|
||||
if (!collision)
|
||||
{
|
||||
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
|
||||
{
|
||||
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++) // We check the matrix from left to right
|
||||
{
|
||||
// Move everything to the left
|
||||
if (grid[i][j] == GridSquare.MOVING)
|
||||
{
|
||||
grid[i-1][j] = MOVING;
|
||||
grid[i][j] = EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
piece_position_x--;
|
||||
}
|
||||
}
|
||||
else if (raylib::is_key_down(keyboard::RIGHT)) // Move right
|
||||
{
|
||||
// Check if is possible to move to right
|
||||
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
|
||||
{
|
||||
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
|
||||
{
|
||||
if (grid[i][j] == GridSquare.MOVING)
|
||||
{
|
||||
// Check if we are touching the right wall or we have a full square at the right
|
||||
if ((i+1 == GRID_HORIZONTAL_SIZE - 1) || (grid[i+1][j] == GridSquare.FULL))
|
||||
{
|
||||
collision = true;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If able move right
|
||||
if (!collision)
|
||||
{
|
||||
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
|
||||
{
|
||||
for (int i = GRID_HORIZONTAL_SIZE - 1; i >= 1; i--) // We check the matrix from right to left
|
||||
{
|
||||
// Move everything to the right
|
||||
if (grid[i][j] == GridSquare.MOVING)
|
||||
{
|
||||
grid[i+1][j] = MOVING;
|
||||
grid[i][j] = EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
piece_position_x++;
|
||||
}
|
||||
}
|
||||
|
||||
return collision;
|
||||
}
|
||||
|
||||
fn bool resolve_turn_movement()
|
||||
{
|
||||
// Input for turning the piece
|
||||
if (raylib::is_key_down(keyboard::UP))
|
||||
{
|
||||
GridSquare aux;
|
||||
bool checker = false;
|
||||
|
||||
// Check all turning possibilities
|
||||
if ((grid[piece_position_x + 3][piece_position_y] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x][piece_position_y] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x][piece_position_y] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 3][piece_position_y + 3] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 3][piece_position_y] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 3][piece_position_y] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x][piece_position_y + 3] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 3][piece_position_y + 3] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 3][piece_position_y + 3] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x][piece_position_y] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x][piece_position_y + 3] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x][piece_position_y + 3] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 1][piece_position_y] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x][piece_position_y + 2] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x][piece_position_y + 2] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 3][piece_position_y + 1] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 1][piece_position_y] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 1][piece_position_y] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 2][piece_position_y + 3] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 3][piece_position_y + 1] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 3][piece_position_y + 1] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x][piece_position_y + 2] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 2][piece_position_y + 3] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 2][piece_position_y + 3] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 2][piece_position_y] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x][piece_position_y + 1] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x][piece_position_y + 1] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 3][piece_position_y + 2] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 2][piece_position_y] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 2][piece_position_y] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 1][piece_position_y + 3] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 3][piece_position_y + 2] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 3][piece_position_y + 2] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x][piece_position_y + 1] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 1][piece_position_y + 3] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 1][piece_position_y + 3] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 1][piece_position_y + 1] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 1][piece_position_y + 2] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 1][piece_position_y + 2] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 2][piece_position_y + 1] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 1][piece_position_y + 1] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 1][piece_position_y + 1] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 2][piece_position_y + 2] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 2][piece_position_y + 1] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 2][piece_position_y + 1] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 1][piece_position_y + 2] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 2][piece_position_y + 2] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 2][piece_position_y + 2] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if (!checker)
|
||||
{
|
||||
aux = piece[0][0];
|
||||
piece[0][0] = piece[3][0];
|
||||
piece[3][0] = piece[3][3];
|
||||
piece[3][3] = piece[0][3];
|
||||
piece[0][3] = aux;
|
||||
|
||||
aux = piece[1][0];
|
||||
piece[1][0] = piece[3][1];
|
||||
piece[3][1] = piece[2][3];
|
||||
piece[2][3] = piece[0][2];
|
||||
piece[0][2] = aux;
|
||||
|
||||
aux = piece[2][0];
|
||||
piece[2][0] = piece[3][2];
|
||||
piece[3][2] = piece[1][3];
|
||||
piece[1][3] = piece[0][1];
|
||||
piece[0][1] = aux;
|
||||
|
||||
aux = piece[1][1];
|
||||
piece[1][1] = piece[2][1];
|
||||
piece[2][1] = piece[2][2];
|
||||
piece[2][2] = piece[1][2];
|
||||
piece[1][2] = aux;
|
||||
}
|
||||
|
||||
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
|
||||
{
|
||||
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
|
||||
{
|
||||
if (grid[i][j] == GridSquare.MOVING)
|
||||
{
|
||||
grid[i][j] = EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = piece_position_x; i < piece_position_x + 4; i++)
|
||||
{
|
||||
for (int j = piece_position_y; j < piece_position_y + 4; j++)
|
||||
{
|
||||
if (piece[i - piece_position_x][j - piece_position_y] == GridSquare.MOVING)
|
||||
{
|
||||
grid[i][j] = MOVING;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
fn bool check_detection()
|
||||
{
|
||||
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
|
||||
{
|
||||
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
|
||||
{
|
||||
if ((grid[i][j] == GridSquare.MOVING) && ((grid[i][j+1] == GridSquare.FULL)
|
||||
|| (grid[i][j+1] == GridSquare.BLOCK))) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn void check_completion(bool *line_to_delete_ref)
|
||||
{
|
||||
int calculator = 0;
|
||||
|
||||
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
|
||||
{
|
||||
calculator = 0;
|
||||
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
|
||||
{
|
||||
// Count each square of the line
|
||||
if (grid[i][j] == GridSquare.FULL)
|
||||
{
|
||||
calculator++;
|
||||
}
|
||||
|
||||
// Check if we completed the whole line
|
||||
if (calculator == GRID_HORIZONTAL_SIZE - 2)
|
||||
{
|
||||
*line_to_delete_ref = true;
|
||||
calculator = 0;
|
||||
// points++;
|
||||
|
||||
// Mark the completed line
|
||||
for (int z = 1; z < GRID_HORIZONTAL_SIZE - 1; z++)
|
||||
{
|
||||
grid[z][j] = FADING;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn int delete_complete_lines()
|
||||
{
|
||||
int lines_to_erase = 0;
|
||||
// Erase the completed line
|
||||
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
|
||||
{
|
||||
while (grid[1][j] == GridSquare.FADING)
|
||||
{
|
||||
lines_to_erase++;
|
||||
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
|
||||
{
|
||||
grid[i][j] = GridSquare.EMPTY;
|
||||
}
|
||||
|
||||
for (int j2 = j-1; j2 >= 0; j2--)
|
||||
{
|
||||
for (int i2 = 1; i2 < GRID_HORIZONTAL_SIZE - 1; i2++)
|
||||
{
|
||||
switch (grid[i2][j2])
|
||||
{
|
||||
case FULL:
|
||||
grid[i2][j2+1] = GridSquare.FULL;
|
||||
grid[i2][j2] = GridSquare.EMPTY;
|
||||
case FADING:
|
||||
grid[i2][j2+1] = GridSquare.FADING;
|
||||
grid[i2][j2] = GridSquare.EMPTY;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return lines_to_erase;
|
||||
}
|
||||
|
||||
44
resources/examples/retry.c3
Normal file
44
resources/examples/retry.c3
Normal file
@@ -0,0 +1,44 @@
|
||||
module test;
|
||||
import libc;
|
||||
|
||||
fault TestErr
|
||||
{
|
||||
NOPE
|
||||
}
|
||||
|
||||
fn int! eventually_succeed()
|
||||
{
|
||||
static int i = 0;
|
||||
if (i++ < 3) return TestErr.NOPE!;
|
||||
return i * 3;
|
||||
}
|
||||
|
||||
macro @retry(#function, int retries = 3)
|
||||
{
|
||||
var $Type = $typeof(#function);
|
||||
anyerr e;
|
||||
do
|
||||
{
|
||||
$Type! result = #function;
|
||||
if (catch err = result)
|
||||
{
|
||||
e = err;
|
||||
continue;
|
||||
}
|
||||
return result;
|
||||
} while (retries-- > 0);
|
||||
return e!;
|
||||
}
|
||||
|
||||
fn void main()
|
||||
{
|
||||
int! result = @retry(eventually_succeed());
|
||||
if (try result)
|
||||
{
|
||||
libc::printf("Got result: %d\n", result);
|
||||
}
|
||||
else
|
||||
{
|
||||
libc::printf("Failed :(\n");
|
||||
}
|
||||
}
|
||||
67
resources/examples/spectralnorm.c3
Normal file
67
resources/examples/spectralnorm.c3
Normal file
@@ -0,0 +1,67 @@
|
||||
module spectralnorm;
|
||||
import std::mem;
|
||||
import std::array;
|
||||
|
||||
extern fn int atoi(char *s);
|
||||
extern fn int printf(char *s, ...);
|
||||
extern fn double sqrt(double);
|
||||
|
||||
double[] temparr;
|
||||
|
||||
fn double eval_A(int i, int j)
|
||||
{
|
||||
return 1.0 / ((i + j) * (i + j + 1) / 2 + i + 1);
|
||||
}
|
||||
|
||||
fn void eval_A_times_u(double[] u, double[] au)
|
||||
{
|
||||
foreach (i, &val : au)
|
||||
{
|
||||
*val = 0;
|
||||
foreach (j, uval : u)
|
||||
{
|
||||
*val += eval_A((int)(i), (int)(j)) * uval;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn void eval_At_times_u(double[] u, double[] au)
|
||||
{
|
||||
foreach (i, &val : au)
|
||||
{
|
||||
*val = 0;
|
||||
foreach (j, uval : u)
|
||||
{
|
||||
*val += eval_A((int)(j), (int)(i)) * uval;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn void eval_AtA_times_u(double[] u, double[] atau) @noinline
|
||||
{
|
||||
eval_A_times_u(u, temparr);
|
||||
eval_At_times_u(temparr, atau);
|
||||
}
|
||||
|
||||
fn int main(int argc, char **argv)
|
||||
{
|
||||
int n = (argc == 2) ? atoi(argv[1]) : 2000;
|
||||
temparr = array::alloc(double, n);
|
||||
double[] u = array::alloc(double, n);
|
||||
double[] v = array::alloc(double, n);
|
||||
foreach(&uval : u) *uval = 1;
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
eval_AtA_times_u(u, v);
|
||||
eval_AtA_times_u(v, u);
|
||||
}
|
||||
double vBv;
|
||||
double vv;
|
||||
foreach (i, vval : v)
|
||||
{
|
||||
vBv += u[i] * vval;
|
||||
vv += vval * vval;
|
||||
}
|
||||
printf("%0.9f\n", sqrt(vBv / vv));
|
||||
return 0;
|
||||
}
|
||||
20
resources/examples/swap.c3
Normal file
20
resources/examples/swap.c3
Normal file
@@ -0,0 +1,20 @@
|
||||
module test;
|
||||
import libc;
|
||||
|
||||
/**
|
||||
* @checked a = b, b = a
|
||||
*/
|
||||
macro void @swap(&a, &b)
|
||||
{
|
||||
$typeof(a) temp = a;
|
||||
a = b;
|
||||
b = temp;
|
||||
}
|
||||
|
||||
fn void main()
|
||||
{
|
||||
int x = 123;
|
||||
int y = 456;
|
||||
@swap(x, y);
|
||||
libc::printf("x: %d y: %d\n", x, y);
|
||||
}
|
||||
@@ -56,7 +56,7 @@ void comment(void);
|
||||
"void" { count(); return(VOID); }
|
||||
"volatile" { count(); return(VOLATILE); }
|
||||
"while" { count(); return(WHILE); }
|
||||
"func" { count(); return(FUNC); }
|
||||
"fn" { count(); return(FUNC); }
|
||||
"nil" { count(); return(NIL); }
|
||||
"next" { count(); return(NEXT); }
|
||||
"in" { count(); return(IN); }
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
module std::array;
|
||||
import std::mem;
|
||||
|
||||
macro make($Type, usize elements)
|
||||
{
|
||||
assert(elements > 0);
|
||||
$Type* ptr = mem::alloc($Type.sizeof, elements);
|
||||
return ptr[0..(elements - 1)];
|
||||
}
|
||||
|
||||
macro make_zero($Type, usize elements)
|
||||
{
|
||||
assert(elements > 0);
|
||||
$Type* ptr = mem::calloc($Type.sizeof, elements);
|
||||
return ptr[0..(elements - 1)];
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
module std::builtin;
|
||||
/*
|
||||
enum TypeKind
|
||||
{
|
||||
VOID,
|
||||
BOOL,
|
||||
FLOAT,
|
||||
INTEGER,
|
||||
STRUCT,
|
||||
UNION,
|
||||
ERROR,
|
||||
ENUM,
|
||||
ARRAY,
|
||||
POINTER,
|
||||
VAR_ARRAY,
|
||||
SUBARRAY,
|
||||
OPAQUE
|
||||
// ALIAS,
|
||||
}
|
||||
|
||||
struct TypeData
|
||||
{
|
||||
typeid typeId;
|
||||
TypeKind kind;
|
||||
int size;
|
||||
int alignment;
|
||||
char* name;
|
||||
char* fullName;
|
||||
}
|
||||
|
||||
struct TypeAlias
|
||||
{
|
||||
TypeData data;
|
||||
typeid aliasType;
|
||||
}
|
||||
|
||||
struct TypeError
|
||||
{
|
||||
TypeData data;
|
||||
TypeErrorValue[] errors;
|
||||
}
|
||||
|
||||
struct TypeArray
|
||||
{
|
||||
TypeData data;
|
||||
typeid elementType;
|
||||
ulong elements;
|
||||
}
|
||||
|
||||
struct TypeVarArray
|
||||
{
|
||||
TypeData data;
|
||||
typeid elementType;
|
||||
}
|
||||
|
||||
struct TypeSubarray
|
||||
{
|
||||
TypeData data;
|
||||
typeid elementType;
|
||||
}
|
||||
|
||||
struct TypePointer
|
||||
{
|
||||
TypeData data;
|
||||
typeid baseType;
|
||||
}
|
||||
|
||||
struct TypeStruct
|
||||
{
|
||||
TypeData data;
|
||||
TypeData*[] fields;
|
||||
}
|
||||
|
||||
struct TypeUnion
|
||||
{
|
||||
TypeData data;
|
||||
TypeData*[] variants;
|
||||
}
|
||||
|
||||
struct TypeEnum
|
||||
{
|
||||
TypeData data;
|
||||
typeid valueType;
|
||||
TypeData*[] associated_value_types;
|
||||
}
|
||||
|
||||
|
||||
struct TypeEnumValue
|
||||
{
|
||||
char* name;
|
||||
ulong value;
|
||||
void*[] associated_values;
|
||||
}
|
||||
|
||||
struct TypeErrorValue
|
||||
{
|
||||
char* name;
|
||||
ulong value;
|
||||
}
|
||||
*/
|
||||
@@ -1,14 +0,0 @@
|
||||
module std::env;
|
||||
|
||||
enum CompilerOptLevel
|
||||
{
|
||||
O0,
|
||||
O1,
|
||||
O2,
|
||||
O3
|
||||
}
|
||||
|
||||
const CompilerOptLevel COMPILER_OPT_LEVEL = (CompilerOptLevel)(${COMPILER_OPT_LEVEL});
|
||||
const bool BIG_ENDIAN = ${PLATFORM_BIG_ENDIAN};
|
||||
const bool I128_SUPPORT = ${PLATFORM_I128_SUPPORTED};
|
||||
const bool COMPILER_SAFE_MODE = ${COMPILER_SAFE_MODE};
|
||||
@@ -1,427 +0,0 @@
|
||||
module std::io;
|
||||
|
||||
errtype IoError
|
||||
{
|
||||
FILE_NOT_FOUND
|
||||
}
|
||||
/*
|
||||
extern File *stdin @cname(__stdinp);
|
||||
extern File *stdout @cname(__stdoutp);
|
||||
extern File *stderr @cname(__stderrp);
|
||||
*/
|
||||
/*
|
||||
extern func int fputc(int, aliased void*);
|
||||
extern func void clearerr(aliased void*);
|
||||
extern func int fclose(aliased void*);
|
||||
extern func int feof(aliased void*);
|
||||
extern func int ferror(aliased void*);
|
||||
extern func int fflush(aliased FILE *);
|
||||
extern func int fgetc(aliased FILE *);
|
||||
extern func int fgetpos(FILE *, fpos_t *);
|
||||
extern func int fseek(void*, long, int);
|
||||
extern func void* fopen(char *, char *);
|
||||
*/
|
||||
|
||||
struct File
|
||||
{
|
||||
void *file;
|
||||
}
|
||||
|
||||
extern func int _puts(char* message) @extname("puts");
|
||||
extern func int printf(char* message, ...);
|
||||
extern func int _putchar(char c) @extname("putchar");
|
||||
|
||||
extern File *__stdinp;
|
||||
|
||||
func int putchar(char c) @inline
|
||||
{
|
||||
return _putchar(c);
|
||||
}
|
||||
|
||||
func int print(char *message)
|
||||
{
|
||||
char* pointer = message;
|
||||
while (*pointer != '\0')
|
||||
{
|
||||
if (!putchar(*pointer)) return 0;
|
||||
pointer++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
func int println(char *message = "") @inline
|
||||
{
|
||||
return _puts(message);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
enum Seek
|
||||
{
|
||||
SET = 0,
|
||||
CURSOR = 1,
|
||||
END = 2
|
||||
}
|
||||
|
||||
error FileError
|
||||
{
|
||||
ulong errno;
|
||||
}
|
||||
|
||||
func FileError errorFromErrno()
|
||||
{
|
||||
return FileError { };
|
||||
}
|
||||
|
||||
public func void! File.open(File *file, char *filename, char *mode)
|
||||
{
|
||||
file.file = fopen(filename, mode);
|
||||
if (!file.file) return errorFromErrno()!;
|
||||
}
|
||||
|
||||
public func void! File.seek(File *file, long offset, Seek seekMode = Seek.SET)
|
||||
{
|
||||
if (fseek(file->file, offset, (int)(seekMode))) return errorFromErrno()!;
|
||||
}
|
||||
|
||||
public func void! File.putChar(File *file as char c)
|
||||
{
|
||||
if (fputc(c, file->file)) return errorFromErrno()!;
|
||||
}
|
||||
|
||||
pubic func void! File.clearerr(File *file) @inline
|
||||
{
|
||||
clearerr(file->file);
|
||||
}
|
||||
|
||||
func void File.close(File *file) @inline
|
||||
{
|
||||
if (fclose(file->file)) return errorFromErrno()!;
|
||||
}
|
||||
|
||||
func void File.eof(File *file) @inline
|
||||
{
|
||||
int err = feof(file->file);
|
||||
}
|
||||
|
||||
func void File.error(File *file) @inline
|
||||
{
|
||||
int err = ferror
|
||||
}
|
||||
*/
|
||||
/*
|
||||
|
||||
#define __SLBF 0x0001 /* line buffered */
|
||||
#define __SNBF 0x0002 /* unbuffered */
|
||||
#define __SRD 0x0004 /* OK to read */
|
||||
#define __SWR 0x0008 /* OK to write */
|
||||
/* RD and WR are never simultaneously asserted */
|
||||
#define __SRW 0x0010 /* open for reading & writing */
|
||||
#define __SEOF 0x0020 /* found EOF */
|
||||
#define __SERR 0x0040 /* found error */
|
||||
#define __SMBF 0x0080 /* _buf is from malloc */
|
||||
#define __SAPP 0x0100 /* fdopen()ed in append mode */
|
||||
#define __SSTR 0x0200 /* this is an sprintf/snprintf string */
|
||||
#define __SOPT 0x0400 /* do fseek() optimisation */
|
||||
#define __SNPT 0x0800 /* do not do fseek() optimisation */
|
||||
#define __SOFF 0x1000 /* set iff _offset is in fact correct */
|
||||
#define __SMOD 0x2000 /* true => fgetln modified _p text */
|
||||
#define __SALC 0x4000 /* allocate string space dynamically */
|
||||
#define __SIGN 0x8000 /* ignore this file in _fwalk */
|
||||
|
||||
/*
|
||||
* The following three definitions are for ANSI C, which took them
|
||||
* from System V, which brilliantly took internal interface macros and
|
||||
* made them official arguments to setvbuf(), without renaming them.
|
||||
* Hence, these ugly _IOxxx names are *supposed* to appear in user code.
|
||||
*
|
||||
* Although numbered as their counterparts above, the implementation
|
||||
* does not rely on this.
|
||||
*/
|
||||
#define _IOFBF 0 /* setvbuf should set fully buffered */
|
||||
#define _IOLBF 1 /* setvbuf should set line buffered */
|
||||
#define _IONBF 2 /* setvbuf should set unbuffered */
|
||||
|
||||
#define BUFSIZ 1024 /* size of buffer used by setbuf */
|
||||
#define EOF (-1)
|
||||
|
||||
/* must be == _POSIX_STREAM_MAX <limits.h> */
|
||||
#define FOPEN_MAX 20 /* must be <= OPEN_MAX <sys/syslimits.h> */
|
||||
#define FILENAME_MAX 1024 /* must be <= PATH_MAX <sys/syslimits.h> */
|
||||
|
||||
/* System V/ANSI C; this is the wrong way to do this, do *not* use these. */
|
||||
#ifndef _ANSI_SOURCE
|
||||
#define P_tmpdir "/var/tmp/"
|
||||
#endif
|
||||
#define L_tmpnam 1024 /* XXX must be == PATH_MAX */
|
||||
#define TMP_MAX 308915776
|
||||
|
||||
|
||||
#define stdin __stdinp
|
||||
#define stdout __stdoutp
|
||||
#define stderr __stderrp
|
||||
|
||||
|
||||
/* ANSI-C */
|
||||
|
||||
__BEGIN_DECLS
|
||||
char *fgets(char * __restrict, int, FILE *);
|
||||
#if defined(_DARWIN_UNLIMITED_STREAMS) || defined(_DARWIN_C_SOURCE)
|
||||
#else /* !_DARWIN_UNLIMITED_STREAMS && !_DARWIN_C_SOURCE */
|
||||
FILE *fopen(const char * __restrict __filename, const char * __restrict __mode) __DARWIN_ALIAS_STARTING(__MAC_10_6, __IPHONE_2_0, __DARWIN_ALIAS(fopen));
|
||||
#endif /* (DARWIN_UNLIMITED_STREAMS || _DARWIN_C_SOURCE) */
|
||||
int fprintf(FILE * __restrict, const char * __restrict, ...) __printflike(2, 3);
|
||||
int fputs(const char * __restrict, FILE * __restrict) __DARWIN_ALIAS(fputs);
|
||||
size_t fread(void * __restrict __ptr, size_t __size, size_t __nitems, FILE * __restrict __stream);
|
||||
FILE *freopen(const char * __restrict, const char * __restrict,
|
||||
FILE * __restrict) __DARWIN_ALIAS(freopen);
|
||||
int fscanf(FILE * __restrict, const char * __restrict, ...) __scanflike(2, 3);
|
||||
int fsetpos(FILE *, const fpos_t *);
|
||||
long ftell(FILE *);
|
||||
size_t fwrite(const void * __restrict __ptr, size_t __size, size_t __nitems, FILE * __restrict __stream) __DARWIN_ALIAS(fwrite);
|
||||
int getc(FILE *);
|
||||
int getchar(void);
|
||||
char *gets(char *);
|
||||
void perror(const char *) __cold;
|
||||
int printf(const char * __restrict, ...) __printflike(1, 2);
|
||||
int putc(int, FILE *);
|
||||
int putchar(int);
|
||||
int puts(const char *);
|
||||
int remove(const char *);
|
||||
int rename (const char *__old, const char *__new);
|
||||
void rewind(FILE *);
|
||||
int scanf(const char * __restrict, ...) __scanflike(1, 2);
|
||||
void setbuf(FILE * __restrict, char * __restrict);
|
||||
int setvbuf(FILE * __restrict, char * __restrict, int, size_t);
|
||||
int sprintf(char * __restrict, const char * __restrict, ...) __printflike(2, 3) __swift_unavailable("Use snprintf instead.");
|
||||
int sscanf(const char * __restrict, const char * __restrict, ...) __scanflike(2, 3);
|
||||
FILE *tmpfile(void);
|
||||
|
||||
__swift_unavailable("Use mkstemp(3) instead.")
|
||||
#if !defined(_POSIX_C_SOURCE)
|
||||
__deprecated_msg("This function is provided for compatibility reasons only. Due to security concerns inherent in the design of tmpnam(3), it is highly recommended that you use mkstemp(3) instead.")
|
||||
#endif
|
||||
char *tmpnam(char *);
|
||||
int ungetc(int, FILE *);
|
||||
int vfprintf(FILE * __restrict, const char * __restrict, va_list) __printflike(2, 0);
|
||||
int vprintf(const char * __restrict, va_list) __printflike(1, 0);
|
||||
int vsprintf(char * __restrict, const char * __restrict, va_list) __printflike(2, 0) __swift_unavailable("Use vsnprintf instead.");
|
||||
__END_DECLS
|
||||
|
||||
|
||||
|
||||
/* Additional functionality provided by:
|
||||
* POSIX.1-1988
|
||||
*/
|
||||
|
||||
#if __DARWIN_C_LEVEL >= 198808L
|
||||
#define L_ctermid 1024 /* size for ctermid(); PATH_MAX */
|
||||
|
||||
__BEGIN_DECLS
|
||||
#include <_ctermid.h>
|
||||
|
||||
#if defined(_DARWIN_UNLIMITED_STREAMS) || defined(_DARWIN_C_SOURCE)
|
||||
FILE *fdopen(int, const char *) __DARWIN_ALIAS_STARTING(__MAC_10_6, __IPHONE_3_2, __DARWIN_EXTSN(fdopen));
|
||||
#else /* !_DARWIN_UNLIMITED_STREAMS && !_DARWIN_C_SOURCE */
|
||||
FILE *fdopen(int, const char *) __DARWIN_ALIAS_STARTING(__MAC_10_6, __IPHONE_2_0, __DARWIN_ALIAS(fdopen));
|
||||
#endif /* (DARWIN_UNLIMITED_STREAMS || _DARWIN_C_SOURCE) */
|
||||
int fileno(FILE *);
|
||||
__END_DECLS
|
||||
#endif /* __DARWIN_C_LEVEL >= 198808L */
|
||||
|
||||
|
||||
/* Additional functionality provided by:
|
||||
* POSIX.2-1992 C Language Binding Option
|
||||
*/
|
||||
#if TARGET_OS_EMBEDDED
|
||||
#define __swift_unavailable_on(osx_msg, ios_msg) __swift_unavailable(ios_msg)
|
||||
#else
|
||||
#define __swift_unavailable_on(osx_msg, ios_msg) __swift_unavailable(osx_msg)
|
||||
#endif
|
||||
|
||||
#if __DARWIN_C_LEVEL >= 199209L
|
||||
__BEGIN_DECLS
|
||||
int pclose(FILE *) __swift_unavailable_on("Use posix_spawn APIs or NSTask instead.", "Process spawning is unavailable.");
|
||||
#if defined(_DARWIN_UNLIMITED_STREAMS) || defined(_DARWIN_C_SOURCE)
|
||||
FILE *popen(const char *, const char *) __DARWIN_ALIAS_STARTING(__MAC_10_6, __IPHONE_3_2, __DARWIN_EXTSN(popen)) __swift_unavailable_on("Use posix_spawn APIs or NSTask instead.", "Process spawning is unavailable.");
|
||||
#else /* !_DARWIN_UNLIMITED_STREAMS && !_DARWIN_C_SOURCE */
|
||||
FILE *popen(const char *, const char *) __DARWIN_ALIAS_STARTING(__MAC_10_6, __IPHONE_2_0, __DARWIN_ALIAS(popen)) __swift_unavailable_on("Use posix_spawn APIs or NSTask instead.", "Process spawning is unavailable.");
|
||||
#endif /* (DARWIN_UNLIMITED_STREAMS || _DARWIN_C_SOURCE) */
|
||||
__END_DECLS
|
||||
#endif /* __DARWIN_C_LEVEL >= 199209L */
|
||||
|
||||
#undef __swift_unavailable_on
|
||||
|
||||
/* Additional functionality provided by:
|
||||
* POSIX.1c-1995,
|
||||
* POSIX.1i-1995,
|
||||
* and the omnibus ISO/IEC 9945-1: 1996
|
||||
*/
|
||||
|
||||
#if __DARWIN_C_LEVEL >= 199506L
|
||||
|
||||
/* Functions internal to the implementation. */
|
||||
__BEGIN_DECLS
|
||||
int __srget(FILE *);
|
||||
int __svfscanf(FILE *, const char *, va_list) __scanflike(2, 0);
|
||||
int __swbuf(int, FILE *);
|
||||
__END_DECLS
|
||||
|
||||
/*
|
||||
* The __sfoo macros are here so that we can
|
||||
* define function versions in the C library.
|
||||
*/
|
||||
#define __sgetc(p) (--(p)->_r < 0 ? __srget(p) : (int)(*(p)->_p++))
|
||||
#if defined(__GNUC__) && defined(__STDC__)
|
||||
__header_always_inline int __sputc(int _c, FILE *_p) {
|
||||
if (--_p->_w >= 0 || (_p->_w >= _p->_lbfsize && (char)_c != '\n'))
|
||||
return (*_p->_p++ = _c);
|
||||
else
|
||||
return (__swbuf(_c, _p));
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* This has been tuned to generate reasonable code on the vax using pcc.
|
||||
*/
|
||||
#define __sputc(c, p) \
|
||||
(--(p)->_w < 0 ? \
|
||||
(p)->_w >= (p)->_lbfsize ? \
|
||||
(*(p)->_p = (c)), *(p)->_p != '\n' ? \
|
||||
(int)*(p)->_p++ : \
|
||||
__swbuf('\n', p) : \
|
||||
__swbuf((int)(c), p) : \
|
||||
(*(p)->_p = (c), (int)*(p)->_p++))
|
||||
#endif
|
||||
|
||||
#define __sfeof(p) (((p)->_flags & __SEOF) != 0)
|
||||
#define __sferror(p) (((p)->_flags & __SERR) != 0)
|
||||
#define __sclearerr(p) ((void)((p)->_flags &= ~(__SERR|__SEOF)))
|
||||
#define __sfileno(p) ((p)->_file)
|
||||
|
||||
__BEGIN_DECLS
|
||||
void flockfile(FILE *);
|
||||
int ftrylockfile(FILE *);
|
||||
void funlockfile(FILE *);
|
||||
int getc_unlocked(FILE *);
|
||||
int getchar_unlocked(void);
|
||||
int putc_unlocked(int, FILE *);
|
||||
int putchar_unlocked(int);
|
||||
|
||||
/* Removed in Issue 6 */
|
||||
#if !defined(_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 200112L
|
||||
int getw(FILE *);
|
||||
int putw(int, FILE *);
|
||||
#endif
|
||||
|
||||
__swift_unavailable("Use mkstemp(3) instead.")
|
||||
#if !defined(_POSIX_C_SOURCE)
|
||||
__deprecated_msg("This function is provided for compatibility reasons only. Due to security concerns inherent in the design of tempnam(3), it is highly recommended that you use mkstemp(3) instead.")
|
||||
#endif
|
||||
char *tempnam(const char *__dir, const char *__prefix) __DARWIN_ALIAS(tempnam);
|
||||
__END_DECLS
|
||||
|
||||
#ifndef lint
|
||||
#define getc_unlocked(fp) __sgetc(fp)
|
||||
#define putc_unlocked(x, fp) __sputc(x, fp)
|
||||
#endif /* lint */
|
||||
|
||||
#define getchar_unlocked() getc_unlocked(stdin)
|
||||
#define putchar_unlocked(x) putc_unlocked(x, stdout)
|
||||
#endif /* __DARWIN_C_LEVEL >= 199506L */
|
||||
|
||||
|
||||
|
||||
/* Additional functionality provided by:
|
||||
* POSIX.1-2001
|
||||
* ISO C99
|
||||
*/
|
||||
|
||||
#if __DARWIN_C_LEVEL >= 200112L
|
||||
#include <sys/_types/_off_t.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
int fseeko(FILE * __stream, off_t __offset, int __whence);
|
||||
off_t ftello(FILE * __stream);
|
||||
__END_DECLS
|
||||
#endif /* __DARWIN_C_LEVEL >= 200112L */
|
||||
|
||||
#if __DARWIN_C_LEVEL >= 200112L || defined(_C99_SOURCE) || defined(__cplusplus)
|
||||
__BEGIN_DECLS
|
||||
int snprintf(char * __restrict __str, size_t __size, const char * __restrict __format, ...) __printflike(3, 4);
|
||||
int vfscanf(FILE * __restrict __stream, const char * __restrict __format, va_list) __scanflike(2, 0);
|
||||
int vscanf(const char * __restrict __format, va_list) __scanflike(1, 0);
|
||||
int vsnprintf(char * __restrict __str, size_t __size, const char * __restrict __format, va_list) __printflike(3, 0);
|
||||
int vsscanf(const char * __restrict __str, const char * __restrict __format, va_list) __scanflike(2, 0);
|
||||
__END_DECLS
|
||||
#endif /* __DARWIN_C_LEVEL >= 200112L || defined(_C99_SOURCE) || defined(__cplusplus) */
|
||||
|
||||
|
||||
|
||||
/* Additional functionality provided by:
|
||||
* POSIX.1-2008
|
||||
*/
|
||||
|
||||
#if __DARWIN_C_LEVEL >= 200809L
|
||||
#include <sys/_types/_ssize_t.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
int dprintf(int, const char * __restrict, ...) __printflike(2, 3) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
|
||||
int vdprintf(int, const char * __restrict, va_list) __printflike(2, 0) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
|
||||
ssize_t getdelim(char ** __restrict __linep, size_t * __restrict __linecapp, int __delimiter, FILE * __restrict __stream) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
|
||||
ssize_t getline(char ** __restrict __linep, size_t * __restrict __linecapp, FILE * __restrict __stream) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
|
||||
FILE *fmemopen(void * __restrict __buf, size_t __size, const char * __restrict __mode) __API_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0));
|
||||
FILE *open_memstream(char **__bufp, size_t *__sizep) __API_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0));
|
||||
__END_DECLS
|
||||
#endif /* __DARWIN_C_LEVEL >= 200809L */
|
||||
|
||||
|
||||
|
||||
/* Darwin extensions */
|
||||
|
||||
#if __DARWIN_C_LEVEL >= __DARWIN_C_FULL
|
||||
__BEGIN_DECLS
|
||||
extern __const int sys_nerr; /* perror(3) external variables */
|
||||
extern __const char *__const sys_errlist[];
|
||||
|
||||
int asprintf(char ** __restrict, const char * __restrict, ...) __printflike(2, 3);
|
||||
char *ctermid_r(char *);
|
||||
char *fgetln(FILE *, size_t *);
|
||||
__const char *fmtcheck(const char *, const char *);
|
||||
int fpurge(FILE *);
|
||||
void setbuffer(FILE *, char *, int);
|
||||
int setlinebuf(FILE *);
|
||||
int vasprintf(char ** __restrict, const char * __restrict, va_list) __printflike(2, 0);
|
||||
FILE *zopen(const char *, const char *, int);
|
||||
|
||||
|
||||
/*
|
||||
* Stdio function-access interface.
|
||||
*/
|
||||
FILE *funopen(const void *,
|
||||
int (* _Nullable)(void *, char *, int),
|
||||
int (* _Nullable)(void *, const char *, int),
|
||||
fpos_t (* _Nullable)(void *, fpos_t, int),
|
||||
int (* _Nullable)(void *));
|
||||
__END_DECLS
|
||||
#define fropen(cookie, fn) funopen(cookie, fn, 0, 0, 0)
|
||||
#define fwopen(cookie, fn) funopen(cookie, 0, fn, 0, 0)
|
||||
|
||||
#define feof_unlocked(p) __sfeof(p)
|
||||
#define ferror_unlocked(p) __sferror(p)
|
||||
#define clearerr_unlocked(p) __sclearerr(p)
|
||||
#define fileno_unlocked(p) __sfileno(p)
|
||||
|
||||
#endif /* __DARWIN_C_LEVEL >= __DARWIN_C_FULL */
|
||||
|
||||
|
||||
#ifdef _USE_EXTENDED_LOCALES_
|
||||
#include <xlocale/_stdio.h>
|
||||
#endif /* _USE_EXTENDED_LOCALES_ */
|
||||
|
||||
#if defined (__GNUC__) && _FORTIFY_SOURCE > 0 && !defined (__cplusplus)
|
||||
/* Security checking functions. */
|
||||
#include <secure/_stdio.h>
|
||||
#endif
|
||||
|
||||
#endif /* _STDIO_H_ */
|
||||
*/
|
||||
@@ -1,155 +0,0 @@
|
||||
module std::array::list<Type>;
|
||||
import std::mem;
|
||||
|
||||
struct List
|
||||
{
|
||||
usize size;
|
||||
usize capacity;
|
||||
Type *entries;
|
||||
}
|
||||
|
||||
private func void List.ensureCapacity(List *list) @inline
|
||||
{
|
||||
if (list.capacity == list.size)
|
||||
{
|
||||
list.capacity = list.capacity ? 2 * list.capacity : 16;
|
||||
list.entries = mem::realloc(list.entries, $sizeof(Type) * list.capacity);
|
||||
}
|
||||
}
|
||||
|
||||
func void List.push(List *list, Type element) @inline
|
||||
{
|
||||
list.append(element);
|
||||
}
|
||||
|
||||
func void List.append(List *list, Type element)
|
||||
{
|
||||
list.ensureCapacity();
|
||||
list.entries[list.size++] = element;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require list.size > 0
|
||||
*/
|
||||
func Type List.pop(List *list)
|
||||
{
|
||||
return list.entries[--list.size];
|
||||
}
|
||||
|
||||
/**
|
||||
* @require list.size > 0
|
||||
*/
|
||||
func Type List.popFirst(List *list)
|
||||
{
|
||||
Type value = list.entries[0];
|
||||
list.removeAt(0);
|
||||
return value;
|
||||
}
|
||||
|
||||
func void List.removeAt(List *list, usize index)
|
||||
{
|
||||
for (usize i = index + 1; i < list.size; i++)
|
||||
{
|
||||
list.entries[i - 1] = list.entries[i];
|
||||
}
|
||||
list.size--;
|
||||
}
|
||||
|
||||
func void List.pushFront(List *list, Type type) @inline
|
||||
{
|
||||
list.insertAt(0, type);
|
||||
}
|
||||
|
||||
func void List.insertAt(List *list, usize index, Type type)
|
||||
{
|
||||
list.ensureCapacity();
|
||||
for (usize i = list.size; i > index; i--)
|
||||
{
|
||||
list.entries[i] = list.entries[i - 1];
|
||||
}
|
||||
list.size++;
|
||||
list.entries[index] = type;
|
||||
}
|
||||
|
||||
func void List.removeLast(List *list)
|
||||
{
|
||||
list.size--;
|
||||
}
|
||||
|
||||
func void List.removeFirst(List *list)
|
||||
{
|
||||
list.removeAt(0);
|
||||
}
|
||||
|
||||
func Type* List.first(List *list)
|
||||
{
|
||||
return list.size ? &list.entries[0] : null;
|
||||
}
|
||||
|
||||
func Type* List.last(List *list)
|
||||
{
|
||||
return list.size ? &list.entries[list.size - 1] : null;
|
||||
}
|
||||
|
||||
func bool List.isEmpty(List *list)
|
||||
{
|
||||
return list.size;
|
||||
}
|
||||
|
||||
func usize List.len(List *list)
|
||||
{
|
||||
return list.size;
|
||||
}
|
||||
|
||||
func Type List.get(List *list, usize index)
|
||||
{
|
||||
return list.entries[index];
|
||||
}
|
||||
|
||||
func void List.free(List *list)
|
||||
{
|
||||
mem::free(list.entries);
|
||||
list.capacity = 0;
|
||||
list.size = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
operator for(List *list; index, Type type)
|
||||
{
|
||||
$IndexType = typeof(index);
|
||||
$IndexType last_index = ($IndexType)(list.size);
|
||||
for ($IndexType i = 0; i < last_index; i++)
|
||||
{
|
||||
yield(i, list.entries[index]);
|
||||
}
|
||||
}
|
||||
|
||||
operator for(List *list; index, Type *type)
|
||||
{
|
||||
$IndexType = typeof(index);
|
||||
$IndexType last_index = ($IndexType)(list.size);
|
||||
for ($IndexType i = 0; i < last_index; i++)
|
||||
{
|
||||
yield(i, &list.entries[index]);
|
||||
}
|
||||
}
|
||||
|
||||
operator for(List *list; Type *type)
|
||||
{
|
||||
usize size = list.size;
|
||||
for (usize i = 0; i < last_index; i++)
|
||||
{
|
||||
yield(i, &list.entries[index]);
|
||||
}
|
||||
}
|
||||
*/
|
||||
/*
|
||||
operator for(List *list; Type type)
|
||||
{
|
||||
usize size = list.size;
|
||||
for (usize i = 0; i < last_index; i++)
|
||||
{
|
||||
yield(i, list.entries[index]);
|
||||
}
|
||||
}*/
|
||||
@@ -1,233 +0,0 @@
|
||||
module std::math;
|
||||
|
||||
// TODO Define these using quad precision.
|
||||
const E = 2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427427466;
|
||||
const LOG2E = 1.44269504088896340735992468100189214; // log2(e)
|
||||
const LOG10E = 0.434294481903251827651128918916605082; // log10(e)
|
||||
const LN2 = 0.693147180559945309417232121458176568; // ln(2)
|
||||
const LN10 = 2.30258509299404568401799145468436421; // ln(10)
|
||||
const PI = 3.14159265358979323846264338327950288419716939937510; // pi
|
||||
const PI_2 = 1.57079632679489661923132169163975144; // pi / 2
|
||||
const PI_4 = 0.785398163397448309615660845819875721; // pi / 4
|
||||
const DIV_PI = 0.318309886183790671537767526745028724; // 1 / pi
|
||||
const DIV_2_PI = 0.636619772367581343075535053490057448; // 2 / pi
|
||||
const DIV_2_SQRTPI = 1.12837916709551257389615890312154517; // 2/sqrt(pi)
|
||||
const SQRT2 = 1.41421356237309504880168872420969808; // sqrt(2)
|
||||
const DIV_1_SQRT2 = 0.707106781186547524400844362104849039; // 1 / sqrt(2)
|
||||
|
||||
const HALF_MAX = 6.5504e+4;
|
||||
const HALF_MIN = 6.103515625e-5;
|
||||
const HALF_DENORM_MIN = 5.9604644775390625e-8;
|
||||
const HALF_DIG = 3;
|
||||
const HALF_DEC_DIGITS = 5;
|
||||
const HALF_MANT_DIG = 11;
|
||||
const HALF_MAX_10_EXP = 4;
|
||||
const HALF_MIN_10_EXP = -4;
|
||||
const HALF_MAX_EXP = 16;
|
||||
const HALF_MIN_EXP = -13;
|
||||
const HALF_EPSILON = 9.765625e-4;
|
||||
|
||||
const FLOAT_MAX = 0x1.fffffep+127;
|
||||
const FLOAT_MIN = 1.17549435e-38;
|
||||
const FLOAT_DENORM_MIN = 1.40129846432481707092e-45;
|
||||
const FLOAT_DIG = 6;
|
||||
const FLOAT_DEC_DIGITS = 9;
|
||||
const FLOAT_MANT_DIG = 24;
|
||||
const FLOAT_MAX_10_EXP = 38;
|
||||
const FLOAT_MIN_10_EXP = -37;
|
||||
const FLOAT_MAX_EXP = 128;
|
||||
const FLOAT_MIN_EXP = -125;
|
||||
const FLOAT_EPSILON = 1.1920928955078125e-07;
|
||||
|
||||
const DOUBLE_MAX = 1.79769313486231570815e+308;
|
||||
const DOUBLE_MIN = 2.2250738585072014e-308;
|
||||
const DOUBLE_DENORM_MIN = 4.94065645841246544177e-324;
|
||||
const DOUBLE_DIG = 15;
|
||||
const DOUBLE_DEC_DIGITS = 17;
|
||||
const DOUBLE_MANT_DIG = 53;
|
||||
const DOUBLE_MAX_10_EXP = 308;
|
||||
const DOUBLE_MIN_10_EXP = -307;
|
||||
const DOUBLE_MAX_EXP = 1024;
|
||||
const DOUBLE_MIN_EXP = -1021;
|
||||
const DOUBLE_EPSILON = 2.22044604925031308085e-16;
|
||||
|
||||
const QUAD_MAX = 1.18973149535723176508575932662800702e+4932;
|
||||
const QUAD_MIN = 3.36210314311209350626267781732175260e-4932;
|
||||
const QUAD_DENORM_MIN = 6.47517511943802511092443895822764655e-4966;
|
||||
const QUAD_DIG = 33;
|
||||
const QUAD_DEC_DIGITS = 36;
|
||||
const QUAD_MANT_DIG = 113;
|
||||
const QUAD_MAX_10_EXP = 4932;
|
||||
const QUAD_MIN_10_EXP = -4931;
|
||||
const QUAD_MAX_EXP = 16384;
|
||||
const QUAD_MIN_EXP = -16481;
|
||||
const QUAD_EPSILON = 1.92592994438723585305597794258492732e-34;
|
||||
|
||||
private union DoubleLong
|
||||
{
|
||||
double f;
|
||||
ulong i;
|
||||
}
|
||||
|
||||
func double log10(double x)
|
||||
{
|
||||
const double IVLN10HI = 4.34294481878168880939e-01; /* 0x3fdbcb7b, 0x15200000 */
|
||||
const double IVLN10LO = 2.50829467116452752298e-11; /* 0x3dbb9438, 0xca9aadd5 */
|
||||
const double LOG10_2HI = 3.01029995663611771306e-01; /* 0x3FD34413, 0x509F6000 */
|
||||
const double LOG10_2LO = 3.69423907715893078616e-13; /* 0x3D59FEF3, 0x11F12B36 */
|
||||
const double LG1 = 6.666666666666735130e-01; /* 3FE55555 55555593 */
|
||||
const double LG2 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */
|
||||
const double LG3 = 2.857142874366239149e-01; /* 3FD24924 94229359 */
|
||||
const double LG4 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */
|
||||
const double LG5 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */
|
||||
const double LG6 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */
|
||||
const double LG7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */
|
||||
DoubleLong u = { .f = x };
|
||||
ulong hx = (uint)(u.i >> 32);
|
||||
int k = 0;
|
||||
if (hx < 0x00100000 || hx >> 31)
|
||||
{
|
||||
if (u.i << 1 == 0) return -1 / (x * x); /* log(+-0)=-inf */
|
||||
if (hx >> 31) return (x - x) / 0.0; /* log(-#) = NaN */
|
||||
/* subnormal number, scale x up */
|
||||
k -= 54;
|
||||
x *= 0x1p54;
|
||||
u.f = x;
|
||||
hx = (uint)(u.i >> 32);
|
||||
}
|
||||
else if (hx >= 0x7ff00000)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
else if (hx == 0x3ff00000 && u.i << 32 == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
/* reduce x into [sqrt(2)/2, sqrt(2)] */
|
||||
hx += 0x3ff00000 - 0x3fe6a09e;
|
||||
k += (int)(hx >> 20) - 0x3ff;
|
||||
hx = (hx & 0x000fffff) + 0x3fe6a09e;
|
||||
u.i = (ulong)(hx << 32) | (u.i & 0xffffffff);
|
||||
x = u.f;
|
||||
|
||||
hx += 0x3ff00000 - 0x3fe6a09e;
|
||||
k += (int)(hx >> 20) - 0x3ff;
|
||||
hx = (hx & 0x000fffff) + 0x3fe6a09e;
|
||||
u.i = (ulong)(hx << 32) | (u.i & 0xffffffff);
|
||||
x = u.f;
|
||||
|
||||
|
||||
double f = x - 1.0;
|
||||
double hfsq = 0.5 * f * f;
|
||||
double s = f / (2.0+f);
|
||||
double z = s * s;
|
||||
double w = z * z;
|
||||
double t1 = w * (LG2 + w * (LG4 + w * LG6));
|
||||
double t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7)));
|
||||
double r = t2 + t1;
|
||||
|
||||
/* See log2.c for details. */
|
||||
/* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */
|
||||
double hi = f - hfsq;
|
||||
u.f = hi;
|
||||
// u.i &= (ulong)(-1) << 32;
|
||||
u.i &= 0xFFFFFFFF00000000;
|
||||
hi = u.f;
|
||||
double lo = f - hi - hfsq + s * (hfsq + r);
|
||||
|
||||
/* val_hi+val_lo ~ log10(1+f) + k*log10(2) */
|
||||
double val_hi = hi * IVLN10HI;
|
||||
double dk = k;
|
||||
double y = dk * LOG10_2HI;
|
||||
double val_lo = dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo*IVLN10HI;
|
||||
|
||||
/*
|
||||
* Extra precision in for adding y is not strictly needed
|
||||
* since there is no very large cancellation near x = sqrt(2) or
|
||||
* x = 1/sqrt(2), but we do it anyway since it costs little on CPUs
|
||||
* with some parallelism and it reduces the error for many args.
|
||||
*/
|
||||
w = y + val_hi;
|
||||
val_lo += (y - w) + val_hi;
|
||||
val_hi = w;
|
||||
|
||||
return val_lo + val_hi;
|
||||
}
|
||||
|
||||
func double cos_limited(double x, double y)
|
||||
{
|
||||
const double C1 = 4.16666666666666019037e-02; /* 0x3FA55555, 0x5555554C */
|
||||
const double C2 = -1.38888888888741095749e-03; /* 0xBF56C16C, 0x16C15177 */
|
||||
const double C3 = 2.48015872894767294178e-05; /* 0x3EFA01A0, 0x19CB1590 */
|
||||
const double C4 = -2.75573143513906633035e-07; /* 0xBE927E4F, 0x809C52AD */
|
||||
const double C5 = 2.08757232129817482790e-09; /* 0x3E21EE9E, 0xBDB4B1C4 */
|
||||
const double C6 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */
|
||||
|
||||
double z = x * x;
|
||||
double w = z * z;
|
||||
double r = z * (C1+ z * (C2 + z * C3)) + w * w * (C4 + z * (C5 + z * C6));
|
||||
double hz = 0.5 * z;
|
||||
w = 1.0 - hz;
|
||||
return w + (((1.0 - w) - hz) + (z*r - x*y));
|
||||
}
|
||||
|
||||
private func double sin_limited(double x, double y, bool iy)
|
||||
{
|
||||
const double S1 = -1.66666666666666324348e-01; // 0xBFC55555, 0x55555549
|
||||
const double S2 = 8.33333333332248946124e-03; // 0x3F811111, 0x1110F8A6
|
||||
const double S3 = -1.98412698298579493134e-04; // 0xBF2A01A0, 0x19C161D5
|
||||
const double S4 = 2.75573137070700676789e-06; // 0x3EC71DE3, 0x57B1FE7D
|
||||
const double S5 = -2.50507602534068634195e-08; // 0xBE5AE5E6, 0x8A2B9CEB
|
||||
const double S6 = 1.58969099521155010221e-10; // 0x3DE5D93A, 0x5ACFD57C
|
||||
|
||||
double z = x * x;
|
||||
double w = z * z;
|
||||
double r = S2 + z * (S3 + z * S4) + z * w * (S5 + z * S6);
|
||||
double v = z * x;
|
||||
if (!iy)
|
||||
{
|
||||
return x + v * (S1 + z * r);
|
||||
}
|
||||
else
|
||||
{
|
||||
return x - ((z * (0.5 * y - v * r) - y) - v * S1);
|
||||
}
|
||||
}
|
||||
/*
|
||||
public func double cos(double x)
|
||||
{
|
||||
double[2] y;
|
||||
uint32_t ix;
|
||||
unsigned n;
|
||||
|
||||
GET_HIGH_WORD(ix, x);
|
||||
ix &= 0x7fffffff;
|
||||
|
||||
/* |x| ~< pi/4 */
|
||||
if (ix <= 0x3fe921fb)
|
||||
{
|
||||
if (ix < 0x3e46a09e)
|
||||
{
|
||||
// |x| < 2**-27 * sqrt(2)
|
||||
/* raise inexact if x!=0 */
|
||||
FORCE_EVAL(x + 0x1p120f);
|
||||
return 1.0;
|
||||
}
|
||||
return cos_limited(x, 0);
|
||||
}
|
||||
|
||||
/* cos(Inf or NaN) is NaN */
|
||||
if (ix >= 0x7ff00000) return x - x;
|
||||
|
||||
/* argument reduction */
|
||||
n = __rem_pio2(x, y);
|
||||
switch (n&3)
|
||||
{
|
||||
case 0: return cos_limited(y[0], y[1]);
|
||||
case 1: return -sin_limited(y[0], y[1], true);
|
||||
case 2: return -cos_limited(y[0], y[1]);
|
||||
default:
|
||||
return sin_limited(y[0], y[1], true);
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -1,9 +1,7 @@
|
||||
module antiprime;
|
||||
import std::io;
|
||||
|
||||
extern func int printf(char* message, ...);
|
||||
|
||||
func int countDivisors(int n)
|
||||
fn int countDivisors(int n)
|
||||
{
|
||||
if (n < 2) return 1;
|
||||
int count = 2;
|
||||
@@ -14,7 +12,7 @@ func int countDivisors(int n)
|
||||
return count;
|
||||
}
|
||||
|
||||
func int main()
|
||||
fn int main()
|
||||
{
|
||||
int maxDiv;
|
||||
int count;
|
||||
@@ -25,7 +23,7 @@ func int main()
|
||||
int d = countDivisors(n);
|
||||
if (d > maxDiv)
|
||||
{
|
||||
printf("%d ", n);
|
||||
io::printf("%d ", n);
|
||||
maxDiv = d;
|
||||
count++;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user