mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 20:11:17 +00:00
Compare commits
133 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
058d637407 | ||
|
|
01335f6862 | ||
|
|
d20d957881 | ||
|
|
008274cda5 | ||
|
|
e07ab7547f | ||
|
|
cf10837eb8 | ||
|
|
291b26f230 | ||
|
|
08e8c9bf57 | ||
|
|
625152440c | ||
|
|
fbd51821d1 | ||
|
|
c3ebf51295 | ||
|
|
9a9ff7f32c | ||
|
|
7b73eec82b | ||
|
|
75ba4a1cdb | ||
|
|
e5ca9065bd | ||
|
|
1042d0825f | ||
|
|
17942925f5 | ||
|
|
7424317d03 | ||
|
|
dbf1d91961 | ||
|
|
eb1644b302 | ||
|
|
cde5bc3263 | ||
|
|
e995e289db | ||
|
|
5020caa9c3 | ||
|
|
f34eb7d9f3 | ||
|
|
bf74ef0e5e | ||
|
|
0ff52311c3 | ||
|
|
e453e6f9ca | ||
|
|
6078598aff | ||
|
|
9fdb3b3b4a | ||
|
|
1362aa655f | ||
|
|
9c22ab8925 | ||
|
|
ca2dbb2f4b | ||
|
|
16bbc5a026 | ||
|
|
627f10cd18 | ||
|
|
13509b9231 | ||
|
|
ca88afbf5b | ||
|
|
42c9c9894b | ||
|
|
b4de62cfc2 | ||
|
|
226fbc191b | ||
|
|
4839d8861d | ||
|
|
789b47d565 | ||
|
|
c13cdcdd36 | ||
|
|
4ae3d0150f | ||
|
|
7d153a162a | ||
|
|
7bc3e94ff3 | ||
|
|
9c1fb26660 | ||
|
|
3dd725a0f0 | ||
|
|
a8aad53038 | ||
|
|
68c60f58c0 | ||
|
|
c9c3f33acc | ||
|
|
5ffc5187eb | ||
|
|
5d31cdfa16 | ||
|
|
e8ff4af5b9 | ||
|
|
723e1dd9a6 | ||
|
|
369a4558a3 | ||
|
|
5e6a3d9d8e | ||
|
|
62dca4f1c5 | ||
|
|
061c02306f | ||
|
|
f006b05010 | ||
|
|
c5a727aa9b | ||
|
|
e67e9d3bbf | ||
|
|
ea86c9d37a | ||
|
|
d1a2e6e5bd | ||
|
|
c96985f1db | ||
|
|
b7010c83e0 | ||
|
|
20a3d19ac7 | ||
|
|
0ded93ab9b | ||
|
|
ec82ec0426 | ||
|
|
6281f8ff89 | ||
|
|
2c9d2d4fd7 | ||
|
|
8569239bc1 | ||
|
|
5463c398cb | ||
|
|
7381734913 | ||
|
|
462322026f | ||
|
|
b5e5c719ed | ||
|
|
a0f4976b07 | ||
|
|
44c2486a74 | ||
|
|
5fc6672784 | ||
|
|
bcb1edba90 | ||
|
|
8099e7a75d | ||
|
|
cc9a501351 | ||
|
|
b536a23124 | ||
|
|
6ca5bcc6b8 | ||
|
|
ac966f118a | ||
|
|
f13472a8c3 | ||
|
|
0e213ae777 | ||
|
|
a0c82a6a47 | ||
|
|
a087ba608b | ||
|
|
9112d63655 | ||
|
|
3f7f7a0aa7 | ||
|
|
8d03aafe72 | ||
|
|
b0c0fd7dc8 | ||
|
|
c273f26cb3 | ||
|
|
60101830cc | ||
|
|
a58d782704 | ||
|
|
9b94c1dda9 | ||
|
|
201a6b350e | ||
|
|
b2724caeda | ||
|
|
9d99d556a1 | ||
|
|
a1a6511e26 | ||
|
|
652456646f | ||
|
|
ca0dc49f64 | ||
|
|
ae1b39eb60 | ||
|
|
22f7faf60e | ||
|
|
f3bf9eb14d | ||
|
|
347a1a48d4 | ||
|
|
c9793457f3 | ||
|
|
50d31ba398 | ||
|
|
2788c4cc00 | ||
|
|
ba54232b8d | ||
|
|
489bb70901 | ||
|
|
dd06dfa5ba | ||
|
|
f39e339726 | ||
|
|
295b374b48 | ||
|
|
8ed390c394 | ||
|
|
f9e9cac6e8 | ||
|
|
f3304acc93 | ||
|
|
a233771433 | ||
|
|
ea9a871d90 | ||
|
|
84d010bb2f | ||
|
|
e0ba468b7e | ||
|
|
f88c0dd645 | ||
|
|
758918c077 | ||
|
|
7b516e6113 | ||
|
|
61a76bb834 | ||
|
|
e6b6edefaf | ||
|
|
a228eb020d | ||
|
|
c46933a81a | ||
|
|
746046c8c0 | ||
|
|
acab95792f | ||
|
|
b882265e52 | ||
|
|
547f2ef189 | ||
|
|
69004943a7 |
68
.github/workflows/main.yml
vendored
68
.github/workflows/main.yml
vendored
@@ -51,7 +51,7 @@ jobs:
|
||||
run: |
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||
cd resources/testproject
|
||||
..\..\build\${{ matrix.build_type }}\c3c.exe --debug-log --emit-llvm run hello_world_win32
|
||||
..\..\build\${{ matrix.build_type }}\c3c.exe -vvv --emit-llvm run hello_world_win32
|
||||
dir build\llvm_ir
|
||||
..\..\build\${{ matrix.build_type }}\c3c.exe clean
|
||||
dir build\llvm_ir
|
||||
@@ -61,13 +61,19 @@ jobs:
|
||||
run: |
|
||||
cd resources/testproject
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||
..\..\build\${{ matrix.build_type }}\c3c.exe --debug-log build hello_world_win32_lib
|
||||
..\..\build\${{ matrix.build_type }}\c3c.exe -vvv build hello_world_win32_lib
|
||||
|
||||
- name: Compile and run dynlib-test
|
||||
run: |
|
||||
cd resources/examples/dynlib-test
|
||||
..\..\..\build\${{ matrix.build_type }}\c3c.exe dynamic-lib add.c3
|
||||
..\..\..\build\${{ matrix.build_type }}\c3c.exe compile-run test.c3 -l ./add.lib
|
||||
..\..\..\build\${{ matrix.build_type }}\c3c.exe -vv dynamic-lib add.c3
|
||||
..\..\..\build\${{ matrix.build_type }}\c3c.exe -vv compile-run test.c3 -l ./add.lib
|
||||
|
||||
- name: Compile and run staticlib-test
|
||||
run: |
|
||||
cd resources/examples/staticlib-test
|
||||
..\..\..\build\${{ matrix.build_type }}\c3c.exe -vv static-lib add.c3
|
||||
..\..\..\build\${{ matrix.build_type }}\c3c.exe -vv compile-run test.c3 -l ./add.lib
|
||||
|
||||
- name: Vendor-fetch
|
||||
run: |
|
||||
@@ -126,8 +132,8 @@ jobs:
|
||||
install: git binutils mingw-w64-x86_64-clang mingw-w64-x86_64-ninja mingw-w64-x86_64-cmake mingw-w64-x86_64-toolchain mingw-w64-x86_64-python
|
||||
- shell: msys2 {0}
|
||||
run: |
|
||||
pacman --noconfirm -U https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-llvm-18.1.8-1-any.pkg.tar.zst
|
||||
pacman --noconfirm -U https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-lld-18.1.8-1-any.pkg.tar.zst
|
||||
pacman --noconfirm -U https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-llvm-19.1.6-1-any.pkg.tar.zst
|
||||
pacman --noconfirm -U https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-lld-19.1.6-1-any.pkg.tar.zst
|
||||
- name: CMake
|
||||
run: |
|
||||
cmake -B build -G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
|
||||
@@ -147,7 +153,7 @@ jobs:
|
||||
- name: Build testproject
|
||||
run: |
|
||||
cd resources/testproject
|
||||
../../build/c3c run --debug-log
|
||||
../../build/c3c run -vvv
|
||||
|
||||
- name: Vendor-fetch
|
||||
run: |
|
||||
@@ -156,7 +162,7 @@ jobs:
|
||||
- name: Build testproject lib
|
||||
run: |
|
||||
cd resources/testproject
|
||||
../../build/c3c build hello_world_lib --cc cc --debug-log
|
||||
../../build/c3c build hello_world_lib --cc cc -vvv
|
||||
|
||||
- name: run compiler tests
|
||||
run: |
|
||||
@@ -203,12 +209,12 @@ jobs:
|
||||
- name: Build testproject
|
||||
run: |
|
||||
cd resources/testproject
|
||||
../../build/c3c run --debug-log
|
||||
../../build/c3c run -vvv
|
||||
|
||||
- name: Build testproject lib
|
||||
run: |
|
||||
cd resources/testproject
|
||||
../../build/c3c build hello_world_lib --debug-log
|
||||
../../build/c3c build hello_world_lib -vvv
|
||||
|
||||
- name: run compiler tests
|
||||
run: |
|
||||
@@ -222,7 +228,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
build_type: [Release, Debug]
|
||||
llvm_version: [17, 18, 19, 20]
|
||||
llvm_version: [17, 18, 19]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -320,12 +326,21 @@ jobs:
|
||||
- name: Compile and run dynlib-test
|
||||
run: |
|
||||
cd resources/examples/dynlib-test
|
||||
../../../build/c3c dynamic-lib add.c3
|
||||
../../../build/c3c -vv dynamic-lib add.c3
|
||||
mv add.so libadd.so
|
||||
cc test.c -L. -ladd -Wl,-rpath=.
|
||||
./a.out
|
||||
../../../build/c3c compile-run test.c3 -L . -l add -z -Wl,-rpath=.
|
||||
|
||||
- name: Compile and run staticlib-test
|
||||
run: |
|
||||
cd resources/examples/staticlib-test
|
||||
../../../build/c3c -vv static-lib add.c3
|
||||
mv add.a libadd.a
|
||||
cc test.c -L. -ladd
|
||||
./a.out
|
||||
../../../build/c3c compile-run test.c3 -L . -l add
|
||||
|
||||
- name: Compile run unit tests
|
||||
run: |
|
||||
cd test
|
||||
@@ -334,7 +349,7 @@ jobs:
|
||||
- name: Build testproject
|
||||
run: |
|
||||
cd resources/testproject
|
||||
../../build/c3c run --debug-log
|
||||
../../build/c3c run -vvv
|
||||
|
||||
- name: Test WASM
|
||||
run: |
|
||||
@@ -353,7 +368,7 @@ jobs:
|
||||
- name: Build testproject direct linker
|
||||
run: |
|
||||
cd resources/testproject
|
||||
../../build/c3c run --debug-log --linker=builtin
|
||||
../../build/c3c run -vvv --linker=builtin
|
||||
|
||||
- name: Init a library & a project
|
||||
run: |
|
||||
@@ -390,7 +405,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
build_type: [Release, Debug]
|
||||
llvm_version: [17, 18, 19, 20]
|
||||
llvm_version: [17, 18, 19]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install common deps
|
||||
@@ -476,12 +491,12 @@ jobs:
|
||||
- name: Build testproject
|
||||
run: |
|
||||
cd resources/testproject
|
||||
../../build/c3c run --debug-log
|
||||
../../build/c3c run -vvv
|
||||
|
||||
- name: Build testproject direct linker
|
||||
run: |
|
||||
cd resources/testproject
|
||||
../../build/c3c run --debug-log --linker=builtin
|
||||
../../build/c3c run -vvv --linker=builtin
|
||||
|
||||
- name: run compiler tests
|
||||
run: |
|
||||
@@ -511,7 +526,7 @@ jobs:
|
||||
matrix:
|
||||
ubuntu_version: [20.04, 22.04]
|
||||
build_type: [Release, Debug]
|
||||
llvm_version: [17, 18, 19, 20]
|
||||
llvm_version: [17, 18, 19]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -568,7 +583,7 @@ jobs:
|
||||
- name: Build testproject
|
||||
run: |
|
||||
cd resources/testproject
|
||||
../../build/c3c run --debug-log
|
||||
../../build/c3c run -vvv
|
||||
|
||||
- name: Test WASM
|
||||
run: |
|
||||
@@ -578,7 +593,7 @@ jobs:
|
||||
- name: Build testproject direct linker
|
||||
run: |
|
||||
cd resources/testproject
|
||||
../../build/c3c run --debug-log --linker=builtin
|
||||
../../build/c3c run -vvv --linker=builtin
|
||||
|
||||
- name: Init a library & a project
|
||||
run: |
|
||||
@@ -639,7 +654,7 @@ jobs:
|
||||
- name: Compile and run dynlib-test
|
||||
run: |
|
||||
cd resources/examples/dynlib-test
|
||||
../../../build/c3c dynamic-lib add.c3
|
||||
../../../build/c3c -vv dynamic-lib add.c3
|
||||
../../../build/c3c compile-run test.c3 -l ./add.dylib
|
||||
|
||||
- name: Compile run unit tests
|
||||
@@ -647,20 +662,25 @@ jobs:
|
||||
cd test
|
||||
../build/c3c compile-test unit
|
||||
|
||||
- name: Test WASM
|
||||
run: |
|
||||
cd resources/testfragments
|
||||
../../build/c3c compile --target wasm32 -g0 --no-entry -Os wasm4.c3
|
||||
|
||||
- name: Build testproject
|
||||
run: |
|
||||
cd resources/testproject
|
||||
../../build/c3c run --debug-log
|
||||
../../build/c3c run -vvv
|
||||
|
||||
- name: Build testproject direct linker
|
||||
run: |
|
||||
cd resources/testproject
|
||||
../../build/c3c run --debug-log --linker=builtin
|
||||
../../build/c3c run -vvv --linker=builtin
|
||||
|
||||
- name: Build testproject lib
|
||||
run: |
|
||||
cd resources/testproject
|
||||
../../build/c3c build hello_world_lib --debug-log
|
||||
../../build/c3c build hello_world_lib -vvv
|
||||
|
||||
- name: run compiler tests
|
||||
run: |
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -19,6 +19,7 @@
|
||||
|
||||
# Libraries
|
||||
*.lib
|
||||
*.tlb
|
||||
*.a
|
||||
*.la
|
||||
*.lo
|
||||
@@ -75,3 +76,6 @@ TAGS
|
||||
/.cache/
|
||||
/compile_commands.json
|
||||
|
||||
# 'nix build' resulting symlink
|
||||
result
|
||||
|
||||
|
||||
161
CMakeLists.txt
161
CMakeLists.txt
@@ -73,9 +73,9 @@ if(C3_USE_MIMALLOC)
|
||||
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}
|
||||
mimalloc
|
||||
GIT_REPOSITORY https://github.com/microsoft/mimalloc.git
|
||||
GIT_TAG ${C3_MIMALLOC_TAG}
|
||||
)
|
||||
FetchContent_MakeAvailable(mimalloc)
|
||||
endif()
|
||||
@@ -108,9 +108,9 @@ endif()
|
||||
# Clangd LSP support
|
||||
option(C3_ENABLE_CLANGD_LSP "Enable/Disable output of compile commands during generation." OFF)
|
||||
if(C3_ENABLE_CLANGD_LSP)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E create_symlink
|
||||
COMMAND ${CMAKE_COMMAND} -E create_symlink
|
||||
${CMAKE_BINARY_DIR}/compile_commands.json
|
||||
${CMAKE_SOURCE_DIR}/compile_commands.json
|
||||
)
|
||||
@@ -119,15 +119,15 @@ endif(C3_ENABLE_CLANGD_LSP)
|
||||
if(C3_WITH_LLVM)
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
|
||||
if (C3_LLVM_VERSION STREQUAL "auto")
|
||||
set(C3_LLVM_VERSION "18")
|
||||
set(C3_LLVM_VERSION "19")
|
||||
endif()
|
||||
FetchContent_Declare(
|
||||
LLVM_Windows
|
||||
URL https://github.com/c3lang/win-llvm/releases/download/llvm_18_1_8_with_rt/llvm-18.1.8-windows-amd64-msvc17-libcmt.7z
|
||||
URL https://github.com/c3lang/win-llvm/releases/download/llvm_19_1_5/llvm-19.1.5-windows-amd64-msvc17-libcmt.7z
|
||||
)
|
||||
FetchContent_Declare(
|
||||
LLVM_Windows_debug
|
||||
URL https://github.com/c3lang/win-llvm/releases/download/llvm_18_1_8_with_rt/llvm-18.1.8-windows-amd64-msvc17-libcmt-dbg.7z
|
||||
URL https://github.com/c3lang/win-llvm/releases/download/llvm_19_1_5/llvm-19.1.5-windows-amd64-msvc17-libcmt-dbg.7z
|
||||
)
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
message("Loading Windows LLVM debug libraries, this may take a while...")
|
||||
@@ -173,54 +173,54 @@ if(C3_WITH_LLVM)
|
||||
|
||||
if(NOT C3_LINK_DYNAMIC)
|
||||
set(LLVM_LINK_COMPONENTS
|
||||
AllTargetsAsmParsers
|
||||
AllTargetsCodeGens
|
||||
AllTargetsDescs
|
||||
AllTargetsDisassemblers
|
||||
AllTargetsInfos
|
||||
Analysis
|
||||
AsmPrinter
|
||||
BitReader
|
||||
Core
|
||||
DebugInfoPDB
|
||||
InstCombine
|
||||
IrReader
|
||||
LibDriver
|
||||
Linker
|
||||
LTO
|
||||
MC
|
||||
MCDisassembler
|
||||
native
|
||||
nativecodegen
|
||||
Object
|
||||
Option
|
||||
ScalarOpts
|
||||
Support
|
||||
Target
|
||||
TransformUtils
|
||||
WindowsManifest
|
||||
WindowsDriver
|
||||
AllTargetsAsmParsers
|
||||
AllTargetsCodeGens
|
||||
AllTargetsDescs
|
||||
AllTargetsDisassemblers
|
||||
AllTargetsInfos
|
||||
Analysis
|
||||
AsmPrinter
|
||||
BitReader
|
||||
Core
|
||||
DebugInfoPDB
|
||||
InstCombine
|
||||
IrReader
|
||||
LibDriver
|
||||
Linker
|
||||
LTO
|
||||
MC
|
||||
MCDisassembler
|
||||
native
|
||||
nativecodegen
|
||||
Object
|
||||
Option
|
||||
ScalarOpts
|
||||
Support
|
||||
Target
|
||||
TransformUtils
|
||||
WindowsManifest
|
||||
WindowsDriver
|
||||
)
|
||||
|
||||
llvm_map_components_to_libnames(llvm_libs ${LLVM_LINK_COMPONENTS})
|
||||
|
||||
if(NOT ${C3_LLD_DIR} EQUAL "" AND EXISTS ${C3_LLD_DIR})
|
||||
if(NOT ${C3_LLD_DIR} EQUAL "" AND EXISTS ${C3_LLD_DIR})
|
||||
message("C3_LLD_DIR: " ${C3_LLD_DIR})
|
||||
set(LLVM_LIBRARY_DIRS
|
||||
"${LLVM_LIBRARY_DIRS}"
|
||||
"${C3_LLD_DIR}"
|
||||
"${LLVM_LIBRARY_DIRS}"
|
||||
"${C3_LLD_DIR}"
|
||||
)
|
||||
list(REMOVE_DUPLICATES LLVM_LIBRARY_DIRS)
|
||||
endif()
|
||||
|
||||
# These don't seem to be reliable on windows.
|
||||
message(STATUS "using find_library")
|
||||
find_library(LLD_COFF NAMES liblldCOFF.dylib lldCOFF.lib lldCOFF.a liblldCOFF.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_COMMON NAMES liblldCommon.dylib lldCommon.lib lldCommon.a liblldCommon.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_ELF NAMES liblldELF.dylib lldELF.lib lldELF.a liblldELF.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_MACHO NAMES liblldMachO.dylib lldMachO.lib lldMachO.a liblldMachO.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_MINGW NAMES liblldMinGW.dylib lldMinGW.lib lldMinGW.a liblldMinGW.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_WASM NAMES liblldWasm.dylib lldWasm.lib lldWasm.a liblldWasm.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_COFF NAMES liblldCOFF.dylib lldCOFF.lib lldCOFF.a liblldCOFF.dll.a liblldCOFF.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_COMMON NAMES liblldCommon.dylib lldCommon.lib lldCommon.a liblldCommon.dll.a liblldCommon.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_ELF NAMES liblldELF.dylib lldELF.lib lldELF.a liblldELF.dll.a liblldELF.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_MACHO NAMES liblldMachO.dylib lldMachO.lib lldMachO.a liblldMachO.dll.a liblldMachO.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_MINGW NAMES liblldMinGW.dylib lldMinGW.lib lldMinGW.a liblldMinGW.dll.a liblldMinGW.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_WASM NAMES liblldWasm.dylib lldWasm.lib lldWasm.a liblldWasm.dll.a liblldWasm.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
else()
|
||||
find_library(LLVM NAMES libLLVM.so PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
set(llvm_libs ${LLVM})
|
||||
@@ -244,13 +244,13 @@ endif()
|
||||
if(C3_WITH_LLVM)
|
||||
find_library(LLD_LOONG NAMES libLLVMLoongArchCodeGen.lib libLLVMLoongArchAsmParser.lib libLLVMLoongArchCodeGen.a libLLVMLoongArchAsmParser.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
set(lld_libs
|
||||
${LLD_COFF}
|
||||
${LLD_COMMON}
|
||||
${LLD_WASM}
|
||||
${LLD_MINGW}
|
||||
${LLD_ELF}
|
||||
${LLD_MACHO}
|
||||
)
|
||||
${LLD_COFF}
|
||||
${LLD_COMMON}
|
||||
${LLD_WASM}
|
||||
${LLD_MINGW}
|
||||
${LLD_ELF}
|
||||
${LLD_MACHO}
|
||||
)
|
||||
|
||||
if (APPLE)
|
||||
set(lld_libs ${lld_libs} xar)
|
||||
@@ -264,7 +264,7 @@ if(C3_WITH_LLVM)
|
||||
# Unused
|
||||
# ${RT_UBSAN_DYNAMIC}
|
||||
# ${RT_LSAN_DYNAMIC}
|
||||
)
|
||||
)
|
||||
endif()
|
||||
|
||||
message(STATUS "linking to llvm libs ${lld_libs}")
|
||||
@@ -343,10 +343,10 @@ add_executable(c3c
|
||||
src/utils/cpus.c
|
||||
src/utils/unzipper.c
|
||||
src/compiler/decltable.c
|
||||
src/compiler/mac_support.c
|
||||
src/compiler/mac_support.c
|
||||
src/compiler/windows_support.c
|
||||
src/compiler/codegen_asm.c
|
||||
src/compiler/asm_target.c
|
||||
src/compiler/asm_target.c
|
||||
src/compiler/expr.c
|
||||
src/utils/time.c
|
||||
src/utils/http.c
|
||||
@@ -354,7 +354,7 @@ add_executable(c3c
|
||||
src/build/common_build.c
|
||||
src/compiler/sema_const.c
|
||||
${CMAKE_BINARY_DIR}/git_hash.h
|
||||
)
|
||||
)
|
||||
|
||||
if(GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
|
||||
# We are inside of a git repository so rebuilding the hash every time something changes.
|
||||
@@ -370,18 +370,19 @@ else()
|
||||
endif()
|
||||
|
||||
if(C3_WITH_LLVM)
|
||||
target_sources(c3c PRIVATE
|
||||
src/compiler/llvm_codegen.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/llvm_codegen_storeload.c
|
||||
src/compiler/llvm_codegen_builtins.c)
|
||||
target_sources(c3c PRIVATE
|
||||
src/compiler/c_codegen.c
|
||||
src/compiler/llvm_codegen.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/llvm_codegen_storeload.c
|
||||
src/compiler/llvm_codegen_builtins.c)
|
||||
|
||||
target_compile_definitions(c3c PUBLIC LLVM_AVAILABLE=1)
|
||||
add_library(c3c_wrappers STATIC wrapper/src/wrapper.cpp)
|
||||
@@ -409,7 +410,7 @@ if (C3_USE_TB)
|
||||
tilde-backend/src/tb/x64/*.c
|
||||
tilde-backend/src/tb/wasm/*.c
|
||||
tilde-backend/src/tb/aarch64/*.c
|
||||
)
|
||||
)
|
||||
target_sources(c3c PRIVATE
|
||||
src/compiler/tilde_codegen.c
|
||||
src/compiler/tilde_codegen_instr.c
|
||||
@@ -447,7 +448,7 @@ if(C3_WITH_LLVM)
|
||||
|
||||
target_link_libraries(c3c_wrappers ${llvm_libs} ${lld_libs})
|
||||
|
||||
else()
|
||||
else()
|
||||
|
||||
target_link_libraries(c3c ${llvm_libs} miniz ${lld_libs})
|
||||
|
||||
@@ -507,10 +508,10 @@ if(MSVC)
|
||||
if(C3_WITH_LLVM)
|
||||
set(clang_lib_dir ${llvm_dir}/lib/clang/${C3_LLVM_VERSION}/lib/windows)
|
||||
set(sanitizer_runtime_libraries
|
||||
${clang_lib_dir}/clang_rt.asan-x86_64.lib
|
||||
${clang_lib_dir}/clang_rt.asan_dynamic-x86_64.lib
|
||||
${clang_lib_dir}/clang_rt.asan_dynamic-x86_64.dll
|
||||
${clang_lib_dir}/clang_rt.asan_dynamic_runtime_thunk-x86_64.lib)
|
||||
${clang_lib_dir}/clang_rt.asan-x86_64.lib
|
||||
${clang_lib_dir}/clang_rt.asan_dynamic-x86_64.lib
|
||||
${clang_lib_dir}/clang_rt.asan_dynamic-x86_64.dll
|
||||
${clang_lib_dir}/clang_rt.asan_dynamic_runtime_thunk-x86_64.lib)
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "using gcc/clang warning switches")
|
||||
@@ -532,17 +533,17 @@ endif()
|
||||
|
||||
if (C3_WITH_LLVM AND DEFINED sanitizer_runtime_libraries)
|
||||
add_custom_command(TARGET c3c POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E rm -rf -- $<TARGET_FILE_DIR:c3c>/c3c_rt
|
||||
COMMAND "${CMAKE_COMMAND}" -E make_directory $<TARGET_FILE_DIR:c3c>/c3c_rt
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy ${sanitizer_runtime_libraries} $<TARGET_FILE_DIR:c3c>/c3c_rt
|
||||
VERBATIM
|
||||
COMMENT "Copying sanitizer runtime libraries to output directory")
|
||||
COMMAND "${CMAKE_COMMAND}" -E rm -rf -- $<TARGET_FILE_DIR:c3c>/c3c_rt
|
||||
COMMAND "${CMAKE_COMMAND}" -E make_directory $<TARGET_FILE_DIR:c3c>/c3c_rt
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy ${sanitizer_runtime_libraries} $<TARGET_FILE_DIR:c3c>/c3c_rt
|
||||
VERBATIM
|
||||
COMMENT "Copying sanitizer runtime libraries to output directory")
|
||||
|
||||
if (APPLE)
|
||||
# Change LC_ID_DYLIB to be rpath-based instead of having an absolute path
|
||||
add_custom_command(TARGET c3c POST_BUILD
|
||||
COMMAND find $<TARGET_FILE_DIR:c3c>/c3c_rt -type f -name "*.dylib" -execdir ${LLVM_TOOLS_BINARY_DIR}/llvm-install-name-tool -id @rpath/{} {} $<SEMICOLON>
|
||||
VERBATIM)
|
||||
COMMAND find $<TARGET_FILE_DIR:c3c>/c3c_rt -type f -name "*.dylib" -execdir ${LLVM_TOOLS_BINARY_DIR}/llvm-install-name-tool -id @rpath/{} {} $<SEMICOLON>
|
||||
VERBATIM)
|
||||
endif()
|
||||
|
||||
install(DIRECTORY $<TARGET_FILE_DIR:c3c>/c3c_rt/ DESTINATION bin/c3c_rt)
|
||||
|
||||
@@ -55,7 +55,7 @@ fn void Stack.push(Stack* this, Type element)
|
||||
if (this.capacity == this.size)
|
||||
{
|
||||
this.capacity *= 2;
|
||||
if (this.capacity < 16) this.capacity = 16;
|
||||
if (this.capacity < 16) this.capacity = 16;
|
||||
this.elems = realloc(this.elems, Type.sizeof * this.capacity);
|
||||
}
|
||||
this.elems[this.size++] = element;
|
||||
@@ -138,7 +138,7 @@ fn void main()
|
||||
|
||||
### Current status
|
||||
|
||||
The current stable version of the compiler is **version 0.6.3**.
|
||||
The current stable version of the compiler is **version 0.6.5**.
|
||||
|
||||
The upcoming 0.6.x releases will focus on expanding the standard library.
|
||||
Follow the issues [here](https://github.com/c3lang/c3c/issues).
|
||||
@@ -303,7 +303,7 @@ called `hello_world` or `hello_world.exe`depending on platform.
|
||||
|
||||
#### Compiling on Windows
|
||||
|
||||
1. Make sure you have Visual Studio 17 2022 installed or alternatively install the "Buildtools for Visual Studio" (https://aka.ms/vs/17/release/vs_BuildTools.exe) and then select "Desktop development with C++" (there is also `c3c/resources/install_win_reqs.bat` to automate this)
|
||||
1. Make sure you have Visual Studio 17 2022 installed or alternatively install the "Buildtools for Visual Studio" (https://aka.ms/vs/17/release/vs_BuildTools.exe) and then select "Desktop development with C++"
|
||||
2. Install CMake
|
||||
3. Clone the C3C github repository: `git clone https://github.com/c3lang/c3c.git`
|
||||
4. Enter the C3C directory `cd c3c`.
|
||||
|
||||
69
benchmarks/stdlib/sort/quicksort.c3
Normal file
69
benchmarks/stdlib/sort/quicksort.c3
Normal file
@@ -0,0 +1,69 @@
|
||||
module sort_bench;
|
||||
|
||||
import std::sort;
|
||||
|
||||
fn void init() @init
|
||||
{
|
||||
set_benchmark_warmup_iterations(5);
|
||||
set_benchmark_max_iterations(10_000);
|
||||
}
|
||||
|
||||
fn void! quicksort_bench() @benchmark
|
||||
{
|
||||
// test set: 500 numbers between 0 and 99;
|
||||
int[] data = {
|
||||
71, 28, 2, 13, 62, 10, 54, 78, 63, 86,
|
||||
33, 65, 89, 51, 58, 0, 51, 16, 87, 30,
|
||||
89, 14, 52, 41, 88, 25, 83, 91, 56, 86,
|
||||
14, 64, 76, 18, 39, 24, 79, 62, 34, 58,
|
||||
90, 24, 56, 73, 85, 82, 79, 63, 47, 69,
|
||||
78, 29, 49, 28, 43, 47, 56, 53, 79, 56,
|
||||
19, 63, 29, 52, 71, 93, 61, 46, 30, 11,
|
||||
21, 26, 37, 86, 93, 74, 62, 0, 41, 17,
|
||||
26, 27, 34, 11, 54, 69, 72, 44, 74, 3,
|
||||
61, 62, 80, 90, 3, 82, 16, 12, 28, 1,
|
||||
2, 49, 4, 44, 57, 86, 63, 74, 33, 41,
|
||||
76, 77, 56, 57, 56, 88, 74, 71, 6, 59,
|
||||
40, 42, 94, 55, 21, 17, 17, 63, 21, 83,
|
||||
73, 19, 39, 88, 93, 74, 21, 0, 63, 45,
|
||||
69, 66, 22, 68, 86, 86, 85, 67, 8, 50,
|
||||
23, 98, 64, 80, 64, 36, 40, 30, 73, 36,
|
||||
23, 14, 1, 77, 82, 8, 18, 73, 37, 86,
|
||||
29, 70, 27, 87, 64, 81, 13, 0, 4, 83,
|
||||
90, 17, 71, 66, 38, 39, 54, 22, 86, 18,
|
||||
84, 66, 77, 25, 64, 93, 80, 91, 2, 92,
|
||||
47, 32, 90, 16, 46, 29, 56, 87, 70, 73,
|
||||
89, 41, 5, 54, 93, 63, 16, 39, 71, 84,
|
||||
74, 91, 69, 59, 49, 87, 74, 37, 75, 83,
|
||||
77, 19, 51, 44, 79, 62, 94, 20, 24, 83,
|
||||
37, 70, 57, 32, 93, 8, 29, 11, 7, 92,
|
||||
8, 23, 20, 21, 7, 70, 28, 20, 96, 6,
|
||||
50, 58, 30, 61, 66, 42, 50, 54, 64, 7,
|
||||
10, 53, 63, 44, 16, 39, 83, 73, 3, 29,
|
||||
97, 32, 36, 68, 84, 64, 73, 5, 29, 13,
|
||||
48, 3, 84, 65, 75, 68, 66, 22, 39, 33,
|
||||
39, 24, 27, 85, 18, 34, 3, 63, 32, 9,
|
||||
29, 66, 24, 90, 75, 50, 11, 95, 47, 14,
|
||||
92, 1, 76, 45, 76, 41, 55, 54, 38, 67,
|
||||
43, 40, 5, 61, 97, 11, 61, 24, 92, 24,
|
||||
76, 53, 60, 34, 78, 80, 70, 75, 30, 90,
|
||||
65, 99, 80, 61, 94, 75, 63, 67, 10, 35,
|
||||
23, 42, 31, 48, 14, 68, 84, 14, 79, 1,
|
||||
25, 94, 23, 53, 49, 69, 44, 73, 63, 51,
|
||||
44, 96, 88, 51, 94, 24, 64, 72, 59, 81,
|
||||
73, 93, 14, 35, 9, 53, 25, 48, 50, 88,
|
||||
46, 97, 67, 40, 27, 17, 2, 42, 11, 82,
|
||||
0, 46, 44, 38, 31, 88, 63, 88, 10, 82,
|
||||
77, 61, 24, 39, 27, 33, 10, 91, 69, 22,
|
||||
42, 74, 71, 13, 32, 56, 12, 46, 81, 74,
|
||||
17, 26, 45, 50, 76, 84, 76, 36, 43, 65,
|
||||
81, 64, 0, 49, 70, 11, 76, 19, 60, 55,
|
||||
15, 98, 31, 91, 56, 8, 97, 9, 3, 94,
|
||||
3, 88, 7, 2, 3, 98, 10, 51, 21, 79,
|
||||
99, 3, 8, 76, 52, 13, 40, 90, 85, 15,
|
||||
70, 77, 43, 30, 4, 89, 18, 21, 59, 17,
|
||||
};
|
||||
sort::quicksort(data);
|
||||
}
|
||||
|
||||
|
||||
61
flake.lock
generated
Normal file
61
flake.lock
generated
Normal file
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1726560853,
|
||||
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1730958623,
|
||||
"narHash": "sha256-JwQZIGSYnRNOgDDoIgqKITrPVil+RMWHsZH1eE1VGN0=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "85f7e662eda4fa3a995556527c87b2524b691933",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
39
flake.nix
Normal file
39
flake.nix
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
description = "C3 compiler flake";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs?ref=nixpkgs-unstable";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs = { self, ... } @ inputs: inputs.flake-utils.lib.eachDefaultSystem
|
||||
(system:
|
||||
let pkgs = import inputs.nixpkgs { inherit system; }; in
|
||||
{
|
||||
packages = {
|
||||
default = self.packages.${system}.c3c;
|
||||
|
||||
c3c = pkgs.callPackage ./nix/default.nix {};
|
||||
|
||||
c3c-checks = pkgs.callPackage ./nix/default.nix {
|
||||
checks = true;
|
||||
};
|
||||
|
||||
c3c-debug = pkgs.callPackage ./nix/default.nix {
|
||||
debug = true;
|
||||
};
|
||||
|
||||
c3c-debug-checks = pkgs.callPackage ./nix/default.nix {
|
||||
debug = true;
|
||||
checks = true;
|
||||
};
|
||||
};
|
||||
|
||||
devShells = {
|
||||
default = pkgs.callPackage ./nix/shell.nix {
|
||||
c3c = self.packages.${system}.c3c-debug;
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -22,7 +22,7 @@ fn usz! EnumMap.to_format(&self, Formatter* formatter) @dynamic
|
||||
foreach (i, &value : self.values)
|
||||
{
|
||||
if (i != 0) formatter.print(", ")!;
|
||||
n += formatter.printf("%s: %s", (Enum)i, *value)!;
|
||||
n += formatter.printf("%s: %s", Enum.from_ordinal(i), *value)!;
|
||||
}
|
||||
n += formatter.print(" }")!;
|
||||
return n;
|
||||
|
||||
@@ -16,9 +16,9 @@ distinct EnumSet (Printable) = EnumSetType;
|
||||
fn void EnumSet.add(&self, Enum v)
|
||||
{
|
||||
$if IS_CHAR_ARRAY:
|
||||
(*self)[(usz)v / 8] |= (char)(1u << ((usz)v % 8));
|
||||
(*self)[(usz)v.ordinal / 8] |= (char)(1u << ((usz)v.ordinal % 8));
|
||||
$else
|
||||
*self = (EnumSet)((EnumSetType)*self | 1u << (EnumSetType)v);
|
||||
*self = (EnumSet)((EnumSetType)*self | 1u << (EnumSetType)v.ordinal);
|
||||
$endif
|
||||
}
|
||||
|
||||
@@ -35,11 +35,11 @@ fn bool EnumSet.remove(&self, Enum v)
|
||||
{
|
||||
$if IS_CHAR_ARRAY:
|
||||
if (!self.has(v) @inline) return false;
|
||||
(*self)[(usz)v / 8] &= (char)~(1u << ((usz)v % 8));
|
||||
(*self)[(usz)v.ordinal / 8] &= (char)~(1u << ((usz)v.ordinal % 8));
|
||||
return true;
|
||||
$else
|
||||
EnumSetType old = (EnumSetType)*self;
|
||||
EnumSetType new = old & ~(1u << (EnumSetType)v);
|
||||
EnumSetType new = old & ~(1u << (EnumSetType)v.ordinal);
|
||||
*self = (EnumSet)new;
|
||||
return old != new;
|
||||
$endif
|
||||
@@ -48,9 +48,9 @@ fn bool EnumSet.remove(&self, Enum v)
|
||||
fn bool EnumSet.has(&self, Enum v)
|
||||
{
|
||||
$if IS_CHAR_ARRAY:
|
||||
return (bool)(((*self)[(usz)v / 8] << ((usz)v % 8)) & 0x01);
|
||||
return (bool)(((*self)[(usz)v.ordinal / 8] << ((usz)v.ordinal % 8)) & 0x01);
|
||||
$else
|
||||
return ((EnumSetType)*self & (1u << (EnumSetType)v)) != 0;
|
||||
return ((EnumSetType)*self & (1u << (EnumSetType)v.ordinal)) != 0;
|
||||
$endif
|
||||
}
|
||||
|
||||
|
||||
@@ -400,6 +400,21 @@ fn bool HashMap.has_value(&map, Value v) @if(VALUE_IS_EQUATABLE)
|
||||
return false;
|
||||
}
|
||||
|
||||
fn HashMapIterator HashMap.iter(&self)
|
||||
{
|
||||
return { .map = self, .index = -1 };
|
||||
}
|
||||
|
||||
fn HashMapValueIterator HashMap.value_iter(&self)
|
||||
{
|
||||
return { .map = self, .index = -1 };
|
||||
}
|
||||
|
||||
fn HashMapKeyIterator HashMap.key_iter(&self)
|
||||
{
|
||||
return { .map = self, .index = -1 };
|
||||
}
|
||||
|
||||
// --- private methods
|
||||
|
||||
fn void HashMap.add_entry(&map, uint hash, Key key, Value value, uint bucket_index) @private
|
||||
@@ -455,8 +470,11 @@ fn void HashMap.put_all_for_create(&map, HashMap* other_map) @private
|
||||
if (!other_map.count) return;
|
||||
foreach (Entry *e : other_map.table)
|
||||
{
|
||||
if (!e) continue;
|
||||
map.put_for_create(e.key, e.value);
|
||||
while (e)
|
||||
{
|
||||
map.put_for_create(e.key, e.value);
|
||||
e = e.next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -482,6 +500,7 @@ fn void HashMap.free_internal(&map, void* ptr) @inline @private
|
||||
|
||||
fn bool HashMap.remove_entry_for_key(&map, Key key) @private
|
||||
{
|
||||
if (!map.count) return false;
|
||||
uint hash = rehash(key.hash());
|
||||
uint i = index_for(hash, map.table.len);
|
||||
Entry* prev = map.table[i];
|
||||
@@ -528,3 +547,54 @@ fn void HashMap.free_entry(&self, Entry *entry) @local
|
||||
self.free_internal(entry);
|
||||
}
|
||||
|
||||
|
||||
struct HashMapIterator
|
||||
{
|
||||
HashMap* map;
|
||||
int top_index;
|
||||
int index;
|
||||
Entry* current_entry;
|
||||
}
|
||||
|
||||
distinct HashMapValueIterator = HashMapIterator;
|
||||
distinct HashMapKeyIterator = HashMapIterator;
|
||||
|
||||
|
||||
<*
|
||||
@require idx < self.map.count
|
||||
*>
|
||||
fn Entry HashMapIterator.get(&self, usz idx) @operator([])
|
||||
{
|
||||
if (idx < self.index)
|
||||
{
|
||||
self.top_index = 0;
|
||||
self.current_entry = null;
|
||||
self.index = -1;
|
||||
}
|
||||
while (self.index != idx)
|
||||
{
|
||||
if (self.current_entry)
|
||||
{
|
||||
self.current_entry = self.current_entry.next;
|
||||
if (self.current_entry) self.index++;
|
||||
continue;
|
||||
}
|
||||
self.current_entry = self.map.table[self.top_index++];
|
||||
if (self.current_entry) self.index++;
|
||||
}
|
||||
return *self.current_entry;
|
||||
}
|
||||
|
||||
fn Value HashMapValueIterator.get(&self, usz idx) @operator([])
|
||||
{
|
||||
return ((HashMapIterator*)self).get(idx).value;
|
||||
}
|
||||
|
||||
fn Key HashMapKeyIterator.get(&self, usz idx) @operator([])
|
||||
{
|
||||
return ((HashMapIterator*)self).get(idx).key;
|
||||
}
|
||||
|
||||
fn usz HashMapValueIterator.len(self) @operator(len) => self.map.count;
|
||||
fn usz HashMapKeyIterator.len(self) @operator(len) => self.map.count;
|
||||
fn usz HashMapIterator.len(self) @operator(len) => self.map.count;
|
||||
|
||||
@@ -131,8 +131,11 @@ fn Map new_from_map(Map other_map, Allocator allocator = null)
|
||||
if (!other_map_impl.count) return (Map)map;
|
||||
foreach (Entry *e : other_map_impl.table)
|
||||
{
|
||||
if (!e) continue;
|
||||
map._put_for_create(e.key, e.value);
|
||||
while (e)
|
||||
{
|
||||
map._put_for_create(e.key, e.value);
|
||||
e = e.next;
|
||||
}
|
||||
}
|
||||
return (Map)map;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
<*
|
||||
@require values::@is_int(SIZE) &&& SIZE > 0 "The size must be positive integer"
|
||||
*>
|
||||
module std::collections::ringbuffer(<Type, SIZE>);
|
||||
|
||||
struct RingBuffer
|
||||
|
||||
@@ -98,7 +98,7 @@ fn void*! SimpleHeapAllocator._alloc(&self, usz bytes) @local
|
||||
return current + 1;
|
||||
case current.size > aligned_bytes:
|
||||
Header* unallocated = (Header*)((char*)current + aligned_bytes + Header.sizeof);
|
||||
unallocated.size = current.size - aligned_bytes;
|
||||
unallocated.size = current.size - aligned_bytes - Header.sizeof;
|
||||
unallocated.next = current.next;
|
||||
if (current == self.free_list)
|
||||
{
|
||||
|
||||
@@ -62,7 +62,7 @@ fn void OnStackAllocator.release(&self, void* old_pointer, bool aligned) @dynami
|
||||
{
|
||||
if (allocation_in_stack_mem(self, old_pointer)) return;
|
||||
on_stack_allocator_remove_chunk(self, old_pointer);
|
||||
self.release(old_pointer, aligned);
|
||||
self.backing_allocator.release(old_pointer, aligned);
|
||||
}
|
||||
|
||||
fn bool allocation_in_stack_mem(OnStackAllocator* a, void* ptr) @local
|
||||
|
||||
@@ -179,8 +179,10 @@ fn void*! TempAllocator.acquire(&self, usz size, AllocInitType init_type, usz al
|
||||
{
|
||||
mem = allocator::malloc_aligned(self.backing_allocator, total_alloc_size, alignment)!;
|
||||
}
|
||||
void* start = mem;
|
||||
mem += mem::aligned_offset(TempAllocatorPage.sizeof, alignment);
|
||||
page = (TempAllocatorPage*)mem - 1;
|
||||
page.start = mem;
|
||||
page.start = start;
|
||||
page.size = size | PAGE_IS_ALIGNED;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -17,15 +17,16 @@ macro index_of(array, element)
|
||||
}
|
||||
|
||||
<*
|
||||
@require @typekind(array) == VECTOR || @typekind(array) == ARRAY
|
||||
@require @typekind(array[0]) == VECTOR || @typekind(array[0]) == ARRAY
|
||||
@require @typekind(array_ptr) == POINTER
|
||||
@require @typekind(*array_ptr) == VECTOR || @typekind(*array_ptr) == ARRAY
|
||||
@require @typekind((*array_ptr)[0]) == VECTOR || @typekind((*array_ptr)[0]) == ARRAY
|
||||
*>
|
||||
macro slice2d(array, x = 0, xlen = 0, y = 0, ylen = 0)
|
||||
macro slice2d(array_ptr, x = 0, xlen = 0, y = 0, ylen = 0)
|
||||
{
|
||||
if (xlen < 1) xlen = $typeof(array[0]).len + xlen;
|
||||
if (ylen < 1) ylen = $typeof(array).len + ylen;
|
||||
var $ElementType = $typeof(array[0][0]);
|
||||
return Slice2d(<$ElementType>) { ($ElementType*)&array, $typeof(array[0]).len, y, ylen, x, xlen };
|
||||
if (xlen < 1) xlen = $typeof((*array_ptr)[0]).len + xlen;
|
||||
if (ylen < 1) ylen = $typeof((*array_ptr)).len + ylen;
|
||||
var $ElementType = $typeof((*array_ptr)[0][0]);
|
||||
return Slice2d(<$ElementType>) { ($ElementType*)array_ptr, $typeof((*array_ptr)[0]).len, y, ylen, x, xlen };
|
||||
}
|
||||
|
||||
|
||||
@@ -145,11 +146,41 @@ macro void Slice2d.@each_ref(&self; @body(usz[<2>], Type*))
|
||||
<*
|
||||
@require idy >= 0 && idy < self.ylen
|
||||
*>
|
||||
macro Type[] Slice2d.get(self, usz idy) @operator([])
|
||||
macro Type[] Slice2d.get_row(self, usz idy) @operator([])
|
||||
{
|
||||
return (self.ptr + self.inner_len * (idy + self.ystart))[self.xstart:self.xlen];
|
||||
}
|
||||
|
||||
macro Type Slice2d.get_coord(self, usz[<2>] coord)
|
||||
{
|
||||
return *self.get_coord_ref(coord);
|
||||
}
|
||||
|
||||
macro Type Slice2d.get_xy(self, x, y)
|
||||
{
|
||||
return *self.get_xy_ref(x, y);
|
||||
}
|
||||
|
||||
macro Type* Slice2d.get_xy_ref(self, x, y)
|
||||
{
|
||||
return self.ptr + self.inner_len * (y + self.ystart) + self.xstart + x;
|
||||
}
|
||||
|
||||
macro Type* Slice2d.get_coord_ref(self, usz[<2>] coord)
|
||||
{
|
||||
return self.get_xy_ref(coord.x, coord.y);
|
||||
}
|
||||
|
||||
macro void Slice2d.set_coord(self, usz[<2>] coord, Type value)
|
||||
{
|
||||
*self.get_coord_ref(coord) = value;
|
||||
}
|
||||
|
||||
macro void Slice2d.set_xy(self, x, y, Type value)
|
||||
{
|
||||
*self.get_xy_ref(x, y) = value;
|
||||
}
|
||||
|
||||
<*
|
||||
@require y >= 0 && y < self.ylen
|
||||
@require x >= 0 && x < self.xlen
|
||||
|
||||
@@ -4,21 +4,22 @@
|
||||
module std::core::builtin;
|
||||
import libc, std::hash, std::io, std::os::backtrace;
|
||||
|
||||
<*
|
||||
/*
|
||||
Use `IteratorResult` when reading the end of an iterator, or accessing a result out of bounds.
|
||||
*>
|
||||
*/
|
||||
fault IteratorResult { NO_MORE_ELEMENT }
|
||||
|
||||
<*
|
||||
/*
|
||||
Use `SearchResult` when trying to return a value from some collection but the element is missing.
|
||||
*>
|
||||
*/
|
||||
fault SearchResult { MISSING }
|
||||
|
||||
<*
|
||||
/*
|
||||
Use `CastResult` when an attempt at conversion fails.
|
||||
*>
|
||||
*/
|
||||
fault CastResult { TYPE_MISMATCH }
|
||||
|
||||
|
||||
def VoidFn = fn void();
|
||||
|
||||
<*
|
||||
@@ -229,7 +230,25 @@ macro enum_by_name($Type, String enum_name) @builtin
|
||||
typeid x = $Type.typeid;
|
||||
foreach (i, name : x.names)
|
||||
{
|
||||
if (name == enum_name) return ($Type)i;
|
||||
if (name == enum_name) return $Type.from_ordinal(i);
|
||||
}
|
||||
return SearchResult.MISSING?;
|
||||
}
|
||||
|
||||
<*
|
||||
@param $Type `The type of the enum`
|
||||
@require $Type.kindof == ENUM `Only enums may be used`
|
||||
@require $defined($Type.#value1) `Expected '#value' to match an enum associated value`
|
||||
@require $assignable(value, $typeof($Type{}.#value)) `Expected the value to match the type of the associated value`
|
||||
@ensure @typeis(return, $Type)
|
||||
@return! SearchResult.MISSING
|
||||
*>
|
||||
macro @enum_from_value($Type, #value, value) @builtin
|
||||
{
|
||||
usz elements = $Type.elements;
|
||||
foreach (e : $Type.values)
|
||||
{
|
||||
if (e.#value == value) return e;
|
||||
}
|
||||
return SearchResult.MISSING?;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
module std::core::dstring;
|
||||
import std::io;
|
||||
|
||||
distinct DString (OutStream) = void*;
|
||||
distinct DString (OutStream) = DStringOpaque*;
|
||||
distinct DStringOpaque = void;
|
||||
|
||||
const usz MIN_CAPACITY @private = 16;
|
||||
|
||||
@@ -132,7 +133,7 @@ fn usz DString.capacity(self)
|
||||
return self.data().capacity;
|
||||
}
|
||||
|
||||
fn usz DString.len(&self) @dynamic
|
||||
fn usz DString.len(&self) @dynamic @operator(len)
|
||||
{
|
||||
if (!*self) return 0;
|
||||
return self.data().len;
|
||||
@@ -154,6 +155,24 @@ fn String DString.str_view(self)
|
||||
return (String)data.chars[:data.len];
|
||||
}
|
||||
|
||||
<*
|
||||
@require index < self.len()
|
||||
@require self.data() "Empty string"
|
||||
*>
|
||||
fn char DString.char_at(self, usz index) @operator([])
|
||||
{
|
||||
return self.data().chars[index];
|
||||
}
|
||||
|
||||
<*
|
||||
@require index < self.len()
|
||||
@require self.data() "Empty string"
|
||||
*>
|
||||
fn char* DString.char_ref(&self, usz index) @operator(&[])
|
||||
{
|
||||
return &self.data().chars[index];
|
||||
}
|
||||
|
||||
fn usz DString.append_utf32(&self, Char32[] chars)
|
||||
{
|
||||
self.reserve(chars.len);
|
||||
@@ -168,7 +187,7 @@ fn usz DString.append_utf32(&self, Char32[] chars)
|
||||
<*
|
||||
@require index < self.len()
|
||||
*>
|
||||
fn void DString.set(self, usz index, char c)
|
||||
fn void DString.set(self, usz index, char c) @operator([]=)
|
||||
{
|
||||
self.data().chars[index] = c;
|
||||
}
|
||||
|
||||
@@ -117,13 +117,13 @@ enum ArchType
|
||||
|
||||
const String COMPILER_BUILD_HASH = $$BUILD_HASH;
|
||||
const String COMPILER_BUILD_DATE = $$BUILD_DATE;
|
||||
const OsType OS_TYPE = (OsType)$$OS_TYPE;
|
||||
const ArchType ARCH_TYPE = (ArchType)$$ARCH_TYPE;
|
||||
const OsType OS_TYPE = OsType.from_ordinal($$OS_TYPE);
|
||||
const ArchType ARCH_TYPE = ArchType.from_ordinal($$ARCH_TYPE);
|
||||
const bool ARCH_32_BIT = $$REGISTER_SIZE == 32;
|
||||
const bool ARCH_64_BIT = $$REGISTER_SIZE == 64;
|
||||
const bool LIBC = $$COMPILER_LIBC_AVAILABLE;
|
||||
const bool NO_LIBC = !$$COMPILER_LIBC_AVAILABLE;
|
||||
const CompilerOptLevel COMPILER_OPT_LEVEL = (CompilerOptLevel)$$COMPILER_OPT_LEVEL;
|
||||
const CompilerOptLevel COMPILER_OPT_LEVEL = CompilerOptLevel.from_ordinal($$COMPILER_OPT_LEVEL);
|
||||
const bool BIG_ENDIAN = $$PLATFORM_BIG_ENDIAN;
|
||||
const bool I128_NATIVE_SUPPORT = $$PLATFORM_I128_SUPPORTED;
|
||||
const bool F16_SUPPORT = $$PLATFORM_F16_SUPPORTED;
|
||||
@@ -135,7 +135,7 @@ const bool BACKTRACE = $$BACKTRACE;
|
||||
const usz LLVM_VERSION = $$LLVM_VERSION;
|
||||
const bool BENCHMARKING = $$BENCHMARKING;
|
||||
const bool TESTING = $$TESTING;
|
||||
const MemoryEnvironment MEMORY_ENV = (MemoryEnvironment)$$MEMORY_ENVIRONMENT;
|
||||
const MemoryEnvironment MEMORY_ENV = MemoryEnvironment.from_ordinal($$MEMORY_ENVIRONMENT);
|
||||
const bool TRACK_MEMORY = DEBUG_SYMBOLS && (COMPILER_SAFE_MODE || TESTING);
|
||||
const bool X86_64 = ARCH_TYPE == X86_64;
|
||||
const bool X86 = ARCH_TYPE == X86;
|
||||
|
||||
@@ -224,7 +224,7 @@ enum AtomicOrdering : int
|
||||
*>
|
||||
macro @atomic_load(&x, AtomicOrdering $ordering = SEQ_CONSISTENT, $volatile = false) @builtin
|
||||
{
|
||||
return $$atomic_load(x, $volatile, (int)$ordering);
|
||||
return $$atomic_load(x, $volatile, $ordering.ordinal);
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -239,7 +239,7 @@ macro @atomic_load(&x, AtomicOrdering $ordering = SEQ_CONSISTENT, $volatile = fa
|
||||
*>
|
||||
macro void @atomic_store(&x, value, AtomicOrdering $ordering = SEQ_CONSISTENT, $volatile = false) @builtin
|
||||
{
|
||||
$$atomic_store(x, value, $volatile, (int)$ordering);
|
||||
$$atomic_store(x, value, $volatile, $ordering.ordinal);
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -455,19 +455,23 @@ macro void @scoped(Allocator allocator; @body())
|
||||
<*
|
||||
Run the tracking allocator in the scope, then
|
||||
print out stats.
|
||||
|
||||
@param $enabled "Set to false to disable tracking"
|
||||
*>
|
||||
macro void @report_heap_allocs_in_scope(;@body())
|
||||
macro void @report_heap_allocs_in_scope($enabled = true; @body())
|
||||
{
|
||||
TrackingAllocator tracker;
|
||||
tracker.init(allocator::thread_allocator);
|
||||
Allocator old_allocator = allocator::thread_allocator;
|
||||
allocator::thread_allocator = &tracker;
|
||||
defer
|
||||
{
|
||||
allocator::thread_allocator = old_allocator;
|
||||
tracker.print_report();
|
||||
tracker.free();
|
||||
}
|
||||
$if $enabled:
|
||||
TrackingAllocator tracker;
|
||||
tracker.init(allocator::thread_allocator);
|
||||
Allocator old_allocator = allocator::thread_allocator;
|
||||
allocator::thread_allocator = &tracker;
|
||||
defer
|
||||
{
|
||||
allocator::thread_allocator = old_allocator;
|
||||
tracker.print_report();
|
||||
tracker.free();
|
||||
}
|
||||
$endif
|
||||
@body();
|
||||
}
|
||||
|
||||
@@ -774,3 +778,41 @@ fn void* trealloc(void* ptr, usz size, usz alignment = mem::DEFAULT_MEM_ALIGNMEN
|
||||
return allocator::temp().resize(ptr, size, alignment)!!;
|
||||
}
|
||||
|
||||
module std::core::mem @if(env::NO_LIBC);
|
||||
|
||||
fn CInt __memcmp(void* s1, void* s2, usz n) @weak @export("memcmp")
|
||||
{
|
||||
char* p1 = s1;
|
||||
char* p2 = s2;
|
||||
for (usz i = 0; i < n; i++, p1++, p2++)
|
||||
{
|
||||
char c1 = *p1;
|
||||
char c2 = *p2;
|
||||
if (c1 < c2) return -1;
|
||||
if (c1 > c2) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn void* __memset(void* str, CInt c, usz n) @weak @export("memset")
|
||||
{
|
||||
char* p = str;
|
||||
char cc = (char)c;
|
||||
for (usz i = 0; i < n; i++, p++)
|
||||
{
|
||||
*p = cc;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
fn void* __memcpy(void* dst, void* src, usz n) @weak @export("memcpy")
|
||||
{
|
||||
char* d = dst;
|
||||
char* s = src;
|
||||
for (usz i = 0; i < n; i++, d++, s++)
|
||||
{
|
||||
*d = *s;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,20 +21,20 @@ interface Allocator
|
||||
fn void reset(usz mark) @optional;
|
||||
fn usz mark() @optional;
|
||||
<*
|
||||
* @require !alignment || math::is_power_of_2(alignment)
|
||||
* @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big`
|
||||
* @require size > 0
|
||||
@require !alignment || math::is_power_of_2(alignment)
|
||||
@require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big`
|
||||
@require size > 0
|
||||
*>
|
||||
fn void*! acquire(usz size, AllocInitType init_type, usz alignment = 0);
|
||||
<*
|
||||
* @require !alignment || math::is_power_of_2(alignment)
|
||||
* @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big`
|
||||
* @require ptr != null
|
||||
* @require new_size > 0
|
||||
@require !alignment || math::is_power_of_2(alignment)
|
||||
@require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big`
|
||||
@require ptr != null
|
||||
@require new_size > 0
|
||||
*>
|
||||
fn void*! resize(void* ptr, usz new_size, usz alignment = 0);
|
||||
<*
|
||||
* @require ptr != null
|
||||
@require ptr != null
|
||||
*>
|
||||
fn void release(void* ptr, bool aligned);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,11 @@ enum X86Feature
|
||||
{
|
||||
ADX,
|
||||
AES,
|
||||
AMX_AVX512,
|
||||
AMX_FP8,
|
||||
AMX_MOVRS,
|
||||
AMX_TF32,
|
||||
AMX_TRANSPOSE,
|
||||
AMX_BF16,
|
||||
AMX_COMPLEX,
|
||||
AMX_FP16,
|
||||
@@ -34,6 +39,8 @@ enum X86Feature
|
||||
AVX,
|
||||
AVX10_1_256,
|
||||
AVX10_1_512,
|
||||
AVX10_2_256,
|
||||
AVX10_2_512,
|
||||
AVX2,
|
||||
AVX5124FMAPS,
|
||||
AVX5124VNNIW,
|
||||
@@ -84,6 +91,7 @@ enum X86Feature
|
||||
MOVBE,
|
||||
MOVDIR64B,
|
||||
MOVDIRI,
|
||||
MOVRS,
|
||||
MWAITX,
|
||||
PCLMUL,
|
||||
PCONFIG,
|
||||
|
||||
@@ -84,7 +84,7 @@ macro bool address_is_poisoned(void* addr)
|
||||
macro void* region_is_poisoned(void* beg, usz size)
|
||||
{
|
||||
$if env::ADDRESS_SANITIZER:
|
||||
return __asan_region_is_poisoned(addr);
|
||||
return __asan_region_is_poisoned(beg, size);
|
||||
$else
|
||||
return null;
|
||||
$endif
|
||||
|
||||
@@ -219,12 +219,14 @@ fn String String.strip_end(string, String needle)
|
||||
|
||||
@param [in] s
|
||||
@param [in] needle
|
||||
@param [&inout] allocator "The allocator to use for the String[]"
|
||||
@param max "Max number of elements, 0 means no limit, defaults to 0"
|
||||
@param skip_empty "True to skip empty elements"
|
||||
@param [&inout] allocator "The allocator to use for the String[]"
|
||||
|
||||
@require needle.len > 0 "The needle must be at least 1 character long"
|
||||
@ensure return.len > 0
|
||||
*>
|
||||
fn String[] String.split(s, String needle, usz max = 0, Allocator allocator = allocator::heap())
|
||||
fn String[] String.split(s, String needle, usz max = 0, Allocator allocator = allocator::heap(), bool skip_empty = false)
|
||||
{
|
||||
usz capacity = 16;
|
||||
usz i = 0;
|
||||
@@ -244,6 +246,11 @@ fn String[] String.split(s, String needle, usz max = 0, Allocator allocator = al
|
||||
res = s;
|
||||
no_more = true;
|
||||
}
|
||||
if (!res.len && skip_empty)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i == capacity)
|
||||
{
|
||||
capacity *= 2;
|
||||
@@ -261,10 +268,11 @@ fn String[] String.split(s, String needle, usz max = 0, Allocator allocator = al
|
||||
@param [in] s
|
||||
@param [in] needle
|
||||
@param max "Max number of elements, 0 means no limit, defaults to 0"
|
||||
@param skip_empty "True to skip empty elements"
|
||||
@require needle.len > 0 "The needle must be at least 1 character long"
|
||||
@ensure return.len > 0
|
||||
*>
|
||||
fn String[] String.new_split(s, String needle, usz max = 0) => s.split(needle, max, allocator::heap()) @inline;
|
||||
fn String[] String.new_split(s, String needle, usz max = 0, bool skip_empty) => s.split(needle, max, allocator::heap(), skip_empty) @inline;
|
||||
|
||||
<*
|
||||
This function is identical to String.split, but implicitly uses the
|
||||
@@ -273,8 +281,54 @@ fn String[] String.new_split(s, String needle, usz max = 0) => s.split(needle, m
|
||||
@param [in] s
|
||||
@param [in] needle
|
||||
@param max "Max number of elements, 0 means no limit, defaults to 0"
|
||||
@param skip_empty "True to skip empty elements"
|
||||
*>
|
||||
fn String[] String.tsplit(s, String needle, usz max = 0) => s.split(needle, max, allocator::temp()) @inline;
|
||||
fn String[] String.tsplit(s, String needle, usz max = 0, bool skip_empty = false) => s.split(needle, max, allocator::temp(), skip_empty) @inline;
|
||||
|
||||
fault SplitResult { BUFFER_EXCEEDED }
|
||||
|
||||
<*
|
||||
Split a string into parts, e.g "a|b|c" split with "|" yields { "a", "b", "c" }
|
||||
|
||||
@param [in] s
|
||||
@param [in] needle
|
||||
@param [inout] buffer
|
||||
@param max "Max number of elements, 0 means no limit, defaults to 0"
|
||||
@require needle.len > 0 "The needle must be at least 1 character long"
|
||||
@ensure return.len > 0
|
||||
@return! SplitResult.BUFFER_EXCEEDED `If there are more elements than would fit the buffer`
|
||||
*>
|
||||
fn String[]! String.split_to_buffer(s, String needle, String[] buffer, usz max = 0, bool skip_empty = false)
|
||||
{
|
||||
usz max_capacity = buffer.len;
|
||||
usz i = 0;
|
||||
bool no_more = false;
|
||||
while (!no_more)
|
||||
{
|
||||
usz! index = i == max - 1 ? SearchResult.MISSING? : s.index_of(needle);
|
||||
String res @noinit;
|
||||
if (try index)
|
||||
{
|
||||
res = s[:index];
|
||||
s = s[index + needle.len..];
|
||||
}
|
||||
else
|
||||
{
|
||||
res = s;
|
||||
no_more = true;
|
||||
}
|
||||
if (!res.len && skip_empty)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (i == max_capacity)
|
||||
{
|
||||
return SplitResult.BUFFER_EXCEEDED?;
|
||||
}
|
||||
buffer[i++] = res;
|
||||
}
|
||||
return buffer[:i];
|
||||
}
|
||||
|
||||
<*
|
||||
Check if a substring is found in the string.
|
||||
@@ -719,7 +773,12 @@ fn float! String.to_float(s) => s.to_real(float);
|
||||
|
||||
fn Splitter String.splitter(self, String split)
|
||||
{
|
||||
return Splitter { self, split, 0 };
|
||||
return { .string = self, .split = split };
|
||||
}
|
||||
|
||||
fn Splitter String.tokenize(self, String split)
|
||||
{
|
||||
return { .string = self, .split = split, .tokenize = true };
|
||||
}
|
||||
|
||||
struct Splitter
|
||||
@@ -727,6 +786,8 @@ struct Splitter
|
||||
String string;
|
||||
String split;
|
||||
usz current;
|
||||
bool tokenize;
|
||||
int last_index;
|
||||
}
|
||||
|
||||
fn void Splitter.reset(&self)
|
||||
@@ -736,18 +797,22 @@ fn void Splitter.reset(&self)
|
||||
|
||||
fn String! Splitter.next(&self)
|
||||
{
|
||||
usz len = self.string.len;
|
||||
usz current = self.current;
|
||||
if (current >= len) return IteratorResult.NO_MORE_ELEMENT?;
|
||||
String remaining = self.string[current..];
|
||||
usz! next = remaining.index_of(self.split);
|
||||
if (try next)
|
||||
while (true)
|
||||
{
|
||||
defer self.current = current + next + self.split.len;
|
||||
return remaining[:next];
|
||||
usz len = self.string.len;
|
||||
usz current = self.current;
|
||||
if (current >= len) return IteratorResult.NO_MORE_ELEMENT?;
|
||||
String remaining = self.string[current..];
|
||||
usz! next = remaining.index_of(self.split);
|
||||
if (try next)
|
||||
{
|
||||
self.current = current + next + self.split.len;
|
||||
if (!next && self.tokenize) continue;
|
||||
return remaining[:next];
|
||||
}
|
||||
self.current = len;
|
||||
return remaining;
|
||||
}
|
||||
self.current = len;
|
||||
return remaining;
|
||||
}
|
||||
|
||||
macro String new_struct_to_str(x, Allocator allocator = allocator::heap())
|
||||
@@ -757,8 +822,8 @@ macro String new_struct_to_str(x, Allocator allocator = allocator::heap())
|
||||
{
|
||||
s.new_init(allocator: mem);
|
||||
io::fprint(&s, x)!!;
|
||||
return s.copy_str(allocator);
|
||||
};
|
||||
return s.copy_str(allocator);
|
||||
}
|
||||
|
||||
macro String temp_struct_to_str(x) => new_struct_to_str(x, allocator::temp());
|
||||
macro String temp_struct_to_str(x) => new_struct_to_str(x, allocator::temp());
|
||||
|
||||
@@ -3,232 +3,117 @@ module std::encoding::base32;
|
||||
// This module implements base32 encoding according to RFC 4648
|
||||
// (https://www.rfc-editor.org/rfc/rfc4648)
|
||||
|
||||
distinct Alphabet = inline char[32];
|
||||
|
||||
// Standard base32 Alphabet
|
||||
const Alphabet STD_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
||||
|
||||
// Extended Hex Alphabet
|
||||
const Alphabet HEX_ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
|
||||
|
||||
const uint MASK @private = 0b11111;
|
||||
const char INVALID @private = 0xff;
|
||||
|
||||
const int STD_PADDING = '=';
|
||||
const int NO_PADDING = -1;
|
||||
|
||||
fault Base32Error
|
||||
struct Base32Alphabet
|
||||
{
|
||||
DUPLICATE_IN_ALPHABET,
|
||||
PADDING_IN_ALPHABET,
|
||||
INVALID_CHARACTER_IN_ALPHABET,
|
||||
DESTINATION_TOO_SMALL,
|
||||
INVALID_PADDING,
|
||||
CORRUPT_INPUT
|
||||
char[32] encoding;
|
||||
char[256] reverse;
|
||||
}
|
||||
|
||||
struct Base32Encoder
|
||||
const char NO_PAD = 0;
|
||||
const char DEFAULT_PAD = '=';
|
||||
|
||||
<*
|
||||
Encode the content of src into a newly allocated string
|
||||
@param [in] src "The input to be encoded."
|
||||
@param padding "The padding character or 0 if none"
|
||||
@param alphabet "The alphabet to use"
|
||||
@require padding < 0xFF "Invalid padding character"
|
||||
@return "The encoded string."
|
||||
*>
|
||||
fn String! encode(char[] src, Allocator allocator, char padding = DEFAULT_PAD, Base32Alphabet* alphabet = &STANDARD)
|
||||
{
|
||||
Alphabet alphabet;
|
||||
int padding;
|
||||
char[] dst = allocator::alloc_array(allocator, char, encode_len(src.len, padding));
|
||||
return encode_buffer(src, dst, padding, alphabet);
|
||||
}
|
||||
|
||||
<*
|
||||
@param encoder "The 32-character alphabet for encoding."
|
||||
@param padding "Set to a negative value to disable padding."
|
||||
@require padding < 256
|
||||
Decode the content of src into a newly allocated char array.
|
||||
@param [in] src "The input to be encoded."
|
||||
@param padding "The padding character or 0 if none"
|
||||
@param alphabet "The alphabet to use"
|
||||
@require padding < 0xFF "Invalid padding character"
|
||||
@return "The decoded data."
|
||||
*>
|
||||
fn void! Base32Encoder.init(&self, Alphabet encoder = STD_ALPHABET, int padding = STD_PADDING)
|
||||
fn char[]! decode(char[] src, Allocator allocator, char padding = DEFAULT_PAD, Base32Alphabet* alphabet = &STANDARD)
|
||||
{
|
||||
encoder.validate(padding)!;
|
||||
*self = { .alphabet = encoder, .padding = padding };
|
||||
char[] dst = allocator::alloc_array(allocator, char, decode_len(src.len, padding));
|
||||
return decode_buffer(src, dst, padding, alphabet);
|
||||
}
|
||||
|
||||
fn String! encode_new(char[] code, char padding = DEFAULT_PAD, Base32Alphabet* alphabet = &STANDARD) @inline => encode(code, allocator::heap(), padding, alphabet);
|
||||
fn String! encode_temp(char[] code, char padding = DEFAULT_PAD, Base32Alphabet* alphabet = &STANDARD) @inline => encode(code, allocator::temp(), padding, alphabet);
|
||||
fn char[]! decode_new(char[] code, char padding = DEFAULT_PAD, Base32Alphabet* alphabet = &STANDARD) @inline => decode(code, allocator::heap(), padding, alphabet);
|
||||
fn char[]! decode_temp(char[] code, char padding = DEFAULT_PAD, Base32Alphabet* alphabet = &STANDARD) @inline => decode(code, allocator::temp(), padding, alphabet);
|
||||
|
||||
<*
|
||||
Calculate the length in bytes of the decoded data.
|
||||
@param n "Length in bytes of input."
|
||||
@param padding "The padding character or 0 if none"
|
||||
@require padding < 0xFF "Invalid padding character"
|
||||
@return "Length in bytes of the decoded data."
|
||||
*>
|
||||
fn usz decode_len(usz n, char padding)
|
||||
{
|
||||
if (padding) return (n / 8) * 5;
|
||||
// no padding
|
||||
usz trailing = n % 8;
|
||||
return n / 8 * 5 + (trailing * 5 ) / 8;
|
||||
}
|
||||
|
||||
<*
|
||||
Calculate the length in bytes of the encoded data.
|
||||
@param n "Length in bytes on input."
|
||||
@param padding "The padding character or 0 if none"
|
||||
@require padding < 0xFF "Invalid padding character"
|
||||
@return "Length in bytes of the encoded data."
|
||||
*>
|
||||
fn usz Base32Encoder.encode_len(&self, usz n)
|
||||
fn usz encode_len(usz n, char padding)
|
||||
{
|
||||
// A character is encoded into 8 x 5-bit blocks.
|
||||
if (self.padding >= 0)
|
||||
{
|
||||
// with padding
|
||||
return (n + 4) / 5 * 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
// no padding
|
||||
usz trailing = n % 5;
|
||||
return n / 5 * 8 + (trailing * 8 + 4) / 5;
|
||||
}
|
||||
}
|
||||
if (padding) return (n + 4) / 5 * 8;
|
||||
|
||||
<*
|
||||
Encode the content of src into dst, which must be properly sized.
|
||||
@param [in] src "The input to be encoded."
|
||||
@param [inout] dst "The encoded input."
|
||||
@return "The encoded size."
|
||||
@return! Base32Error.DESTINATION_TOO_SMALL
|
||||
*>
|
||||
fn usz! Base32Encoder.encode(&self, char[] src, char[] dst)
|
||||
{
|
||||
if (src.len == 0) return 0;
|
||||
|
||||
usz n = (src.len / 5) * 5;
|
||||
usz dn = self.encode_len(src.len);
|
||||
if (dst.len < dn) return Base32Error.DESTINATION_TOO_SMALL?;
|
||||
|
||||
uint msb, lsb;
|
||||
for (usz i = 0; i < n; i += 5)
|
||||
{
|
||||
// to fit 40 bits we need two 32-bit uints
|
||||
msb = (uint)src[i] << 24 | (uint)src[i+1] << 16
|
||||
| (uint)src[i+2] << 8 | (uint)src[i+3];
|
||||
lsb = msb << 8 | (uint)src[i+4];
|
||||
|
||||
// now slice them into 5-bit chunks and translate to the
|
||||
// alphabet.
|
||||
dst[0] = self.alphabet[(msb >> 27) & MASK];
|
||||
dst[1] = self.alphabet[(msb >> 22) & MASK];
|
||||
dst[2] = self.alphabet[(msb >> 17) & MASK];
|
||||
dst[3] = self.alphabet[(msb >> 12) & MASK];
|
||||
dst[4] = self.alphabet[(msb >> 7) & MASK];
|
||||
dst[5] = self.alphabet[(msb >> 2) & MASK];
|
||||
dst[6] = self.alphabet[(lsb >> 5) & MASK];
|
||||
dst[7] = self.alphabet[lsb & MASK];
|
||||
|
||||
dst = dst[8..];
|
||||
}
|
||||
|
||||
usz trailing = src.len - n;
|
||||
if (trailing == 0) return dn;
|
||||
|
||||
msb = 0;
|
||||
switch (trailing)
|
||||
{
|
||||
case 4:
|
||||
msb |= (uint)src[n+3];
|
||||
lsb = msb << 8;
|
||||
dst[6] = self.alphabet[(lsb >> 5) & MASK];
|
||||
dst[5] = self.alphabet[(msb >> 2) & MASK];
|
||||
nextcase 3;
|
||||
case 3:
|
||||
msb |= (uint)src[n+2] << 8;
|
||||
dst[4] = self.alphabet[(msb >> 7) & MASK];
|
||||
nextcase 2;
|
||||
case 2:
|
||||
msb |= (uint)src[n+1] << 16;
|
||||
dst[3] = self.alphabet[(msb >> 12) & MASK];
|
||||
dst[2] = self.alphabet[(msb >> 17) & MASK];
|
||||
nextcase 1;
|
||||
case 1:
|
||||
msb |= (uint)src[n] << 24;
|
||||
dst[1] = self.alphabet[(msb >> 22) & MASK];
|
||||
dst[0] = self.alphabet[(msb >> 27) & MASK];
|
||||
}
|
||||
|
||||
// add the padding
|
||||
if (self.padding >= 0)
|
||||
{
|
||||
char pad = (char)self.padding;
|
||||
for (usz i = (trailing * 8 / 5) + 1; i < 8; i++)
|
||||
{
|
||||
dst[i] = pad;
|
||||
}
|
||||
}
|
||||
|
||||
return dn;
|
||||
}
|
||||
|
||||
struct Base32Decoder
|
||||
{
|
||||
Alphabet alphabet;
|
||||
int padding;
|
||||
char[256] reverse;
|
||||
}
|
||||
|
||||
<*
|
||||
@param decoder "The alphabet used for decoding."
|
||||
@param padding "Set to a negative value to disable padding."
|
||||
@require padding < 256
|
||||
*>
|
||||
fn void! Base32Decoder.init(&self, Alphabet decoder = STD_ALPHABET, int padding = STD_PADDING)
|
||||
{
|
||||
decoder.validate(padding)!;
|
||||
*self = { .alphabet = decoder, .padding = padding };
|
||||
|
||||
self.reverse[..] = INVALID;
|
||||
foreach (char i, c : decoder)
|
||||
{
|
||||
self.reverse[c] = i;
|
||||
}
|
||||
}
|
||||
|
||||
<*
|
||||
Calculate the length in bytes of the decoded data.
|
||||
@param n "Length in bytes of input."
|
||||
@return "Length in bytes of the decoded data."
|
||||
*>
|
||||
fn usz Base32Decoder.decode_len(&self, usz n)
|
||||
{
|
||||
if (self.padding >= 0)
|
||||
{
|
||||
// with padding
|
||||
return (n / 8) * 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
// no padding
|
||||
usz trailing = n % 8;
|
||||
return n / 8 * 5 + (trailing * 5 ) / 8;
|
||||
}
|
||||
// no padding
|
||||
usz trailing = n % 5;
|
||||
return n / 5 * 8 + (trailing * 8 + 4) / 5;
|
||||
}
|
||||
|
||||
<*
|
||||
Decode the content of src into dst, which must be properly sized.
|
||||
@param src "The input to be decoded."
|
||||
@param dst "The decoded input."
|
||||
@return "The decoded size."
|
||||
@return! Base32Error.DESTINATION_TOO_SMALL, Base32Error.CORRUPT_INPUT
|
||||
@param padding "The padding character or 0 if none"
|
||||
@param alphabet "The alphabet to use"
|
||||
@require padding < 0xFF "Invalid padding character"
|
||||
@require dst.len >= decode_len(src.len, padding) "Destination buffer too small"
|
||||
@return "The resulting dst buffer"
|
||||
@return! DecodingFailure
|
||||
*>
|
||||
fn usz! Base32Decoder.decode(&self, char[] src, char[] dst)
|
||||
fn char[]! decode_buffer(char[] src, char[] dst, char padding = DEFAULT_PAD, Base32Alphabet* alphabet = &STANDARD)
|
||||
{
|
||||
if (src.len == 0) return 0;
|
||||
usz dn = self.decode_len(src.len);
|
||||
if (dst.len < dn) return Base32Error.DESTINATION_TOO_SMALL?;
|
||||
|
||||
usz j, n;
|
||||
if (src.len == 0) return dst[:0];
|
||||
char* dst_ptr = dst;
|
||||
usz dn = decode_len(src.len, padding);
|
||||
usz n;
|
||||
char[8] buf;
|
||||
while (src.len > 0 && dst.len > 0)
|
||||
{
|
||||
|
||||
usz i @noinit;
|
||||
// load 8 bytes into buffer
|
||||
for (j = 0; j < 8; j++)
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
if (src.len == 0)
|
||||
{
|
||||
if (self.padding >= 0)
|
||||
{
|
||||
return Base32Error.CORRUPT_INPUT?;
|
||||
}
|
||||
if (padding > 0) return DecodingFailure.INVALID_PADDING?;
|
||||
break;
|
||||
}
|
||||
if (src[0] == (char)self.padding)
|
||||
{
|
||||
break;
|
||||
}
|
||||
buf[j] = self.reverse[src[0]];
|
||||
if (buf[j] == INVALID)
|
||||
{
|
||||
return Base32Error.CORRUPT_INPUT?;
|
||||
}
|
||||
if (src[0] == padding) break;
|
||||
buf[i] = alphabet.reverse[src[0]];
|
||||
if (buf[i] == INVALID) return DecodingFailure.INVALID_CHARACTER?;
|
||||
src = src[1..];
|
||||
}
|
||||
|
||||
// extract 5-bytes from the buffer which contains 8 x 5 bit chunks
|
||||
switch (j)
|
||||
switch (i)
|
||||
{
|
||||
case 8:
|
||||
// |66677777| dst[4]
|
||||
@@ -267,14 +152,195 @@ fn usz! Base32Decoder.decode(&self, char[] src, char[] dst)
|
||||
dst[0] = buf[1] >> 2 | buf[0] << 3;
|
||||
n++;
|
||||
default:
|
||||
return Base32Error.CORRUPT_INPUT?;
|
||||
return DecodingFailure.INVALID_CHARACTER?;
|
||||
}
|
||||
|
||||
if (dst.len < 5) break;
|
||||
dst = dst[5..];
|
||||
}
|
||||
return dst_ptr[:n];
|
||||
}
|
||||
|
||||
return n;
|
||||
<*
|
||||
Encode the content of src into dst, which must be properly sized.
|
||||
@param [in] src "The input to be encoded."
|
||||
@param [inout] dst "The encoded input."
|
||||
@param padding "The padding character or 0 if none"
|
||||
@param alphabet "The alphabet to use"
|
||||
@require padding < 0xFF "Invalid padding character"
|
||||
@require dst.len >= encode_len(src.len, padding) "Destination buffer too small"
|
||||
@return "The encoded size."
|
||||
*>
|
||||
fn String encode_buffer(char[] src, char[] dst, char padding = DEFAULT_PAD, Base32Alphabet* alphabet = &STANDARD)
|
||||
{
|
||||
if (src.len == 0) return (String)dst[:0];
|
||||
|
||||
char* dst_ptr = dst;
|
||||
usz n = (src.len / 5) * 5;
|
||||
usz dn = encode_len(src.len, padding);
|
||||
|
||||
uint msb, lsb;
|
||||
for (usz i = 0; i < n; i += 5)
|
||||
{
|
||||
// to fit 40 bits we need two 32-bit uints
|
||||
msb = (uint)src[i] << 24 | (uint)src[i+1] << 16
|
||||
| (uint)src[i+2] << 8 | (uint)src[i+3];
|
||||
lsb = msb << 8 | (uint)src[i+4];
|
||||
|
||||
// now slice them into 5-bit chunks and translate to the
|
||||
// alphabet.
|
||||
dst[0] = alphabet.encoding[(msb >> 27) & MASK];
|
||||
dst[1] = alphabet.encoding[(msb >> 22) & MASK];
|
||||
dst[2] = alphabet.encoding[(msb >> 17) & MASK];
|
||||
dst[3] = alphabet.encoding[(msb >> 12) & MASK];
|
||||
dst[4] = alphabet.encoding[(msb >> 7) & MASK];
|
||||
dst[5] = alphabet.encoding[(msb >> 2) & MASK];
|
||||
dst[6] = alphabet.encoding[(lsb >> 5) & MASK];
|
||||
dst[7] = alphabet.encoding[lsb & MASK];
|
||||
|
||||
dst = dst[8..];
|
||||
}
|
||||
|
||||
usz trailing = src.len - n;
|
||||
if (trailing == 0) return (String)dst_ptr[:dn];
|
||||
|
||||
msb = 0;
|
||||
switch (trailing)
|
||||
{
|
||||
case 4:
|
||||
msb |= (uint)src[n+3];
|
||||
lsb = msb << 8;
|
||||
dst[6] = alphabet.encoding[(lsb >> 5) & MASK];
|
||||
dst[5] = alphabet.encoding[(msb >> 2) & MASK];
|
||||
nextcase 3;
|
||||
case 3:
|
||||
msb |= (uint)src[n+2] << 8;
|
||||
dst[4] = alphabet.encoding[(msb >> 7) & MASK];
|
||||
nextcase 2;
|
||||
case 2:
|
||||
msb |= (uint)src[n+1] << 16;
|
||||
dst[3] = alphabet.encoding[(msb >> 12) & MASK];
|
||||
dst[2] = alphabet.encoding[(msb >> 17) & MASK];
|
||||
nextcase 1;
|
||||
case 1:
|
||||
msb |= (uint)src[n] << 24;
|
||||
dst[1] = alphabet.encoding[(msb >> 22) & MASK];
|
||||
dst[0] = alphabet.encoding[(msb >> 27) & MASK];
|
||||
}
|
||||
|
||||
// add the padding
|
||||
if (padding > 0)
|
||||
{
|
||||
for (usz i = (trailing * 8 / 5) + 1; i < 8; i++)
|
||||
{
|
||||
dst[i] = padding;
|
||||
}
|
||||
}
|
||||
return (String)dst_ptr[:dn];
|
||||
}
|
||||
|
||||
const uint MASK @private = 0b11111;
|
||||
const char INVALID @private = 0xff;
|
||||
|
||||
const int STD_PADDING = '=';
|
||||
const int NO_PADDING = -1;
|
||||
|
||||
fault Base32Error
|
||||
{
|
||||
DUPLICATE_IN_ALPHABET,
|
||||
PADDING_IN_ALPHABET,
|
||||
INVALID_CHARACTER_IN_ALPHABET,
|
||||
DESTINATION_TOO_SMALL,
|
||||
INVALID_PADDING,
|
||||
CORRUPT_INPUT
|
||||
}
|
||||
|
||||
struct Base32Encoder @deprecated
|
||||
{
|
||||
Base32Alphabet alphabet;
|
||||
char padding;
|
||||
}
|
||||
|
||||
<*
|
||||
@param encoder "The 32-character alphabet for encoding."
|
||||
@param padding "Set to a negative value to disable padding."
|
||||
@require padding < 256
|
||||
*>
|
||||
fn void! Base32Encoder.init(&self, Alphabet encoder = STD_ALPHABET, int padding = STD_PADDING)
|
||||
{
|
||||
encoder.validate(padding)!;
|
||||
*self = { .alphabet = { .encoding = (char[32])encoder }, .padding = padding < 0 ? (char)0 : (char)padding};
|
||||
}
|
||||
|
||||
<*
|
||||
Calculate the length in bytes of the encoded data.
|
||||
@param n "Length in bytes on input."
|
||||
@return "Length in bytes of the encoded data."
|
||||
*>
|
||||
fn usz Base32Encoder.encode_len(&self, usz n)
|
||||
{
|
||||
return encode_len(n, self.padding);
|
||||
}
|
||||
|
||||
<*
|
||||
Encode the content of src into dst, which must be properly sized.
|
||||
@param [in] src "The input to be encoded."
|
||||
@param [inout] dst "The encoded input."
|
||||
@return "The encoded size."
|
||||
@return! Base32Error.DESTINATION_TOO_SMALL
|
||||
*>
|
||||
fn usz! Base32Encoder.encode(&self, char[] src, char[] dst)
|
||||
{
|
||||
usz dn = self.encode_len(src.len);
|
||||
if (dst.len < dn) return Base32Error.DESTINATION_TOO_SMALL?;
|
||||
return encode_buffer(src, dst, self.padding, &self.alphabet).len;
|
||||
}
|
||||
|
||||
struct Base32Decoder @deprecated
|
||||
{
|
||||
Base32Alphabet alphabet;
|
||||
char padding;
|
||||
}
|
||||
|
||||
<*
|
||||
@param decoder "The alphabet used for decoding."
|
||||
@param padding "Set to a negative value to disable padding."
|
||||
@require padding < 256
|
||||
*>
|
||||
fn void! Base32Decoder.init(&self, Alphabet decoder = STD_ALPHABET, int padding = STD_PADDING)
|
||||
{
|
||||
decoder.validate(padding)!;
|
||||
*self = { .alphabet = { .encoding = (char[32])decoder }, .padding = padding < 0 ? (char)0 : (char)padding };
|
||||
|
||||
self.alphabet.reverse[..] = INVALID;
|
||||
foreach (char i, c : decoder)
|
||||
{
|
||||
self.alphabet.reverse[c] = i;
|
||||
}
|
||||
}
|
||||
|
||||
<*
|
||||
Calculate the length in bytes of the decoded data.
|
||||
@param n "Length in bytes of input."
|
||||
@return "Length in bytes of the decoded data."
|
||||
*>
|
||||
fn usz Base32Decoder.decode_len(&self, usz n)
|
||||
{
|
||||
return decode_len(n, self.padding);
|
||||
}
|
||||
|
||||
<*
|
||||
Decode the content of src into dst, which must be properly sized.
|
||||
@param src "The input to be decoded."
|
||||
@param dst "The decoded input."
|
||||
@return "The decoded size."
|
||||
@return! Base32Error.DESTINATION_TOO_SMALL, Base32Error.CORRUPT_INPUT
|
||||
*>
|
||||
fn usz! Base32Decoder.decode(&self, char[] src, char[] dst)
|
||||
{
|
||||
if (src.len == 0) return 0;
|
||||
usz dn = self.decode_len(src.len);
|
||||
if (dst.len < dn) return Base32Error.DESTINATION_TOO_SMALL?;
|
||||
return decode_buffer(src, dst, self.padding, &self.alphabet).len;
|
||||
}
|
||||
|
||||
|
||||
@@ -308,3 +374,33 @@ fn void! Alphabet.validate(&self, int padding)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
distinct Alphabet = char[32];
|
||||
// Standard base32 Alphabet
|
||||
const Alphabet STD_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
||||
// Extended Hex Alphabet
|
||||
const Alphabet HEX_ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
|
||||
|
||||
const Base32Alphabet STANDARD = {
|
||||
.encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",
|
||||
.reverse = x`ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffff1a1b1c1d1e1fffffffffffffffff
|
||||
ff000102030405060708090a0b0c0d0e0f10111213141516171819ffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff`
|
||||
};
|
||||
|
||||
const Base32Alphabet HEX = {
|
||||
.encoding = "0123456789ABCDEFGHIJKLMNOPQRSTUV",
|
||||
.reverse = x`ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffff00010203040506070809ffffffffffff
|
||||
ff0a0b0c0d0e0f101112131415161718191a1b1c1d1e1fffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff`
|
||||
};
|
||||
|
||||
@@ -5,14 +5,260 @@ import std::core::bitorder;
|
||||
// Specifically this section:
|
||||
// https://www.rfc-editor.org/rfc/rfc4648#section-4
|
||||
|
||||
const char NO_PAD = 0;
|
||||
const char DEFAULT_PAD = '=';
|
||||
|
||||
struct Base64Alphabet
|
||||
{
|
||||
char[64] encoding;
|
||||
char[256] reverse;
|
||||
}
|
||||
|
||||
const Base64Alphabet STANDARD = {
|
||||
.encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
|
||||
.reverse =
|
||||
x`ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffff3effffff3f3435363738393a3b3c3dffffffffffff
|
||||
ff000102030405060708090a0b0c0d0e0f10111213141516171819ffffffffff
|
||||
ff1a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30313233ffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff`
|
||||
};
|
||||
|
||||
const Base64Alphabet URL = {
|
||||
.encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
|
||||
.reverse =
|
||||
x`ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffff3effff3435363738393a3b3c3dffffffffffff
|
||||
ff000102030405060708090a0b0c0d0e0f10111213141516171819ffffffff3f
|
||||
ff1a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30313233ffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff`
|
||||
};
|
||||
|
||||
const STD_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
const URL_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
||||
|
||||
fn String encode(char[] src, Allocator allocator, char padding = DEFAULT_PAD, Base64Alphabet* alphabet = &STANDARD)
|
||||
{
|
||||
char[] dst = allocator::alloc_array(allocator, char, encode_len(src.len, padding));
|
||||
return encode_buffer(src, dst, padding, alphabet);
|
||||
}
|
||||
|
||||
fn char[]! decode(char[] src, Allocator allocator, char padding = DEFAULT_PAD, Base64Alphabet* alphabet = &STANDARD)
|
||||
{
|
||||
char[] dst = allocator::alloc_array(allocator, char, decode_len(src.len, padding))!;
|
||||
return decode_buffer(src, dst, padding, alphabet);
|
||||
}
|
||||
|
||||
fn String encode_new(char[] code, char padding = DEFAULT_PAD, Base64Alphabet* alphabet = &STANDARD) @inline => encode(code, allocator::heap(), padding, alphabet);
|
||||
fn String encode_temp(char[] code, char padding = DEFAULT_PAD, Base64Alphabet* alphabet = &STANDARD) @inline => encode(code, allocator::temp(), padding, alphabet);
|
||||
fn char[]! decode_new(char[] code, char padding = DEFAULT_PAD, Base64Alphabet* alphabet = &STANDARD) @inline => decode(code, allocator::heap(), padding, alphabet);
|
||||
fn char[]! decode_temp(char[] code, char padding = DEFAULT_PAD, Base64Alphabet* alphabet = &STANDARD) @inline => decode(code, allocator::temp(), padding, alphabet);
|
||||
|
||||
|
||||
<*
|
||||
Calculate the size of the encoded data.
|
||||
@param n "Size of the input to be encoded."
|
||||
@param padding "The padding character or 0 if none"
|
||||
@require padding < 0xFF "Invalid padding character"
|
||||
@return "The size of the input once encoded."
|
||||
*>
|
||||
fn usz encode_len(usz n, char padding)
|
||||
{
|
||||
if (padding) return (n + 2) / 3 * 4;
|
||||
usz trailing = n % 3;
|
||||
return n / 3 * 4 + (trailing * 4 + 2) / 3;
|
||||
}
|
||||
|
||||
<*
|
||||
Calculate the size of the decoded data.
|
||||
@param n "Size of the input to be decoded."
|
||||
@param padding "The padding character or 0 if none"
|
||||
@require padding < 0xFF "Invalid padding character"
|
||||
@return "The size of the input once decoded."
|
||||
@return! DecodingFailure.INVALID_PADDING
|
||||
*>
|
||||
fn usz! decode_len(usz n, char padding)
|
||||
{
|
||||
usz dn = n / 4 * 3;
|
||||
usz trailing = n % 4;
|
||||
if (padding)
|
||||
{
|
||||
if (trailing != 0) return DecodingFailure.INVALID_PADDING?;
|
||||
// source size is multiple of 4
|
||||
return dn;
|
||||
}
|
||||
if (trailing == 1) return DecodingFailure.INVALID_PADDING?;
|
||||
return dn + trailing * 3 / 4;
|
||||
}
|
||||
|
||||
<*
|
||||
Encode the content of src into dst, which must be properly sized.
|
||||
@param src "The input to be encoded."
|
||||
@param dst "The encoded input."
|
||||
@param padding "The padding character or 0 if none"
|
||||
@param alphabet "The alphabet to use"
|
||||
@require padding < 0xFF "Invalid padding character"
|
||||
@return "The encoded size."
|
||||
@return! Base64Error.DESTINATION_TOO_SMALL
|
||||
*>
|
||||
fn String encode_buffer(char[] src, char[] dst, char padding = DEFAULT_PAD, Base64Alphabet* alphabet = &STANDARD)
|
||||
{
|
||||
if (src.len == 0) return (String)dst[:0];
|
||||
usz dn = encode_len(src.len, padding);
|
||||
char* dst_ptr = dst;
|
||||
assert(dst.len >= dn);
|
||||
usz trailing = src.len % 3;
|
||||
char[] src3 = src[:^trailing];
|
||||
|
||||
while (src3.len > 0)
|
||||
{
|
||||
uint group = (uint)src3[0] << 16 | (uint)src3[1] << 8 | (uint)src3[2];
|
||||
dst[0] = alphabet.encoding[group >> 18 & MASK];
|
||||
dst[1] = alphabet.encoding[group >> 12 & MASK];
|
||||
dst[2] = alphabet.encoding[group >> 6 & MASK];
|
||||
dst[3] = alphabet.encoding[group & MASK];
|
||||
dst = dst[4..];
|
||||
src3 = src3[3..];
|
||||
}
|
||||
|
||||
// Encode the remaining bytes according to:
|
||||
// https://www.rfc-editor.org/rfc/rfc4648#section-3.5
|
||||
switch (trailing)
|
||||
{
|
||||
case 1:
|
||||
uint group = (uint)src[^1] << 16;
|
||||
dst[0] = alphabet.encoding[group >> 18 & MASK];
|
||||
dst[1] = alphabet.encoding[group >> 12 & MASK];
|
||||
if (padding > 0)
|
||||
{
|
||||
dst[2] = padding;
|
||||
dst[3] = padding;
|
||||
}
|
||||
case 2:
|
||||
uint group = (uint)src[^2] << 16 | (uint)src[^1] << 8;
|
||||
dst[0] = alphabet.encoding[group >> 18 & MASK];
|
||||
dst[1] = alphabet.encoding[group >> 12 & MASK];
|
||||
dst[2] = alphabet.encoding[group >> 6 & MASK];
|
||||
if (padding > 0)
|
||||
{
|
||||
dst[3] = padding;
|
||||
}
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
unreachable();
|
||||
}
|
||||
return (String)dst_ptr[:dn];
|
||||
}
|
||||
|
||||
<*
|
||||
Decode the content of src into dst, which must be properly sized.
|
||||
@param src "The input to be decoded."
|
||||
@param dst "The decoded input."
|
||||
@param padding "The padding character or 0 if none"
|
||||
@param alphabet "The alphabet to use"
|
||||
@require (decode_len(src.len, padding) ?? 0) <= dst.len "Destination buffer too small"
|
||||
@require padding < 0xFF "Invalid padding character"
|
||||
@return "The decoded data."
|
||||
@return! DecodingFailure
|
||||
*>
|
||||
fn char[]! decode_buffer(char[] src, char[] dst, char padding = DEFAULT_PAD, Base64Alphabet* alphabet = &STANDARD)
|
||||
{
|
||||
if (src.len == 0) return dst[:0];
|
||||
usz dn = decode_len(src.len, padding)!;
|
||||
assert(dst.len >= dn);
|
||||
|
||||
usz trailing = src.len % 4;
|
||||
char* dst_ptr = dst;
|
||||
char[] src4 = src;
|
||||
switch
|
||||
{
|
||||
case !padding:
|
||||
src4 = src[:^trailing];
|
||||
default:
|
||||
// If there is padding, keep the last 4 bytes for later.
|
||||
// NB. src.len >= 4 as decode_len passed
|
||||
trailing = 4;
|
||||
if (src[^1] == padding) src4 = src[:^4];
|
||||
}
|
||||
while (src4.len > 0)
|
||||
{
|
||||
char c0 = alphabet.reverse[src4[0]];
|
||||
char c1 = alphabet.reverse[src4[1]];
|
||||
char c2 = alphabet.reverse[src4[2]];
|
||||
char c3 = alphabet.reverse[src4[3]];
|
||||
switch (0xFF)
|
||||
{
|
||||
case c0:
|
||||
case c1:
|
||||
case c2:
|
||||
case c3:
|
||||
return DecodingFailure.INVALID_CHARACTER?;
|
||||
}
|
||||
uint group = (uint)c0 << 18 | (uint)c1 << 12 | (uint)c2 << 6 | (uint)c3;
|
||||
dst[0] = (char)(group >> 16);
|
||||
dst[1] = (char)(group >> 8);
|
||||
dst[2] = (char)group;
|
||||
dst = dst[3..];
|
||||
src4 = src4[4..];
|
||||
}
|
||||
|
||||
if (trailing == 0) return dst_ptr[:dn];
|
||||
|
||||
src = src[^trailing..];
|
||||
char c0 = alphabet.reverse[src[0]];
|
||||
char c1 = alphabet.reverse[src[1]];
|
||||
if (c0 == 0xFF || c1 == 0xFF) return DecodingFailure.INVALID_PADDING?;
|
||||
if (!padding)
|
||||
{
|
||||
switch (src.len)
|
||||
{
|
||||
case 2:
|
||||
uint group = (uint)c0 << 18 | (uint)c1 << 12;
|
||||
dst[0] = (char)(group >> 16);
|
||||
case 3:
|
||||
char c2 = alphabet.reverse[src[2]];
|
||||
if (c2 == 0xFF) return DecodingFailure.INVALID_CHARACTER?;
|
||||
uint group = (uint)c0 << 18 | (uint)c1 << 12 | (uint)c2 << 6;
|
||||
dst[0] = (char)(group >> 16);
|
||||
dst[1] = (char)(group >> 8);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Valid paddings are:
|
||||
// 2: xx==
|
||||
// 1: xxx=
|
||||
switch (padding)
|
||||
{
|
||||
case src[2]:
|
||||
if (src[3] != padding) return DecodingFailure.INVALID_PADDING?;
|
||||
uint group = (uint)c0 << 18 | (uint)c1 << 12;
|
||||
dst[0] = (char)(group >> 16);
|
||||
dn -= 2;
|
||||
case src[3]:
|
||||
char c2 = alphabet.reverse[src[2]];
|
||||
if (c2 == 0xFF) return DecodingFailure.INVALID_CHARACTER?;
|
||||
uint group = (uint)c0 << 18 | (uint)c1 << 12 | (uint)c2 << 6;
|
||||
dst[0] = (char)(group >> 16);
|
||||
dst[1] = (char)(group >> 8);
|
||||
dn -= 1;
|
||||
}
|
||||
}
|
||||
return dst_ptr[:dn];
|
||||
}
|
||||
|
||||
const MASK @private = 0b111111;
|
||||
|
||||
struct Base64Encoder
|
||||
struct Base64Encoder @deprecated
|
||||
{
|
||||
int padding;
|
||||
char padding;
|
||||
String alphabet;
|
||||
}
|
||||
|
||||
@@ -32,10 +278,11 @@ fault Base64Error
|
||||
@require padding < 256
|
||||
@return! Base64Error.DUPLICATE_IN_ALPHABET, Base64Error.PADDING_IN_ALPHABET
|
||||
*>
|
||||
fn void! Base64Encoder.init(&self, String alphabet, int padding = '=')
|
||||
fn Base64Encoder*! Base64Encoder.init(&self, String alphabet, int padding = '=')
|
||||
{
|
||||
check_alphabet(alphabet, padding)!;
|
||||
*self = { .padding = padding, .alphabet = alphabet };
|
||||
*self = { .padding = padding < 0 ? 0 : (char)padding, .alphabet = alphabet };
|
||||
return self;
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -45,9 +292,7 @@ fn void! Base64Encoder.init(&self, String alphabet, int padding = '=')
|
||||
*>
|
||||
fn usz Base64Encoder.encode_len(&self, usz n)
|
||||
{
|
||||
if (self.padding >= 0) return (n + 2) / 3 * 4;
|
||||
usz trailing = n % 3;
|
||||
return n / 3 * 4 + (trailing * 4 + 2) / 3;
|
||||
return encode_len(n, self.padding);
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -62,56 +307,18 @@ fn usz! Base64Encoder.encode(&self, char[] src, char[] dst)
|
||||
if (src.len == 0) return 0;
|
||||
usz dn = self.encode_len(src.len);
|
||||
if (dst.len < dn) return Base64Error.DESTINATION_TOO_SMALL?;
|
||||
usz trailing = src.len % 3;
|
||||
char[] src3 = src[:^trailing];
|
||||
|
||||
while (src3.len > 0)
|
||||
{
|
||||
uint group = (uint)src3[0] << 16 | (uint)src3[1] << 8 | (uint)src3[2];
|
||||
dst[0] = self.alphabet[group >> 18 & MASK];
|
||||
dst[1] = self.alphabet[group >> 12 & MASK];
|
||||
dst[2] = self.alphabet[group >> 6 & MASK];
|
||||
dst[3] = self.alphabet[group & MASK];
|
||||
dst = dst[4..];
|
||||
src3 = src3[3..];
|
||||
}
|
||||
|
||||
// Encode the remaining bytes according to:
|
||||
// https://www.rfc-editor.org/rfc/rfc4648#section-3.5
|
||||
switch (trailing)
|
||||
{
|
||||
case 1:
|
||||
uint group = (uint)src[^1] << 16;
|
||||
dst[0] = self.alphabet[group >> 18 & MASK];
|
||||
dst[1] = self.alphabet[group >> 12 & MASK];
|
||||
if (self.padding >= 0)
|
||||
{
|
||||
char pad = (char)self.padding;
|
||||
dst[2] = pad;
|
||||
dst[3] = pad;
|
||||
}
|
||||
case 2:
|
||||
uint group = (uint)src[^2] << 16 | (uint)src[^1] << 8;
|
||||
dst[0] = self.alphabet[group >> 18 & MASK];
|
||||
dst[1] = self.alphabet[group >> 12 & MASK];
|
||||
dst[2] = self.alphabet[group >> 6 & MASK];
|
||||
if (self.padding >= 0)
|
||||
{
|
||||
char pad = (char)self.padding;
|
||||
dst[3] = pad;
|
||||
}
|
||||
}
|
||||
return dn;
|
||||
Base64Alphabet a = { .encoding = self.alphabet[:64] };
|
||||
return encode_buffer(src, dst, self.padding, &a).len;
|
||||
}
|
||||
|
||||
struct Base64Decoder
|
||||
struct Base64Decoder @deprecated
|
||||
{
|
||||
int padding;
|
||||
String alphabet;
|
||||
char[256] reverse;
|
||||
char invalid;
|
||||
char padding;
|
||||
Base64Alphabet encoding;
|
||||
bool init_done;
|
||||
}
|
||||
|
||||
import std;
|
||||
<*
|
||||
@param alphabet "The alphabet used for encoding."
|
||||
@param padding "Set to a negative value to disable padding."
|
||||
@@ -121,29 +328,15 @@ struct Base64Decoder
|
||||
*>
|
||||
fn void! Base64Decoder.init(&self, String alphabet, int padding = '=')
|
||||
{
|
||||
self.init_done = true;
|
||||
check_alphabet(alphabet, padding)!;
|
||||
*self = { .padding = padding, .alphabet = alphabet };
|
||||
*self = { .padding = padding < 0 ? 0 : (char)padding, .encoding.encoding = alphabet[:64] };
|
||||
|
||||
self.encoding.reverse[..] = 0xFF;
|
||||
|
||||
bool[256] checked;
|
||||
foreach (i, c : alphabet)
|
||||
{
|
||||
checked[c] = true;
|
||||
self.reverse[c] = (char)i;
|
||||
}
|
||||
if (padding < 0)
|
||||
{
|
||||
self.invalid = 255;
|
||||
return;
|
||||
}
|
||||
// Find a character for invalid neither in the alphabet nor equal to the padding.
|
||||
char pad = (char)padding;
|
||||
foreach (i, ok : checked)
|
||||
{
|
||||
if (!ok && (char)i != pad)
|
||||
{
|
||||
self.invalid = (char)i;
|
||||
break;
|
||||
}
|
||||
self.encoding.reverse[c] = (char)i;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,19 +348,7 @@ fn void! Base64Decoder.init(&self, String alphabet, int padding = '=')
|
||||
*>
|
||||
fn usz! Base64Decoder.decode_len(&self, usz n)
|
||||
{
|
||||
usz dn = n / 4 * 3;
|
||||
usz trailing = n % 4;
|
||||
if (self.padding >= 0)
|
||||
{
|
||||
if (trailing != 0) return Base64Error.INVALID_PADDING?;
|
||||
// source size is multiple of 4
|
||||
}
|
||||
else
|
||||
{
|
||||
if (trailing == 1) return Base64Error.INVALID_PADDING?;
|
||||
dn += trailing * 3 / 4;
|
||||
}
|
||||
return dn;
|
||||
return decode_len(n, self.padding) ?? Base64Error.INVALID_PADDING?;
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -182,86 +363,17 @@ fn usz! Base64Decoder.decode(&self, char[] src, char[] dst)
|
||||
if (src.len == 0) return 0;
|
||||
usz dn = self.decode_len(src.len)!;
|
||||
if (dst.len < dn) return Base64Error.DESTINATION_TOO_SMALL?;
|
||||
|
||||
usz trailing = src.len % 4;
|
||||
char[] src4 = src;
|
||||
switch
|
||||
char[]! decoded = decode_buffer(src, dst, self.padding, &self.encoding);
|
||||
if (catch err = decoded)
|
||||
{
|
||||
case self.padding < 0:
|
||||
src4 = src[:^trailing];
|
||||
case DecodingFailure.INVALID_PADDING:
|
||||
return Base64Error.INVALID_PADDING?;
|
||||
case DecodingFailure.INVALID_CHARACTER:
|
||||
return Base64Error.INVALID_CHARACTER?;
|
||||
default:
|
||||
// If there is padding, keep the last 4 bytes for later.
|
||||
// NB. src.len >= 4 as decode_len passed
|
||||
trailing = 4;
|
||||
char pad = (char)self.padding;
|
||||
if (src[^1] == pad) src4 = src[:^4];
|
||||
return err?;
|
||||
}
|
||||
while (src4.len > 0)
|
||||
{
|
||||
char c0 = self.reverse[src4[0]];
|
||||
char c1 = self.reverse[src4[1]];
|
||||
char c2 = self.reverse[src4[2]];
|
||||
char c3 = self.reverse[src4[3]];
|
||||
switch (self.invalid)
|
||||
{
|
||||
case c0:
|
||||
case c1:
|
||||
case c2:
|
||||
case c3:
|
||||
return Base64Error.INVALID_CHARACTER?;
|
||||
}
|
||||
uint group = (uint)c0 << 18 | (uint)c1 << 12 | (uint)c2 << 6 | (uint)c3;
|
||||
dst[0] = (char)(group >> 16);
|
||||
dst[1] = (char)(group >> 8);
|
||||
dst[2] = (char)group;
|
||||
dst = dst[3..];
|
||||
src4 = src4[4..];
|
||||
}
|
||||
|
||||
if (trailing == 0) return dn;
|
||||
|
||||
src = src[^trailing..];
|
||||
char c0 = self.reverse[src[0]];
|
||||
char c1 = self.reverse[src[1]];
|
||||
if (c0 == self.invalid || c1 == self.invalid) return Base64Error.INVALID_PADDING?;
|
||||
if (self.padding < 0)
|
||||
{
|
||||
switch (src.len)
|
||||
{
|
||||
case 2:
|
||||
uint group = (uint)c0 << 18 | (uint)c1 << 12;
|
||||
dst[0] = (char)(group >> 16);
|
||||
case 3:
|
||||
char c2 = self.reverse[src[2]];
|
||||
if (c2 == self.invalid) return Base64Error.INVALID_CHARACTER?;
|
||||
uint group = (uint)c0 << 18 | (uint)c1 << 12 | (uint)c2 << 6;
|
||||
dst[0] = (char)(group >> 16);
|
||||
dst[1] = (char)(group >> 8);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Valid paddings are:
|
||||
// 2: xx==
|
||||
// 1: xxx=
|
||||
char pad = (char)self.padding;
|
||||
switch (pad)
|
||||
{
|
||||
case src[2]:
|
||||
if (src[3] != pad) return Base64Error.INVALID_PADDING?;
|
||||
uint group = (uint)c0 << 18 | (uint)c1 << 12;
|
||||
dst[0] = (char)(group >> 16);
|
||||
dn -= 2;
|
||||
case src[3]:
|
||||
char c2 = self.reverse[src[2]];
|
||||
if (c2 == self.invalid) return Base64Error.INVALID_CHARACTER?;
|
||||
uint group = (uint)c0 << 18 | (uint)c1 << 12 | (uint)c2 << 6;
|
||||
dst[0] = (char)(group >> 16);
|
||||
dst[1] = (char)(group >> 8);
|
||||
dn -= 1;
|
||||
}
|
||||
}
|
||||
return dn;
|
||||
return decoded.len;
|
||||
}
|
||||
|
||||
// Make sure that all bytes in the alphabet are unique and
|
||||
@@ -285,4 +397,5 @@ fn void! check_alphabet(String alphabet, int padding) @local
|
||||
if (checked[c]) return Base64Error.DUPLICATE_IN_ALPHABET?;
|
||||
checked[c] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
7
lib/std/encoding/encoding.c3
Normal file
7
lib/std/encoding/encoding.c3
Normal file
@@ -0,0 +1,7 @@
|
||||
module std::encoding;
|
||||
|
||||
fault DecodingFailure
|
||||
{
|
||||
INVALID_CHARACTER,
|
||||
INVALID_PADDING,
|
||||
}
|
||||
109
lib/std/encoding/hex.c3
Normal file
109
lib/std/encoding/hex.c3
Normal file
@@ -0,0 +1,109 @@
|
||||
module std::encoding::hex;
|
||||
import std::encoding @norecurse;
|
||||
|
||||
// The implementation is based on https://www.rfc-editor.org/rfc/rfc4648
|
||||
|
||||
fn String encode_buffer(char[] code, char[] buffer)
|
||||
{
|
||||
return (String)buffer[:encode_bytes(code, buffer)];
|
||||
}
|
||||
|
||||
fn char[]! decode_buffer(char[] code, char[] buffer)
|
||||
{
|
||||
return buffer[:decode_bytes(code, buffer)!];
|
||||
}
|
||||
|
||||
fn String encode(char[] code, Allocator allocator)
|
||||
{
|
||||
char[] data = allocator::alloc_array(allocator, char, encode_len(code.len));
|
||||
return (String)data[:encode_bytes(code, data)];
|
||||
}
|
||||
|
||||
fn char[]! decode(char[] code, Allocator allocator)
|
||||
{
|
||||
char[] data = allocator::alloc_array(allocator, char, decode_len(code.len));
|
||||
return data[:decode_bytes(code, data)!];
|
||||
}
|
||||
|
||||
fn String encode_new(char[] code) @inline => encode(code, allocator::heap());
|
||||
fn String encode_temp(char[] code) @inline => encode(code, allocator::temp());
|
||||
fn char[]! decode_new(char[] code) @inline => decode(code, allocator::heap());
|
||||
fn char[]! decode_temp(char[] code) @inline => decode(code, allocator::temp());
|
||||
|
||||
<*
|
||||
Calculate the size of the encoded data.
|
||||
@param n "Size of the input to be encoded."
|
||||
@return "The size of the input once encoded."
|
||||
*>
|
||||
fn usz encode_len(usz n) => n * 2;
|
||||
|
||||
<*
|
||||
Encode the content of src into dst, which must be properly sized.
|
||||
@param src "The input to be encoded."
|
||||
@param dst "The encoded input."
|
||||
@return "The encoded size."
|
||||
@require dst.len >= encode_len(src.len) "Destination array is not large enough"
|
||||
*>
|
||||
fn usz encode_bytes(char[] src, char[] dst)
|
||||
{
|
||||
usz j = 0;
|
||||
foreach (v : src)
|
||||
{
|
||||
dst[j] = HEXALPHABET[v >> 4];
|
||||
dst[j + 1] = HEXALPHABET[v & 0x0f];
|
||||
j = j + 2;
|
||||
}
|
||||
return src.len * 2;
|
||||
}
|
||||
|
||||
<*
|
||||
Calculate the size of the decoded data.
|
||||
@param n "Size of the input to be decoded."
|
||||
@return "The size of the input once decoded."
|
||||
*>
|
||||
macro usz decode_len(usz n) => n / 2;
|
||||
|
||||
<*
|
||||
Decodes src into bytes. Returns the actual number of bytes written to dst.
|
||||
|
||||
Expects that src only contains hexadecimal characters and that src has even
|
||||
length.
|
||||
|
||||
@param src "The input to be decoded."
|
||||
@param dst "The decoded input."
|
||||
@require src.len % 2 == 0 "src is not of even length"
|
||||
@require dst.len >= decode_len(src.len) "Destination array is not large enough"
|
||||
@return! DecodingFailure.INVALID_CHARACTER
|
||||
*>
|
||||
fn usz! decode_bytes(char[] src, char[] dst)
|
||||
{
|
||||
usz i;
|
||||
for (usz j = 1; j < src.len; j += 2)
|
||||
{
|
||||
char a = HEXREVERSE[src[j - 1]];
|
||||
char b = HEXREVERSE[src[j]];
|
||||
if (a > 0x0f || b > 0x0f) return DecodingFailure.INVALID_CHARACTER?;
|
||||
dst[i] = (a << 4) | b;
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
const char[*] HEXALPHABET @private = "0123456789abcdef";
|
||||
const char[*] HEXREVERSE @private =
|
||||
x`ffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffff
|
||||
00010203040506070809ffffffffffff
|
||||
ff0a0b0c0d0e0fffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffff
|
||||
ff0a0b0c0d0e0fffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffff`;
|
||||
@@ -8,7 +8,7 @@ distinct Fnv32a = uint;
|
||||
const FNV32A_START @private = 0x811c9dc5;
|
||||
const FNV32A_MUL @private = 0x01000193;
|
||||
|
||||
macro void @update(uint* &h, char x) @private => *h = (*h * FNV32A_MUL) ^ x;
|
||||
macro void @update(&h, char x) @private => *h = (*h ^ ($typeof(*h))x) * FNV32A_MUL;
|
||||
|
||||
fn void Fnv32a.init(&self)
|
||||
{
|
||||
@@ -17,17 +17,17 @@ fn void Fnv32a.init(&self)
|
||||
|
||||
fn void Fnv32a.update(&self, char[] data)
|
||||
{
|
||||
uint h = (uint)*self;
|
||||
Fnv32a h = *self;
|
||||
foreach (char x : data)
|
||||
{
|
||||
@update(h, x);
|
||||
}
|
||||
*self = (Fnv32a)h;
|
||||
*self = h;
|
||||
}
|
||||
|
||||
macro void Fnv32a.update_char(&self, char c)
|
||||
{
|
||||
@update(*self, x);
|
||||
@update(*self, c);
|
||||
}
|
||||
|
||||
fn uint encode(char[] data)
|
||||
@@ -38,4 +38,4 @@ fn uint encode(char[] data)
|
||||
@update(h, x);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ distinct Fnv64a = ulong;
|
||||
const FNV64A_START @private = 0xcbf29ce484222325;
|
||||
const FNV64A_MUL @private = 0x00000100000001b3;
|
||||
|
||||
macro void @update(ulong* &h, char x) @private => *h = (*h * FNV64A_MUL) ^ x;
|
||||
macro void @update(&h, char x) @private => *h = (*h ^ ($typeof(*h))x) * FNV64A_MUL;
|
||||
|
||||
fn void Fnv64a.init(&self)
|
||||
{
|
||||
@@ -17,17 +17,17 @@ fn void Fnv64a.init(&self)
|
||||
|
||||
fn void Fnv64a.update(&self, char[] data)
|
||||
{
|
||||
ulong h = (ulong)*self;
|
||||
Fnv64a h = *self;
|
||||
foreach (char x : data)
|
||||
{
|
||||
@update(h, x);
|
||||
}
|
||||
*self = (Fnv64a)h;
|
||||
*self = h;
|
||||
}
|
||||
|
||||
macro void Fnv64a.update_char(&self, char c)
|
||||
{
|
||||
@update(*self, x);
|
||||
@update(*self, c);
|
||||
}
|
||||
|
||||
fn ulong encode(char[] data)
|
||||
@@ -38,4 +38,4 @@ fn ulong encode(char[] data)
|
||||
@update(h, x);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,10 @@ struct BitWriter
|
||||
uint len;
|
||||
}
|
||||
|
||||
// c3 doesn't allow to shift more than bit width of a variable,
|
||||
// so use closest byte boundary of 24 instead of 32
|
||||
const int WRITER_BITS = 24;
|
||||
|
||||
fn void BitWriter.init(&self, OutStream byte_writer)
|
||||
{
|
||||
*self = { .writer = byte_writer };
|
||||
@@ -53,7 +57,9 @@ fn void BitWriter.init(&self, OutStream byte_writer)
|
||||
fn void! BitWriter.flush(&self)
|
||||
{
|
||||
if (self.len == 0) return;
|
||||
uint bits = self.bits << (32 - self.len);
|
||||
|
||||
int padding = ($sizeof(self.bits) * 8 - self.len);
|
||||
uint bits = self.bits << padding;
|
||||
uint n = (self.len + 7) / 8;
|
||||
char[4] buffer;
|
||||
bitorder::write(bits, &buffer, UIntBE);
|
||||
@@ -62,24 +68,27 @@ fn void! BitWriter.flush(&self)
|
||||
}
|
||||
|
||||
<*
|
||||
@require nbits <= 8
|
||||
@require nbits <= 32
|
||||
*>
|
||||
fn void! BitWriter.write_bits(&self, uint bits, uint nbits)
|
||||
{
|
||||
if (nbits == 0) return;
|
||||
uint n = self.len + nbits;
|
||||
uint to_write = n / 8;
|
||||
uint left = n % 8;
|
||||
if (to_write > 0)
|
||||
while (self.len + nbits > WRITER_BITS)
|
||||
{
|
||||
ulong lbits;
|
||||
if (self.len > 0) lbits = (ulong)self.bits << (64 - self.len);
|
||||
lbits |= (ulong)(bits >> left) << (64 - (n - left));
|
||||
char[8] buffer;
|
||||
bitorder::write(lbits, &buffer, ULongBE);
|
||||
io::write_all(self.writer, buffer[:to_write])!;
|
||||
uint to_push = WRITER_BITS - self.len;
|
||||
uint bits_to_push = (bits >> (nbits - to_push)) & ((1 << to_push) - 1);
|
||||
|
||||
self.bits <<= to_push;
|
||||
self.bits |= bits_to_push;
|
||||
self.len += to_push;
|
||||
nbits -= to_push;
|
||||
|
||||
self.flush()!;
|
||||
}
|
||||
self.bits <<= left;
|
||||
self.bits |= bits & ((1 << left) - 1);
|
||||
self.len = left;
|
||||
|
||||
if (nbits == 0) return;
|
||||
|
||||
self.bits <<= nbits;
|
||||
self.bits |= bits & ((1 << nbits) - 1);
|
||||
self.len += nbits;
|
||||
}
|
||||
@@ -182,6 +182,17 @@ fn char[]! load_temp(String filename)
|
||||
return load_new(filename, allocator::temp());
|
||||
}
|
||||
|
||||
fn void! save(String filename, char[] data)
|
||||
{
|
||||
File file = open(filename, "wb")!;
|
||||
defer (void)file.close();
|
||||
while (data.len)
|
||||
{
|
||||
usz written = file.write(data)!;
|
||||
data = data[written..];
|
||||
}
|
||||
}
|
||||
|
||||
<*
|
||||
@require self.file `File must be initialized`
|
||||
*>
|
||||
|
||||
@@ -28,7 +28,8 @@ macro bool is_struct_with_default_print($Type)
|
||||
{
|
||||
return $Type.kindof == STRUCT
|
||||
&&& !$defined($Type.to_format)
|
||||
&&& !$defined($Type.to_new_string);
|
||||
&&& !$defined($Type.to_new_string)
|
||||
&&& !$defined($Type.to_string);
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -529,4 +530,4 @@ fn usz! Formatter.print(&self, String str)
|
||||
}
|
||||
foreach (c : str) self.out(c)!;
|
||||
return self.idx;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ fn void*! native_freopen(void* file, String filename, String mode) @inline
|
||||
|
||||
fn void! native_fseek(void* file, isz offset, Seek seek_mode) @inline
|
||||
{
|
||||
if (libc::fseek(file, (SeekIndex)offset, (CInt)seek_mode)) return file_seek_errno()?;
|
||||
if (libc::fseek(file, (SeekIndex)offset, seek_mode.ordinal)) return file_seek_errno()?;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -121,13 +121,16 @@ fn usz! WriteBuffer.write(&self, char[] bytes) @dynamic
|
||||
fn void! WriteBuffer.write_byte(&self, char c) @dynamic
|
||||
{
|
||||
usz n = self.bytes.len - self.index;
|
||||
if (n == 0) self.write_pending()!;
|
||||
self.bytes[0] = c;
|
||||
self.index = 1;
|
||||
if (n == 0)
|
||||
{
|
||||
self.write_pending()!;
|
||||
}
|
||||
self.bytes[self.index] = c;
|
||||
self.index += 1;
|
||||
}
|
||||
|
||||
fn void! WriteBuffer.write_pending(&self) @local
|
||||
{
|
||||
self.index -= self.wrapped_stream.write(self.bytes[:self.index])!;
|
||||
if (self.index != 0) return IoError.INCOMPLETE_WRITE?;
|
||||
}
|
||||
}
|
||||
|
||||
70
lib/std/io/stream/multireader.c3
Normal file
70
lib/std/io/stream/multireader.c3
Normal file
@@ -0,0 +1,70 @@
|
||||
module std::io;
|
||||
|
||||
/* MultiReader implements the InStream interface and provides a logical
|
||||
* concatenation of the provided readers. They are read sequentially. If all the
|
||||
* data has been read, IoError.EOF is returned.
|
||||
*/
|
||||
struct MultiReader (InStream)
|
||||
{
|
||||
InStream[] readers;
|
||||
usz index;
|
||||
Allocator allocator;
|
||||
}
|
||||
|
||||
|
||||
<*
|
||||
@param [&inout] self
|
||||
@param [&inout] allocator
|
||||
@require self.readers.len == 0 "Init may not run on already initialized data"
|
||||
@ensure self.index == 0
|
||||
*>
|
||||
fn MultiReader* MultiReader.new_init(&self, InStream... readers, Allocator allocator = allocator::heap())
|
||||
{
|
||||
InStream []copy = allocator::new_array(allocator, InStream, readers.len);
|
||||
copy[..] = readers[..];
|
||||
*self = { .readers = copy, .allocator = allocator };
|
||||
return self;
|
||||
}
|
||||
|
||||
<*
|
||||
@param [&inout] self
|
||||
@require self.readers.len == 0 "Init may not run on already initialized data"
|
||||
@ensure self.index == 0
|
||||
*>
|
||||
fn MultiReader* MultiReader.temp_init(&self, InStream... readers)
|
||||
{
|
||||
return self.new_init(...readers, allocator: allocator::temp());
|
||||
}
|
||||
|
||||
fn void MultiReader.free(&self)
|
||||
{
|
||||
if (!self.allocator) return;
|
||||
allocator::free(self.allocator, self.readers);
|
||||
*self = {};
|
||||
}
|
||||
|
||||
fn usz! MultiReader.read(&self, char[] bytes) @dynamic
|
||||
{
|
||||
InStream r = self.readers[self.index];
|
||||
usz! n = r.read(bytes);
|
||||
if (catch err = n)
|
||||
{
|
||||
case IoError.EOF:
|
||||
self.index++;
|
||||
if (self.index >= self.readers.len)
|
||||
{
|
||||
return IoError.EOF?;
|
||||
}
|
||||
return self.read(bytes);
|
||||
default:
|
||||
return err?;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
fn char! MultiReader.read_byte(&self) @dynamic
|
||||
{
|
||||
char[1] data;
|
||||
self.read(data[..])!;
|
||||
return data[0];
|
||||
}
|
||||
59
lib/std/io/stream/multiwriter.c3
Normal file
59
lib/std/io/stream/multiwriter.c3
Normal file
@@ -0,0 +1,59 @@
|
||||
module std::io;
|
||||
|
||||
/* MultiWriter implements the OutStream interface and duplicates any write
|
||||
* operation to all the wrapped writers.
|
||||
*/
|
||||
struct MultiWriter (OutStream)
|
||||
{
|
||||
OutStream[] writers;
|
||||
Allocator allocator;
|
||||
}
|
||||
|
||||
<*
|
||||
@param [&inout] self
|
||||
@param [&inout] allocator
|
||||
@require writers.len > 0
|
||||
@require self.writers.len == 0 "Init may not run on already initialized data"
|
||||
*>
|
||||
fn MultiWriter* MultiWriter.new_init(&self, OutStream... writers, Allocator allocator = allocator::heap())
|
||||
{
|
||||
OutStream[] copy = allocator::new_array(allocator, OutStream, writers.len);
|
||||
copy[..] = writers[..];
|
||||
*self = { .writers = copy, .allocator = allocator };
|
||||
return self;
|
||||
}
|
||||
|
||||
<*
|
||||
@param [&inout] self
|
||||
@require writers.len > 0
|
||||
@require self.writers.len == 0 "Init may not run on already initialized data"
|
||||
*>
|
||||
fn MultiWriter* MultiWriter.temp_init(&self, OutStream... writers)
|
||||
{
|
||||
return self.new_init(...writers, allocator: allocator::temp());
|
||||
}
|
||||
|
||||
fn void MultiWriter.free(&self)
|
||||
{
|
||||
if (!self.allocator) return;
|
||||
allocator::free(self.allocator, self.writers);
|
||||
*self = {};
|
||||
}
|
||||
|
||||
fn usz! MultiWriter.write(&self, char[] bytes) @dynamic
|
||||
{
|
||||
usz n;
|
||||
foreach (w : self.writers)
|
||||
{
|
||||
n = w.write(bytes)!;
|
||||
if (n != bytes.len) return IoError.INCOMPLETE_WRITE?;
|
||||
}
|
||||
return bytes.len;
|
||||
}
|
||||
|
||||
fn void! MultiWriter.write_byte(&self, char c) @dynamic
|
||||
{
|
||||
char[1] data;
|
||||
data[0] = c;
|
||||
self.write(data[..])!;
|
||||
}
|
||||
42
lib/std/io/stream/teereader.c3
Normal file
42
lib/std/io/stream/teereader.c3
Normal file
@@ -0,0 +1,42 @@
|
||||
module std::io;
|
||||
|
||||
struct TeeReader (InStream)
|
||||
{
|
||||
InStream r;
|
||||
OutStream w;
|
||||
}
|
||||
|
||||
<* Returns a reader that implements InStream and that will write any data read
|
||||
from the wrapped reader r to the writer w. There is no internal buffering.
|
||||
|
||||
@param [&inout] r "Stream r to read from."
|
||||
@param [&inout] w "Stream w to write to what it reads from r."
|
||||
*>
|
||||
macro TeeReader tee_reader(InStream r, OutStream w) => { r, w };
|
||||
|
||||
<*
|
||||
@param [&inout] self
|
||||
@param [&inout] r "Stream r to read from."
|
||||
@param [&inout] w "Stream w to write to what it reads from r."
|
||||
*>
|
||||
fn TeeReader* TeeReader.init(&self, InStream r, OutStream w)
|
||||
{
|
||||
*self = tee_reader(r, w);
|
||||
return self;
|
||||
}
|
||||
|
||||
fn usz! TeeReader.read(&self, char[] bytes) @dynamic
|
||||
{
|
||||
usz nr, nw;
|
||||
nr = self.r.read(bytes)!;
|
||||
nw = self.w.write(bytes[:nr])!;
|
||||
if (nr != nw) return IoError.GENERAL_ERROR?;
|
||||
return nr;
|
||||
}
|
||||
|
||||
fn char! TeeReader.read_byte(&self) @dynamic
|
||||
{
|
||||
char[1] data;
|
||||
self.read(data[..])!;
|
||||
return data[0];
|
||||
}
|
||||
@@ -63,12 +63,6 @@ const bool BSD_FLAVOR_SIG @local = env::DARWIN || env::BSD_FAMILY;
|
||||
def Time_t = $typefrom(env::WIN32 ? long.typeid : CLong.typeid);
|
||||
def Off_t = $typefrom(env::WIN32 ? int.typeid : usz.typeid);
|
||||
|
||||
struct Timespec
|
||||
{
|
||||
Time_t tv_sec;
|
||||
CLong tv_nsec;
|
||||
}
|
||||
|
||||
module libc @if(env::LIBC);
|
||||
|
||||
extern fn void abort();
|
||||
|
||||
@@ -17,10 +17,10 @@ struct Stat
|
||||
Gid_t st_gid;
|
||||
Dev_t st_rdev;
|
||||
|
||||
Timespec st_atimespec; // time of last access
|
||||
Timespec st_mtimespec; // time of last data modification
|
||||
Timespec st_ctimespec; // time of last status change
|
||||
Timespec st_birthtimespec; // time of file creation(birth)
|
||||
TimeSpec st_atimespec; // time of last access
|
||||
TimeSpec st_mtimespec; // time of last data modification
|
||||
TimeSpec st_ctimespec; // time of last status change
|
||||
TimeSpec st_birthtimespec; // time of file creation(birth)
|
||||
Off_t st_size; // file size, in bytes
|
||||
Blkcnt_t st_blocks; // blocks allocated for file
|
||||
Blksize_t st_blocksize; // optimal blocksize for I/O
|
||||
|
||||
@@ -328,7 +328,7 @@ fn BigInt BigInt.unary_minus(&self)
|
||||
}
|
||||
|
||||
|
||||
macro void BigInt.div(self, BigInt other)
|
||||
macro BigInt BigInt.div(self, BigInt other)
|
||||
{
|
||||
self.div_this(other);
|
||||
return self;
|
||||
@@ -831,6 +831,14 @@ fn BigInt BigInt.gcd(&self, BigInt other)
|
||||
return g;
|
||||
}
|
||||
|
||||
fn BigInt BigInt.lcm(&self, BigInt other)
|
||||
{
|
||||
BigInt x = self.abs();
|
||||
BigInt y = other.abs();
|
||||
BigInt g = y.mult(x);
|
||||
return g.div(x.gcd(y));
|
||||
}
|
||||
|
||||
<*
|
||||
@require bits >> 5 < MAX_LEN "Required bits > maxlength"
|
||||
*>
|
||||
|
||||
@@ -131,6 +131,28 @@ macro deg_to_rad(x) {
|
||||
*>
|
||||
macro abs(x) => $$abs(x);
|
||||
|
||||
<*
|
||||
@require values::@is_int(x) || values::@is_float(x) "Expected an integer or floating point value"
|
||||
@require values::@is_int(y) || values::@is_float(y) "Expected an integer or floating point value"
|
||||
*>
|
||||
macro is_approx(x, y, eps)
|
||||
{
|
||||
if (x == y) return true;
|
||||
if (is_nan(x) || is_nan(y)) return false;
|
||||
return abs(x-y) <= eps;
|
||||
}
|
||||
|
||||
<*
|
||||
@require values::@is_int(x) || values::@is_float(x) "Expected an integer or floating point value"
|
||||
@require values::@is_int(y) || values::@is_float(y) "Expected an integer or floating point value"
|
||||
*>
|
||||
macro is_approx_rel(x, y, eps)
|
||||
{
|
||||
if (x == y) return true;
|
||||
if (is_nan(x) || is_nan(y)) return false;
|
||||
return abs(x-y) <= eps * max(abs(x), abs(y));
|
||||
}
|
||||
|
||||
<*
|
||||
@require values::@is_int(x) `The input must be an integer`
|
||||
*>
|
||||
@@ -290,7 +312,7 @@ macro copysign(mag, sgn) => $$copysign(values::promote_int_same(mag, sgn), ($typ
|
||||
<*
|
||||
@require values::@is_promotable_to_floatlike(x) `The input must be a number value or float vector`
|
||||
*>
|
||||
macro cos(x) => $$cos(x);
|
||||
macro cos(x) => $$cos(values::promote_int(x));
|
||||
|
||||
<*
|
||||
@require values::@is_promotable_to_floatlike(x) `The input must be a number value or float vector`
|
||||
@@ -1183,4 +1205,62 @@ macro long[<*>] long[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, di
|
||||
@require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar`
|
||||
@require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar`
|
||||
*>
|
||||
macro ulong[<*>] ulong[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
|
||||
macro ulong[<*>] ulong[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
|
||||
|
||||
<*
|
||||
@require types::is_int($typeof(a)) `The input must be an integer`
|
||||
@require types::is_int($typeof(b)) `The input must be an integer`
|
||||
*>
|
||||
macro _gcd(a, b) @private
|
||||
{
|
||||
if (a == 0) return b;
|
||||
if (b == 0) return a;
|
||||
|
||||
var $Type = $typeof(a);
|
||||
$Type r, aa, ab;
|
||||
aa = abs(a);
|
||||
ab = abs(b);
|
||||
while (ab != 0)
|
||||
{
|
||||
r = aa % ab;
|
||||
aa = ab;
|
||||
ab = r;
|
||||
}
|
||||
return aa;
|
||||
}
|
||||
|
||||
<*
|
||||
Calculate the least common multiple for the provided arguments.
|
||||
|
||||
@require $vacount >= 2 `At least two arguments are required.`
|
||||
*>
|
||||
macro lcm(...)
|
||||
{
|
||||
$typeof($vaarg[0]) result = $vaarg[0];
|
||||
$for (var $i = 1; $i < $vacount; $i++)
|
||||
$if $defined(result.lcm):
|
||||
result = result.lcm($vaarg[$i]);
|
||||
$else
|
||||
result = (abs($vaarg[$i]) * abs(result)) / (_gcd($vaarg[$i], result));
|
||||
$endif
|
||||
$endfor
|
||||
return result;
|
||||
}
|
||||
|
||||
<*
|
||||
Calculate the greatest common divisor for the provided arguments.
|
||||
|
||||
@require $vacount >= 2 `At least two arguments are required.`
|
||||
*>
|
||||
macro gcd(...)
|
||||
{
|
||||
$typeof($vaarg[0]) result = $vaarg[0];
|
||||
$for (var $i = 1; $i < $vacount; $i++)
|
||||
$if $defined(result.gcd):
|
||||
result = result.gcd($vaarg[$i]);
|
||||
$else
|
||||
result = _gcd($vaarg[$i], result);
|
||||
$endif
|
||||
$endfor
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@ union Complex
|
||||
Real[<2>] v;
|
||||
}
|
||||
|
||||
|
||||
const Complex IDENTITY = { 1, 0 };
|
||||
const Complex IMAGINARY = { 0, 1 };
|
||||
macro Complex Complex.add(self, Complex b) => Complex { .v = self.v + b.v };
|
||||
macro Complex Complex.add_each(self, Real b) => Complex { .v = self.v + b };
|
||||
macro Complex Complex.sub(self, Complex b) => Complex { .v = self.v - b.v };
|
||||
@@ -22,3 +22,10 @@ macro Complex Complex.div(self, Complex b)
|
||||
Real div = b.v.dot(b.v);
|
||||
return Complex{ (self.r * b.r + self.c * b.c) / div, (self.c * b.r - self.r * b.c) / div };
|
||||
}
|
||||
macro Complex Complex.inverse(self)
|
||||
{
|
||||
Real sqr = self.v.dot(self.v);
|
||||
return Complex{ self.r / sqr, -self.c / sqr };
|
||||
}
|
||||
macro Complex Complex.conjugate(self) => Complex { .r = self.r, .c = -self.c };
|
||||
macro bool Complex.equals(self, Complex b) => self.v == b.v;
|
||||
|
||||
@@ -197,7 +197,7 @@ fn Real Matrix4x4.determinant(&self)
|
||||
|
||||
fn Matrix2x2 Matrix2x2.adjoint(&self)
|
||||
{
|
||||
return { self.m00, -self.m01, -self.m10, self.m11 };
|
||||
return { self.m11, -self.m01, -self.m10, self.m00 };
|
||||
}
|
||||
|
||||
fn Matrix3x3 Matrix3x3.adjoint(&self)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::math::nolibc @if(env::NO_LIBC);
|
||||
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
|
||||
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/k_cos.c */
|
||||
/*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::math::nolibc @if(env::NO_LIBC);
|
||||
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
|
||||
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/k_cosf.c */
|
||||
/*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::math::nolibc @if(env::NO_LIBC);
|
||||
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
|
||||
|
||||
union DoubleInternal
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::math::nolibc @if(env::NO_LIBC);
|
||||
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
|
||||
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/k_sin.c */
|
||||
/*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::math::nolibc @if(env::NO_LIBC);
|
||||
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
|
||||
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/k_sinf.c */
|
||||
/*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::math::nolibc @if(env::NO_LIBC);
|
||||
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
|
||||
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/k_tan.c */
|
||||
/*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::math::nolibc @if(env::NO_LIBC);
|
||||
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
|
||||
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/k_tanf.c */
|
||||
/*
|
||||
|
||||
146
lib/std/math/math_nolibc/acos.c3
Normal file
146
lib/std/math/math_nolibc/acos.c3
Normal file
@@ -0,0 +1,146 @@
|
||||
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
|
||||
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/e_acos.c */
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunSoft, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
|
||||
const PIO2_HI @local = 1.57079632679489655800e+00; /* 0x3FF921FB, 0x54442D18 */
|
||||
const PIO2_LO @local = 6.12323399573676603587e-17; /* 0x3C91A626, 0x33145C07 */
|
||||
const PS0 @local = 1.66666666666666657415e-01; /* 0x3FC55555, 0x55555555 */
|
||||
const PS1 @local = -3.25565818622400915405e-01; /* 0xBFD4D612, 0x03EB6F7D */
|
||||
const PS2 @local = 2.01212532134862925881e-01; /* 0x3FC9C155, 0x0E884455 */
|
||||
const PS3 @local = -4.00555345006794114027e-02; /* 0xBFA48228, 0xB5688F3B */
|
||||
const PS4 @local = 7.91534994289814532176e-04; /* 0x3F49EFE0, 0x7501B288 */
|
||||
const PS5 @local = 3.47933107596021167570e-05; /* 0x3F023DE1, 0x0DFDF709 */
|
||||
const QS1 @local = -2.40339491173441421878e+00; /* 0xC0033A27, 0x1C8A2D4B */
|
||||
const QS2 @local = 2.02094576023350569471e+00; /* 0x40002AE5, 0x9C598AC8 */
|
||||
const QS3 @local = -6.88283971605453293030e-01; /* 0xBFE6066C, 0x1B8D0159 */
|
||||
const QS4 @local = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */
|
||||
|
||||
fn double _r(double z) @local
|
||||
{
|
||||
double p = z * (PS0 + z * (PS1 + z * (PS2 + z * (PS3 + z * (PS4 + z * PS5)))));
|
||||
double q = 1.0 + z * (QS1 + z * (QS2 + z * (QS3 + z * QS4)));
|
||||
return p / q;
|
||||
}
|
||||
|
||||
fn double _acos(double x) @weak @extern("acos") @nostrip
|
||||
{
|
||||
uint hx = x.high_word();
|
||||
uint ix = hx & 0x7fffffff;
|
||||
switch
|
||||
{
|
||||
/* |x| >= 1 or nan */
|
||||
case ix >= 0x3ff00000:
|
||||
uint lx = x.low_word();
|
||||
if ((ix - 0x3ff00000 | lx) == 0)
|
||||
{
|
||||
/* acos(1)=0, acos(-1)=pi */
|
||||
if (hx >> 31) return 2. * PIO2_HI + 0x1p-120f;
|
||||
return 0.;
|
||||
}
|
||||
return double.nan;
|
||||
/* |x| < 0.5 */
|
||||
case ix < 0x3fe00000:
|
||||
/* |x| < 2**-57 */
|
||||
if (ix <= 0x3c600000) return PIO2_HI + 0x1p-120f;
|
||||
return PIO2_HI - (x - (PIO2_LO - x * _r(x * x)));
|
||||
/* x < -0.5 */
|
||||
case (hx >> 31) != 0:
|
||||
double z = (1. + x) * 0.5;
|
||||
double s = math::sqrt(z);
|
||||
double w = _r(z) * s - PIO2_LO;
|
||||
return 2. * (PIO2_HI - (s + w));
|
||||
/* x > 0.5 */
|
||||
default:
|
||||
double z = (1. - x) * 0.5;
|
||||
double s = math::sqrt(z);
|
||||
double df @noinit;
|
||||
{
|
||||
ulong rep = bitcast(s, ulong);
|
||||
rep &= 0xffffffff00000000;
|
||||
df = bitcast(rep, double);
|
||||
}
|
||||
double c = (z - df * df) / (s + df);
|
||||
double w = _r(z) * s + c;
|
||||
return 2. * (df + w);
|
||||
}
|
||||
}
|
||||
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/e_acosf.c */
|
||||
/*
|
||||
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
|
||||
*/
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunPro, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
|
||||
const float PIO2_HI_F @local = 1.5707962513e+00; /* 0x3fc90fda */
|
||||
const float PIO2_LO_F @local = 7.5497894159e-08; /* 0x33a22168 */
|
||||
const float PS0_F @local = 1.6666586697e-01;
|
||||
const float PS1_F @local = -4.2743422091e-02;
|
||||
const float PS2_F @local = -8.6563630030e-03;
|
||||
const float QS1_F @local = -7.0662963390e-01;
|
||||
|
||||
fn float _r_f(float z) @local
|
||||
{
|
||||
float p = z * ( PS0_F + z * (PS1_F + z * PS2_F));
|
||||
float q = 1.0f + z * QS1_F;
|
||||
return p / q;
|
||||
}
|
||||
|
||||
fn float _acosf(float x) @weak @extern("acosf") @nostrip
|
||||
{
|
||||
uint hx = bitcast(x, uint);
|
||||
uint ix = hx & 0x7fffffff;
|
||||
switch
|
||||
{
|
||||
/* |x| >= 1 or nan */
|
||||
case ix >= 0x3f800000:
|
||||
if (ix == 0x3f800000)
|
||||
{
|
||||
if (hx >> 31) return 2.f * PIO2_HI_F + 0x1p-120f;
|
||||
return 0;
|
||||
}
|
||||
return float.nan;
|
||||
/* |x| < 0.5 */
|
||||
case ix < 0x3f000000:
|
||||
/* |x| < 2**-26 */
|
||||
if (ix <= 0x32800000) return PIO2_HI_F + 0x1p-120f;
|
||||
return PIO2_HI_F - (x - (PIO2_LO_F - x * _r_f(x * x)));
|
||||
/* x < -0.5 */
|
||||
case (hx >> 31) != 0:
|
||||
float z = (1.f + x) * 0.5f;
|
||||
float s = math::sqrt(z);
|
||||
float w = _r_f(z) * s - PIO2_LO_F;
|
||||
return 2.f * (PIO2_HI_F - (s + w));
|
||||
/* x > 0.5 */
|
||||
default:
|
||||
float z = (1.f - x) * 0.5f;
|
||||
float s = math::sqrt(z);
|
||||
float df @noinit;
|
||||
{
|
||||
uint rep = bitcast(s, uint);
|
||||
rep &= 0xfffff000;
|
||||
df = bitcast(rep, float);
|
||||
}
|
||||
float c = (z - df * df) / (s + df);
|
||||
float w = _r_f(z) * s + c;
|
||||
return 2.f * (df + w);
|
||||
}
|
||||
}
|
||||
136
lib/std/math/math_nolibc/asin.c3
Normal file
136
lib/std/math/math_nolibc/asin.c3
Normal file
@@ -0,0 +1,136 @@
|
||||
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
|
||||
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/e_asin.c */
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunSoft, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
|
||||
const PIO2_HI @local = 1.57079632679489655800e+00; /* 0x3FF921FB, 0x54442D18 */
|
||||
const PIO2_LO @local = 6.12323399573676603587e-17; /* 0x3C91A626, 0x33145C07 */
|
||||
const PS0 @local = 1.66666666666666657415e-01; /* 0x3FC55555, 0x55555555 */
|
||||
const PS1 @local = -3.25565818622400915405e-01; /* 0xBFD4D612, 0x03EB6F7D */
|
||||
const PS2 @local = 2.01212532134862925881e-01; /* 0x3FC9C155, 0x0E884455 */
|
||||
const PS3 @local = -4.00555345006794114027e-02; /* 0xBFA48228, 0xB5688F3B */
|
||||
const PS4 @local = 7.91534994289814532176e-04; /* 0x3F49EFE0, 0x7501B288 */
|
||||
const PS5 @local = 3.47933107596021167570e-05; /* 0x3F023DE1, 0x0DFDF709 */
|
||||
const QS1 @local = -2.40339491173441421878e+00; /* 0xC0033A27, 0x1C8A2D4B */
|
||||
const QS2 @local = 2.02094576023350569471e+00; /* 0x40002AE5, 0x9C598AC8 */
|
||||
const QS3 @local = -6.88283971605453293030e-01; /* 0xBFE6066C, 0x1B8D0159 */
|
||||
const QS4 @local = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */
|
||||
|
||||
fn double _r(double z) @local
|
||||
{
|
||||
double p = z * (PS0 + z * (PS1 + z * (PS2 + z * (PS3 + z * (PS4 + z * PS5)))));
|
||||
double q = 1.0 + z * (QS1 + z * (QS2 + z * (QS3 + z * QS4)));
|
||||
return p / q;
|
||||
}
|
||||
|
||||
fn double _asin(double x) @weak @extern("asin") @nostrip
|
||||
{
|
||||
uint hx = x.high_word();
|
||||
uint ix = hx & 0x7fffffff;
|
||||
switch
|
||||
{
|
||||
/* |x| >= 1 or nan */
|
||||
case ix >= 0x3ff00000:
|
||||
uint lx = x.low_word();
|
||||
if ((ix-0x3ff00000 | lx) == 0)
|
||||
{
|
||||
/* asin(1) = +-pi/2 with inexact */
|
||||
return x * PIO2_HI + 0x1p-120f;
|
||||
}
|
||||
return double.nan;
|
||||
/* |x| < 0.5 */
|
||||
case ix < 0x3fe00000:
|
||||
/* if 0x1p-1022 <= |x| < 0x1p-26, avoid raising underflow */
|
||||
if (ix < 0x3e500000 && ix >= 0x00100000) return x;
|
||||
return x + x * _r(x * x);
|
||||
/* 1 > |x| >= 0.5 */
|
||||
default:
|
||||
double z = (1. - math::abs(x)) * 0.5;
|
||||
double s = math::sqrt(z);
|
||||
double r = _r(z);
|
||||
/* if |x| > 0.975 */
|
||||
if (ix >= 0x3fef3333)
|
||||
{
|
||||
x = PIO2_HI - (2. * (s + s * r) - PIO2_LO);
|
||||
}
|
||||
else
|
||||
{
|
||||
double f @noinit;
|
||||
{
|
||||
ulong rep = bitcast(s, ulong);
|
||||
rep &= 0xffffffff00000000;
|
||||
f = bitcast(rep, double);
|
||||
}
|
||||
double c = (z - f * f) / (s + f);
|
||||
x = 0.5 * PIO2_HI - (2. * s * r - (PIO2_LO - 2. * c) - (0.5 * PIO2_HI - 2. * f));
|
||||
}
|
||||
if (hx >> 31 != 0) return -x;
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/e_asinf.c */
|
||||
/*
|
||||
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
|
||||
*/
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunPro, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
|
||||
const PIO2 @local = 1.570796326794896558e+00;
|
||||
const float PS0_F @local = 1.6666586697e-01;
|
||||
const float PS1_F @local = -4.2743422091e-02;
|
||||
const float PS2_F @local = -8.6563630030e-03;
|
||||
const float QS1_F @local = -7.0662963390e-01;
|
||||
|
||||
fn float _r_f(float z) @local
|
||||
{
|
||||
float p = z * ( PS0_F + z * (PS1_F + z * PS2_F));
|
||||
float q = 1.0f + z * QS1_F;
|
||||
return p / q;
|
||||
}
|
||||
|
||||
fn float _asinf(float x) @weak @extern("asinf") @nostrip
|
||||
{
|
||||
uint hx = bitcast(x, uint);
|
||||
uint ix = hx & 0x7fffffff;
|
||||
switch
|
||||
{
|
||||
/* |x| >= 1 */
|
||||
case ix >= 0x3f800000:
|
||||
if (ix == 0x3f800000)
|
||||
{
|
||||
/* asin(+-1) = +-pi/2 with inexact */
|
||||
return x * (float)PIO2 + 0x1p-120f;
|
||||
}
|
||||
return float.nan;
|
||||
/* |x| < 0.5 */
|
||||
case ix < 0x3f000000:
|
||||
/* if 0x1p-126 <= |x| < 0x1p-12, avoid raising underflow */
|
||||
if (ix < 0x39800000 && ix >= 0x00800000) return x;
|
||||
return x + x * _r_f(x * x);
|
||||
/* 1 > |x| >= 0.5 */
|
||||
default:
|
||||
float z = (1.f - math::abs(x)) * 0.5f;
|
||||
float s = math::sqrt(z);
|
||||
x = (float)PIO2 - 2.f * (s + s * _r_f(z));
|
||||
if (hx >> 31) return -x;
|
||||
return x;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,16 @@
|
||||
module std::math::nolibc @if(env::NO_LIBC);
|
||||
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
|
||||
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/s_atan.c */
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunPro, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
|
||||
const double[*] ATANHI @private = {
|
||||
4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */
|
||||
@@ -89,6 +101,21 @@ fn double _atan(double x) @weak @extern("atan") @nostrip
|
||||
return sign ? -z : z;
|
||||
}
|
||||
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/s_atanf.c */
|
||||
/*
|
||||
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
|
||||
*/
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunPro, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
|
||||
const float[*] ATANHIF @private = {
|
||||
4.6364760399e-01, /* atan(0.5)hi 0x3eed6338 */
|
||||
7.8539812565e-01, /* atan(1.0)hi 0x3f490fda */
|
||||
@@ -170,11 +197,24 @@ fn float _atanf(float x) @weak @extern("atanf") @nostrip
|
||||
/* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */
|
||||
float s1 = z * (ATF[0] + w * (ATF[2] + w * ATF[4]));
|
||||
float s2 = w * (ATF[1] + w * ATF[3]);
|
||||
if (id < 0) return x - x * (s1 + s2) * 10000;
|
||||
if (id < 0) return x - x * (s1 + s2);
|
||||
z = ATANHIF[id] - ((x * (s1 + s2) - ATANLOF[id]) - x);
|
||||
return sign ? -z : z;
|
||||
}
|
||||
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2.c */
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunSoft, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*
|
||||
*/
|
||||
|
||||
const PI_LO @private = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */
|
||||
|
||||
macro void extract_words(double d, uint* hi, uint* lo) @private
|
||||
@@ -252,6 +292,21 @@ fn double _atan2(double y, double x) @weak @extern("atan2") @nostrip
|
||||
}
|
||||
}
|
||||
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2f.c */
|
||||
/*
|
||||
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
|
||||
*/
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunPro, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
|
||||
const float PI_F @private = 3.1415927410e+00; /* 0x40490fdb */
|
||||
const float PI_LO_F @private = -8.7422776573e-08; /* 0xb3bbbd2e */
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::math::nolibc @if(env::NO_LIBC);
|
||||
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
|
||||
|
||||
fn double _ceil(double x) @weak @extern("ceil") @nostrip
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::math::nolibc @if(env::NO_LIBC);
|
||||
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
|
||||
|
||||
fn float _cosf(float x) @extern("cosf") @weak @nostrip
|
||||
{
|
||||
@@ -51,7 +51,7 @@ fn float _cosf(float x) @extern("cosf") @weak @nostrip
|
||||
* ====================================================
|
||||
*/
|
||||
|
||||
fn double _cos(double x) @weak @nostrip
|
||||
fn double _cos(double x) @extern("cos") @weak @nostrip
|
||||
{
|
||||
// High word of x.
|
||||
uint ix = (uint)(bitcast(x, ulong) >> 32);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::math::nolibc @if(env::NO_LIBC);
|
||||
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
|
||||
|
||||
macro uint _top12f(float x) @private => bitcast(x, uint) >> 20;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::math::nolibc @if(env::NO_LIBC);
|
||||
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
|
||||
|
||||
fn double _floor(double x) @weak @extern("floor") @nostrip
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::math::nolibc;
|
||||
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
|
||||
|
||||
const double TOINT = 1 / math::DOUBLE_EPSILON;
|
||||
const double TOINT15 = 1.5 / math::DOUBLE_EPSILON;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::math::nolibc @if(env::NO_LIBC);
|
||||
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
|
||||
|
||||
fn float powf_broken(float x, float f) @extern("powf") @weak @nostrip
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::math::nolibc @if(env::NO_LIBC);
|
||||
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
|
||||
import std::math;
|
||||
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2f.c */
|
||||
@@ -23,11 +23,11 @@ import std::math;
|
||||
* use __rem_pio2_large() for large x
|
||||
*/
|
||||
|
||||
<*
|
||||
/*
|
||||
* invpio2: 53 bits of 2/pi
|
||||
* pio2_1: first 25 bits of pi/2
|
||||
* pio2_1t: pi/2 - pio2_1
|
||||
*>
|
||||
*/
|
||||
fn int __rem_pio2f(float x, double *y)
|
||||
{
|
||||
const double PIO4 = 0x1.921fb6p-1;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::math::nolibc @if(env::NO_LIBC);
|
||||
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
|
||||
|
||||
fn double _round(double x) @extern("round") @weak @nostrip
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::math::nolibc @if(env::NO_LIBC);
|
||||
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
|
||||
|
||||
fn double _scalbn(double x, int n) @weak @extern("scalbn") @nostrip
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::math::nolibc @if(env::NO_LIBC);
|
||||
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
|
||||
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */
|
||||
/*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::math::nolibc @if(env::NO_LIBC);
|
||||
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
|
||||
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */
|
||||
/*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::math::nolibc @if(env::NO_LIBC);
|
||||
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
|
||||
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/s_tan.c */
|
||||
/*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::math::nolibc @if(env::NO_LIBC);
|
||||
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
|
||||
|
||||
fn double sincos_broken(double x) @extern("sincos") @weak @nostrip
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::math::nolibc @if(env::NO_LIBC);
|
||||
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
|
||||
|
||||
fn double _trunc(double x) @weak @extern("trunc") @nostrip
|
||||
{
|
||||
|
||||
@@ -13,6 +13,21 @@ macro quicksort(list, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLOT) @built
|
||||
qs::qsort(<$typeof(list), $typeof(cmp), $typeof(context)>)(list, 0, (isz)len - 1, cmp, context);
|
||||
}
|
||||
|
||||
<*
|
||||
Select the (k+1)th smallest element in an unordered list using Hoare's
|
||||
selection algorithm (Quickselect). k should be between 0 and len-1. The data
|
||||
list will be partially sorted.
|
||||
|
||||
@require @is_sortable(list) "The list must be indexable and support .len or .len()"
|
||||
@require @is_valid_cmp_fn(cmp, list, context) "expected a comparison function which compares values"
|
||||
@require @is_valid_context(cmp, context) "Expected a valid context"
|
||||
*>
|
||||
macro quickselect(list, isz k, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLOT) @builtin
|
||||
{
|
||||
usz len = sort::@len_from_list(list);
|
||||
return qs::qselect(<$typeof(list), $typeof(cmp), $typeof(context)>)(list, 0, (isz)len - 1, k, cmp, context);
|
||||
}
|
||||
|
||||
module std::sort::qs(<Type, CmpFn, Context>);
|
||||
|
||||
def ElementType = $typeof(Type{}[0]);
|
||||
@@ -29,10 +44,6 @@ def Stack = StackElementItem[64] @private;
|
||||
|
||||
fn void qsort(Type list, isz low, isz high, CmpFn cmp, Context context)
|
||||
{
|
||||
var $has_cmp = @is_valid_macro_slot(cmp);
|
||||
var $has_context = @is_valid_macro_slot(context);
|
||||
var $cmp_by_value = $has_cmp &&& $assignable(list[0], $typefrom(CmpFn.paramsof[0].type));
|
||||
|
||||
if (low >= 0 && high >= 0 && low < high)
|
||||
{
|
||||
Stack stack;
|
||||
@@ -48,34 +59,7 @@ fn void qsort(Type list, isz low, isz high, CmpFn cmp, Context context)
|
||||
|
||||
if (l < h)
|
||||
{
|
||||
ElementType pivot = list[l];
|
||||
while (l < h)
|
||||
{
|
||||
$switch
|
||||
$case $cmp_by_value && $has_context:
|
||||
while (cmp(list[h], pivot, context) >= 0 && l < h) h--;
|
||||
if (l < h) list[l++] = list[h];
|
||||
while (cmp(list[l], pivot, context) <= 0 && l < h) l++;
|
||||
$case $cmp_by_value:
|
||||
while (cmp(list[h], pivot) >= 0 && l < h) h--;
|
||||
if (l < h) list[l++] = list[h];
|
||||
while (cmp(list[l], pivot) <= 0 && l < h) l++;
|
||||
$case $has_cmp && $has_context:
|
||||
while (cmp(&list[h], &pivot, context) >= 0 && l < h) h--;
|
||||
if (l < h) list[l++] = list[h];
|
||||
while (cmp(&list[l], &pivot, context) <= 0 && l < h) l++;
|
||||
$case $has_cmp:
|
||||
while (cmp(&list[h], &pivot) >= 0 && l < h) h--;
|
||||
if (l < h) list[l++] = list[h];
|
||||
while (cmp(&list[l], &pivot) <= 0 && l < h) l++;
|
||||
$default:
|
||||
while (greater_eq(list[h], pivot) && l < h) h--;
|
||||
if (l < h) list[l++] = list[h];
|
||||
while (less_eq(list[l], pivot) && l < h) l++;
|
||||
$endswitch
|
||||
if (l < h) list[h--] = list[l];
|
||||
}
|
||||
list[l] = pivot;
|
||||
l = @partition(list, l, h, cmp, context);
|
||||
stack[i + 1].low = l + 1;
|
||||
stack[i + 1].high = stack[i].high;
|
||||
stack[i++].high = l;
|
||||
@@ -91,3 +75,71 @@ fn void qsort(Type list, isz low, isz high, CmpFn cmp, Context context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
<*
|
||||
@require low <= k "kth smalles element is smaller than lower bounds"
|
||||
@require k <= high "kth smalles element is larger than upper bounds"
|
||||
*>
|
||||
fn ElementType! qselect(Type list, isz low, isz high, isz k, CmpFn cmp, Context context)
|
||||
{
|
||||
if (low >= 0 && high >= 0 && low < high)
|
||||
{
|
||||
isz l = low;
|
||||
isz h = high;
|
||||
isz pivot;
|
||||
|
||||
usz max_retries = 64;
|
||||
while (l <= h && max_retries--)
|
||||
{
|
||||
pivot = @partition(list, l, h, cmp, context);
|
||||
if (k == pivot) return list[k];
|
||||
if (k < pivot)
|
||||
{
|
||||
h = pivot - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
l = pivot + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return SearchResult.MISSING?;
|
||||
}
|
||||
|
||||
macro @partition(Type list, isz l, isz h, CmpFn cmp, Context context)
|
||||
{
|
||||
var $has_cmp = @is_valid_macro_slot(cmp);
|
||||
var $has_context = @is_valid_macro_slot(context);
|
||||
var $cmp_by_value = $has_cmp &&& $assignable(list[0], $typefrom(CmpFn.paramsof[0].type));
|
||||
|
||||
ElementType pivot = list[l];
|
||||
while (l < h)
|
||||
{
|
||||
$switch
|
||||
$case $cmp_by_value && $has_context:
|
||||
while (cmp(list[h], pivot, context) >= 0 && l < h) h--;
|
||||
if (l < h) list[l++] = list[h];
|
||||
while (cmp(list[l], pivot, context) <= 0 && l < h) l++;
|
||||
$case $cmp_by_value:
|
||||
while (cmp(list[h], pivot) >= 0 && l < h) h--;
|
||||
if (l < h) list[l++] = list[h];
|
||||
while (cmp(list[l], pivot) <= 0 && l < h) l++;
|
||||
$case $has_cmp && $has_context:
|
||||
while (cmp(&list[h], &pivot, context) >= 0 && l < h) h--;
|
||||
if (l < h) list[l++] = list[h];
|
||||
while (cmp(&list[l], &pivot, context) <= 0 && l < h) l++;
|
||||
$case $has_cmp:
|
||||
while (cmp(&list[h], &pivot) >= 0 && l < h) h--;
|
||||
if (l < h) list[l++] = list[h];
|
||||
while (cmp(&list[l], &pivot) <= 0 && l < h) l++;
|
||||
$default:
|
||||
while (greater_eq(list[h], pivot) && l < h) h--;
|
||||
if (l < h) list[l++] = list[h];
|
||||
while (less_eq(list[l], pivot) && l < h) l++;
|
||||
$endswitch
|
||||
if (l < h) list[h--] = list[l];
|
||||
}
|
||||
list[l] = pivot;
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
59
lib/std/sort/sorted.c3
Normal file
59
lib/std/sort/sorted.c3
Normal file
@@ -0,0 +1,59 @@
|
||||
module std::sort;
|
||||
|
||||
<*
|
||||
Returns true if list is sorted in either ascending or descending order.
|
||||
@require @is_sortable(list) "The list must be indexable and support .len or .len()"
|
||||
@require @is_valid_cmp_fn(cmp, list, ctx) "Expected a comparison function which compares values"
|
||||
@require @is_valid_context(cmp, ctx) "Expected a valid context"
|
||||
*>
|
||||
macro bool is_sorted(list, cmp = EMPTY_MACRO_SLOT, ctx = EMPTY_MACRO_SLOT) @builtin
|
||||
{
|
||||
var $Type = $typeof(list);
|
||||
usz len = sort::@len_from_list(list);
|
||||
if (len <= 1) return true;
|
||||
var check_sort = fn bool($Type list, usz start, usz end, $typeof(cmp) cmp, $typeof(ctx) ctx)
|
||||
{
|
||||
usz i;
|
||||
int sort_order;
|
||||
|
||||
// determine sort order (ascending or descending)
|
||||
for (i = start; i < end && sort_order == 0; i++)
|
||||
{
|
||||
sort_order = @sort_cmp(list, i, cmp, ctx);
|
||||
}
|
||||
|
||||
// no sort order found, all elements are the same, consider list sorted
|
||||
if (sort_order == 0) return true;
|
||||
|
||||
// compare adjacent elements to the sort order
|
||||
for (; i < end; i++)
|
||||
{
|
||||
if (sort_order * @sort_cmp(list, i, cmp, ctx) < 0) return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
return check_sort(list, 0, len - 1, cmp, ctx);
|
||||
}
|
||||
|
||||
macro int @sort_cmp(list, pos, cmp, ctx) @local
|
||||
{
|
||||
var $has_cmp = @is_valid_macro_slot(cmp);
|
||||
var $has_context = @is_valid_macro_slot(ctx);
|
||||
var $cmp_by_value = $has_cmp &&& $assignable(list[0], $typefrom($typeof(cmp).paramsof[0].type));
|
||||
|
||||
var a = list[pos];
|
||||
var b = list[pos+1];
|
||||
|
||||
$switch
|
||||
$case $cmp_by_value && $has_context:
|
||||
return cmp(a, b);
|
||||
$case $cmp_by_value:
|
||||
return cmp(a, b);
|
||||
$case $has_cmp && $has_context:
|
||||
return cmp(&a, &b, ctx);
|
||||
$case $has_cmp:
|
||||
return cmp(&a, &b);
|
||||
$default:
|
||||
return compare_to(a,b);
|
||||
$endswitch
|
||||
}
|
||||
@@ -44,9 +44,9 @@ fn TzDateTime DateTime.to_local(&self)
|
||||
dt.min = (char)tm.tm_min;
|
||||
dt.hour = (char)tm.tm_hour;
|
||||
dt.day = (char)tm.tm_mday;
|
||||
dt.month = (Month)tm.tm_mon;
|
||||
dt.month = Month.from_ordinal(tm.tm_mon);
|
||||
dt.year = tm.tm_year + 1900;
|
||||
dt.weekday = !tm.tm_wday ? Weekday.SUNDAY : (Weekday)tm.tm_wday + 1;
|
||||
dt.weekday = !tm.tm_wday ? Weekday.SUNDAY : Weekday.from_ordinal(tm.tm_wday - 1);
|
||||
dt.year_day = (ushort)tm.tm_yday;
|
||||
dt.time = self.time;
|
||||
$if $defined(tm.tm_gmtoff):
|
||||
@@ -142,9 +142,9 @@ fn void DateTime.set_time(&self, Time time)
|
||||
self.min = (char)tm.tm_min;
|
||||
self.hour = (char)tm.tm_hour;
|
||||
self.day = (char)tm.tm_mday;
|
||||
self.month = (Month)tm.tm_mon;
|
||||
self.month = Month.from_ordinal(tm.tm_mon);
|
||||
self.year = tm.tm_year + 1900;
|
||||
self.weekday = !tm.tm_wday ? Weekday.SUNDAY : (Weekday)tm.tm_wday + 1;
|
||||
self.weekday = !tm.tm_wday ? Weekday.SUNDAY : Weekday.from_ordinal(tm.tm_wday - 1);
|
||||
self.year_day = (ushort)tm.tm_yday;
|
||||
self.time = time;
|
||||
}
|
||||
@@ -183,7 +183,7 @@ fn DateTime DateTime.add_months(&self, int months)
|
||||
year += month / 12;
|
||||
month %= 12;
|
||||
}
|
||||
return from_date(year, (Month)month, self.day, self.hour, self.min, self.sec, self.usec);
|
||||
return from_date(year, Month.from_ordinal(month), self.day, self.hour, self.min, self.sec, self.usec);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -234,10 +234,19 @@ lib = list((OUTPUT / "VC/Tools/MSVC/").glob("*/lib"))[0]
|
||||
|
||||
SDK_OUTPUT.mkdir(exist_ok=True)
|
||||
|
||||
def copy(src, dst):
|
||||
low = dst.lower()
|
||||
base = os.path.basename(low)
|
||||
if base == "msvcrt.lib" or base == "oldnames.lib":
|
||||
base = base[:-3].upper() + "lib"
|
||||
path = os.path.join(os.path.dirname(low), base);
|
||||
shutil.copy(src, path)
|
||||
shutil.copy(src, low)
|
||||
|
||||
for arch in archs:
|
||||
out_dir = SDK_OUTPUT / arch
|
||||
shutil.copytree(ucrt / arch, out_dir, dirs_exist_ok=True)
|
||||
shutil.copytree(um / arch, out_dir, dirs_exist_ok=True)
|
||||
shutil.copytree(lib / arch, out_dir, dirs_exist_ok=True)
|
||||
shutil.copytree(ucrt / arch, out_dir, copy_function=copy, dirs_exist_ok=True)
|
||||
shutil.copytree(um / arch, out_dir, copy_function=copy, dirs_exist_ok=True)
|
||||
shutil.copytree(lib / arch, out_dir, copy_function=copy, dirs_exist_ok=True)
|
||||
|
||||
print("Congratulations! The 'msvc_sdk' directory was successfully generated.")
|
||||
|
||||
85
nix/default.nix
Normal file
85
nix/default.nix
Normal file
@@ -0,0 +1,85 @@
|
||||
{
|
||||
lib,
|
||||
llvmPackages,
|
||||
cmake,
|
||||
python3,
|
||||
curl,
|
||||
libxml2,
|
||||
libffi,
|
||||
xar,
|
||||
debug ? false,
|
||||
checks ? false,
|
||||
}: let
|
||||
inherit (builtins) baseNameOf toString readFile elemAt;
|
||||
inherit (lib.sources) cleanSourceWith cleanSource;
|
||||
inherit (lib.lists) findFirst;
|
||||
inherit (lib.asserts) assertMsg;
|
||||
inherit (lib.strings) hasInfix hasSuffix splitString removeSuffix removePrefix optionalString;
|
||||
in
|
||||
llvmPackages.stdenv.mkDerivation (finalAttrs: {
|
||||
pname = "c3c${optionalString debug "-debug"}";
|
||||
version = let
|
||||
findLine = findFirst (x: hasInfix "COMPILER_VERSION" x) "none";
|
||||
foundLine = findLine ( splitString "\n" ( readFile ../src/version.h ) );
|
||||
version = removeSuffix "\"" ( removePrefix "\"" ( elemAt ( splitString " " foundLine ) 2 ) );
|
||||
in
|
||||
assert assertMsg (foundLine != "none") "No COMPILER_VERSION substring was found in version.h";
|
||||
version;
|
||||
|
||||
src = cleanSourceWith {
|
||||
filter = _path: _type: !(hasSuffix ".nix" (baseNameOf(toString _path)));
|
||||
src = cleanSource ../.;
|
||||
};
|
||||
|
||||
postPatch = ''
|
||||
substituteInPlace CMakeLists.txt \
|
||||
--replace-fail "\''${LLVM_LIBRARY_DIRS}" "${llvmPackages.lld.lib}/lib ${llvmPackages.llvm.lib}/lib"
|
||||
'';
|
||||
|
||||
cmakeBuildType = if debug then "Debug" else "Release";
|
||||
|
||||
cmakeFlags = [
|
||||
"-DC3_ENABLE_CLANGD_LSP=${if debug then "ON" else "OFF"}"
|
||||
];
|
||||
|
||||
nativeBuildInputs = [ cmake ];
|
||||
|
||||
postBuild = optionalString debug ''
|
||||
mkdir $out
|
||||
substituteInPlace compile_commands.json \
|
||||
--replace "/build/source/" "$src/"
|
||||
cp compile_commands.json $out/compile_commands.json
|
||||
'';
|
||||
|
||||
buildInputs = [
|
||||
llvmPackages.llvm
|
||||
llvmPackages.lld
|
||||
curl
|
||||
libxml2
|
||||
libffi
|
||||
] ++ lib.optionals llvmPackages.stdenv.hostPlatform.isDarwin [ xar ];
|
||||
|
||||
nativeCheckInputs = [ python3 ];
|
||||
|
||||
doCheck = llvmPackages.stdenv.system == "x86_64-linux" && checks;
|
||||
|
||||
checkPhase = ''
|
||||
runHook preCheck
|
||||
( cd ../resources/testproject; ../../build/c3c build )
|
||||
( cd ../test; python src/tester.py ../build/c3c test_suite )
|
||||
runHook postCheck
|
||||
'';
|
||||
|
||||
meta = with lib; {
|
||||
description = "Compiler for the C3 language";
|
||||
homepage = "https://github.com/c3lang/c3c";
|
||||
license = licenses.lgpl3Only;
|
||||
maintainers = with maintainers; [
|
||||
luc65r
|
||||
anas
|
||||
];
|
||||
platforms = platforms.all;
|
||||
mainProgram = "c3c";
|
||||
};
|
||||
})
|
||||
|
||||
20
nix/shell.nix
Normal file
20
nix/shell.nix
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
mkShell,
|
||||
clang-tools,
|
||||
c3c,
|
||||
}:
|
||||
|
||||
mkShell {
|
||||
inputsFrom = [
|
||||
c3c
|
||||
];
|
||||
|
||||
packages = [
|
||||
clang-tools
|
||||
c3c
|
||||
];
|
||||
|
||||
shellHook = ''
|
||||
ln -sf ${c3c}/compile_commands.json compile_commands.json
|
||||
'';
|
||||
}
|
||||
@@ -1,5 +1,94 @@
|
||||
# C3C Release Notes
|
||||
|
||||
## 0.6.6 Change list
|
||||
|
||||
### Changes / improvements
|
||||
- Split help into normal and "full" help, #1703
|
||||
- Removed 'headers' command line option.
|
||||
- Add `enum.from_ordinal` and `fault.from_ordinal`
|
||||
- Deprecate cast-style conversion from integer <-> enum.
|
||||
- Make deprecation an error in test mode.
|
||||
- Add `--win-vs-dirs` to override VS detection dirs.
|
||||
- Add `"name"` project property to override the name of the resulting binary. #1719
|
||||
- Improved `add-project` to take arguments.
|
||||
|
||||
### Fixes
|
||||
- Fix case trying to initialize a `char[*]*` from a String.
|
||||
- Fix Map & HashMap `put_all_for_create` not copying all elements, causing `init_from_map` to create incomplete copy.
|
||||
- Fix bug when a macro calling an extern function was called in another module also declaring and calling the same function. #1690
|
||||
- `static-lib` and `dynamic-lib` options from the command line now produces headers.
|
||||
- Fix bug outputting exported functions without predefined extname.
|
||||
- Fix problem where crt1 was linked for dynamic libraries on Linux and BSD. #1710
|
||||
- Fix CRT detection on Arch Linux.
|
||||
- Fix lexer allowing a trailing underscore (_) with hex and binary literals.
|
||||
- Fix `--list-operators` CLI command printing underscore (_) and hash (#).
|
||||
- Fix bug in temp allocator when temp memory is exhausted and allocation needs overaligned mem. #1715
|
||||
- Incorrectly handles distinct enums and pointers with '+=' and '-=' #1717.
|
||||
- Prevent DString from being initialized with "".
|
||||
- Fix bug in OnStackAllocator when freeing overallocated data. #1720
|
||||
- Use `weak_odr` rather than `weak` on Windows which seems to prevent issues such as #1704.
|
||||
- Use `weak` on dyn-symbols on Linux.
|
||||
- Fix crash on project.json not having an empty set of targets.
|
||||
|
||||
### Stdlib changes
|
||||
- Increase BitWriter.write_bits limit up to 32 bits.
|
||||
- Updates to `Slice2d`, like `get_xy` and others.
|
||||
- Added `iter()` `value_iter()` and `key_iter()` to HashMap.
|
||||
- Add "tokenizer" to String.
|
||||
- Add "skip_empty" to split methods. Add split_to_buffer method.
|
||||
- Add `@enum_from_value`.
|
||||
|
||||
## 0.6.5 Change list
|
||||
|
||||
### Changes / improvements
|
||||
- Allow splat in initializers.
|
||||
- Init command will now add `test-sources` to `project.json` #1520
|
||||
- `a++` may be discarded if `a` is optional and ++/-- works for overloaded operators.
|
||||
- Improve support for Windows cross compilation on targets with case sensitive file systems.
|
||||
- Add "sources" support to library `manifest.json`, defaults to root folder if unspecified.
|
||||
- Add char_at method in DString and operators [], len, []= and &[].
|
||||
- Add `-q` option, make `--run-once` implicitly `-q`.
|
||||
- Add `-v`, `-vv` and `-vvv` options for increasing verbosity, replacing debug-log and debug-stats options.
|
||||
|
||||
### Fixes
|
||||
- Fix bug where `a > 0 ? f() : g()` could cause a compiler crash if both returned `void!`.
|
||||
- `@builtin` was not respected for generic modules #1617.
|
||||
- Fix issue writing a single byte in the WriteBuffer
|
||||
- A distinct inline pointer type can now participate in pointer arithmetics.
|
||||
- Support &a[0] returning the distinct type when applying it to a distinct of a pointer.
|
||||
- Fix error when calling `HashMap.remove` on uninitialized `HashMap`.
|
||||
- Fix issue with resolved try-unwrap in defer.
|
||||
- Fix issue with overloaded subscript and ++/-- and assign ops (e.g. `*=`)
|
||||
- Fix issue with properties in different targets not being respected #1633.
|
||||
- Indexing an Optional slice would crash in codegen #1636.
|
||||
- SimpleHeapAllocator bug when splitting blocks allowed memory overrun.
|
||||
- Not possible to alias or take reference for extension methods on non-user defined types. #1637
|
||||
- Prevent methods from using names of properties or fields. #1638
|
||||
- b64 / hex data strings can now be used with \` as well.
|
||||
- Contracts on generic modules would evaluate too late, sometimes not catching the error until it already occurred elsewhere.
|
||||
- Fix bug preventing optionals from being used in ranges or as indices.
|
||||
- Crash compiling for arm64 when returning 16 byte and smaller structs by value not a power of 2 #1649.
|
||||
- Enforce single module compilation for static libraries to make constructors run properly.
|
||||
- Crash when using --no-obj without compile-only. #1653
|
||||
- Do not produce expression locations for windows.
|
||||
- Issue where multiple methods were accepted for the same type.
|
||||
- Issue where a method was linked to a type alias instead of the underlying type.
|
||||
- Fix Fnv1a encoding.
|
||||
- Fix issue with accessing arrays in access-overloaded types, e.g. `list[1][2]` #1665.
|
||||
- Cast removing arbitrary array indices and converting them to pointers should always be fine #1664
|
||||
- Incorrect "no-libc" definition of `cos`, making it unavailable for wasm.
|
||||
- Fix issue with the adjoint and inverse calculations for `Matrix2x2`.
|
||||
- It was possible to create 0 length arrays using byte literals. #1678
|
||||
- Crash when a constant null typeid is checked for properties. #1679
|
||||
|
||||
### Stdlib changes
|
||||
- Add `io::MultiReader`, `io::MultiWriter`, and `io::TeeReader` structs.
|
||||
- Updated Base32 API.
|
||||
- Add `file::save`.
|
||||
- Add `memcpy` / `memset` / `memcmp` to nolibc.
|
||||
- Add `sort::quickselect` to find the k-th smallest element in an unordered list.
|
||||
- Add `sort::is_sorted` to determine if a list is sorted.
|
||||
|
||||
## 0.6.4 Change list
|
||||
|
||||
### Changes / improvements
|
||||
|
||||
@@ -1,31 +1,196 @@
|
||||
Some short names:
|
||||
1. expl - explicit
|
||||
2. sw/sn - simple widening + subexpression narrowing
|
||||
3. yes - always allowed
|
||||
4. explptr - explicit if pointer sized
|
||||
5. ptrconv - to/from void* is fine, other cast must be explicit
|
||||
6. saconv - explicit if same element size
|
||||
7. explbase - explicit to base disregaring sign
|
||||
8. distel - explicit to same element disregarding distinct
|
||||
9. inline - implicit if type subtype
|
||||
10. cond - implicit in cond, explicit otherwise
|
||||
11. edist - explicit to anything underlying type can convert to, if inline as underlying
|
||||
12. arve - if array or vec ptr
|
||||
## Special rules for distinct types
|
||||
|
||||
| from, to | bool | int | float | pointer | subarr | vec | bits | distc | array | struct | union | any | fault | enum | typeid |
|
||||
|----------|--------|----------|--------|---------|--------|----------|----------|-------|----------|--------|--------|--------|--------|--------|--------|
|
||||
| bool | n/a | expl | expl | no | no | expand | no | edist | no | no | no | no | no | no | no |
|
||||
| int | cond | sw/sn | always | explptr | no | expand | explbase | edist | no | no | no | no | no | edist | no |
|
||||
| float | cond | expl | sw/sn | no | no | expand | no | edist | no | no | no | no | no | no | no |
|
||||
| pointer | cond | explptr | no | ptrconv | arve | expand | no | edist | no | no | no | yes | expl | no | expl |
|
||||
| slice | cond | no | no | no | saconv | no | no | edist | no? | no | no | no | no | no | no |
|
||||
| vec | cond | no | no | no | no | as base | no | edist | expl | no | no | no | no | no | no |
|
||||
| bits | no | explbase | no | no | no | no | no? | edist | explbase | no | no | no | no | no | no |
|
||||
| distc | edist | edist | edist | edist | edist | edist | edist | edist | edist | edist | edist | edist | edist | edist | edist |
|
||||
| array | no | no | no | no | no | explbase | explbase | edist | distel | no | no | no | no | no | no |
|
||||
| struct | inline | inline | inline | inline | inline | inline | inline | edist | inline | inline | inline | inline | inline | inline | inline |
|
||||
| union | no | no | no | no | no | no | no | edist | no | no | no | no | no | no | no |
|
||||
| any | cond | no | no | expl | no | no | no | edist | no | no | no | n/a | no | no | no |
|
||||
| fault | cond | explptr | no | expl | no | no | no | edist | no | no | no | no | anyf | no | no |
|
||||
| enum | no | expl | no | no | no | expand | no | edist | no | no | no | no | no | no | no |
|
||||
| typeid | cond | no | no | expl | no | no | no | edist | no | no | no | no | no | no | n/a |
|
||||
1. Implicit conversion will happen from constant values that can be implicitly converted to the underlying type.
|
||||
2. Implicit conversion will happen to the underlying type if inline.
|
||||
|
||||
## Special rules for vectors
|
||||
|
||||
1. Implicit conversion will happen for non-vector numeric types, bools and pointers for init only.
|
||||
2. Explicit conversion is available in all other cases.
|
||||
|
||||
## Special rules for bool conversion in conditionals
|
||||
|
||||
Types that may convert to a bool, will implicitly do so in a conditional.
|
||||
|
||||
### Bool
|
||||
|
||||
#### Implicit conversion
|
||||
None
|
||||
|
||||
#### Explicit conversion
|
||||
|
||||
1. To float => 0.0 and 1.0
|
||||
2. To int => 0 and 1 (note, there is an argument for ~0 instead)
|
||||
|
||||
### Int
|
||||
|
||||
#### Implicit conversion
|
||||
|
||||
1. To float if simple expression
|
||||
2. To wider int if simple expression
|
||||
|
||||
#### Explicit conversion
|
||||
|
||||
1. To bool/float/int always works
|
||||
2. To pointer if the int is pointer sized
|
||||
3. To enum (const will be range checked)
|
||||
4. To bitstruct if size matches
|
||||
5. To bool
|
||||
|
||||
### Float
|
||||
|
||||
#### Implicit conversion
|
||||
|
||||
1. To wider float if simple expression
|
||||
|
||||
#### Explicit conversion
|
||||
|
||||
1. To int / float
|
||||
2. To bool
|
||||
|
||||
### Non "void\*" pointer
|
||||
|
||||
#### Implicit conversion
|
||||
|
||||
1. To void*
|
||||
2. To `any`
|
||||
3. To slice if it is a pointer to a vector or array
|
||||
4. To an interface if the pointee implements the interface.
|
||||
|
||||
#### Explicit conversion
|
||||
|
||||
1. To any pointer
|
||||
2. To any interface
|
||||
3. To an int size pointer
|
||||
4. To bool
|
||||
|
||||
### "void\*" pointer
|
||||
|
||||
#### Implicit conversion
|
||||
|
||||
1. To any pointer
|
||||
|
||||
#### Explicit conversion
|
||||
|
||||
1. To a pointer sized int.
|
||||
2. To bool
|
||||
|
||||
### Slice
|
||||
|
||||
#### Implicit conversion
|
||||
|
||||
1. To a pointer of the same base pointer. For constant strings the ichar and char are equivalent.
|
||||
2. To an array or vector of the same compile time known length if the array/vector conversion exists.
|
||||
|
||||
#### Explicit conversion
|
||||
|
||||
1. To a pointer of the same structure.
|
||||
2. To a slice of the same structure.
|
||||
3. To an array of the vector of the same compile time known length if the explicit array/vector conversion exists.
|
||||
|
||||
### Vector
|
||||
|
||||
#### Implicit conversion
|
||||
|
||||
1. To a slice of the same type *if* the vector is constant.
|
||||
2. To another vector if the base type conversion is implicit
|
||||
3. To an array if the conversion would work if this was an array -> array conversion.
|
||||
|
||||
#### Explicit conversion
|
||||
|
||||
1. To a slice of the same structural equivalent type *if* the vector is constant.
|
||||
2. To another vector if the base type conversion is valid.
|
||||
3. To an array if the conversion would work if this was an explicit array -> array conversion.
|
||||
|
||||
### Array
|
||||
|
||||
#### Implicit conversion
|
||||
|
||||
1. To a slice of the same type *if* the array is constant.
|
||||
2. To another array of the same length but with compatible types.
|
||||
3. To a vector if the conversion would work if this was an array -> array conversion.
|
||||
|
||||
#### Explicit conversion
|
||||
|
||||
1. To a slice of the same structural equivalent type *if* the array is constant.
|
||||
2. To another array of the same length with structurally equivalent elements.
|
||||
3. To a vector if the conversion would work if this was an explicit array -> array conversion.
|
||||
|
||||
### Bitstruct
|
||||
|
||||
#### Implicit conversion
|
||||
None
|
||||
|
||||
#### Explicit conversion
|
||||
|
||||
1. To the underlying type (integer or char array).
|
||||
2. To bool
|
||||
|
||||
### Struct
|
||||
|
||||
#### Implicit conversion
|
||||
|
||||
1. To inline member
|
||||
|
||||
#### Explicit conversion
|
||||
|
||||
None
|
||||
|
||||
### Union
|
||||
|
||||
No conversions
|
||||
|
||||
### "any"
|
||||
|
||||
#### Implicit conversion
|
||||
|
||||
1. To `void*`
|
||||
|
||||
#### Explicit conversion
|
||||
|
||||
1. To any interface
|
||||
2. To any pointer
|
||||
3. To bool
|
||||
|
||||
### Interface
|
||||
|
||||
#### Implicit conversion
|
||||
|
||||
1. To `void*`
|
||||
2. To `any`
|
||||
2. To a parent interface
|
||||
|
||||
#### Explicit conversion
|
||||
|
||||
1. To any other interface
|
||||
2. To any pointer
|
||||
3. To bool
|
||||
|
||||
### Fault
|
||||
|
||||
#### Implicit conversion
|
||||
|
||||
1. To `anyfault`
|
||||
|
||||
#### Explicit conversion
|
||||
|
||||
1. To a pointer sized int
|
||||
2. To bool
|
||||
3. To pointer
|
||||
|
||||
### "anyfault"
|
||||
|
||||
#### Explicit conversion
|
||||
|
||||
1. To a pointer sized int
|
||||
2. To bool
|
||||
3. To pointer
|
||||
4. To a `fault`
|
||||
|
||||
### "typeid"
|
||||
|
||||
#### Explicit conversion
|
||||
|
||||
1. To a pointer size int
|
||||
2. To bool
|
||||
3. To pointer
|
||||
@@ -124,12 +124,12 @@ fn void update_game()
|
||||
|
||||
if (rl::isKeyPressed(rl::KEY_RIGHT) && allow_move)
|
||||
{
|
||||
snake_direction = (SnakeDirection)((snake_direction.ordinal + 1) % 4);
|
||||
snake_direction = SnakeDirection.from_ordinal((snake_direction.ordinal + 1) % 4);
|
||||
allow_move = false;
|
||||
}
|
||||
if (rl::isKeyPressed(rl::KEY_LEFT) && allow_move)
|
||||
{
|
||||
snake_direction = (SnakeDirection)((snake_direction.ordinal + 3) % 4);
|
||||
snake_direction = SnakeDirection.from_ordinal((snake_direction.ordinal + 3) % 4);
|
||||
allow_move = false;
|
||||
}
|
||||
|
||||
|
||||
19
resources/examples/staticlib-test/add.c3
Normal file
19
resources/examples/staticlib-test/add.c3
Normal file
@@ -0,0 +1,19 @@
|
||||
module add;
|
||||
import std;
|
||||
struct Foo(Printable)
|
||||
{
|
||||
int a;
|
||||
}
|
||||
|
||||
fn usz! Foo.to_format(&self, Formatter* f) @dynamic
|
||||
{
|
||||
return f.printf("Foo[%d]", self.a);
|
||||
}
|
||||
|
||||
fn int add(int a, int b) @export("adder")
|
||||
{
|
||||
io::printn("In adder");
|
||||
Foo x = { a };
|
||||
io::printfn("Print foo: %s", x);
|
||||
return a + b;
|
||||
}
|
||||
8
resources/examples/staticlib-test/test.c
Normal file
8
resources/examples/staticlib-test/test.c
Normal file
@@ -0,0 +1,8 @@
|
||||
#include <stdio.h>
|
||||
extern int adder(int a, int b);
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("%d\n", adder(1, 4));
|
||||
return 0;
|
||||
}
|
||||
9
resources/examples/staticlib-test/test.c3
Normal file
9
resources/examples/staticlib-test/test.c3
Normal file
@@ -0,0 +1,9 @@
|
||||
module add;
|
||||
import std;
|
||||
extern fn int adder(int a, int b);
|
||||
|
||||
fn int main()
|
||||
{
|
||||
io::printn(adder(1, 4));
|
||||
return 0;
|
||||
}
|
||||
@@ -17,8 +17,9 @@
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BACKEND_LLVM = 1,
|
||||
BACKEND_TB = 2
|
||||
BACKEND_LLVM = 0,
|
||||
BACKEND_TB = 1,
|
||||
BACKEND_C = 2,
|
||||
} CompilerBackend;
|
||||
|
||||
typedef enum
|
||||
@@ -28,7 +29,6 @@ typedef enum
|
||||
COMMAND_COMPILE_ONLY,
|
||||
COMMAND_COMPILE_BENCHMARK,
|
||||
COMMAND_COMPILE_TEST,
|
||||
COMMAND_GENERATE_HEADERS,
|
||||
COMMAND_INIT,
|
||||
COMMAND_INIT_LIB,
|
||||
COMMAND_BUILD,
|
||||
@@ -416,6 +416,7 @@ typedef struct BuildOptions_
|
||||
{
|
||||
const char *sdk;
|
||||
const char *def;
|
||||
const char *vs_dirs;
|
||||
WinCrtLinking crt_linking;
|
||||
} win;
|
||||
struct
|
||||
@@ -453,6 +454,7 @@ typedef struct BuildOptions_
|
||||
ProjectSubcommand command;
|
||||
const char *target_name;
|
||||
TargetType target_type;
|
||||
const char **sources;
|
||||
} project_options;
|
||||
CompileOption compile_option;
|
||||
TrustLevel trust_level;
|
||||
@@ -479,6 +481,7 @@ typedef struct BuildOptions_
|
||||
bool print_output;
|
||||
bool print_input;
|
||||
bool run_once;
|
||||
int verbosity_level;
|
||||
const char *panicfn;
|
||||
const char *benchfn;
|
||||
const char *testfn;
|
||||
@@ -523,6 +526,7 @@ typedef struct
|
||||
const char *cc;
|
||||
const char *cflags;
|
||||
WinCrtLinking win_crt;
|
||||
const char **source_dirs;
|
||||
const char **csource_dirs;
|
||||
const char **csources;
|
||||
const char **cinclude_dirs;
|
||||
@@ -540,6 +544,7 @@ typedef struct Library__
|
||||
const char **execs;
|
||||
const char *cc;
|
||||
const char *cflags;
|
||||
const char **source_dirs;
|
||||
const char **csource_dirs;
|
||||
const char **cinclude_dirs;
|
||||
WinCrtLinking win_crt;
|
||||
@@ -553,6 +558,7 @@ typedef struct
|
||||
Library **library_list;
|
||||
LibraryTarget **ccompiling_libraries;
|
||||
const char *name;
|
||||
const char *output_name;
|
||||
const char *version;
|
||||
const char *langrev;
|
||||
const char **source_dirs;
|
||||
@@ -587,6 +593,7 @@ typedef struct
|
||||
bool emit_object_files;
|
||||
bool benchmarking;
|
||||
bool testing;
|
||||
bool silent;
|
||||
bool read_stdin;
|
||||
bool print_output;
|
||||
bool print_input;
|
||||
@@ -594,6 +601,7 @@ typedef struct
|
||||
bool no_entry;
|
||||
bool kernel_build;
|
||||
bool silence_deprecation;
|
||||
bool print_stats;
|
||||
int build_threads;
|
||||
TrustLevel trust_level;
|
||||
OptimizationSetting optsetting;
|
||||
@@ -657,6 +665,7 @@ typedef struct
|
||||
{
|
||||
const char *sdk;
|
||||
const char *def;
|
||||
const char *vs_dirs;
|
||||
WinCrtLinking crt_linking;
|
||||
bool use_win_subsystem;
|
||||
} win;
|
||||
|
||||
@@ -88,6 +88,12 @@ static const char *optlevels[4] = {
|
||||
[OPTIMIZATION_AGGRESSIVE] = "max",
|
||||
};
|
||||
|
||||
static const char *backends[3] = {
|
||||
[BACKEND_LLVM] = "llvm",
|
||||
[BACKEND_TB] = "tb",
|
||||
[BACKEND_C] = "c",
|
||||
};
|
||||
|
||||
static const char *backtrace_levels[2] = {
|
||||
[SHOW_BACKTRACE_OFF] = "off",
|
||||
[SHOW_BACKTRACE_ON] = "on",
|
||||
|
||||
@@ -40,10 +40,10 @@ const char *trust_level[3];
|
||||
|
||||
#define EOUTPUT(string, ...) fprintf(stderr, string "\n", ##__VA_ARGS__) // NOLINT
|
||||
#define PRINTF(string, ...) fprintf(stdout, string "\n", ##__VA_ARGS__) // NOLINT
|
||||
#define FAIL_WITH_ERR(string, ...) do { fprintf(stderr, "Error: " string "\n\n", ##__VA_ARGS__); usage(); exit_compiler(EXIT_FAILURE); } while (0) /* NOLINT */
|
||||
#define FAIL_WITH_ERR(string, ...) do { fprintf(stderr, "Error: " string "\n\n", ##__VA_ARGS__); usage(false); exit_compiler(EXIT_FAILURE); } while (0) /* NOLINT */
|
||||
#define PROJECT_FAIL_WITH_ERR(string, ...) do { fprintf(stderr, "Error: " string "\n\n", ##__VA_ARGS__); project_usage(); exit_compiler(EXIT_FAILURE); } while (0) /* NOLINT */
|
||||
|
||||
static void usage(void)
|
||||
static void usage(bool full)
|
||||
{
|
||||
PRINTF("Usage: %s [<options>] <command> [<args>]", args[0]);
|
||||
PRINTF("");
|
||||
@@ -71,18 +71,11 @@ static void usage(void)
|
||||
PRINTF(" vendor-fetch <library> ... Fetches one or more libraries from the vendor collection.");
|
||||
PRINTF(" project <subcommand> ... Manipulate or view project files.");
|
||||
PRINTF("");
|
||||
PRINTF("Options:");
|
||||
PRINTF(" --stdlib <dir> - Use this directory as the C3 standard library path.");
|
||||
PRINTF(" --no-entry - Do not generate (or require) a main function.");
|
||||
PRINTF(" --libdir <dir> - Add this directory to the C3 library search paths.");
|
||||
PRINTF(" --lib <name> - Add this library to the compilation.");
|
||||
PRINTF(" --path <dir> - Use this as the base directory for the current command.");
|
||||
PRINTF(" --template <template> - Select template for 'init': \"exe\", \"static-lib\", \"dynamic-lib\" or a path.");
|
||||
PRINTF(" --about - Prints a short description of C3.");
|
||||
PRINTF(" --symtab <value> - Sets the preferred symtab size.");
|
||||
PRINTF(" --max-mem <value> - Sets the preferred max memory size.");
|
||||
PRINTF(" --run-once - After running the output file, delete it immediately.");
|
||||
PRINTF(full ? "Options:" : "Common options:");
|
||||
PRINTF(" -h -hh --help - Print the help, -h for the normal options, -hh for the full help.");
|
||||
PRINTF(" -V --version - Print version information.");
|
||||
PRINTF(" -q --quiet - Silence unnecessary output.");
|
||||
PRINTF(" -v -vv -vvv - Verbose output, -v for default, -vv and -vvv gives more information.");
|
||||
PRINTF(" -E - Lex only.");
|
||||
PRINTF(" -P - Only parse and output the AST as JSON.");
|
||||
PRINTF(" -C - Only lex, parse and check.");
|
||||
@@ -98,26 +91,40 @@ static void usage(void)
|
||||
PRINTF(" -Oz - Unsafe, high optimization, tiny code, single module, no debug info, no panic messages, no backtrace.");
|
||||
PRINTF(" -D <name> - Add feature flag <name>.");
|
||||
PRINTF(" -U <name> - Remove feature flag <name>.");
|
||||
PRINTF(" --trust=<option> - Trust level: none (default), include ($include allowed), full ($exec / exec allowed).");
|
||||
PRINTF(" --output-dir <dir> - Override general output directory.");
|
||||
PRINTF(" --build-dir <dir> - Override build output directory.");
|
||||
PRINTF(" --obj-out <dir> - Override object file output directory.");
|
||||
PRINTF(" --script-dir <dir> - Override the base directory for $exec.");
|
||||
PRINTF(" --llvm-out <dir> - Override llvm output directory for '--emit-llvm'.");
|
||||
PRINTF(" --emit-llvm - Emit LLVM IR as a .ll file per module.");
|
||||
PRINTF(" --asm-out <dir> - Override asm output directory for '--emit-asm'.");
|
||||
PRINTF(" --emit-asm - Emit asm as a .s file per module.");
|
||||
PRINTF(" --obj - Emit object files. (Enabled by default)");
|
||||
PRINTF(" --no-obj - Do not output object files, this is only valid for `compile-only`.");
|
||||
PRINTF(" --no-headers - Do not generate C headers when building a library.");
|
||||
PRINTF(" --target <target> - Compile for a particular architecture + OS target.");
|
||||
PRINTF(" --threads <number> - Set the number of threads to use for compilation.");
|
||||
PRINTF(" --safe=<yes|no> - Turn safety (contracts, runtime bounds checking, null pointer checks etc) on or off.");
|
||||
PRINTF(" --panic-msg=<yes|no> - Turn panic message output on or off.");
|
||||
PRINTF(" --optlevel=<option> - Code optimization level: none, less, more, max.");
|
||||
PRINTF(" --optsize=<option> - Code size optimization: none, small, tiny.");
|
||||
PRINTF(" --single-module=<yes|no> - Compile all modules together, enables more inlining.");
|
||||
PRINTF(" --show-backtrace=<yes|no> - Show detailed backtrace on segfaults.");
|
||||
PRINTF("");
|
||||
PRINTF(" --about - Prints a short description of C3.");
|
||||
PRINTF(" --libdir <dir> - Add this directory to the c3l library search paths.");
|
||||
PRINTF(" --lib <name> - Add this c3l library to the compilation.");
|
||||
if (full)
|
||||
{
|
||||
PRINTF(" --stdlib <dir> - Use this directory as the C3 standard library path.");
|
||||
PRINTF(" --no-entry - Do not generate (or require) a main function.");
|
||||
PRINTF(" --path <dir> - Use this as the base directory for the current command.");
|
||||
PRINTF(" --template <template> - Select template for 'init': \"exe\", \"static-lib\", \"dynamic-lib\" or a path.");
|
||||
PRINTF(" --symtab <value> - Sets the preferred symtab size.");
|
||||
PRINTF(" --max-mem <value> - Sets the preferred max memory size.");
|
||||
PRINTF(" --run-once - After running the output file, delete it immediately.");
|
||||
PRINTF(" --trust=<option> - Trust level: none (default), include ($include allowed), full ($exec / exec allowed).");
|
||||
PRINTF(" --output-dir <dir> - Override general output directory.");
|
||||
PRINTF(" --build-dir <dir> - Override build output directory.");
|
||||
PRINTF(" --obj-out <dir> - Override object file output directory.");
|
||||
PRINTF(" --script-dir <dir> - Override the base directory for $exec.");
|
||||
PRINTF(" --llvm-out <dir> - Override llvm output directory for '--emit-llvm'.");
|
||||
PRINTF(" --emit-llvm - Emit LLVM IR as a .ll file per module.");
|
||||
PRINTF(" --asm-out <dir> - Override asm output directory for '--emit-asm'.");
|
||||
PRINTF(" --emit-asm - Emit asm as a .s file per module.");
|
||||
PRINTF(" --obj - Emit object files. (Enabled by default)");
|
||||
PRINTF(" --no-obj - Do not output object files, this is only valid for `compile-only`.");
|
||||
PRINTF(" --no-headers - Do not generate C headers when building a library.");
|
||||
PRINTF(" --target <target> - Compile for a particular architecture + OS target.");
|
||||
PRINTF(" --threads <number> - Set the number of threads to use for compilation.");
|
||||
PRINTF(" --safe=<yes|no> - Turn safety (contracts, runtime bounds checking, null pointer checks etc) on or off.");
|
||||
PRINTF(" --panic-msg=<yes|no> - Turn panic message output on or off.");
|
||||
PRINTF(" --optlevel=<option> - Code optimization level: none, less, more, max.");
|
||||
PRINTF(" --optsize=<option> - Code size optimization: none, small, tiny.");
|
||||
PRINTF(" --single-module=<yes|no> - Compile all modules together, enables more inlining.");
|
||||
PRINTF(" --show-backtrace=<yes|no> - Show detailed backtrace on segfaults.");
|
||||
}
|
||||
PRINTF("");
|
||||
PRINTF(" -g - Emit debug info.");
|
||||
PRINTF(" -g0 - Emit no debug info.");
|
||||
@@ -125,60 +132,65 @@ static void usage(void)
|
||||
PRINTF(" -l <library> - Link with the library provided.");
|
||||
PRINTF(" -L <library dir> - Append the directory to the linker search paths.");
|
||||
PRINTF(" -z <argument> - Send the <argument> as a parameter to the linker.");
|
||||
PRINTF(" --cc <path> - Set C compiler (for C files in projects and use as system linker).");
|
||||
PRINTF(" --linker=<option> [<path>] - Linker: builtin, cc, custom (default is 'cc'), 'custom' requires a path.");
|
||||
PRINTF("");
|
||||
PRINTF(" --use-stdlib=<yes|no> - Include the standard library (default: yes).");
|
||||
PRINTF(" --link-libc=<yes|no> - Link libc other default libraries (default: yes).");
|
||||
PRINTF(" --emit-stdlib=<yes|no> - Output files for the standard library. (default: yes)");
|
||||
PRINTF(" --panicfn <name> - Override the panic function name.");
|
||||
PRINTF(" --testfn <name> - Override the test runner function name.");
|
||||
PRINTF(" --benchfn <name> - Override the benchmark runner function name.");
|
||||
PRINTF("");
|
||||
PRINTF(" --reloc=<option> - Relocation model: none, pic, PIC, pie, PIE.");
|
||||
PRINTF(" --x86cpu=<option> - Set general level of x64 cpu: baseline, ssse3, sse4, avx1, avx2-v1, avx2-v2 (Skylake/Zen1+), avx512 (Icelake/Zen4+), native.");
|
||||
PRINTF(" --x86vec=<option> - Set max type of vector use: none, mmx, sse, avx, avx512, default.");
|
||||
PRINTF(" --riscvfloat=<option> - Set type of RISC-V float support: none, float, double");
|
||||
PRINTF(" --memory-env=<option> - Set the memory environment: normal, small, tiny, none.");
|
||||
PRINTF(" --strip-unused=<yes|no> - Strip unused code and globals from the output. (default: yes)");
|
||||
PRINTF(" --fp-math=<option> - FP math behaviour: strict, relaxed, fast.");
|
||||
PRINTF(" --win64-simd=<option> - Win64 SIMD ABI: array, full.");
|
||||
PRINTF("");
|
||||
PRINTF(" --debug-stats - Print debug statistics.");
|
||||
PRINTF(" --print-linking - Print linker arguments.");
|
||||
#ifndef NDEBUG
|
||||
PRINTF(" --debug-log - Print debug logging to stdout.");
|
||||
#endif
|
||||
PRINTF("");
|
||||
PRINTF(" --benchmarking - Run built-in benchmarks.");
|
||||
PRINTF(" --testing - Run built-in tests.");
|
||||
PRINTF("");
|
||||
PRINTF(" --list-attributes - List all attributes.");
|
||||
PRINTF(" --list-builtins - List all builtins.");
|
||||
PRINTF(" --list-keywords - List all keywords.");
|
||||
PRINTF(" --list-operators - List all operators.");
|
||||
PRINTF(" --list-precedence - List operator precedence order.");
|
||||
PRINTF(" --list-project-properties - List all available keys used in project.json files.");
|
||||
PRINTF(" --list-manifest-properties - List all available keys used in manifest.json files.");
|
||||
PRINTF(" --list-targets - List all architectures the compiler supports.");
|
||||
PRINTF(" --list-type-properties - List all type properties.");
|
||||
PRINTF("");
|
||||
PRINTF(" --print-output - Print the object files created to stdout.");
|
||||
PRINTF(" --print-input - Print inputted C3 files to stdout.");
|
||||
PRINTF("");
|
||||
PRINTF(" --winsdk <dir> - Set the directory for Windows system library files for cross compilation.");
|
||||
PRINTF(" --wincrt=<option> - Windows CRT linking: none, static-debug, static, dynamic-debug (default if debug info enabled), dynamic (default).");
|
||||
PRINTF(" --windef <file> - Use Windows 'def' file for function exports instead of 'dllexport'.");
|
||||
PRINTF("");
|
||||
PRINTF(" --macossdk <dir> - Set the directory for the MacOS SDK for cross compilation.");
|
||||
PRINTF(" --macos-min-version <ver> - Set the minimum MacOS version to compile for.");
|
||||
PRINTF(" --macos-sdk-version <ver> - Set the MacOS SDK compiled for.");
|
||||
PRINTF("");
|
||||
PRINTF(" --linux-crt <dir> - Set the directory to use for finding crt1.o and related files.");
|
||||
PRINTF(" --linux-crtbegin <dir> - Set the directory to use for finding crtbegin.o and related files.");
|
||||
PRINTF("");
|
||||
PRINTF(" --vector-conv=<option> - Set vector conversion behaviour: default, old.");
|
||||
PRINTF(" --sanitize=<option> - Enable sanitizer: address, memory, thread.");
|
||||
if (full)
|
||||
{
|
||||
PRINTF(" --cc <path> - Set C compiler (for C files in projects and use as system linker).");
|
||||
PRINTF(" --linker=<option> [<path>] - Linker: builtin, cc, custom (default is 'cc'), 'custom' requires a path.");
|
||||
PRINTF("");
|
||||
PRINTF(" --use-stdlib=<yes|no> - Include the standard library (default: yes).");
|
||||
PRINTF(" --link-libc=<yes|no> - Link libc other default libraries (default: yes).");
|
||||
PRINTF(" --emit-stdlib=<yes|no> - Output files for the standard library. (default: yes)");
|
||||
PRINTF(" --panicfn <name> - Override the panic function name.");
|
||||
PRINTF(" --testfn <name> - Override the test runner function name.");
|
||||
PRINTF(" --benchfn <name> - Override the benchmark runner function name.");
|
||||
PRINTF("");
|
||||
PRINTF(" --reloc=<option> - Relocation model: none, pic, PIC, pie, PIE.");
|
||||
PRINTF(" --x86cpu=<option> - Set general level of x64 cpu: baseline, ssse3, sse4, avx1, avx2-v1, avx2-v2 (Skylake/Zen1+), avx512 (Icelake/Zen4+), native.");
|
||||
PRINTF(" --x86vec=<option> - Set max type of vector use: none, mmx, sse, avx, avx512, default.");
|
||||
PRINTF(" --riscvfloat=<option> - Set type of RISC-V float support: none, float, double");
|
||||
PRINTF(" --memory-env=<option> - Set the memory environment: normal, small, tiny, none.");
|
||||
PRINTF(" --strip-unused=<yes|no> - Strip unused code and globals from the output. (default: yes)");
|
||||
PRINTF(" --fp-math=<option> - FP math behaviour: strict, relaxed, fast.");
|
||||
PRINTF(" --win64-simd=<option> - Win64 SIMD ABI: array, full.");
|
||||
PRINTF("");
|
||||
PRINTF(" --print-linking - Print linker arguments.");
|
||||
PRINTF("");
|
||||
PRINTF(" --benchmarking - Run built-in benchmarks.");
|
||||
PRINTF(" --testing - Run built-in tests.");
|
||||
PRINTF("");
|
||||
PRINTF(" --list-attributes - List all attributes.");
|
||||
PRINTF(" --list-builtins - List all builtins.");
|
||||
PRINTF(" --list-keywords - List all keywords.");
|
||||
PRINTF(" --list-operators - List all operators.");
|
||||
PRINTF(" --list-precedence - List operator precedence order.");
|
||||
PRINTF(" --list-project-properties - List all available keys used in project.json files.");
|
||||
PRINTF(" --list-manifest-properties - List all available keys used in manifest.json files.");
|
||||
PRINTF(" --list-targets - List all architectures the compiler supports.");
|
||||
PRINTF(" --list-type-properties - List all type properties.");
|
||||
PRINTF("");
|
||||
PRINTF(" --print-output - Print the object files created to stdout.");
|
||||
PRINTF(" --print-input - Print inputted C3 files to stdout.");
|
||||
PRINTF("");
|
||||
PRINTF(" --winsdk <dir> - Set the directory for Windows system library files for cross compilation.");
|
||||
PRINTF(" --wincrt=<option> - Windows CRT linking: none, static-debug, static, dynamic-debug (default if debug info enabled), dynamic (default).");
|
||||
PRINTF(" --windef <file> - Use Windows 'def' file for function exports instead of 'dllexport'.");
|
||||
PRINTF(" --win-vs-dirs <dir>;<dir> - Override Windows VS detection.");
|
||||
PRINTF("");
|
||||
PRINTF(" --macossdk <dir> - Set the directory for the MacOS SDK for cross compilation.");
|
||||
PRINTF(" --macos-min-version <ver> - Set the minimum MacOS version to compile for.");
|
||||
PRINTF(" --macos-sdk-version <ver> - Set the MacOS SDK compiled for.");
|
||||
PRINTF("");
|
||||
PRINTF(" --linux-crt <dir> - Set the directory to use for finding crt1.o and related files.");
|
||||
PRINTF(" --linux-crtbegin <dir> - Set the directory to use for finding crtbegin.o and related files.");
|
||||
PRINTF("");
|
||||
PRINTF(" --vector-conv=<option> - Set vector conversion behaviour: default, old.");
|
||||
PRINTF(" --sanitize=<option> - Enable sanitizer: address, memory, thread.");
|
||||
}
|
||||
if (!full)
|
||||
{
|
||||
PRINTF("");
|
||||
PRINTF("Use -hh to view the full list of options.");
|
||||
}
|
||||
}
|
||||
|
||||
static void project_usage()
|
||||
@@ -186,8 +198,8 @@ static void project_usage()
|
||||
PRINTF("Usage: %s [<options>] project <subcommand> [<args>]", args[0]);
|
||||
PRINTF("");
|
||||
PRINTF("Project Subcommands:");
|
||||
PRINTF(" view view the current projects structure");
|
||||
PRINTF(" add-target <name> <target_type> add a new target to the project");
|
||||
PRINTF(" view view the current projects structure");
|
||||
PRINTF(" add-target <name> <target_type> [sources...] add a new target to the project");
|
||||
#if FETCH_AVAILABLE
|
||||
PRINTF(" fetch fetch missing project libraries");
|
||||
#endif
|
||||
@@ -210,6 +222,11 @@ static void parse_project_subcommand(BuildOptions *options)
|
||||
if (at_end() || next_is_opt()) error_exit("Expected a target type like 'executable' or 'static-lib'");
|
||||
options->project_options.target_type = (TargetType)get_valid_enum_from_string(next_arg(), "type", targets, ELEMENTLEN(targets), "a target type like 'executable' or 'static-lib'");
|
||||
|
||||
while (!at_end() && !next_is_opt())
|
||||
{
|
||||
vec_add(options->project_options.sources, next_arg());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
if (arg_match("fetch"))
|
||||
@@ -276,11 +293,6 @@ static void parse_command(BuildOptions *options)
|
||||
options->command = COMMAND_COMPILE_ONLY;
|
||||
return;
|
||||
}
|
||||
if (arg_match("headers"))
|
||||
{
|
||||
options->command = COMMAND_GENERATE_HEADERS;
|
||||
return;
|
||||
}
|
||||
if (arg_match("static-lib"))
|
||||
{
|
||||
options->command = COMMAND_STATIC_LIB;
|
||||
@@ -318,6 +330,7 @@ static void parse_command(BuildOptions *options)
|
||||
{
|
||||
options->command = COMMAND_TEST;
|
||||
options->testing = true;
|
||||
parse_optional_target(options);
|
||||
return;
|
||||
}
|
||||
if (arg_match("run"))
|
||||
@@ -407,12 +420,41 @@ static void parse_option(BuildOptions *options)
|
||||
case '\0':
|
||||
options->read_stdin = true;
|
||||
return;
|
||||
case '?':
|
||||
if (match_shortopt("?"))
|
||||
case 'h':
|
||||
if (match_shortopt("hh"))
|
||||
{
|
||||
usage();
|
||||
usage(true);
|
||||
exit_compiler(COMPILER_SUCCESS_EXIT);
|
||||
}
|
||||
if (match_shortopt("h"))
|
||||
{
|
||||
usage(false);
|
||||
exit_compiler(COMPILER_SUCCESS_EXIT);
|
||||
}
|
||||
break;
|
||||
case 'q':
|
||||
if (match_shortopt("q"))
|
||||
{
|
||||
options->verbosity_level = -1;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
if (match_shortopt("vvv"))
|
||||
{
|
||||
options->verbosity_level = 3;
|
||||
return;
|
||||
}
|
||||
if (match_shortopt("vv"))
|
||||
{
|
||||
options->verbosity_level = 2;
|
||||
return;
|
||||
}
|
||||
if (match_shortopt("v"))
|
||||
{
|
||||
options->verbosity_level = 1;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 'V':
|
||||
if (match_shortopt("V"))
|
||||
@@ -438,8 +480,6 @@ static void parse_option(BuildOptions *options)
|
||||
return;
|
||||
}
|
||||
FAIL_WITH_ERR("Unknown debug argument -%s.", ¤t_arg[1]);
|
||||
case 'h':
|
||||
break;
|
||||
case 'z':
|
||||
if (match_shortopt("z"))
|
||||
{
|
||||
@@ -604,14 +644,25 @@ static void parse_option(BuildOptions *options)
|
||||
options->symtab_size = next_highest_power_of_2(symtab);
|
||||
return;
|
||||
}
|
||||
if (match_longopt("quiet"))
|
||||
{
|
||||
options->verbosity_level = -1;
|
||||
return;
|
||||
}
|
||||
if (match_longopt("version"))
|
||||
{
|
||||
print_version();
|
||||
exit_compiler(COMPILER_SUCCESS_EXIT);
|
||||
}
|
||||
if ((argopt = match_argopt("backend")))
|
||||
{
|
||||
options->backend = (CompilerBackend)parse_multi_option(argopt, 3, backends);
|
||||
return;
|
||||
}
|
||||
if (match_longopt("run-once"))
|
||||
{
|
||||
options->run_once = true;
|
||||
if (!options->verbosity_level) options->verbosity_level = -1;
|
||||
return;
|
||||
}
|
||||
if ((argopt = match_argopt("fp-math")))
|
||||
@@ -731,17 +782,6 @@ static void parse_option(BuildOptions *options)
|
||||
options->no_headers = true;
|
||||
return;
|
||||
}
|
||||
if (match_longopt("debug-log"))
|
||||
{
|
||||
debug_log = true;
|
||||
debug_stats = true;
|
||||
return;
|
||||
}
|
||||
if (match_longopt("debug-stats"))
|
||||
{
|
||||
debug_stats = true;
|
||||
return;
|
||||
}
|
||||
if (match_longopt("print-linking"))
|
||||
{
|
||||
options->print_linking = true;
|
||||
@@ -893,6 +933,10 @@ static void parse_option(BuildOptions *options)
|
||||
}
|
||||
if (match_longopt("winsdk"))
|
||||
{
|
||||
if (options->win.vs_dirs)
|
||||
{
|
||||
error_exit("error: --winsdk cannot be combined with --win-vs-dirs.");
|
||||
}
|
||||
if (at_end() || next_is_opt()) error_exit("error: --winsdk needs a directory.");
|
||||
options->win.sdk = check_dir(next_arg());
|
||||
return;
|
||||
@@ -918,6 +962,16 @@ static void parse_option(BuildOptions *options)
|
||||
options->win.crt_linking = (WinCrtLinking)parse_multi_option(argopt, 5, wincrt_linking);
|
||||
return;
|
||||
}
|
||||
if (match_longopt("win-vs-dirs"))
|
||||
{
|
||||
if (options->win.sdk)
|
||||
{
|
||||
error_exit("error: --win-vs-dirs cannot be combined with --winsdk.");
|
||||
}
|
||||
if (at_end() || next_is_opt()) error_exit("error: --win-vs-dirs needs to followed by the directories.");
|
||||
options->win.vs_dirs = next_arg();
|
||||
return;
|
||||
}
|
||||
if ((argopt = match_argopt("sanitize")))
|
||||
{
|
||||
options->sanitize_mode = (SanitizeMode)parse_multi_option(argopt, 4, sanitize_modes);
|
||||
@@ -1058,7 +1112,7 @@ static void parse_option(BuildOptions *options)
|
||||
}
|
||||
if (match_longopt("help"))
|
||||
{
|
||||
usage();
|
||||
usage(true);
|
||||
exit_compiler(COMPILER_SUCCESS_EXIT);
|
||||
}
|
||||
break;
|
||||
@@ -1076,7 +1130,7 @@ BuildOptions parse_arguments(int argc, const char *argv[])
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
usage();
|
||||
usage(false);
|
||||
exit_compiler(COMPILER_SUCCESS_EXIT);
|
||||
}
|
||||
|
||||
@@ -1155,7 +1209,7 @@ BuildOptions parse_arguments(int argc, const char *argv[])
|
||||
parse_command(&build_options);
|
||||
continue;
|
||||
}
|
||||
if (command_accepts_files(build_options.command) || build_options.command == COMMAND_GENERATE_HEADERS)
|
||||
if (command_accepts_files(build_options.command))
|
||||
{
|
||||
append_file(&build_options);
|
||||
continue;
|
||||
@@ -1166,6 +1220,7 @@ BuildOptions parse_arguments(int argc, const char *argv[])
|
||||
{
|
||||
FAIL_WITH_ERR("Missing a compiler command such as 'compile' or 'build'.");
|
||||
}
|
||||
debug_log = build_options.verbosity_level > 2;
|
||||
return build_options;
|
||||
}
|
||||
|
||||
@@ -1202,7 +1257,7 @@ static inline bool at_end()
|
||||
|
||||
static inline const char *next_arg()
|
||||
{
|
||||
assert(!at_end());
|
||||
ASSERT0(!at_end());
|
||||
current_arg = args[++arg_index];
|
||||
return current_arg;
|
||||
}
|
||||
|
||||
@@ -73,7 +73,6 @@ bool command_accepts_files(CompilerCommand command)
|
||||
case COMMAND_UNIT_TEST:
|
||||
return true;
|
||||
case COMMAND_MISSING:
|
||||
case COMMAND_GENERATE_HEADERS:
|
||||
case COMMAND_INIT:
|
||||
case COMMAND_INIT_LIB:
|
||||
case COMMAND_BUILD:
|
||||
@@ -109,7 +108,6 @@ bool command_passes_args(CompilerCommand command)
|
||||
case COMMAND_COMPILE_TEST:
|
||||
case COMMAND_UNIT_TEST:
|
||||
case COMMAND_MISSING:
|
||||
case COMMAND_GENERATE_HEADERS:
|
||||
case COMMAND_INIT:
|
||||
case COMMAND_INIT_LIB:
|
||||
case COMMAND_BUILD:
|
||||
@@ -297,6 +295,7 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
|
||||
break;
|
||||
case COMMAND_STATIC_LIB:
|
||||
target->type = TARGET_TYPE_STATIC_LIB;
|
||||
target->single_module = true;
|
||||
break;
|
||||
default:
|
||||
target->run_after_compile = false;
|
||||
@@ -308,7 +307,8 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
|
||||
case COMMAND_BUILD:
|
||||
target->output_headers = (target->type == TARGET_TYPE_DYNAMIC_LIB || target->type == TARGET_TYPE_STATIC_LIB) && !options->no_headers;
|
||||
break;
|
||||
case COMMAND_GENERATE_HEADERS:
|
||||
case COMMAND_STATIC_LIB:
|
||||
case COMMAND_DYNAMIC_LIB:
|
||||
target->output_headers = true;
|
||||
break;
|
||||
default:
|
||||
@@ -363,8 +363,8 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
|
||||
if (options->arch_os_target_override != ARCH_OS_TARGET_DEFAULT) target->arch_os_target = options->arch_os_target_override;
|
||||
if (options->reloc_model != RELOC_DEFAULT) target->reloc_model = options->reloc_model;
|
||||
if (options->symtab_size) target->symtab_size = options->symtab_size;
|
||||
if (options->silence_deprecation) target->silence_deprecation = options->silence_deprecation;
|
||||
target->print_linking = options->print_linking;
|
||||
if (options->silence_deprecation) target->silence_deprecation = options->silence_deprecation || options->verbosity_level < 0;
|
||||
target->print_linking = options->print_linking || options->verbosity_level > 1;
|
||||
|
||||
for (size_t i = 0; i < options->linker_arg_count; i++)
|
||||
{
|
||||
@@ -394,15 +394,18 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
|
||||
target->emit_llvm = options->emit_llvm;
|
||||
target->build_threads = options->build_threads;
|
||||
target->emit_asm = options->emit_asm;
|
||||
target->print_stats = options->verbosity_level >= 2;
|
||||
if (options->output_dir) target->output_dir = options->output_dir;
|
||||
if (options->panicfn) target->panicfn = options->panicfn;
|
||||
if (options->testfn) target->testfn = options->testfn;
|
||||
if (options->benchfn) target->benchfn = options->benchfn;
|
||||
target->benchmarking = options->benchmarking;
|
||||
target->testing = options->testing;
|
||||
target->silent = options->verbosity_level < 0;
|
||||
target->vector_conv = options->vector_conv;
|
||||
if (options->macos.sysroot) target->macos.sysroot = options->macos.sysroot;
|
||||
if (options->win.sdk) target->win.sdk = options->win.sdk;
|
||||
if (options->win.vs_dirs) target->win.vs_dirs = options->win.vs_dirs;
|
||||
if (options->macos.min_version) target->macos.min_version = options->macos.min_version;
|
||||
if (options->macos.sdk_version) target->macos.sdk_version = options->macos.sdk_version;
|
||||
if (options->win.crt_linking != WIN_CRT_DEFAULT) target->win.crt_linking = options->win.crt_linking;
|
||||
@@ -518,6 +521,7 @@ void init_default_build_target(BuildTarget *target, BuildOptions *options)
|
||||
*target = default_build_target;
|
||||
target->source_dirs = options->files;
|
||||
target->name = options->output_name;
|
||||
target->output_name = options->output_name;
|
||||
update_build_target_from_options(target, options);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#define MANIFEST_FILE "manifest.json"
|
||||
|
||||
const char *manifest_default_keys[][2] = {
|
||||
{"sources", "Paths to library sources for targets, such as interface files."},
|
||||
{"c-sources", "Set the C sources to be compiled."},
|
||||
{"c-include-dirs", "Set the include directories for C sources."},
|
||||
{"cc", "Set C compiler (defaults to 'cc')."},
|
||||
@@ -19,6 +20,8 @@ const char *manifest_default_keys[][2] = {
|
||||
const int manifest_default_keys_count = ELEMENTLEN(manifest_default_keys);
|
||||
|
||||
const char *manifest_target_keys[][2] = {
|
||||
{"sources", "Additional library sources to be compiled for this target."},
|
||||
{"sources-override", "Paths to library sources for this target, overriding global settings."},
|
||||
{"c-sources", "Additional C sources to be compiled for the target."},
|
||||
{"c-sources-override", "C sources to be compiled, overriding global settings."},
|
||||
{"c-include-dirs", "C source include directories for the target."},
|
||||
@@ -86,9 +89,11 @@ static inline void parse_library_target(Library *library, LibraryTarget *target,
|
||||
target->execs = get_string_array(library->dir, target_name, object, "exec", false);
|
||||
target->cc = get_string(library->dir, target_name, object, "cc", library->cc);
|
||||
target->cflags = get_cflags(library->dir, target_name, object, library->cflags);
|
||||
target->source_dirs = library->source_dirs;
|
||||
target->csource_dirs = library->csource_dirs;
|
||||
target->cinclude_dirs = library->cinclude_dirs;
|
||||
target->win_crt = (WinCrtLinking)get_valid_string_setting(library->dir, target_name, object, "wincrt", wincrt_linking, 0, 3, "'none', 'static' or 'dynamic'.");
|
||||
get_list_append_strings(library->dir, target_name, object, &target->source_dirs, "sources", "sources-override", "sources-add");
|
||||
get_list_append_strings(library->dir, target_name, object, &target->csource_dirs, "c-sources", "c-sources-override", "c-sources-add");
|
||||
get_list_append_strings(library->dir, target_name, object, &target->cinclude_dirs, "c-include-dirs", "c-include-dirs-override", "c-include-dirs-add");
|
||||
}
|
||||
@@ -112,6 +117,7 @@ static Library *add_library(JSONObject *object, const char *dir)
|
||||
library->cc = get_optional_string(dir, NULL, object, "cc");
|
||||
library->cflags = get_cflags(library->dir, NULL, object, NULL);
|
||||
library->win_crt = (WinCrtLinking)get_valid_string_setting(library->dir, NULL, object, "wincrt", wincrt_linking, 0, 3, "'none', 'static' or 'dynamic'.");
|
||||
get_list_append_strings(library->dir, NULL, object, &library->source_dirs, "sources", "sources-override", "sources-add");
|
||||
get_list_append_strings(library->dir, NULL, object, &library->csource_dirs, "c-sources", "c-sources-override", "c-sources-add");
|
||||
get_list_append_strings(library->dir, NULL, object, &library->cinclude_dirs, "c-include-dirs", "c-include-dirs-override", "c-include-dirs-add");
|
||||
parse_library_type(library, &library->targets, json_map_get(object, "targets"));
|
||||
@@ -291,7 +297,19 @@ void resolve_libraries(BuildTarget *build_target)
|
||||
{
|
||||
vec_add(build_target->ccompiling_libraries, target);
|
||||
}
|
||||
file_add_wildcard_files(&build_target->sources, library->dir, false, c3_suffix_list, 3);
|
||||
if (target->source_dirs)
|
||||
{
|
||||
const char **files = target_expand_source_names(library->dir, target->source_dirs, c3_suffix_list, &build_target->object_files, 3, true);
|
||||
FOREACH(const char *, file, files)
|
||||
{
|
||||
vec_add(build_target->sources, file);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// fallback if sources doesn't exist
|
||||
file_add_wildcard_files(&build_target->sources, library->dir, false, c3_suffix_list, 3);
|
||||
}
|
||||
vec_add(build_target->library_list, library);
|
||||
const char *libdir = file_append_path(library->dir, arch_os_target[build_target->arch_os_target]);
|
||||
if (file_is_dir(libdir)) vec_add(build_target->linker_libdirs, libdir);
|
||||
@@ -312,4 +330,4 @@ void resolve_libraries(BuildTarget *build_target)
|
||||
puts(execute_cmd(exec, false, NULL));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ const char *project_default_keys[][2] = {
|
||||
{"single-module", "Compile all modules together, enables more inlining."},
|
||||
{"soft-float", "Output soft-float functions."},
|
||||
{"sources", "Paths to project sources for all targets."},
|
||||
{"test-sources", "Paths to project test sources for all targets."},
|
||||
{"strip-unused", "Strip unused code and globals from the output. (default: true)"},
|
||||
{"symtab", "Sets the preferred symtab size."},
|
||||
{"target", "Compile for a particular architecture + OS target."},
|
||||
@@ -100,6 +101,7 @@ const char* project_target_keys[][2] = {
|
||||
{"macos-sdk-version", "Set the MacOS SDK compiled for." },
|
||||
{"macossdk", "Set the directory for the MacOS SDK for cross compilation."},
|
||||
{"memory-env", "Set the memory environment: normal, small, tiny, none."},
|
||||
{"name", "Set the name to be different from the target name."},
|
||||
{"no-entry", "Do not generate (or require) a main function."},
|
||||
{"opt", "Optimization setting: O0, O1, O2, O3, O4, O5, Os, Oz."},
|
||||
{"optlevel", "Code optimization level: none, less, more, max."},
|
||||
@@ -116,6 +118,8 @@ const char* project_target_keys[][2] = {
|
||||
{"soft-float", "Output soft-float functions."},
|
||||
{"sources", "Additional paths to project sources for the target."},
|
||||
{"sources-override", "Paths to project sources for this target, overriding global settings."},
|
||||
{"test-sources", "Additional paths to project test sources for the target."},
|
||||
{"test-sources-override", "Paths to project test sources for this target, overriding global settings."},
|
||||
{"strip-unused", "Strip unused code and globals from the output. (default: true)"},
|
||||
{"symtab", "Sets the preferred symtab size."},
|
||||
{"target", "Compile for a particular architecture + OS target."},
|
||||
@@ -244,6 +248,9 @@ static void load_into_build_target(const char *filename, JSONObject *json, const
|
||||
target->feature.panic_level = (PanicLevel)get_valid_bool(filename, target_name, json, "panic-msg",
|
||||
target->feature.panic_level);
|
||||
|
||||
// Overridden name
|
||||
target->output_name = get_optional_string(filename, target_name, json, "name");
|
||||
|
||||
// Single module
|
||||
target->single_module = (SingleModule) get_valid_bool(filename, target_name, json, "single-module", target->single_module);
|
||||
|
||||
@@ -331,6 +338,9 @@ static void load_into_build_target(const char *filename, JSONObject *json, const
|
||||
RiscvFloatCapability riscv_float = GET_SETTING(RiscvFloatCapability, "riscvfloat", riscv_capability, "`none`, `float` or `double`.");
|
||||
if (riscv_float != RISCVFLOAT_DEFAULT) target->feature.riscv_float_capability = riscv_float;
|
||||
|
||||
// winsdk
|
||||
target->win.vs_dirs = get_string(filename, target_name, json, "win-vs-dirs", target->win.vs_dirs);
|
||||
|
||||
// winsdk
|
||||
target->win.sdk = get_string(filename, target_name, json, "winsdk", target->win.sdk);
|
||||
|
||||
@@ -421,12 +431,37 @@ static void load_into_build_target(const char *filename, JSONObject *json, const
|
||||
target->feature.pass_win64_simd_as_arrays);
|
||||
}
|
||||
|
||||
static void duplicate_prop(const char ***prop_ref)
|
||||
{
|
||||
if (!*prop_ref) return;
|
||||
const char **copy = NULL;
|
||||
FOREACH(const char *, str, *prop_ref)
|
||||
{
|
||||
vec_add(copy, str);
|
||||
}
|
||||
*prop_ref = copy;
|
||||
}
|
||||
static void project_add_target(const char *filename, Project *project, BuildTarget *default_target, JSONObject *json,
|
||||
const char *name, const char *type, TargetType target_type)
|
||||
{
|
||||
assert(json->type == J_OBJECT);
|
||||
ASSERT0(json->type == J_OBJECT);
|
||||
BuildTarget *target = CALLOCS(BuildTarget);
|
||||
*target = *default_target;
|
||||
duplicate_prop(&target->args);
|
||||
duplicate_prop(&target->csource_dirs);
|
||||
duplicate_prop(&target->csources);
|
||||
duplicate_prop(&target->cinclude_dirs);
|
||||
duplicate_prop(&target->exec);
|
||||
duplicate_prop(&target->feature_list);
|
||||
duplicate_prop(&target->sources);
|
||||
duplicate_prop(&target->source_dirs);
|
||||
duplicate_prop(&target->test_source_dirs);
|
||||
duplicate_prop(&target->libdirs);
|
||||
duplicate_prop(&target->libs);
|
||||
duplicate_prop(&target->linker_libdirs);
|
||||
duplicate_prop(&target->linker_libs);
|
||||
duplicate_prop(&target->link_args);
|
||||
|
||||
vec_add(project->targets, target);
|
||||
target->name = name;
|
||||
target->type = target_type;
|
||||
@@ -444,7 +479,7 @@ static void project_add_target(const char *filename, Project *project, BuildTarg
|
||||
|
||||
static void project_add_targets(const char *filename, Project *project, JSONObject *project_data)
|
||||
{
|
||||
assert(project_data->type == J_OBJECT);
|
||||
ASSERT0(project_data->type == J_OBJECT);
|
||||
|
||||
BuildTarget default_target = default_build_target;
|
||||
load_into_build_target(filename, project_data, NULL, &default_target);
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include "../utils/json.h"
|
||||
|
||||
const char** get_project_dependency_directories();
|
||||
|
||||
const char** get_project_dependencies();
|
||||
|
||||
static void print_vec(const char *header, const char **vec, bool opt);
|
||||
|
||||
@@ -20,6 +20,8 @@ const char* JSON_EXE =
|
||||
" \"version\": \"0.1.0\",\n"
|
||||
" // Sources compiled for all targets.\n"
|
||||
" \"sources\": [ \"src/**\" ],\n"
|
||||
" // Test sources compiled for all targets.\n"
|
||||
" \"test-sources\": [ \"test/**\" ],\n"
|
||||
" // C sources if the project also compiles C sources\n"
|
||||
" // relative to the project file.\n"
|
||||
" // \"c-sources\": [ \"csource/**\" ],\n"
|
||||
@@ -63,6 +65,8 @@ const char* JSON_STATIC =
|
||||
" \"version\": \"0.1.0\",\n"
|
||||
" // Sources compiled for all targets.\n"
|
||||
" \"sources\": [ \"src/**\" ],\n"
|
||||
" // Test sources compiled for all targets.\n"
|
||||
" \"test-sources\": [ \"test/**\" ],\n"
|
||||
" // C sources if the project also compiles C sources\n"
|
||||
" // relative to the project file.\n"
|
||||
" // \"c-sources\": [ \"csource/**\" ],\n"
|
||||
@@ -104,6 +108,8 @@ const char* JSON_DYNAMIC =
|
||||
" \"version\": \"0.1.0\",\n"
|
||||
" // Sources compiled for all targets.\n"
|
||||
" \"sources\": [ \"src/**\" ],\n"
|
||||
" // Test sources compiled for all targets.\n"
|
||||
" \"test-sources\": [ \"test/**\" ],\n"
|
||||
" // C sources if the project also compiles C sources\n"
|
||||
" // relative to the project file.\n"
|
||||
" // \"c-sources\": [ \"csource/**\" ],\n"
|
||||
@@ -132,6 +138,7 @@ const char* JSON_DYNAMIC =
|
||||
const char *MANIFEST_TEMPLATE =
|
||||
"{\n"
|
||||
" \"provides\" : \"%s\",\n"
|
||||
" // \"sources\" : [ \"src/**\" ],\n"
|
||||
" \"targets\" : {\n"
|
||||
"%s"
|
||||
" }\n"
|
||||
@@ -213,9 +220,11 @@ void create_library(BuildOptions *build_options)
|
||||
}
|
||||
|
||||
chdir_or_fail(build_options, dir);
|
||||
|
||||
create_file_or_fail(build_options, "LICENSE", NULL);
|
||||
create_file_or_fail(build_options, "README.md", LIB_README, build_options->project_name);
|
||||
mkdir_or_fail(build_options, "scripts");
|
||||
|
||||
scratch_buffer_clear();
|
||||
scratch_buffer_printf("%s.c3i", build_options->project_name);
|
||||
const char *interface_file = scratch_buffer_copy();
|
||||
|
||||
@@ -3,12 +3,24 @@
|
||||
#define PRINTFN(string, ...) fprintf(stdout, string "\n", ##__VA_ARGS__) // NOLINT
|
||||
#define PRINTF(string, ...) fprintf(stdout, string, ##__VA_ARGS__) // NOLINT
|
||||
|
||||
static JSONObject *read_project(const char **file_used)
|
||||
static JSONObject *read_project(const char **file_used, bool assume_empty_if_not_exists)
|
||||
{
|
||||
size_t size;
|
||||
const char *project_filename = file_exists(PROJECT_JSON5) ? PROJECT_JSON5 : PROJECT_JSON;
|
||||
*file_used = project_filename;
|
||||
char *read = file_read_all(project_filename, &size);
|
||||
char *read;
|
||||
if (assume_empty_if_not_exists)
|
||||
{
|
||||
// If project file does not exist assume the project simply being empty instead of
|
||||
// failing. This is useful for such commands as `project add-target`. It enables
|
||||
// them to update otherwise non-existing project files reducing the friction.
|
||||
read = "{}";
|
||||
if (file_exists(project_filename)) read = file_read_all(project_filename, &size);
|
||||
}
|
||||
else
|
||||
{
|
||||
read = file_read_all(project_filename, &size);
|
||||
}
|
||||
JsonParser parser;
|
||||
json_init_string(&parser, read);
|
||||
JSONObject *json = json_parse(&parser);
|
||||
@@ -26,7 +38,7 @@ static JSONObject *read_project(const char **file_used)
|
||||
const char** get_project_dependency_directories()
|
||||
{
|
||||
const char *filename;
|
||||
JSONObject *json = read_project(&filename);
|
||||
JSONObject *json = read_project(&filename, false);
|
||||
|
||||
const char *target = NULL;
|
||||
const char **deps_dirs = NULL;
|
||||
@@ -57,7 +69,7 @@ const char** get_project_dependencies()
|
||||
const char *filename;
|
||||
const char** dependencies = NULL;
|
||||
|
||||
JSONObject *project_json = read_project(&filename);
|
||||
JSONObject *project_json = read_project(&filename, false);
|
||||
JSONObject *dependencies_json = json_map_get(project_json, "dependencies");
|
||||
|
||||
FOREACH(JSONObject *, element, dependencies_json->elements)
|
||||
@@ -209,6 +221,7 @@ static void view_target(const char *filename, const char *name, JSONObject *targ
|
||||
print_opt_str("\tName", name);
|
||||
TARGET_VIEW_MANDATORY_STRING("Type", "type");
|
||||
TARGET_VIEW_STRING("Target language target", "langrev");
|
||||
TARGET_VIEW_STRING("Target output name", "name");
|
||||
TARGET_VIEW_STRING_ARRAY("Warnings used", "warnings");
|
||||
TARGET_VIEW_STRING_ARRAY("Additional c3l library search paths", "dependency-search-paths");
|
||||
TARGET_VIEW_STRING_ARRAY("c3l library search paths (override)", "dependency-search-paths-override");
|
||||
@@ -289,7 +302,7 @@ void fetch_project(BuildOptions* options)
|
||||
const char **libdirs = get_project_dependency_directories();
|
||||
const char **deps = get_project_dependencies();
|
||||
const char *filename;
|
||||
JSONObject *project_json = read_project(&filename);
|
||||
JSONObject *project_json = read_project(&filename, false);
|
||||
|
||||
JSONObject *targets_json = json_map_get(project_json, "targets");
|
||||
|
||||
@@ -358,7 +371,7 @@ void add_libraries_to_project_file(const char** libs, const char* target_name) {
|
||||
//TODO! Target name option not implemented
|
||||
|
||||
const char *filename;
|
||||
JSONObject *project_json = read_project(&filename);
|
||||
JSONObject *project_json = read_project(&filename, false);
|
||||
|
||||
// TODO! check if target is specified and exists (NULL at the moment)
|
||||
JSONObject *libraries_json = json_map_get(project_json, "dependencies");
|
||||
@@ -395,9 +408,15 @@ void add_libraries_to_project_file(const char** libs, const char* target_name) {
|
||||
void add_target_project(BuildOptions *build_options)
|
||||
{
|
||||
const char *filename;
|
||||
JSONObject *project_json = read_project(&filename);
|
||||
JSONObject *project_json = read_project(&filename, true);
|
||||
JSONObject *targets_json = json_map_get(project_json, "targets");
|
||||
|
||||
if (targets_json == NULL)
|
||||
{
|
||||
targets_json = json_new_object(J_OBJECT);
|
||||
json_map_set(project_json, "targets", targets_json);
|
||||
}
|
||||
|
||||
if (json_map_get(targets_json, build_options->project_options.target_name) != NULL)
|
||||
{
|
||||
error_exit("Target with name '%s' already exists", build_options->project_options.target_name);
|
||||
@@ -407,6 +426,12 @@ void add_target_project(BuildOptions *build_options)
|
||||
|
||||
JSONObject *new_target = json_new_map();
|
||||
json_map_set(new_target, "type", target_type_obj);
|
||||
JSONObject *target_sources = json_new_object(J_ARRAY);
|
||||
FOREACH(const char *, source, build_options->project_options.sources)
|
||||
{
|
||||
vec_add(target_sources->elements, json_new_string(source));
|
||||
}
|
||||
json_map_set(new_target, "sources", target_sources);
|
||||
|
||||
json_map_set(targets_json, build_options->project_options.target_name, new_target);
|
||||
|
||||
@@ -418,7 +443,7 @@ void add_target_project(BuildOptions *build_options)
|
||||
void view_project(BuildOptions *build_options)
|
||||
{
|
||||
const char *filename;
|
||||
JSONObject *project_json = read_project(&filename);
|
||||
JSONObject *project_json = read_project(&filename, false);
|
||||
|
||||
/* General information */
|
||||
VIEW_MANDATORY_STRING_ARRAY("Authors", "authors");
|
||||
|
||||
@@ -61,10 +61,10 @@ bool abi_arg_is_indirect(ABIArgInfo *info)
|
||||
|
||||
ABIArgInfo *abi_arg_new_indirect_realigned(AlignSize alignment, Type *by_val_type)
|
||||
{
|
||||
assert(alignment > 0);
|
||||
ASSERT0(alignment > 0);
|
||||
ABIArgInfo *info = abi_arg_new(ABI_ARG_INDIRECT);
|
||||
info->indirect.alignment = alignment;
|
||||
assert(info->indirect.alignment);
|
||||
ASSERT0(info->indirect.alignment);
|
||||
info->attributes.realign = true;
|
||||
info->indirect.type = by_val_type;
|
||||
info->attributes.by_val = true;
|
||||
@@ -77,7 +77,7 @@ ABIArgInfo *abi_arg_new_indirect_by_val(Type *by_val_type)
|
||||
info->indirect.alignment = type_abi_alignment(by_val_type);
|
||||
info->indirect.type = by_val_type;
|
||||
info->attributes.by_val = true;
|
||||
assert(info->indirect.alignment);
|
||||
ASSERT0(info->indirect.alignment);
|
||||
return info;
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ ABIArgInfo *abi_arg_new_indirect_not_by_val(Type *type)
|
||||
{
|
||||
ABIArgInfo *info = abi_arg_new(ABI_ARG_INDIRECT);
|
||||
info->indirect.alignment = type_abi_alignment(type);
|
||||
assert(info->indirect.alignment);
|
||||
ASSERT0(info->indirect.alignment);
|
||||
info->indirect.type = type;
|
||||
info->attributes.by_val = false;
|
||||
return info;
|
||||
@@ -175,7 +175,7 @@ ABIArgInfo *abi_arg_new_direct_coerce_int(void)
|
||||
|
||||
ABIArgInfo *abi_arg_new_direct_coerce_type(Type *type)
|
||||
{
|
||||
assert(type);
|
||||
ASSERT0(type);
|
||||
ABIArgInfo *info = abi_arg_new(ABI_ARG_DIRECT_COERCE);
|
||||
info->direct_coerce_type = type->canonical;
|
||||
return info;
|
||||
@@ -191,7 +191,7 @@ ABIArgInfo *abi_arg_new_direct_struct_expand_i32(uint8_t elements)
|
||||
|
||||
void c_abi_func_create(FunctionPrototype *proto)
|
||||
{
|
||||
assert(!proto->is_resolved);
|
||||
ASSERT0(!proto->is_resolved);
|
||||
proto->is_resolved = true;
|
||||
switch (compiler.platform.abi)
|
||||
{
|
||||
|
||||
@@ -57,7 +57,7 @@ ABIArgInfo *aarch64_coerce_illegal_vector(Type *type)
|
||||
UNREACHABLE
|
||||
}*/
|
||||
}
|
||||
assert(type->type_kind == TYPE_VECTOR);
|
||||
ASSERT0(type->type_kind == TYPE_VECTOR);
|
||||
TypeSize size = type_size(type);
|
||||
|
||||
// CLANG: Android promotes char[<2>] to ushort, not uint
|
||||
@@ -107,7 +107,7 @@ ABIArgInfo *aarch64_classify_argument_type(Type *type)
|
||||
unsigned members = 0;
|
||||
if (type_is_homogenous_aggregate(type, &base, &members))
|
||||
{
|
||||
assert(members < 128);
|
||||
ASSERT0(members < 128);
|
||||
if (members > 1)
|
||||
{
|
||||
return abi_arg_new_direct_coerce_type(type_get_array(base, members));
|
||||
@@ -134,7 +134,7 @@ ABIArgInfo *aarch64_classify_argument_type(Type *type)
|
||||
size = aligned_offset(size, alignment);
|
||||
// We use a pair of i64 for 16-byte aggregate with 8-byte alignment.
|
||||
// For aggregates with 16-byte alignment, we use i128.
|
||||
assert(alignment == 8 || alignment == 16);
|
||||
ASSERT0(alignment == 8 || alignment == 16);
|
||||
|
||||
if (alignment == 16) return abi_arg_new_direct_coerce_type(type_u128);
|
||||
ArraySize m = size / alignment;
|
||||
@@ -196,7 +196,7 @@ ABIArgInfo *aarch64_classify_return_type(Type *type, bool variadic)
|
||||
|
||||
if (size <= 8 && !compiler.platform.big_endian)
|
||||
{
|
||||
return abi_arg_new_direct_coerce_type(type_int_unsigned_by_bitsize(size * 8));
|
||||
return abi_arg_new_direct_coerce_int();
|
||||
}
|
||||
|
||||
unsigned alignment = type_abi_alignment(type);
|
||||
|
||||
@@ -7,13 +7,13 @@
|
||||
|
||||
static ABIArgInfo *riscv_coerce_and_expand_fpcc_struct(AbiType field1, unsigned field1_offset, AbiType field2, unsigned field2_offset)
|
||||
{
|
||||
assert(abi_type_is_type(field1));
|
||||
ASSERT0(abi_type_is_type(field1));
|
||||
if (!abi_type_is_valid(field2))
|
||||
{
|
||||
return abi_arg_new_direct_coerce_type(field1.type);
|
||||
}
|
||||
|
||||
assert(abi_type_is_type(field2));
|
||||
ASSERT0(abi_type_is_type(field2));
|
||||
Type *type2 = field2.type;
|
||||
ByteSize abi_type_size = type_size(type2);
|
||||
// Not on even offset, use packed semantics.
|
||||
@@ -132,10 +132,10 @@ static bool riscv_detect_fpcc_struct(Type *type, AbiType *field1_ref, unsigned *
|
||||
static ABIArgInfo *riscv_classify_argument_type(Type *type, bool is_fixed, unsigned *gprs, unsigned *fprs)
|
||||
{
|
||||
|
||||
assert(type == type->canonical);
|
||||
ASSERT0(type == type->canonical);
|
||||
|
||||
unsigned xlen = compiler.platform.riscv.xlen;
|
||||
assert(is_power_of_two(xlen));
|
||||
ASSERT0(is_power_of_two(xlen));
|
||||
|
||||
ByteSize size = type_size(type);
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ ABIArgInfo *x64_indirect_result(Type *type, unsigned free_int_regs)
|
||||
*/
|
||||
ABIArgInfo *x64_classify_reg_call_struct_type_check(Type *type, Registers *needed_registers)
|
||||
{
|
||||
assert(x64_type_is_structure(type));
|
||||
ASSERT0(x64_type_is_structure(type));
|
||||
|
||||
// These are all passed in two registers.
|
||||
if (type->type_kind == TYPE_SLICE || type->type_kind == TYPE_ANY)
|
||||
@@ -132,7 +132,7 @@ ABIArgInfo *x64_classify_reg_call_struct_type_check(Type *type, Registers *neede
|
||||
}
|
||||
|
||||
// Struct, err type handled =>
|
||||
assert(type->type_kind == TYPE_STRUCT);
|
||||
ASSERT0(type->type_kind == TYPE_STRUCT);
|
||||
|
||||
// Variable array structs are always passed by pointer.
|
||||
if (type->decl->has_variable_array) return x64_indirect_return_result(type);
|
||||
@@ -175,7 +175,7 @@ static X64Class x64_merge(X64Class accum, X64Class field)
|
||||
// 6. SSE
|
||||
|
||||
// Accum should never be memory (we should have returned) or
|
||||
assert(accum != CLASS_MEMORY);
|
||||
ASSERT0(accum != CLASS_MEMORY);
|
||||
if (accum == field) return accum;
|
||||
|
||||
// Swap
|
||||
@@ -305,7 +305,7 @@ void x64_classify_array(Type *type, ByteSize offset_base, X64Class *current, X64
|
||||
if (*lo_class == CLASS_MEMORY || *hi_class == CLASS_MEMORY) break;
|
||||
}
|
||||
x64_classify_post_merge(size, lo_class, hi_class);
|
||||
assert(*hi_class != CLASS_SSEUP || *lo_class == CLASS_SSE);
|
||||
ASSERT0(*hi_class != CLASS_SSEUP || *lo_class == CLASS_SSE);
|
||||
}
|
||||
|
||||
void x64_classify_vector(Type *type, ByteSize offset_base, X64Class *current, X64Class *lo_class, X64Class *hi_class,
|
||||
@@ -365,7 +365,7 @@ static Decl *x64_get_member_at_offset(Decl *decl, unsigned offset)
|
||||
if (member->offset > (ArrayIndex)offset) break;
|
||||
last_match = member;
|
||||
}
|
||||
assert(last_match);
|
||||
ASSERT0(last_match);
|
||||
return last_match;
|
||||
}
|
||||
|
||||
@@ -616,7 +616,7 @@ AbiType x64_get_int_type_at_offset(Type *type, unsigned offset, Type *source_typ
|
||||
break;
|
||||
}
|
||||
ByteSize size = type_size(source_type);
|
||||
assert(size != source_offset);
|
||||
ASSERT0(size != source_offset);
|
||||
if (size - source_offset > 8) return abi_type_get(type_ulong);
|
||||
return abi_type_get_int_bits((size - source_offset) * 8);
|
||||
}
|
||||
@@ -649,7 +649,7 @@ static AbiType x64_get_byte_vector_type(Type *type)
|
||||
|
||||
unsigned size = type_size(type);
|
||||
|
||||
assert(size == 16 || size == 32 || size == 64);
|
||||
ASSERT0(size == 16 || size == 32 || size == 64);
|
||||
|
||||
// Return a vector type based on the size.
|
||||
return abi_type_get(type_get_vector(type_double, size / 8));
|
||||
@@ -659,7 +659,7 @@ static ABIArgInfo *x64_get_argument_pair_return(AbiType low_type, AbiType high_t
|
||||
{
|
||||
TypeSize low_size = abi_type_size(low_type);
|
||||
unsigned hi_start = aligned_offset(low_size, abi_type_abi_alignment(high_type));
|
||||
assert(hi_start == 8 && "Expected aligned with C-style structs.");
|
||||
ASSERT0(hi_start == 8 && "Expected aligned with C-style structs.");
|
||||
return abi_arg_new_direct_pair(low_type, high_type);
|
||||
}
|
||||
|
||||
@@ -673,8 +673,8 @@ ABIArgInfo *x64_classify_return(Type *return_type)
|
||||
x64_classify(return_type, 0, &lo_class, &hi_class, NAMED);
|
||||
|
||||
// Invariants
|
||||
assert(hi_class != CLASS_MEMORY || lo_class == CLASS_MEMORY);
|
||||
assert(hi_class != CLASS_SSEUP || lo_class == CLASS_SSE);
|
||||
ASSERT0(hi_class != CLASS_MEMORY || lo_class == CLASS_MEMORY);
|
||||
ASSERT0(hi_class != CLASS_SSEUP || lo_class == CLASS_SSE);
|
||||
|
||||
AbiType result_type = ABI_TYPE_EMPTY;
|
||||
switch (lo_class)
|
||||
@@ -685,7 +685,7 @@ ABIArgInfo *x64_classify_return(Type *return_type)
|
||||
return abi_arg_ignore();
|
||||
}
|
||||
// If low part is padding, keep type null
|
||||
assert(hi_class == CLASS_SSE || hi_class == CLASS_INTEGER);
|
||||
ASSERT0(hi_class == CLASS_SSE || hi_class == CLASS_INTEGER);
|
||||
break;
|
||||
case CLASS_SSEUP:
|
||||
UNREACHABLE
|
||||
@@ -717,11 +717,11 @@ ABIArgInfo *x64_classify_return(Type *return_type)
|
||||
// Previously handled.
|
||||
break;
|
||||
case CLASS_INTEGER:
|
||||
assert(lo_class != CLASS_NO_CLASS);
|
||||
ASSERT0(lo_class != CLASS_NO_CLASS);
|
||||
high_part = x64_get_int_type_at_offset(return_type, 8, return_type, 8);
|
||||
break;
|
||||
case CLASS_SSE:
|
||||
assert(lo_class != CLASS_NO_CLASS);
|
||||
ASSERT0(lo_class != CLASS_NO_CLASS);
|
||||
high_part = abi_type_get(x64_get_sse_type_at_offset(return_type, 8, return_type, 8));
|
||||
break;
|
||||
case CLASS_SSEUP:
|
||||
@@ -730,7 +730,7 @@ ABIArgInfo *x64_classify_return(Type *return_type)
|
||||
// vector register.
|
||||
//
|
||||
// SSEUP should always be preceded by SSE, just widen.
|
||||
assert(lo_class == CLASS_SSE && "Unexpected SSEUp classification.");
|
||||
ASSERT0(lo_class == CLASS_SSE && "Unexpected SSEUp classification.");
|
||||
result_type = x64_get_byte_vector_type(return_type);
|
||||
break;
|
||||
}
|
||||
@@ -748,7 +748,7 @@ ABIArgInfo *x64_classify_return(Type *return_type)
|
||||
}
|
||||
return abi_arg_new_direct_coerce_type(result_type.type->canonical);
|
||||
}
|
||||
assert(result_type.int_bits_plus_1 - 1 == type_size(return_type) * 8);
|
||||
ASSERT0(result_type.int_bits_plus_1 - 1 == type_size(return_type) * 8);
|
||||
return abi_arg_new_direct_coerce_int();
|
||||
}
|
||||
|
||||
@@ -764,14 +764,14 @@ ABIArgInfo *x64_classify_return(Type *return_type)
|
||||
*/
|
||||
static ABIArgInfo *x64_classify_argument_type(Type *type, unsigned free_int_regs, Registers *needed_registers, NamedArgument is_named)
|
||||
{
|
||||
assert(type == type_lowering(type));
|
||||
ASSERT0(type == type_lowering(type));
|
||||
X64Class hi_class;
|
||||
X64Class lo_class;
|
||||
x64_classify(type, 0, &lo_class, &hi_class, is_named);
|
||||
|
||||
// Invariants
|
||||
assert(hi_class != CLASS_MEMORY || lo_class == CLASS_MEMORY);
|
||||
assert(hi_class != CLASS_SSEUP || lo_class == CLASS_SSE);
|
||||
ASSERT0(hi_class != CLASS_MEMORY || lo_class == CLASS_MEMORY);
|
||||
ASSERT0(hi_class != CLASS_SSEUP || lo_class == CLASS_SSE);
|
||||
|
||||
AbiType result_type;
|
||||
*needed_registers = (Registers) { 0, 0 };
|
||||
@@ -781,7 +781,7 @@ static ABIArgInfo *x64_classify_argument_type(Type *type, unsigned free_int_regs
|
||||
{
|
||||
case CLASS_NO_CLASS:
|
||||
// Only C++ would leave 8 bytes of padding, so we can ignore that case.
|
||||
assert(hi_class == CLASS_NO_CLASS);
|
||||
ASSERT0(hi_class == CLASS_NO_CLASS);
|
||||
return abi_arg_ignore();
|
||||
case CLASS_SSEUP:
|
||||
UNREACHABLE
|
||||
@@ -792,7 +792,7 @@ static ABIArgInfo *x64_classify_argument_type(Type *type, unsigned free_int_regs
|
||||
result_type = x64_get_int_type_at_offset(type, 0, type, 0);
|
||||
if (hi_class == CLASS_NO_CLASS && type_is_promotable_int_bool(type))
|
||||
{
|
||||
assert(abi_type_is_type(result_type));
|
||||
ASSERT0(abi_type_is_type(result_type));
|
||||
return abi_arg_new_direct_coerce_int_ext(result_type.type);
|
||||
}
|
||||
break;
|
||||
@@ -814,15 +814,15 @@ static ABIArgInfo *x64_classify_argument_type(Type *type, unsigned free_int_regs
|
||||
needed_registers->int_registers++;
|
||||
high_part = x64_get_int_type_at_offset(type, 8, type, 8);
|
||||
// Return directly into high part.
|
||||
assert(lo_class != CLASS_NO_CLASS && "empty first 8 bytes not allowed, this is C++ stuff.");
|
||||
ASSERT0(lo_class != CLASS_NO_CLASS && "empty first 8 bytes not allowed, this is C++ stuff.");
|
||||
break;
|
||||
case CLASS_SSE:
|
||||
needed_registers->sse_registers++;
|
||||
high_part = abi_type_get(x64_get_sse_type_at_offset(type, 8, type, 8));
|
||||
assert(lo_class != CLASS_NO_CLASS && "empty first 8 bytes not allowed, this is C++ stuff");
|
||||
ASSERT0(lo_class != CLASS_NO_CLASS && "empty first 8 bytes not allowed, this is C++ stuff");
|
||||
break;
|
||||
case CLASS_SSEUP:
|
||||
assert(lo_class == CLASS_SSE && "Unexpected SSEUp classification.");
|
||||
ASSERT0(lo_class == CLASS_SSE && "Unexpected SSEUp classification.");
|
||||
result_type = x64_get_byte_vector_type(type);
|
||||
break;
|
||||
}
|
||||
@@ -843,7 +843,7 @@ static ABIArgInfo *x64_classify_argument_type(Type *type, unsigned free_int_regs
|
||||
}
|
||||
return abi_arg_new_direct_coerce_type(result);
|
||||
}
|
||||
assert(result_type.int_bits_plus_1 - 1 == type_size(type) * 8);
|
||||
ASSERT0(result_type.int_bits_plus_1 - 1 == type_size(type) * 8);
|
||||
return abi_arg_new_direct_coerce_int();
|
||||
}
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ static ABIArgInfo *create_indirect_return_x86(Type *type, Regs *regs)
|
||||
|
||||
static bool x86_should_return_type_in_reg(Type *type)
|
||||
{
|
||||
assert(type->canonical == type);
|
||||
ASSERT0(type->canonical == type);
|
||||
ByteSize size = type_size(type);
|
||||
if (size > 8) return false;
|
||||
|
||||
@@ -226,7 +226,7 @@ static inline bool x86_is_mmxtype(Type *type)
|
||||
|
||||
static inline bool x86_can_expand_indirect_aggregate_arg(Type *type)
|
||||
{
|
||||
assert(type_is_abi_aggregate(type));
|
||||
ASSERT0(type_is_abi_aggregate(type));
|
||||
|
||||
// Test whether an argument type which is to be passed indirectly (on the
|
||||
// stack) would have the equivalent layout if it was expanded into separate
|
||||
@@ -373,7 +373,7 @@ static inline ABIArgInfo *x86_classify_vector(Regs *regs, Type *type)
|
||||
static inline ABIArgInfo *x86_classify_aggregate(CallABI call, Regs *regs, Type *type)
|
||||
{
|
||||
// Only called for aggregates.
|
||||
assert(type_is_abi_aggregate(type));
|
||||
ASSERT0(type_is_abi_aggregate(type));
|
||||
|
||||
if (type_is_union_or_strukt(type) && type->decl->has_variable_array)
|
||||
{
|
||||
@@ -390,7 +390,7 @@ static inline ABIArgInfo *x86_classify_aggregate(CallABI call, Regs *regs, Type
|
||||
// Here we coerce the aggregate into a struct { i32, i32, ... }
|
||||
// but we do not generate this struct immediately here.
|
||||
unsigned size_in_regs = (size + 3) / 4;
|
||||
assert(size_in_regs < 8);
|
||||
ASSERT0(size_in_regs < 8);
|
||||
ABIArgInfo *info;
|
||||
if (size_in_regs > 1)
|
||||
{
|
||||
|
||||
@@ -175,7 +175,7 @@ static inline void reg_instr_clob(PlatformTarget *target, const char *name, Clob
|
||||
unsigned param_count = 0;
|
||||
while (args && args[0] != 0)
|
||||
{
|
||||
assert(param_count <= MAX_ASM_INSTRUCTION_PARAMS);
|
||||
ASSERT0(param_count <= MAX_ASM_INSTRUCTION_PARAMS);
|
||||
instr->param[param_count++] = decode_arg_type(&args);
|
||||
}
|
||||
instr->param_count = param_count;
|
||||
@@ -188,7 +188,7 @@ static inline void reg_instr(PlatformTarget *target, const char *name, const cha
|
||||
int param_count = 0;
|
||||
while (args && args[0] != 0)
|
||||
{
|
||||
assert(param_count <= MAX_ASM_INSTRUCTION_PARAMS);
|
||||
ASSERT0(param_count <= MAX_ASM_INSTRUCTION_PARAMS);
|
||||
instr->param[param_count++] = decode_arg_type(&args);
|
||||
}
|
||||
instr->param_count = param_count;
|
||||
|
||||
@@ -174,7 +174,7 @@ Decl *decl_new_generated_var(Type *type, VarDeclKind kind, SourceSpan span)
|
||||
decl->var.kind = kind;
|
||||
decl->type = type;
|
||||
decl->alignment = type ? type_alloca_alignment(type) : 0;
|
||||
assert(!type || !type_is_user_defined(type) || type->decl->resolve_status == RESOLVE_DONE);
|
||||
ASSERT0(!type || !type_is_user_defined(type) || type->decl->resolve_status == RESOLVE_DONE);
|
||||
decl->var.type_info = type_info_id_new_base(type, span);
|
||||
decl->resolve_status = RESOLVE_DONE;
|
||||
return decl;
|
||||
@@ -428,7 +428,7 @@ AlignSize decl_find_member_offset(Decl *decl, Decl *member)
|
||||
default:
|
||||
return NO_MATCH;
|
||||
}
|
||||
assert(members);
|
||||
ASSERT0(members);
|
||||
unsigned list = vec_size(members);
|
||||
for (unsigned i = 0; i < list; i++)
|
||||
{
|
||||
|
||||
@@ -41,7 +41,7 @@ UNUSED static char digit_to_char(uint8_t digit, bool upper)
|
||||
|
||||
char *i128_to_string(Int128 op, uint64_t base, bool is_signed, bool use_prefix)
|
||||
{
|
||||
assert(base >= 2 && base <= 16);
|
||||
ASSERT0(base >= 2 && base <= 16);
|
||||
static char digits[16] = "0123456789ABCDEF";
|
||||
char buffer[130];
|
||||
char *loc = buffer;
|
||||
@@ -322,7 +322,7 @@ Int128 i128_from_float_unsigned(Real d)
|
||||
|
||||
UNUSED bool i128_get_bit(const Int128 *op, int bit)
|
||||
{
|
||||
assert(bit < 128 && bit >= 0);
|
||||
ASSERT0(bit < 128 && bit >= 0);
|
||||
if (bit > 63)
|
||||
{
|
||||
return (op->high >> (bit - 64)) & 1;
|
||||
@@ -761,7 +761,7 @@ unsigned int_bits_needed(Int op)
|
||||
|
||||
Int int_add(Int op1, Int op2)
|
||||
{
|
||||
assert(op1.type == op2.type);
|
||||
ASSERT0(op1.type == op2.type);
|
||||
return (Int){ i128_extend(i128_add(op1.i, op2.i), op1.type), op1.type };
|
||||
}
|
||||
|
||||
@@ -772,7 +772,7 @@ Int int_add64(Int op1, uint64_t op2)
|
||||
|
||||
Int int_sub(Int op1, Int op2)
|
||||
{
|
||||
assert(op1.type == op2.type);
|
||||
ASSERT0(op1.type == op2.type);
|
||||
return (Int){ i128_extend(i128_sub(op1.i, op2.i), op1.type), op1.type };
|
||||
}
|
||||
|
||||
@@ -783,7 +783,7 @@ Int int_sub64(Int op1, uint64_t op2)
|
||||
|
||||
Int int_mul(Int op1, Int op2)
|
||||
{
|
||||
assert(op1.type == op2.type);
|
||||
ASSERT0(op1.type == op2.type);
|
||||
return (Int){ i128_extend(i128_mult(op1.i, op2.i), op1.type), op1.type };
|
||||
}
|
||||
|
||||
@@ -821,7 +821,7 @@ Int int_conv(Int op, TypeKind to_type)
|
||||
|
||||
Int int_div(Int op1, Int op2)
|
||||
{
|
||||
assert(op1.type == op2.type);
|
||||
ASSERT0(op1.type == op2.type);
|
||||
Int128 res;
|
||||
if (type_kind_is_signed(op1.type))
|
||||
{
|
||||
@@ -836,7 +836,7 @@ Int int_div(Int op1, Int op2)
|
||||
|
||||
Int int_rem(Int op1, Int op2)
|
||||
{
|
||||
assert(op1.type == op2.type);
|
||||
ASSERT0(op1.type == op2.type);
|
||||
Int128 res;
|
||||
if (type_kind_is_signed(op1.type))
|
||||
{
|
||||
@@ -851,19 +851,19 @@ Int int_rem(Int op1, Int op2)
|
||||
|
||||
Int int_and(Int op1, Int op2)
|
||||
{
|
||||
assert(op1.type == op2.type);
|
||||
ASSERT0(op1.type == op2.type);
|
||||
return (Int){ i128_and(op1.i, op2.i), op1.type };
|
||||
}
|
||||
|
||||
Int int_or(Int op1, Int op2)
|
||||
{
|
||||
assert(op1.type == op2.type);
|
||||
ASSERT0(op1.type == op2.type);
|
||||
return (Int){ i128_or(op1.i, op2.i), op1.type };
|
||||
}
|
||||
|
||||
Int int_xor(Int op1, Int op2)
|
||||
{
|
||||
assert(op1.type == op2.type);
|
||||
ASSERT0(op1.type == op2.type);
|
||||
return (Int){ i128_xor(op1.i, op2.i), op1.type };
|
||||
}
|
||||
|
||||
|
||||
1078
src/compiler/c_codegen.c
Normal file
1078
src/compiler/c_codegen.c
Normal file
File diff suppressed because it is too large
Load Diff
1
src/compiler/c_codegen_internal.h
Normal file
1
src/compiler/c_codegen_internal.h
Normal file
@@ -0,0 +1 @@
|
||||
#include "codegen_internal.h"
|
||||
@@ -7,6 +7,13 @@
|
||||
#define CAST_AND_EXTEND(x, n) \
|
||||
(((int64_t)((x) << (64 - (n)))) >> (64 - (n)))
|
||||
|
||||
INLINE bool codegen_asm_label(Ast *ast)
|
||||
{
|
||||
if (ast->ast_kind != AST_ASM_LABEL) return false;
|
||||
scratch_buffer_printf("${:private}%s.${:uid}:\n", ast->asm_label);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void codegen_create_x86att_arg(AsmInlineBlock *block, unsigned input_offset, Expr *expr)
|
||||
{
|
||||
ExprAsmArg *arg = &expr->expr_asm_arg;
|
||||
@@ -177,6 +184,7 @@ static inline char *codegen_create_x86_att_asm(AsmInlineBlock *block)
|
||||
{
|
||||
Ast *ast = astptr(next);
|
||||
next = ast->next;
|
||||
if (codegen_asm_label(ast)) continue;
|
||||
scratch_buffer_append(ast->asm_stmt.instruction);
|
||||
Expr** args = ast->asm_stmt.args;
|
||||
unsigned arg_count = vec_size(args);
|
||||
@@ -201,6 +209,7 @@ static inline char *codegen_create_aarch64_asm(AsmInlineBlock *block)
|
||||
{
|
||||
Ast *ast = astptr(next);
|
||||
next = ast->next;
|
||||
if (codegen_asm_label(ast)) continue;
|
||||
scratch_buffer_append(ast->asm_stmt.instruction);
|
||||
Expr** args = ast->asm_stmt.args;
|
||||
unsigned arg_count = vec_size(args);
|
||||
@@ -225,6 +234,7 @@ static inline char *codegen_create_riscv_asm(AsmInlineBlock *block)
|
||||
{
|
||||
Ast *ast = astptr(next);
|
||||
next = ast->next;
|
||||
if (codegen_asm_label(ast)) continue;
|
||||
scratch_buffer_append(ast->asm_stmt.instruction);
|
||||
Expr** args = ast->asm_stmt.args;
|
||||
unsigned arg_count = vec_size(args);
|
||||
@@ -242,7 +252,7 @@ static inline char *codegen_create_riscv_asm(AsmInlineBlock *block)
|
||||
|
||||
const char *codegen_create_asm(Ast *ast)
|
||||
{
|
||||
assert(ast->ast_kind == AST_ASM_BLOCK_STMT);
|
||||
ASSERT0(ast->ast_kind == AST_ASM_BLOCK_STMT);
|
||||
scratch_buffer_clear();
|
||||
AsmInlineBlock *block = ast->asm_block_stmt.block;
|
||||
if (compiler.platform.arch == ARCH_TYPE_X86_64 || compiler.platform.arch == ARCH_TYPE_X86)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user