mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Compare commits
1 Commits
v0.6.3
...
cbuttner/s
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ab5fdf954 |
@@ -1,28 +0,0 @@
|
||||
# EditorConfig is awesome: https://editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
|
||||
[CMakeLists.txt]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[*.{c,cc,h}]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[*.{c3}]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[*.{json,toml,yml,gyp}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.{py,pyi}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -1,2 +1,4 @@
|
||||
$ cat .gitattributes
|
||||
* text=auto
|
||||
*.c3 linguist-language=C
|
||||
*.c3t linguist-language=C
|
||||
140
.github/workflows/main.yml
vendored
140
.github/workflows/main.yml
vendored
@@ -8,7 +8,7 @@ on:
|
||||
|
||||
env:
|
||||
LLVM_RELEASE_VERSION_WINDOWS: 18
|
||||
LLVM_RELEASE_VERSION_MAC: 17
|
||||
LLVM_RELEASE_VERSION_MAC: 18
|
||||
LLVM_RELEASE_VERSION_LINUX: 17
|
||||
LLVM_RELEASE_VERSION_UBUNTU20: 17
|
||||
LLVM_DEV_VERSION: 20
|
||||
@@ -65,15 +65,15 @@ jobs:
|
||||
|
||||
- name: Vendor-fetch
|
||||
run: |
|
||||
build\${{ matrix.build_type }}\c3c.exe vendor-fetch raylib5
|
||||
build\${{ matrix.build_type }}\c3c.exe vendor-fetch raylib
|
||||
|
||||
- name: Try raylib5
|
||||
- name: Try raylib
|
||||
run: |
|
||||
cd resources
|
||||
..\build\${{ matrix.build_type }}\c3c.exe vendor-fetch raylib5
|
||||
..\build\${{ matrix.build_type }}\c3c.exe compile --lib raylib5 --print-linking examples\raylib\raylib_arkanoid.c3
|
||||
..\build\${{ matrix.build_type }}\c3c.exe compile --lib raylib5 --print-linking examples\raylib\raylib_snake.c3
|
||||
..\build\${{ matrix.build_type }}\c3c.exe compile --lib raylib5 --print-linking examples\raylib\raylib_tetris.c3
|
||||
..\build\${{ matrix.build_type }}\c3c.exe vendor-fetch raylib
|
||||
..\build\${{ matrix.build_type }}\c3c.exe compile --lib raylib --wincrt=none examples\raylib\raylib_arkanoid.c3
|
||||
..\build\${{ matrix.build_type }}\c3c.exe compile --lib raylib --wincrt=none examples\raylib\raylib_snake.c3
|
||||
..\build\${{ matrix.build_type }}\c3c.exe compile --lib raylib --wincrt=none examples\raylib\raylib_tetris.c3
|
||||
|
||||
- name: run compiler tests
|
||||
run: |
|
||||
@@ -91,7 +91,7 @@ jobs:
|
||||
dir msvc_sdk
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: c3-windows-${{ matrix.build_type }}
|
||||
path: |
|
||||
@@ -145,7 +145,7 @@ jobs:
|
||||
|
||||
- name: Vendor-fetch
|
||||
run: |
|
||||
./build/c3c vendor-fetch raylib5
|
||||
./build/c3c vendor-fetch raylib
|
||||
|
||||
- name: Build testproject lib
|
||||
run: |
|
||||
@@ -216,7 +216,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
build_type: [Release, Debug]
|
||||
llvm_version: [17, 18, 19]
|
||||
llvm_version: [17, 18, 19, 20]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -324,7 +324,7 @@ jobs:
|
||||
- name: Test WASM
|
||||
run: |
|
||||
cd resources/testfragments
|
||||
../../build/c3c compile --target wasm32 -g0 --no-entry -Os wasm4.c3
|
||||
../../build/c3c compile --reloc=none --target wasm32 -g0 --link-libc=no --no-entry -Os wasm4.c3
|
||||
|
||||
- name: Install QEMU and Risc-V toolchain
|
||||
run: |
|
||||
@@ -363,7 +363,7 @@ jobs:
|
||||
|
||||
- name: upload artifacts
|
||||
if: matrix.llvm_version == env.LLVM_RELEASE_VERSION_LINUX
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: c3-linux-${{matrix.build_type}}
|
||||
path: c3-linux-${{matrix.build_type}}.tar.gz
|
||||
@@ -484,7 +484,7 @@ jobs:
|
||||
|
||||
- name: upload artifacts
|
||||
if: matrix.llvm_version == env.LLVM_RELEASE_VERSION_UBUNTU20
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: c3-ubuntu-20-${{matrix.build_type}}
|
||||
path: c3-ubuntu-20-${{matrix.build_type}}.tar.gz
|
||||
@@ -496,7 +496,7 @@ jobs:
|
||||
matrix:
|
||||
ubuntu_version: [20.04, 22.04]
|
||||
build_type: [Release, Debug]
|
||||
llvm_version: [17, 18, 19]
|
||||
llvm_version: [17, 18, 19, 20]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -558,7 +558,7 @@ jobs:
|
||||
- name: Test WASM
|
||||
run: |
|
||||
cd resources/testfragments
|
||||
../../build/c3c compile --reloc=none --target wasm32 -g0 --no-entry -Os wasm4.c3
|
||||
../../build/c3c compile --reloc=none --target wasm32 -g0 --link-libc=no --no-entry -Os wasm4.c3
|
||||
|
||||
- name: Build testproject direct linker
|
||||
run: |
|
||||
@@ -607,7 +607,7 @@ jobs:
|
||||
|
||||
- name: Vendor-fetch
|
||||
run: |
|
||||
./build/c3c vendor-fetch raylib5
|
||||
./build/c3c vendor-fetch raylib
|
||||
|
||||
- name: Compile and run some examples
|
||||
run: |
|
||||
@@ -657,7 +657,7 @@ jobs:
|
||||
|
||||
- name: upload artifacts
|
||||
if: matrix.llvm_version == env.LLVM_RELEASE_VERSION_MAC
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: c3-macos-${{matrix.build_type}}
|
||||
path: c3-macos-${{matrix.build_type}}.zip
|
||||
@@ -665,7 +665,7 @@ jobs:
|
||||
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build-msvc, build-linux, build-mac, build-linux-ubuntu20]
|
||||
needs: [build-msvc, build-linux, build-mac]
|
||||
if: github.ref == 'refs/heads/master'
|
||||
|
||||
steps:
|
||||
@@ -692,22 +692,16 @@ jobs:
|
||||
sha: context.sha
|
||||
})
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
- uses: actions/download-artifact@v3
|
||||
- run: cp -r lib c3-windows-Release
|
||||
- run: cp -r lib c3-windows-Debug
|
||||
- run: cp msvc_build_libraries.py c3-windows-Release
|
||||
- run: cp msvc_build_libraries.py c3-windows-Debug
|
||||
- run: zip -r c3-windows.zip c3-windows-Release
|
||||
- run: zip -r c3-windows-debug.zip c3-windows-Debug
|
||||
- run: mv c3-linux-Release/c3-linux-Release.tar.gz c3-linux-Release/c3-linux.tar.gz
|
||||
- run: mv c3-linux-Debug/c3-linux-Debug.tar.gz c3-linux-Debug/c3-linux-debug.tar.gz
|
||||
- run: mv c3-ubuntu-20-Release/c3-ubuntu-20-Release.tar.gz c3-ubuntu-20-Release/c3-ubuntu-20.tar.gz
|
||||
- run: mv c3-ubuntu-20-Debug/c3-ubuntu-20-Debug.tar.gz c3-ubuntu-20-Debug/c3-ubuntu-20-debug.tar.gz
|
||||
- run: mv c3-macos-Release/c3-macos-Release.zip c3-macos-Release/c3-macos.zip
|
||||
- run: mv c3-macos-Debug/c3-macos-Debug.zip c3-macos-Debug/c3-macos-debug.zip
|
||||
- run: zip -r c3-windows-Release.zip c3-windows-Release
|
||||
- run: zip -r c3-windows-Debug.zip c3-windows-Debug
|
||||
|
||||
- id: create_release
|
||||
uses: softprops/action-gh-release@v2
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
@@ -715,12 +709,84 @@ jobs:
|
||||
release_name: latest
|
||||
draft: false
|
||||
prerelease: true
|
||||
files: |
|
||||
c3-windows.zip
|
||||
c3-windows-debug.zip
|
||||
c3-linux-Release/c3-linux.tar.gz
|
||||
c3-linux-Debug/c3-linux-debug.tar.gz
|
||||
c3-ubuntu-20-Release/c3-ubuntu-20.tar.gz
|
||||
c3-ubuntu-20-Debug/c3-ubuntu-20-debug.tar.gz
|
||||
c3-macos-Release/c3-macos.zip
|
||||
c3-macos-Debug/c3-macos-debug.zip
|
||||
|
||||
- name: upload windows
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: c3-windows-Release.zip
|
||||
asset_name: c3-windows.zip
|
||||
asset_content_type: application/zip
|
||||
|
||||
- name: upload windows debug
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: c3-windows-Debug.zip
|
||||
asset_name: c3-windows-debug.zip
|
||||
asset_content_type: application/zip
|
||||
|
||||
- name: upload linux
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: c3-linux-Release/c3-linux-Release.tar.gz
|
||||
asset_name: c3-linux.tar.gz
|
||||
asset_content_type: application/gzip
|
||||
|
||||
- name: upload linux debug
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: c3-linux-Debug/c3-linux-Debug.tar.gz
|
||||
asset_name: c3-linux-debug.tar.gz
|
||||
asset_content_type: application/gzip
|
||||
|
||||
- name: upload ubuntu 20
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
|
||||
asset_path: c3-ubuntu-20-Release/c3-ubuntu-20-Release.tar.gz
|
||||
asset_name: c3-ubuntu-20.tar.gz
|
||||
asset_content_type: application/gzip
|
||||
|
||||
- name: upload ubuntu 20 debug
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: c3-ubuntu-20-Debug/c3-ubuntu-20-Debug.tar.gz
|
||||
asset_name: c3-ubuntu-20-debug.tar.gz
|
||||
asset_content_type: application/gzip
|
||||
|
||||
- name: upload macos
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: c3-macos-Release/c3-macos-Release.zip
|
||||
asset_name: c3-macos.zip
|
||||
asset_content_type: application/zip
|
||||
|
||||
- name: upload macos debug
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: c3-macos-Debug/c3-macos-Debug.zip
|
||||
asset_name: c3-macos-debug.zip
|
||||
asset_content_type: application/zip
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -70,8 +70,3 @@ out/
|
||||
|
||||
# Emacs files
|
||||
TAGS
|
||||
|
||||
# Clangd LSP files
|
||||
/.cache/
|
||||
/compile_commands.json
|
||||
|
||||
|
||||
389
CMakeLists.txt
389
CMakeLists.txt
@@ -63,7 +63,6 @@ set(C3_LLVM_VERSION "auto" CACHE STRING "Use LLVM version [default: auto]")
|
||||
option(C3_USE_MIMALLOC "Use built-in mimalloc" OFF)
|
||||
option(C3_USE_TB "Use TB" OFF)
|
||||
set(C3_MIMALLOC_TAG "v1.7.3" CACHE STRING "Used version of mimalloc")
|
||||
option(C3_WITH_LLVM "Build with LLVM" ON)
|
||||
|
||||
set(C3_USE_MIMALLOC OFF)
|
||||
if(C3_USE_MIMALLOC)
|
||||
@@ -81,11 +80,9 @@ endif()
|
||||
if (NOT WIN32)
|
||||
find_package(CURL)
|
||||
endif()
|
||||
if(C3_WITH_LLVM)
|
||||
if (NOT C3_LLVM_VERSION STREQUAL "auto")
|
||||
if (${C3_LLVM_VERSION} VERSION_LESS 17 OR ${C3_LLVM_VERSION} VERSION_GREATER 20)
|
||||
message(FATAL_ERROR "LLVM ${C3_LLVM_VERSION} is not supported!")
|
||||
endif()
|
||||
if (NOT C3_LLVM_VERSION STREQUAL "auto")
|
||||
if (${C3_LLVM_VERSION} VERSION_LESS 17 OR ${C3_LLVM_VERSION} VERSION_GREATER 20)
|
||||
message(FATAL_ERROR "LLVM ${C3_LLVM_VERSION} is not supported!")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -104,126 +101,113 @@ if(C3_USE_TB AND GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
|
||||
endif()
|
||||
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)
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E create_symlink
|
||||
${CMAKE_BINARY_DIR}/compile_commands.json
|
||||
${CMAKE_SOURCE_DIR}/compile_commands.json
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
|
||||
if (C3_LLVM_VERSION STREQUAL "auto")
|
||||
set(C3_LLVM_VERSION "18")
|
||||
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
|
||||
)
|
||||
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")
|
||||
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
|
||||
)
|
||||
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
|
||||
)
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
message("Loading Windows LLVM debug libraries, this may take a while...")
|
||||
FetchContent_MakeAvailable(LLVM_Windows_debug)
|
||||
set(llvm_dir ${llvm_windows_debug_SOURCE_DIR})
|
||||
else()
|
||||
message("Loading Windows LLVM libraries, this may take a while...")
|
||||
FetchContent_MakeAvailable(LLVM_Windows)
|
||||
set(llvm_dir ${llvm_windows_SOURCE_DIR})
|
||||
endif()
|
||||
set(CMAKE_SYSTEM_PREFIX_PATH ${llvm_dir} ${CMAKE_SYSTEM_PREFIX_PATH})
|
||||
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
|
||||
)
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
message("Loading Windows LLVM debug libraries, this may take a while...")
|
||||
FetchContent_MakeAvailable(LLVM_Windows_debug)
|
||||
set(llvm_dir ${llvm_windows_debug_SOURCE_DIR})
|
||||
else()
|
||||
message("Loading Windows LLVM libraries, this may take a while...")
|
||||
FetchContent_MakeAvailable(LLVM_Windows)
|
||||
set(llvm_dir ${llvm_windows_SOURCE_DIR})
|
||||
endif()
|
||||
set(CMAKE_SYSTEM_PREFIX_PATH ${llvm_dir} ${CMAKE_SYSTEM_PREFIX_PATH})
|
||||
|
||||
find_package(LLVM REQUIRED CONFIG)
|
||||
find_package(LLD REQUIRED CONFIG)
|
||||
else()
|
||||
if (NOT C3_LLVM_VERSION STREQUAL "auto")
|
||||
find_package(LLVM ${C3_LLVM_VERSION} REQUIRED CONFIG)
|
||||
else()
|
||||
find_package(LLVM REQUIRED CONFIG)
|
||||
find_package(LLD REQUIRED CONFIG)
|
||||
else()
|
||||
if (NOT C3_LLVM_VERSION STREQUAL "auto")
|
||||
find_package(LLVM ${C3_LLVM_VERSION} REQUIRED CONFIG)
|
||||
else()
|
||||
find_package(LLVM REQUIRED CONFIG)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
|
||||
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
|
||||
message(STATUS "Libraries located in: ${LLVM_LIBRARY_DIRS}")
|
||||
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
|
||||
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
|
||||
message(STATUS "Libraries located in: ${LLVM_LIBRARY_DIRS}")
|
||||
|
||||
if (NOT LLVM_PACKAGE_VERSION VERSION_GREATER_EQUAL 15.0)
|
||||
message(FATAL_ERROR "LLVM version 15.0 or later is required.")
|
||||
endif()
|
||||
if (NOT LLVM_PACKAGE_VERSION VERSION_GREATER_EQUAL 15.0)
|
||||
message(FATAL_ERROR "LLVM version 15.0 or later is required.")
|
||||
endif()
|
||||
|
||||
if(LLVM_ENABLE_RTTI)
|
||||
message(STATUS "LLVM was built with RTTI")
|
||||
else()
|
||||
message(STATUS "LLVM was not built with RTTI")
|
||||
endif()
|
||||
if(LLVM_ENABLE_RTTI)
|
||||
message(STATUS "LLVM was built with RTTI")
|
||||
else()
|
||||
message(STATUS "LLVM was not built with RTTI")
|
||||
endif()
|
||||
|
||||
string(REPLACE "." ";" VERSION_LIST ${LLVM_PACKAGE_VERSION})
|
||||
list(GET VERSION_LIST 0 LLVM_MAJOR_VERSION)
|
||||
string(REPLACE "." ";" VERSION_LIST ${LLVM_PACKAGE_VERSION})
|
||||
list(GET VERSION_LIST 0 LLVM_MAJOR_VERSION)
|
||||
|
||||
include_directories(${LLVM_INCLUDE_DIRS})
|
||||
link_directories(${LLVM_LIBRARY_DIRS})
|
||||
add_definitions(${LLVM_DEFINITIONS})
|
||||
include_directories(${LLVM_INCLUDE_DIRS})
|
||||
link_directories(${LLVM_LIBRARY_DIRS})
|
||||
add_definitions(${LLVM_DEFINITIONS})
|
||||
|
||||
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
|
||||
)
|
||||
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
|
||||
)
|
||||
|
||||
llvm_map_components_to_libnames(llvm_libs ${LLVM_LINK_COMPONENTS})
|
||||
llvm_map_components_to_libnames(llvm_libs ${LLVM_LINK_COMPONENTS})
|
||||
|
||||
# These don't seem to be reliable on windows.
|
||||
message(STATUS "using find_library")
|
||||
find_library(LLD_COFF NAMES lldCOFF.lib lldCOFF.a liblldCOFF.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_COMMON NAMES lldCommon.lib lldCommon.a liblldCommon.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_ELF NAMES lldELF.lib lldELF.a liblldELF.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_MACHO NAMES lldMachO.lib lldMachO.a liblldMachO.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_MINGW NAMES lldMinGW.lib lldMinGW.a liblldMinGW.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_WASM NAMES lldWasm.lib lldWasm.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})
|
||||
# These don't seem to be reliable on windows.
|
||||
message(STATUS "using find_library")
|
||||
find_library(LLD_COFF NAMES lldCOFF.lib lldCOFF.a liblldCOFF.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_COMMON NAMES lldCommon.lib lldCommon.a liblldCommon.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_ELF NAMES lldELF.lib lldELF.a liblldELF.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_MACHO NAMES lldMachO.lib lldMachO.a liblldMachO.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_MINGW NAMES lldMinGW.lib lldMinGW.a liblldMinGW.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_WASM NAMES lldWasm.lib lldWasm.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})
|
||||
|
||||
# These don't seem to be reliable on windows.
|
||||
message(STATUS "using find_library")
|
||||
find_library(LLD_COFF NAMES liblldCOFF.so PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_COMMON NAMES liblldCommon.so PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_ELF NAMES liblldELF.so PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_MACHO NAMES liblldMachO.so PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_MINGW NAMES liblldMinGW.so PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_WASM NAMES liblldWasm.so PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
endif()
|
||||
# These don't seem to be reliable on windows.
|
||||
message(STATUS "using find_library")
|
||||
find_library(LLD_COFF NAMES liblldCOFF.so PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_COMMON NAMES liblldCommon.so PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_ELF NAMES liblldELF.so PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_MACHO NAMES liblldMachO.so PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_MINGW NAMES liblldMinGW.so PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_WASM NAMES liblldWasm.so PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
endif()
|
||||
|
||||
if (NOT(${CMAKE_BINARY_DIR} EQUAL ${CMAKE_SOURCE_DIR}))
|
||||
@@ -231,36 +215,36 @@ if (NOT(${CMAKE_BINARY_DIR} EQUAL ${CMAKE_SOURCE_DIR}))
|
||||
file(COPY ${CMAKE_SOURCE_DIR}/lib DESTINATION ${CMAKE_BINARY_DIR})
|
||||
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}
|
||||
find_library(LLD_LOONG NAMES libLLVMLoongArchCodeGen.lib libLLVMLoongArchAsmParser.lib libLLVMLoongArchCodeGen.a libLLVMLoongArchAsmParser.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
set(lld_libs
|
||||
${LLD_COFF}
|
||||
${LLD_COMMON}
|
||||
${LLD_WASM}
|
||||
${LLD_MINGW}
|
||||
${LLD_ELF}
|
||||
${LLD_MACHO}
|
||||
)
|
||||
|
||||
if (APPLE)
|
||||
set(lld_libs ${lld_libs} xar)
|
||||
find_file(RT_ASAN_DYNAMIC NAMES libclang_rt.asan_osx_dynamic.dylib PATHS "${LLVM_LIBRARY_DIRS}/clang/${LLVM_MAJOR_VERSION}/lib/darwin")
|
||||
find_file(RT_TSAN_DYNAMIC NAMES libclang_rt.tsan_osx_dynamic.dylib PATHS "${LLVM_LIBRARY_DIRS}/clang/${LLVM_MAJOR_VERSION}/lib/darwin")
|
||||
find_file(RT_UBSAN_DYNAMIC NAMES libclang_rt.ubsan_osx_dynamic.dylib PATHS "${LLVM_LIBRARY_DIRS}/clang/${LLVM_MAJOR_VERSION}/lib/darwin")
|
||||
find_file(RT_LSAN_DYNAMIC NAMES libclang_rt.lsan_osx_dynamic.dylib PATHS "${LLVM_LIBRARY_DIRS}/clang/${LLVM_MAJOR_VERSION}/lib/darwin")
|
||||
set(sanitizer_runtime_libraries
|
||||
${RT_ASAN_DYNAMIC}
|
||||
${RT_TSAN_DYNAMIC}
|
||||
# Unused
|
||||
# ${RT_UBSAN_DYNAMIC}
|
||||
# ${RT_LSAN_DYNAMIC}
|
||||
)
|
||||
|
||||
if (APPLE)
|
||||
set(lld_libs ${lld_libs} xar)
|
||||
find_file(RT_ASAN_DYNAMIC NAMES libclang_rt.asan_osx_dynamic.dylib PATHS "${LLVM_LIBRARY_DIRS}/clang/${LLVM_MAJOR_VERSION}/lib/darwin")
|
||||
find_file(RT_TSAN_DYNAMIC NAMES libclang_rt.tsan_osx_dynamic.dylib PATHS "${LLVM_LIBRARY_DIRS}/clang/${LLVM_MAJOR_VERSION}/lib/darwin")
|
||||
find_file(RT_UBSAN_DYNAMIC NAMES libclang_rt.ubsan_osx_dynamic.dylib PATHS "${LLVM_LIBRARY_DIRS}/clang/${LLVM_MAJOR_VERSION}/lib/darwin")
|
||||
find_file(RT_LSAN_DYNAMIC NAMES libclang_rt.lsan_osx_dynamic.dylib PATHS "${LLVM_LIBRARY_DIRS}/clang/${LLVM_MAJOR_VERSION}/lib/darwin")
|
||||
set(sanitizer_runtime_libraries
|
||||
${RT_ASAN_DYNAMIC}
|
||||
${RT_TSAN_DYNAMIC}
|
||||
# Unused
|
||||
# ${RT_UBSAN_DYNAMIC}
|
||||
# ${RT_LSAN_DYNAMIC}
|
||||
)
|
||||
endif()
|
||||
|
||||
message(STATUS "linking to llvm libs ${lld_libs}")
|
||||
message(STATUS "Found lld libs ${lld_libs}")
|
||||
endif()
|
||||
|
||||
message(STATUS "linking to llvm libs ${lld_libs}")
|
||||
message(STATUS "Found lld libs ${lld_libs}")
|
||||
|
||||
|
||||
add_library(c3c_wrappers STATIC wrapper/src/wrapper.cpp)
|
||||
add_library(miniz STATIC dependencies/miniz/miniz.c)
|
||||
|
||||
add_executable(c3c
|
||||
@@ -284,6 +268,7 @@ add_executable(c3c
|
||||
src/compiler/json_output.c
|
||||
src/compiler/lexer.c
|
||||
src/compiler/linker.c
|
||||
src/compiler/llvm_codegen.c
|
||||
src/compiler/abi/c_abi_aarch64.c
|
||||
src/compiler/abi/c_abi.c
|
||||
src/compiler/abi/c_abi_riscv.c
|
||||
@@ -291,6 +276,14 @@ add_executable(c3c
|
||||
src/compiler/abi/c_abi_win64.c
|
||||
src/compiler/abi/c_abi_x64.c
|
||||
src/compiler/abi/c_abi_x86.c
|
||||
src/compiler/llvm_codegen_debug_info.c
|
||||
src/compiler/llvm_codegen_expr.c
|
||||
src/compiler/llvm_codegen_function.c
|
||||
src/compiler/llvm_codegen_instr.c
|
||||
src/compiler/llvm_codegen_module.c
|
||||
src/compiler/llvm_codegen_stmt.c
|
||||
src/compiler/llvm_codegen_type.c
|
||||
src/compiler/llvm_codegen_value.c
|
||||
src/compiler/module.c
|
||||
src/compiler/number.c
|
||||
src/compiler/parse_expr.c
|
||||
@@ -333,59 +326,18 @@ 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/llvm_codegen_storeload.c
|
||||
src/compiler/windows_support.c
|
||||
src/compiler/codegen_asm.c
|
||||
src/compiler/asm_target.c
|
||||
src/compiler/asm_target.c
|
||||
src/compiler/llvm_codegen_builtins.c
|
||||
src/compiler/expr.c
|
||||
src/utils/time.c
|
||||
src/utils/http.c
|
||||
src/compiler/sema_liveness.c
|
||||
src/build/common_build.c
|
||||
src/compiler/sema_const.c
|
||||
${CMAKE_BINARY_DIR}/git_hash.h
|
||||
)
|
||||
src/build/common_build.c)
|
||||
|
||||
if(GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
|
||||
# We are inside of a git repository so rebuilding the hash every time something changes.
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_BINARY_DIR}/git_hash.h
|
||||
COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_LIST_DIR}/git_hash.cmake"
|
||||
DEPENDS "${CMAKE_CURRENT_LIST_DIR}/.git")
|
||||
else()
|
||||
# We are NOT inside of a git repository. Building the has only once.
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_BINARY_DIR}/git_hash.h
|
||||
COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_LIST_DIR}/git_hash.cmake")
|
||||
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_compile_definitions(c3c PUBLIC LLVM_AVAILABLE=1)
|
||||
add_library(c3c_wrappers STATIC wrapper/src/wrapper.cpp)
|
||||
else()
|
||||
target_sources(c3c PRIVATE src/utils/hostinfo.c)
|
||||
target_compile_definitions(c3c PUBLIC LLVM_AVAILABLE=0)
|
||||
endif()
|
||||
|
||||
target_include_directories(c3c PRIVATE
|
||||
"${CMAKE_SOURCE_DIR}/src/"
|
||||
"${CMAKE_BINARY_DIR}")
|
||||
|
||||
target_include_directories(miniz PUBLIC
|
||||
"${CMAKE_SOURCE_DIR}/dependencies/miniz/")
|
||||
|
||||
if (C3_USE_TB)
|
||||
file(GLOB tilde-sources
|
||||
@@ -419,29 +371,24 @@ if (C3_USE_TB)
|
||||
|
||||
target_include_directories(c3c PRIVATE
|
||||
"${CMAKE_SOURCE_DIR}/tilde-backend/include/")
|
||||
|
||||
else()
|
||||
|
||||
target_compile_definitions(c3c PUBLIC TB_AVAILABLE=0)
|
||||
|
||||
endif()
|
||||
|
||||
if(C3_WITH_LLVM)
|
||||
target_link_libraries(c3c ${llvm_libs} miniz c3c_wrappers ${lld_libs})
|
||||
|
||||
target_include_directories(c3c PRIVATE
|
||||
"${CMAKE_SOURCE_DIR}/wrapper/include/")
|
||||
target_include_directories(c3c PRIVATE
|
||||
"${CMAKE_SOURCE_DIR}/src/"
|
||||
"${CMAKE_SOURCE_DIR}/wrapper/include/")
|
||||
|
||||
target_include_directories(c3c_wrappers PRIVATE
|
||||
"${CMAKE_SOURCE_DIR}/wrapper/include/")
|
||||
|
||||
target_link_libraries(c3c_wrappers ${llvm_libs} ${lld_libs})
|
||||
target_include_directories(c3c_wrappers PRIVATE
|
||||
"${CMAKE_SOURCE_DIR}/wrapper/include/")
|
||||
|
||||
else()
|
||||
target_include_directories(miniz PUBLIC
|
||||
"${CMAKE_SOURCE_DIR}/dependencies/miniz/")
|
||||
|
||||
target_link_libraries(c3c ${llvm_libs} miniz ${lld_libs})
|
||||
|
||||
endif()
|
||||
target_link_libraries(c3c_wrappers ${llvm_libs} ${lld_libs})
|
||||
target_link_libraries(c3c ${llvm_libs} miniz c3c_wrappers ${lld_libs})
|
||||
|
||||
if(C3_USE_MIMALLOC)
|
||||
target_link_libraries(c3c mimalloc-static)
|
||||
@@ -451,11 +398,6 @@ if (WIN32)
|
||||
target_link_libraries(c3c Winhttp.lib)
|
||||
endif()
|
||||
|
||||
if(MINGW)
|
||||
message("Increase stack for msys")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--stack,8388608")
|
||||
endif ()
|
||||
|
||||
if (CURL_FOUND)
|
||||
target_link_libraries(c3c ${CURL_LIBRARIES})
|
||||
target_include_directories(c3c PRIVATE ${CURL_INCLUDES})
|
||||
@@ -464,48 +406,39 @@ else()
|
||||
target_compile_definitions(c3c PUBLIC CURL_FOUND=0)
|
||||
endif()
|
||||
|
||||
|
||||
if(MSVC)
|
||||
message("Adding MSVC options")
|
||||
target_compile_options(c3c PRIVATE /wd4068 /wd4090 /WX /Wv:18)
|
||||
if(C3_WITH_LLVM)
|
||||
target_compile_options(c3c_wrappers PUBLIC /wd4624 /wd4267 /wd4244 /WX /Wv:18)
|
||||
if(NOT LLVM_ENABLE_RTTI)
|
||||
target_compile_options(c3c_wrappers PUBLIC /GR-)
|
||||
endif()
|
||||
target_link_options(c3c_wrappers PUBLIC /ignore:4099)
|
||||
target_compile_options(c3c_wrappers PUBLIC /wd4624 /wd4267 /wd4244 /WX /Wv:18)
|
||||
if (NOT LLVM_ENABLE_RTTI)
|
||||
target_compile_options(c3c_wrappers PUBLIC /GR-)
|
||||
endif()
|
||||
target_link_options(c3c_wrappers PUBLIC /ignore:4099)
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
target_compile_options(c3c PUBLIC /MTd)
|
||||
if (C3_WITH_LLVM)
|
||||
target_compile_options(c3c_wrappers PUBLIC /MTd)
|
||||
endif()
|
||||
target_compile_options(c3c_wrappers PUBLIC /MTd)
|
||||
target_compile_options(miniz PUBLIC /MTd)
|
||||
if (C3_USE_TB)
|
||||
target_compile_options(tilde-backend PUBLIC /MTd)
|
||||
endif()
|
||||
else()
|
||||
target_compile_options(c3c PUBLIC /MT)
|
||||
if (C3_WITH_LLVM)
|
||||
target_compile_options(c3c_wrappers PUBLIC /MT)
|
||||
endif()
|
||||
target_compile_options(c3c_wrappers PUBLIC /MT)
|
||||
target_compile_options(miniz PUBLIC /MT)
|
||||
if (C3_USE_TB)
|
||||
target_compile_options(tilde-backend PUBLIC /MT)
|
||||
endif()
|
||||
endif()
|
||||
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)
|
||||
endif()
|
||||
set(clang_lib_dir ${llvm_dir}/lib/clang/${C3_LLVM_VERSION}/lib/windows)
|
||||
set(sanitizer_runtime_libraries
|
||||
${clang_lib_dir}/clang_rt.asan-x86_64.lib
|
||||
${clang_lib_dir}/clang_rt.asan_dynamic-x86_64.lib
|
||||
${clang_lib_dir}/clang_rt.asan_dynamic-x86_64.dll
|
||||
${clang_lib_dir}/clang_rt.asan_dynamic_runtime_thunk-x86_64.lib)
|
||||
else()
|
||||
message(STATUS "using gcc/clang warning switches")
|
||||
target_link_options(c3c PRIVATE -pthread)
|
||||
if (C3_WITH_LLVM AND NOT LLVM_ENABLE_RTTI)
|
||||
if (NOT LLVM_ENABLE_RTTI)
|
||||
target_compile_options(c3c_wrappers PRIVATE -fno-rtti)
|
||||
endif()
|
||||
target_compile_options(c3c PRIVATE -pthread -Wall -Werror -Wno-unknown-pragmas -Wno-unused-result
|
||||
@@ -515,7 +448,7 @@ endif()
|
||||
install(TARGETS c3c DESTINATION bin)
|
||||
install(DIRECTORY lib/ DESTINATION lib/c3)
|
||||
|
||||
if (C3_WITH_LLVM AND DEFINED sanitizer_runtime_libraries)
|
||||
if (DEFINED sanitizer_runtime_libraries)
|
||||
add_custom_command(TARGET c3c POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E rm -rf -- $<TARGET_FILE_DIR:c3c>/c3c_rt
|
||||
COMMAND "${CMAKE_COMMAND}" -E make_directory $<TARGET_FILE_DIR:c3c>/c3c_rt
|
||||
|
||||
51
README.md
51
README.md
@@ -10,8 +10,7 @@ Precompiled binaries for the following operating systems are available:
|
||||
|
||||
- Windows x64 [download](https://github.com/c3lang/c3c/releases/download/latest/c3-windows.zip), [install instructions](#installing-on-windows-with-precompiled-binaries).
|
||||
- Debian x64 [download](https://github.com/c3lang/c3c/releases/download/latest/c3-linux.tar.gz), [install instructions](#installing-on-debian-with-precompiled-binaries).
|
||||
- Ubuntu x86 [download](https://github.com/c3lang/c3c/releases/download/latest/c3-ubuntu-20.tar.gz), [install instructions](#installing-on-ubuntu-with-precompiled-binaries).
|
||||
- MacOS Arm64 [download](https://github.com/c3lang/c3c/releases/download/latest/c3-macos.zip), [install instructions](#installing-on-mac-with-precompiled-binaries).
|
||||
- MacOS x64 [download](https://github.com/c3lang/c3c/releases/download/latest/c3-macos.zip), [install instructions](#installing-on-mac-with-precompiled-binaries).
|
||||
|
||||
The manual for C3 can be found at [www.c3-lang.org](http://www.c3-lang.org).
|
||||
|
||||
@@ -35,7 +34,7 @@ whole new language.
|
||||
|
||||
The following code shows [generic modules](https://c3-lang.org/references/docs/generics/) (more examples can be found at https://c3-lang.org/references/docs/examples/).
|
||||
|
||||
```cpp
|
||||
```c++
|
||||
module stack (<Type>);
|
||||
// Above: the parameterized type is applied to the entire module.
|
||||
|
||||
@@ -138,7 +137,7 @@ fn void main()
|
||||
|
||||
### Current status
|
||||
|
||||
The current stable version of the compiler is **version 0.6.2**.
|
||||
The current stable version of the compiler is **version 0.6.1**.
|
||||
|
||||
The upcoming 0.6.x releases will focus on expanding the standard library.
|
||||
Follow the issues [here](https://github.com/c3lang/c3c/issues).
|
||||
@@ -206,13 +205,7 @@ More platforms will be supported in the future.
|
||||
2. Unpack executable and standard lib.
|
||||
3. Run `./c3c`.
|
||||
|
||||
#### Installing on Ubuntu with precompiled binaries
|
||||
1. Download tar file: [https://github.com/c3lang/c3c/releases/download/latest/c3-ubuntu-20.tar.gz](https://github.com/c3lang/c3c/releases/download/latest/c3-ubuntu-20.tar.gz)
|
||||
(debug version [here](https://github.com/c3lang/c3c/releases/download/latest/c3-ubuntu-20-debug.tar.gz))
|
||||
2. Unpack executable and standard lib.
|
||||
3. Run `./c3c`.
|
||||
|
||||
#### Installing on MacOS with precompiled binaries
|
||||
#### Installing on Mac with precompiled binaries
|
||||
1. Make sure you have XCode with command line tools installed.
|
||||
2. Download the zip file: [https://github.com/c3lang/c3c/releases/download/latest/c3-macos.zip](https://github.com/c3lang/c3c/releases/download/latest/c3-macos.zip)
|
||||
(debug version [here](https://github.com/c3lang/c3c/releases/download/latest/c3-macos-debug.zip))
|
||||
@@ -222,16 +215,9 @@ More platforms will be supported in the future.
|
||||
(*Note that there is a known issue with debug symbol generation on MacOS 13, see [issue #1086](https://github.com/c3lang/c3c/issues/1086))
|
||||
|
||||
#### Installing on Arch Linux
|
||||
Arch includes c3c in the official 'extra' repo. It can be easily installed the usual way:
|
||||
There is an AUR package for the c3c compiler : [c3c-git](https://aur.archlinux.org/packages/c3c-git).
|
||||
|
||||
```sh
|
||||
sudo pacman -S c3c
|
||||
# or paru -S c3c
|
||||
# or yay -S c3c
|
||||
# or aura -A c3c
|
||||
```
|
||||
|
||||
There is also an AUR package for the c3c compiler : [c3c-git](https://aur.archlinux.org/packages/c3c-git).
|
||||
Due to some issues with the LLVM packaged for Arch Linux, the AUR package will download and use LLVM 16 for Ubuntu-23.04 to compile the c3c compiler.
|
||||
|
||||
You can use your AUR package manager:
|
||||
```sh
|
||||
@@ -318,16 +304,17 @@ You can try it out by running some sample code: `c3c.exe compile ../resources/ex
|
||||
*Note that if you run into linking issues when building, make sure that you are using the latest version of VS17.*
|
||||
|
||||
|
||||
#### Compiling on Ubuntu 24.04 LTS
|
||||
#### Compiling on Ubuntu 20.10
|
||||
|
||||
1. Make sure you have a C compiler that handles C11 and a C++ compiler, such as GCC or Clang. Git also needs to be installed.
|
||||
2. Install LLVM 18 `sudo apt-get install cmake git clang zlib1g zlib1g-dev libllvm18 llvm llvm-dev llvm-runtime liblld-dev liblld-18 libpolly-18-dev`
|
||||
3. Clone the C3C github repository: `git clone https://github.com/c3lang/c3c.git`
|
||||
4. Enter the C3C directory `cd c3c`.
|
||||
5. Create a build directory `mkdir build`
|
||||
6. Change directory to the build directory `cd build`
|
||||
7. Set up CMake build: `cmake ..`
|
||||
8. Build: `cmake --build .`
|
||||
2. Install CMake: `sudo apt install cmake`
|
||||
3. Install LLVM 17+ (or greater: C3C supports LLVM 17+): `sudo apt-get install clang-17 zlib1g zlib1g-dev libllvm17 llvm-17 llvm-17-dev llvm-17-runtime liblld-17-dev liblld-17`
|
||||
4. Clone the C3C github repository: `git clone https://github.com/c3lang/c3c.git`
|
||||
5. Enter the C3C directory `cd c3c`.
|
||||
6. Create a build directory `mkdir build`
|
||||
7. Change directory to the build directory `cd build`
|
||||
8. Set up CMake build: `cmake ..`
|
||||
9. Build: `cmake --build .`
|
||||
|
||||
You should now have a `c3c` executable.
|
||||
|
||||
@@ -336,7 +323,7 @@ You can try it out by running some sample code: `./c3c compile ../resources/exam
|
||||
|
||||
#### Compiling on Void Linux
|
||||
|
||||
1. As root, ensure that all project dependencies are installed: `xbps-install git cmake llvm17 llvm17-devel lld17-devel libcurl-devel ncurses-devel zlib-devel libzstd-devel libxml2-devel`
|
||||
1. As root, ensure that all project dependencies are installed: `xbps-install git cmake llvm17 lld17-devel libcurl-devel ncurses-devel zlib-devel libzstd-devel libxml2-devel`
|
||||
2. Clone the C3C repository: `git clone https://github.com/c3lang/c3c.git`
|
||||
- If you only need the latest commit, you may want to make a shallow clone instead: `git clone https://github.com/c3lang/c3c.git --depth=1`
|
||||
3. Enter the directory: `cd c3c`
|
||||
@@ -382,9 +369,3 @@ Editor plugins can be found at https://github.com/c3lang/editor-plugins.
|
||||
3. Run tests and see that they pass. (Recommended settings: `c3c compile-test -O0 test/unit`.
|
||||
- in this example `test/unit/` is the relative path to the test directory, so adjust as required)
|
||||
4. Make a pull request for the new tests.
|
||||
|
||||
## Thank yous
|
||||
|
||||
A huge "thank you" goes out to all contributors and sponsors.
|
||||
|
||||
A special thank you to sponsor [Caleb-o](https://github.com/Caleb-o) for going the extra mile.
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
find_package(Git QUIET)
|
||||
|
||||
set(GIT_HASH "unknown")
|
||||
|
||||
if(GIT_FOUND AND EXISTS "${CMAKE_CURRENT_LIST_DIR}/.git")
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse HEAD
|
||||
OUTPUT_VARIABLE GIT_HASH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
COMMAND_ERROR_IS_FATAL ANY)
|
||||
endif()
|
||||
|
||||
message("Git Hash: ${GIT_HASH}")
|
||||
|
||||
file(WRITE ${CMAKE_BINARY_DIR}/git_hash.h "#pragma once\n#define GIT_HASH \"${GIT_HASH}\"\n")
|
||||
@@ -18,18 +18,9 @@ struct AnyList (Printable)
|
||||
|
||||
/**
|
||||
* @param initial_capacity "The initial capacity to reserve"
|
||||
* Use `init` for to use a custom allocator.
|
||||
* @param [&inout] allocator "The allocator to use, defaults to the heap allocator"
|
||||
**/
|
||||
fn AnyList* AnyList.new_init(&self, usz initial_capacity = 16, Allocator allocator = null)
|
||||
{
|
||||
return self.init(allocator ?: allocator::heap(), initial_capacity) @inline;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [&inout] allocator "The allocator to use"
|
||||
* @param initial_capacity "The initial capacity to reserve"
|
||||
**/
|
||||
fn AnyList* AnyList.init(&self, Allocator allocator, usz initial_capacity = 16)
|
||||
fn AnyList* AnyList.new_init(&self, usz initial_capacity = 16, Allocator allocator = allocator::heap())
|
||||
{
|
||||
self.allocator = allocator;
|
||||
self.size = 0;
|
||||
@@ -53,7 +44,7 @@ fn AnyList* AnyList.init(&self, Allocator allocator, usz initial_capacity = 16)
|
||||
**/
|
||||
fn AnyList* AnyList.temp_init(&self, usz initial_capacity = 16)
|
||||
{
|
||||
return self.init(allocator::temp(), initial_capacity) @inline;
|
||||
return self.new_init(initial_capacity, allocator::temp()) @inline;
|
||||
}
|
||||
|
||||
fn usz! AnyList.to_format(&self, Formatter* formatter) @dynamic
|
||||
@@ -76,19 +67,16 @@ fn usz! AnyList.to_format(&self, Formatter* formatter) @dynamic
|
||||
}
|
||||
}
|
||||
|
||||
fn String AnyList.to_new_string(&self, Allocator allocator = null) @dynamic
|
||||
fn String AnyList.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic
|
||||
{
|
||||
return string::format("%s", *self, allocator: allocator ?: allocator::heap());
|
||||
return string::new_format("%s", *self, .allocator = allocator);
|
||||
}
|
||||
|
||||
|
||||
fn String AnyList.to_string(&self, Allocator allocator) @dynamic
|
||||
fn String AnyList.to_tstring(&self)
|
||||
{
|
||||
return string::format("%s", *self, allocator: allocator);
|
||||
return string::tformat("%s", *self);
|
||||
}
|
||||
|
||||
fn String AnyList.to_tstring(&self) => string::tformat("%s", *self);
|
||||
|
||||
/**
|
||||
* Push an element on the list by cloning it.
|
||||
**/
|
||||
@@ -129,35 +117,18 @@ macro AnyList.pop(&self, $Type)
|
||||
* Pop the last value and allocate the copy using the given allocator.
|
||||
* @return! IteratorResult.NO_MORE_ELEMENT
|
||||
**/
|
||||
fn any! AnyList.copy_pop(&self, Allocator allocator = allocator::heap())
|
||||
fn any! AnyList.new_pop(&self, Allocator allocator = allocator::heap())
|
||||
{
|
||||
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
|
||||
defer self.free_element(self.entries[self.size]);
|
||||
return allocator::clone_any(allocator, self.entries[--self.size]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pop the last value and allocate the copy using the given allocator.
|
||||
* @return! IteratorResult.NO_MORE_ELEMENT
|
||||
* @deprecated `use copy_pop`
|
||||
**/
|
||||
fn any! AnyList.new_pop(&self, Allocator allocator = allocator::heap())
|
||||
{
|
||||
return self.copy_pop(allocator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pop the last value and allocate the copy using the temp allocator
|
||||
* @return! IteratorResult.NO_MORE_ELEMENT
|
||||
* @deprecated `use tcopy_pop`
|
||||
**/
|
||||
fn any! AnyList.temp_pop(&self) => self.copy_pop(allocator::temp());
|
||||
|
||||
/**
|
||||
* Pop the last value and allocate the copy using the temp allocator
|
||||
* @return! IteratorResult.NO_MORE_ELEMENT
|
||||
**/
|
||||
fn any! AnyList.tcopy_pop(&self) => self.copy_pop(allocator::temp());
|
||||
fn any! AnyList.temp_pop(&self) => self.new_pop(allocator::temp());
|
||||
|
||||
/**
|
||||
* Pop the last value. It must later be released using list.free_element()
|
||||
@@ -200,17 +171,8 @@ fn any! AnyList.pop_first_retained(&self)
|
||||
|
||||
/**
|
||||
* Same as new_pop() but pops the first value instead.
|
||||
* @deprecated `use copy_pop_first`
|
||||
**/
|
||||
fn any! AnyList.new_pop_first(&self, Allocator allocator = allocator::heap())
|
||||
{
|
||||
return self.copy_pop_first(allocator) @inline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as new_pop() but pops the first value instead.
|
||||
**/
|
||||
fn any! AnyList.copy_pop_first(&self, Allocator allocator = allocator::heap())
|
||||
{
|
||||
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
|
||||
defer self.free_element(self.entries[self.size]);
|
||||
@@ -221,12 +183,6 @@ fn any! AnyList.copy_pop_first(&self, Allocator allocator = allocator::heap())
|
||||
/**
|
||||
* Same as temp_pop() but pops the first value instead.
|
||||
**/
|
||||
fn any! AnyList.tcopy_pop_first(&self) => self.copy_pop_first(allocator::temp());
|
||||
|
||||
/**
|
||||
* Same as temp_pop() but pops the first value instead.
|
||||
* @deprecated `use tcopy_pop_first`
|
||||
**/
|
||||
fn any! AnyList.temp_pop_first(&self) => self.new_pop_first(allocator::temp());
|
||||
|
||||
/**
|
||||
|
||||
@@ -41,12 +41,7 @@ fn usz! ElasticArray.to_format(&self, Formatter* formatter) @dynamic
|
||||
|
||||
fn String ElasticArray.to_string(&self, Allocator allocator) @dynamic
|
||||
{
|
||||
return string::format("%s", *self, allocator: allocator);
|
||||
}
|
||||
|
||||
fn String ElasticArray.to_new_string(&self, Allocator allocator = nul) @dynamic
|
||||
{
|
||||
return string::format("%s", *self, allocator: allocator ?: allocator::heap());
|
||||
return string::new_format("%s", *self, .allocator = allocator);
|
||||
}
|
||||
|
||||
fn String ElasticArray.to_tstring(&self)
|
||||
@@ -163,15 +158,7 @@ fn void ElasticArray.add_array(&self, Type[] array)
|
||||
/**
|
||||
* IMPORTANT The returned array must be freed using free_aligned.
|
||||
**/
|
||||
fn Type[] ElasticArray.to_new_aligned_array(&self)
|
||||
{
|
||||
return list_common::list_to_new_aligned_array(Type, self, allocator::heap());
|
||||
}
|
||||
|
||||
/**
|
||||
* IMPORTANT The returned array must be freed using free_aligned.
|
||||
**/
|
||||
fn Type[] ElasticArray.to_aligned_array(&self, Allocator allocator)
|
||||
fn Type[] ElasticArray.to_new_aligned_array(&self, Allocator allocator = allocator::heap())
|
||||
{
|
||||
return list_common::list_to_new_aligned_array(Type, self, allocator);
|
||||
}
|
||||
@@ -179,15 +166,7 @@ fn Type[] ElasticArray.to_aligned_array(&self, Allocator allocator)
|
||||
/**
|
||||
* @require !type_is_overaligned() : "This function is not available on overaligned types"
|
||||
**/
|
||||
macro Type[] ElasticArray.to_new_array(&self)
|
||||
{
|
||||
return list_common::list_to_array(Type, self, allocator::heap());
|
||||
}
|
||||
|
||||
/**
|
||||
* @require !type_is_overaligned() : "This function is not available on overaligned types"
|
||||
**/
|
||||
macro Type[] ElasticArray.to_array(&self, Allocator allocator)
|
||||
macro Type[] ElasticArray.to_new_array(&self, Allocator allocator = allocator::heap())
|
||||
{
|
||||
return list_common::list_to_new_array(Type, self, allocator);
|
||||
}
|
||||
@@ -195,9 +174,9 @@ macro Type[] ElasticArray.to_array(&self, Allocator allocator)
|
||||
fn Type[] ElasticArray.to_tarray(&self)
|
||||
{
|
||||
$if type_is_overaligned():
|
||||
return self.to_aligned_array(allocator::temp());
|
||||
return self.to_new_aligned_array(allocator::temp());
|
||||
$else
|
||||
return self.to_array(allocator::temp());
|
||||
return self.to_new_array(allocator::temp());
|
||||
$endif;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
/**
|
||||
* @require Enum.kindof == TypeKind.ENUM : "Only enums may be used with an enummap"
|
||||
**/
|
||||
module std::collections::enummap(<Enum, ValueType>);
|
||||
import std::io;
|
||||
struct EnumMap (Printable)
|
||||
@@ -28,14 +25,9 @@ fn usz! EnumMap.to_format(&self, Formatter* formatter) @dynamic
|
||||
return n;
|
||||
}
|
||||
|
||||
fn String EnumMap.to_string(&self, Allocator allocator) @dynamic
|
||||
fn String EnumMap.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic
|
||||
{
|
||||
return string::format("%s", *self, allocator: allocator);
|
||||
}
|
||||
|
||||
fn String EnumMap.to_new_string(&self, Allocator allocator = null) @dynamic
|
||||
{
|
||||
return string::format("%s", *self, allocator: allocator ?: allocator::heap());
|
||||
return string::new_format("%s", *self, .allocator = allocator);
|
||||
}
|
||||
|
||||
fn String EnumMap.to_tstring(&self) @dynamic
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
|
||||
/**
|
||||
* @require Enum.kindof == TypeKind.ENUM : "Only enums may be used with an enumset"
|
||||
* @require Enum.kindof == TypeKind.ENUM : "Only enums maybe be used with an enumset"
|
||||
**/
|
||||
module std::collections::enumset(<Enum>);
|
||||
import std::io;
|
||||
@@ -143,12 +143,7 @@ fn usz! EnumSet.to_format(&set, Formatter* formatter) @dynamic
|
||||
|
||||
fn String EnumSet.to_new_string(&set, Allocator allocator = allocator::heap()) @dynamic
|
||||
{
|
||||
return string::format("%s", *set, allocator: allocator);
|
||||
}
|
||||
|
||||
fn String EnumSet.to_string(&set, Allocator allocator) @dynamic
|
||||
{
|
||||
return string::format("%s", *set, allocator: allocator);
|
||||
return string::new_format("%s", *set, .allocator = allocator);
|
||||
}
|
||||
|
||||
fn String EnumSet.to_tstring(&set) @dynamic
|
||||
|
||||
@@ -20,19 +20,7 @@ struct HashMap
|
||||
* @require !self.allocator "Map was already initialized"
|
||||
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
|
||||
**/
|
||||
fn HashMap* HashMap.new_init(&self, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = null)
|
||||
{
|
||||
return self.init(allocator ?: allocator::heap(), capacity, load_factor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [&inout] allocator "The allocator to use"
|
||||
* @require capacity > 0 "The capacity must be 1 or higher"
|
||||
* @require load_factor > 0.0 "The load factor must be higher than 0"
|
||||
* @require !self.allocator "Map was already initialized"
|
||||
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
|
||||
**/
|
||||
fn HashMap* HashMap.init(&self, Allocator allocator, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR)
|
||||
fn HashMap* HashMap.new_init(&self, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap())
|
||||
{
|
||||
capacity = math::next_power_of_2(capacity);
|
||||
self.allocator = allocator;
|
||||
@@ -50,83 +38,9 @@ fn HashMap* HashMap.init(&self, Allocator allocator, uint capacity = DEFAULT_INI
|
||||
**/
|
||||
fn HashMap* HashMap.temp_init(&self, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR)
|
||||
{
|
||||
return self.init(allocator::temp(), capacity, load_factor) @inline;
|
||||
return self.new_init(capacity, load_factor, allocator::temp()) @inline;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [&inout] allocator "The allocator to use"
|
||||
* @require $vacount % 2 == 0 "There must be an even number of arguments provided for keys and values"
|
||||
* @require capacity > 0 "The capacity must be 1 or higher"
|
||||
* @require load_factor > 0.0 "The load factor must be higher than 0"
|
||||
* @require !self.allocator "Map was already initialized"
|
||||
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
|
||||
**/
|
||||
macro HashMap* HashMap.new_init_with_key_values(&self, ..., uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap())
|
||||
{
|
||||
self.new_init(capacity, load_factor, allocator);
|
||||
$for (var $i = 0; $i < $vacount; $i += 2)
|
||||
self.set($vaarg[$i], $vaarg[$i+1]);
|
||||
$endfor
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [in] keys "The keys for the HashMap entries"
|
||||
* @param [in] values "The values for the HashMap entries"
|
||||
* @param [&inout] allocator "The allocator to use"
|
||||
* @require keys.len == values.len "Both keys and values arrays must be the same length"
|
||||
* @require capacity > 0 "The capacity must be 1 or higher"
|
||||
* @require load_factor > 0.0 "The load factor must be higher than 0"
|
||||
* @require !self.allocator "Map was already initialized"
|
||||
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
|
||||
**/
|
||||
fn HashMap* HashMap.new_init_from_keys_and_values(&self, Key[] keys, Value[] values, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap())
|
||||
{
|
||||
assert(keys.len == values.len);
|
||||
self.new_init(capacity, load_factor, allocator);
|
||||
for (usz i = 0; i < keys.len; i++)
|
||||
{
|
||||
self.set(keys[i], values[i]);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require $vacount % 2 == 0 "There must be an even number of arguments provided for keys and values"
|
||||
* @require capacity > 0 "The capacity must be 1 or higher"
|
||||
* @require load_factor > 0.0 "The load factor must be higher than 0"
|
||||
* @require !self.allocator "Map was already initialized"
|
||||
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
|
||||
**/
|
||||
macro HashMap* HashMap.temp_init_with_key_values(&self, ..., uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR)
|
||||
{
|
||||
self.temp_init(capacity, load_factor);
|
||||
$for (var $i = 0; $i < $vacount; $i += 2)
|
||||
self.set($vaarg[$i], $vaarg[$i+1]);
|
||||
$endfor
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [in] keys "The keys for the HashMap entries"
|
||||
* @param [in] values "The values for the HashMap entries"
|
||||
* @param [&inout] allocator "The allocator to use"
|
||||
* @require keys.len == values.len "Both keys and values arrays must be the same length"
|
||||
* @require capacity > 0 "The capacity must be 1 or higher"
|
||||
* @require load_factor > 0.0 "The load factor must be higher than 0"
|
||||
* @require !self.allocator "Map was already initialized"
|
||||
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
|
||||
**/
|
||||
fn HashMap* HashMap.temp_init_from_keys_and_values(&self, Key[] keys, Value[] values, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap())
|
||||
{
|
||||
assert(keys.len == values.len);
|
||||
self.temp_init(capacity, load_factor);
|
||||
for (usz i = 0; i < keys.len; i++)
|
||||
{
|
||||
self.set(keys[i], values[i]);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* Has this hash map been initialized yet?
|
||||
@@ -139,19 +53,11 @@ fn bool HashMap.is_initialized(&map)
|
||||
return (bool)map.allocator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [&in] other_map "The map to copy from."
|
||||
**/
|
||||
fn HashMap* HashMap.new_init_from_map(&self, HashMap* other_map)
|
||||
{
|
||||
return self.init_from_map(other_map, allocator::heap()) @inline;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [&inout] allocator "The allocator to use"
|
||||
* @param [&in] other_map "The map to copy from."
|
||||
**/
|
||||
fn HashMap* HashMap.init_from_map(&self, HashMap* other_map, Allocator allocator)
|
||||
fn HashMap* HashMap.new_init_from_map(&self, HashMap* other_map, Allocator allocator = allocator::heap())
|
||||
{
|
||||
self.new_init(other_map.table.len, other_map.load_factor, allocator);
|
||||
self.put_all_for_create(other_map);
|
||||
@@ -163,7 +69,7 @@ fn HashMap* HashMap.init_from_map(&self, HashMap* other_map, Allocator allocator
|
||||
**/
|
||||
fn HashMap* HashMap.temp_init_from_map(&map, HashMap* other_map)
|
||||
{
|
||||
return map.init_from_map(other_map, allocator::temp()) @inline;
|
||||
return map.new_init_from_map(other_map, allocator::temp()) @inline;
|
||||
}
|
||||
|
||||
fn bool HashMap.is_empty(&map) @inline
|
||||
@@ -285,25 +191,12 @@ fn void HashMap.free(&map)
|
||||
map.table = {};
|
||||
}
|
||||
|
||||
fn Key[] HashMap.tcopy_keys(&map)
|
||||
fn Key[] HashMap.key_tlist(&map)
|
||||
{
|
||||
return map.copy_keys(allocator::temp()) @inline;
|
||||
return map.key_new_list(allocator::temp()) @inline;
|
||||
}
|
||||
|
||||
fn Key[] HashMap.key_tlist(&map) @deprecated("Use 'tcopy_keys'")
|
||||
{
|
||||
return map.copy_keys(allocator::temp()) @inline;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated "use copy_keys"
|
||||
**/
|
||||
fn Key[] HashMap.key_new_list(&map, Allocator allocator = allocator::heap())
|
||||
{
|
||||
return map.copy_keys() @inline;
|
||||
}
|
||||
|
||||
fn Key[] HashMap.copy_keys(&map, Allocator allocator = allocator::heap())
|
||||
{
|
||||
if (!map.count) return {};
|
||||
|
||||
@@ -342,28 +235,12 @@ macro HashMap.@each_entry(map; @body(entry))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated `use tcopy_values`
|
||||
**/
|
||||
fn Value[] HashMap.value_tlist(&map)
|
||||
{
|
||||
return map.copy_values(allocator::temp()) @inline;
|
||||
return map.value_new_list(allocator::temp()) @inline;
|
||||
}
|
||||
|
||||
fn Value[] HashMap.tcopy_values(&map)
|
||||
{
|
||||
return map.copy_values(allocator::temp()) @inline;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated `use copy_values`
|
||||
**/
|
||||
fn Value[] HashMap.value_new_list(&map, Allocator allocator = allocator::heap())
|
||||
{
|
||||
return map.copy_values(allocator);
|
||||
}
|
||||
|
||||
fn Value[] HashMap.copy_values(&map, Allocator allocator = allocator::heap())
|
||||
{
|
||||
if (!map.count) return {};
|
||||
Value[] list = allocator::alloc_array(allocator, Value, map.count);
|
||||
|
||||
@@ -24,24 +24,16 @@ struct LinkedList
|
||||
* @param [&inout] allocator "The allocator to use, defaults to the heap allocator"
|
||||
* @return "the initialized list"
|
||||
**/
|
||||
fn LinkedList* LinkedList.init(&self, Allocator allocator)
|
||||
fn LinkedList* LinkedList.new_init(&self, Allocator allocator = allocator::heap())
|
||||
{
|
||||
*self = { .allocator = allocator };
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return "the initialized list"
|
||||
**/
|
||||
fn LinkedList* LinkedList.new_init(&self)
|
||||
{
|
||||
return self.init(allocator::heap()) @inline;
|
||||
}
|
||||
|
||||
|
||||
fn LinkedList* LinkedList.temp_init(&self)
|
||||
{
|
||||
return self.init(allocator::temp()) @inline;
|
||||
return self.new_init(allocator::temp()) @inline;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -102,7 +102,7 @@ fn usz! List.to_format(&self, Formatter* formatter) @dynamic
|
||||
|
||||
fn String List.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic
|
||||
{
|
||||
return string::format("%s", *self, allocator: allocator);
|
||||
return string::new_format("%s", *self, .allocator = allocator);
|
||||
}
|
||||
|
||||
fn String List.to_tstring(&self)
|
||||
@@ -352,7 +352,7 @@ fn void List.ensure_capacity(&self, usz min_capacity) @local
|
||||
|
||||
min_capacity = math::next_power_of_2(min_capacity);
|
||||
$if type_is_overaligned():
|
||||
self.entries = allocator::realloc_aligned(self.allocator, self.entries, Type.sizeof * min_capacity, alignment: Type[1].alignof)!!;
|
||||
self.entries = allocator::realloc_aligned(self.allocator, self.entries, Type.sizeof * min_capacity, .alignment = Type[1].alignof)!!;
|
||||
$else
|
||||
self.entries = allocator::realloc(self.allocator, self.entries, Type.sizeof * min_capacity);
|
||||
$endif;
|
||||
|
||||
@@ -45,77 +45,6 @@ fn Map temp(uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAUL
|
||||
return (Map)map;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [&inout] allocator "The allocator to use"
|
||||
* @require $vacount % 2 == 0 "There must be an even number of arguments provided for keys and values"
|
||||
* @require capacity > 0 "The capacity must be 1 or higher"
|
||||
* @require load_factor > 0.0 "The load factor must be higher than 0"
|
||||
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
|
||||
**/
|
||||
macro Map new_init_with_key_values(..., uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap())
|
||||
{
|
||||
Map map = new(capacity, load_factor, allocator);
|
||||
$for (var $i = 0; $i < $vacount; $i += 2)
|
||||
map.set($vaarg[$i], $vaarg[$i+1]);
|
||||
$endfor
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [in] keys "Array of keys for the Map entries"
|
||||
* @param [in] values "Array of values for the Map entries"
|
||||
* @param [&inout] allocator "The allocator to use"
|
||||
* @require keys.len == values.len "Both keys and values arrays must be the same length"
|
||||
* @require capacity > 0 "The capacity must be 1 or higher"
|
||||
* @require load_factor > 0.0 "The load factor must be higher than 0"
|
||||
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
|
||||
**/
|
||||
fn Map new_init_from_keys_and_values(Key[] keys, Value[] values, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap())
|
||||
{
|
||||
assert(keys.len == values.len);
|
||||
Map map = new(capacity, load_factor, allocator);
|
||||
for (usz i = 0; i < keys.len; i++)
|
||||
{
|
||||
map.set(keys[i], values[i]);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require $vacount % 2 == 0 "There must be an even number of arguments provided for keys and values"
|
||||
* @require capacity > 0 "The capacity must be 1 or higher"
|
||||
* @require load_factor > 0.0 "The load factor must be higher than 0"
|
||||
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
|
||||
**/
|
||||
macro Map temp_new_with_key_values(..., uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR)
|
||||
{
|
||||
Map map = temp(capacity, load_factor);
|
||||
$for (var $i = 0; $i < $vacount; $i += 2)
|
||||
map.set($vaarg[$i], $vaarg[$i+1]);
|
||||
$endfor
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [in] keys "The keys for the HashMap entries"
|
||||
* @param [in] values "The values for the HashMap entries"
|
||||
* @param [&inout] allocator "The allocator to use"
|
||||
* @require keys.len == values.len "Both keys and values arrays must be the same length"
|
||||
* @require capacity > 0 "The capacity must be 1 or higher"
|
||||
* @require load_factor > 0.0 "The load factor must be higher than 0"
|
||||
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
|
||||
**/
|
||||
fn Map temp_init_from_keys_and_values(Key[] keys, Value[] values, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap())
|
||||
{
|
||||
assert(keys.len == values.len);
|
||||
Map map = temp(capacity, load_factor);
|
||||
for (usz i = 0; i < keys.len; i++)
|
||||
{
|
||||
map.set(keys[i], values[i]);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [&in] other_map "The map to copy from."
|
||||
**/
|
||||
@@ -124,7 +53,7 @@ fn Map new_from_map(Map other_map, Allocator allocator = null)
|
||||
MapImpl* other_map_impl = (MapImpl*)other_map;
|
||||
if (!other_map_impl)
|
||||
{
|
||||
if (allocator) return new(allocator: allocator);
|
||||
if (allocator) return new(.allocator = allocator);
|
||||
return null;
|
||||
}
|
||||
MapImpl* map = (MapImpl*)new(other_map_impl.table.len, other_map_impl.load_factor, allocator ?: allocator::heap());
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module std::collections::maybe(<Type>);
|
||||
|
||||
struct Maybe @adhoc
|
||||
struct Maybe
|
||||
{
|
||||
Type value;
|
||||
bool has_value;
|
||||
|
||||
@@ -128,9 +128,9 @@ fn void Object.free(&self)
|
||||
self.array.free();
|
||||
case ObjectInternalMap:
|
||||
self.map.@each_entry(; ObjectInternalMapEntry* entry) {
|
||||
allocator::free(self.allocator, entry.key);
|
||||
entry.value.free();
|
||||
};
|
||||
self.map.free();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -156,7 +156,7 @@ fn void Object.init_map_if_needed(&self) @private
|
||||
if (self.is_empty())
|
||||
{
|
||||
self.type = ObjectInternalMap.typeid;
|
||||
self.map.new_init(allocator: self.allocator);
|
||||
self.map.new_init(.allocator = self.allocator);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,7 +168,7 @@ fn void Object.init_array_if_needed(&self) @private
|
||||
if (self.is_empty())
|
||||
{
|
||||
self.type = ObjectInternalList.typeid;
|
||||
self.array.new_init(allocator: self.allocator);
|
||||
self.array.new_init(.allocator = self.allocator);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,9 +181,10 @@ fn void Object.set_object(&self, String key, Object* new_object) @private
|
||||
ObjectInternalMapEntry*! entry = self.map.get_entry(key);
|
||||
defer
|
||||
{
|
||||
(void)allocator::free(self.allocator, entry.key);
|
||||
(void)entry.value.free();
|
||||
}
|
||||
self.map.set(key, new_object);
|
||||
self.map.set(key.copy(self.map.allocator), new_object);
|
||||
}
|
||||
|
||||
macro Object* Object.object_from_value(&self, value) @private
|
||||
|
||||
@@ -29,19 +29,14 @@ fn Type Range.get(&self, usz index) @operator([])
|
||||
return (Type)(self.start + (usz)index);
|
||||
}
|
||||
|
||||
fn String Range.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic @deprecated
|
||||
fn String Range.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic
|
||||
{
|
||||
return string::format("[%s..%s]", self.start, self.end, allocator: allocator);
|
||||
}
|
||||
|
||||
fn String Range.to_string(&self, Allocator allocator) @dynamic
|
||||
{
|
||||
return string::format("[%s..%s]", self.start, self.end, allocator: allocator);
|
||||
return string::new_format("[%s..%s]", self.start, self.end, .allocator = allocator);
|
||||
}
|
||||
|
||||
fn String Range.to_tstring(&self)
|
||||
{
|
||||
return self.to_string(allocator::temp());
|
||||
return self.to_new_string(allocator::temp());
|
||||
}
|
||||
|
||||
fn usz! Range.to_format(&self, Formatter* formatter) @dynamic
|
||||
@@ -71,14 +66,9 @@ fn usz! ExclusiveRange.to_format(&self, Formatter* formatter) @dynamic
|
||||
return formatter.printf("[%s..<%s]", self.start, self.end)!;
|
||||
}
|
||||
|
||||
fn String ExclusiveRange.to_new_string(&self, Allocator allocator = null) @dynamic
|
||||
fn String ExclusiveRange.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic
|
||||
{
|
||||
return self.to_string(allocator ?: allocator::heap());
|
||||
}
|
||||
|
||||
fn String ExclusiveRange.to_string(&self, Allocator allocator) @dynamic
|
||||
{
|
||||
return string::format("[%s..<%s]", self.start, self.end, allocator: allocator);
|
||||
return string::new_format("[%s..<%s]", self.start, self.end, .allocator = allocator);
|
||||
}
|
||||
|
||||
fn String ExclusiveRange.to_tstring(&self)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module std::collections::tuple(<Type1, Type2>);
|
||||
|
||||
struct Tuple @adhoc
|
||||
struct Tuple
|
||||
{
|
||||
Type1 first;
|
||||
Type2 second;
|
||||
@@ -8,7 +8,7 @@ struct Tuple @adhoc
|
||||
|
||||
module std::collections::triple(<Type1, Type2, Type3>);
|
||||
|
||||
struct Triple @adhoc
|
||||
struct Triple
|
||||
{
|
||||
Type1 first;
|
||||
Type2 second;
|
||||
|
||||
@@ -1,476 +0,0 @@
|
||||
module std::compression::qoi;
|
||||
|
||||
const uint PIXELS_MAX = 400000000;
|
||||
|
||||
/**
|
||||
* Colorspace.
|
||||
* Purely informative. It will be saved to the file header,
|
||||
* but does not affect how chunks are en-/decoded.
|
||||
*/
|
||||
enum QOIColorspace : char (char id)
|
||||
{
|
||||
SRGB = 0, // sRGB with linear alpha
|
||||
LINEAR = 1 // all channels linear
|
||||
}
|
||||
|
||||
/**
|
||||
* Channels.
|
||||
* The channels used in an image.
|
||||
* AUTO can be used when decoding to automatically determine
|
||||
* the channels from the file's header.
|
||||
*/
|
||||
enum QOIChannels : char (char id)
|
||||
{
|
||||
AUTO = 0,
|
||||
RGB = 3,
|
||||
RGBA = 4
|
||||
}
|
||||
|
||||
/**
|
||||
* Descriptor.
|
||||
* Contains information about an image.
|
||||
*/
|
||||
struct QOIDesc
|
||||
{
|
||||
uint width;
|
||||
uint height;
|
||||
QOIChannels channels;
|
||||
QOIColorspace colorspace;
|
||||
}
|
||||
|
||||
/**
|
||||
* QOI Errors.
|
||||
* These are all the possible bad outcomes.
|
||||
*/
|
||||
fault QOIError
|
||||
{
|
||||
INVALID_PARAMETERS,
|
||||
FILE_OPEN_FAILED,
|
||||
FILE_WRITE_FAILED,
|
||||
INVALID_DATA,
|
||||
TOO_MANY_PIXELS
|
||||
}
|
||||
|
||||
|
||||
// Let the user decide if they want to use std::io
|
||||
module std::compression::qoi @if(!$feature(QOI_NO_STDIO));
|
||||
import std::io;
|
||||
|
||||
/**
|
||||
* Encode raw RGB or RGBA pixels into a QOI image and write it to the
|
||||
* file system.
|
||||
*
|
||||
* The desc struct must be filled with the image width, height, the
|
||||
* used channels (QOIChannels.RGB or RGBA) and the colorspace
|
||||
* (QOIColorspace.SRGB or LINEAR).
|
||||
*
|
||||
* The function returns an optional, which can either be a QOIError
|
||||
* or the number of bytes written on success.
|
||||
*
|
||||
* @param [in] filename `The file's name to write the image to`
|
||||
* @param [in] input `The raw RGB or RGBA pixels to encode`
|
||||
* @param [&in] desc `The descriptor of the image`
|
||||
*/
|
||||
fn usz! write(String filename, char[] input, QOIDesc* desc)
|
||||
{
|
||||
@pool() {
|
||||
// encode data
|
||||
char[] output = encode(input, desc)!;
|
||||
|
||||
// open file
|
||||
File! f = file::open(filename, "wb");
|
||||
if (catch f) { return QOIError.FILE_OPEN_FAILED?; }
|
||||
|
||||
// write data to file and close it
|
||||
usz! written = f.write(output);
|
||||
if (catch written) { return QOIError.FILE_WRITE_FAILED?; }
|
||||
if (catch f.close()) { return QOIError.FILE_WRITE_FAILED?; }
|
||||
|
||||
return written;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read and decode a QOI image from the file system.
|
||||
*
|
||||
* If channels is set to QOIChannels.AUTO, the function will
|
||||
* automatically determine the channels from the file's header.
|
||||
* However, if channels is RGB or RGBA, the output format will be
|
||||
* forced into this number of channels.
|
||||
*
|
||||
* The desc struct will be filled with the width, height,
|
||||
* channels and colorspace of the image.
|
||||
*
|
||||
* The function returns an optional, which can either be a QOIError
|
||||
* or a char[] pointing to the decoded pixels on success.
|
||||
*
|
||||
* The returned pixel data should be free()d after use, or the decoding
|
||||
* and use of the data should be wrapped in a @pool() { ... }; block.
|
||||
*
|
||||
* @param [in] filename `The file's name to read the image from`
|
||||
* @param [&out] desc `The descriptor to fill with the image's info`
|
||||
* @param channels `The channels to be used`
|
||||
*/
|
||||
fn char[]! read(String filename, QOIDesc* desc, QOIChannels channels = AUTO, Allocator allocator = allocator::heap())
|
||||
{
|
||||
// read file
|
||||
char[]! data = file::load_new(filename);
|
||||
if (catch data) return QOIError.FILE_OPEN_FAILED?;
|
||||
defer mem::free(data);
|
||||
|
||||
// pass data to decode function
|
||||
return decode(data, desc, channels, allocator);
|
||||
}
|
||||
|
||||
|
||||
// Back to basic non-stdio mode
|
||||
module std::compression::qoi;
|
||||
import std::bits;
|
||||
|
||||
/**
|
||||
* Encode raw RGB or RGBA pixels into a QOI image in memory.
|
||||
*
|
||||
* The function returns an optional, which can either be a QOIError
|
||||
* or a char[] pointing to the encoded data on success.
|
||||
*
|
||||
* The returned qoi data should be free()d after use, or the encoding
|
||||
* and use of the data should be wrapped in a @pool() { ... }; block.
|
||||
* See the write() function for an example.
|
||||
*
|
||||
* @param [in] input `The raw RGB or RGBA pixels to encode`
|
||||
* @param [&in] desc `The descriptor of the image`
|
||||
*/
|
||||
fn char[]! encode(char[] input, QOIDesc* desc, Allocator allocator = allocator::heap())
|
||||
{
|
||||
// check info in desc
|
||||
if (desc.width == 0 || desc.height == 0) return QOIError.INVALID_PARAMETERS?;
|
||||
if (desc.channels == AUTO) return QOIError.INVALID_PARAMETERS?;
|
||||
uint pixels = desc.width * desc.height;
|
||||
if (pixels > PIXELS_MAX) return QOIError.TOO_MANY_PIXELS?;
|
||||
|
||||
// check input data size
|
||||
uint image_size = pixels * desc.channels.id;
|
||||
if (image_size != input.len) return QOIError.INVALID_DATA?;
|
||||
|
||||
// allocate memory for encoded data (output)
|
||||
// header + chunk tag and RGB(A) data for each pixel + end of stream
|
||||
uint max_size = Header.sizeof + pixels + image_size + END_OF_STREAM.len;
|
||||
char[] output = allocator::alloc_array(allocator, char, max_size); // no need to init
|
||||
defer catch allocator::free(allocator, output);
|
||||
|
||||
// write header
|
||||
*(Header*)output.ptr = {
|
||||
.be_magic = bswap('qoif'),
|
||||
.be_width = bswap(desc.width),
|
||||
.be_height = bswap(desc.height),
|
||||
.channels = desc.channels.id,
|
||||
.colorspace = desc.colorspace.id
|
||||
};
|
||||
|
||||
uint pos = Header.sizeof; // Current position in output
|
||||
uint loc; // Current position in image (top-left corner)
|
||||
uint loc_end = image_size - desc.channels.id; // End of image data
|
||||
char run_length = 0; // Length of the current run
|
||||
|
||||
Pixel[64] palette; // Zero-initialized by default
|
||||
Pixel prev = { 0, 0, 0, 255 };
|
||||
Pixel p = { 0, 0, 0, 255 };
|
||||
|
||||
ichar[<3>] diff; // pre-allocate for diff
|
||||
ichar[<3>] luma; // ...and luma
|
||||
|
||||
// write chunks
|
||||
for (loc = 0; loc < image_size; loc += desc.channels.id)
|
||||
{
|
||||
// set previous pixel
|
||||
prev = p;
|
||||
|
||||
// get current pixel
|
||||
p[:3] = input[loc:3]; // cutesy slices :3
|
||||
if (desc.channels == RGBA) p.a = input[loc + 3];
|
||||
|
||||
// check if we can run the previous pixel
|
||||
if (prev == p) {
|
||||
run_length++;
|
||||
if (run_length == 62 || loc == loc_end) {
|
||||
*@extract(OpRun, output, &pos) = { OP_RUN, run_length - 1 };
|
||||
run_length = 0;
|
||||
}
|
||||
} else {
|
||||
// end last run if there was one
|
||||
if (run_length > 0) {
|
||||
*@extract(OpRun, output, &pos) = { OP_RUN, run_length - 1 };
|
||||
run_length = 0;
|
||||
}
|
||||
|
||||
switch {
|
||||
// check if we can index the palette
|
||||
case (palette[p.hash()] == p):
|
||||
*@extract(OpIndex, output, &pos) = {
|
||||
OP_INDEX,
|
||||
p.hash()
|
||||
};
|
||||
|
||||
// check if we can use diff or luma
|
||||
case (prev != p && prev.a == p.a):
|
||||
// diff the pixels
|
||||
diff = p.rgb - prev.rgb;
|
||||
if (
|
||||
diff.r > -3 && diff.r < 2 &&
|
||||
diff.g > -3 && diff.g < 2 &&
|
||||
diff.b > -3 && diff.b < 2
|
||||
) {
|
||||
*@extract(OpDiff, output, &pos) = {
|
||||
OP_DIFF,
|
||||
(char)diff.r + 2,
|
||||
(char)diff.g + 2,
|
||||
(char)diff.b + 2
|
||||
};
|
||||
palette[p.hash()] = p;
|
||||
} else {
|
||||
// check luma eligibility
|
||||
luma = { diff.r - diff.g, diff.g, diff.b - diff.g };
|
||||
if (
|
||||
luma.r >= -8 && luma.r <= 7 &&
|
||||
luma.g >= -32 && luma.g <= 31 &&
|
||||
luma.b >= -8 && luma.b <= 7
|
||||
) {
|
||||
*@extract(OpLuma, output, &pos) = {
|
||||
OP_LUMA,
|
||||
(char)luma.g + 32,
|
||||
(char)luma.r + 8,
|
||||
(char)luma.b + 8
|
||||
};
|
||||
palette[p.hash()] = p;
|
||||
} else { nextcase; }
|
||||
}
|
||||
|
||||
// worst case scenario: just encode the raw pixel
|
||||
default:
|
||||
if (prev.a != p.a) {
|
||||
*@extract(OpRGBA, output, &pos) = { OP_RGBA, p.r, p.g, p.b, p.a };
|
||||
} else {
|
||||
*@extract(OpRGB, output, &pos) = { OP_RGB, p.r, p.g, p.b };
|
||||
}
|
||||
palette[p.hash()] = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// write end of stream
|
||||
output[pos:END_OF_STREAM.len] = END_OF_STREAM;
|
||||
pos += END_OF_STREAM.len;
|
||||
|
||||
return output[:pos];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Decode a QOI image from memory.
|
||||
*
|
||||
* If channels is set to QOIChannels.AUTO, the function will
|
||||
* automatically determine the channels from the file's header.
|
||||
* However, if channels is RGB or RGBA, the output format will be
|
||||
* forced into this number of channels.
|
||||
*
|
||||
* The desc struct will be filled with the width, height,
|
||||
* channels and colorspace of the image.
|
||||
*
|
||||
* The function returns an optional, which can either be a QOIError
|
||||
* or a char[] pointing to the decoded pixels on success.
|
||||
*
|
||||
* The returned pixel data should be free()d after use, or the decoding
|
||||
* and use of the data should be wrapped in a @pool() { ... }; block.
|
||||
*
|
||||
* @param [in] data `The QOI image data to decode`
|
||||
* @param [&out] desc `The descriptor to fill with the image's info`
|
||||
* @param channels `The channels to be used`
|
||||
*/
|
||||
fn char[]! decode(char[] data, QOIDesc* desc, QOIChannels channels = AUTO, Allocator allocator = allocator::heap())
|
||||
{
|
||||
// check input data
|
||||
if (data.len < Header.sizeof + END_OF_STREAM.len) return QOIError.INVALID_DATA?;
|
||||
|
||||
// get header
|
||||
Header* header = (Header*)data.ptr;
|
||||
|
||||
// check magic bytes (FourCC)
|
||||
if (bswap(header.be_magic) != 'qoif') return QOIError.INVALID_DATA?;
|
||||
|
||||
// copy header data to desc
|
||||
desc.width = bswap(header.be_width);
|
||||
desc.height = bswap(header.be_height);
|
||||
desc.channels = @enumcast(QOIChannels, header.channels)!; // Rethrow if invalid
|
||||
desc.colorspace = @enumcast(QOIColorspace, header.colorspace)!; // Rethrow if invalid
|
||||
if (desc.channels == AUTO) return QOIError.INVALID_DATA?; // Channels must be specified in the header
|
||||
|
||||
// check width and height
|
||||
if (desc.width == 0 || desc.height == 0) return QOIError.INVALID_DATA?;
|
||||
|
||||
// check pixel count
|
||||
ulong pixels = (ulong)desc.width * (ulong)desc.height;
|
||||
if (pixels > PIXELS_MAX) return QOIError.TOO_MANY_PIXELS?;
|
||||
|
||||
uint pos = Header.sizeof; // Current position in data
|
||||
uint loc; // Current position in image (top-left corner)
|
||||
char run_length = 0; // Length of the current run
|
||||
char tag; // Current chunk tag
|
||||
|
||||
Pixel[64] palette; // Zero-initialized by default
|
||||
Pixel p = { 0, 0, 0, 255 };
|
||||
|
||||
if (channels == AUTO) channels = desc.channels;
|
||||
|
||||
// allocate memory for image data
|
||||
usz image_size = (usz)pixels * channels.id;
|
||||
char[] image = allocator::alloc_array(allocator, char, image_size);
|
||||
defer catch allocator::free(allocator, image);
|
||||
|
||||
for (loc = 0; loc < image_size; loc += channels.id)
|
||||
{
|
||||
// get chunk tag
|
||||
tag = data[pos];
|
||||
|
||||
// check for chunk type
|
||||
switch
|
||||
{
|
||||
case run_length > 0:
|
||||
run_length--;
|
||||
|
||||
case tag == OP_RGB:
|
||||
OpRGB* op = @extract(OpRGB, data, &pos);
|
||||
p = { op.red, op.green, op.blue, p.a };
|
||||
palette[p.hash()] = p;
|
||||
|
||||
case tag == OP_RGBA:
|
||||
OpRGBA* op = @extract(OpRGBA, data, &pos);
|
||||
p = { op.red, op.green, op.blue, op.alpha };
|
||||
palette[p.hash()] = p;
|
||||
|
||||
case tag >> 6 == OP_INDEX:
|
||||
OpIndex* op = @extract(OpIndex, data, &pos);
|
||||
p = palette[op.index];
|
||||
|
||||
case tag >> 6 == OP_DIFF:
|
||||
OpDiff* op = @extract(OpDiff, data, &pos);
|
||||
p.r += op.diff_red - 2;
|
||||
p.g += op.diff_green - 2;
|
||||
p.b += op.diff_blue - 2;
|
||||
palette[p.hash()] = p;
|
||||
|
||||
case tag >> 6 == OP_LUMA:
|
||||
OpLuma* op = @extract(OpLuma, data, &pos);
|
||||
int diff_green = op.diff_green - 32;
|
||||
p.r += (char)(op.diff_red_minus_green - 8 + diff_green);
|
||||
p.g += (char)(diff_green);
|
||||
p.b += (char)(op.diff_blue_minus_green - 8 + diff_green);
|
||||
palette[p.hash()] = p;
|
||||
|
||||
case tag >> 6 == OP_RUN:
|
||||
OpRun* op = @extract(OpRun, data, &pos);
|
||||
run_length = op.run;
|
||||
}
|
||||
|
||||
// draw the pixel
|
||||
if (channels == RGBA) { image[loc:4] = p.rgba; } else { image[loc:3] = p.rgb; }
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ***************************************************************************
|
||||
// *** ***
|
||||
// *** Main functions are at the top to make the file more readable. ***
|
||||
// *** From here on, helper functions and types are defined. ***
|
||||
// *** ***
|
||||
// ***************************************************************************
|
||||
module std::compression::qoi @private;
|
||||
|
||||
// 8-bit opcodes
|
||||
const OP_RGB = 0b11111110;
|
||||
const OP_RGBA = 0b11111111;
|
||||
// 2-bit opcodes
|
||||
const OP_INDEX = 0b00;
|
||||
const OP_DIFF = 0b01;
|
||||
const OP_LUMA = 0b10;
|
||||
const OP_RUN = 0b11;
|
||||
|
||||
struct Header @packed
|
||||
{
|
||||
uint be_magic; // magic bytes "qoif"
|
||||
uint be_width; // image width in pixels (BE)
|
||||
uint be_height; // image height in pixels (BE)
|
||||
|
||||
// informative fields
|
||||
char channels; // 3 = RGB, 4 = RGB
|
||||
char colorspace; // 0 = sRGB with linear alpha, 1 = all channels linear
|
||||
}
|
||||
|
||||
const char[*] END_OF_STREAM = {0, 0, 0, 0, 0, 0, 0, 1};
|
||||
|
||||
// inefficient, but it's only run once at a time
|
||||
macro @enumcast($Type, raw)
|
||||
{
|
||||
foreach (value : $Type.values) {
|
||||
if (value.id == raw) return value;
|
||||
}
|
||||
return QOIError.INVALID_DATA?;
|
||||
}
|
||||
|
||||
distinct Pixel = inline char[<4>];
|
||||
macro char Pixel.hash(Pixel p) {
|
||||
return (p.r * 3 + p.g * 5 + p.b * 7 + p.a * 11) % 64;
|
||||
}
|
||||
|
||||
struct OpRGB // No need to use @packed here, the alignment is 1 anyways.
|
||||
{
|
||||
char tag;
|
||||
char red;
|
||||
char green;
|
||||
char blue;
|
||||
}
|
||||
struct OpRGBA @packed
|
||||
{
|
||||
char tag;
|
||||
char red;
|
||||
char green;
|
||||
char blue;
|
||||
char alpha;
|
||||
}
|
||||
bitstruct OpIndex : char
|
||||
{
|
||||
char tag : 6..7;
|
||||
char index : 0..5;
|
||||
}
|
||||
bitstruct OpDiff : char
|
||||
{
|
||||
char tag : 6..7;
|
||||
char diff_red : 4..5;
|
||||
char diff_green : 2..3;
|
||||
char diff_blue : 0..1;
|
||||
}
|
||||
bitstruct OpLuma : ushort
|
||||
{
|
||||
char tag : 6..7;
|
||||
char diff_green : 0..5;
|
||||
char diff_red_minus_green : 12..15;
|
||||
char diff_blue_minus_green : 8..11;
|
||||
}
|
||||
bitstruct OpRun : char
|
||||
{
|
||||
char tag : 6..7;
|
||||
char run : 0..5;
|
||||
}
|
||||
|
||||
// Macro used to locate chunks in data buffers.
|
||||
// Can be used both for reading and writing.
|
||||
macro @extract($Type, char[] data, uint* pos)
|
||||
{
|
||||
// slice data, then double cast
|
||||
$Type* chunk = ($Type*)data[*pos : $Type.sizeof].ptr;
|
||||
*pos += $Type.sizeof;
|
||||
return chunk;
|
||||
}
|
||||
@@ -24,6 +24,7 @@ fn void DynamicArenaAllocator.init(&self, usz page_size, Allocator allocator)
|
||||
self.backing_allocator = allocator;
|
||||
}
|
||||
|
||||
import std::io;
|
||||
fn void DynamicArenaAllocator.free(&self)
|
||||
{
|
||||
DynamicArenaPage* page = self.page;
|
||||
|
||||
@@ -2,21 +2,16 @@
|
||||
// Use of this source code is governed by the MIT license
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
|
||||
module std::core::mem::allocator @if(env::LIBC);
|
||||
import std::io;
|
||||
module std::core::mem::allocator;
|
||||
import libc;
|
||||
|
||||
const LibcAllocator LIBC_ALLOCATOR = {};
|
||||
distinct LibcAllocator (Allocator, Printable) = uptr;
|
||||
|
||||
fn String LibcAllocator.to_string(&self, Allocator allocator) @dynamic => "Libc allocator".copy(allocator);
|
||||
fn usz! LibcAllocator.to_format(&self, Formatter *format) @dynamic => format.print("Libc allocator");
|
||||
distinct LibcAllocator (Allocator) = uptr;
|
||||
|
||||
module std::core::mem::allocator @if(env::POSIX);
|
||||
import std::os;
|
||||
import libc;
|
||||
|
||||
|
||||
fn void*! LibcAllocator.acquire(&self, usz bytes, AllocInitType init_type, usz alignment) @dynamic
|
||||
{
|
||||
if (init_type == ZERO)
|
||||
@@ -115,7 +110,7 @@ fn void LibcAllocator.release(&self, void* old_ptr, bool aligned) @dynamic
|
||||
libc::free(old_ptr);
|
||||
}
|
||||
|
||||
module std::core::mem::allocator @if(!env::WIN32 && !env::POSIX && env::LIBC);
|
||||
module std::core::mem::allocator @if(!env::WIN32 && !env::POSIX);
|
||||
import libc;
|
||||
|
||||
fn void*! LibcAllocator.acquire(&self, usz bytes, AllocInitType init_type, usz alignment) @dynamic
|
||||
|
||||
@@ -68,7 +68,6 @@ fn void TempAllocator.reset(&self, usz mark) @dynamic
|
||||
TempAllocatorPage *last_page = self.last_page;
|
||||
while (last_page && last_page.mark > mark)
|
||||
{
|
||||
self.used = last_page.mark;
|
||||
TempAllocatorPage *to_free = last_page;
|
||||
last_page = last_page.prev_page;
|
||||
self._free_page(to_free)!!;
|
||||
|
||||
@@ -34,7 +34,7 @@ struct TrackingAllocator (Allocator)
|
||||
fn void TrackingAllocator.init(&self, Allocator allocator)
|
||||
{
|
||||
*self = { .inner_allocator = allocator };
|
||||
self.map.new_init(allocator: allocator);
|
||||
self.map.new_init(.allocator = allocator);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -87,6 +87,7 @@ fn void*! TrackingAllocator.acquire(&self, usz size, AllocInitType init_type, us
|
||||
backtrace::capture_current(&bt);
|
||||
self.map.set((uptr)data, { data, size, bt });
|
||||
self.mem_total += size;
|
||||
self.allocs_total++;
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ macro rindex_of(array, element)
|
||||
* @require @typeis(arr1[0], $typeof(arr2[0])) "Arrays must have the same type"
|
||||
* @ensure result.len == arr1.len + arr2.len
|
||||
**/
|
||||
macro concat(arr1, arr2, Allocator allocator) @nodiscard
|
||||
macro concat_new(arr1, arr2, Allocator allocator = allocator::heap())
|
||||
{
|
||||
var $Type = $typeof(arr1[0]);
|
||||
$Type[] result = allocator::alloc_array(allocator, $Type, arr1.len + arr2.len);
|
||||
@@ -69,21 +69,6 @@ macro concat(arr1, arr2, Allocator allocator) @nodiscard
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Concatenate two arrays or slices, returning a slice containing the concatenation of them.
|
||||
*
|
||||
* @param [in] arr1
|
||||
* @param [in] arr2
|
||||
* @param [&inout] allocator "The allocator to use, default is the heap allocator"
|
||||
* @require @typekind(arr1) == SLICE || @typekind(arr1) == ARRAY
|
||||
* @require @typekind(arr2) == SLICE || @typekind(arr2) == ARRAY
|
||||
* @require @typeis(arr1[0], $typeof(arr2[0])) "Arrays must have the same type"
|
||||
* @ensure result.len == arr1.len + arr2.len
|
||||
**/
|
||||
macro concat_new(arr1, arr2, Allocator allocator = allocator::heap()) @nodiscard
|
||||
{
|
||||
return concat(arr1, arr2, allocator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenate two arrays or slices, returning a slice containing the concatenation of them,
|
||||
@@ -96,7 +81,7 @@ macro concat_new(arr1, arr2, Allocator allocator = allocator::heap()) @nodiscard
|
||||
* @require @typeis(arr1[0], $typeof(arr2[0])) "Arrays must have the same type"
|
||||
* @ensure result.len == arr1.len + arr2.len
|
||||
**/
|
||||
macro tconcat(arr1, arr2) @nodiscard => concat(arr1, arr2, allocator::temp());
|
||||
macro tconcat(arr1, arr2) => concat(arr1, arr2, allocator::temp());
|
||||
|
||||
module std::core::array::slice(<Type>);
|
||||
|
||||
|
||||
@@ -104,29 +104,13 @@ fn void default_panic(String message, String file, String function, uint line) @
|
||||
$$trap();
|
||||
|
||||
}
|
||||
|
||||
macro void abort(String string = "Unrecoverable error reached", ...) @builtin @noreturn
|
||||
{
|
||||
panicf(string, $$FILE, $$FUNC, $$LINE, $vasplat);
|
||||
$$trap();
|
||||
}
|
||||
|
||||
bool in_panic @local = false;
|
||||
|
||||
fn void default_panic(String message, String file, String function, uint line) @if(!env::NATIVE_STACKTRACE)
|
||||
{
|
||||
if (in_panic)
|
||||
{
|
||||
io::eprintn("Panic inside of panic.");
|
||||
return;
|
||||
}
|
||||
in_panic = true;
|
||||
$if $defined(io::stderr):
|
||||
io::eprint("\nERROR: '");
|
||||
io::eprint(message);
|
||||
io::eprintfn("', in %s (%s:%d)", function, file, line);
|
||||
$endif
|
||||
in_panic = false;
|
||||
$$trap();
|
||||
}
|
||||
|
||||
@@ -136,19 +120,11 @@ PanicFn panic = &default_panic;
|
||||
|
||||
fn void panicf(String fmt, String file, String function, uint line, args...)
|
||||
{
|
||||
if (in_panic)
|
||||
{
|
||||
io::eprint("Panic inside of panic: ");
|
||||
io::eprintn(fmt);
|
||||
return;
|
||||
}
|
||||
in_panic = true;
|
||||
@stack_mem(512; Allocator allocator)
|
||||
{
|
||||
DString s;
|
||||
s.new_init(allocator: allocator);
|
||||
s.new_init(.allocator = allocator);
|
||||
s.appendf(fmt, ...args);
|
||||
in_panic = false;
|
||||
panic(s.str_view(), file, function, line);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -154,15 +154,13 @@ fn String DString.str_view(self)
|
||||
return (String)data.chars[:data.len];
|
||||
}
|
||||
|
||||
fn usz DString.append_utf32(&self, Char32[] chars)
|
||||
fn void DString.append_utf32(&self, Char32[] chars)
|
||||
{
|
||||
self.reserve(chars.len);
|
||||
usz end = self.len();
|
||||
foreach (Char32 c : chars)
|
||||
{
|
||||
self.append_char32(c);
|
||||
}
|
||||
return self.data().len - end;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -187,7 +185,7 @@ fn void DString.append_repeat(&self, char c, usz times)
|
||||
/**
|
||||
* @require c <= 0x10ffff
|
||||
*/
|
||||
fn usz DString.append_char32(&self, Char32 c)
|
||||
fn void DString.append_char32(&self, Char32 c)
|
||||
{
|
||||
char[4] buffer @noinit;
|
||||
char* p = &buffer;
|
||||
@@ -196,7 +194,6 @@ fn usz DString.append_char32(&self, Char32 c)
|
||||
StringData* data = self.data();
|
||||
data.chars[data.len:n] = buffer[:n];
|
||||
data.len += n;
|
||||
return n;
|
||||
}
|
||||
|
||||
fn DString DString.tcopy(&self) => self.copy(allocator::temp());
|
||||
@@ -295,7 +292,7 @@ fn void DString.append_chars(&self, String str)
|
||||
|
||||
fn Char32[] DString.copy_utf32(&self, Allocator allocator = allocator::heap())
|
||||
{
|
||||
return self.str_view().to_utf32(allocator) @inline!!;
|
||||
return self.str_view().to_new_utf32(allocator) @inline!!;
|
||||
}
|
||||
|
||||
fn void DString.append_string(&self, DString str)
|
||||
@@ -390,10 +387,7 @@ macro void DString.append(&self, value)
|
||||
$endswitch
|
||||
}
|
||||
|
||||
/**
|
||||
* @require index <= self.len()
|
||||
**/
|
||||
fn void DString.insert_chars_at(&self, usz index, String s)
|
||||
fn void DString.insert_at(&self, usz index, String s)
|
||||
{
|
||||
if (s.len == 0) return;
|
||||
self.reserve(s.len);
|
||||
@@ -425,103 +419,6 @@ fn void DString.insert_chars_at(&self, usz index, String s)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @require index <= self.len()
|
||||
**/
|
||||
fn void DString.insert_string_at(&self, usz index, DString str)
|
||||
{
|
||||
StringData* other = str.data();
|
||||
if (!other) return;
|
||||
self.insert_at(index, str.str_view());
|
||||
}
|
||||
|
||||
/**
|
||||
* @require index <= self.len()
|
||||
**/
|
||||
fn void DString.insert_char_at(&self, usz index, char c)
|
||||
{
|
||||
self.reserve(1);
|
||||
StringData* data = self.data();
|
||||
|
||||
char* start = &data.chars[index];
|
||||
mem::move(start + 1, start, self.len() - index);
|
||||
data.chars[index] = c;
|
||||
data.len++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require index <= self.len()
|
||||
**/
|
||||
fn usz DString.insert_char32_at(&self, usz index, Char32 c)
|
||||
{
|
||||
char[4] buffer @noinit;
|
||||
char* p = &buffer;
|
||||
usz n = conv::char32_to_utf8_unsafe(c, &p);
|
||||
|
||||
self.reserve(n);
|
||||
StringData* data = self.data();
|
||||
|
||||
char* start = &data.chars[index];
|
||||
mem::move(start + n, start, self.len() - index);
|
||||
data.chars[index:n] = buffer[:n];
|
||||
data.len += n;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require index <= self.len()
|
||||
**/
|
||||
fn usz DString.insert_utf32_at(&self, usz index, Char32[] chars)
|
||||
{
|
||||
usz n = conv::utf8len_for_utf32(chars);
|
||||
|
||||
self.reserve(n);
|
||||
StringData* data = self.data();
|
||||
|
||||
char* start = &data.chars[index];
|
||||
mem::move(start + n, start, self.len() - index);
|
||||
|
||||
char[4] buffer @noinit;
|
||||
|
||||
foreach(c : chars)
|
||||
{
|
||||
char* p = &buffer;
|
||||
usz m = conv::char32_to_utf8_unsafe(c, &p);
|
||||
data.chars[index:m] = buffer[:m];
|
||||
index += m;
|
||||
}
|
||||
|
||||
data.len += n;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
macro void DString.insert_at(&self, usz index, value)
|
||||
{
|
||||
var $Type = $typeof(value);
|
||||
$switch ($Type)
|
||||
$case char:
|
||||
$case ichar:
|
||||
self.insert_char_at(index, value);
|
||||
$case DString:
|
||||
self.insert_string_at(index, value);
|
||||
$case String:
|
||||
self.insert_chars_at(index, value);
|
||||
$case Char32:
|
||||
self.insert_char32_at(index, value);
|
||||
$default:
|
||||
$switch
|
||||
$case $defined((Char32)value):
|
||||
self.insert_char32_at(index, (Char32)value);
|
||||
$case $defined((String)value):
|
||||
self.insert_chars_at(index, (String)value);
|
||||
$default:
|
||||
$error "Unsupported type for insert";
|
||||
$endswitch
|
||||
$endswitch
|
||||
}
|
||||
|
||||
fn usz! DString.appendf(&self, String format, args...) @maydiscard
|
||||
{
|
||||
if (!self.data()) self.new_init(format.len + 20);
|
||||
@@ -570,19 +467,6 @@ fn void! out_string_append_fn(void* data, char c) @private
|
||||
s.append_char(c);
|
||||
}
|
||||
|
||||
fn void DString.reverse(self)
|
||||
{
|
||||
StringData *data = self.data();
|
||||
if (!data) return;
|
||||
isz mid = data.len / 2;
|
||||
for (isz i = 0; i < mid; i++)
|
||||
{
|
||||
char temp = data.chars[i];
|
||||
isz reverse_index = data.len - 1 - i;
|
||||
data.chars[i] = data.chars[reverse_index];
|
||||
data.chars[reverse_index] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
fn StringData* DString.data(self) @inline @private
|
||||
{
|
||||
|
||||
@@ -115,8 +115,6 @@ enum ArchType
|
||||
XTENSA, // Xtensa
|
||||
}
|
||||
|
||||
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 bool ARCH_32_BIT = $$REGISTER_SIZE == 32;
|
||||
@@ -148,7 +146,6 @@ const bool POSIX = LIBC && os_is_posix();
|
||||
const bool OPENBSD = LIBC && OS_TYPE == OPENBSD;
|
||||
const bool FREEBSD = LIBC && OS_TYPE == FREEBSD;
|
||||
const bool NETBSD = LIBC && OS_TYPE == NETBSD;
|
||||
const bool BSD_FAMILY = env::FREEBSD || env::OPENBSD || env::NETBSD;
|
||||
const bool WASI = LIBC && OS_TYPE == WASI;
|
||||
const bool WASM_NOLIBC @builtin = !LIBC && ARCH_TYPE == ArchType.WASM32 || ARCH_TYPE == ArchType.WASM64;
|
||||
const bool ADDRESS_SANITIZER = $$ADDRESS_SANITIZER;
|
||||
|
||||
@@ -281,11 +281,6 @@ fn bool ptr_is_aligned(void* ptr, usz alignment) @inline
|
||||
return (uptr)ptr & ((uptr)alignment - 1) == 0;
|
||||
}
|
||||
|
||||
macro void zero_volatile(char[] data)
|
||||
{
|
||||
$$memset(data.ptr, (char)0, data.len, true, (usz)1);
|
||||
}
|
||||
|
||||
macro void clear(void* dst, usz len, usz $dst_align = 0, bool $is_volatile = false, bool $inlined = false)
|
||||
{
|
||||
$$memset(dst, (char)0, len, $is_volatile, $dst_align);
|
||||
@@ -541,7 +536,7 @@ import std::core::mem::allocator @public;
|
||||
SimpleHeapAllocator wasm_allocator @private;
|
||||
extern int __heap_base;
|
||||
|
||||
fn void initialize_wasm_mem() @init(1024) @private
|
||||
fn void initialize_wasm_mem() @init(1) @private
|
||||
{
|
||||
allocator::wasm_memory.allocate_block(mem::DEFAULT_MEM_ALIGNMENT)!!; // Give us a valid null.
|
||||
// Check if we need to move the heap.
|
||||
@@ -549,7 +544,6 @@ fn void initialize_wasm_mem() @init(1024) @private
|
||||
if (start > mem::DEFAULT_MEM_ALIGNMENT) allocator::wasm_memory.use = start;
|
||||
wasm_allocator.init(fn (x) => allocator::wasm_memory.allocate_block(x));
|
||||
allocator::thread_allocator = &wasm_allocator;
|
||||
allocator::temp_base_allocator = &wasm_allocator;
|
||||
allocator::init_default_temp_allocators();
|
||||
}
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ macro void free_aligned(Allocator allocator, void* ptr)
|
||||
$if env::TESTING:
|
||||
((char*)ptr)[0] = 0xBA;
|
||||
$endif
|
||||
allocator.release(ptr, aligned: true);
|
||||
allocator.release(ptr, .aligned = true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -358,22 +358,10 @@ macro void*! @aligned_realloc(#calloc_fn, #free_fn, void* old_pointer, usz bytes
|
||||
|
||||
|
||||
// All allocators
|
||||
|
||||
|
||||
tlocal Allocator thread_allocator @private = base_allocator();
|
||||
Allocator temp_base_allocator @private = base_allocator();
|
||||
|
||||
tlocal Allocator thread_allocator @private = &allocator::LIBC_ALLOCATOR;
|
||||
tlocal TempAllocator* thread_temp_allocator @private = null;
|
||||
tlocal TempAllocator*[2] temp_allocator_pair @private;
|
||||
|
||||
macro Allocator base_allocator() @private
|
||||
{
|
||||
$if env::LIBC:
|
||||
return &allocator::LIBC_ALLOCATOR;
|
||||
$else
|
||||
return &allocator::NULL_ALLOCATOR;
|
||||
$endif
|
||||
}
|
||||
Allocator temp_base_allocator @private = &allocator::LIBC_ALLOCATOR;
|
||||
|
||||
macro TempAllocator* create_default_sized_temp_allocator(Allocator allocator) @local
|
||||
{
|
||||
@@ -434,21 +422,3 @@ fn TempAllocator* temp_allocator_next() @private
|
||||
usz index = thread_temp_allocator == temp_allocator_pair[0] ? 1 : 0;
|
||||
return thread_temp_allocator = temp_allocator_pair[index];
|
||||
}
|
||||
|
||||
const NullAllocator NULL_ALLOCATOR = {};
|
||||
distinct NullAllocator (Allocator) = uptr;
|
||||
|
||||
fn void*! NullAllocator.acquire(&self, usz bytes, AllocInitType init_type, usz alignment) @dynamic
|
||||
{
|
||||
return AllocationFailure.OUT_OF_MEMORY?;
|
||||
}
|
||||
|
||||
fn void*! NullAllocator.resize(&self, void* old_ptr, usz new_bytes, usz alignment) @dynamic
|
||||
{
|
||||
return AllocationFailure.OUT_OF_MEMORY?;
|
||||
}
|
||||
|
||||
fn void NullAllocator.release(&self, void* old_ptr, bool aligned) @dynamic
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@ enum X86Feature
|
||||
AMX_FP16,
|
||||
AMX_INT8,
|
||||
AMX_TILE,
|
||||
APXF,
|
||||
AVX,
|
||||
AVX10_1_256,
|
||||
AVX10_1_512,
|
||||
@@ -157,7 +156,6 @@ fn void x86_initialize_cpu_features()
|
||||
add_feature_if_bit(AMX_FP16, leaf7s1.eax, 21);
|
||||
add_feature_if_bit(AMX_INT8, leaf7.edx, 25);
|
||||
add_feature_if_bit(AMX_TILE, leaf7.edx, 24);
|
||||
add_feature_if_bit(APXF, leaf7s1.edx, 21);
|
||||
add_feature_if_bit(AVX, feat.ecx, 28);
|
||||
add_feature_if_bit(AVX10_1_256, leaf7s1.edx, 19);
|
||||
add_feature_if_bit(AVX10_1_512, leaf_24.ebx, 18);
|
||||
@@ -257,4 +255,4 @@ fn void x86_initialize_cpu_features()
|
||||
add_feature_if_bit(XSAVEOPT, leaf_d.eax, 0);
|
||||
add_feature_if_bit(XSAVES, leaf_d.eax, 3);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -4,12 +4,6 @@
|
||||
module std::core::runtime;
|
||||
import libc, std::time, std::io, std::sort;
|
||||
|
||||
struct ReflectedParam @if(!$defined(ReflectedParam))
|
||||
{
|
||||
String name;
|
||||
typeid type;
|
||||
}
|
||||
|
||||
struct AnyRaw
|
||||
{
|
||||
void* ptr;
|
||||
@@ -221,7 +215,6 @@ fn bool run_tests(TestUnit[] tests)
|
||||
name.appendf("Testing %s ", unit.name);
|
||||
name.append_repeat('.', max_name - unit.name.len + 2);
|
||||
io::printf("%s ", name.str_view());
|
||||
(void)io::stdout().flush();
|
||||
if (libc::setjmp(&context.buf) == 0)
|
||||
{
|
||||
if (catch err = unit.func())
|
||||
|
||||
@@ -32,66 +32,58 @@ fault NumberConversion
|
||||
FLOAT_OUT_OF_RANGE,
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a temporary String created using the formatting function.
|
||||
*
|
||||
* @param [in] fmt `The formatting string`
|
||||
**/
|
||||
macro String tformat(String fmt, ...)
|
||||
{
|
||||
DString str = dstring::temp_with_capacity(fmt.len + $vacount * 8);
|
||||
str.appendf(fmt, $vasplat);
|
||||
return str.str_view();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a temporary ZString created using the formatting function.
|
||||
*
|
||||
* @param [in] fmt `The formatting string`
|
||||
**/
|
||||
fn ZString tformat_zstr(String fmt, args...)
|
||||
macro ZString tformat_zstr(String fmt, ...)
|
||||
{
|
||||
DString str = dstring::temp_with_capacity(fmt.len + args.len * 8);
|
||||
str.appendf(fmt, ...args);
|
||||
DString str = dstring::temp_with_capacity(fmt.len + $vacount * 8);
|
||||
str.appendf(fmt, $vasplat);
|
||||
return str.zstr_view();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new String created using the formatting function.
|
||||
*
|
||||
* @param [inout] allocator `The allocator to use`
|
||||
* @param [in] fmt `The formatting string`
|
||||
* @param [inout] allocator `The allocator to use`
|
||||
**/
|
||||
fn String format(String fmt, args..., Allocator allocator)
|
||||
macro String new_format(String fmt, ..., Allocator allocator = allocator::heap())
|
||||
{
|
||||
@pool(allocator)
|
||||
{
|
||||
DString str = dstring::temp_with_capacity(fmt.len + args.len * 8);
|
||||
str.appendf(fmt, ...args);
|
||||
DString str = dstring::temp_with_capacity(fmt.len + $vacount * 8);
|
||||
str.appendf(fmt, $vasplat);
|
||||
return str.copy_str(allocator);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a heap allocated String created using the formatting function.
|
||||
*
|
||||
* @param [in] fmt `The formatting string`
|
||||
**/
|
||||
fn String new_format(String fmt, args..., Allocator allocator = null) => format(fmt, ...args, allocator: allocator ?: allocator::heap());
|
||||
|
||||
/**
|
||||
* Return a temporary String created using the formatting function.
|
||||
*
|
||||
* @param [in] fmt `The formatting string`
|
||||
**/
|
||||
fn String tformat(String fmt, args...)
|
||||
{
|
||||
DString str = dstring::temp_with_capacity(fmt.len + args.len * 8);
|
||||
str.appendf(fmt, ...args);
|
||||
return str.str_view();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new ZString created using the formatting function.
|
||||
*
|
||||
* @param [in] fmt `The formatting string`
|
||||
* @param [inout] allocator `The allocator to use`
|
||||
**/
|
||||
fn ZString new_format_zstr(String fmt, args..., Allocator allocator = allocator::heap())
|
||||
macro ZString new_format_zstr(String fmt, ..., Allocator allocator = allocator::heap())
|
||||
{
|
||||
@pool(allocator)
|
||||
{
|
||||
DString str = dstring::temp_with_capacity(fmt.len + args.len * 8);
|
||||
str.appendf(fmt, ...args);
|
||||
DString str = dstring::temp_with_capacity(fmt.len + $vacount * 8);
|
||||
str.appendf(fmt, $vasplat);
|
||||
return str.copy_zstr(allocator);
|
||||
};
|
||||
}
|
||||
@@ -213,12 +205,13 @@ fn String String.strip_end(string, String needle)
|
||||
return string[:(string.len - needle.len)];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Split a string into parts, e.g "a|b|c" split with "|" yields { "a", "b", "c" }
|
||||
*
|
||||
* @param [in] s
|
||||
* @param [in] needle
|
||||
* @param [&inout] allocator "The allocator to use for the String[]"
|
||||
* @param [&inout] allocator "The allocator, defaults to the heap allocator"
|
||||
* @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
|
||||
@@ -253,18 +246,6 @@ fn String[] String.split(s, String needle, usz max = 0, Allocator allocator = al
|
||||
return holder[:i];
|
||||
}
|
||||
|
||||
/**
|
||||
* Split a string into parts, e.g "a|b|c" split with "|" yields { "a", "b", "c" }, using the heap allocator
|
||||
* to store the parts.
|
||||
*
|
||||
* @param [in] s
|
||||
* @param [in] needle
|
||||
* @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
|
||||
**/
|
||||
fn String[] String.new_split(s, String needle, usz max = 0) => s.split(needle, max, allocator::heap()) @inline;
|
||||
|
||||
/**
|
||||
* This function is identical to String.split, but implicitly uses the
|
||||
* temporary allocator.
|
||||
@@ -273,7 +254,10 @@ fn String[] String.new_split(s, String needle, usz max = 0) => s.split(needle, m
|
||||
* @param [in] needle
|
||||
* @param max "Max number of elements, 0 means no limit, defaults to 0"
|
||||
**/
|
||||
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)
|
||||
{
|
||||
return s.split(needle, max, allocator::temp()) @inline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a substring is found in the string.
|
||||
@@ -502,15 +486,17 @@ fn Char16[]! String.to_temp_utf16(s)
|
||||
return s.to_new_utf16(allocator::temp());
|
||||
}
|
||||
|
||||
fn WString! String.to_wstring(s, Allocator allocator)
|
||||
fn WString! String.to_new_wstring(s, Allocator allocator = allocator::heap())
|
||||
{
|
||||
return (WString)s.to_new_utf16(allocator).ptr;
|
||||
}
|
||||
|
||||
fn WString! String.to_temp_wstring(s) => s.to_wstring(allocator::temp());
|
||||
fn WString! String.to_new_wstring(s) => s.to_wstring(allocator::heap());
|
||||
fn WString! String.to_temp_wstring(s)
|
||||
{
|
||||
return (WString)s.to_temp_utf16().ptr;
|
||||
}
|
||||
|
||||
fn Char32[]! String.to_utf32(s, Allocator allocator)
|
||||
fn Char32[]! String.to_new_utf32(s, Allocator allocator = allocator::heap())
|
||||
{
|
||||
usz codepoints = conv::utf8_codepoints(s);
|
||||
Char32* data = allocator::alloc_array_try(allocator, Char32, codepoints + 1)!;
|
||||
@@ -519,8 +505,10 @@ fn Char32[]! String.to_utf32(s, Allocator allocator)
|
||||
return data[:codepoints];
|
||||
}
|
||||
|
||||
fn Char32[]! String.to_new_utf32(s) => s.to_utf32(allocator::heap()) @inline;
|
||||
fn Char32[]! String.to_temp_utf32(s) => s.to_utf32(allocator::temp()) @inline;
|
||||
fn Char32[]! String.to_temp_utf32(s)
|
||||
{
|
||||
return s.to_new_utf32(allocator::temp());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a string to ASCII lower case.
|
||||
@@ -540,7 +528,7 @@ fn String String.new_ascii_to_lower(s, Allocator allocator = allocator::heap())
|
||||
return copy;
|
||||
}
|
||||
|
||||
fn String String.temp_ascii_to_lower(s)
|
||||
fn String String.temp_ascii_to_lower(s, Allocator allocator = allocator::heap())
|
||||
{
|
||||
return s.new_ascii_to_lower(allocator::temp());
|
||||
}
|
||||
|
||||
@@ -123,37 +123,6 @@ macro bool is_slice_convertable($Type)
|
||||
macro bool is_bool($Type) @const => $Type.kindof == TypeKind.BOOL;
|
||||
macro bool is_int($Type) @const => $Type.kindof == TypeKind.SIGNED_INT || $Type.kindof == TypeKind.UNSIGNED_INT;
|
||||
|
||||
/**
|
||||
* @require is_numerical($Type) "Expected a numerical type"
|
||||
**/
|
||||
macro bool is_signed($Type) @const
|
||||
{
|
||||
$switch (inner_kind($Type))
|
||||
$case SIGNED_INT:
|
||||
$case FLOAT:
|
||||
return true;
|
||||
$case VECTOR:
|
||||
return is_signed($typefrom($Type.inner));
|
||||
$default:
|
||||
return false;
|
||||
$endswitch
|
||||
}
|
||||
|
||||
/**
|
||||
* @require is_numerical($Type) "Expected a numerical type"
|
||||
**/
|
||||
macro bool is_unsigned($Type) @const
|
||||
{
|
||||
$switch (inner_kind($Type))
|
||||
$case UNSIGNED_INT:
|
||||
return true;
|
||||
$case VECTOR:
|
||||
return is_unsigned($typefrom($Type.inner));
|
||||
$default:
|
||||
return false;
|
||||
$endswitch
|
||||
}
|
||||
|
||||
macro bool is_indexable($Type) @const
|
||||
{
|
||||
return $defined($Type{}[0]);
|
||||
@@ -209,18 +178,13 @@ macro bool is_vector($Type) @const
|
||||
return $Type.kindof == TypeKind.VECTOR;
|
||||
}
|
||||
|
||||
macro typeid inner_type($Type) @const
|
||||
{
|
||||
$if $Type.kindof == TypeKind.DISTINCT:
|
||||
return inner_type($typefrom($Type.inner));
|
||||
$else
|
||||
return $Type.typeid;
|
||||
$endif
|
||||
}
|
||||
|
||||
macro TypeKind inner_kind($Type) @const
|
||||
{
|
||||
return inner_type($Type).kindof;
|
||||
$if $Type.kindof == TypeKind.DISTINCT:
|
||||
return inner_kind($typefrom($Type.inner));
|
||||
$else
|
||||
return $Type.kindof;
|
||||
$endif
|
||||
}
|
||||
|
||||
macro bool is_same($TypeA, $TypeB) @const
|
||||
|
||||
@@ -1,12 +1,2 @@
|
||||
module std::crypto;
|
||||
|
||||
fn bool safe_compare(void* data1, void* data2, usz len)
|
||||
{
|
||||
char match = 0;
|
||||
for (usz i = 0; i < len; i++)
|
||||
{
|
||||
match = match | (mem::@volatile_load(((char*)data1)[i]) ^ mem::@volatile_load(((char*)data2)[i]));
|
||||
}
|
||||
return match == 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
module std::crypto::dh;
|
||||
import std::math::bigint;
|
||||
|
||||
fn BigInt generate_secret(BigInt p, BigInt x, BigInt y)
|
||||
{
|
||||
return y.mod_pow(x, p);
|
||||
}
|
||||
|
||||
fn BigInt public_key(BigInt p, BigInt g, BigInt x)
|
||||
{
|
||||
return g.mod_pow(x, p);
|
||||
}
|
||||
@@ -22,7 +22,7 @@ fn String[]! CsvReader.read_new_row_with_allocator(self, Allocator allocator = a
|
||||
{
|
||||
@pool(allocator)
|
||||
{
|
||||
return io::treadline(self.stream).split(self.separator, allocator: allocator);
|
||||
return io::treadline(self.stream).split(self.separator, .allocator = allocator);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ macro CsvReader.@each_row(self, int rows = int.max; @body(String[] row))
|
||||
if (err == IoError.EOF) return;
|
||||
return err?;
|
||||
}
|
||||
parts = s.split(sep, allocator: mem);
|
||||
parts = s.split(sep, .allocator = mem);
|
||||
};
|
||||
@body(parts);
|
||||
};
|
||||
|
||||
@@ -27,13 +27,11 @@ fn Object*! temp_parse_string(String s)
|
||||
|
||||
fn Object*! parse(InStream s, Allocator allocator = allocator::heap())
|
||||
{
|
||||
@stack_mem(512; Allocator mem)
|
||||
JsonContext context = { .last_string = dstring::new_with_capacity(64, allocator), .stream = s, .allocator = allocator };
|
||||
defer context.last_string.free();
|
||||
@pool(allocator)
|
||||
{
|
||||
JsonContext context = { .last_string = dstring::new_with_capacity(64, mem), .stream = s, .allocator = allocator };
|
||||
@pool(allocator)
|
||||
{
|
||||
return parse_any(&context);
|
||||
};
|
||||
return parse_any(&context);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -104,9 +102,9 @@ fn Object*! parse_any(JsonContext* context) @local
|
||||
|
||||
fn JsonTokenType! lex_number(JsonContext *context, char c) @local
|
||||
{
|
||||
@stack_mem(256; Allocator mem)
|
||||
@pool()
|
||||
{
|
||||
DString t = dstring::new_with_capacity(32, allocator: mem);
|
||||
DString t = dstring::temp_with_capacity(32);
|
||||
bool negate = c == '-';
|
||||
if (negate)
|
||||
{
|
||||
@@ -154,34 +152,32 @@ fn JsonTokenType! lex_number(JsonContext *context, char c) @local
|
||||
fn Object*! parse_map(JsonContext* context) @local
|
||||
{
|
||||
Object* map = object::new_obj(context.allocator);
|
||||
defer catch map.free();
|
||||
JsonTokenType token = advance(context)!;
|
||||
defer catch map.free();
|
||||
|
||||
@stack_mem(256; Allocator mem)
|
||||
DString temp_key = dstring::new_with_capacity(32, context.allocator);
|
||||
defer temp_key.free();
|
||||
while (token != JsonTokenType.RBRACE)
|
||||
{
|
||||
DString temp_key = dstring::new_with_capacity(32, mem);
|
||||
while (token != JsonTokenType.RBRACE)
|
||||
if (token != JsonTokenType.STRING) return JsonParsingError.UNEXPECTED_CHARACTER?;
|
||||
DString string = context.last_string;
|
||||
if (map.has_key(string.str_view())) return JsonParsingError.DUPLICATE_MEMBERS?;
|
||||
// Copy the key to our temp holder. We do this to work around the issue
|
||||
// if the temp allocator should be used as the default allocator.
|
||||
temp_key.clear();
|
||||
temp_key.append(string);
|
||||
parse_expected(context, COLON)!;
|
||||
Object* element = parse_any(context)!;
|
||||
map.set(temp_key.str_view(), element);
|
||||
token = advance(context)!;
|
||||
if (token == JsonTokenType.COMMA)
|
||||
{
|
||||
if (token != JsonTokenType.STRING) return JsonParsingError.UNEXPECTED_CHARACTER?;
|
||||
DString string = context.last_string;
|
||||
if (map.has_key(string.str_view())) return JsonParsingError.DUPLICATE_MEMBERS?;
|
||||
// Copy the key to our temp holder, since our
|
||||
// last_string may be used in parse_any
|
||||
temp_key.clear();
|
||||
temp_key.append(string);
|
||||
parse_expected(context, COLON)!;
|
||||
Object* element = parse_any(context)!;
|
||||
map.set(temp_key.str_view(), element);
|
||||
token = advance(context)!;
|
||||
if (token == JsonTokenType.COMMA)
|
||||
{
|
||||
token = advance(context)!;
|
||||
continue;
|
||||
}
|
||||
if (token != JsonTokenType.RBRACE) return JsonParsingError.UNEXPECTED_CHARACTER?;
|
||||
continue;
|
||||
}
|
||||
return map;
|
||||
};
|
||||
if (token != JsonTokenType.RBRACE) return JsonParsingError.UNEXPECTED_CHARACTER?;
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
fn Object*! parse_array(JsonContext* context) @local
|
||||
@@ -386,7 +382,6 @@ fn JsonTokenType! lex_string(JsonContext* context)
|
||||
default:
|
||||
return JsonParsingError.INVALID_ESCAPE_SEQUENCE?;
|
||||
}
|
||||
context.last_string.append(c);
|
||||
}
|
||||
return STRING;
|
||||
}
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
module std::hash::hmac(<HashAlg, HASH_BYTES, BLOCK_BYTES>);
|
||||
import std::crypto;
|
||||
|
||||
struct Hmac
|
||||
{
|
||||
HashAlg a, b;
|
||||
}
|
||||
|
||||
fn char[HASH_BYTES] hash(char[] key, char[] message)
|
||||
{
|
||||
Hmac hmac @noinit;
|
||||
hmac.init(key);
|
||||
hmac.update(message);
|
||||
return hmac.final();
|
||||
}
|
||||
|
||||
/**
|
||||
* @require output.len > 0 "Output must be greater than zero"
|
||||
* @require output.len < int.max / HASH_BYTES "Output is too large"
|
||||
**/
|
||||
fn void pbkdf2(char[] pw, char[] salt, uint iterations, char[] output)
|
||||
{
|
||||
usz l = output.len / HASH_BYTES;
|
||||
usz r = output.len % HASH_BYTES;
|
||||
|
||||
Hmac hmac;
|
||||
hmac.init(pw);
|
||||
|
||||
char[] dst_curr = output;
|
||||
for (usz i = 1; i <= l; i++)
|
||||
{
|
||||
@derive(&hmac, salt, iterations, i, dst_curr[:HASH_BYTES]);
|
||||
dst_curr = dst_curr[HASH_BYTES..];
|
||||
}
|
||||
|
||||
if (r > 0)
|
||||
{
|
||||
char[HASH_BYTES] tmp;
|
||||
@derive(&hmac, salt, iterations, l + 1, &tmp);
|
||||
dst_curr[..] = tmp[:dst_curr.len];
|
||||
mem::zero_volatile(&tmp);
|
||||
}
|
||||
}
|
||||
|
||||
fn void Hmac.init(&self, char[] key)
|
||||
{
|
||||
char[BLOCK_BYTES] buffer;
|
||||
if (key.len > BLOCK_BYTES)
|
||||
{
|
||||
self.a.init();
|
||||
self.a.update(key);
|
||||
buffer[:HASH_BYTES] = self.a.final()[..];
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer[:key.len] = key[..];
|
||||
}
|
||||
|
||||
foreach (&b : buffer) *b ^= IPAD;
|
||||
|
||||
self.a.init();
|
||||
self.a.update(&buffer);
|
||||
|
||||
foreach (&b : buffer) *b ^= IPAD ^ OPAD;
|
||||
|
||||
self.b.init();
|
||||
self.b.update(&buffer);
|
||||
|
||||
mem::zero_volatile(&buffer);
|
||||
}
|
||||
|
||||
fn void Hmac.update(&self, char[] data)
|
||||
{
|
||||
self.a.update(data);
|
||||
}
|
||||
|
||||
fn char[HASH_BYTES] Hmac.final(&self)
|
||||
{
|
||||
self.b.update(&&self.a.final());
|
||||
return self.b.final();
|
||||
}
|
||||
|
||||
const IPAD @private = 0x36;
|
||||
const OPAD @private = 0x5C;
|
||||
|
||||
macro @derive(Hmac *hmac_start, char[] salt, uint iterations, usz index, char[] out)
|
||||
{
|
||||
assert(out.len == HASH_BYTES);
|
||||
char[HASH_BYTES] tmp @noinit;
|
||||
defer mem::zero_volatile(&tmp);
|
||||
Hmac hmac = *hmac_start;
|
||||
hmac.update(salt);
|
||||
UIntBE be = { (uint)index };
|
||||
hmac.update(&&bitcast(be, char[4]));
|
||||
tmp = hmac.final();
|
||||
out[..] = tmp;
|
||||
for (int it = 1; it < iterations; it++)
|
||||
{
|
||||
hmac = *hmac_start;
|
||||
hmac.update(&tmp);
|
||||
tmp = hmac.final();
|
||||
foreach (i, v : tmp)
|
||||
{
|
||||
out[i] ^= v;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,225 +0,0 @@
|
||||
module std::hash::md5;
|
||||
import std::hash::hmac;
|
||||
import std::bits;
|
||||
|
||||
const BLOCK_BYTES = 64;
|
||||
const HASH_BYTES = 16;
|
||||
|
||||
struct Md5
|
||||
{
|
||||
uint lo, hi;
|
||||
uint a, b, c, d;
|
||||
char[64] buffer;
|
||||
uint[16] block;
|
||||
}
|
||||
|
||||
def HmacMd5 = Hmac(<Md5, HASH_BYTES, BLOCK_BYTES>);
|
||||
def hmac = hmac::hash(<Md5, HASH_BYTES, BLOCK_BYTES>);
|
||||
def pbkdf2 = hmac::pbkdf2(<Md5, HASH_BYTES, BLOCK_BYTES>);
|
||||
|
||||
fn char[HASH_BYTES] hash(char[] data)
|
||||
{
|
||||
Md5 md5;
|
||||
md5.init();
|
||||
md5.update(data);
|
||||
return md5.final();
|
||||
}
|
||||
|
||||
fn void Md5.init(&self)
|
||||
{
|
||||
self.a = 0x67452301;
|
||||
self.b = 0xefcdab89;
|
||||
self.c = 0x98badcfe;
|
||||
self.d = 0x10325476;
|
||||
|
||||
self.lo = 0;
|
||||
self.hi = 0;
|
||||
}
|
||||
|
||||
|
||||
fn void Md5.update(&ctx, char[] data)
|
||||
{
|
||||
uint saved_lo = ctx.lo;
|
||||
if ((ctx.lo = (saved_lo + data.len) & 0x1fffffff) < saved_lo) ctx.hi++;
|
||||
ctx.hi += data.len >> 29;
|
||||
|
||||
usz used = (usz)saved_lo & 0x3f;
|
||||
|
||||
if (used)
|
||||
{
|
||||
usz available = 64 - used;
|
||||
|
||||
if (data.len < available)
|
||||
{
|
||||
ctx.buffer[used:data.len] = data[..];
|
||||
return;
|
||||
}
|
||||
ctx.buffer[used:available] = data[:available];
|
||||
data = data[available..];
|
||||
body(ctx, &ctx.buffer, 64);
|
||||
}
|
||||
|
||||
if (data.len >= 64)
|
||||
{
|
||||
data = body(ctx, data, data.len & ~(usz)0x3f)[:data.len & 0x3f];
|
||||
}
|
||||
ctx.buffer[:data.len] = data[..];
|
||||
}
|
||||
|
||||
fn char[HASH_BYTES] Md5.final(&ctx)
|
||||
{
|
||||
usz used = (usz)ctx.lo & 0x3f;
|
||||
ctx.buffer[used++] = 0x80;
|
||||
|
||||
usz available = 64 - used;
|
||||
|
||||
if (available < 8)
|
||||
{
|
||||
ctx.buffer[used:available] = 0;
|
||||
body(ctx, &ctx.buffer, 64);
|
||||
used = 0;
|
||||
available = 64;
|
||||
}
|
||||
ctx.buffer[used:available - 8] = 0;
|
||||
|
||||
ctx.lo <<= 3;
|
||||
ctx.buffer[56:4] = bitcast(ctx.lo, char[4])[..];
|
||||
ctx.buffer[60:4] = bitcast(ctx.hi, char[4])[..];
|
||||
|
||||
body(ctx, &ctx.buffer, 64);
|
||||
|
||||
char[16] res @noinit;
|
||||
res[0:4] = bitcast(ctx.a, char[4]);
|
||||
res[4:4] = bitcast(ctx.b, char[4]);
|
||||
res[8:4] = bitcast(ctx.c, char[4]);
|
||||
res[12:4] = bitcast(ctx.d, char[4]);
|
||||
*ctx = {};
|
||||
return res;
|
||||
}
|
||||
|
||||
module std::hash::md5 @private;
|
||||
|
||||
// Implementation
|
||||
macro @f(x, y, z) => z ^ (x & (y ^ z));
|
||||
macro @g(x, y, z) => y ^ (z & (x ^ y));
|
||||
macro @h(x, y, z) => (x ^ y) ^ z;
|
||||
macro @h2(x, y, z) => x ^ (y ^ z);
|
||||
macro @i(x, y, z) => y ^ (x | ~z);
|
||||
|
||||
macro @step(#f, &a, b, c, d, ptr, n, t, s)
|
||||
{
|
||||
*a += #f(b, c, d) + *(uint *)&ptr[n * 4] + t;
|
||||
*a = (*a << s) | ((*a & 0xffffffff) >> (32 - s));
|
||||
*a += b;
|
||||
}
|
||||
|
||||
|
||||
fn char* body(Md5* ctx, void* data, usz size)
|
||||
{
|
||||
char* ptr;
|
||||
uint a, b, c, d;
|
||||
uint saved_a, saved_b, saved_c, saved_d;
|
||||
ptr = data;
|
||||
a = ctx.a;
|
||||
b = ctx.b;
|
||||
c = ctx.c;
|
||||
d = ctx.d;
|
||||
|
||||
do
|
||||
{
|
||||
saved_a = a;
|
||||
saved_b = b;
|
||||
saved_c = c;
|
||||
saved_d = d;
|
||||
|
||||
/* Round 1 */
|
||||
@step(@f, a, b, c, d, ptr, 0, 0xd76aa478, 7) ;
|
||||
@step(@f, d, a, b, c, ptr, 1, 0xe8c7b756, 12) ;
|
||||
@step(@f, c, d, a, b, ptr, 2, 0x242070db, 17) ;
|
||||
@step(@f, b, c, d, a, ptr, 3, 0xc1bdceee, 22) ;
|
||||
@step(@f, a, b, c, d, ptr, 4, 0xf57c0faf, 7) ;
|
||||
@step(@f, d, a, b, c, ptr, 5, 0x4787c62a, 12) ;
|
||||
@step(@f, c, d, a, b, ptr, 6, 0xa8304613, 17) ;
|
||||
@step(@f, b, c, d, a, ptr, 7, 0xfd469501, 22) ;
|
||||
@step(@f, a, b, c, d, ptr, 8, 0x698098d8, 7) ;
|
||||
@step(@f, d, a, b, c, ptr, 9, 0x8b44f7af, 12) ;
|
||||
@step(@f, c, d, a, b, ptr, 10, 0xffff5bb1, 17);
|
||||
@step(@f, b, c, d, a, ptr, 11, 0x895cd7be, 22);
|
||||
@step(@f, a, b, c, d, ptr, 12, 0x6b901122, 7) ;
|
||||
@step(@f, d, a, b, c, ptr, 13, 0xfd987193, 12);
|
||||
@step(@f, c, d, a, b, ptr, 14, 0xa679438e, 17);
|
||||
@step(@f, b, c, d, a, ptr, 15, 0x49b40821, 22);
|
||||
|
||||
/* Round 2 */
|
||||
@step(@g, a, b, c, d, ptr, 1, 0xf61e2562, 5) ;
|
||||
@step(@g, d, a, b, c, ptr, 6, 0xc040b340, 9) ;
|
||||
@step(@g, c, d, a, b, ptr, 11, 0x265e5a51, 14);
|
||||
@step(@g, b, c, d, a, ptr, 0, 0xe9b6c7aa, 20) ;
|
||||
@step(@g, a, b, c, d, ptr, 5, 0xd62f105d, 5) ;
|
||||
@step(@g, d, a, b, c, ptr, 10, 0x02441453, 9) ;
|
||||
@step(@g, c, d, a, b, ptr, 15, 0xd8a1e681, 14);
|
||||
@step(@g, b, c, d, a, ptr, 4, 0xe7d3fbc8, 20) ;
|
||||
@step(@g, a, b, c, d, ptr, 9, 0x21e1cde6, 5) ;
|
||||
@step(@g, d, a, b, c, ptr, 14, 0xc33707d6, 9) ;
|
||||
@step(@g, c, d, a, b, ptr, 3, 0xf4d50d87, 14) ;
|
||||
@step(@g, b, c, d, a, ptr, 8, 0x455a14ed, 20) ;
|
||||
@step(@g, a, b, c, d, ptr, 13, 0xa9e3e905, 5) ;
|
||||
@step(@g, d, a, b, c, ptr, 2, 0xfcefa3f8, 9) ;
|
||||
@step(@g, c, d, a, b, ptr, 7, 0x676f02d9, 14) ;
|
||||
@step(@g, b, c, d, a, ptr, 12, 0x8d2a4c8a, 20);
|
||||
|
||||
/* Round 3 */
|
||||
@step(@h, a, b, c, d, ptr, 5, 0xfffa3942, 4);
|
||||
@step(@h2, d, a, b, c, ptr, 8, 0x8771f681, 11);
|
||||
@step(@h, c, d, a, b, ptr, 11, 0x6d9d6122, 16);
|
||||
@step(@h2, b, c, d, a, ptr, 14, 0xfde5380c, 23);
|
||||
@step(@h, a, b, c, d, ptr, 1, 0xa4beea44, 4);
|
||||
@step(@h2, d, a, b, c, ptr, 4, 0x4bdecfa9, 11);
|
||||
@step(@h, c, d, a, b, ptr, 7, 0xf6bb4b60, 16);
|
||||
@step(@h2, b, c, d, a, ptr, 10, 0xbebfbc70, 23);
|
||||
@step(@h, a, b, c, d, ptr, 13, 0x289b7ec6, 4) ;
|
||||
@step(@h2, d, a, b, c, ptr, 0, 0xeaa127fa, 11) ;
|
||||
@step(@h, c, d, a, b, ptr, 3, 0xd4ef3085, 16) ;
|
||||
@step(@h2, b, c, d, a, ptr, 6, 0x04881d05, 23) ;
|
||||
@step(@h, a, b, c, d, ptr, 9, 0xd9d4d039, 4) ;
|
||||
@step(@h2, d, a, b, c, ptr, 12, 0xe6db99e5, 11) ;
|
||||
@step(@h, c, d, a, b, ptr, 15, 0x1fa27cf8, 16) ;
|
||||
@step(@h2, b, c, d, a, ptr, 2, 0xc4ac5665, 23) ;
|
||||
|
||||
/* Round 4 */
|
||||
@step(@i, a, b, c, d, ptr, 0, 0xf4292244, 6) ;
|
||||
@step(@i, d, a, b, c, ptr, 7, 0x432aff97, 10) ;
|
||||
@step(@i, c, d, a, b, ptr, 14, 0xab9423a7, 15) ;
|
||||
@step(@i, b, c, d, a, ptr, 5, 0xfc93a039, 21) ;
|
||||
@step(@i, a, b, c, d, ptr, 12, 0x655b59c3, 6) ;
|
||||
@step(@i, d, a, b, c, ptr, 3, 0x8f0ccc92, 10) ;
|
||||
@step(@i, c, d, a, b, ptr, 10, 0xffeff47d, 15) ;
|
||||
@step(@i, b, c, d, a, ptr, 1, 0x85845dd1, 21) ;
|
||||
@step(@i, a, b, c, d, ptr, 8, 0x6fa87e4f, 6) ;
|
||||
@step(@i, d, a, b, c, ptr, 15, 0xfe2ce6e0, 10) ;
|
||||
@step(@i, c, d, a, b, ptr, 6, 0xa3014314, 15) ;
|
||||
@step(@i, b, c, d, a, ptr, 13, 0x4e0811a1, 21) ;
|
||||
@step(@i, a, b, c, d, ptr, 4, 0xf7537e82, 6) ;
|
||||
@step(@i, d, a, b, c, ptr, 11, 0xbd3af235, 10) ;
|
||||
@step(@i, c, d, a, b, ptr, 2, 0x2ad7d2bb, 15) ;
|
||||
@step(@i, b, c, d, a, ptr, 9, 0xeb86d391, 21) ;
|
||||
|
||||
a += saved_a;
|
||||
b += saved_b;
|
||||
c += saved_c;
|
||||
d += saved_d;
|
||||
|
||||
ptr += 64;
|
||||
|
||||
} while (size -= 64);
|
||||
|
||||
ctx.a = a;
|
||||
ctx.b = b;
|
||||
ctx.c = c;
|
||||
ctx.d = d;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -5,29 +5,13 @@
|
||||
// Implementation was off Steve Reid's SHA-1 C implementation
|
||||
|
||||
module std::hash::sha1;
|
||||
import std::hash::hmac;
|
||||
import std::bits;
|
||||
|
||||
const BLOCK_BYTES = 64;
|
||||
const HASH_BYTES = 20;
|
||||
|
||||
struct Sha1
|
||||
{
|
||||
uint[5] state;
|
||||
uint[2] count;
|
||||
char[BLOCK_BYTES] buffer;
|
||||
}
|
||||
|
||||
def HmacSha1 = Hmac(<Sha1, HASH_BYTES, BLOCK_BYTES>);
|
||||
def hmac = hmac::hash(<Sha1, HASH_BYTES, BLOCK_BYTES>);
|
||||
def pbkdf2 = hmac::pbkdf2(<Sha1, HASH_BYTES, BLOCK_BYTES>);
|
||||
|
||||
fn char[HASH_BYTES] hash(char[] data)
|
||||
{
|
||||
Sha1 sha1 @noinit;
|
||||
sha1.init();
|
||||
sha1.update(data);
|
||||
return sha1.final();
|
||||
char[64] buffer;
|
||||
}
|
||||
|
||||
fn void Sha1.init(&self)
|
||||
@@ -71,7 +55,7 @@ fn void Sha1.update(&self, char[] data)
|
||||
}
|
||||
|
||||
|
||||
fn char[HASH_BYTES] Sha1.final(&self)
|
||||
fn char[20] Sha1.final(&self)
|
||||
{
|
||||
char[8] finalcount;
|
||||
for (uint i = 0; i < 8; i++)
|
||||
@@ -85,21 +69,21 @@ fn char[HASH_BYTES] Sha1.final(&self)
|
||||
}
|
||||
|
||||
self.update(&finalcount);
|
||||
char[HASH_BYTES] digest;
|
||||
for (uint i = 0; i < HASH_BYTES; i++)
|
||||
char[20] digest;
|
||||
for (uint i = 0; i < 20; i++)
|
||||
{
|
||||
digest[i] = (char)((self.state[i >> 2] >> ((3 - (i & 3)) * 8)) & 0xFF);
|
||||
}
|
||||
|
||||
// Clear mem
|
||||
*self = {};
|
||||
mem::clear(self, Sha1.sizeof);
|
||||
finalcount = {};
|
||||
return digest;
|
||||
}
|
||||
|
||||
union Long16 @local
|
||||
{
|
||||
char[BLOCK_BYTES] c;
|
||||
char[64] c;
|
||||
uint[16] l;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,176 +0,0 @@
|
||||
module std::hash::sha256;
|
||||
|
||||
import std::hash::hmac;
|
||||
|
||||
const BLOCK_SIZE = 64;
|
||||
const HASH_SIZE = 32;
|
||||
|
||||
const uint[64] K @local = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
};
|
||||
|
||||
// Right rotate function
|
||||
macro uint @rotr(uint x, uint n) @local => (((x) >> (n)) | ((x) << (32 - (n))));
|
||||
|
||||
// SHA-256 functions
|
||||
macro uint @ch(uint x, uint y, uint z) @local => (x & y) ^ (~x & z);
|
||||
macro uint @maj(uint x, uint y, uint z) @local => (x & y) ^ (x & z) ^ (y & z);
|
||||
macro uint @_sigma0(uint x) @local => @rotr(x, 2) ^ @rotr(x, 13) ^ @rotr(x, 22);
|
||||
macro uint @_sigma1(uint x) @local => @rotr(x, 6) ^ @rotr(x, 11) ^ @rotr(x, 25);
|
||||
macro uint @sigma0(uint x) @local => @rotr(x, 7) ^ @rotr(x, 18) ^ (x >> 3);
|
||||
macro uint @sigma1(uint x) @local => @rotr(x, 17) ^ @rotr(x, 19) ^ (x >> 10);
|
||||
|
||||
struct Sha256
|
||||
{
|
||||
uint[8] state;
|
||||
ulong bitcount;
|
||||
char[BLOCK_SIZE] buffer;
|
||||
}
|
||||
|
||||
def HmacSha256 = Hmac(<Sha256, HASH_SIZE, BLOCK_SIZE>);
|
||||
def hmac = hmac::hash(<Sha256, HASH_SIZE, BLOCK_SIZE>);
|
||||
def pbkdf2 = hmac::pbkdf2(<Sha256, HASH_SIZE, BLOCK_SIZE>);
|
||||
|
||||
fn char[HASH_SIZE] hash(char[] data)
|
||||
{
|
||||
Sha256 sha256 @noinit;
|
||||
sha256.init();
|
||||
sha256.update(data);
|
||||
return sha256.final();
|
||||
}
|
||||
|
||||
fn void Sha256.init(&self)
|
||||
{
|
||||
// Sha256 initialization constants
|
||||
*self = {
|
||||
.state = {
|
||||
0x6A09E667,
|
||||
0xBB67AE85,
|
||||
0x3C6EF372,
|
||||
0xA54FF53A,
|
||||
0x510E527F,
|
||||
0x9B05688C,
|
||||
0x1F83D9AB,
|
||||
0x5BE0CD19
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [in] data
|
||||
* @require data.len <= uint.max
|
||||
**/
|
||||
fn void Sha256.update(&self, char[] data) {
|
||||
uint i = 0;
|
||||
uint len = data.len;
|
||||
uint buffer_pos = (uint)(self.bitcount / 8) % BLOCK_SIZE;
|
||||
self.bitcount += (ulong)(len * 8);
|
||||
|
||||
while (len--) {
|
||||
self.buffer[buffer_pos++] = data[i++];
|
||||
if (buffer_pos == BLOCK_SIZE) {
|
||||
sha256_transform(&self.state, &self.buffer);
|
||||
buffer_pos = 0; // Reset buffer position
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn char[HASH_SIZE] Sha256.final(&self) {
|
||||
char[HASH_SIZE] hash;
|
||||
ulong i = (self.bitcount / 8) % BLOCK_SIZE;
|
||||
|
||||
// Append 0x80 to the buffer
|
||||
self.buffer[i++] = 0x80;
|
||||
|
||||
// Pad the buffer with zeros
|
||||
if (i > BLOCK_SIZE - 8) {
|
||||
while (i < BLOCK_SIZE) {
|
||||
self.buffer[i++] = 0x00;
|
||||
}
|
||||
sha256_transform(&self.state, &self.buffer);
|
||||
i = 0; // Reset buffer index after transformation
|
||||
}
|
||||
|
||||
while (i < BLOCK_SIZE - 8) {
|
||||
self.buffer[i++] = 0x00;
|
||||
}
|
||||
|
||||
// Append the bitcount in big-endian format
|
||||
for (int j = 0; j < 8; ++j) {
|
||||
self.buffer[BLOCK_SIZE - 8 + j] = (char)((self.bitcount >> (56 - j * 8)) & 0xFF);
|
||||
}
|
||||
|
||||
sha256_transform(&self.state, &self.buffer);
|
||||
|
||||
// Convert state to the final hash
|
||||
for (i = 0; i < 8; ++i) {
|
||||
hash[i * 4] = (char)((self.state[i] >> 24) & 0xFF);
|
||||
hash[i * 4 + 1] = (char)((self.state[i] >> 16) & 0xFF);
|
||||
hash[i * 4 + 2] = (char)((self.state[i] >> 8) & 0xFF);
|
||||
hash[i * 4 + 3] = (char)(self.state[i] & 0xFF);
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [&inout] state
|
||||
* @param [&in] buffer
|
||||
**/
|
||||
fn void sha256_transform(uint* state, char* buffer) @local {
|
||||
uint a, b, c, d, e, f, g, h, t1, t2;
|
||||
uint[64] m;
|
||||
int i;
|
||||
|
||||
// Prepare the message schedule
|
||||
for (i = 0; i < 16; ++i) {
|
||||
m[i] = ((uint)buffer[i * 4] << 24) | ((uint)buffer[i * 4 + 1] << 16) |
|
||||
((uint)buffer[i * 4 + 2] << 8) | ((uint)buffer[i * 4 + 3]); // Ensure values are cast to uint for correct shifts
|
||||
}
|
||||
for (i = 16; i < 64; ++i) {
|
||||
m[i] = @sigma1(m[i - 2]) + m[i - 7] + @sigma0(m[i - 15]) + m[i - 16];
|
||||
}
|
||||
|
||||
// Initialize working variables
|
||||
a = state[0];
|
||||
b = state[1];
|
||||
c = state[2];
|
||||
d = state[3];
|
||||
e = state[4];
|
||||
f = state[5];
|
||||
g = state[6];
|
||||
h = state[7];
|
||||
|
||||
// Perform the main SHA-256 compression function
|
||||
for (i = 0; i < 64; ++i) {
|
||||
t1 = h + @_sigma1(e) + @ch(e, f, g) + K[i] + m[i];
|
||||
t2 = @_sigma0(a) + @maj(a, b, c);
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = d + t1;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = t1 + t2;
|
||||
}
|
||||
|
||||
// Update the state
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
state[4] += e;
|
||||
state[5] += f;
|
||||
state[6] += g;
|
||||
state[7] += h;
|
||||
a = b = c = d = e = f = g = h = t1 = t2 = i = 0;
|
||||
m[:64] = buffer[:64] = 0;
|
||||
}
|
||||
@@ -76,7 +76,7 @@ fn void! File.memopen(File* file, char[] data, String mode)
|
||||
*/
|
||||
fn void! File.write_byte(&self, char c) @dynamic
|
||||
{
|
||||
return os::native_fputc(c, self.file);
|
||||
if (!libc::fputc(c, self.file)) return IoError.EOF?;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,8 +6,7 @@ const int PRINTF_NTOA_BUFFER_SIZE = 256;
|
||||
|
||||
interface Printable
|
||||
{
|
||||
fn String to_string(Allocator allocator) @optional;
|
||||
fn String to_new_string(Allocator allocator) @optional @deprecated("Use to_string");
|
||||
fn String to_new_string(Allocator allocator) @optional;
|
||||
fn usz! to_format(Formatter* formatter) @optional;
|
||||
}
|
||||
|
||||
@@ -15,14 +14,24 @@ fault PrintFault
|
||||
{
|
||||
BUFFER_EXCEEDED,
|
||||
INTERNAL_BUFFER_EXCEEDED,
|
||||
INVALID_FORMAT,
|
||||
NOT_ENOUGH_ARGUMENTS,
|
||||
INVALID_ARGUMENT,
|
||||
INVALID_FORMAT_STRING,
|
||||
MISSING_ARG,
|
||||
INVALID_ARGUMENT_TYPE,
|
||||
}
|
||||
|
||||
fault FormattingFault
|
||||
{
|
||||
UNTERMINATED_FORMAT,
|
||||
MISSING_ARG,
|
||||
INVALID_WIDTH_ARG,
|
||||
INVALID_FORMAT_TYPE,
|
||||
}
|
||||
|
||||
def OutputFn = fn void!(void* buffer, char c);
|
||||
def FloatType = double;
|
||||
|
||||
|
||||
|
||||
fn usz! Formatter.printf(&self, String format, args...)
|
||||
{
|
||||
return self.vprintf(format, args) @inline;
|
||||
@@ -38,7 +47,6 @@ struct Formatter
|
||||
uint width;
|
||||
uint prec;
|
||||
usz idx;
|
||||
anyfault first_fault;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,12 +68,7 @@ fn void Formatter.init(&self, OutputFn out_fn, void* data = null)
|
||||
|
||||
fn usz! Formatter.out(&self, char c) @private
|
||||
{
|
||||
if (catch err = self.out_fn(self.data, c))
|
||||
{
|
||||
if (self.first_fault) return self.first_fault?;
|
||||
self.first_fault = err;
|
||||
return err?;
|
||||
}
|
||||
self.out_fn(self.data, c)!;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -85,7 +88,7 @@ fn usz! Formatter.print_with_function(&self, Printable arg)
|
||||
if (!arg) return self.out_substr("(null)");
|
||||
return arg.to_format(self);
|
||||
}
|
||||
if (&arg.to_string)
|
||||
if (&arg.to_new_string)
|
||||
{
|
||||
PrintFlags old = self.flags;
|
||||
uint old_width = self.width;
|
||||
@@ -99,7 +102,7 @@ fn usz! Formatter.print_with_function(&self, Printable arg)
|
||||
if (!arg) return self.out_substr("(null)");
|
||||
@stack_mem(1024; Allocator mem)
|
||||
{
|
||||
return self.out_substr(arg.to_string(mem));
|
||||
return self.out_substr(arg.to_new_string(mem));
|
||||
};
|
||||
}
|
||||
return SearchResult.MISSING?;
|
||||
@@ -117,7 +120,6 @@ fn usz! Formatter.out_str(&self, any arg) @private
|
||||
case ANYFAULT:
|
||||
case FAULT:
|
||||
return self.out_substr((*(anyfault*)arg.ptr).nameof);
|
||||
case INTERFACE:
|
||||
case ANY:
|
||||
return self.out_str(*(any*)arg);
|
||||
case OPTIONAL:
|
||||
@@ -133,7 +135,7 @@ fn usz! Formatter.out_str(&self, any arg) @private
|
||||
}
|
||||
self.flags = {};
|
||||
self.width = 0;
|
||||
return self.ntoa_any(arg, 10) ?? self.out_substr("<INVALID>");
|
||||
return self.ntoa_any(arg, 10);
|
||||
case FLOAT:
|
||||
PrintFlags flags = self.flags;
|
||||
uint width = self.width;
|
||||
@@ -144,7 +146,7 @@ fn usz! Formatter.out_str(&self, any arg) @private
|
||||
}
|
||||
self.flags = {};
|
||||
self.width = 0;
|
||||
return self.ftoa(float_from_any(arg)) ?? self.out_substr("ERR");
|
||||
return self.ftoa(float_from_any(arg)!!);
|
||||
case BOOL:
|
||||
return self.out_substr(*(bool*)arg.ptr ? "true" : "false");
|
||||
default:
|
||||
@@ -159,12 +161,6 @@ fn usz! Formatter.out_str(&self, any arg) @private
|
||||
assert(i < arg.type.names.len, "Illegal enum value found, numerical value was %d.", i);
|
||||
return self.out_substr(arg.type.names[i]);
|
||||
case STRUCT:
|
||||
if (arg.type == ReflectedParam.typeid)
|
||||
{
|
||||
ReflectedParam* param = arg.ptr;
|
||||
return self.out_substr("[Parameter '")
|
||||
+ self.out_substr(param.name) + self.out_substr("']");
|
||||
}
|
||||
return self.out_substr("<struct>");
|
||||
case UNION:
|
||||
return self.out_substr("<union>");
|
||||
@@ -283,9 +279,6 @@ fn usz! Formatter.out_str(&self, any arg) @private
|
||||
}
|
||||
len += self.out(']')!;
|
||||
return len;
|
||||
case ANY:
|
||||
case INTERFACE:
|
||||
unreachable("Already handled");
|
||||
default:
|
||||
}
|
||||
return self.out_substr("Invalid type");
|
||||
@@ -298,31 +291,10 @@ fn void! out_null_fn(void* data @unused, char c @unused) @private
|
||||
{
|
||||
}
|
||||
|
||||
macro usz! @report_fault(Formatter* f, $fault)
|
||||
{
|
||||
(void)f.out_substr($fault);
|
||||
return PrintFault.INVALID_FORMAT?;
|
||||
}
|
||||
|
||||
macro usz! @wrap_bad(Formatter* f, #action)
|
||||
{
|
||||
usz! len = #action;
|
||||
if (catch err = len)
|
||||
{
|
||||
case PrintFault.BUFFER_EXCEEDED:
|
||||
case PrintFault.INTERNAL_BUFFER_EXCEEDED:
|
||||
return f.first_err(err)?;
|
||||
default:
|
||||
err = f.first_err(PrintFault.INVALID_ARGUMENT);
|
||||
f.out_substr("<INVALID>")!;
|
||||
return err?;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
fn usz! Formatter.vprintf(&self, String format, any[] anys)
|
||||
{
|
||||
self.first_fault = {};
|
||||
if (!self.out_fn)
|
||||
{
|
||||
// use null output function
|
||||
@@ -342,7 +314,7 @@ fn usz! Formatter.vprintf(&self, String format, any[] anys)
|
||||
continue;
|
||||
}
|
||||
i++;
|
||||
if (i >= format_len) return @report_fault(self, "%ERR");
|
||||
if (i >= format_len) return PrintFault.INVALID_FORMAT_STRING?;
|
||||
c = format[i];
|
||||
if (c == '%')
|
||||
{
|
||||
@@ -362,12 +334,11 @@ fn usz! Formatter.vprintf(&self, String format, any[] anys)
|
||||
case '#': self.flags.hash = true;
|
||||
default: break FLAG_EVAL;
|
||||
}
|
||||
if (++i >= format_len) return @report_fault(self, "%ERR");
|
||||
if (++i >= format_len) return PrintFault.INVALID_FORMAT_STRING?;
|
||||
c = format[i];
|
||||
}
|
||||
// evaluate width field
|
||||
int! w = printf_parse_format_field(anys.ptr, anys.len, &variant_index, format.ptr, format.len, &i);
|
||||
if (catch w) return @report_fault(self, "%ERR");
|
||||
int w = printf_parse_format_field(anys.ptr, anys.len, &variant_index, format.ptr, format.len, &i)!;
|
||||
c = format[i];
|
||||
if (w < 0)
|
||||
{
|
||||
@@ -380,21 +351,15 @@ fn usz! Formatter.vprintf(&self, String format, any[] anys)
|
||||
if (c == '.')
|
||||
{
|
||||
self.flags.precision = true;
|
||||
if (++i >= format_len) return @report_fault(self, "<BAD FORMAT>");
|
||||
int! prec = printf_parse_format_field(anys.ptr, anys.len, &variant_index, format.ptr, format.len, &i);
|
||||
if (catch prec) return @report_fault(self, "<BAD FORMAT>");
|
||||
if (++i >= format_len) return PrintFault.INVALID_FORMAT_STRING?;
|
||||
int prec = printf_parse_format_field(anys.ptr, anys.len, &variant_index, format.ptr, format.len, &i)!;
|
||||
self.prec = prec < 0 ? 0 : prec;
|
||||
c = format[i];
|
||||
}
|
||||
|
||||
// evaluate specifier
|
||||
uint base = 0;
|
||||
if (variant_index >= anys.len)
|
||||
{
|
||||
self.first_err(PrintFault.NOT_ENOUGH_ARGUMENTS);
|
||||
total_len += self.out_substr("<MISSING>")!;
|
||||
continue;
|
||||
}
|
||||
if (variant_index >= anys.len) return PrintFault.MISSING_ARG?;
|
||||
any current = anys[variant_index++];
|
||||
switch (c)
|
||||
{
|
||||
@@ -420,25 +385,25 @@ fn usz! Formatter.vprintf(&self, String format, any[] anys)
|
||||
self.flags.uppercase = true;
|
||||
nextcase;
|
||||
case 'a':
|
||||
total_len += @wrap_bad(self, self.atoa(float_from_any(current)))!;
|
||||
total_len += self.atoa(float_from_any(current)!!)!;
|
||||
continue;
|
||||
case 'F' :
|
||||
self.flags.uppercase = true;
|
||||
nextcase;
|
||||
case 'f':
|
||||
total_len += @wrap_bad(self, self.ftoa(float_from_any(current)))!;
|
||||
total_len += self.ftoa(float_from_any(current)!!)!;
|
||||
continue;
|
||||
case 'E':
|
||||
self.flags.uppercase = true;
|
||||
nextcase;
|
||||
case 'e':
|
||||
total_len += @wrap_bad(self, self.etoa(float_from_any(current)))!;
|
||||
total_len += self.etoa(float_from_any(current)!!)!;
|
||||
continue;
|
||||
case 'G':
|
||||
self.flags.uppercase = true;
|
||||
nextcase;
|
||||
case 'g':
|
||||
total_len += @wrap_bad(self, self.gtoa(float_from_any(current)))!;
|
||||
total_len += self.gtoa(float_from_any(current)!!)!;
|
||||
continue;
|
||||
case 'c':
|
||||
total_len += self.out_char(current)!;
|
||||
@@ -463,9 +428,7 @@ fn usz! Formatter.vprintf(&self, String format, any[] anys)
|
||||
self.flags.hash = true;
|
||||
base = 16;
|
||||
default:
|
||||
self.first_err(PrintFault.INVALID_FORMAT);
|
||||
total_len += self.out_substr("<BAD FORMAT>")!;
|
||||
continue;
|
||||
return PrintFault.INVALID_FORMAT_STRING?;
|
||||
}
|
||||
if (base != 10)
|
||||
{
|
||||
@@ -476,13 +439,14 @@ fn usz! Formatter.vprintf(&self, String format, any[] anys)
|
||||
if (self.flags.precision) self.flags.zeropad = false;
|
||||
|
||||
bool is_neg;
|
||||
total_len += @wrap_bad(self, self.ntoa(int_from_any(current, &is_neg), is_neg, base))!;
|
||||
uint128 v = int_from_any(current, &is_neg)!!;
|
||||
|
||||
total_len += self.ntoa(v, is_neg, base)!;
|
||||
}
|
||||
// termination
|
||||
// out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen);
|
||||
|
||||
// return written chars without terminating \0
|
||||
if (self.first_fault) return self.first_fault?;
|
||||
return total_len;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,18 +4,6 @@ import std::math;
|
||||
const char[16] XDIGITS_H = "0123456789ABCDEF";
|
||||
const char[16] XDIGITS_L = "0123456789abcdef";
|
||||
|
||||
fault FormattingFault
|
||||
{
|
||||
BAD_FORMAT
|
||||
}
|
||||
|
||||
macro Formatter.first_err(&self, anyfault f)
|
||||
{
|
||||
if (self.first_fault) return self.first_fault;
|
||||
self.first_fault = f;
|
||||
return f;
|
||||
}
|
||||
|
||||
fn usz! Formatter.adjust(&self, usz len) @local
|
||||
{
|
||||
if (!self.flags.left) return 0;
|
||||
@@ -33,7 +21,6 @@ fn uint128! int_from_any(any arg, bool *is_neg) @private
|
||||
case TypeKind.ENUM:
|
||||
return int_from_any(arg.as_inner(), is_neg);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
*is_neg = false;
|
||||
switch (arg)
|
||||
@@ -72,7 +59,7 @@ fn uint128! int_from_any(any arg, bool *is_neg) @private
|
||||
double d = *arg;
|
||||
return (uint128)((*is_neg = d < 0) ? -d : d);
|
||||
default:
|
||||
return FormattingFault.BAD_FORMAT?;
|
||||
return PrintFault.INVALID_ARGUMENT_TYPE?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +101,7 @@ fn FloatType! float_from_any(any arg) @private
|
||||
case double:
|
||||
return (FloatType)*arg;
|
||||
default:
|
||||
return FormattingFault.BAD_FORMAT?;
|
||||
return PrintFault.INVALID_ARGUMENT_TYPE?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -601,7 +588,8 @@ fn usz! Formatter.ntoa_format(&self, String buf, usz len, bool negative, uint ba
|
||||
fn usz! Formatter.ntoa_any(&self, any arg, uint base) @private
|
||||
{
|
||||
bool is_neg;
|
||||
return self.ntoa(int_from_any(arg, &is_neg)!!, is_neg, base) @inline;
|
||||
uint128 val = int_from_any(arg, &is_neg)!!;
|
||||
return self.ntoa(val, is_neg, base) @inline;
|
||||
}
|
||||
|
||||
fn usz! Formatter.out_char(&self, any arg) @private
|
||||
@@ -652,6 +640,17 @@ fn usz! Formatter.out_reverse(&self, char[] buf) @private
|
||||
return n;
|
||||
}
|
||||
|
||||
fn void! printf_advance_format(usz format_len, usz *index_ptr) @inline @private
|
||||
{
|
||||
usz val = ++(*index_ptr);
|
||||
if (val >= format_len) return FormattingFault.UNTERMINATED_FORMAT?;
|
||||
}
|
||||
|
||||
fn any! next_any(any* args_ptr, usz args_len, usz* arg_index_ptr) @inline @private
|
||||
{
|
||||
if (*arg_index_ptr >= args_len) return FormattingFault.MISSING_ARG?;
|
||||
return args_ptr[(*arg_index_ptr)++];
|
||||
}
|
||||
|
||||
fn int! printf_parse_format_field(
|
||||
any* args_ptr, usz args_len, usz* args_index_ptr,
|
||||
@@ -660,11 +659,9 @@ fn int! printf_parse_format_field(
|
||||
char c = format_ptr[*index_ptr];
|
||||
if (c.is_digit()) return simple_atoi(format_ptr, format_len, index_ptr);
|
||||
if (c != '*') return 0;
|
||||
usz len = ++(*index_ptr);
|
||||
if (len >= format_len) return FormattingFault.BAD_FORMAT?;
|
||||
if (*args_index_ptr >= args_len) return FormattingFault.BAD_FORMAT?;
|
||||
any val = args_ptr[(*args_index_ptr)++];
|
||||
if (!val.type.kindof.is_int()) return FormattingFault.BAD_FORMAT?;
|
||||
printf_advance_format(format_len, index_ptr)!;
|
||||
any val = next_any(args_ptr, args_len, args_index_ptr)!;
|
||||
if (!val.type.kindof.is_int()) return FormattingFault.INVALID_WIDTH_ARG?;
|
||||
uint! intval = types::any_to_int(val, int);
|
||||
return intval ?? FormattingFault.BAD_FORMAT?;
|
||||
return intval ?? FormattingFault.INVALID_WIDTH_ARG?;
|
||||
}
|
||||
|
||||
@@ -256,7 +256,7 @@ fn usz! printfn(String format, args...) @maydiscard
|
||||
{
|
||||
Formatter formatter;
|
||||
formatter.init(&out_putchar_fn);
|
||||
usz! len = formatter.vprintf(format, args);
|
||||
usz len = formatter.vprintf(format, args)!;
|
||||
putchar('\n');
|
||||
io::stdout().flush()!;
|
||||
return len + 1;
|
||||
@@ -290,10 +290,10 @@ fn usz! eprintfn(String format, args...) @maydiscard
|
||||
Formatter formatter;
|
||||
OutStream stream = stderr();
|
||||
formatter.init(&out_putstream_fn, &stream);
|
||||
usz! len = formatter.vprintf(format, args);
|
||||
usz len = formatter.vprintf(format, args)! + 1;
|
||||
stderr().write_byte('\n')!;
|
||||
stderr().flush()!;
|
||||
return len + 1;
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -401,11 +401,3 @@ fn File* stdin()
|
||||
{
|
||||
return &stdin_file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap bytes for reading using io functions.
|
||||
**/
|
||||
fn ByteReader wrap_bytes(char[] bytes)
|
||||
{
|
||||
return { bytes, 0 };
|
||||
}
|
||||
@@ -75,11 +75,6 @@ fn usz! native_fwrite(CFile file, char[] buffer) @inline
|
||||
return libc::fwrite(buffer.ptr, 1, buffer.len, file);
|
||||
}
|
||||
|
||||
fn void! native_fputc(CInt c, CFile stream) @inline
|
||||
{
|
||||
if (!libc::fputc(c, stream)) return IoError.EOF?;
|
||||
}
|
||||
|
||||
fn usz! native_fread(CFile file, char[] buffer) @inline
|
||||
{
|
||||
return libc::fread(buffer.ptr, 1, buffer.len, file);
|
||||
|
||||
@@ -9,7 +9,6 @@ def FtellFn = fn usz!(void*);
|
||||
def FwriteFn = fn usz!(void*, char[] buffer);
|
||||
def FreadFn = fn usz!(void*, char[] buffer);
|
||||
def RemoveFn = fn void!(String);
|
||||
def FputcFn = fn void!(int, void*);
|
||||
|
||||
FopenFn native_fopen_fn @weak @if(!$defined(native_fopen_fn));
|
||||
FcloseFn native_fclose_fn @weak @if(!$defined(native_fclose_fn));
|
||||
@@ -19,7 +18,6 @@ FtellFn native_ftell_fn @weak @if(!$defined(native_ftell_fn));
|
||||
FwriteFn native_fwrite_fn @weak @if(!$defined(native_fwrite_fn));
|
||||
FreadFn native_fread_fn @weak @if(!$defined(native_fread_fn));
|
||||
RemoveFn native_remove_fn @weak @if(!$defined(native_remove_fn));
|
||||
FputcFn native_fputc_fn @weak @if(!$defined(native_fputc_fn));
|
||||
|
||||
/**
|
||||
* @require mode.len > 0
|
||||
@@ -75,9 +73,3 @@ fn usz! native_fread(CFile file, char[] buffer) @inline
|
||||
if (native_fread_fn) return native_fread_fn(file, buffer);
|
||||
return IoError.UNSUPPORTED_OPERATION?;
|
||||
}
|
||||
|
||||
fn void! native_fputc(CInt c, CFile stream) @inline
|
||||
{
|
||||
if (native_fputc_fn) return native_fputc_fn(c, stream);
|
||||
return IoError.UNSUPPORTED_OPERATION?;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
module std::io::os;
|
||||
import libc, std::os, std::io;
|
||||
|
||||
fn void! native_stat(Stat* stat, String path) @if(env::DARWIN || env::LINUX || env::BSD_FAMILY)
|
||||
fn void! native_stat(Stat* stat, String path) @if(env::DARWIN || env::LINUX)
|
||||
{
|
||||
@pool()
|
||||
{
|
||||
$if env::DARWIN || env::LINUX || env::BSD_FAMILY:
|
||||
$if env::DARWIN || env::LINUX:
|
||||
int res = libc::stat(path.zstr_tcopy(), stat);
|
||||
$else
|
||||
unreachable("Stat unimplemented");
|
||||
@@ -71,9 +71,6 @@ fn bool native_file_or_dir_exists(String path)
|
||||
{
|
||||
$switch
|
||||
$case env::DARWIN:
|
||||
$case env::FREEBSD:
|
||||
$case env::NETBSD:
|
||||
$case env::OPENBSD:
|
||||
$case env::LINUX:
|
||||
Stat stat;
|
||||
return @ok(native_stat(&stat, path));
|
||||
@@ -96,9 +93,6 @@ fn bool native_is_file(String path)
|
||||
{
|
||||
$switch
|
||||
$case env::DARWIN:
|
||||
$case env::FREEBSD:
|
||||
$case env::NETBSD:
|
||||
$case env::OPENBSD:
|
||||
$case env::LINUX:
|
||||
Stat stat;
|
||||
return @ok(native_stat(&stat, path)) && libc_S_ISTYPE(stat.st_mode, libc::S_IFREG);
|
||||
@@ -111,7 +105,7 @@ fn bool native_is_file(String path)
|
||||
|
||||
fn bool native_is_dir(String path)
|
||||
{
|
||||
$if env::DARWIN || env::LINUX || env::BSD_FAMILY:
|
||||
$if env::DARWIN || env::LINUX:
|
||||
Stat stat;
|
||||
return @ok(native_stat(&stat, path)) && libc_S_ISTYPE(stat.st_mode, libc::S_IFDIR);
|
||||
$else
|
||||
|
||||
@@ -4,7 +4,7 @@ import std::io, std::os;
|
||||
fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Allocator allocator)
|
||||
{
|
||||
PathList list;
|
||||
list.new_init(allocator: allocator);
|
||||
list.new_init(.allocator = allocator);
|
||||
DIRPtr directory = posix::opendir(dir.str_view() ? dir.as_zstr() : (ZString)".");
|
||||
defer if (directory) posix::closedir(directory);
|
||||
if (!directory) return (path::is_dir(dir) ? IoError.CANNOT_READ_DIR : IoError.FILE_NOT_DIR)?;
|
||||
@@ -27,7 +27,7 @@ import std::time, std::os, std::io;
|
||||
fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Allocator allocator)
|
||||
{
|
||||
PathList list;
|
||||
list.new_init(allocator: allocator);
|
||||
list.new_init(.allocator = allocator);
|
||||
|
||||
@pool(allocator)
|
||||
{
|
||||
|
||||
@@ -141,7 +141,7 @@ fn Path! new_win32_wstring(WString path, Allocator allocator = allocator::heap()
|
||||
{
|
||||
@pool(allocator)
|
||||
{
|
||||
return path::new(string::temp_from_wstring(path)!, allocator: allocator);
|
||||
return path::new(string::temp_from_wstring(path)!, .allocator = allocator);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -520,7 +520,7 @@ fn bool! Path.walk(self, PathWalker w, void* data)
|
||||
@stack_mem(PATH_MAX; Allocator allocator)
|
||||
{
|
||||
Path abs = self.new_absolute(allocator)!;
|
||||
PathList files = new_ls(abs, allocator: allocator)!;
|
||||
PathList files = new_ls(abs, .allocator = allocator)!;
|
||||
foreach (f : files)
|
||||
{
|
||||
if (f.str_view() == "." || f.str_view() == "..") continue;
|
||||
|
||||
@@ -77,22 +77,6 @@ macro usz! read_all(stream, char[] buffer)
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require @is_instream(stream)
|
||||
*/
|
||||
macro char[]! read_new_fully(stream, Allocator allocator = allocator::heap())
|
||||
{
|
||||
usz len = available(stream)!;
|
||||
char* data = allocator::malloc_try(allocator, len)!;
|
||||
defer catch allocator::free(allocator, data);
|
||||
usz read = 0;
|
||||
while (read < len)
|
||||
{
|
||||
read += stream.read(data[read:len - read])!;
|
||||
}
|
||||
return data[:len];
|
||||
}
|
||||
|
||||
/**
|
||||
* @require @is_outstream(stream)
|
||||
*/
|
||||
|
||||
@@ -131,7 +131,7 @@ fn usz! ByteBuffer.available(&self) @inline @dynamic
|
||||
fn void! ByteBuffer.grow(&self, usz n)
|
||||
{
|
||||
n = math::next_power_of_2(n);
|
||||
char* p = allocator::realloc_aligned(self.allocator, self.bytes, n, alignment: char.alignof)!;
|
||||
char* p = allocator::realloc_aligned(self.allocator, self.bytes, n, .alignment = char.alignof)!;
|
||||
self.bytes = p[:n];
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
module libc;
|
||||
|
||||
|
||||
// Constants need to be per os/arch
|
||||
const int EXIT_FAILURE = 1;
|
||||
const int EXIT_SUCCESS = 0;
|
||||
@@ -58,7 +59,7 @@ const CInt SIGTSTP = BSD_FLAVOR_SIG ? 18 : 20;
|
||||
const CInt SIGCONT = BSD_FLAVOR_SIG ? 19 : 18;
|
||||
const CInt SIGCHLD = BSD_FLAVOR_SIG ? 20 : 17;
|
||||
|
||||
const bool BSD_FLAVOR_SIG @local = env::DARWIN || env::BSD_FAMILY;
|
||||
const bool BSD_FLAVOR_SIG @local = env::OPENBSD || env::DARWIN || env::FREEBSD || env::NETBSD;
|
||||
|
||||
def Time_t = $typefrom(env::WIN32 ? long.typeid : CLong.typeid);
|
||||
def Off_t = $typefrom(env::WIN32 ? int.typeid : usz.typeid);
|
||||
@@ -118,7 +119,7 @@ extern fn CLong labs(CLong x);
|
||||
extern fn LongDivResult ldiv(CLong number, CLong denom);
|
||||
extern fn Tm* localtime(Time_t* timer);
|
||||
extern fn Tm* localtime_r(Time_t* timer, Tm* result) @if(!env::WIN32);
|
||||
extern fn void longjmp(JmpBuf* buffer, CInt value) @if(!env::NETBSD && !env::OPENBSD);
|
||||
extern fn void longjmp(JmpBuf* buffer, CInt value);
|
||||
extern fn void* malloc(usz size);
|
||||
extern fn void* memchr(void* str, CInt c, usz n);
|
||||
extern fn CInt memcmp(void* buf1, void* buf2, usz count);
|
||||
@@ -142,7 +143,7 @@ extern fn void rewind(CFile stream);
|
||||
extern fn CInt scanf(ZString format, ...);
|
||||
extern fn void setbuf(CFile stream, char* buffer);
|
||||
extern fn int setenv(ZString name, ZString value, CInt overwrite);
|
||||
extern fn CInt setjmp(JmpBuf* buffer) @if(!env::WIN32 && !env::NETBSD && !env::OPENBSD);
|
||||
extern fn CInt setjmp(JmpBuf* buffer) @if(!env::WIN32);
|
||||
extern fn void setvbuf(CFile stream, char* buf, CInt type, usz size);
|
||||
extern fn SignalFunction signal(CInt sig, SignalFunction function);
|
||||
extern fn CInt snprintf(char* buffer, usz size, ZString format, ...);
|
||||
@@ -202,39 +203,23 @@ macro CFile stdin() => __stdin;
|
||||
macro CFile stdout() => __stdout;
|
||||
macro CFile stderr() => __stderr;
|
||||
|
||||
module libc @if(env::NETBSD || env::OPENBSD);
|
||||
extern fn int fcntl(CInt socket, int cmd, ...);
|
||||
extern fn int _setjmp(void*);
|
||||
macro int setjmp(void* ptr) => _setjmp(ptr);
|
||||
extern fn int _longjmp(void*, int);
|
||||
macro usz longjmp(void* ptr, CInt i) => _longjmp(ptr, i);
|
||||
extern fn usz malloc_size(void* ptr);
|
||||
extern fn void* aligned_alloc(usz align, usz size);
|
||||
macro CFile stdin() { return fdopen(0, "r"); }
|
||||
macro CFile stdout() { return fdopen(1, "w"); }
|
||||
macro CFile stderr() { return fdopen(2, "w"); }
|
||||
|
||||
module libc @if(env::DARWIN || env::FREEBSD);
|
||||
module libc @if(env::DARWIN);
|
||||
extern CFile __stdinp;
|
||||
extern CFile __stdoutp;
|
||||
extern CFile __stderrp;
|
||||
extern fn usz malloc_size(void* ptr) @if(!env::FREEBSD);
|
||||
extern fn usz malloc_size(void* ptr);
|
||||
extern fn void* aligned_alloc(usz align, usz size);
|
||||
macro CFile stdin() => __stdinp;
|
||||
macro CFile stdout() => __stdoutp;
|
||||
macro CFile stderr() => __stderrp;
|
||||
|
||||
module libc @if(env::FREEBSD);
|
||||
extern fn usz malloc_usable_size(void* ptr);
|
||||
macro usz malloc_size(void* ptr) => malloc_usable_size(ptr);
|
||||
|
||||
module libc @if(env::WIN32);
|
||||
macro usz malloc_size(void* ptr) => _msize(ptr);
|
||||
macro CFile stdin() => __acrt_iob_func(STDIN_FD);
|
||||
macro CFile stdout() => __acrt_iob_func(STDOUT_FD);
|
||||
macro CFile stderr() => __acrt_iob_func(STDERR_FD);
|
||||
|
||||
module libc @if(env::LIBC && !env::WIN32 && !env::LINUX && !env::DARWIN && !env::BSD_FAMILY);
|
||||
module libc @if(env::LIBC && !env::WIN32 && !env::LINUX && !env::DARWIN);
|
||||
macro CFile stdin() { return (CFile*)(uptr)STDIN_FD; }
|
||||
macro CFile stdout() { return (CFile*)(uptr)STDOUT_FD; }
|
||||
macro CFile stderr() { return (CFile*)(uptr)STDERR_FD; }
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
module libc @if(env::FREEBSD);
|
||||
|
||||
// Checked for x86_64, this is notoriously incorrect when comparing with Rust code etc
|
||||
|
||||
def Blksize_t = $typefrom(env::X86_64 ? long.typeid : CInt.typeid);
|
||||
def Nlink_t = $typefrom(env::X86_64 ? ulong.typeid : CUInt.typeid);
|
||||
def Blkcnt_t = long;
|
||||
def Ino_t = ulong;
|
||||
def Dev_t = ulong;
|
||||
def Mode_t = uint;
|
||||
def Ino64_t = ulong;
|
||||
def Blkcnt64_t = long;
|
||||
|
||||
struct Stat @if(env::X86_64)
|
||||
{
|
||||
Dev_t st_dev;
|
||||
Ino_t st_ino;
|
||||
Nlink_t st_nlink;
|
||||
Mode_t st_mode;
|
||||
Uid_t st_uid;
|
||||
Gid_t st_gid;
|
||||
CInt __pad0;
|
||||
Dev_t st_rdev;
|
||||
Off_t st_size;
|
||||
Blksize_t st_blksize;
|
||||
Blkcnt_t st_blocks;
|
||||
Time_t st_atime;
|
||||
long st_atime_nsec;
|
||||
Time_t st_mtime;
|
||||
long st_mtime_nsec;
|
||||
Time_t st_ctime;
|
||||
long st_ctime_nsec;
|
||||
long[3] __unused;
|
||||
}
|
||||
|
||||
struct Stat @if(!env::X86_64)
|
||||
{
|
||||
Dev_t st_dev;
|
||||
Ino_t st_ino;
|
||||
Mode_t st_mode;
|
||||
Nlink_t st_nlink;
|
||||
Uid_t st_uid;
|
||||
Gid_t st_gid;
|
||||
Dev_t st_rdev;
|
||||
CInt __pad1;
|
||||
Off_t st_size;
|
||||
Blksize_t st_blksize;
|
||||
CInt __pad2;
|
||||
Blkcnt_t st_blocks;
|
||||
Time_t st_atime;
|
||||
long st_atime_nsec;
|
||||
Time_t st_mtime;
|
||||
long st_mtime_nsec;
|
||||
Time_t st_ctime;
|
||||
long st_ctime_nsec;
|
||||
CInt[2] __unused;
|
||||
}
|
||||
|
||||
extern fn CInt stat(ZString path, Stat* stat);
|
||||
|
||||
extern fn CInt get_nprocs();
|
||||
extern fn CInt get_nprocs_conf();
|
||||
@@ -32,9 +32,9 @@ struct Sigaction
|
||||
SignalFunction sa_handler;
|
||||
SigActionFunction sa_sigaction;
|
||||
}
|
||||
CInt sa_flags @if(env::BSD_FAMILY);
|
||||
CInt sa_flags @if(env::FREEBSD);
|
||||
Sigset_t sa_mask; // 128
|
||||
CInt sa_flags @if(!env::BSD_FAMILY);
|
||||
CInt sa_flags @if(!env::FREEBSD);
|
||||
void* sa_restorer @if(env::LINUX);
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -10,186 +10,54 @@ fn int128 __divti3(int128 a, int128 b) @extern("__divti3") @weak @nostrip
|
||||
return __udivti3(unsigned_a, unsigned_b) @inline ^ sign_a + (-sign_a);
|
||||
}
|
||||
|
||||
macro uint128 @__udivmodti4(uint128 a, uint128 b, bool $return_rem)
|
||||
{
|
||||
Int128bits n = { .all = a };
|
||||
Int128bits d = { .all = b };
|
||||
Int128bits q @noinit;
|
||||
Int128bits r @noinit;
|
||||
uint sr;
|
||||
if (n.high == 0)
|
||||
{
|
||||
if (d.high == 0)
|
||||
{
|
||||
$if $return_rem:
|
||||
return n.low % d.low;
|
||||
$else
|
||||
return n.low / d.low;
|
||||
$endif
|
||||
}
|
||||
$if $return_rem:
|
||||
return n.low;
|
||||
$else
|
||||
return 0;
|
||||
$endif
|
||||
}
|
||||
if (d.low == 0)
|
||||
{
|
||||
if (d.high == 0)
|
||||
{
|
||||
$if $return_rem:
|
||||
return n.high % d.low;
|
||||
$else
|
||||
return n.high / d.low;
|
||||
$endif
|
||||
}
|
||||
if (n.low == 0)
|
||||
{
|
||||
$if $return_rem:
|
||||
r.high = n.high % d.high;
|
||||
r.low = 0;
|
||||
return r.all;
|
||||
$else
|
||||
return n.high / d.high;
|
||||
$endif
|
||||
}
|
||||
if (d.high & (d.high - 1) == 0) // d is pot
|
||||
{
|
||||
$if $return_rem:
|
||||
r.low = n.low;
|
||||
r.high = n.high & (d.high - 1);
|
||||
return r.all;
|
||||
$else
|
||||
return (uint128)(n.high >> $$ctz(d.high));
|
||||
$endif
|
||||
}
|
||||
sr = (uint)$$clz(d.high) - (uint)$$clz(n.high);
|
||||
// 0 <= sr <= n_udword_bits - 2 or sr large
|
||||
if (sr > 64 - 2)
|
||||
{
|
||||
$if $return_rem:
|
||||
return n.all;
|
||||
$else
|
||||
return 0;
|
||||
$endif
|
||||
}
|
||||
sr++;
|
||||
// 1 <= sr <= n_udword_bits - 1
|
||||
// q.all = n.all << (n_utword_bits - sr);
|
||||
q.low = 0;
|
||||
q.high = n.low << (64 - sr);
|
||||
r.high = n.high >> sr;
|
||||
r.low = (n.high << (64 - sr)) | (n.low >> sr);
|
||||
}
|
||||
else // d.s.low != 0
|
||||
{
|
||||
if (d.high == 0)
|
||||
{
|
||||
if (d.low & (d.low - 1) == 0) // if d is a power of 2
|
||||
{
|
||||
$if $return_rem:
|
||||
return (uint128)(n.low & (d.low - 1));
|
||||
$else
|
||||
if (d.low == 1) return n.all;
|
||||
sr = (uint)$$ctz(d.low);
|
||||
q.high = n.high >> sr;
|
||||
q.low = (n.high << (64 - sr)) | (n.low >> sr);
|
||||
return q.all;
|
||||
$endif
|
||||
}
|
||||
sr = 1 + 64 + (uint)$$clz(d.low) - (uint)$$clz(n.high);
|
||||
// 2 <= sr <= n_utword_bits - 1
|
||||
// q.all = n.all << (n_utword_bits - sr);
|
||||
// r.all = n.all >> sr;
|
||||
switch
|
||||
{
|
||||
case sr == 64:
|
||||
q.low = 0;
|
||||
q.high = n.low;
|
||||
r.high = 0;
|
||||
r.low = n.high;
|
||||
case sr < 64:
|
||||
q.low = 0;
|
||||
q.high = n.low << (64 - sr);
|
||||
r.high = n.high >> sr;
|
||||
r.low = (n.high << (64 - sr)) | (n.low >> sr);
|
||||
default: // n_udword_bits + 1 <= sr <= n_utword_bits - 1
|
||||
q.low = n.low << (128 - sr);
|
||||
q.high = (n.high << (128 - sr)) | (n.low >> (sr - 64));
|
||||
r.high = 0;
|
||||
r.low = n.high >> (sr - 64);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sr = (uint)$$clz(d.high) - (uint)$$clz(n.high);
|
||||
// 0 <= sr <= n_udword_bits - 1 or sr large
|
||||
if (sr > 64 - 1)
|
||||
{
|
||||
$if $return_rem:
|
||||
return n.all;
|
||||
$else
|
||||
return 0;
|
||||
$endif
|
||||
}
|
||||
|
||||
sr++;
|
||||
// 1 <= sr <= n_udword_bits
|
||||
// q.all = n.all << (n_utword_bits - sr);
|
||||
// r.all = n.all >> sr;
|
||||
q.low = 0;
|
||||
if (sr == 64)
|
||||
{
|
||||
q.high = n.low;
|
||||
r.high = 0;
|
||||
r.low = n.high;
|
||||
}
|
||||
else
|
||||
{
|
||||
r.high = n.high >> sr;
|
||||
r.low = (n.high << (64 - sr)) | (n.low >> sr);
|
||||
q.high = n.low << (64 - sr);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Not a special case
|
||||
// q and r are initialized with:
|
||||
// q.all = n.all << (128 - sr);
|
||||
// r.all = n.all >> sr;
|
||||
// 1 <= sr <= n_utword_bits - 1
|
||||
uint carry = 0;
|
||||
for (; sr > 0; sr--)
|
||||
{
|
||||
// r:q = ((r:q) << 1) | carry
|
||||
r.high = (r.high << 1) | (r.low >> (64 - 1));
|
||||
r.low = (r.low << 1) | (q.high >> (64 - 1));
|
||||
q.high = (q.high << 1) | (q.low >> (64 - 1));
|
||||
q.low = (q.low << 1) | carry;
|
||||
// carry = 0;
|
||||
// if (r.all >= d.all)
|
||||
// {
|
||||
// r.all -= d.all;
|
||||
// carry = 1;
|
||||
// }
|
||||
int128 s = (int128)(d.all - r.all - 1) >> (128 - 1);
|
||||
carry = (uint)(s & 1);
|
||||
r.all -= d.all & s;
|
||||
}
|
||||
$if $return_rem:
|
||||
return r.all;
|
||||
$else
|
||||
return (q.all << 1) | carry;
|
||||
$endif
|
||||
}
|
||||
|
||||
fn uint128 __umodti3(uint128 n, uint128 d) @extern("__umodti3") @weak @nostrip
|
||||
{
|
||||
return @__udivmodti4(n, d, true);
|
||||
// Ignore d = 0
|
||||
uint128 sr = (d ? $$clz(d) : 128) - (n ? $$clz(n) : 128);
|
||||
// If n < d then sr is wrapping.
|
||||
// which means we can just return n.
|
||||
if (sr > 127) return n;
|
||||
// If d == 1 and n = MAX
|
||||
if (sr == 127) return 0;
|
||||
sr++;
|
||||
uint128 r = n >> sr;
|
||||
// Follow known algorithm:
|
||||
n <<= 128 - sr;
|
||||
for (uint128 carry = 0; sr > 0; sr--)
|
||||
{
|
||||
r = (r << 1) | (n >> 127);
|
||||
n = (n << 1) | carry;
|
||||
int128 sign = (int128)(d - r - 1) >> 127;
|
||||
carry = sign & 1;
|
||||
r -= d & sign;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
fn uint128 __udivti3(uint128 n, uint128 d) @extern("__udivti3") @weak @nostrip
|
||||
{
|
||||
return @__udivmodti4(n, d, false);
|
||||
// Ignore d = 0
|
||||
uint128 sr = (d ? $$clz(d) : 128) - (n ? $$clz(n) : 128);
|
||||
// If n < d then sr is wrapping.
|
||||
// which means we can just return 0.
|
||||
if (sr > 127) return 0;
|
||||
// If d == 1 and n = MAX
|
||||
if (sr == 127) return n;
|
||||
sr++;
|
||||
uint128 r = n >> sr;
|
||||
// Follow known algorithm:
|
||||
n <<= 128 - sr;
|
||||
uint128 carry = 0;
|
||||
for (; sr > 0; sr--)
|
||||
{
|
||||
r = (r << 1) | (n >> 127);
|
||||
n = (n << 1) | carry;
|
||||
int128 sign = (int128)(d - r - 1) >> 127;
|
||||
carry = sign & 1;
|
||||
r -= d & sign;
|
||||
}
|
||||
n = (n << 1) | carry;
|
||||
return n;
|
||||
}
|
||||
|
||||
fn int128 __modti3(int128 a, int128 b) @extern("__modti3") @weak @nostrip
|
||||
@@ -206,8 +74,11 @@ union Int128bits @private
|
||||
{
|
||||
struct
|
||||
{
|
||||
ulong low;
|
||||
ulong high;
|
||||
ulong ulow, uhigh;
|
||||
}
|
||||
struct
|
||||
{
|
||||
long ilow, ihigh;
|
||||
}
|
||||
uint128 all;
|
||||
}
|
||||
@@ -218,14 +89,14 @@ fn uint128 __lshrti3(uint128 a, uint b) @extern("__lshrti3") @weak @nostrip
|
||||
result.all = a;
|
||||
if (b >= 64)
|
||||
{
|
||||
result.low = result.high >> (b - 64);
|
||||
result.high = 0;
|
||||
result.ulow = result.uhigh >> (b - 64);
|
||||
result.uhigh = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (b == 0) return a;
|
||||
result.low = (result.high << (64 - b)) | (result.low >> b);
|
||||
result.high = result.high >> b;
|
||||
result.ulow = (result.uhigh << (64 - b)) | (result.ulow >> b);
|
||||
result.uhigh = result.uhigh >> b;
|
||||
}
|
||||
return result.all;
|
||||
}
|
||||
@@ -236,14 +107,14 @@ fn int128 __ashrti3(int128 a, uint b) @extern("__ashrti3") @weak @nostrip
|
||||
result.all = a;
|
||||
if (b >= 64)
|
||||
{
|
||||
result.low = result.high >> (b - 64);
|
||||
result.high = result.high >> 63;
|
||||
result.ilow = result.ihigh >> (b - 64);
|
||||
result.ihigh = result.ihigh >> 63;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (b == 0) return a;
|
||||
result.low = result.high << (64 - b) | (result.low >> b);
|
||||
result.high = result.high >> b;
|
||||
result.ilow = result.ihigh << (64 - b) | (result.ilow >> b);
|
||||
result.ihigh = result.ihigh >> b;
|
||||
}
|
||||
return result.all;
|
||||
}
|
||||
@@ -254,14 +125,14 @@ fn int128 __ashlti3(int128 a, uint b) @extern("__ashlti3") @weak @nostrip
|
||||
result.all = a;
|
||||
if (b >= 64)
|
||||
{
|
||||
result.low = 0;
|
||||
result.high = result.low << (b - 64);
|
||||
result.ulow = 0;
|
||||
result.uhigh = result.ulow << (b - 64);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (b == 0) return a;
|
||||
result.high = (result.high << b) | (result.low >> (64 - b));
|
||||
result.low = result.low << b;
|
||||
result.uhigh = (result.uhigh << b) | (result.ulow >> (64 - b));
|
||||
result.ulow = result.ulow << b;
|
||||
}
|
||||
return result.all;
|
||||
}
|
||||
@@ -272,18 +143,18 @@ fn int128 __mulddi3(ulong a, ulong b) @private
|
||||
{
|
||||
Int128bits r;
|
||||
const ulong LOWER_MASK = 0xffff_ffff;
|
||||
r.low = (a & LOWER_MASK) * (b & LOWER_MASK);
|
||||
ulong t = r.low >> 32;
|
||||
r.low &= LOWER_MASK;
|
||||
r.ulow = (a & LOWER_MASK) * (b & LOWER_MASK);
|
||||
ulong t = r.ulow >> 32;
|
||||
r.ulow &= LOWER_MASK;
|
||||
t += (a >> 32) * (b & LOWER_MASK);
|
||||
r.low += (t & LOWER_MASK) << 32;
|
||||
r.high = t >> 32;
|
||||
t = r.low >> 32;
|
||||
r.low &= LOWER_MASK;
|
||||
r.ulow += (t & LOWER_MASK) << 32;
|
||||
r.uhigh = t >> 32;
|
||||
t = r.ulow >> 32;
|
||||
r.ulow &= LOWER_MASK;
|
||||
t += (b >> 32) * (a & LOWER_MASK);
|
||||
r.low += (t & LOWER_MASK) << 32;
|
||||
r.high += t >> 32;
|
||||
r.high += (a >> 32) * (b >> 32);
|
||||
r.ulow += (t & LOWER_MASK) << 32;
|
||||
r.uhigh += t >> 32;
|
||||
r.uhigh += (a >> 32) * (b >> 32);
|
||||
return r.all;
|
||||
}
|
||||
|
||||
@@ -291,8 +162,8 @@ fn int128 __multi3(int128 a, int128 b) @extern("__multi3") @weak @nostrip
|
||||
{
|
||||
Int128bits x = { .all = a };
|
||||
Int128bits y = { .all = b };
|
||||
Int128bits r = { .all = __mulddi3(x.low, y.low) };
|
||||
r.high += x.high * y.low + x.low * y.high;
|
||||
Int128bits r = { .all = __mulddi3(x.ulow, y.ulow) };
|
||||
r.uhigh += x.uhigh * y.ulow + x.ulow * y.uhigh;
|
||||
return r.all;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
module std::math::matrix(<Real>);
|
||||
import std::math::vector;
|
||||
|
||||
struct Matrix2x2
|
||||
{
|
||||
@@ -133,7 +132,6 @@ fn Matrix2x2 Matrix2x2.sub(&self, Matrix2x2 mat2) => matrix_sub(self, mat2);
|
||||
fn Matrix3x3 Matrix3x3.sub(&self, Matrix3x3 mat2) => matrix_sub(self, mat2);
|
||||
fn Matrix4x4 Matrix4x4.sub(&self, Matrix4x4 mat2) => matrix_sub(self, mat2);
|
||||
|
||||
fn Matrix4x4 look_at(Real[<3>] eye, Real[<3>] target, Real[<3>] up) => matrix_look_at(Matrix4x4, eye, target, up);
|
||||
|
||||
|
||||
fn Matrix2x2 Matrix2x2.transpose(&self)
|
||||
@@ -434,17 +432,3 @@ macro matrix_sub(mat, mat2) @private
|
||||
var $Type = Real[<$typeof(mat.m).len>];
|
||||
return $typeof(*mat) { .m = ($Type)mat.m - ($Type)mat2.m };
|
||||
}
|
||||
|
||||
macro matrix_look_at($Type, eye, target, up) @private
|
||||
{
|
||||
var vz = (eye - target).normalize();
|
||||
var vx = up.cross(vz).normalize();
|
||||
var vy = vz.cross(vx);
|
||||
|
||||
return $Type {
|
||||
vx[0], vx[1], vx[2], - (Real)vx.dot(eye),
|
||||
vy[0], vy[1], vy[2], - (Real)vy.dot(eye),
|
||||
vz[0], vz[1], vz[2], - (Real)vz.dot(eye),
|
||||
0.0, 0.0, 0.0, 1
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
module std::math::nolibc @if(env::NO_LIBC);
|
||||
|
||||
union DoubleInternal
|
||||
{
|
||||
double f;
|
||||
ulong i;
|
||||
}
|
||||
|
||||
// Based on the musl implementation
|
||||
fn double fmod(double x, double y) @extern("fmod") @weak @nostrip
|
||||
{
|
||||
DoubleInternal ux = { .f = x };
|
||||
DoubleInternal uy = { .f = y };
|
||||
int ex = (int)((ux.i >> 52) & 0x7ff);
|
||||
int ey = (int)((uy.i >> 52) & 0x7ff);
|
||||
int sx = (int)(ux.i >> 63);
|
||||
ulong uxi = ux.i;
|
||||
if (uy.i << 1 == 0 || math::is_nan(y) || ex == 0x7ff) return (x * y)/(x * y);
|
||||
if (uxi << 1 <= uy.i << 1)
|
||||
{
|
||||
if (uxi << 1 == uy.i << 1) return 0 * x;
|
||||
return x;
|
||||
}
|
||||
|
||||
if (!ex)
|
||||
{
|
||||
for (ulong i = uxi << 12; i >> 63 == 0; ex--, i <<= 1);
|
||||
uxi <<= -ex + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
uxi &= -1UL >> 12;
|
||||
uxi |= 1UL << 52;
|
||||
}
|
||||
if (!ey)
|
||||
{
|
||||
for (ulong i = uy.i << 12; i >> 63 == 0; ey--, i <<= 1);
|
||||
uy.i <<= -ey + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
uy.i &= -1UL >> 12;
|
||||
uy.i |= 1UL << 52;
|
||||
}
|
||||
|
||||
/* x mod y */
|
||||
for (; ex > ey; ex--)
|
||||
{
|
||||
ulong i = uxi - uy.i;
|
||||
if (i >> 63 == 0)
|
||||
{
|
||||
if (i == 0) return 0 * x;
|
||||
uxi = i;
|
||||
}
|
||||
uxi <<= 1;
|
||||
}
|
||||
ulong i = uxi - uy.i;
|
||||
if (i >> 63 == 0)
|
||||
{
|
||||
if (i == 0) return 0*x;
|
||||
uxi = i;
|
||||
}
|
||||
for (; uxi>>52 == 0; uxi <<= 1, ex--);
|
||||
|
||||
/* scale result */
|
||||
if (ex > 0)
|
||||
{
|
||||
uxi -= 1UL << 52;
|
||||
uxi |= (ulong)ex << 52;
|
||||
}
|
||||
else
|
||||
{
|
||||
uxi >>= -ex + 1;
|
||||
}
|
||||
uxi |= (ulong)sx << 63;
|
||||
ux.i = uxi;
|
||||
return ux.f;
|
||||
}
|
||||
@@ -29,75 +29,30 @@ macro void seed_entropy(random)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next value between 0 and range (not including range).
|
||||
* Get the next value between 0 and max (not including max).
|
||||
*
|
||||
* @require is_random(random)
|
||||
* @require range > 0
|
||||
**/
|
||||
macro int next(random, uint range)
|
||||
macro int next(random, int max)
|
||||
{
|
||||
if (range == 1) return 0;
|
||||
uint mask = ~0U;
|
||||
range--;
|
||||
mask >>= range.clz();
|
||||
uint x @noinit;
|
||||
do
|
||||
{
|
||||
x = random.next_int() & mask;
|
||||
}
|
||||
while (x > range);
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a random in the range [min, max], both included.
|
||||
*
|
||||
* @require is_random(random)
|
||||
* @require max >= min
|
||||
**/
|
||||
macro int next_in_range(random, int min, int max)
|
||||
{
|
||||
return next(random, max - min + 1) + min;
|
||||
return (int)(next_double(random) * max);
|
||||
}
|
||||
|
||||
def DefaultRandom = Sfc64Random;
|
||||
|
||||
tlocal Sfc64Random default_random @private;
|
||||
tlocal bool default_random_initialized @private = false;
|
||||
|
||||
/**
|
||||
* Seed the default random function.
|
||||
*/
|
||||
fn void srand(ulong seed) @builtin
|
||||
{
|
||||
default_random.set_seed(@as_char_view(seed));
|
||||
default_random_initialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a default random value between 0 and range (not including range)
|
||||
* Get a default random value between 0 and max (not including max)
|
||||
**/
|
||||
fn int rand(int range) @builtin
|
||||
fn int rand(int max) @builtin
|
||||
{
|
||||
init_default_random();
|
||||
return next(&default_random, range);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a random in the range, both included.
|
||||
* @require max >= min
|
||||
**/
|
||||
fn int rand_in_range(int min, int max) @builtin
|
||||
{
|
||||
init_default_random();
|
||||
return next_in_range(&default_random, min, max);
|
||||
}
|
||||
|
||||
fn double rnd() @builtin
|
||||
{
|
||||
init_default_random();
|
||||
ulong val = default_random.next_long() & (1UL << 53 - 1);
|
||||
return val * 0x1.0p-53;
|
||||
tlocal Sfc64Random default_random;
|
||||
tlocal bool initialized = false;
|
||||
if (!initialized)
|
||||
{
|
||||
seed_entropy(&default_random);
|
||||
initialized = true;
|
||||
}
|
||||
return next(&default_random, max);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -172,13 +127,3 @@ interface Random
|
||||
fn uint128 next_int128();
|
||||
fn void next_bytes(char[] buffer);
|
||||
}
|
||||
|
||||
|
||||
macro init_default_random() @private
|
||||
{
|
||||
if (!default_random_initialized)
|
||||
{
|
||||
seed_entropy(&default_random);
|
||||
default_random_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,8 +66,8 @@ fn Vec3 Vec3.refract(self, Vec3 n, double r) => refract3(self, n, r);
|
||||
fn void ortho_normalize(Vec3f* v1, Vec3f* v2) => ortho_normalize3(v1, v2);
|
||||
fn void ortho_normalized(Vec3* v1, Vec3* v2) => ortho_normalize3(v1, v2);
|
||||
|
||||
fn Matrix4f matrix4f_look_at(Vec3f eye, Vec3f target, Vec3f up) @deprecated => matrix::look_at(<float>)(eye, target, up);
|
||||
fn Matrix4 matrix4_look_at(Vec3 eye, Vec3 target, Vec3 up) @deprecated => matrix::look_at(<double>)(eye, target, up);
|
||||
fn Matrix4f matrix4f_look_at(Vec3f eye, Vec3f target, Vec3f up) => matrix_look_at(Matrix4f, eye, target, up);
|
||||
fn Matrix4 matrix4_look_at(Vec3 eye, Vec3 target, Vec3 up) => matrix_look_at(Matrix4, eye, target, up);
|
||||
|
||||
fn Vec3f Vec3f.rotate_quat(self, Quaternionf q) => rotate_by_quat3(self, q);
|
||||
fn Vec3 Vec3.rotate_quat(self, Quaternion q) => rotate_by_quat3(self, q);
|
||||
@@ -196,6 +196,20 @@ macro rotate_axis_angle(v, axis, angle) @private
|
||||
return v + wv + wwv;
|
||||
}
|
||||
|
||||
macro matrix_look_at($Type, eye, target, up) @private
|
||||
{
|
||||
var vz = (eye - target).normalize();
|
||||
var vx = up.cross(vz).normalize();
|
||||
var vy = vz.cross(vx);
|
||||
|
||||
return $Type {
|
||||
vx[0], vx[1], vx[2], - vx.dot(eye),
|
||||
vy[0], vy[1], vy[2], - vy.dot(eye),
|
||||
vz[0], vz[1], vz[2], - vz.dot(eye),
|
||||
0.0, 0.0, 0.0, 1
|
||||
};
|
||||
}
|
||||
|
||||
macro unproject3(v, m1, m2) @private
|
||||
{
|
||||
return v;
|
||||
@@ -242,4 +256,4 @@ macro refract3(v, n, r) @private
|
||||
var d = 1 - r * r * (1 - dot * dot);
|
||||
|
||||
return d < 0 ? v : r * v - (r * dot + math::sqrt(d)) * n;
|
||||
}
|
||||
}
|
||||
@@ -72,9 +72,8 @@ macro uint hash(value) @local
|
||||
return fnv32a::encode(&&bitcast(value, char[$sizeof(value)]));
|
||||
}
|
||||
|
||||
fn char[8 * 4] entropy() @if(!env::WASM_NOLIBC)
|
||||
fn char[8 * 4] entropy()
|
||||
{
|
||||
|
||||
void* addr = malloc(1);
|
||||
free(addr);
|
||||
static uint random_int;
|
||||
@@ -90,21 +89,4 @@ fn char[8 * 4] entropy() @if(!env::WASM_NOLIBC)
|
||||
hash(allocator::heap())
|
||||
};
|
||||
return bitcast(entropy_data, char[8 * 4]);
|
||||
}
|
||||
|
||||
fn char[8 * 4] entropy() @if(env::WASM_NOLIBC)
|
||||
{
|
||||
static uint random_int;
|
||||
random_int += 0xedf19156;
|
||||
uint[8] entropy_data = {
|
||||
hash($$TIME),
|
||||
hash(&entropy),
|
||||
random_int,
|
||||
hash($$TIME),
|
||||
hash(&entropy),
|
||||
random_int,
|
||||
hash($$TIME),
|
||||
hash(&entropy),
|
||||
};
|
||||
return bitcast(entropy_data, char[8 * 4]);
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
module std::math::uuid;
|
||||
import std::math::random @public;
|
||||
import std::io;
|
||||
|
||||
distinct Uuid (Printable) = char[16];
|
||||
|
||||
/**
|
||||
* Generate a version 4 UUID from the default random.
|
||||
**/
|
||||
fn Uuid generate()
|
||||
{
|
||||
random::init_default_random();
|
||||
return generate_from_random(&random::default_random);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a version 4 UUID from the given random.
|
||||
**/
|
||||
fn Uuid generate_from_random(Random random)
|
||||
{
|
||||
Uuid uuid;
|
||||
random.next_bytes(&(char[16])uuid);
|
||||
uuid[6] = (uuid[6] & 0b0000_1111) | 0b0100_0000;
|
||||
uuid[8] = (uuid[8] & 0b0011_1111) | 0b1000_0000;
|
||||
return uuid;
|
||||
}
|
||||
|
||||
fn usz! Uuid.to_format(&self, Formatter* formatter) @dynamic
|
||||
{
|
||||
return formatter.printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
||||
(*self)[0], (*self)[1], (*self)[2], (*self)[3],
|
||||
(*self)[4], (*self)[5],
|
||||
(*self)[6], (*self)[7],
|
||||
(*self)[8], (*self)[9],
|
||||
(*self)[10], (*self)[11], (*self)[12], (*self)[13], (*self)[14], (*self)[15]);
|
||||
}
|
||||
|
||||
fn String Uuid.to_string(&self, Allocator allocator) @dynamic
|
||||
{
|
||||
return string::new_format("%s", *self, allocator: allocator);
|
||||
}
|
||||
@@ -22,7 +22,7 @@ const int SO_ERROR = 4;
|
||||
const int SO_DONTROUTE = 5; // just use interface addresses
|
||||
const int SO_BROADCAST = 6; // permit sending of broadcast msgs
|
||||
const int SO_SNDBUF = 7; // Send buffer size
|
||||
const int SO_RCVBUF = 8; // Receive buffer size
|
||||
const int SO_RCVBUF = 8; // Recieve buffer size
|
||||
const int SO_KEEPALIVE = 9; // keep connections alive
|
||||
const int SO_OOBINLINE = 10; // leave received OOB data in line
|
||||
const int SO_NO_CHECK = 11;
|
||||
|
||||
@@ -105,7 +105,7 @@ fn Path! new_get_config_dir(Allocator allocator = allocator::heap())
|
||||
String s = get_var_temp("XDG_CONFIG_HOME") ?? get_var_temp("HOME")!;
|
||||
const DIR = ".config";
|
||||
$endif
|
||||
return path::temp_new(s).new_append(DIR, allocator: allocator);
|
||||
return path::temp_new(s).new_append(DIR, .allocator = allocator);
|
||||
$endif
|
||||
};
|
||||
}
|
||||
|
||||
@@ -7,22 +7,15 @@ distinct DIRPtr = void*;
|
||||
struct Posix_dirent
|
||||
{
|
||||
Ino_t d_fileno;
|
||||
Off_t d_off @if(!env::NETBSD);
|
||||
Off_t d_off;
|
||||
ushort d_reclen;
|
||||
ushort d_namelen @if(env::DARWIN || env::NETBSD);
|
||||
ushort d_namelen @if(env::DARWIN);
|
||||
char d_type;
|
||||
|
||||
char d_namelen @if(env::OPENBSD);
|
||||
char d_namelen @if(env::FREEBSD || env::OPENBSD);
|
||||
uint d_pad0 @if(env::FREEBSD);
|
||||
char[4] d_pad0 @if(env::OPENBSD);
|
||||
|
||||
char d_pad0 @if(env::FREEBSD);
|
||||
ushort d_namelen @if(env::FREEBSD);
|
||||
ushort d_pad1 @if(env::FREEBSD);
|
||||
|
||||
char[255+1] name @if(env::FREEBSD || env::OPENBSD);
|
||||
char[511+1] name @if(env::NETBSD);
|
||||
char[1024] name @if(env::DARWIN);
|
||||
char[*] name @if(!env::DARWIN && !env::BSD_FAMILY);
|
||||
char[*] name @if(!env::DARWIN);
|
||||
}
|
||||
|
||||
extern fn int rmdir(ZString);
|
||||
@@ -48,3 +41,4 @@ const DT_WHT = 14;
|
||||
|
||||
const USE_DARWIN_INODE64 = env::DARWIN && env::X86_64;
|
||||
extern fn Posix_dirent* readdir(DIRPtr) @extern("readdir$INODE64") @if(USE_DARWIN_INODE64);
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ import std::thread;
|
||||
import libc;
|
||||
|
||||
const PTHREAD_MUTEX_NORMAL = 0;
|
||||
const PTHREAD_MUTEX_ERRORCHECK = env::LINUX ? 2 : 1;
|
||||
const PTHREAD_MUTEX_RECURSIVE = env::LINUX ? 1 : 2;
|
||||
const PTHREAD_MUTEX_ERRORCHECK = 1;
|
||||
const PTHREAD_MUTEX_RECURSIVE = 2;
|
||||
|
||||
def PosixThreadFn = fn void*(void*);
|
||||
distinct Pthread_t = void*;
|
||||
|
||||
@@ -193,10 +193,10 @@ fn Backtrace! resolve_backtrace(void* addr, Win32_HANDLE process, Allocator allo
|
||||
ZString zname = (ZString)&name;
|
||||
if (!symGetLineFromAddr64(process, (Win32_ULONG64)addr - 1, &offset, &line))
|
||||
{
|
||||
backtrace.init((uptr)addr, zname.str_view(), module_name.str_view(), allocator: allocator);
|
||||
backtrace.init((uptr)addr, .function = zname.str_view(), .object_file = module_name.str_view(), .allocator = allocator);
|
||||
return backtrace;
|
||||
}
|
||||
String filename = ((ZString)line.fileName).str_view();
|
||||
backtrace.init((uptr)addr, zname.str_view(), module_name.str_view(), file: filename, line: line.lineNumber, allocator: allocator);
|
||||
backtrace.init((uptr)addr, .function = zname.str_view(), .object_file = module_name.str_view(), .file = filename, .line = line.lineNumber, .allocator = allocator);
|
||||
return backtrace;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ def Indexs = char[256] @private;
|
||||
def ElementType = $typeof(Type{}[0]);
|
||||
|
||||
const bool NO_KEY_FN @private = types::is_same(KeyFn, EmptySlot);
|
||||
const bool KEY_BY_VALUE @private = NO_KEY_FN ||| $assignable(Type{}[0], $typefrom(KeyFn.paramsof[0].type));
|
||||
const bool KEY_BY_VALUE @private = NO_KEY_FN ||| $assignable(Type{}[0], $typefrom(KeyFn.params[0]));
|
||||
const bool LIST_HAS_REF @private = $defined(&Type{}[0]);
|
||||
|
||||
def KeyFnReturnType = $typefrom(KeyFn.returns) @if(!NO_KEY_FN);
|
||||
|
||||
@@ -20,7 +20,7 @@ fn void isort(Type list, usz low, usz high, CmpFn comp, Context context)
|
||||
{
|
||||
var $has_cmp = @is_valid_macro_slot(comp);
|
||||
var $has_context = @is_valid_macro_slot(context);
|
||||
var $cmp_by_value = $has_cmp &&& $assignable(list[0], $typefrom(CmpFn.paramsof[0].type));
|
||||
var $cmp_by_value = $has_cmp &&& $assignable(list[0], $typefrom(CmpFn.params[0]));
|
||||
var $has_get_ref = $defined(&list[0]);
|
||||
for (usz i = low; i < high; ++i)
|
||||
{
|
||||
|
||||
@@ -31,7 +31,7 @@ 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));
|
||||
var $cmp_by_value = $has_cmp &&& $assignable(list[0], $typefrom(CmpFn.params[0]));
|
||||
|
||||
if (low >= 0 && high >= 0 && low < high)
|
||||
{
|
||||
|
||||
@@ -1,178 +0,0 @@
|
||||
module std::thread::threadpool @if (env::POSIX || env::WIN32);
|
||||
import std::thread;
|
||||
|
||||
// Please do not use this one in production.
|
||||
|
||||
fault ThreadPoolResult
|
||||
{
|
||||
QUEUE_FULL
|
||||
}
|
||||
|
||||
def ThreadPoolFn = fn void(any[] args);
|
||||
|
||||
struct FixedThreadPool @adhoc
|
||||
{
|
||||
Mutex mu;
|
||||
QueueItem[] queue;
|
||||
usz qindex;
|
||||
usz num_threads;
|
||||
bitstruct : char {
|
||||
bool initialized;
|
||||
bool stop;
|
||||
bool stop_now;
|
||||
}
|
||||
Thread[] pool;
|
||||
ConditionVariable notify;
|
||||
}
|
||||
|
||||
struct QueueItem @private
|
||||
{
|
||||
ThreadPoolFn func;
|
||||
any[] args;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require !self.initialized "ThreadPool must not be already initialized"
|
||||
* @require threads > 0 && threads < 0x1000 `Threads should be greater than 0 and less than 0x1000`
|
||||
* @require queue_size < 0x10000 `Queue size must be less than 65536`
|
||||
**/
|
||||
fn void! FixedThreadPool.init(&self, usz threads, usz queue_size = 0)
|
||||
{
|
||||
if (queue_size == 0) queue_size = threads * 32;
|
||||
defer catch @ok(self.destroy());
|
||||
assert(queue_size > 0);
|
||||
*self = {
|
||||
.num_threads = threads,
|
||||
.initialized = true,
|
||||
.queue = mem::alloc_array(QueueItem, queue_size),
|
||||
.pool = mem::new_array(Thread, threads)
|
||||
};
|
||||
self.mu.init()!;
|
||||
self.notify.init()!;
|
||||
foreach (&thread : self.pool)
|
||||
{
|
||||
thread.create(&process_work, self)!;
|
||||
// The thread resources will be cleaned up when the thread exits.
|
||||
thread.detach()!;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Stop all the threads and cleanup the pool.
|
||||
* Any pending work will be dropped.
|
||||
*/
|
||||
fn void! FixedThreadPool.destroy(&self)
|
||||
{
|
||||
return self.@shutdown(stop_now);
|
||||
}
|
||||
|
||||
/*
|
||||
* Stop all the threads and cleanup the pool.
|
||||
* Any pending work will be processed.
|
||||
*/
|
||||
fn void! FixedThreadPool.stop_and_destroy(&self)
|
||||
{
|
||||
return self.@shutdown(stop);
|
||||
}
|
||||
|
||||
macro void! FixedThreadPool.@shutdown(&self, #stop) @private
|
||||
{
|
||||
if (self.initialized)
|
||||
{
|
||||
self.mu.lock()!;
|
||||
self.#stop = true;
|
||||
self.notify.broadcast()!;
|
||||
self.mu.unlock()!;
|
||||
// Wait for all threads to shutdown.
|
||||
while (true)
|
||||
{
|
||||
self.mu.lock()!;
|
||||
defer self.mu.unlock()!!;
|
||||
if (self.num_threads == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
self.notify.signal()!;
|
||||
}
|
||||
self.mu.destroy()!;
|
||||
self.initialized = false;
|
||||
while (self.qindex)
|
||||
{
|
||||
free_qitem(self.queue[--self.qindex]);
|
||||
}
|
||||
free(self.queue);
|
||||
self.queue = {};
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Push a new job to the pool.
|
||||
* Returns whether the queue is full, in which case the job is ignored.
|
||||
*/
|
||||
fn void! FixedThreadPool.push(&self, ThreadPoolFn func, args...)
|
||||
{
|
||||
self.mu.lock()!;
|
||||
defer self.mu.unlock()!!;
|
||||
if (self.qindex == self.queue.len) return ThreadPoolResult.QUEUE_FULL?;
|
||||
any[] data;
|
||||
if (args.len)
|
||||
{
|
||||
data = mem::alloc_array(any, args.len);
|
||||
foreach (i, arg : args) data[i] = allocator::clone_any(allocator::heap(), arg);
|
||||
}
|
||||
self.queue[self.qindex] = { .func = func, .args = data };
|
||||
self.qindex++;
|
||||
defer catch
|
||||
{
|
||||
free_qitem(self.queue[--self.qindex]);
|
||||
}
|
||||
// Notify the threads that work is available.
|
||||
self.notify.broadcast()!;
|
||||
}
|
||||
|
||||
fn int process_work(void* self_arg) @private
|
||||
{
|
||||
FixedThreadPool* self = self_arg;
|
||||
while (true)
|
||||
{
|
||||
self.mu.lock()!!;
|
||||
if (self.stop_now)
|
||||
{
|
||||
// Shutdown requested.
|
||||
self.num_threads--;
|
||||
self.mu.unlock()!!;
|
||||
return 0;
|
||||
}
|
||||
// Wait for work.
|
||||
while (self.qindex == 0)
|
||||
{
|
||||
if (self.stop)
|
||||
{
|
||||
// Shutdown requested.
|
||||
self.num_threads--;
|
||||
self.mu.unlock()!!;
|
||||
return 0;
|
||||
}
|
||||
self.notify.wait(&self.mu)!!;
|
||||
if (self.stop_now)
|
||||
{
|
||||
// Shutdown requested.
|
||||
self.num_threads--;
|
||||
self.mu.unlock()!!;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// Process the job.
|
||||
self.qindex--;
|
||||
QueueItem item = self.queue[self.qindex];
|
||||
self.mu.unlock()!!;
|
||||
defer free_qitem(item);
|
||||
item.func(item.args);
|
||||
}
|
||||
}
|
||||
|
||||
fn void free_qitem(QueueItem item) @private
|
||||
{
|
||||
foreach (arg : item.args) free(arg.ptr);
|
||||
free(item.args);
|
||||
}
|
||||
@@ -24,12 +24,6 @@ fn void! NativeMutex.init(&self, MutexType type)
|
||||
{
|
||||
if (posix::pthread_mutexattr_settype(&attr, posix::PTHREAD_MUTEX_RECURSIVE)) return ThreadFault.INIT_FAILED?;
|
||||
}
|
||||
else
|
||||
{
|
||||
$if env::COMPILER_SAFE_MODE:
|
||||
if (posix::pthread_mutexattr_settype(&attr, posix::PTHREAD_MUTEX_ERRORCHECK)) return ThreadFault.INIT_FAILED?;
|
||||
$endif
|
||||
}
|
||||
if (posix::pthread_mutex_init(&self.mutex, &attr)) return ThreadFault.INIT_FAILED?;
|
||||
self.initialized = true;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ struct NativeMutex
|
||||
}
|
||||
// Size is less than a Win32_HANDLE so due to alignment
|
||||
// there is no benefit to pack these into a bitstruct.
|
||||
uint locks;
|
||||
bool already_locked;
|
||||
bool recursive;
|
||||
bool timed;
|
||||
}
|
||||
@@ -40,7 +40,7 @@ struct NativeConditionVariable
|
||||
|
||||
fn void! NativeMutex.init(&mtx, MutexType type)
|
||||
{
|
||||
mtx.locks = 0;
|
||||
mtx.already_locked = false;
|
||||
mtx.recursive = (bool)(type & thread::MUTEX_RECURSIVE);
|
||||
mtx.timed = (bool)(type & thread::MUTEX_TIMED);
|
||||
if (!mtx.timed)
|
||||
@@ -53,7 +53,6 @@ fn void! NativeMutex.init(&mtx, MutexType type)
|
||||
|
||||
fn void! NativeMutex.destroy(&mtx)
|
||||
{
|
||||
mtx.locks = 0;
|
||||
if (!mtx.timed)
|
||||
{
|
||||
win32::deleteCriticalSection(&mtx.critical_section);
|
||||
@@ -80,11 +79,11 @@ fn void! NativeMutex.lock(&mtx)
|
||||
|
||||
}
|
||||
}
|
||||
if (!mtx.recursive && mtx.locks)
|
||||
if (!mtx.recursive)
|
||||
{
|
||||
return ThreadFault.LOCK_FAILED?;
|
||||
while (mtx.already_locked) win32::sleep(1);
|
||||
}
|
||||
mtx.locks++;
|
||||
mtx.already_locked = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -104,11 +103,20 @@ fn void! NativeMutex.lock_timeout(&mtx, ulong ms)
|
||||
default:
|
||||
return ThreadFault.LOCK_FAILED?;
|
||||
}
|
||||
if (!mtx.recursive && mtx.locks)
|
||||
if (!mtx.recursive)
|
||||
{
|
||||
return ThreadFault.LOCK_FAILED?;
|
||||
usz left_timeout = ms - 1;
|
||||
while (mtx.already_locked)
|
||||
{
|
||||
if (left_timeout-- == 0)
|
||||
{
|
||||
win32::releaseMutex(mtx.handle);
|
||||
return ThreadFault.LOCK_TIMEOUT?;
|
||||
}
|
||||
win32::sleep(1);
|
||||
}
|
||||
mtx.already_locked = true;
|
||||
}
|
||||
mtx.locks++;
|
||||
}
|
||||
|
||||
fn bool NativeMutex.try_lock(&mtx)
|
||||
@@ -120,7 +128,7 @@ fn bool NativeMutex.try_lock(&mtx)
|
||||
if (!success) return false;
|
||||
if (!mtx.recursive)
|
||||
{
|
||||
if (mtx.locks)
|
||||
if (mtx.already_locked)
|
||||
{
|
||||
if (mtx.timed)
|
||||
{
|
||||
@@ -132,15 +140,14 @@ fn bool NativeMutex.try_lock(&mtx)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
mtx.already_locked = true;
|
||||
}
|
||||
mtx.locks++;
|
||||
return true;
|
||||
}
|
||||
|
||||
fn void! NativeMutex.unlock(&mtx)
|
||||
{
|
||||
if (!mtx.locks) return ThreadFault.UNLOCK_FAILED?;
|
||||
mtx.locks--;
|
||||
mtx.already_locked = false;
|
||||
if (!mtx.timed)
|
||||
{
|
||||
win32::leaveCriticalSection(&mtx.critical_section);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
module std::thread::pool(<SIZE>);
|
||||
import std::thread;
|
||||
|
||||
struct ThreadPool @adhoc
|
||||
struct ThreadPool
|
||||
{
|
||||
Mutex mu;
|
||||
QueueItem[SIZE] queue;
|
||||
@@ -17,7 +17,7 @@ struct ThreadPool @adhoc
|
||||
ConditionVariable notify;
|
||||
}
|
||||
|
||||
struct QueueItem @private
|
||||
struct QueueItem
|
||||
{
|
||||
ThreadFn func;
|
||||
void* arg;
|
||||
|
||||
@@ -67,7 +67,7 @@ macro bool Thread.equals(thread, Thread other) => NativeThread.equals((NativeThr
|
||||
macro void OnceFlag.call(&flag, OnceFn func) => NativeOnceFlag.call_once((NativeOnceFlag*)flag, func);
|
||||
|
||||
macro void yield() => os::native_thread_yield();
|
||||
macro Thread current() => (Thread)os::native_thread_current();
|
||||
macro Thread current() => os::native_thread_current();
|
||||
macro void exit(int result) => os::native_thread_exit(result);
|
||||
macro void! sleep(Duration d) @maydiscard => os::native_sleep_nano(d.to_nano());
|
||||
macro void! sleep_ms(ulong ms) @maydiscard => sleep(time::ms(ms));
|
||||
|
||||
@@ -20,19 +20,6 @@ fn DateTime from_date(int year, Month month = JANUARY, int day = 1, int hour = 0
|
||||
return dt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require day >= 1 && day < 32
|
||||
* @require hour >= 0 && hour < 24
|
||||
* @require min >= 0 && min < 60
|
||||
* @require sec >= 0 && sec < 60
|
||||
* @require us >= 0 && us < 999_999
|
||||
* @require gmt_offset >= -12 * 3600 && gmt_offset <= 14 * 3600
|
||||
**/
|
||||
fn TzDateTime from_date_tz(int year, Month month = JANUARY, int day = 1, int hour = 0, int min = 0, int sec = 0, int us = 0, int gmt_offset = 0)
|
||||
{
|
||||
return from_date(year, month, day, hour, min, sec, us).with_gmt_offset(gmt_offset);
|
||||
}
|
||||
|
||||
fn TzDateTime DateTime.to_local(&self)
|
||||
{
|
||||
Tm tm @noinit;
|
||||
@@ -60,58 +47,6 @@ fn TzDateTime DateTime.to_local(&self)
|
||||
return dt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update timestamp to gmt_offset while keeping the date and time
|
||||
* values unchanged.
|
||||
*
|
||||
* @require gmt_offset >= -12 * 3600 && gmt_offset <= 14 * 3600
|
||||
**/
|
||||
fn TzDateTime DateTime.with_gmt_offset(self, int gmt_offset)
|
||||
{
|
||||
TzDateTime dt = { self, 0 };
|
||||
return dt.with_gmt_offset(gmt_offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update timestamp to gmt_offset while keeping the date and time
|
||||
* values unchanged.
|
||||
*
|
||||
* @require gmt_offset >= -12 * 3600 && gmt_offset <= 14 * 3600
|
||||
**/
|
||||
fn TzDateTime TzDateTime.with_gmt_offset(self, int gmt_offset)
|
||||
{
|
||||
self.time -= (Time)(gmt_offset - self.gmt_offset) * (Time)time::SEC;
|
||||
return { self.date_time, gmt_offset };
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the date and time values to gmt_offset while keeping the
|
||||
* timestamp unchanged.
|
||||
*
|
||||
* @require gmt_offset >= -12 * 3600 && gmt_offset <= 14 * 3600
|
||||
* @ensure self.time == return.time
|
||||
**/
|
||||
fn TzDateTime DateTime.to_gmt_offset(self, int gmt_offset)
|
||||
{
|
||||
TzDateTime dt = { self, 0 };
|
||||
return dt.to_gmt_offset(gmt_offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the date and time values to gmt_offset while keeping the
|
||||
* timestamp unchanged.
|
||||
*
|
||||
* @require gmt_offset >= -12 * 3600 && gmt_offset <= 14 * 3600
|
||||
* @ensure self.time == return.time
|
||||
**/
|
||||
fn TzDateTime TzDateTime.to_gmt_offset(self, int gmt_offset) {
|
||||
if (self.gmt_offset == gmt_offset) return self;
|
||||
Time time = self.time + (Time)gmt_offset * (Time)time::SEC;
|
||||
DateTime dt = from_time(time);
|
||||
dt.time = self.time;
|
||||
return { dt, gmt_offset };
|
||||
}
|
||||
|
||||
/**
|
||||
* @require day >= 1 && day < 32
|
||||
* @require hour >= 0 && hour < 24
|
||||
@@ -186,16 +121,6 @@ fn DateTime DateTime.add_months(&self, int months)
|
||||
return from_date(year, (Month)month, self.day, self.hour, self.min, self.sec, self.usec);
|
||||
}
|
||||
|
||||
|
||||
fn TzDateTime TzDateTime.add_seconds(&self, int seconds) => self.date_time.add_seconds(seconds).to_gmt_offset(self.gmt_offset);
|
||||
fn TzDateTime TzDateTime.add_minutes(&self, int minutes) => self.date_time.add_minutes(minutes).to_gmt_offset(self.gmt_offset);
|
||||
fn TzDateTime TzDateTime.add_hours(&self, int hours) => self.date_time.add_hours(hours).to_gmt_offset(self.gmt_offset);
|
||||
fn TzDateTime TzDateTime.add_days(&self, int days) => self.date_time.add_days(days).to_gmt_offset(self.gmt_offset);
|
||||
fn TzDateTime TzDateTime.add_weeks(&self, int weeks) => self.date_time.add_weeks(weeks).to_gmt_offset(self.gmt_offset);
|
||||
|
||||
fn TzDateTime TzDateTime.add_years(&self, int years) => self.date_time.add_years(years).with_gmt_offset(self.gmt_offset);
|
||||
fn TzDateTime TzDateTime.add_months(&self, int months) => self.date_time.add_months(months).with_gmt_offset(self.gmt_offset);
|
||||
|
||||
fn DateTime from_time(Time time)
|
||||
{
|
||||
DateTime dt @noinit;
|
||||
@@ -203,15 +128,6 @@ fn DateTime from_time(Time time)
|
||||
return dt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require gmt_offset >= -12 * 3600 && gmt_offset <= 14 * 3600
|
||||
* @ensure time == return.time
|
||||
**/
|
||||
fn TzDateTime from_time_tz(Time time, int gmt_offset)
|
||||
{
|
||||
return from_time(time).to_gmt_offset(gmt_offset);
|
||||
}
|
||||
|
||||
fn Time DateTime.to_time(&self) @inline
|
||||
{
|
||||
return self.time;
|
||||
@@ -251,4 +167,4 @@ fn double DateTime.diff_sec(self, DateTime from)
|
||||
fn Duration DateTime.diff_us(self, DateTime from)
|
||||
{
|
||||
return self.time.diff_us(from.time);
|
||||
}
|
||||
}
|
||||
107
releasenotes.md
107
releasenotes.md
@@ -1,92 +1,5 @@
|
||||
# C3C Release Notes
|
||||
|
||||
## 0.6.3 Change list
|
||||
|
||||
### Changes / improvements
|
||||
- Introduce `arg: x` named arguments instead of `.arg = x`, deprecate old style.
|
||||
- Support splat for varargs #1352.
|
||||
- Allow `var` in lambdas in macros.
|
||||
- Support `int[*] { 1, 2, 3 }` expressions.
|
||||
- Support inline struct designated init as if inline was anonymous.
|
||||
- Introduce the `.paramsof` property.
|
||||
- Support environment variable 'C3C_LIB' to find the standard library.
|
||||
- Support environment variable 'C3C_CC' to find the default C compiler.
|
||||
- Support casting bitstructs to bool.
|
||||
- Allow user-defined attributes to have typed parameters.
|
||||
- Add `.gitkeep` files to project subfolders.
|
||||
- Add `env::COMPILER_BUILD_HASH` and `env::COMPILER_BUILD_DATE`
|
||||
- Support linking .o files in compilation command. #1417
|
||||
- Slicing constant strings at compile time works.
|
||||
- Add `project fetch` subcommand to fetch missing project dependencies (general and target specific)
|
||||
- Ability of `vendor-fetch` to download the dependencies in the first specified path `dependencies-search-path`
|
||||
- Ability of `vendor-fetch` to register the fetched dependencies in the project file.
|
||||
- Allow the "self" parameter to be $/# for macro methods.
|
||||
- Support compile time slicing of untyped lists.
|
||||
- Allow specifying an import module using `@wasm` #1305.
|
||||
- Deprecated inline generic types outside of struct definitions and macros unless marked `@adhoc`.
|
||||
- Improved method detection in earlier stages of checking.
|
||||
- Allow `@norecurse` attribute for non-recursive imports #1480.
|
||||
- wasm32 / wasm64 targets are use-libc=no by default.
|
||||
- Add hash/sha256 module
|
||||
|
||||
### Fixes
|
||||
- Issue where a lambda wasn't correctly registered as external. #1408
|
||||
- Generic methods were incorrectly registered as functions, leading to naming collisions. #1402
|
||||
- Deprecated tuple / triple types.
|
||||
- Converting a slice to a vector/array would copy too little data.
|
||||
- Crash when reading an empty 'manifest.json'.
|
||||
- "optsize" did not work correctly in project.json.
|
||||
- `l[0].a = 1` now supported for overloads due to better lvalue handling #1357.
|
||||
- Asserts are retained regardless of optimization when running tests.
|
||||
- Limit object filename lengths. #1415
|
||||
- Fix regression for `$include`.
|
||||
- Correct '.so' suffix on dynamic libraries on Linux.
|
||||
- Fix bug where inline index access to array in a struct would crash the compiler.
|
||||
- Asserts are now correctly included and traced in when running tests.
|
||||
- Use atexit to fix finalizers on Windows #1361.
|
||||
- Fix bugs in "trap-on-wrap" #1434.
|
||||
- Bug with casting anyfault to error.
|
||||
- Lambda / function type would accidentally be processed as a method.
|
||||
- Fix error message when not finding a particular function.
|
||||
- Crash invoking a `@body` argument with the wrong number of parameters.
|
||||
- Fix reordering semantics in struct assignment.
|
||||
- Regression when passing types as `#expr` arguments. #1461
|
||||
- Temp allocator overwrites data when doing reset on extra allocated pages. #1462
|
||||
- User defined attributes could not have more than 1 parameter due to bug.
|
||||
- Folding a constant array of structs at compile time would cause an assert.
|
||||
- Enum attributes would be overwritten by enum value attributes.
|
||||
- LLVM issue with try when bool is combined #1467.
|
||||
- Segfault using ternary with no assignment #1468.
|
||||
- Inner types make some errors misleading #1471.
|
||||
- Fix bug when passing a type as a compile time value.
|
||||
- Fix bug due to enum associated values not being checked for liveness.
|
||||
- Regression when compile time accessing a union field not last assigned to.
|
||||
- Safer seed of rand() for WASM without libc.
|
||||
- Bad error message aliasing an ident with a path. #1481.
|
||||
- Error when slicing a struct with an inline array #1488.
|
||||
- Improved error messages on `Foo a = foo { 1 };` #1496
|
||||
- Bug in json decoder escape handling.
|
||||
- Fix bug when reading zip manifest, that would not return a zero terminated string. #1490
|
||||
- Fix thread tests.
|
||||
- Detect recursion errors on non-recursive mutexes in safe mode.
|
||||
- Foreach over distinct pointer failed to be caught as error #1506.
|
||||
- Foreach over distinct iterable would ignore operator(len).
|
||||
- Compiler crash when compiling c code in a library without --obj-out #1503.
|
||||
|
||||
### Stdlib changes
|
||||
- Additional init functions for hashmap.
|
||||
- `format` functions are now functions and work better with splat.
|
||||
- Add support for the QOI format.
|
||||
- Add `io::read_new_fully` for reading to the end of a stream.
|
||||
- Add `io::wrap_bytes` for reading bytes with `io` functions.
|
||||
- Add `rnd` and `rand_in_range` default random functions.
|
||||
- Additional timezone related functions for `datetime`.
|
||||
- Added MD5 and crypto::safe_compare.
|
||||
- Added generic HMAC.
|
||||
- Added generic PBKDF2 implementation.
|
||||
- DString `reverse`.
|
||||
- `DString.insert_at` now has variants for other types.
|
||||
|
||||
## 0.6.2 Change list
|
||||
|
||||
### Changes / improvements
|
||||
@@ -123,8 +36,6 @@
|
||||
- Introduce `$vaarg[...]` syntax and deprecate the old `$vaarg(...)`.
|
||||
- Similar change to `$vasplat`: `$vasplat` and `$vasplat[1..]`.
|
||||
- Add `$member.get(value)` to replace `value.$eval($member.nameof)`
|
||||
- Improve the error message when the compilation does not produce any files #1390.
|
||||
- Add `fmod` implementation for nolibc.
|
||||
|
||||
### Fixes
|
||||
|
||||
@@ -171,22 +82,6 @@
|
||||
- Bug when compile time subtracting a distinct type.
|
||||
- `insert_at` incorrectly prevented inserts at the end of a list.
|
||||
- Fix aligned alloc for Win32 targets.
|
||||
- Compiler didn't detect when a module name was used both as a generic and regular module.
|
||||
- Assigning a const zero to an aliased distinct caused an error.
|
||||
- `--path` is now properly respected.
|
||||
- `--test` will now provide the full filename and the column.
|
||||
- Fix of bug in `defer (catch err)` with a direct return error.
|
||||
- Too restrictive compile time checks for @const.
|
||||
- Fixes to wasm nolibc in the standard library.
|
||||
- Fixed int128 div/mod.
|
||||
- Fix WASM memory init priority.
|
||||
- Fix bug with `defer (catch err)` when used together with regular defer.
|
||||
- Methods can now properly be aliased using `def` #1393.
|
||||
- Memory leak in Object when not using temp allocators.
|
||||
- Tracking allocator would double the allocations in the report.
|
||||
- `printf` will now show errors in the output when there are errors.
|
||||
- Bug where `if try` would work incorrectly in a macro.
|
||||
- Prevent loading / storing large structs with LLVM.
|
||||
|
||||
### Stdlib changes
|
||||
|
||||
@@ -198,7 +93,6 @@
|
||||
- Added `dstring.replace`
|
||||
- New hashmap type, `Map`
|
||||
- Added `ElasticArray`.
|
||||
- Added `types::is_signed`, `types::is_unsigned` and `types::inner_type`.
|
||||
|
||||
## 0.6.1 Change list
|
||||
|
||||
@@ -224,7 +118,6 @@
|
||||
- Added `--list-manifest-properties` to list the available properties in `manifest.json`.
|
||||
- Indexing into a constant array / struct now works at compile time.
|
||||
- Improved error message when trying user foreach with an untyped list.
|
||||
- RISCV asm support.
|
||||
|
||||
### Fixes
|
||||
- Error with unsigned compare in `@ensure` when early returning 0 #1207.
|
||||
|
||||
@@ -2,8 +2,8 @@ import std::io;
|
||||
|
||||
fn void main()
|
||||
{
|
||||
Path path = path::new_cwd()!!;
|
||||
foreach (i, p : path::new_ls(path)!!)
|
||||
Path path = path::getcwd()!!;
|
||||
foreach (i, p : path::ls(path)!!)
|
||||
{
|
||||
io::printfn("%02d %s", i, p.str_view());
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
fn int main()
|
||||
{
|
||||
String msg = "Hello, C3 World!\n";
|
||||
$$syscall(4, 1, (uptr)msg.ptr, msg.len); // __NR_write, STDOUT
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn void _start() @export("_start")
|
||||
{
|
||||
int ret = main();
|
||||
$$syscall(1, ret); // __NR_exit
|
||||
}
|
||||
|
||||
module std::core::builtin;
|
||||
|
||||
def PanicFn = fn void(String message, String file, String function, uint line);
|
||||
|
||||
PanicFn panic = &default_panic;
|
||||
|
||||
fn void default_panic(String message, String file, String function, uint line)
|
||||
{
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
{
|
||||
// Language version of C3.
|
||||
"langrev": "1",
|
||||
// Warnings used for all targets.
|
||||
"warnings": [ "no-unused" ],
|
||||
// Directories where C3 library files may be found.
|
||||
"dependency-search-paths": [ ],
|
||||
// Libraries to use for all targets.
|
||||
"dependencies": [ ],
|
||||
// Authors, optionally with email.
|
||||
"authors": [ "John Doe <john.doe@example.com>" ],
|
||||
// Version using semantic versioning.
|
||||
"version": "0.1.0",
|
||||
// Sources compiled for all targets.
|
||||
"sources": [ "./**" ],
|
||||
// C sources if the project also compiles C sources
|
||||
// relative to the project file.
|
||||
// "c-sources": [ "csource/**" ],
|
||||
// Output location, relative to project file.
|
||||
"output": ".",
|
||||
// Architecture and OS target.
|
||||
// You can use 'c3c --list-targets' to list all valid targets.
|
||||
"target": "freebsd-x64",
|
||||
// Targets.
|
||||
"targets": {
|
||||
"hello_world": {
|
||||
"type": "executable",
|
||||
"debug-info": "none",
|
||||
"link-libc": false,
|
||||
"opt": "O0",
|
||||
"safe": false,
|
||||
"linker": "builtin",
|
||||
"use-stdlib": false,
|
||||
},
|
||||
},
|
||||
// Global settings.
|
||||
// C compiler if the project also compiles C sources
|
||||
// defaults to 'cc'.
|
||||
"cc": "cc",
|
||||
// CPU name, used for optimizations in the LLVM backend.
|
||||
"cpu": "generic",
|
||||
// Debug information, may be "none", "full" and "line-tables".
|
||||
"debug-info": "full",
|
||||
// FP math behaviour: "strict", "relaxed", "fast".
|
||||
"fp-math": "strict",
|
||||
// Link libc other default libraries.
|
||||
"link-libc": true,
|
||||
// Memory environment: "normal", "small", "tiny", "none".
|
||||
"memory-env": "normal",
|
||||
// Optimization: "O0", "O1", "O2", "O3", "O4", "O5", "Os", "Oz".
|
||||
"opt": "O0",
|
||||
// Code optimization level: "none", "less", "more", "max".
|
||||
"optlevel": "none",
|
||||
// Code size optimization: "none", "small", "tiny".
|
||||
"optsize": "none",
|
||||
// Relocation model: "none", "pic", "PIC", "pie", "PIE".
|
||||
"reloc": "none",
|
||||
// Trap on signed and unsigned integer wrapping for testing.
|
||||
"trap-on-wrap": false,
|
||||
// Turn safety (contracts, runtime bounds checking, null pointer checks etc).
|
||||
"safe": true,
|
||||
// Compile all modules together, enables more inlining.
|
||||
"single-module": true,
|
||||
// Use / don't use soft float, value is otherwise target default.
|
||||
"soft-float": false,
|
||||
// Strip unused code and globals from the output.
|
||||
"strip-unused": true,
|
||||
// The size of the symtab, which limits the amount
|
||||
// of symbols that can be used. Should usually not be changed.
|
||||
"symtab": 1048576,
|
||||
// Select linker.
|
||||
"linker": "cc",
|
||||
// Include the standard library.
|
||||
"use-stdlib": true,
|
||||
// Set general level of x64 cpu: "baseline", "ssse3", "sse4", "avx1", "avx2-v1", "avx2-v2", "avx512", "native".
|
||||
"x86cpu": "native",
|
||||
// Set max type of vector use: "none", "mmx", "sse", "avx", "avx512", "native".
|
||||
"x86vec": "sse",
|
||||
}
|
||||
76
resources/examples/opengl/.gitignore
vendored
76
resources/examples/opengl/.gitignore
vendored
@@ -1,76 +0,0 @@
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Object files
|
||||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.elf
|
||||
*.ll
|
||||
|
||||
# Linker output
|
||||
*.ilk
|
||||
*.map
|
||||
*.exp
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Libraries
|
||||
*.lib
|
||||
*.a
|
||||
*.la
|
||||
*.lo
|
||||
|
||||
# Shared objects (inc. Windows DLLs)
|
||||
*.dll
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
*.i*86
|
||||
*.x86_64
|
||||
*.hex
|
||||
|
||||
# Debug files
|
||||
*.dSYM/
|
||||
*.su
|
||||
*.idb
|
||||
*.pdb
|
||||
|
||||
# Kernel Module Compile Results
|
||||
*.mod*
|
||||
*.cmd
|
||||
.tmp_versions/
|
||||
modules.order
|
||||
Module.symvers
|
||||
Mkfile.old
|
||||
dkms.conf
|
||||
/build/
|
||||
.idea/
|
||||
/resources/grammar.tab.c
|
||||
/resources/grammar.vcg
|
||||
/resources/lex.yy.c
|
||||
/resources/y.tab.c
|
||||
/resources/y.tab.h
|
||||
/bin/
|
||||
|
||||
#visual studio files
|
||||
.vs/
|
||||
.vscode/
|
||||
out/
|
||||
|
||||
/cmake-build-debug/
|
||||
/cmake-build-release/
|
||||
|
||||
# Emacs files
|
||||
TAGS
|
||||
|
||||
# Clangd LSP files
|
||||
/.cache/
|
||||
/compile_commands.json
|
||||
@@ -1,28 +0,0 @@
|
||||
{
|
||||
"version": "0.1.0",
|
||||
"authors": [
|
||||
"John Doe <john.doe@example.com>"
|
||||
],
|
||||
"langrev": "1",
|
||||
"warnings": [
|
||||
"no-unused"
|
||||
],
|
||||
"sources": [
|
||||
"./**"
|
||||
],
|
||||
"dependency-search-paths": [],
|
||||
"dependencies": [],
|
||||
"cc": "cc",
|
||||
"c-sources": [],
|
||||
"targets": {
|
||||
"build/triangle": {
|
||||
"type": "executable"
|
||||
}
|
||||
},
|
||||
"linked-libraries": [
|
||||
"glfw",
|
||||
"GL"
|
||||
],
|
||||
"cpu": "generic",
|
||||
"opt": "O0"
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
module gl;
|
||||
|
||||
def BitField = int;
|
||||
|
||||
enum BufferBit : int(int value) {
|
||||
COLOR = 0x00004000,
|
||||
STENCIL = 0x00000400,
|
||||
DEPTH = 0x00000100,
|
||||
}
|
||||
|
||||
enum Primitive : int(int value) {
|
||||
POINTS = 0,
|
||||
LINES = 1,
|
||||
LINE_LOOP = 2,
|
||||
LINE_STRIP = 3,
|
||||
TRIANGLES = 4,
|
||||
TRIANGLE_STRIP = 5,
|
||||
TRIANGLE_FAN = 6,
|
||||
QUADS = 7,
|
||||
QUAD_STRIP = 8,
|
||||
POLYGON = 9,
|
||||
}
|
||||
|
||||
extern fn void clear(BitField mask) @extern("glClear") @public;
|
||||
|
||||
extern fn void begin(BitField mask) @extern("glBegin") @public;
|
||||
|
||||
extern fn void end() @extern("glEnd") @public;
|
||||
|
||||
extern fn void flush() @extern("glFlush") @public;
|
||||
|
||||
extern fn void color3f(float r, float g, float b)
|
||||
@extern("glColor3f") @public;
|
||||
|
||||
extern fn void vertex3f(float x, float y, float z)
|
||||
@extern("glVertex3f") @public;
|
||||
@@ -1,64 +0,0 @@
|
||||
module glfw;
|
||||
|
||||
import std::io;
|
||||
|
||||
distinct Window @public = _Window*;
|
||||
distinct Monitor @public = _Monitor*;
|
||||
|
||||
fn void Window.create(
|
||||
&self,
|
||||
int width,
|
||||
int height,
|
||||
String title,
|
||||
Monitor monitor = {},
|
||||
Window share = {}
|
||||
) @public {
|
||||
*self = (Window)_glfwCreateWindow(
|
||||
width,
|
||||
height,
|
||||
title,
|
||||
(_Monitor*)monitor,
|
||||
(_Window*)share
|
||||
);
|
||||
}
|
||||
|
||||
fn void Window.destroy(self) @public {
|
||||
_glfwDestroyWindow((_Window*)self);
|
||||
}
|
||||
|
||||
fn bool Window.shouldClose(self) @public {
|
||||
return _glfwWindowShouldClose((_Window*)self);
|
||||
}
|
||||
|
||||
fn void Window.swapBuffers(self) @public {
|
||||
return _glfwSwapBuffers((_Window*)self);
|
||||
}
|
||||
|
||||
fn void Window.makeContextCurrent(self) @public {
|
||||
return _glfwMakeContextCurrent((_Window*)self);
|
||||
}
|
||||
|
||||
extern fn void initialize() @extern("glfwInit") @public;
|
||||
|
||||
extern fn void terminate() @extern("glfwTerminate") @public;
|
||||
|
||||
extern fn void pollEvents() @extern("glfwPollEvents") @public;
|
||||
|
||||
distinct _Window @private = void;
|
||||
distinct _Monitor @private = void;
|
||||
|
||||
extern fn _Window* _glfwCreateWindow(
|
||||
int width, int height, char* title, _Monitor* monitor, _Window* share
|
||||
) @extern("glfwCreateWindow") @private;
|
||||
|
||||
extern fn bool _glfwWindowShouldClose(_Window* window)
|
||||
@extern("glfwWindowShouldClose") @private;
|
||||
|
||||
extern fn void _glfwDestroyWindow(_Window* window)
|
||||
@extern("glfwDestroyWindow") @private;
|
||||
|
||||
extern fn void _glfwSwapBuffers(_Window* window)
|
||||
@extern("glfwSwapBuffers") @private;
|
||||
|
||||
extern fn void _glfwMakeContextCurrent(_Window* window)
|
||||
@extern("glfwMakeContextCurrent") @private;
|
||||
@@ -1,30 +0,0 @@
|
||||
import std::io;
|
||||
import glfw;
|
||||
import gl;
|
||||
|
||||
fn void main() {
|
||||
glfw::initialize();
|
||||
|
||||
Window window;
|
||||
window.create(1280, 720, "Triangle example");
|
||||
window.makeContextCurrent();
|
||||
|
||||
while(!window.shouldClose()) {
|
||||
gl::clear(BufferBit.COLOR.value);
|
||||
|
||||
gl::begin(Primitive.TRIANGLES.value);
|
||||
gl::color3f(1, 0, 0); gl::vertex3f(-0.6, -0.75, 0.5);
|
||||
gl::color3f(0, 1, 0); gl::vertex3f(0.6, -0.75, 0);
|
||||
gl::color3f(0, 0, 1); gl::vertex3f(0, 0.75, 0);
|
||||
gl::end();
|
||||
|
||||
gl::flush();
|
||||
|
||||
window.swapBuffers();
|
||||
glfw::pollEvents();
|
||||
}
|
||||
|
||||
window.destroy();
|
||||
|
||||
glfw::terminate();
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
module arkanoid;
|
||||
import raylib5;
|
||||
import raylib;
|
||||
import std::math;
|
||||
/**
|
||||
*
|
||||
@@ -72,15 +72,15 @@ fn void main()
|
||||
{
|
||||
// Initialization (Note windowTitle is unused on Android)
|
||||
//---------------------------------------------------------
|
||||
rl::initWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "classic game: arkanoid");
|
||||
raylib::init_window(SCREEN_WIDTH, SCREEN_HEIGHT, "classic game: arkanoid");
|
||||
|
||||
init_game();
|
||||
|
||||
rl::setTargetFPS(60);
|
||||
raylib::set_target_fps(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Main game loop
|
||||
while (!rl::windowShouldClose()) // Detect window close button or ESC key
|
||||
while (!raylib::window_should_close()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update and Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
@@ -91,7 +91,7 @@ fn void main()
|
||||
//--------------------------------------------------------------------------------------
|
||||
unload_game(); // Unload loaded data (textures, sounds, models...)
|
||||
|
||||
rl::closeWindow(); // Close window and OpenGL context
|
||||
raylib::close_window(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
}
|
||||
@@ -103,7 +103,7 @@ fn void main()
|
||||
// Initialize game variables
|
||||
fn void init_game()
|
||||
{
|
||||
brick_size = { (float)rl::getScreenWidth() / BRICKS_PER_LINE, 40 };
|
||||
brick_size = { (float)raylib::get_screen_width() / BRICKS_PER_LINE, 40 };
|
||||
|
||||
// Initialize player
|
||||
player.position = { SCREEN_WIDTH/2, SCREEN_HEIGHT * 7 / 8 };
|
||||
@@ -134,25 +134,25 @@ fn void update_game()
|
||||
{
|
||||
if (game_over)
|
||||
{
|
||||
if (rl::isKeyPressed(rl::KEY_ENTER))
|
||||
if (raylib::is_key_pressed(keyboard::ENTER))
|
||||
{
|
||||
init_game();
|
||||
game_over = false;
|
||||
}
|
||||
}
|
||||
if (rl::isKeyPressed((KeyboardKey)'P')) pause = !pause;
|
||||
if (raylib::is_key_pressed((KeyboardKey)'P')) pause = !pause;
|
||||
|
||||
if (pause) return;
|
||||
// Player movement logic
|
||||
if (rl::isKeyDown(rl::KEY_LEFT)) player.position.x -= 5;
|
||||
if (raylib::is_key_down(keyboard::LEFT)) player.position.x -= 5;
|
||||
if ((player.position.x - player.size.x/2) <= 0) player.position.x = player.size.x/2;
|
||||
if (rl::isKeyDown(rl::KEY_RIGHT)) player.position.x += 5;
|
||||
if (raylib::is_key_down(keyboard::RIGHT)) player.position.x += 5;
|
||||
if ((player.position.x + player.size.x/2) >= SCREEN_WIDTH) player.position.x = SCREEN_WIDTH - player.size.x/2;
|
||||
|
||||
// Ball launching logic
|
||||
if (!ball.active)
|
||||
{
|
||||
if (rl::isKeyPressed(rl::KEY_SPACE))
|
||||
if (raylib::is_key_pressed(keyboard::SPACE))
|
||||
{
|
||||
ball.active = true;
|
||||
ball.speed = { 0, -5 };
|
||||
@@ -182,7 +182,7 @@ fn void update_game()
|
||||
}
|
||||
|
||||
// Collision logic: ball vs player
|
||||
if (rl::checkCollisionCircleRec(ball.position, ball.radius,
|
||||
if (raylib::check_collision_circle_rec(ball.position, ball.radius,
|
||||
Rectangle{ player.position.x - player.size.x / 2, player.position.y - player.size.y / 2, player.size.x, player.size.y}))
|
||||
{
|
||||
if (ball.speed.y > 0)
|
||||
@@ -256,20 +256,20 @@ fn void update_game()
|
||||
// Draw game (one frame)
|
||||
fn void draw_game()
|
||||
{
|
||||
rl::beginDrawing();
|
||||
defer rl::endDrawing();
|
||||
rl::clearBackground(rl::RAYWHITE);
|
||||
raylib::begin_drawing();
|
||||
|
||||
raylib::clear_background(raylib::RAYWHITE);
|
||||
|
||||
if (!game_over)
|
||||
{
|
||||
// Draw player bar
|
||||
rl::drawRectangle((int)(player.position.x - player.size.x/2), (int)(player.position.y - player.size.y/2), (int)player.size.x, (int)player.size.y, rl::BLACK);
|
||||
raylib::draw_rectangle((int)(player.position.x - player.size.x/2), (int)(player.position.y - player.size.y/2), (int)player.size.x, (int)player.size.y, raylib::BLACK);
|
||||
|
||||
// Draw player lives
|
||||
for (int i = 0; i < player.life; i++) rl::drawRectangle(20 + 40*i, SCREEN_HEIGHT - 30, 35, 10, rl::LIGHTGRAY);
|
||||
for (int i = 0; i < player.life; i++) raylib::draw_rectangle(20 + 40*i, SCREEN_HEIGHT - 30, 35, 10, raylib::LIGHTGRAY);
|
||||
|
||||
// Draw ball
|
||||
rl::drawCircleV(ball.position, ball.radius, rl::MAROON);
|
||||
raylib::draw_circle_v(ball.position, ball.radius, raylib::MAROON);
|
||||
|
||||
// Draw bricks
|
||||
for (int i = 0; i < LINES_OF_BRICKS; i++)
|
||||
@@ -280,22 +280,24 @@ fn void draw_game()
|
||||
{
|
||||
if ((i + j) % 2 == 0)
|
||||
{
|
||||
rl::drawRectangle((int)(brick[i][j].position.x - brick_size.x/2), (int)(brick[i][j].position.y - brick_size.y/2), (int)brick_size.x, (int)brick_size.y, rl::GRAY);
|
||||
raylib::draw_rectangle((int)(brick[i][j].position.x - brick_size.x/2), (int)(brick[i][j].position.y - brick_size.y/2), (int)brick_size.x, (int)brick_size.y, raylib::GRAY);
|
||||
}
|
||||
else
|
||||
{
|
||||
rl::drawRectangle((int)(brick[i][j].position.x - brick_size.x/2), (int)(brick[i][j].position.y - brick_size.y/2), (int)brick_size.x, (int)brick_size.y, rl::DARKGRAY);
|
||||
raylib::draw_rectangle((int)(brick[i][j].position.x - brick_size.x/2), (int)(brick[i][j].position.y - brick_size.y/2), (int)brick_size.x, (int)brick_size.y, raylib::DARKGRAY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pause) rl::drawText("GAME PAUSED", SCREEN_WIDTH/2 - rl::measureText("GAME PAUSED", 40)/2, SCREEN_HEIGHT/2 - 40, 40, rl::GRAY);
|
||||
if (pause) raylib::draw_text("GAME PAUSED", SCREEN_WIDTH/2 - raylib::measure_text("GAME PAUSED", 40)/2, SCREEN_HEIGHT/2 - 40, 40, raylib::GRAY);
|
||||
}
|
||||
else
|
||||
{
|
||||
rl::drawText("PRESS [ENTER] TO PLAY AGAIN", rl::getScreenWidth()/2 - rl::measureText("PRESS [ENTER] TO PLAY AGAIN", 20)/2, rl::getScreenHeight()/2 - 50, 20, rl::GRAY);
|
||||
raylib::draw_text("PRESS [ENTER] TO PLAY AGAIN", raylib::get_screen_width()/2 - raylib::measure_text("PRESS [ENTER] TO PLAY AGAIN", 20)/2, raylib::get_screen_height()/2 - 50, 20, raylib::GRAY);
|
||||
}
|
||||
|
||||
raylib::end_drawing();
|
||||
}
|
||||
|
||||
// Unload game variables
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module snake;
|
||||
import raylib5;
|
||||
import raylib;
|
||||
/**
|
||||
*
|
||||
* raylib - classic game: snake
|
||||
@@ -53,18 +53,18 @@ int counter_tail = 0;
|
||||
|
||||
fn void main()
|
||||
{
|
||||
rl::initWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "classic game: snake");
|
||||
raylib::init_window(SCREEN_WIDTH, SCREEN_HEIGHT, "classic game: snake");
|
||||
init_game();
|
||||
rl::setTargetFPS(60);
|
||||
raylib::set_target_fps(60);
|
||||
|
||||
while (!rl::windowShouldClose()) // Detect window close button or ESC key
|
||||
while (!raylib::window_should_close()) // Detect window close button or ESC key
|
||||
{
|
||||
update_draw_frame();
|
||||
}
|
||||
|
||||
unload_game();
|
||||
|
||||
rl::closeWindow();
|
||||
raylib::close_window();
|
||||
}
|
||||
|
||||
// Initialize game variables
|
||||
@@ -87,11 +87,11 @@ fn void init_game()
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
snake[i].color = rl::DARKBLUE;
|
||||
snake[i].color = raylib::DARKBLUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
snake[i].color = rl::BLUE;
|
||||
snake[i].color = raylib::BLUE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ fn void init_game()
|
||||
}
|
||||
|
||||
fruit.size = { SQUARE_SIZE, SQUARE_SIZE };
|
||||
fruit.color = rl::SKYBLUE;
|
||||
fruit.color = raylib::SKYBLUE;
|
||||
fruit.active = false;
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ fn void update_game()
|
||||
{
|
||||
if (game_over)
|
||||
{
|
||||
if (rl::isKeyPressed(rl::KEY_ENTER))
|
||||
if (raylib::is_key_pressed(keyboard::ENTER))
|
||||
{
|
||||
init_game();
|
||||
game_over = false;
|
||||
@@ -118,16 +118,16 @@ fn void update_game()
|
||||
return;
|
||||
}
|
||||
|
||||
if (rl::isKeyPressed((KeyboardKey)'P')) pause = !pause;
|
||||
if (raylib::is_key_pressed((KeyboardKey)'P')) pause = !pause;
|
||||
|
||||
if (pause) return;
|
||||
|
||||
if (rl::isKeyPressed(rl::KEY_RIGHT) && allow_move)
|
||||
if (raylib::is_key_pressed(keyboard::RIGHT) && allow_move)
|
||||
{
|
||||
snake_direction = (SnakeDirection)((snake_direction.ordinal + 1) % 4);
|
||||
allow_move = false;
|
||||
}
|
||||
if (rl::isKeyPressed(rl::KEY_LEFT) && allow_move)
|
||||
if (raylib::is_key_pressed(keyboard::LEFT) && allow_move)
|
||||
{
|
||||
snake_direction = (SnakeDirection)((snake_direction.ordinal + 3) % 4);
|
||||
allow_move = false;
|
||||
@@ -179,13 +179,13 @@ fn void update_game()
|
||||
if (!fruit.active)
|
||||
{
|
||||
fruit.active = true;
|
||||
fruit.position = { (float)rl::getRandomValue(0, (SCREEN_WIDTH / SQUARE_SIZE) - 1) * SQUARE_SIZE + offset.x / 2, (float)rl::getRandomValue(0, (SCREEN_HEIGHT / SQUARE_SIZE) - 1) * SQUARE_SIZE + offset.y / 2 };
|
||||
fruit.position = { (float)raylib::get_random_value(0, (SCREEN_WIDTH / SQUARE_SIZE) - 1) * SQUARE_SIZE + offset.x / 2, (float)raylib::get_random_value(0, (SCREEN_HEIGHT / SQUARE_SIZE) - 1) * SQUARE_SIZE + offset.y / 2 };
|
||||
|
||||
for (int i = 0; i < counter_tail; i++)
|
||||
{
|
||||
while ((fruit.position.x == snake[i].position.x) && (fruit.position.y == snake[i].position.y))
|
||||
{
|
||||
fruit.position = { (float)rl::getRandomValue(0, (SCREEN_WIDTH / SQUARE_SIZE) - 1) * SQUARE_SIZE + offset.x/2, (float)rl::getRandomValue(0, (SCREEN_HEIGHT / SQUARE_SIZE) - 1) * SQUARE_SIZE + offset.y / 2 };
|
||||
fruit.position = { (float)raylib::get_random_value(0, (SCREEN_WIDTH / SQUARE_SIZE) - 1) * SQUARE_SIZE + offset.x/2, (float)raylib::get_random_value(0, (SCREEN_HEIGHT / SQUARE_SIZE) - 1) * SQUARE_SIZE + offset.y / 2 };
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
@@ -204,37 +204,37 @@ fn void update_game()
|
||||
// Draw game (one frame)
|
||||
fn void draw_game()
|
||||
{
|
||||
rl::beginDrawing();
|
||||
raylib::begin_drawing();
|
||||
|
||||
rl::clearBackground(rl::RAYWHITE);
|
||||
raylib::clear_background(raylib::RAYWHITE);
|
||||
|
||||
if (!game_over)
|
||||
{
|
||||
// Draw grid lines
|
||||
for (int i = 0; i < SCREEN_WIDTH / SQUARE_SIZE + 1; i++)
|
||||
{
|
||||
rl::drawLineV({(float)SQUARE_SIZE * i + offset.x/2, offset.y/2}, {(float)SQUARE_SIZE * i + offset.x/2, SCREEN_HEIGHT - offset.y/2}, rl::LIGHTGRAY);
|
||||
raylib::draw_line_v({(float)SQUARE_SIZE * i + offset.x/2, offset.y/2}, {(float)SQUARE_SIZE * i + offset.x/2, SCREEN_HEIGHT - offset.y/2}, raylib::LIGHTGRAY);
|
||||
}
|
||||
|
||||
for (int i = 0; i < SCREEN_HEIGHT/SQUARE_SIZE + 1; i++)
|
||||
{
|
||||
rl::drawLineV({offset.x/2, (float)SQUARE_SIZE * i + offset.y / 2 }, { SCREEN_WIDTH - offset.x/2, (float)SQUARE_SIZE * i + offset.y / 2 }, rl::LIGHTGRAY);
|
||||
raylib::draw_line_v({offset.x/2, (float)SQUARE_SIZE * i + offset.y / 2 }, { SCREEN_WIDTH - offset.x/2, (float)SQUARE_SIZE * i + offset.y / 2 }, raylib::LIGHTGRAY);
|
||||
}
|
||||
|
||||
// Draw snake
|
||||
for (int i = 0; i < counter_tail; i++) rl::drawRectangleV(snake[i].position, snake[i].size, snake[i].color);
|
||||
for (int i = 0; i < counter_tail; i++) raylib::draw_rectangle_v(snake[i].position, snake[i].size, snake[i].color);
|
||||
|
||||
// Draw fruit to pick
|
||||
rl::drawRectangleV(fruit.position, fruit.size, fruit.color);
|
||||
raylib::draw_rectangle_v(fruit.position, fruit.size, fruit.color);
|
||||
|
||||
if (pause) rl::drawText("GAME PAUSED", SCREEN_WIDTH/2 - rl::measureText("GAME PAUSED", 40)/2, SCREEN_HEIGHT / 2 - 40, 40, rl::GRAY);
|
||||
if (pause) raylib::draw_text("GAME PAUSED", SCREEN_WIDTH/2 - raylib::measure_text("GAME PAUSED", 40)/2, SCREEN_HEIGHT / 2 - 40, 40, raylib::GRAY);
|
||||
}
|
||||
else
|
||||
{
|
||||
rl::drawText("PRESS [ENTER] TO PLAY AGAIN", rl::getScreenWidth()/2 - rl::measureText("PRESS [ENTER] TO PLAY AGAIN", 20)/2, rl::getScreenHeight()/2 - 50, 20, rl::GRAY);
|
||||
raylib::draw_text("PRESS [ENTER] TO PLAY AGAIN", raylib::get_screen_width()/2 - raylib::measure_text("PRESS [ENTER] TO PLAY AGAIN", 20)/2, raylib::get_screen_height()/2 - 50, 20, raylib::GRAY);
|
||||
}
|
||||
|
||||
rl::endDrawing();
|
||||
raylib::end_drawing();
|
||||
}
|
||||
|
||||
// Unload game variables
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module tetris;
|
||||
import raylib5;
|
||||
import raylib;
|
||||
/**
|
||||
* raylib - classic game: tetris
|
||||
*
|
||||
@@ -83,15 +83,15 @@ fn void main()
|
||||
{
|
||||
// Initialization (Note windowTitle is unused on Android)
|
||||
//---------------------------------------------------------
|
||||
rl::initWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "classic game: tetris");
|
||||
raylib::init_window(SCREEN_WIDTH, SCREEN_HEIGHT, "classic game: tetris");
|
||||
|
||||
init_game();
|
||||
|
||||
rl::setTargetFPS(60);
|
||||
raylib::set_target_fps(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Main game loop
|
||||
while (!rl::windowShouldClose()) // Detect window close button or ESC key
|
||||
while (!raylib::window_should_close()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update and Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
@@ -102,7 +102,7 @@ fn void main()
|
||||
//--------------------------------------------------------------------------------------
|
||||
unload_game(); // Unload loaded data (textures, sounds, models...)
|
||||
|
||||
rl::closeWindow(); // Close window and OpenGL context
|
||||
raylib::close_window(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
}
|
||||
@@ -118,7 +118,7 @@ fn void init_game()
|
||||
level = 1;
|
||||
lines = 0;
|
||||
|
||||
fading_color = rl::GRAY;
|
||||
fading_color = raylib::GRAY;
|
||||
|
||||
piece_position_x = 0;
|
||||
piece_position_y = 0;
|
||||
@@ -170,14 +170,14 @@ fn void update_game()
|
||||
{
|
||||
if (game_over)
|
||||
{
|
||||
if (rl::isKeyPressed(rl::KEY_ENTER))
|
||||
if (raylib::is_key_pressed(keyboard::ENTER))
|
||||
{
|
||||
init_game();
|
||||
game_over = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (rl::isKeyPressed((KeyboardKey)'P')) pause = !pause;
|
||||
if (raylib::is_key_pressed((KeyboardKey)'P')) pause = !pause;
|
||||
|
||||
if (pause) return;
|
||||
if (line_to_delete)
|
||||
@@ -185,7 +185,7 @@ fn void update_game()
|
||||
// Animation when deleting lines
|
||||
fade_line_counter++;
|
||||
|
||||
fading_color = fade_line_counter % 8 < 4 ? rl::MAROON : rl::GRAY;
|
||||
fading_color = fade_line_counter % 8 < 4 ? raylib::MAROON : raylib::GRAY;
|
||||
|
||||
if (fade_line_counter >= FADING_TIME)
|
||||
{
|
||||
@@ -213,11 +213,11 @@ fn void update_game()
|
||||
turn_movement_counter++;
|
||||
|
||||
// We make sure to move if we've pressed the key this frame
|
||||
if (rl::isKeyPressed(rl::KEY_LEFT) || rl::isKeyPressed(rl::KEY_RIGHT)) lateral_movement_counter = LATERAL_SPEED;
|
||||
if (rl::isKeyPressed(rl::KEY_UP)) turn_movement_counter = TURNING_SPEED;
|
||||
if (raylib::is_key_pressed(keyboard::LEFT) || raylib::is_key_pressed(keyboard::RIGHT)) lateral_movement_counter = LATERAL_SPEED;
|
||||
if (raylib::is_key_pressed(keyboard::UP)) turn_movement_counter = TURNING_SPEED;
|
||||
|
||||
// Fall down
|
||||
if (rl::isKeyDown(rl::KEY_DOWN) && (fast_fall_movement_counter >= FAST_FALL_AWAIT_COUNTER))
|
||||
if (raylib::is_key_down(keyboard::DOWN) && (fast_fall_movement_counter >= FAST_FALL_AWAIT_COUNTER))
|
||||
{
|
||||
// We make sure the piece is going to fall this frame
|
||||
gravity_movement_counter += gravity_speed;
|
||||
@@ -268,13 +268,14 @@ fn void update_game()
|
||||
// Draw game (one frame)
|
||||
fn void draw_game()
|
||||
{
|
||||
rl::beginDrawing();
|
||||
defer rl::endDrawing();
|
||||
rl::clearBackground(rl::RAYWHITE);
|
||||
raylib::begin_drawing();
|
||||
|
||||
raylib::clear_background(raylib::RAYWHITE);
|
||||
|
||||
if (game_over)
|
||||
{
|
||||
rl::drawText("PRESS [ENTER] TO PLAY AGAIN", rl::getScreenWidth() / 2 - rl::measureText("PRESS [ENTER] TO PLAY AGAIN", 20) / 2, rl::getScreenHeight() / 2 - 50, 20, rl::GRAY);
|
||||
raylib::draw_text("PRESS [ENTER] TO PLAY AGAIN", raylib::get_screen_width() / 2 - raylib::measure_text("PRESS [ENTER] TO PLAY AGAIN", 20) / 2, raylib::get_screen_height() / 2 - 50, 20, raylib::GRAY);
|
||||
raylib::end_drawing();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -295,22 +296,22 @@ fn void draw_game()
|
||||
switch (grid[i][j])
|
||||
{
|
||||
case EMPTY:
|
||||
rl::drawLine(offset.x, offset.y, offset.x + SQUARE_SIZE, offset.y, rl::LIGHTGRAY );
|
||||
rl::drawLine(offset.x, offset.y, offset.x, offset.y + SQUARE_SIZE, rl::LIGHTGRAY );
|
||||
rl::drawLine(offset.x + SQUARE_SIZE, offset.y, offset.x + SQUARE_SIZE, offset.y + SQUARE_SIZE, rl::LIGHTGRAY );
|
||||
rl::drawLine(offset.x, offset.y + SQUARE_SIZE, offset.x + SQUARE_SIZE, offset.y + SQUARE_SIZE, rl::LIGHTGRAY );
|
||||
raylib::draw_line(offset.x, offset.y, offset.x + SQUARE_SIZE, offset.y, raylib::LIGHTGRAY );
|
||||
raylib::draw_line(offset.x, offset.y, offset.x, offset.y + SQUARE_SIZE, raylib::LIGHTGRAY );
|
||||
raylib::draw_line(offset.x + SQUARE_SIZE, offset.y, offset.x + SQUARE_SIZE, offset.y + SQUARE_SIZE, raylib::LIGHTGRAY );
|
||||
raylib::draw_line(offset.x, offset.y + SQUARE_SIZE, offset.x + SQUARE_SIZE, offset.y + SQUARE_SIZE, raylib::LIGHTGRAY );
|
||||
offset.x += SQUARE_SIZE;
|
||||
case FULL:
|
||||
rl::drawRectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, rl::GRAY);
|
||||
raylib::draw_rectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, raylib::GRAY);
|
||||
offset.x += SQUARE_SIZE;
|
||||
case MOVING:
|
||||
rl::drawRectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, rl::DARKGRAY);
|
||||
raylib::draw_rectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, raylib::DARKGRAY);
|
||||
offset.x += SQUARE_SIZE;
|
||||
case BLOCK:
|
||||
rl::drawRectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, rl::LIGHTGRAY);
|
||||
raylib::draw_rectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, raylib::LIGHTGRAY);
|
||||
offset.x += SQUARE_SIZE;
|
||||
case FADING:
|
||||
rl::drawRectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, fading_color);
|
||||
raylib::draw_rectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, fading_color);
|
||||
offset.x += SQUARE_SIZE;
|
||||
default:
|
||||
}
|
||||
@@ -333,13 +334,13 @@ fn void draw_game()
|
||||
switch (incoming_piece[i][j])
|
||||
{
|
||||
case EMPTY:
|
||||
rl::drawLine(offset.x, offset.y, offset.x + SQUARE_SIZE, offset.y, rl::LIGHTGRAY);
|
||||
rl::drawLine(offset.x, offset.y, offset.x, offset.y + SQUARE_SIZE, rl::LIGHTGRAY);
|
||||
rl::drawLine(offset.x + SQUARE_SIZE, offset.y, offset.x + SQUARE_SIZE, offset.y + SQUARE_SIZE, rl::LIGHTGRAY);
|
||||
rl::drawLine(offset.x, offset.y + SQUARE_SIZE, offset.x + SQUARE_SIZE, offset.y + SQUARE_SIZE, rl::LIGHTGRAY);
|
||||
raylib::draw_line(offset.x, offset.y, offset.x + SQUARE_SIZE, offset.y, raylib::LIGHTGRAY);
|
||||
raylib::draw_line(offset.x, offset.y, offset.x, offset.y + SQUARE_SIZE, raylib::LIGHTGRAY);
|
||||
raylib::draw_line(offset.x + SQUARE_SIZE, offset.y, offset.x + SQUARE_SIZE, offset.y + SQUARE_SIZE, raylib::LIGHTGRAY);
|
||||
raylib::draw_line(offset.x, offset.y + SQUARE_SIZE, offset.x + SQUARE_SIZE, offset.y + SQUARE_SIZE, raylib::LIGHTGRAY);
|
||||
offset.x += SQUARE_SIZE;
|
||||
case MOVING:
|
||||
rl::drawRectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, rl::GRAY);
|
||||
raylib::draw_rectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, raylib::GRAY);
|
||||
offset.x += SQUARE_SIZE;
|
||||
default:
|
||||
break;
|
||||
@@ -350,13 +351,14 @@ fn void draw_game()
|
||||
offset.y += SQUARE_SIZE;
|
||||
}
|
||||
|
||||
rl::drawText("INCOMING:", offset.x, offset.y - 100, 10, rl::GRAY);
|
||||
rl::drawText(rl::textFormat("LINES: %04i", lines), offset.x, offset.y + 20, 10, rl::GRAY);
|
||||
raylib::draw_text("INCOMING:", offset.x, offset.y - 100, 10, raylib::GRAY);
|
||||
raylib::draw_text(raylib::text_format("LINES: %04i", lines), offset.x, offset.y + 20, 10, raylib::GRAY);
|
||||
|
||||
if (pause)
|
||||
{
|
||||
rl::drawText("GAME PAUSED", SCREEN_WIDTH / 2 - rl::measureText("GAME PAUSED", 40)/2, SCREEN_HEIGHT/2 - 40, 40, rl::GRAY);
|
||||
raylib::draw_text("GAME PAUSED", SCREEN_WIDTH / 2 - raylib::measure_text("GAME PAUSED", 40)/2, SCREEN_HEIGHT/2 - 40, 40, raylib::GRAY);
|
||||
}
|
||||
raylib::end_drawing();
|
||||
}
|
||||
|
||||
// Unload game variables
|
||||
@@ -413,7 +415,7 @@ fn bool create_piece()
|
||||
|
||||
fn void get_random_piece()
|
||||
{
|
||||
int random = rl::getRandomValue(0, 6);
|
||||
int random = raylib::get_random_value(0, 6);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
@@ -506,7 +508,7 @@ fn bool resolve_lateral_movement()
|
||||
bool collision = false;
|
||||
|
||||
// Piece movement
|
||||
if (rl::isKeyDown(rl::KEY_LEFT)) // Move left
|
||||
if (raylib::is_key_down(keyboard::LEFT)) // Move left
|
||||
{
|
||||
// Check if is possible to move to left
|
||||
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
|
||||
@@ -540,7 +542,7 @@ fn bool resolve_lateral_movement()
|
||||
piece_position_x--;
|
||||
}
|
||||
}
|
||||
else if (rl::isKeyDown(rl::KEY_RIGHT)) // Move right
|
||||
else if (raylib::is_key_down(keyboard::RIGHT)) // Move right
|
||||
{
|
||||
// Check if is possible to move to right
|
||||
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
|
||||
@@ -585,7 +587,7 @@ fn bool resolve_lateral_movement()
|
||||
fn bool resolve_turn_movement()
|
||||
{
|
||||
// Input for turning the piece
|
||||
if (rl::isKeyDown(rl::KEY_UP))
|
||||
if (raylib::is_key_down(keyboard::UP))
|
||||
{
|
||||
GridSquare aux;
|
||||
bool checker = false;
|
||||
@@ -788,4 +790,5 @@ fn int delete_complete_lines()
|
||||
}
|
||||
}
|
||||
return lines_to_erase;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
c3yacc: grammar.y c3.l
|
||||
flex --header-file=lex.yy.h -8 c3.l
|
||||
bison -d grammar.y;
|
||||
cc -O2 -o c3yacc lex.yy.c grammar.tab.c
|
||||
bison -d grammar.y; cc -c grammar.tab.c
|
||||
flex c3.l; gcc -c lex.yy.c
|
||||
cc -o c3yacc lex.yy.o grammar.tab.o
|
||||
|
||||
clean:
|
||||
rm -f c3yacc grammar.output *.o grammar.tab.* lex.yy.*
|
||||
rm -f c3yacc grammar.output *.o grammar.tab.* lex.yy.c
|
||||
@@ -1,7 +1,4 @@
|
||||
%option yylineno
|
||||
%option bison-locations
|
||||
%option reentrant
|
||||
%option bison-bridge
|
||||
|
||||
D [0-9]
|
||||
DU [0-9_]
|
||||
@@ -34,250 +31,251 @@ BINT {B}(_?{B})*
|
||||
%{
|
||||
#include <stdio.h>
|
||||
#include "grammar.tab.h"
|
||||
void count(void);
|
||||
int comment_level = 0;
|
||||
|
||||
typedef struct {
|
||||
int comment_level;
|
||||
} YY_Extra_Type;
|
||||
|
||||
#define YY_EXTRA_TYPE YY_Extra_Type
|
||||
|
||||
#define YY_USER_ACTION \
|
||||
yylloc->first_line = yylloc->last_line; \
|
||||
yylloc->first_column = yylloc->last_column; \
|
||||
for(int i = 0; yytext[i] != '\0'; i++) { \
|
||||
if(yytext[i] == '\n') { \
|
||||
yylloc->last_line++; \
|
||||
yylloc->last_column = 0; \
|
||||
} \
|
||||
else { \
|
||||
yylloc->last_column++; \
|
||||
} \
|
||||
}
|
||||
%}
|
||||
|
||||
%%
|
||||
|
||||
|
||||
"$alignof" { return(CT_ALIGNOF); }
|
||||
"$assert" { return(CT_ASSERT); }
|
||||
"$assignable" { return(CT_ASSIGNABLE); }
|
||||
"$case" { return(CT_CASE); }
|
||||
"$default" { return(CT_DEFAULT); }
|
||||
"$defined" { return(CT_DEFINED); }
|
||||
"$echo" { return(CT_ECHO); }
|
||||
"$else" { return(CT_ELSE); }
|
||||
"$endfor" { return(CT_ENDFOR); }
|
||||
"$endforeach" { return(CT_ENDFOREACH); }
|
||||
"$endif" { return(CT_ENDIF); }
|
||||
"$endswitch" { return(CT_ENDSWITCH); }
|
||||
"$error" { return(CT_ERROR); }
|
||||
"$eval" { return(CT_EVAL); }
|
||||
"$evaltype" { return(CT_EVALTYPE); }
|
||||
"$exec" { return(CT_EXEC); }
|
||||
"$extnameof" { return(CT_EXTNAMEOF); }
|
||||
"$feature" { return(CT_FEATURE); }
|
||||
"$for" { return(CT_FOR); }
|
||||
"$foreach" { return(CT_FOREACH); }
|
||||
"$if" { return(CT_IF); }
|
||||
"$is_const" { return(CT_IS_CONST); }
|
||||
"$include" { return(CT_INCLUDE); }
|
||||
"$nameof" { return(CT_NAMEOF); }
|
||||
"$offsetof" { return(CT_OFFSETOF); }
|
||||
"$qnameof" { return(CT_QNAMEOF); }
|
||||
"$sizeof" { return(CT_SIZEOF); }
|
||||
"$stringify" { return(CT_STRINGIFY); }
|
||||
"$switch" { return(CT_SWITCH); }
|
||||
"$typefrom" { return(CT_TYPEFROM); }
|
||||
"$typeof" { return(CT_TYPEOF); }
|
||||
"$vaarg" { return(CT_VAARG); }
|
||||
"$vaconst" { return(CT_VACONST); }
|
||||
"$vacount" { return(CT_VACOUNT); }
|
||||
"$vaexpr" { return(CT_VAEXPR); }
|
||||
"$varef" { return(CT_VAREF); }
|
||||
"$vasplat" { return(CT_VASPLAT); }
|
||||
"$vatype" { return(CT_VATYPE); }
|
||||
"/*" { BEGIN(COMMENT); }
|
||||
"$alignof" { count(); return(CT_ALIGNOF); }
|
||||
"$assert" { count(); return(CT_ASSERT); }
|
||||
"$assignable" { count(); return(CT_ASSIGNABLE); }
|
||||
"$case" { count(); return(CT_CASE); }
|
||||
"$default" { count(); return(CT_DEFAULT); }
|
||||
"$defined" { count(); return(CT_DEFINED); }
|
||||
"$echo" { count(); return(CT_ECHO); }
|
||||
"$else" { count(); return(CT_ELSE); }
|
||||
"$endfor" { count(); return(CT_ENDFOR); }
|
||||
"$endforeach" { count(); return(CT_ENDFOREACH); }
|
||||
"$endif" { count(); return(CT_ENDIF); }
|
||||
"$endswitch" { count(); return(CT_ENDSWITCH); }
|
||||
"$error" { count(); return(CT_ERROR); }
|
||||
"$eval" { count(); return(CT_EVAL); }
|
||||
"$evaltype" { count(); return(CT_EVALTYPE); }
|
||||
"$exec" { count(); return(CT_EXEC); }
|
||||
"$extnameof" { count(); return(CT_EXTNAMEOF); }
|
||||
"$feature" { count(); return(CT_FEATURE); }
|
||||
"$for" { count(); return(CT_FOR); }
|
||||
"$foreach" { count(); return(CT_FOREACH); }
|
||||
"$if" { count(); return(CT_IF); }
|
||||
"$is_const" { count(); return(CT_IS_CONST); }
|
||||
"$include" { count(); return(CT_INCLUDE); }
|
||||
"$nameof" { count(); return(CT_NAMEOF); }
|
||||
"$offsetof" { count(); return(CT_OFFSETOF); }
|
||||
"$qnameof" { count(); return(CT_QNAMEOF); }
|
||||
"$sizeof" { count(); return(CT_SIZEOF); }
|
||||
"$stringify" { count(); return(CT_STRINGIFY); }
|
||||
"$switch" { count(); return(CT_SWITCH); }
|
||||
"$typefrom" { count(); return(CT_TYPEFROM); }
|
||||
"$typeof" { count(); return(CT_TYPEOF); }
|
||||
"$vaarg" { count(); return(CT_VAARG); }
|
||||
"$vaconst" { count(); return(CT_VACONST); }
|
||||
"$vacount" { count(); return(CT_VACOUNT); }
|
||||
"$vaexpr" { count(); return(CT_VAEXPR); }
|
||||
"$varef" { count(); return(CT_VAREF); }
|
||||
"$vasplat" { count(); return(CT_VASPLAT); }
|
||||
"$vatype" { count(); return(CT_VATYPE); }
|
||||
"/*" { count(); BEGIN(COMMENT); }
|
||||
<COMMENT>{
|
||||
"/*" { yyg->yyextra_r.comment_level++; }
|
||||
"*"+"/" { if (yyg->yyextra_r.comment_level) { yyg->yyextra_r.comment_level--; } else { BEGIN(INITIAL); } }
|
||||
"*"+ { }
|
||||
[^/*\n]+ { }
|
||||
[/] { }
|
||||
\n { }
|
||||
"/*" { count(); comment_level++; }
|
||||
"*"+"/" { count(); if (comment_level) { comment_level--; } else { BEGIN(INITIAL); } }
|
||||
"*"+ { count(); }
|
||||
[^/*\n]+ { count(); }
|
||||
[/] { count(); }
|
||||
\n { count(); }
|
||||
}
|
||||
\/\/.* { }
|
||||
"any" { return(ANY); }
|
||||
"anyfault" { return(ANYFAULT); }
|
||||
"asm" { return(ASM); }
|
||||
"assert" { return(ASSERT); }
|
||||
"bitstruct" { return(BITSTRUCT); }
|
||||
"bool" { return(BOOL); }
|
||||
"break" { return(BREAK); }
|
||||
"case" { return(CASE); }
|
||||
"catch" { return(CATCH); }
|
||||
"char" { return(CHAR); }
|
||||
"const" { return(CONST); }
|
||||
"continue" { return(CONTINUE); }
|
||||
"def" { return(DEF); }
|
||||
"default" { return(DEFAULT); }
|
||||
"defer" { return(DEFER); }
|
||||
"distinct" { return(DISTINCT); }
|
||||
"do" { return(DO); }
|
||||
"double" { return(DOUBLE); }
|
||||
"else" { return(ELSE); }
|
||||
"enum" { return(ENUM); }
|
||||
"extern" { return(EXTERN); }
|
||||
"false" { return(FALSE); }
|
||||
"fault" { return(FAULT); }
|
||||
"float" { return(FLOAT); }
|
||||
"bfloat16" { return(BFLOAT16); }
|
||||
"float16" { return(FLOAT16); }
|
||||
"float128" { return(FLOAT128); }
|
||||
"fn" { return(FN); }
|
||||
"for" { return(FOR); }
|
||||
"foreach" { return(FOREACH); }
|
||||
"foreach_r" { return(FOREACH_R); }
|
||||
"ichar" { return(ICHAR); }
|
||||
"if" { return(IF); }
|
||||
"import" { return(IMPORT); }
|
||||
"inline" { return(INLINE); }
|
||||
"int" { return(INT); }
|
||||
"int128" { return(INT128); }
|
||||
"interface" { return(INTERFACE); }
|
||||
"iptr" { return(IPTR); }
|
||||
"isz" { return(ISZ); }
|
||||
"long" { return(LONG); }
|
||||
"macro" { return(MACRO); }
|
||||
"module" { return(MODULE); }
|
||||
"nextcase" { return(NEXTCASE); }
|
||||
"null" { return(NUL); }
|
||||
"return" { return(RETURN); }
|
||||
"short" { return(SHORT); }
|
||||
"struct" { return(STRUCT); }
|
||||
"static" { return(STATIC); }
|
||||
"switch" { return(SWITCH); }
|
||||
"tlocal" { return(TLOCAL); }
|
||||
"true" { return(TRUE); }
|
||||
"try" { return(TRY); }
|
||||
"typeid" { return(TYPEID); }
|
||||
"uint" { return(UINT); }
|
||||
"uint128" { return(UINT128); }
|
||||
"ulong" { return(ULONG); }
|
||||
"union" { return(UNION); }
|
||||
"uptr" { return(UPTR); }
|
||||
"ushort" { return(USHORT); }
|
||||
"usz" { return(USZ); }
|
||||
"var" { return(VAR); }
|
||||
"void" { return(VOID); }
|
||||
"while" { return(WHILE); }
|
||||
\/\/.* { count(); }
|
||||
"any" { count(); return(ANY); }
|
||||
"anyfault" { count(); return(ANYFAULT); }
|
||||
"asm" { count(); return(ASM); }
|
||||
"assert" { count(); return(ASSERT); }
|
||||
"bitstruct" { count(); return(BITSTRUCT); }
|
||||
"bool" { count(); return(BOOL); }
|
||||
"break" { count(); return(BREAK); }
|
||||
"case" { count(); return(CASE); }
|
||||
"catch" { count(); return(CATCH); }
|
||||
"char" { count(); return(CHAR); }
|
||||
"const" { count(); return(CONST); }
|
||||
"continue" { count(); return(CONTINUE); }
|
||||
"def" { count(); return(DEF); }
|
||||
"default" { count(); return(DEFAULT); }
|
||||
"defer" { count(); return(DEFER); }
|
||||
"distinct" { count(); return(DISTINCT); }
|
||||
"do" { count(); return(DO); }
|
||||
"double" { count(); return(DOUBLE); }
|
||||
"else" { count(); return(ELSE); }
|
||||
"enum" { count(); return(ENUM); }
|
||||
"extern" { count(); return(EXTERN); }
|
||||
"false" { count(); return(FALSE); }
|
||||
"fault" { count(); return(FAULT); }
|
||||
"float" { count(); return(FLOAT); }
|
||||
"bfloat16" { count(); return(BFLOAT16); }
|
||||
"float16" { count(); return(FLOAT16); }
|
||||
"float128" { count(); return(FLOAT128); }
|
||||
"fn" { count(); return(FN); }
|
||||
"for" { count(); return(FOR); }
|
||||
"foreach" { count(); return(FOREACH); }
|
||||
"foreach_r" { count(); return(FOREACH_R); }
|
||||
"ichar" { count(); return(ICHAR); }
|
||||
"if" { count(); return(IF); }
|
||||
"import" { count(); return(IMPORT); }
|
||||
"inline" { count(); return(INLINE); }
|
||||
"int" { count(); return(INT); }
|
||||
"int128" { count(); return(INT128); }
|
||||
"interface" { count(); return(INTERFACE); }
|
||||
"iptr" { count(); return(IPTR); }
|
||||
"isz" { count(); return(ISZ); }
|
||||
"long" { count(); return(LONG); }
|
||||
"macro" { count(); return(MACRO); }
|
||||
"module" { count(); return(MODULE); }
|
||||
"nextcase" { count(); return(NEXTCASE); }
|
||||
"null" { count(); return(NUL); }
|
||||
"return" { count(); return(RETURN); }
|
||||
"short" { count(); return(SHORT); }
|
||||
"struct" { count(); return(STRUCT); }
|
||||
"static" { count(); return(STATIC); }
|
||||
"switch" { count(); return(SWITCH); }
|
||||
"tlocal" { count(); return(TLOCAL); }
|
||||
"true" { count(); return(TRUE); }
|
||||
"try" { count(); return(TRY); }
|
||||
"typeid" { count(); return(TYPEID); }
|
||||
"uint" { count(); return(UINT); }
|
||||
"uint128" { count(); return(UINT128); }
|
||||
"ulong" { count(); return(ULONG); }
|
||||
"union" { count(); return(UNION); }
|
||||
"uptr" { count(); return(UPTR); }
|
||||
"ushort" { count(); return(USHORT); }
|
||||
"usz" { count(); return(USZ); }
|
||||
"var" { count(); return(VAR); }
|
||||
"void" { count(); return(VOID); }
|
||||
"while" { count(); return(WHILE); }
|
||||
|
||||
@{CONST} { return(AT_CONST_IDENT); }
|
||||
#{CONST} { return(HASH_CONST_IDENT); }
|
||||
${CONST} { return(CT_CONST_IDENT); }
|
||||
{CONST} { return(CONST_IDENT); }
|
||||
@{TYPE} { return(AT_TYPE_IDENT); }
|
||||
#{TYPE} { return(HASH_TYPE_IDENT); }
|
||||
${TYPE} { return(CT_TYPE_IDENT); }
|
||||
{TYPE} { return(TYPE_IDENT); }
|
||||
@{IDENTIFIER} { return(AT_IDENT); }
|
||||
#{IDENTIFIER} { return(HASH_IDENT); }
|
||||
${IDENTIFIER} { return(CT_IDENT); }
|
||||
{IDENTIFIER} { return(IDENT); }
|
||||
0[xX]{HINT}{INTTYPE}? { return(INTEGER); }
|
||||
0[oO]{OINT}{INTTYPE}? { return(INTEGER); }
|
||||
0[bB]{BINT}{INTTYPE}? { return(INTEGER); }
|
||||
{INT}{INTTYPE}? { return(INTEGER); }
|
||||
x\'{HEX}\' { return(BYTES); }
|
||||
x\"{HEX}\" { return(BYTES); }
|
||||
x\`{HEX}\` { return(BYTES); }
|
||||
b64\'{B64}\' { return(BYTES); }
|
||||
b64\"{B64}\" { return(BYTES); }
|
||||
b64\`{B64}\` { return(BYTES); }
|
||||
@{CONST} { count(); return(AT_CONST_IDENT); }
|
||||
#{CONST} { count(); return(HASH_CONST_IDENT); }
|
||||
${CONST} { count(); return(CT_CONST_IDENT); }
|
||||
{CONST} { count(); return(CONST_IDENT); }
|
||||
@{TYPE} { count(); return(AT_TYPE_IDENT); }
|
||||
#{TYPE} { count(); return(HASH_TYPE_IDENT); }
|
||||
${TYPE} { count(); return(CT_TYPE_IDENT); }
|
||||
{TYPE} { count(); return(TYPE_IDENT); }
|
||||
@{IDENTIFIER} { count(); return(AT_IDENT); }
|
||||
#{IDENTIFIER} { count(); return(HASH_IDENT); }
|
||||
${IDENTIFIER} { count(); return(CT_IDENT); }
|
||||
{IDENTIFIER} { count(); return(IDENT); }
|
||||
0[xX]{HINT}{INTTYPE}? { count(); return(INTEGER); }
|
||||
0[oO]{OINT}{INTTYPE}? { count(); return(INTEGER); }
|
||||
0[bB]{BINT}{INTTYPE}? { count(); return(INTEGER); }
|
||||
{INT}{INTTYPE}? { count(); return(INTEGER); }
|
||||
x\'{HEX}\' { count(); return(BYTES); }
|
||||
x\"{HEX}\" { count(); return(BYTES); }
|
||||
x\`{HEX}\` { count(); return(BYTES); }
|
||||
b64\'{B64}\' { count(); return(BYTES); }
|
||||
b64\"{B64}\" { count(); return(BYTES); }
|
||||
b64\`{B64}\` { count(); return(BYTES); }
|
||||
|
||||
{INT}{REALTYPE} { return(REAL); }
|
||||
{INT}{E}{REALTYPE}? { return(REAL); }
|
||||
0[xX]{HINT}{P}{REALTYPE}? { return(REAL); }
|
||||
{INT}"."{INT}{E}?{REALTYPE}? { return(REAL); }
|
||||
0[xX]{HINT}"."{HINT}{P}{REALTYPE}? { return(REAL); }
|
||||
{INT}{REALTYPE} { count(); return(REAL); }
|
||||
{INT}{E}{REALTYPE}? { count(); return(REAL); }
|
||||
0[xX]{HINT}{P}{REALTYPE}? { count(); return(REAL); }
|
||||
{INT}"."{INT}{E}?{REALTYPE}? { count(); return(REAL); }
|
||||
0[xX]{HINT}"."{HINT}{P}{REALTYPE}? { count(); return(REAL); }
|
||||
|
||||
\"(\\.|[^\\"])*\" { return(STRING_LITERAL); }
|
||||
\'(\\[ux]{HEX}|\\.|[^\\']+)\' { return(CHAR_LITERAL); }
|
||||
\"(\\.|[^\\"])*\" { count(); return(STRING_LITERAL); }
|
||||
\'(\\[ux]{HEX}|\\.|[^\\'])\' { count(); return(CHAR_LITERAL); }
|
||||
|
||||
"`" { BEGIN(RAW_STRING); }
|
||||
"`" { count(); BEGIN(RAW_STRING); }
|
||||
<RAW_STRING>{
|
||||
"``" { }
|
||||
"`" { BEGIN(INITIAL); return(STRING_LITERAL); }
|
||||
"[^`]"+ { }
|
||||
"``" { count(); }
|
||||
"`" { count(); BEGIN(INITIAL); return(STRING_LITERAL); }
|
||||
"[^`]"+ { count(); }
|
||||
<<EOF>> { BEGIN(INITIAL); return(RAW_STRING); }
|
||||
}
|
||||
|
||||
"!!" { return(BANGBANG); }
|
||||
"..." { return(ELLIPSIS); }
|
||||
".." { return(DOTDOT); }
|
||||
"&&&" { return(CT_AND_OP); }
|
||||
"|||" { return(CT_OR_OP); }
|
||||
"+++" { return(CT_CONCAT_OP); }
|
||||
">>=" { return(SHR_ASSIGN); }
|
||||
"<<=" { return(SHL_ASSIGN); }
|
||||
"+=" { return(ADD_ASSIGN); }
|
||||
"-=" { return(SUB_ASSIGN); }
|
||||
"*=" { return(MUL_ASSIGN); }
|
||||
"/=" { return(DIV_ASSIGN); }
|
||||
"%=" { return(MOD_ASSIGN); }
|
||||
"&=" { return(AND_ASSIGN); }
|
||||
"^=" { return(XOR_ASSIGN); }
|
||||
"|=" { return(OR_ASSIGN); }
|
||||
">>" { return(SHR_OP); }
|
||||
"<<" { return(SHL_OP); }
|
||||
"++" { return(INC_OP); }
|
||||
"--" { return(DEC_OP); }
|
||||
"&&" { return(AND_OP); }
|
||||
"||" { return(OR_OP); }
|
||||
"<=" { return(LE_OP); }
|
||||
">=" { return(GE_OP); }
|
||||
"==" { return(EQ_OP); }
|
||||
"!=" { return(NE_OP); }
|
||||
"??" { return(OPTELSE); }
|
||||
"::" { return(SCOPE); }
|
||||
"?:" { return(ELVIS); }
|
||||
"=>" { return(IMPLIES); }
|
||||
"[<" { return(LVEC); }
|
||||
">]" { return(RVEC); }
|
||||
"(<" { return(LGENPAR); }
|
||||
">)" { return(RGENPAR); }
|
||||
"$$" { return(BUILTIN); }
|
||||
";" { return(';'); }
|
||||
("{") { return('{'); }
|
||||
("}") { return('}'); }
|
||||
"," { return(','); }
|
||||
":" { return(':'); }
|
||||
"=" { return('='); }
|
||||
"(" { return('('); }
|
||||
")" { return(')'); }
|
||||
("[") { return('['); }
|
||||
("]") { return(']'); }
|
||||
"." { return('.'); }
|
||||
"&" { return('&'); }
|
||||
"!" { return('!'); }
|
||||
"~" { return('~'); }
|
||||
"-" { return('-'); }
|
||||
"+" { return('+'); }
|
||||
"*" { return('*'); }
|
||||
"/" { return('/'); }
|
||||
"%" { return('%'); }
|
||||
"<" { return('<'); }
|
||||
">" { return('>'); }
|
||||
"^" { return('^'); }
|
||||
"|" { return('|'); }
|
||||
"?" { return('?'); }
|
||||
"{|" { return(LBRAPIPE); }
|
||||
"|}" { return(RBRAPIPE); }
|
||||
[ \t\v\n\f] { }
|
||||
"!!" { count(); return(BANGBANG); }
|
||||
"..." { count(); return(ELLIPSIS); }
|
||||
".." { count(); return(DOTDOT); }
|
||||
"&&&" { count(); return(CT_AND_OP); }
|
||||
"|||" { count(); return(CT_OR_OP); }
|
||||
"+++" { count(); return(CT_CONCAT_OP); }
|
||||
">>=" { count(); return(SHR_ASSIGN); }
|
||||
"<<=" { count(); return(SHL_ASSIGN); }
|
||||
"+=" { count(); return(ADD_ASSIGN); }
|
||||
"-=" { count(); return(SUB_ASSIGN); }
|
||||
"*=" { count(); return(MUL_ASSIGN); }
|
||||
"/=" { count(); return(DIV_ASSIGN); }
|
||||
"%=" { count(); return(MOD_ASSIGN); }
|
||||
"&=" { count(); return(AND_ASSIGN); }
|
||||
"^=" { count(); return(XOR_ASSIGN); }
|
||||
"|=" { count(); return(OR_ASSIGN); }
|
||||
">>" { count(); return(SHR_OP); }
|
||||
"<<" { count(); return(SHL_OP); }
|
||||
"++" { count(); return(INC_OP); }
|
||||
"--" { count(); return(DEC_OP); }
|
||||
"&&" { count(); return(AND_OP); }
|
||||
"||" { count(); return(OR_OP); }
|
||||
"<=" { count(); return(LE_OP); }
|
||||
">=" { count(); return(GE_OP); }
|
||||
"==" { count(); return(EQ_OP); }
|
||||
"!=" { count(); return(NE_OP); }
|
||||
"??" { count(); return(OPTELSE); }
|
||||
"::" { count(); return(SCOPE); }
|
||||
"?:" { count(); return(ELVIS); }
|
||||
"=>" { count(); return(IMPLIES); }
|
||||
"[<" { count(); return(LVEC); }
|
||||
">]" { count(); return(RVEC); }
|
||||
"(<" { count(); return(LGENPAR); }
|
||||
">)" { count(); return(RGENPAR); }
|
||||
"$$" { count(); return(BUILTIN); }
|
||||
";" { count(); return(';'); }
|
||||
("{") { count(); return('{'); }
|
||||
("}") { count(); return('}'); }
|
||||
"," { count(); return(','); }
|
||||
":" { count(); return(':'); }
|
||||
"=" { count(); return('='); }
|
||||
"(" { count(); return('('); }
|
||||
")" { count(); return(')'); }
|
||||
("[") { count(); return('['); }
|
||||
("]") { count(); return(']'); }
|
||||
"." { count(); return('.'); }
|
||||
"&" { count(); return('&'); }
|
||||
"!" { count(); return('!'); }
|
||||
"~" { count(); return('~'); }
|
||||
"-" { count(); return('-'); }
|
||||
"+" { count(); return('+'); }
|
||||
"*" { count(); return('*'); }
|
||||
"/" { count(); return('/'); }
|
||||
"%" { count(); return('%'); }
|
||||
"<" { count(); return('<'); }
|
||||
">" { count(); return('>'); }
|
||||
"^" { count(); return('^'); }
|
||||
"|" { count(); return('|'); }
|
||||
"?" { count(); return('?'); }
|
||||
"{|" { count(); return(LBRAPIPE); }
|
||||
"|}" { count(); return(RBRAPIPE); }
|
||||
[ \t\v\n\f] { count(); }
|
||||
. { /* ignore bad characters */ }
|
||||
|
||||
%%
|
||||
|
||||
int yywrap(yyscan_t yyscanner)
|
||||
int yywrap(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int column = 0;
|
||||
|
||||
void count(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; yytext[i] != '\0'; i++)
|
||||
if (yytext[i] == '\n')
|
||||
column = 0;
|
||||
else if (yytext[i] == '\t')
|
||||
column += 8 - (column % 8);
|
||||
else
|
||||
column++;
|
||||
|
||||
ECHO;
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
for fn in `find ../../../c3c -name '*.c3' | sort`
|
||||
do
|
||||
echo -n $fn
|
||||
cat $fn | ./c3yacc
|
||||
done
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user