Compare commits

..

118 Commits

Author SHA1 Message Date
Christoffer Lerno
5961bcaf86 Update current version. 2025-12-04 15:45:14 +01:00
Christoffer Lerno
fd5489458a Additional fix and updated error message. 2025-12-03 22:25:38 +01:00
Christoffer Lerno
cf5dd5496a @param name parsing too lenient #2614. 2025-12-03 21:54:06 +01:00
DylanDoesProgramming
ccffa03de2 musl-based linux distro support (#2577)
* added switch statement to link musl-based linux distros to ld-musl-x86-64.so.2

* Update linker.c

/lib/ld-musl-x86-64.so.1 is musl's ld so. My bad

* don't need ENV_MUSLEABI.* in the switch for x86_64

* typo

* Added a CI test for an Alpine Linux container

* Update main.yml

Forgot to have bundle_output job use `env.LLVM_RELEASE_VERSION_ALPINEv3_22`.

* Added env.LLVM_RELEASE_VERSION_ALPINEv3_22 to `upload artifacts`

* changed bundle name to c3-musl-${{matrix,build_type}}.tar.gz

* Undid an accidental name change in build-linux-ubuntu22

* Update main.yml

sudo doesn't exist in alpine by default, and runs in root by default.

* Update main.yml

* Update main.yml

* Update main.yml

* Update main.yml

`--linker=builtin` fails because it forces search of `/lib64/ld-linux-x86-64.so.2`. lib64 doesn't exist on musl unless created as a symlink, and the appropriate so is /lib/ld-musl-<arch>.so.1

* Update main.yml

* Update main.yml

* Update main.yml

* Update main.yml

make isn't in alpine by default. added it in for risc-v example.

* gcc-riscv-none-elf is alpine's package

* using realpath for c3c over using relative pathing

* Have to use relative path for arguments in compiler test

* added --linker=builtin to

* Added linux-musl-<arch> targets

* Added more ld targets for glibc

* set both testproject libs as folders until they behave better

* added linux-musl-x64 target to clib2

* added riscv targets for ld-linux

* ubuntu doesn't have ld in /lib, but solely in /lib64?

* Make MUSL distinct from the target.

* Fix default in project schema

* Fix define

* Fix manifests.

* Update main.yml

add --linux-libc flag for builtin linking

* Grammar refresh

* Update releasenotes.

---------

Co-authored-by: Christoffer Lerno <christoffer@aegik.com>
2025-12-03 00:42:36 +01:00
Christoffer Lerno
ce0ab62c78 Grammar refresh 2025-12-03 00:36:10 +01:00
Christoffer Lerno
0bc5cbca74 More raylib examples. 2025-12-01 22:33:01 +01:00
Christoffer Lerno
a2aa9fae6b - Reference macro parameters syntax does not error in certain cases. #2612 2025-11-30 02:23:00 +01:00
Christoffer Lerno
9d79c3f33d - $defined(hashmap.init(mem)) causes compiler segfault #2611. 2025-11-30 00:08:46 +01:00
Christoffer Lerno
a26055c932 Added more raylib examples. 2025-11-29 22:40:58 +01:00
Christoffer Lerno
b296875c05 Fix BigInt 2025-11-28 23:20:45 +01:00
Glenn Kirk
a54658d37f Add a missing enum value for NSEventModifierFlags 2025-11-28 17:05:57 +01:00
Christoffer Lerno
0a0e097bdf Improve printf("%d") speed. 2025-11-28 17:04:10 +01:00
Dmitry Atamanov
2df51bfe07 Remove unused tester.py 2025-11-28 16:09:06 +01:00
Dmitry Atamanov
cb065152ea Fix typo in @char16 macro 2025-11-28 16:08:38 +01:00
Dmitry Atamanov
07fa14f00b Change sema_decls.c mode to 0664 (rw-rw-r--) 2025-11-28 16:06:58 +01:00
Glenn Kirk
ff1b17d18b Fix the precompiled binary download links on the Github readme page 2025-11-28 16:04:41 +01:00
Christoffer Lerno
c3d5778ae0 Cache printf output. 2025-11-28 12:43:26 +01:00
Christoffer Lerno
373ad1a399 Added raylib example 2025-11-27 23:39:38 +01:00
Christoffer Lerno
6deed2d4a4 Update raylib in CI 2025-11-27 22:58:04 +01:00
Christoffer Lerno
6324d78c32 Added raylib example. 2025-11-27 21:53:32 +01:00
Christoffer Lerno
9e14338b77 Update raylib examples. 2025-11-27 20:42:35 +01:00
Christoffer Lerno
6e4614b6a4 - Fix bug when converting from vector to distinct type of wider vector. #2604 2025-11-27 16:40:55 +01:00
Christoffer Lerno
0b52819090 - Bug on rethrow in return with defer #2603. 2025-11-27 12:53:12 +01:00
Christoffer Lerno
404a78943d - Somewhat faster BigInt output. 2025-11-27 12:15:40 +01:00
Christoffer Lerno
7215a9fa12 Unexpected maybe-deref subscript error with out parameter #2600. 2025-11-27 00:21:59 +01:00
Christoffer Lerno
463c6957fc - Support int $foo... arguments. #2601 2025-11-26 23:54:18 +01:00
Christoffer Lerno
8ec3a52ef7 - Add float[<3>] x = { .xy = 1.2, .z = 3.3 } swizzle initialization for vectors. #2599 2025-11-26 11:31:22 +01:00
Glenn
ab1efdda73 Add NSApplicationTerminateReply and registerClassPair to objc stdlib
The missing registerClassPair function is required to register a class and make it active with objc after allocating with the existing allocateClassPair function.
2025-11-26 08:44:46 +01:00
Christoffer Lerno
4f3b6f922d - Resolving a missing property on a const enum with inline, reached an assert #2597. 2025-11-25 23:48:40 +01:00
Book-reader
869a1d93cb Disable Xtensa target by default, enabled with -DXTENSA_ENABLE (#2586)
Co-authored-by: Christoffer Lerno <christoffer@aegik.com>
2025-11-24 23:50:52 +01:00
Christoffer Lerno
5d468ccbf0 - Make printing typeids give some helpful typeid data. 2025-11-24 17:11:19 +01:00
Christoffer Lerno
887ed5b9e9 - String.to_integer does not correctly return in some cases where it should #2590. 2025-11-24 12:46:31 +01:00
Christoffer Lerno
5c1a6d7623 - Incorrect error message when using generic type that isn't imported #2589 2025-11-24 12:27:09 +01:00
Christoffer Lerno
1b49ebf855 - Deprecate --test-nocapture in favour of --test-show-output #2588. 2025-11-24 11:46:06 +01:00
Christoffer Lerno
98155b61f1 - Name property would be used even under c3c test #2587. 2025-11-22 18:02:00 +01:00
m0tholith
60cdea5292 Add test option --test-log-level to choose tests' log level (#2560)
* Add test option `--test-log-level` to choose tests' log level
* draft: Improvements to `--test-log-level`
* Some fixes.

---------

Co-authored-by: Christoffer Lerno <christoffer@aegik.com>
2025-11-20 23:15:14 +01:00
Glenn Kirk
49e836b1ab [stdlib] macOS - Add objc and core foundation types and enums. (#2572)
* Add CGFloat, CGPoint, CGSize, CGRect
* Add WindowCollectionBehavior, WindowLevel, and WindowTabbingMode
* Change EventMask to ulong to match the objc unsigned long long
* Change int types to NS(U)Integer types to match objc
* Add core foundation tests
* Add objc tests
* Add darwin conditional to the test files
* Change enums to const inline to better match the NSEvent.h api.
Update the EventMask helper function to match the NSEvent.h api:
event_type_from -> event_mask_from_type.
* Update the release notes
* Deprecate original objc enums and replace with const inline enums backed with NS numerical types.
Rename the new objc enums with an NS prefix.
Update unit tests to account for new NS prefixed enums.
Add states item length constants to core_foundation.
Status item lengths don't really belong in either file, but as they are
dependant on CGFloat it made sense to move them to the same module.
Update release notes.
* Some tweaks

---------

Co-authored-by: Christoffer Lerno <christoffer@aegik.com>
2025-11-20 22:47:20 +01:00
Christoffer Lerno
5b83108dd1 - Add sigsegv stacktrace in test and regular errors for Darwin Arm64. #1105 2025-11-20 21:05:19 +01:00
Christoffer Lerno
a50de26c5d - With project.json, when overriding with an empty list the base settings would still be used. #2583 2025-11-20 14:52:02 +01:00
Christoffer Lerno
7b50c87858 - Fix issue when tests encounter a segmentation fault or similar. 2025-11-20 12:52:25 +01:00
Christoffer Lerno
a816a78e98 Fix alignment. 2025-11-20 12:09:38 +01:00
Christoffer Lerno
39694e65c0 - *(int*)1 incorrectly yielded an assert in LLVM IR lowering #2584. 2025-11-20 10:36:32 +01:00
Christoffer Lerno
2a41fa6281 Passing a single value to @wasm would ignore the renaming 2025-11-18 18:25:07 +01:00
Christoffer Lerno
49b8cfe267 - Allow splatting of structs. #2555 2025-11-17 16:33:22 +01:00
Christoffer Lerno
20dfdf5c5d Fix test breaking for MSVC 2025-11-17 10:46:01 +01:00
Christoffer Lerno
1e543dc286 - Support @param directives for ... parameters. #2578 2025-11-17 10:44:04 +01:00
Christoffer Lerno
06884720e5 - Improve error message for Foo{} when Foo is not a generic type #2574. 2025-11-16 23:54:19 +01:00
Christoffer Lerno
1ea181524e - Fix decl attribute in the wrong place causing an assertion. #2581 2025-11-16 22:57:37 +01:00
Christoffer Lerno
b16ee3119d - Using defer catch with a (void), would cause an assertion. #2580
- Fix testcase
2025-11-16 22:07:04 +01:00
Christoffer Lerno
4e66693065 - Refactored @simd implementation.
- Regression vector ABI: npot vectors would load incorrectly from pointers and other things. #2576
2025-11-16 01:37:39 +01:00
Christoffer Lerno
5f96b8e4c6 - Casting a distinct type based on a pointer to an any would accidentally be permitted. #2575 2025-11-13 15:54:29 +01:00
Christoffer Lerno
748a2f6530 - Enums now work with membersof to return the associated values. #2571
- Deprecated `SomeEnum.associated` in favour of `SomeEnum.membersof`
2025-11-13 13:15:02 +01:00
Christoffer Lerno
6360ddbc77 - When encountering a foreach over a ZString* it would not properly emit a compilation error, but hit an assert #2573. 2025-11-11 12:36:02 +01:00
Christoffer Lerno
eccc6700dc - Fix appending to c:\ or \ #2569. 2025-11-09 21:45:19 +01:00
Christoffer Lerno
52ececba37 - Fix to Path handling c:\foo and \home parent. #2569 2025-11-08 23:42:47 +01:00
Christoffer Lerno
ffc65bcbf4 - Compiler assert with const enum based on vector #2566 2025-11-08 22:30:18 +01:00
Christoffer Lerno
0da6bf4455 - Passing a compile time type implicitly converted to a typeid would crash instead of producing an error. #2568 2025-11-08 22:17:58 +01:00
m0tholith
7063e684ba Make expected error in test::@error macro optional
If not supplied with a fault, `test::@error` checks if a fault of any
type/value was returned
2025-11-07 11:46:37 +01:00
Christoffer Lerno
07363c6ecd - Error message with hashmap shows "mangled" name instead of original #2562. 2025-11-04 23:19:57 +01:00
Christoffer Lerno
5070840da9 - Regression vector ABI: initializing a struct containing a NPOT vector with a constant value would crash LLVM. #2559 2025-11-04 01:04:07 +01:00
Christoffer Lerno
4a25bcc5ee Function referencing in @return? for simplified fault declarations. Check @return? eagerly #2340. 2025-11-03 23:49:35 +01:00
Christoffer Lerno
d43d7100af Fix division-by-zero checks on a /= 0 and b /= 0f #2558. 2025-11-03 21:31:47 +01:00
Christoffer Lerno
791cbbfb62 Fix division-by-zero checks on a /= 0 and b /= 0f #2558. 2025-11-03 16:47:57 +01:00
Christoffer Lerno
9b05dfdef1 Update release notes. 2025-11-03 15:13:58 +01:00
Dave Akers
b072e88bb3 Add $schema to project_default_keys
Adding $schema to avoid compiler WARNING about an unknown parameter.
2025-11-03 15:13:18 +01:00
Christoffer Lerno
af33d2b1cc Update release notes. 2025-11-03 13:58:52 +01:00
Technical Fowl
d438d7510e Add default exception handler for win32 (#2557)
* Add default exception handler for win32
2025-11-03 13:58:07 +01:00
Christoffer Lerno
1673aef74f Fix test. 2025-11-03 12:55:00 +01:00
Christoffer Lerno
b3bce10699 Remove division-by-zero checks for floating point in safe mode #2556. 2025-11-03 02:43:01 +01:00
Christoffer Lerno
3ff922e12b - Missing imports allowed if module @if evaluates to false #2251. 2025-11-02 13:20:36 +01:00
Christoffer Lerno
3b718335ec - Improve multiline string parser inside compiler #2552 2025-11-01 00:12:32 +01:00
Christoffer Lerno
f25ad512a7 Foo.is_eq would return false if the type was a typedef and had an overload, but the underlying type was not comparable. Version 0.7.8. 2025-10-31 22:47:01 +01:00
Christoffer Lerno
5a3c484ceb Remove automatic win32 cleanup. RC2 2025-10-30 21:29:48 +01:00
Christoffer Lerno
331a77c1c2 Update 0.7.7 2025-10-30 11:01:01 +01:00
Christoffer Lerno
045053f6bf Fix for RISCV on LLVM 17 2025-10-28 18:22:32 +01:00
Christoffer Lerno
4809979898 - Add --riscv-cpu settings for RISC-V processors #2549. 2025-10-27 18:33:54 +01:00
Christoffer Lerno
a5b2636b2e Added cpu-flags to the command line help 2025-10-27 14:11:50 +01:00
Christoffer Lerno
c483c3b75f Update naming to cpu-flags 2025-10-27 14:08:21 +01:00
Christopher Coverdale
c10d449e43 Add local TcpSocketPair (#2526)
* Add extern fn socketpair() to posix
* Add extern fn getsockname() for local socketpair loopback in windows
* Add local TcpSocketPair
* Add unit test for TcpSocketPair
* Add implicit wsa startup

---------

Co-authored-by: Christoffer Lerno <christoffer@aegik.com>
2025-10-27 13:16:14 +01:00
Christoffer Lerno
54b110a367 Dev (#2547)
* Update feature handling for Wasm, RiscV, Aarch64, Arm
* - The option `--riscvfloat` renamed `--riscv-abi`.
- Add initial `--cpu-features` allowing fine grained control over CPU features.
2025-10-27 01:09:59 +01:00
Dmitry Atamanov
ee8dc3d681 Update Linux nolibc/hello_world (#2546) 2025-10-27 00:45:16 +01:00
Christoffer Lerno
a38a627a1d Allow (Foo)0 bitstruct casts even if type sizes do not match. 2025-10-25 20:33:47 +02:00
Christoffer Lerno
8aaf54e8b1 - Rename @extern to @cname, deprecating the old name #2493. 2025-10-25 15:55:25 +02:00
Christoffer Lerno
423152202f Dev (#2545)
* Optimize vector load / store. Fixes to alignment. Support typedef with `@simd` and `@align` #2543. Update vector ABI #2542
* Fix alignment issue with indirect arguments.
2025-10-25 12:31:06 +02:00
Christoffer Lerno
f37e7460aa Update OpenBSD llvm version. 2025-10-23 13:58:10 +02:00
Christoffer Lerno
8f5d5a0bb5 "Maybe-deref" subscripting foo.[i] += 1 #2540. 2025-10-23 00:42:38 +02:00
Christoffer Lerno
883052a6bb Improved generic inference in initializers #2541. 2025-10-22 23:48:32 +02:00
Christoffer Lerno
9cf271f5fb Refactoring codegen with Flat / Lowered types. Helpers for struct gep. type_get_indexed_type no longer returns the canonical type, fixes issues in #2534 2025-10-21 16:53:38 +02:00
Christoffer Lerno
5d8cad91b1 Fix lambda regression 2025-10-20 22:55:24 +02:00
Giuliano Macedo
614c6989d8 Fixed incorrect format strings when using error_exit. (#2530)
* Fixed incorrect format strings when using `error_exit`.
2025-10-20 11:24:07 +02:00
Tonis
03ad72afbb Quaternion math improvements (#2524)
* Add radians to deg function

* Quaternion math fixes

* Formatting, use splat/swizzling, divide into multiple tests.

---------

Co-authored-by: tonis2 <tanton@paysure.solutions>
Co-authored-by: Christoffer Lerno <christoffer@aegik.com>
2025-10-20 11:04:28 +02:00
Christoffer Lerno
b924ede71a Regression: Not printing backtrace when tests fail for MacOS #2536. 2025-10-20 02:50:06 +02:00
Christoffer Lerno
a81f857d8c Update to fix with splat. 2025-10-20 02:26:04 +02:00
Christoffer Lerno
6169d7acdf Correctly mention aliased type when method is not implemented #2534. 2025-10-20 00:19:51 +02:00
Christoffer Lerno
4af31da7ea Compiler segfault when getting a nonexistant member from an unnamed struct #2533. 2025-10-20 00:03:15 +02:00
Christoffer Lerno
0bd2c81757 Splatting optional compile-time macro parameter from inside lambda expression does not work #2532. 2025-10-19 23:05:50 +02:00
Book-reader
5ed1281451 fix nix hooks & patch phase 2025-10-15 22:06:10 +02:00
Christoffer Lerno
7b649314ec Fix tests. 2025-10-15 00:50:24 +02:00
Christoffer Lerno
e37343fbe3 Refactor the C ABI conversion to use frontend independent types. 2025-10-14 19:38:51 +02:00
Christoffer Lerno
7b02907830 Try to workaround tag lock. 2025-10-12 21:59:41 +02:00
Christoffer Lerno
6eee760239 Add --max-macro-iterations to set macro iteration limit. 2025-10-11 16:26:07 +02:00
Christoffer Lerno
ae33d1a206 Fix issue testing if something is global. Remove ScopeId. Adding comments to code. 2025-10-11 13:50:06 +02:00
Christoffer Lerno
3430240c2a Update readme with OpenBSD 2025-10-11 00:47:37 +02:00
Christoffer Lerno
6f11260a5c Disallow aliasing of @local symbols with a higher visibility in the alias. 2025-10-10 14:04:19 +02:00
Christoffer Lerno
df67b7dddd Allow .. ranges to use "a..a-1" in order to express zero length. 2025-10-10 00:34:30 +02:00
Christoffer Lerno
f3b7df2ab0 "build-dir" option now available for project.json, added to project. #2323 2025-10-09 23:41:58 +02:00
Christoffer Lerno
a000ae560a Add new builtins $$str_snakecase $$str_replace and $$str_pascalcase.
Added `@str_snakecase`, `@str_replace` and `@str_pascalcase` builtin compile time macros based on the `$$` builtins.
2025-10-09 22:13:59 +02:00
Christoffer Lerno
0d85caf21c Add splat defaults for designated initialization #2441.
Add ??? and +++= to list-precedence.
2025-10-09 12:45:55 +02:00
Christoffer Lerno
e34a26422f Change macro recursion depth to work on MSVC 2025-10-07 23:47:05 +02:00
Christoffer Lerno
fe70f10bcc Sorting functions correctly took slices by value, but also other types by value. Now, only slices are accepted by value, other containers are always by ref. 2025-10-07 22:43:40 +02:00
Christoffer Lerno
d6be1cbf65 Incorrect visibility on local globals with public aliases. #2519 2025-10-07 21:52:15 +02:00
Christoffer Lerno
04cd079d4e - Compiler segfault when accessing member of number cast to bitstruct #2516.
- Additional fix to #2515
- Compiler assert when getting a member of a `bitstruct : char @bigendian` #2517.
2025-10-07 00:12:41 +02:00
Christoffer Lerno
b4b14674b4 - Bitstruct truncated constant error escapes $defined #2515 2025-10-06 20:50:56 +02:00
Christoffer Lerno
5a1831c989 Error when using $vaarg/$vacount/$vasplat and similar in a macro without vaargs #2510. 2025-10-06 00:45:36 +02:00
Christoffer Lerno
e9ec421b3b Compiler fails to stop error print in recursive macro, and also prints unnecessary "inline at" #2513. 2025-10-06 00:31:27 +02:00
Christoffer Lerno
872f63eecc - Bitstruct value cannot be used to index a const array in compile time. #2512 2025-10-05 22:23:07 +02:00
Christoffer Lerno
1eb8c0ced1 Bug in io::write_using_write_byte. 2025-10-05 00:29:34 +02:00
Christoffer Lerno
b5ae2485a7 Update version to 0.7.7 2025-10-04 11:49:23 +02:00
353 changed files with 12995 additions and 7214 deletions

View File

@@ -12,6 +12,7 @@ env:
LLVM_RELEASE_VERSION_LINUX: 19
LLVM_RELEASE_VERSION_OPENBSD: 19
LLVM_RELEASE_VERSION_UBUNTU22: 19
LLVM_RELEASE_VERSION_ALPINEv3_22: 20
LLVM_DEV_VERSION: 22
jobs:
@@ -78,15 +79,15 @@ jobs:
- name: Vendor-fetch
run: |
build\${{ matrix.build_type }}\c3c.exe vendor-fetch raylib55
build\${{ matrix.build_type }}\c3c.exe vendor-fetch raylib
- name: Try raylib5
run: |
cd resources
..\build\${{ matrix.build_type }}\c3c.exe vendor-fetch raylib55
..\build\${{ matrix.build_type }}\c3c.exe compile --lib raylib55 --print-linking examples\raylib\raylib_arkanoid.c3
..\build\${{ matrix.build_type }}\c3c.exe compile --lib raylib55 --print-linking examples\raylib\raylib_snake.c3
..\build\${{ matrix.build_type }}\c3c.exe compile --lib raylib55 --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 --print-linking examples\raylib\raylib_arkanoid.c3
..\build\${{ matrix.build_type }}\c3c.exe compile --lib raylib --print-linking examples\raylib\raylib_snake.c3
..\build\${{ matrix.build_type }}\c3c.exe compile --lib raylib --print-linking examples\raylib\raylib_tetris.c3
- name: run compiler tests
run: |
@@ -159,7 +160,7 @@ jobs:
- name: Vendor-fetch
run: |
./build/c3c vendor-fetch raylib55
./build/c3c vendor-fetch raylib
- name: Build testproject lib
run: |
@@ -384,7 +385,7 @@ jobs:
- name: Vendor-fetch
run: |
./build/c3c vendor-fetch raylib55
./build/c3c vendor-fetch raylib
- name: run compiler tests
run: |
@@ -409,6 +410,187 @@ jobs:
name: c3-linux-${{matrix.build_type}}
path: c3-linux-${{matrix.build_type}}.tar.gz
build-linux-alpine:
runs-on: ubuntu-22.04
container:
image: alpine:3.22
strategy:
# Don't abort runners if a single one fails
fail-fast: false
matrix:
build_type: [Release, Debug]
llvm_version: [18, 19, 20]
steps:
- uses: actions/checkout@v4
- name: Install common deps
run: |
apk update
apk add zlib-dev zlib-static python3 samurai cmake curl-dev curl-static openssl-dev
- name: Install Clang ${{matrix.llvm_version}}
run: |
apk add "llvm${{matrix.llvm_version}}-dev" "llvm${{matrix.llvm_version}}-static" \
"llvm${{matrix.llvm_version}}-gtest" "llvm${{matrix.llvm_version}}-linker-tools" \
"llvm${{matrix.llvm_version}}-test-utils" "llvm${{matrix.llvm_version}}-test-utils-pyc" \
"lld${{matrix.llvm_version}}-dev" "clang${{matrix.llvm_version}}-dev" \
"clang${{matrix.llvm_version}}-extra-tools" "clang${{matrix.llvm_version}}-static"
- name: CMake
if: matrix.llvm_version == env.LLVM_DEV_VERSION
run: |
cmake -B build \
-G Ninja \
-DCMAKE_BUILD_TYPE=${{matrix.build_type}}" \
-DCMAKE_C_COMPILER=clang-${{matrix.llvm_version}} \
-DCMAKE_CXX_COMPILER=clang++-${{matrix.llvm_version}} \
-DCMAKE_LINKER=lld-link-${{matrix.llvm_version}} \
-DCMAKE_OBJCOPY=llvm-objcopy-${{matrix.llvm_version}} \
-DCMAKE_STRIP=llvm-strip-${{matrix.llvm_version}} \
-DCMAKE_DLLTOOL=llvm-dlltool-${{matrix.llvm_version}} \
-DLLVM_ENABLE_LIBXML2=OFF \
-DC3_LINK_DYNAMIC=ON \
-DC3_LLVM_VERSION=${{matrix.llvm_version}}
cmake --build build
- name: CMake_Stable
if: matrix.llvm_version >= 18 && matrix.llvm_version != env.LLVM_DEV_VERSION
run: |
cmake -B build \
-G Ninja \
-DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
-DCMAKE_C_COMPILER=clang-${{matrix.llvm_version}} \
-DCMAKE_CXX_COMPILER=clang++-${{matrix.llvm_version}} \
-DCMAKE_LINKER=lld-link-${{matrix.llvm_version}} \
-DCMAKE_OBJCOPY=llvm-objcopy-${{matrix.llvm_version}} \
-DCMAKE_STRIP=llvm-strip-${{matrix.llvm_version}} \
-DCMAKE_DLLTOOL=llvm-dlltool-${{matrix.llvm_version}} \
-DLLVM_ENABLE_LIBXML2=OFF \
-DC3_LINK_DYNAMIC=ON \
-DC3_LLVM_VERSION=${{matrix.llvm_version}}.1
cmake --build build
- name: Compile and run some examples
run: |
export C3C="$(realpath ./build/c3c)"
cd resources
"$C3C" compile examples/base64.c3
"$C3C" compile examples/binarydigits.c3
"$C3C" compile examples/brainfk.c3
"$C3C" compile examples/factorial_macro.c3
"$C3C" compile examples/fasta.c3
"$C3C" compile examples/gameoflife.c3
"$C3C" compile examples/hash.c3
"$C3C" compile-only examples/levenshtein.c3
"$C3C" compile examples/load_world.c3
"$C3C" compile-only examples/map.c3
"$C3C" compile examples/mandelbrot.c3
"$C3C" compile examples/plus_minus.c3
"$C3C" compile examples/nbodies.c3
"$C3C" compile examples/spectralnorm.c3
"$C3C" compile examples/swap.c3
"$C3C" compile examples/contextfree/boolerr.c3
"$C3C" compile examples/contextfree/dynscope.c3
"$C3C" compile examples/contextfree/guess_number.c3
"$C3C" compile examples/contextfree/multi.c3
"$C3C" compile examples/contextfree/cleanup.c3
"$C3C" compile-run examples/hello_world_many.c3
"$C3C" compile-run examples/time.c3
"$C3C" compile-run examples/fannkuch-redux.c3
"$C3C" compile-run examples/contextfree/boolerr.c3
"$C3C" compile-run examples/load_world.c3
"$C3C" compile-run examples/process.c3
"$C3C" compile-run examples/ls.c3
# "$C3C" compile-run --linker=builtin linux_stack.c3 # Program will hang due to incorrect linking to `/lib64/ld-linux-x86-64.so.2` instead of `/lib/ld-musl-x86_64.so.1`
"$C3C" compile-run linux_stack.c3
"$C3C" compile-run examples/args.c3 -- foo -bar "baz baz"
- name: Compile and run dynlib-test
run: |
export C3C="$(realpath ./build/c3c)"
cd resources/examples/dynlib-test
"$C3C" -vv dynamic-lib add.c3
mv add.so libadd.so
cc test.c -L. -ladd -Wl,-rpath=.
./a.out
"$C3C" compile-run test.c3 -L . -l add -z -Wl,-rpath=.
- name: Compile and run staticlib-test
run: |
export C3C="$(realpath ./build/c3c)"
cd resources/examples/staticlib-test
"$C3C" -vv static-lib add.c3
mv add.a libadd.a
cc test.c -L. -ladd
./a.out
"$C3C" compile-run test.c3 -L . -l add
- name: Compile run unit tests
run: |
export C3C="$(realpath ./build/c3c)"
cd test
"$C3C" compile-test unit -D SLOW_TESTS
- name: Build testproject
run: |
export C3C="$(realpath ./build/c3c)"
cd resources/testproject
"$C3C" run -vvv --trust=full
- name: Test WASM
run: |
export C3C="$(realpath ./build/c3c)"
cd resources/testfragments
"$C3C" compile --target wasm32 -g0 --no-entry -Os wasm4.c3
- name: Install QEMU and Risc-V toolchain
run: |
apk add qemu-dev qemu-system-riscv32 gcc-riscv-none-elf make
- name: Compile and run Baremetal Risc-V Example
run: |
cd resources/examples/embedded/riscv-qemu
make C3C_PATH=../../../../build/ run
- name: Build testproject direct linker
run: |
export C3C="$(realpath ./build/c3c)"
cd resources/testproject
"$C3C" run -vvv --linker=builtin --trust=full --linux-libc=musl
- name: Init a library & a project
run: |
./build/c3c init-lib mylib
ls mylib.c3l
./build/c3c init myproject
ls myproject
- name: Vendor-fetch
run: |
"$(realpath ./build/c3c)" vendor-fetch raylib55
- name: run compiler tests
run: |
export C3C="$(realpath ./build/c3c)"
cd test
"$C3C" compile-run -O1 src/test_suite_runner.c3 -- ../build/c3c test_suite/
- name: bundle_output
if: matrix.llvm_version == env.LLVM_RELEASE_VERSION_ALPINEv3_22
run: |
mkdir c3
cp -r lib c3
cp msvc_build_libraries.py c3
cp build/c3c c3
cp README.md c3
cp releasenotes.md c3
tar -czf c3-musl-${{matrix.build_type}}.tar.gz c3
- name: upload artifacts
if: matrix.llvm_version == env.LLVM_RELEASE_VERSION_ALPINEv3_22
uses: actions/upload-artifact@v4
with:
name: c3-musl-${{matrix.build_type}}
path: c3-musl-${{matrix.build_type}}.tar.gz
build-linux-ubuntu22:
runs-on: ubuntu-22.04
strategy:
@@ -515,7 +697,7 @@ jobs:
- name: Vendor-fetch
run: |
./build/c3c vendor-fetch raylib55
./build/c3c vendor-fetch raylib
- name: run compiler tests
run: |
@@ -658,7 +840,7 @@ jobs:
- name: Vendor-fetch
run: |
./build/c3c vendor-fetch raylib55
./build/c3c vendor-fetch raylib
- name: Compile and run some examples
run: |
@@ -777,7 +959,7 @@ jobs:
uses: vmactions/openbsd-vm@main
with:
prepare: |
pkg_add cmake llvm-19.1.7p3 ninja
pkg_add cmake llvm-20.1.8p1 ninja
run: |
echo "CMake"
@@ -904,7 +1086,7 @@ jobs:
- run: mv c3-ubuntu-22-Debug/c3-ubuntu-22-Debug.tar.gz c3-ubuntu-22-Debug/c3-ubuntu-22-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: gh release delete latest-prerelease --cleanup-tag -y || true
- run: gh release delete latest-prerelease-tag --cleanup-tag -y || true
- run: echo "RELEASE_NAME=latest-prerelease-$(date +'%Y%m%d-%H%M')" >> $GITHUB_ENV
- id: create_release
@@ -912,7 +1094,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: latest-prerelease
tag_name: latest-prerelease-tag
name: ${{ env.RELEASE_NAME }}
draft: false
prerelease: true

5
.gitignore vendored
View File

@@ -92,3 +92,8 @@ result
/test/tmp/*
/test/testrun
/test/test_suite_runner
# patches, originals and rejects
*.patch
*.rej
*.orig

View File

@@ -65,8 +65,8 @@ if(MSVC)
else()
add_compile_options(-gdwarf-3 -fno-exceptions)
# add_compile_options(-fsanitize=address,undefined)
# add_link_options(-fsanitize=address,undefined)
#add_compile_options(-fsanitize=address,undefined)
#add_link_options(-fsanitize=address,undefined)
endif()
# Options

View File

@@ -8,11 +8,11 @@ for programmers who like C.
Precompiled binaries for the following operating systems are available:
- Windows x64 [download](https://github.com/c3lang/c3c/releases/download/latest-prerelease/c3-windows.zip), [install instructions](#installing-on-windows-with-precompiled-binaries).
- Debian x64 [download](https://github.com/c3lang/c3c/releases/download/latest-prerelease/c3-linux.tar.gz), [install instructions](#installing-on-debian-with-precompiled-binaries).
- Ubuntu x86 [download](https://github.com/c3lang/c3c/releases/download/latest-prerelease/c3-ubuntu-20.tar.gz), [install instructions](#installing-on-ubuntu-with-precompiled-binaries).
- MacOS Arm64 [download](https://github.com/c3lang/c3c/releases/download/latest-prerelease/c3-macos.zip), [install instructions](#installing-on-macos-with-precompiled-binaries).
- OpenBSD x64 [download](https://github.com/c3lang/c3c/releases/download/latest-prerelease/c3-openbsd.tar.gz), [install instructions](#installing-on-openbsd-with-precompiled-binaries).
- Windows x64 [download](https://github.com/c3lang/c3c/releases/download/latest-prerelease-tag/c3-windows.zip), [install instructions](#installing-on-windows-with-precompiled-binaries).
- Debian x64 [download](https://github.com/c3lang/c3c/releases/download/latest-prerelease-tag/c3-linux.tar.gz), [install instructions](#installing-on-debian-with-precompiled-binaries).
- Ubuntu x86 [download](https://github.com/c3lang/c3c/releases/download/latest-prerelease-tag/c3-ubuntu-20.tar.gz), [install instructions](#installing-on-ubuntu-with-precompiled-binaries).
- MacOS Arm64 [download](https://github.com/c3lang/c3c/releases/download/latest-prerelease-tag/c3-macos.zip), [install instructions](#installing-on-macos-with-precompiled-binaries).
- OpenBSD x64 [download](https://github.com/c3lang/c3c/releases/download/latest-prerelease-tag/c3-openbsd.tar.gz), [install instructions](#installing-on-openbsd-with-precompiled-binaries).
The manual for C3 can be found at [www.c3-lang.org](http://www.c3-lang.org).
@@ -142,7 +142,7 @@ fn void main()
### Current status
The current stable version of the compiler is **version 0.7.6**.
The current stable version of the compiler is **version 0.7.8**.
The upcoming 0.7.x releases will focus on expanding the standard library,
fixing bugs and improving compile time analysis.
@@ -151,7 +151,7 @@ Follow the issues [here](https://github.com/c3lang/c3c/issues).
If you have suggestions on how to improve the language, either [file an issue](https://github.com/c3lang/c3c/issues)
or discuss C3 on its dedicated Discord: [https://discord.gg/qN76R87](https://discord.gg/qN76R87).
The compiler is currently verified to compile on Linux, Windows and MacOS.
The compiler is currently verified to compile on Linux, OpenBSD, Windows and MacOS.
**Support matrix**
@@ -172,6 +172,7 @@ The compiler is currently verified to compile on Linux, Windows and MacOS.
| ELF freestanding Aarch64 | No | Untested | No | No | No | Yes* |
| ELF freestanding Riscv64 | No | Untested | No | No | No | Untested |
| ELF freestanding Riscv32 | No | Untested | No | No | No | Untested |
| ELF freestanding Xtensa* | No | Untested | No | No | No | Untested |
| FreeBSD x86 | Untested | Untested | No | Yes | Untested | Yes* |
| FreeBSD x64 | Untested | Untested | No | Yes | Untested | Yes* |
| NetBSD x86 | Untested | Untested | No | Yes | Untested | Yes* |
@@ -184,7 +185,8 @@ The compiler is currently verified to compile on Linux, Windows and MacOS.
*\* Inline asm is still a work in progress*<br>
*\* OpenBSD 7.7 is the only tested version*<br>
*\* OpenBSD has limited stacktrace, needs to be tested further*
*\* OpenBSD has limited stacktrace, needs to be tested further*<br>
*\* Xtensa support is enabled by compiling with `-DXTENSA_ENABLE`. The [espressif llvm fork](https://github.com/espressif/llvm-project) is recommended for best compatibility*
More platforms will be supported in the future.
@@ -203,8 +205,8 @@ More platforms will be supported in the future.
This installs the latest prerelease build, as opposed to the latest released version.
#### Installing on Windows with precompiled binaries
1. Download the zip file: [https://github.com/c3lang/c3c/releases/download/latest-prerelease/c3-windows.zip](https://github.com/c3lang/c3c/releases/download/latest-prerelease/c3-windows.zip)
(debug version [here](https://github.com/c3lang/c3c/releases/download/latest-prerelease/c3-windows-debug.zip))
1. Download the zip file: [https://github.com/c3lang/c3c/releases/download/latest-prerelease-tag/c3-windows.zip](https://github.com/c3lang/c3c/releases/download/latest-prerelease-tag/c3-windows.zip)
(debug version [here](https://github.com/c3lang/c3c/releases/download/latest-prerelease-tag/c3-windows-debug.zip))
2. Unzip exe and standard lib.
3. If you don't have Visual Studio 17 installed you can either do so, or run the `msvc_build_libraries.py` Python script which will download the necessary files to compile on Windows.
4. Run `c3c.exe`.
@@ -227,8 +229,8 @@ If you don't have Visual Studio 17 installed you can either do so, or run the `m
#### Installing on Debian with precompiled binaries
1. Download tar file: [https://github.com/c3lang/c3c/releases/download/latest-prerelease/c3-linux.tar.gz](https://github.com/c3lang/c3c/releases/download/latest-prerelease/c3-linux.tar.gz)
(debug version [here](https://github.com/c3lang/c3c/releases/download/latest-prerelease/c3-linux-debug.tar.gz))
1. Download tar file: [https://github.com/c3lang/c3c/releases/download/latest-prerelease-tag/c3-linux.tar.gz](https://github.com/c3lang/c3c/releases/download/latest-prerelease-tag/c3-linux.tar.gz)
(debug version [here](https://github.com/c3lang/c3c/releases/download/latest-prerelease-tag/c3-linux-debug.tar.gz))
2. Unpack executable and standard lib.
3. Run `./c3c`.
@@ -247,23 +249,23 @@ curl -fsSL https://raw.githubusercontent.com/c3lang/c3c/refs/heads/master/instal
```
#### Installing on Ubuntu with precompiled binaries
1. Download tar file: [https://github.com/c3lang/c3c/releases/download/latest-prerelease/c3-ubuntu-20.tar.gz](https://github.com/c3lang/c3c/releases/download/latest-prerelease/c3-ubuntu-20.tar.gz)
(debug version [here](https://github.com/c3lang/c3c/releases/download/latest-prerelease/c3-ubuntu-20-debug.tar.gz))
1. Download tar file: [https://github.com/c3lang/c3c/releases/download/latest-prerelease-tag/c3-ubuntu-20.tar.gz](https://github.com/c3lang/c3c/releases/download/latest-prerelease-tag/c3-ubuntu-20.tar.gz)
(debug version [here](https://github.com/c3lang/c3c/releases/download/latest-prerelease-tag/c3-ubuntu-20-debug.tar.gz))
2. Unpack executable and standard lib.
3. Run `./c3c`.
#### Installing on MacOS 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-prerelease/c3-macos.zip](https://github.com/c3lang/c3c/releases/download/latest-prerelease/c3-macos.zip)
(debug version [here](https://github.com/c3lang/c3c/releases/download/latest-prerelease/c3-macos-debug.zip))
2. Download the zip file: [https://github.com/c3lang/c3c/releases/download/latest-prerelease-tag/c3-macos.zip](https://github.com/c3lang/c3c/releases/download/latest-prerelease-tag/c3-macos.zip)
(debug version [here](https://github.com/c3lang/c3c/releases/download/latest-prerelease-tag/c3-macos-debug.zip))
3. Unzip executable and standard lib.
4. Run `./c3c`.
(*Note that there is a known issue with debug symbol generation on MacOS 13, see [issue #1086](https://github.com/c3lang/c3c/issues/1086))
#### Installing on OpenBSD with precompiled binaries
1. Download tar file: [https://github.com/c3lang/c3c/releases/download/latest-prerelease/c3-openbsd.tar.gz](https://github.com/c3lang/c3c/releases/download/latest-prerelease/c3-openbsd.tar.gz)
(debug version [here](https://github.com/c3lang/c3c/releases/download/latest-prerelease/c3-openbsd-debug.tar.gz))
1. Download tar file: [https://github.com/c3lang/c3c/releases/download/latest-prerelease-tag/c3-openbsd.tar.gz](https://github.com/c3lang/c3c/releases/download/latest-prerelease-tag/c3-openbsd.tar.gz)
(debug version [here](https://github.com/c3lang/c3c/releases/download/latest-prerelease-tag/c3-openbsd-debug.tar.gz))
2. Unpack executable and standard lib.
3. Run `./c3c`.

View File

@@ -21,11 +21,11 @@ fn void bench_ctr_xcrypt() @benchmark
Aes ctx;
// encrypt
ctx.init_with_iv(aes, CTR, key, iv);
ctx.init(aes, key, iv);
ctx.encrypt_buffer(text, &out);
// decrypt
ctx.init_with_iv(aes, CTR, key, iv);
ctx.init(aes, key, iv);
ctx.decrypt_buffer(cipher, &out);
}

View File

@@ -532,7 +532,8 @@ fn bool List.remove_first_item(&self, Type value) @if(ELEMENT_IS_EQUATABLE)
fn usz List.remove_item(&self, Type value) @if(ELEMENT_IS_EQUATABLE)
{
usz old_size = self.size;
defer {
defer
{
if (old_size != self.size) self._update_size_change(old_size, self.size);
}
return list_common::list_remove_item(self, value);

View File

@@ -135,11 +135,14 @@ macro bool @typeis(#value, $Type) @const @builtin @deprecated("Use `$typeof(#val
}
fn bool print_backtrace(String message, int backtraces_to_ignore) @if (env::NATIVE_STACKTRACE) => @stack_mem(0x1100; Allocator smem)
fn bool print_backtrace(String message, int backtraces_to_ignore, void *added_backtrace = null) @if (env::NATIVE_STACKTRACE) => @stack_mem(0x1100; Allocator smem)
{
void*[256] buffer;
void*[] backtraces = backtrace::capture_current(&buffer);
backtraces_to_ignore++;
if (added_backtrace)
{
backtraces[++backtraces_to_ignore] = added_backtrace;
}
@stack_mem(2048; Allocator mem)
{
BacktraceList? backtrace = backtrace::symbolize_backtrace(mem, backtraces);
@@ -500,7 +503,7 @@ macro void? @try(#v, #expr) @builtin @maydiscard
{
char[] data;
// Read until end of file
if (@try_catch(data, load_line(), io::EOF)) break;
if (@try_catch(data, load_line(), io::EOF)!) break;
.. use data ..
}
@@ -547,6 +550,27 @@ macro isz @str_find(String $string, String $needle) @builtin => $$str_find($stri
macro String @str_upper(String $str) @builtin => $$str_upper($str);
macro String @str_lower(String $str) @builtin => $$str_lower($str);
macro uint @str_hash(String $str) @builtin => $$str_hash($str);
macro String @str_pascalcase(String $str) @builtin => $$str_pascalcase($str);
macro String @str_snakecase(String $str) @builtin => $$str_snakecase($str);
macro String @str_camelcase(String $str) @builtin => @str_capitalize($$str_pascalcase($str));
macro String @str_constantcase(String $str) @builtin => @str_upper($$str_snakecase($str));
macro String @str_replace(String $str, String $pattern, String $replace, uint $limit = 0) @builtin => $$str_replace($str, $pattern, $replace, $limit);
macro String @str_capitalize(String $str) @builtin
{
$switch $str.len:
$case 0: return $str;
$case 1: return $$str_upper($str);
$default: return $$str_upper($str[0:1]) +++ $str[1..];
$endswitch
}
macro String @str_uncapitalize(String $str) @builtin
{
$switch $str.len:
$case 0: return $str;
$case 1: return $$str_lower($str);
$default: return $$str_lower($str[0:1]) +++ $str[1..];
$endswitch
}
macro @generic_hash_core(h, value)
{
@@ -920,23 +944,20 @@ macro void* get_returnaddress(int n)
}
module std::core::builtin @if((env::LINUX || env::ANDROID || env::DARWIN) && env::COMPILER_SAFE_MODE && env::DEBUG_SYMBOLS);
import libc, std::io;
import libc, std::io, std::os::posix;
fn void sig_panic(String message)
{
default_panic(message, "???", "???", 0);
}
SignalFunction old_bus_error;
SignalFunction old_segmentation_fault;
fn void sig_bus_error(CInt i)
fn void sig_bus_error(CInt i, void* info, void* context)
{
$if !env::NATIVE_STACKTRACE:
sig_panic("Illegal memory access.");
$else
$if $defined(io::stderr):
if (!print_backtrace("Illegal memory access.", 1))
if (!print_backtrace("Illegal memory access.", 2, posix::stack_instruction(context)))
{
io::eprintn("\nERROR: 'Illegal memory access'.");
}
@@ -945,13 +966,13 @@ fn void sig_bus_error(CInt i)
$$trap();
}
fn void sig_segmentation_fault(CInt i)
fn void sig_segmentation_fault(CInt i, void* p1, void* context)
{
$if !env::NATIVE_STACKTRACE:
sig_panic("Out of bounds memory access.");
$else
$if $defined(io::stderr):
if (!print_backtrace("Out of bounds memory access.", 1))
if (!print_backtrace("Out of bounds memory access.", 2, posix::stack_instruction(context)))
{
io::eprintn("\nERROR: Memory error without backtrace, possible stack overflow.");
}
@@ -960,17 +981,12 @@ fn void sig_segmentation_fault(CInt i)
$$trap();
}
fn void install_signal_handler(CInt signal, SignalFunction func) @local
{
SignalFunction old = libc::signal(signal, func);
// Restore
if ((iptr)old > 1024) libc::signal(signal, old);
}
// Clean this up
fn void install_signal_handlers() @init(101) @local @if(env::BACKTRACE)
{
install_signal_handler(libc::SIGBUS, &sig_bus_error);
install_signal_handler(libc::SIGSEGV, &sig_segmentation_fault);
posix::install_signal_handler(libc::SIGBUS, &sig_bus_error);
posix::install_signal_handler(libc::SIGSEGV, &sig_segmentation_fault);
}

View File

@@ -64,7 +64,7 @@ macro int @main_to_void_main_args(#m, int argc, char** argv)
module std::core::main_stub @if(env::WIN32);
extern fn Char16** _win_command_line_to_argv_w(ushort* cmd_line, int* argc_ptr) @extern("CommandLineToArgvW");
extern fn Char16** _win_command_line_to_argv_w(ushort* cmd_line, int* argc_ptr) @cname("CommandLineToArgvW");
macro String[] win_command_line_to_strings(ushort* cmd_line) @private
{

View File

@@ -42,7 +42,7 @@ macro @enum_lookup_new($Type, $name, value)
module std::core::runtime @if(env::FREESTANDING_WASM);
extern fn void __wasm_call_ctors();
fn void wasm_initialize() @extern("_initialize") @wasm
fn void wasm_initialize() @cname("_initialize") @wasm
{
// The linker synthesizes this to call constructors.
__wasm_call_ctors();

View File

@@ -4,8 +4,8 @@
module std::core::runtime;
import std::core::test @public;
import std::core::mem::allocator @public;
import libc, std::time, std::io, std::sort;
import std::os::env;
import libc, std::time, std::io, std::sort, std::os;
alias TestFn = fn void();
@@ -18,6 +18,8 @@ struct TestContext
String test_filter;
<* Triggers debugger breakpoint when assert or test:: checks failed *>
bool breakpoint_on_assert;
<* Controls level of printed logs *>
LogPriority log_level;
// internal state
bool assert_print_backtrace;
@@ -86,7 +88,21 @@ fn bool terminal_has_ansi_codes() @local => @pool()
$endif
}
fn void sig_bus_error(CInt i, void*, void* context) @local @if(env::POSIX)
{
panic_test("Bus error", "Unknown", "Unknown", 1, posix::stack_instruction(context));
}
fn void sig_segmentation_fault(CInt i, void*, void* context) @local @if(env::POSIX)
{
panic_test("Segmentation fault", "Unknown", "Unknown", 1, posix::stack_instruction(context));
}
fn void test_panic(String message, String file, String function, uint line) @local
{
panic_test(message, file, function, line);
}
fn void panic_test(String message, String file, String function, uint line, void* extra_trace = null) @local
{
if (test_context.is_in_panic) return;
test_context.is_in_panic = true;
@@ -96,7 +112,7 @@ fn void test_panic(String message, String file, String function, uint line) @loc
if (test_context.assert_print_backtrace)
{
$if env::NATIVE_STACKTRACE:
builtin::print_backtrace(message, 0);
builtin::print_backtrace(message, extra_trace ? 3 : 0, extra_trace);
$endif
}
io::printf("\nTest failed ^^^ ( %s:%s ) %s\n", file, line, message);
@@ -165,6 +181,7 @@ fn void unmute_output(bool has_error) @local
(void)stdout.flush();
}
fn bool run_tests(String[] args, TestUnit[] tests) @private
{
usz max_name;
@@ -175,6 +192,10 @@ fn bool run_tests(String[] args, TestUnit[] tests) @private
io::printn("There are no test units to run.");
return true; // no tests == technically a pass
}
$if !env::NO_LIBC && env::POSIX:
posix::install_signal_handler(libc::SIGBUS, &sig_bus_error);
posix::install_signal_handler(libc::SIGSEGV, &sig_segmentation_fault);
$endif
foreach (&unit : tests)
{
if (max_name < unit.name.len) max_name = unit.name.len;
@@ -183,6 +204,7 @@ fn bool run_tests(String[] args, TestUnit[] tests) @private
{
.assert_print_backtrace = true,
.breakpoint_on_assert = false,
.log_level = LogPriority.ERROR,
.test_filter = "",
.has_ansi_codes = terminal_has_ansi_codes(),
.stored.allocator = mem,
@@ -200,6 +222,7 @@ fn bool run_tests(String[] args, TestUnit[] tests) @private
case "--test-noleak":
check_leaks = false;
case "--test-nocapture":
case "--test-show-output":
context.is_no_capture = true;
case "--noansi":
context.has_ansi_codes = false;
@@ -215,11 +238,28 @@ fn bool run_tests(String[] args, TestUnit[] tests) @private
}
context.test_filter = args[i + 1];
i++;
case "--test-log-level":
if (i == args.len - 1)
{
io::printn("Missing log level for argument `--test-log-level`.");
return false;
}
@pool()
{
String upper = args[i + 1].to_upper_copy(tmem);
if (catch @try(context.log_level, enum_by_name(LogPriority, upper)))
{
io::printn("Log level given to `--test-log-level` is not one of verbose, debug, info, warn, error or critical.");
return false;
}
};
i++;
default:
io::printfn("Unknown argument: %s", args[i]);
}
}
test_context = &context;
log::set_priority_all(test_context.log_level);
if (sort_tests)
{

View File

@@ -70,7 +70,7 @@ macro WString @wstring(String $string) @builtin
}
<*
Create a slice of an UTF32 encoded string at compile time.
Create a slice of an UTF16 encoded string at compile time.
@param $string : "The string to encode"
*>
@@ -1067,14 +1067,10 @@ macro String.to_integer(self, $Type, int base = 10)
{
if (is_negative)
{
$Type new_value = value * base_used - c;
if (new_value > value) return INTEGER_OVERFLOW?;
value = new_value;
value = value.overflow_mul(base_used).overflow_sub(c) ?? INTEGER_OVERFLOW?!;
break;
}
$Type new_value = value * base_used + c;
if (new_value < value) return INTEGER_OVERFLOW?;
value = new_value;
value = value.overflow_mul(base_used).overflow_add(c) ?? INTEGER_OVERFLOW?!;
};
}
return value;

View File

@@ -26,6 +26,7 @@ fn void? test_div() @test
test::le(2, 3);
test::eq_approx(m::divide(1, 3)!, 0.333, places: 3);
test::@check(2 == 2, "divide: %d", divide(6, 3)!);
test::@error(m::divide(3, 0));
test::@error(m::divide(3, 0), MathError.DIVISION_BY_ZERO);
}
@@ -78,14 +79,15 @@ macro @check(#condition, String format = "", args...)
}
<*
Check if function returns specific error
Check if function returns (specific) error
@param #funcresult : `result of function execution`
@param error_expected : `expected error of function execution`
@require runtime::test_context != null : "Only allowed in @test functions"
*>
macro @error(#funcresult, fault error_expected)
macro @error(#funcresult, fault error_expected = ...)
{
$if $defined(error_expected):
if (catch err = #funcresult)
{
if (err != error_expected)
@@ -96,6 +98,10 @@ macro @error(#funcresult, fault error_expected)
return;
}
print_panicf("`%s` error [%s] was not returned.", $stringify(#funcresult), error_expected);
$else
if (catch err = #funcresult) return;
print_panicf("`%s` unexpectedly did not return error.", $stringify(#funcresult));
$endif
}
<*

View File

@@ -141,8 +141,6 @@ fn usz? Formatter.out_str(&self, any arg) @private
{
switch (arg.type.kindof)
{
case TYPEID:
return self.out_substr("typeid");
case VOID:
return self.out_substr("void");
case FAULT:
@@ -188,6 +186,8 @@ fn usz? Formatter.out_str(&self, any arg) @private
if (@catch(n) != NOT_FOUND) n!;
switch (arg.type.kindof)
{
case TYPEID:
return self.out_substr("typeid[")! + self.ntoa((iptr)*(typeid*)arg, false, 16)! + self.out_substr("]")!;
case ENUM:
usz i = types::any_to_enum_ordinal(arg, usz)!!;
assert(i < arg.type.names.len, "Illegal enum value found, numerical value was %d.", i);

View File

@@ -526,6 +526,19 @@ fn usz? Formatter.floatformat(&self, FloatFormatting formatting, double y) @priv
return len;
}
const char[201] DIGIT_PAIRS @private =
"00102030405060708090"
"01112131415161718191"
"02122232425262728292"
"03132333435363738393"
"04142434445464748494"
"05152535455565758595"
"06162636465666768696"
"07172737475767778797"
"08182838485868788898"
"09192939495969798999";
fn usz? Formatter.ntoa(&self, uint128 value, bool negative, uint base) @private
{
char[PRINTF_NTOA_BUFFER_SIZE] buf @noinit;
@@ -538,14 +551,56 @@ fn usz? Formatter.ntoa(&self, uint128 value, bool negative, uint base) @private
if (!self.flags.precision || value)
{
char past_10 = (self.flags.uppercase ? 'A' : 'a') - 10;
do
switch (base)
{
if (len >= PRINTF_NTOA_BUFFER_SIZE) return INTERNAL_BUFFER_EXCEEDED?;
char digit = (char)(value % base);
buf[len++] = digit + (digit < 10 ? '0' : past_10);
value /= base;
case 2:
do
{
if (len >= PRINTF_NTOA_BUFFER_SIZE) return INTERNAL_BUFFER_EXCEEDED?;
buf[len++] = '0' + (char)value & 1;
value >>= 1;
}
while (value);
case 10:
if (!value)
{
if (len >= PRINTF_NTOA_BUFFER_SIZE) return INTERNAL_BUFFER_EXCEEDED?;
buf[len++] = '0';
break;
}
while (value >= 10)
{
if (len + 1 >= PRINTF_NTOA_BUFFER_SIZE) return INTERNAL_BUFFER_EXCEEDED?;
char digit = (char)(value % 100);
buf[len:2] = DIGIT_PAIRS[2 * digit:2];
len += 2;
value /= 100;
}
if (value > 0)
{
if (len >= PRINTF_NTOA_BUFFER_SIZE) return INTERNAL_BUFFER_EXCEEDED?;
buf[len++] = '0' + (char)value;
}
case 16:
do
{
if (len >= PRINTF_NTOA_BUFFER_SIZE) return INTERNAL_BUFFER_EXCEEDED?;
char digit = (char)value & 0xF;
buf[len++] = digit + (digit < 10 ? '0' : past_10);
value >>= 4;
}
while (value);
case 8:
do
{
if (len >= PRINTF_NTOA_BUFFER_SIZE) return INTERNAL_BUFFER_EXCEEDED?;
buf[len++] = '0' + (char)value & 0x7;
value >>= 3;
}
while (value);
default:
unreachable();
}
while (value);
}
return self.ntoa_format((String)buf[:PRINTF_NTOA_BUFFER_SIZE], len, negative, base);
}

View File

@@ -267,7 +267,32 @@ fn void? out_putstream_fn(void* data, char c) @private
return (*stream).write_byte(c);
}
fn void? out_putchar_fn(void* data @unused, char c) @private
macro usz putchar_buf_size() @const
{
$switch env::MEMORY_ENV:
$case NORMAL: return 32 * 1024;
$case SMALL: return 1024;
$case TINY: return 256;
$case NONE: return 256;
$endswitch
}
struct PutcharBuffer
{
char[putchar_buf_size()] data;
usz len;
bool should_flush;
}
fn void? write_putchar_buffer(PutcharBuffer* buff, bool flush) @private
{
File* stdout = io::stdout();
libc::fwrite(&buff.data, 1, buff.len, stdout.file);
buff.len = 0;
if (flush) stdout.flush()!;
}
fn void? out_putchar_buffer_fn(void* data @unused, char c) @private
{
$if env::TESTING:
// HACK: this is used for the purpose of unit test output hijacking
@@ -275,7 +300,10 @@ fn void? out_putchar_fn(void* data @unused, char c) @private
assert(stdout.file);
libc::fputc(c, stdout.file);
$else
libc::putchar(c);
PutcharBuffer* buff = data;
buff.data[buff.len++] = c;
if (c == '\n') buff.should_flush = true;
if (buff.len == buff.data.len) write_putchar_buffer(buff, false)!;
$endif
}
@@ -296,8 +324,11 @@ fn void? out_putchar_fn(void* data @unused, char c) @private
fn usz? printf(String format, args...) @format(0) @maydiscard
{
Formatter formatter;
formatter.init(&out_putchar_fn);
return formatter.vprintf(format, args);
PutcharBuffer buff;
formatter.init(&out_putchar_buffer_fn, &buff);
usz? len = formatter.vprintf(format, args);
write_putchar_buffer(&buff, buff.should_flush)!;
return len;
}
<*
@@ -310,10 +341,11 @@ fn usz? printf(String format, args...) @format(0) @maydiscard
fn usz? printfn(String format, args...) @format(0) @maydiscard
{
Formatter formatter;
formatter.init(&out_putchar_fn);
PutcharBuffer buff;
formatter.init(&out_putchar_buffer_fn, &buff);
usz? len = formatter.vprintf(format, args);
out_putchar_fn(null, '\n')!;
io::stdout().flush()!;
formatter.out('\n')!;
write_putchar_buffer(&buff, true)!;
return len + 1;
}

View File

@@ -186,13 +186,11 @@ fn bool Path.equals(self, Path p2) @operator(==)
fn Path? Path.append(self, Allocator allocator, String filename)
{
if (!self.path_string.len) return new(allocator, filename, self.env)!;
assert(!is_separator(self.path_string[^1], self.env));
@pool()
{
DString dstr = dstring::temp_with_capacity(self.path_string.len + 1 + filename.len);
dstr.append(self.path_string);
dstr.append(PREFERRED_SEPARATOR);
if (!is_separator(self.path_string[^1], self.env)) dstr.append(PREFERRED_SEPARATOR);
dstr.append(filename);
return new(allocator, dstr.str_view(), self.env);
};
@@ -399,6 +397,19 @@ fn Path? Path.parent(self)
{
if (is_separator(c, self.env))
{
if (i == 0) return { self.path_string[..0], self.env, null };
if (self.env == WIN32 && i > 1)
{
if (try volume_len = volume_name_len(self.path_string, WIN32))
{
// Handle C:\foo
if (volume_len == i)
{
if (i + 1 == self.path_string.len) return NO_PARENT?;
return { self.path_string[:i + 1], WIN32, null };
}
}
}
return { self.path_string[:i], self.env, null };
}
}

View File

@@ -116,6 +116,9 @@ macro usz? write_all(stream, char[] buffer)
return n;
}
<*
@require @is_instream(s)
*>
macro usz? read_using_read_byte(s, char[] buffer)
{
usz len = 0;
@@ -133,12 +136,18 @@ macro usz? read_using_read_byte(s, char[] buffer)
return len;
}
<*
@require @is_outstream(s)
*>
macro void? write_byte_using_write(s, char c)
{
char[1] buff = { c };
s.write(&buff)!;
}
<*
@require @is_instream(s)
*>
macro char? read_byte_using_read(s)
{
char[1] buffer;
@@ -149,10 +158,12 @@ macro char? read_byte_using_read(s)
alias ReadByteFn = fn char?();
<*
@require @is_outstream(s)
*>
macro usz? write_using_write_byte(s, char[] bytes)
{
foreach (c : bytes) s.write_byte(self, c)!;
foreach (c : bytes) s.write_byte(c)!;
return bytes.len;
}

View File

@@ -100,7 +100,7 @@ extern fn CInt close(CInt fd) @if(!env::WIN32);
extern fn double difftime(Time_t time1, Time_t time2) @if(!env::WIN32);
extern fn DivResult div(CInt numer, CInt denom);
extern fn void exit(CInt status);
extern fn void _exit(CInt status) @extern("_Exit");
extern fn void _exit(CInt status) @cname("_Exit");
extern fn CInt fclose(CFile stream);
extern fn CFile fdopen(CInt fd, ZString mode) @if(!env::WIN32);
extern fn CInt feof(CFile stream);
@@ -211,9 +211,9 @@ const CInt STDOUT_FD = 1;
const CInt STDERR_FD = 2;
module libc @if(env::LINUX || env::ANDROID);
extern CFile __stdin @extern("stdin");
extern CFile __stdout @extern("stdout");
extern CFile __stderr @extern("stderr");
extern CFile __stdin @cname("stdin");
extern CFile __stdout @cname("stdout");
extern CFile __stderr @cname("stderr");
extern fn usz malloc_usable_size(void* ptr);
macro usz malloc_size(void* ptr) => malloc_usable_size(ptr);
extern fn void* aligned_alloc(usz align, usz size);
@@ -262,30 +262,30 @@ module libc @if(!env::LIBC);
import std::core::mem;
fn void longjmp(JmpBuf* buffer, CInt value) @weak @extern("longjmp") @nostrip
fn void longjmp(JmpBuf* buffer, CInt value) @weak @cname("longjmp") @nostrip
{
unreachable("longjmp unavailable");
}
fn CInt setjmp(JmpBuf* buffer) @weak @extern("setjmp") @nostrip
fn CInt setjmp(JmpBuf* buffer) @weak @cname("setjmp") @nostrip
{
unreachable("setjmp unavailable");
}
fn void* malloc(usz size) @weak @extern("malloc") @nostrip
fn void* malloc(usz size) @weak @cname("malloc") @nostrip
{
unreachable("malloc unavailable");
}
fn void* calloc(usz count, usz size) @weak @extern("calloc") @nostrip
fn void* calloc(usz count, usz size) @weak @cname("calloc") @nostrip
{
unreachable("calloc unavailable");
}
fn void* free(void*) @weak @extern("free")
fn void* free(void*) @weak @cname("free")
{
unreachable("free unavailable");
}
fn void* realloc(void* ptr, usz size) @weak @extern("realloc") @nostrip
fn void* realloc(void* ptr, usz size) @weak @cname("realloc") @nostrip
{
unreachable("realloc unavailable");
}
@@ -294,69 +294,69 @@ alias memcpy = mem::__memcpy;
alias memmove = mem::__memcpy;
alias memset = mem::__memset;
fn int fseek(CFile stream, SeekIndex offset, int whence) @weak @extern("fseek") @nostrip
fn int fseek(CFile stream, SeekIndex offset, int whence) @weak @cname("fseek") @nostrip
{
unreachable("'fseek' not available.");
}
fn CFile fopen(ZString filename, ZString mode) @weak @extern("fopen") @nostrip
fn CFile fopen(ZString filename, ZString mode) @weak @cname("fopen") @nostrip
{
unreachable("'fopen' not available.");
}
fn CFile freopen(ZString filename, ZString mode, CFile stream) @weak @extern("fopen") @nostrip
fn CFile freopen(ZString filename, ZString mode, CFile stream) @weak @cname("fopen") @nostrip
{
unreachable("'freopen' not available.");
}
fn usz fwrite(void* ptr, usz size, usz nmemb, CFile stream) @weak @extern("fwrite") @nostrip
fn usz fwrite(void* ptr, usz size, usz nmemb, CFile stream) @weak @cname("fwrite") @nostrip
{
unreachable("'fwrite' not available.");
}
fn usz fread(void* ptr, usz size, usz nmemb, CFile stream) @weak @extern("fread") @nostrip
fn usz fread(void* ptr, usz size, usz nmemb, CFile stream) @weak @cname("fread") @nostrip
{
unreachable("'fread' not available.");
}
fn CFile fclose(CFile) @weak @extern("fclose") @nostrip
fn CFile fclose(CFile) @weak @cname("fclose") @nostrip
{
unreachable("'fclose' not available.");
}
fn int fflush(CFile stream) @weak @extern("fflush") @nostrip
fn int fflush(CFile stream) @weak @cname("fflush") @nostrip
{
unreachable("'fflush' not available.");
}
fn int fputc(int c, CFile stream) @weak @extern("fputc") @nostrip
fn int fputc(int c, CFile stream) @weak @cname("fputc") @nostrip
{
unreachable("'fputc' not available.");
}
fn char* fgets(ZString str, int n, CFile stream) @weak @extern("fgets") @nostrip
fn char* fgets(ZString str, int n, CFile stream) @weak @cname("fgets") @nostrip
{
unreachable("'fgets' not available.");
}
fn int fgetc(CFile stream) @weak @extern("fgetc") @nostrip
fn int fgetc(CFile stream) @weak @cname("fgetc") @nostrip
{
unreachable("'fgetc' not available.");
}
fn int feof(CFile stream) @weak @extern("feof") @nostrip
fn int feof(CFile stream) @weak @cname("feof") @nostrip
{
unreachable("'feof' not available.");
}
fn int putc(int c, CFile stream) @weak @extern("putc") @nostrip
fn int putc(int c, CFile stream) @weak @cname("putc") @nostrip
{
unreachable("'putc' not available.");
}
fn int putchar(int c) @weak @extern("putchar") @nostrip
fn int putchar(int c) @weak @cname("putchar") @nostrip
{
unreachable("'putchar' not available.");
}
fn int puts(ZString str) @weak @extern("puts") @nostrip
fn int puts(ZString str) @weak @cname("puts") @nostrip
{
unreachable("'puts' not available.");
}

View File

@@ -41,6 +41,6 @@ struct Stat
long[2] st_qspare;
}
extern fn int stat(ZString str, Stat* stat) @extern("stat64");
extern fn int stat(ZString str, Stat* stat) @cname("stat64");
extern fn CInt sysctl(CInt *name, CUInt namelen, void *oldp, usz *oldlenp, void *newp, usz newlen);

View File

@@ -62,7 +62,7 @@ struct SystemInfo
ushort wProcessorRevision;
}
extern fn CInt get_system_info(SystemInfo*) @extern("GetSystemInfo");
extern fn CInt get_system_info(SystemInfo*) @cname("GetSystemInfo");
// Aliases to simplify libc use
macro Tm* localtime_r(Time_t* timer, Tm* buf) => _localtime64_s(buf, timer);

View File

@@ -506,19 +506,56 @@ fn BigInt BigInt.abs(&self)
return self.is_negative() ? self.unary_minus() : *self;
}
fn usz? BigInt.to_format(&self, Formatter* format) @dynamic
{
@stack_mem(4100; Allocator mem)
{
return format.print(self.to_string_with_radix(10, mem));
};
}
fn String BigInt.to_string(&self, Allocator allocator) @dynamic
{
return self.to_string_with_radix(10, allocator);
}
fn usz? BigInt.to_format(&self, Formatter* format) @dynamic
{
if (self.is_zero())
{
format.print("0")!;
return 1;
}
BigInt a = *self;
bool negative = self.is_negative();
usz len;
if (negative)
{
format.out('-')!;
len++;
a.negate();
}
uint[280] chunks @noinit;
int chunk_count;
const BASE10_9 = 1000000000;
foreach_r(d : self.data[:self.len])
{
ulong carry = d;
for (int i = 0; i < chunk_count; i++)
{
ulong v = (ulong)chunks[i] << 32 + carry;
carry = v / BASE10_9;
chunks[i] = (uint)(v - carry * BASE10_9);
}
if (carry)
{
ulong new_carry = carry / BASE10_9;
chunks[chunk_count++] = (uint)(carry - new_carry * BASE10_9);
if (new_carry) chunks[chunk_count++] = (uint)new_carry;
}
}
int ms = chunk_count - 1;
len += format.printf("%d", chunks[ms])!;
foreach_r (c : chunks[:ms])
{
len += format.printf("%09d", c)!;
}
return len;
}
<*
@require radix > 1 && radix <= 36 : "Radix must be 2-36"
*>
@@ -527,7 +564,7 @@ fn String BigInt.to_string_with_radix(&self, int radix, Allocator allocator)
if (self.is_zero()) return "0".copy(allocator);
const char[*] CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
@stack_mem(4100; Allocator mem)
@stack_mem(4120; Allocator mem)
{
BigInt a = *self;
DString str;

View File

@@ -6,7 +6,7 @@ import std::math::complex;
import std::math::matrix;
import std::math::quaternion;
attrdef @MathLibc(name) = @extern(name), @link(env::POSIX, "m");
attrdef @MathLibc(name) = @cname(name), @link(env::POSIX, "m");
const E = 2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427427466;
const LOG2E = 1.44269504088896340735992468100189214; // log2(e)
@@ -73,6 +73,11 @@ faultdef OVERFLOW, MATRIX_INVERSE_DOESNT_EXIST;
*>
macro deg_to_rad(x) => x * PI / 180;
<*
@require types::is_numerical($typeof(x)) : `The input must be a numerical value or numerical vector`
*>
macro rad_to_deg(x) => x * 180 / PI;
<*
@require types::is_numerical($typeof(x)) : `The input must be a numerical value or numerical vector`
*>
@@ -1042,8 +1047,8 @@ extern fn void _sincosf(float, float*, float*) @MathLibc("__sincosf") @if(env::D
extern fn void _sincos(double, double*, double*) @MathLibc("sincos") @if(!env::DARWIN && !env::WIN32);
extern fn void _sincosf(float, float*, float*) @MathLibc("sincosf") @if(!env::DARWIN && !env::WIN32);
fn void _sincos(double a, double* s, double* c) @extern("sincos") @if(env::WIN32) { *s = sin(a); *c = cos(a); }
fn void _sincosf(float a, float* s, float* c) @extern("sincosf") @if(env::WIN32) { *s = sin(a); *c = cos(a); }
fn void _sincos(double a, double* s, double* c) @cname("sincos") @if(env::WIN32) { *s = sin(a); *c = cos(a); }
fn void _sincosf(float a, float* s, float* c) @cname("sincosf") @if(env::WIN32) { *s = sin(a); *c = cos(a); }
extern fn double _tan(double x) @MathLibc("tan");
extern fn float _tanf(float x) @MathLibc("tanf");
@@ -1157,7 +1162,7 @@ macro bool overflow_sub(a, b, out) => $$overflow_sub(a, b, out);
@require values::@is_flat_intlike(a) &&& values::@is_flat_intlike(b) : "a and b must both be integer or integer vector based"
@require $defined(*out) &&& @typematch(*out, a) : "out must be a pointer of the same type as a and b"
*>
macro bool overflow_mul(a, b, out) => $$overflow_mul(a, b, out);
macro overflow_mul(a, b, out) => $$overflow_mul(a, b, out);
<*
@require types::is_vector($Type) || ($Type.kindof == ARRAY &&& types::is_numerical($typefrom($Type.inner)))

View File

@@ -12,7 +12,7 @@ module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
* ====================================================
*/
fn double __cos(double x, double y) @extern("__cos") @weak @nostrip
fn double __cos(double x, double y) @cname("__cos") @weak @nostrip
{
const C1 = 4.16666666666666019037e-02; /* 0x3FA55555, 0x5555554C */
const C2 = -1.38888888888741095749e-03; /* 0xBF56C16C, 0x16C15177 */

View File

@@ -22,7 +22,7 @@ const double C1 @private = 0x155553e1053a42.0p-57; /* 0.0416666233237390631894
const double C2 @private = -0x16c087e80f1e27.0p-62; /* -0.00138867637746099294692 */
const double C3 @private = 0x199342e0ee5069.0p-68; /* 0.0000243904487962774090654 */
fn float __cosdf(double x) @extern("__cosdf") @weak @nostrip
fn float __cosdf(double x) @cname("__cosdf") @weak @nostrip
{
/* Try to optimize for parallel evaluation as in __tandf.c. */
double z = x * x;

View File

@@ -13,7 +13,7 @@ union FloatInternal
}
// Based on the musl implementation
fn double fmod(double x, double y) @extern("fmod") @weak @nostrip
fn double fmod(double x, double y) @cname("fmod") @weak @nostrip
{
DoubleInternal ux = { .f = x };
DoubleInternal uy = { .f = y };
@@ -83,7 +83,7 @@ fn double fmod(double x, double y) @extern("fmod") @weak @nostrip
return ux.f;
}
fn float fmodf(float x, float y) @extern("fmodf") @weak @nostrip
fn float fmodf(float x, float y) @cname("fmodf") @weak @nostrip
{
FloatInternal ux = { .f = x };
FloatInternal uy = { .f = y };

View File

@@ -11,7 +11,7 @@ module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
* is preserved.
* ====================================================
*/
fn double __sin(double x, double y, int iy) @extern("__sin") @weak @nostrip
fn double __sin(double x, double y, int iy) @cname("__sin") @weak @nostrip
{
const S1 = -1.66666666666666324348e-01; /* 0xBFC55555, 0x55555549 */

View File

@@ -16,7 +16,7 @@ module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
* ====================================================
*/
// |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]).
fn float __sindf(double x) @extern("__sindf") @weak @nostrip
fn float __sindf(double x) @cname("__sindf") @weak @nostrip
{
const S1F = -0x15555554cbac77.0p-55; /* -0.166666666416265235595 */
const S2F = 0x111110896efbb2.0p-59; /* 0.0083333293858894631756 */

View File

@@ -27,7 +27,7 @@ const double[*] TAN_T = {
2.59073051863633712884e-05, /* 3EFB2A70, 74BF7AD4 */
};
fn double __tan(double x, double y, int odd) @extern("__tan") @weak @nostrip
fn double __tan(double x, double y, int odd) @cname("__tan") @weak @nostrip
{
const double PIO4 = 7.85398163397448278999e-01; /* 3FE921FB, 54442D18 */
const double PIO4LO = 3.06161699786838301793e-17; /* 3C81A626, 33145C07 */

View File

@@ -25,7 +25,7 @@ const double[*] TANDF = {
0x1362b9bf971bcd.0p-59, /* 0.00946564784943673166728 */
};
fn float __tandf(double x, int odd) @extern("__tandf") @weak @nostrip
fn float __tandf(double x, int odd) @cname("__tandf") @weak @nostrip
{
double z = x * x;
/*

View File

@@ -32,7 +32,7 @@ fn double _r(double z) @local
return p / q;
}
fn double _acos(double x) @weak @extern("acos") @nostrip
fn double _acos(double x) @weak @cname("acos") @nostrip
{
uint hx = x.high_word();
uint ix = hx & 0x7fffffff;
@@ -100,7 +100,7 @@ fn float _r_f(float z) @local
return p / q;
}
fn float _acosf(float x) @weak @extern("acosf") @nostrip
fn float _acosf(float x) @weak @cname("acosf") @nostrip
{
uint hx = bitcast(x, uint);
uint ix = hx & 0x7fffffff;

View File

@@ -32,7 +32,7 @@ fn double _r(double z) @local
return p / q;
}
fn double _asin(double x) @weak @extern("asin") @nostrip
fn double _asin(double x) @weak @cname("asin") @nostrip
{
uint hx = x.high_word();
uint ix = hx & 0x7fffffff;
@@ -102,7 +102,7 @@ fn float _r_f(float z) @local
return p / q;
}
fn float _asinf(float x) @weak @extern("asinf") @nostrip
fn float _asinf(float x) @weak @cname("asinf") @nostrip
{
uint hx = bitcast(x, uint);
uint ix = hx & 0x7fffffff;

View File

@@ -40,7 +40,7 @@ const double[*] AT @private = {
1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */
};
fn double _atan(double x) @weak @extern("atan") @nostrip
fn double _atan(double x) @weak @cname("atan") @nostrip
{
int id @noinit;
uint ix = x.high_word();
@@ -138,7 +138,7 @@ const float[*] ATF @private = {
6.1687607318e-02,
};
fn float _atanf(float x) @weak @extern("atanf") @nostrip
fn float _atanf(float x) @weak @cname("atanf") @nostrip
{
int id @noinit;
uint ix = x.word();
@@ -217,7 +217,7 @@ fn float _atanf(float x) @weak @extern("atanf") @nostrip
const PI_LO @private = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */
fn double _atan2(double y, double x) @weak @extern("atan2") @nostrip
fn double _atan2(double y, double x) @weak @cname("atan2") @nostrip
{
if (math::is_nan(x) || math::is_nan(y)) return x + y;
@@ -301,7 +301,7 @@ fn double _atan2(double y, double x) @weak @extern("atan2") @nostrip
const float PI_F @private = 3.1415927410e+00; /* 0x40490fdb */
const float PI_LO_F @private = -8.7422776573e-08; /* 0xb3bbbd2e */
fn float _atan2f(float y, float x) @weak @extern("atan2f") @nostrip
fn float _atan2f(float y, float x) @weak @cname("atan2f") @nostrip
{
if (math::is_nan(x) || math::is_nan(y)) return x + y;
uint ix = x.word();

View File

@@ -12,7 +12,7 @@ module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
* ====================================================
*/
fn double _atanh(double x) @weak @extern("atanh") @nostrip
fn double _atanh(double x) @weak @cname("atanh") @nostrip
{
double t @noinit;
uint hx = x.high_word();
@@ -61,7 +61,7 @@ fn double _atanh(double x) @weak @extern("atanh") @nostrip
* ====================================================
*/
fn float _atanhf(float x) @weak @extern("atanhf") @nostrip
fn float _atanhf(float x) @weak @cname("atanhf") @nostrip
{
float t @noinit;
uint hx = bitcast(x, uint);

View File

@@ -1,6 +1,6 @@
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
fn double _ceil(double x) @weak @extern("ceil") @nostrip
fn double _ceil(double x) @weak @cname("ceil") @nostrip
{
ulong ui = bitcast(x, ulong);
int e = (int)((ui >> 52) & 0x7ff);
@@ -17,7 +17,7 @@ fn double _ceil(double x) @weak @extern("ceil") @nostrip
}
fn float _ceilf(float x) @weak @extern("ceilf") @nostrip
fn float _ceilf(float x) @weak @cname("ceilf") @nostrip
{
uint u = bitcast(x, uint);
int e = (int)((u >> 23) & 0xff) - 0x7f;

View File

@@ -1,6 +1,6 @@
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
fn float _cosf(float x) @extern("cosf") @weak @nostrip
fn float _cosf(float x) @cname("cosf") @weak @nostrip
{
uint ix = x.word();
uint sign = ix >> 31;
@@ -51,7 +51,7 @@ fn float _cosf(float x) @extern("cosf") @weak @nostrip
* ====================================================
*/
fn double _cos(double x) @extern("cos") @weak @nostrip
fn double _cos(double x) @cname("cos") @weak @nostrip
{
// High word of x.
uint ix = x.high_word() & 0x7fffffff;

View File

@@ -17,7 +17,7 @@ const float EXPF_P2 = -2.7777778450e-03f;
const float EXPF_P3 = 6.6137559770e-05f;
const float EXPF_P4 = -1.6533901999e-06f;
fn double exp(double x) @extern("exp") @nostrip @weak
fn double exp(double x) @cname("exp") @nostrip @weak
{
if (x != x) return x;
if (x == double.inf) return double.inf;
@@ -38,7 +38,7 @@ fn double exp(double x) @extern("exp") @nostrip @weak
return ldexp(exp_r, (int)k);
}
fn float expf(float x) @extern("expf") @nostrip @weak
fn float expf(float x) @cname("expf") @nostrip @weak
{
if (x != x) return x;
if (x == float.inf) return float.inf;

View File

@@ -3,7 +3,7 @@ module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
macro uint _top12f(float x) @private => bitcast(x, uint) >> 20;
fn float _exp2f(float x) @extern("exp2f") @weak @nostrip
fn float _exp2f(float x) @cname("exp2f") @weak @nostrip
{
double xd = x;
uint abstop = _top12f(x) & 0x7ff;
@@ -80,7 +80,7 @@ macro uint _top12d(double x) @private
return (uint)(bitcast(x, ulong) >> 52);
}
fn double _exp2(double x) @extern("exp2") @weak @nostrip
fn double _exp2(double x) @cname("exp2") @weak @nostrip
{
uint abstop = _top12d(x) & 0x7ff;
ulong u = bitcast(x, ulong);

View File

@@ -1,13 +1,13 @@
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
fn double _fabs(double x) @weak @extern("fabs") @nostrip
fn double _fabs(double x) @weak @cname("fabs") @nostrip
{
ulong ix = bitcast(x, ulong);
ix &= ~(1ul << 63);
return bitcast(ix, double);
}
fn float _fabsf(float x) @weak @extern("fabsf") @nostrip
fn float _fabsf(float x) @weak @cname("fabsf") @nostrip
{
uint ix = bitcast(x, uint);
ix &= 0x7fffffff;

View File

@@ -1,6 +1,6 @@
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
fn double _floor(double x) @weak @extern("floor") @nostrip
fn double _floor(double x) @weak @cname("floor") @nostrip
{
ulong ui = bitcast(x, ulong);
int e = (int)((ui >> 52) & 0x7ff);
@@ -17,7 +17,7 @@ fn double _floor(double x) @weak @extern("floor") @nostrip
}
fn float _floorf(float x) @weak @extern("floorf") @nostrip
fn float _floorf(float x) @weak @cname("floorf") @nostrip
{
uint u = bitcast(x, uint);
int e = (int)((u >> 23) & 0xff) - 0x7f;

View File

@@ -1,6 +1,6 @@
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
fn double frexp(double x, int* exp) @extern("frexp")
fn double frexp(double x, int* exp) @cname("frexp")
{
uint hx = x.high_word();
uint ix = hx & 0x7fffffff;
@@ -31,7 +31,7 @@ fn double frexp(double x, int* exp) @extern("frexp")
}
}
fn float frexpf(float x, int* exp) @extern("frexpf")
fn float frexpf(float x, int* exp) @cname("frexpf")
{
uint ix = x.word();
uint hx = ix & 0x7fffffff;

View File

@@ -1,6 +1,6 @@
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
fn double ldexp(double x, int exp) @extern("ldexp")
fn double ldexp(double x, int exp) @cname("ldexp")
{
uint hx = x.high_word();
int hexp = (int)((hx & 0x7ff00000) >> 20);
@@ -35,7 +35,7 @@ fn double ldexp(double x, int exp) @extern("ldexp")
}
}
fn float ldexpf(float x, int exp) @extern("ldexpf")
fn float ldexpf(float x, int exp) @cname("ldexpf")
{
uint ix = x.word();
int hexp = (int)((ix & 0x7f800000) >> 23);

View File

@@ -19,7 +19,7 @@ const float LOGF_L4 = 2.4279078841e-01f;
const double SQRT2 = 1.41421356237309504880;
const float SQRT2F = 1.41421356237309504880f;
fn double log(double x) @extern("log") @nostrip @weak
fn double log(double x) @cname("log") @nostrip @weak
{
if (x != x) return x;
if (x < 0.0) return double.nan;
@@ -50,7 +50,7 @@ fn double log(double x) @extern("log") @nostrip @weak
return k * LOG_LN2_HI - ((hfsq - (s * (hfsq + r) + k * LOG_LN2_LO)) - f);
}
fn float logf(float x) @extern("logf") @nostrip @weak
fn float logf(float x) @cname("logf") @nostrip @weak
{
if (x != x) return x;
if (x < 0.0f) return float.nan;

View File

@@ -48,7 +48,7 @@ const LG5 @local = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */
const LG6 @local = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */
const LG7 @local = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */
fn double _log1p(double x) @weak @extern("log1p") @nostrip
fn double _log1p(double x) @weak @cname("log1p") @nostrip
{
uint hx = x.high_word();
int k = 1;
@@ -162,7 +162,7 @@ const float LG2_F @local = 0xccce13.0p-25; /* 0.40000972152 */
const float LG3_F @local = 0x91e9ee.0p-25; /* 0.28498786688 */
const float LG4_F @local = 0xf89e26.0p-26; /* 0.24279078841 */
fn float _log1pf(float x) @weak @extern("log1pf") @nostrip
fn float _log1pf(float x) @weak @cname("log1pf") @nostrip
{
uint ix = x.word();
int k = 1;

View File

@@ -1,6 +1,6 @@
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
fn double pow(double x, double y) @extern("pow")
fn double pow(double x, double y) @cname("pow")
{
if (x != x || y != y) return double.nan;
@@ -54,7 +54,7 @@ fn double pow(double x, double y) @extern("pow")
return result;
}
fn float powf(float x, float y) @extern("powf")
fn float powf(float x, float y) @cname("powf")
{
if (x != x || y != y) return float.nan;

View File

@@ -1,6 +1,6 @@
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
fn double _round(double x) @extern("round") @weak @nostrip
fn double _round(double x) @cname("round") @weak @nostrip
{
ulong u = bitcast(x, ulong);
int e = (int)((u >> 52) & 0x7ff);
@@ -26,7 +26,7 @@ fn double _round(double x) @extern("round") @weak @nostrip
return y;
}
fn float _roundf(float x) @extern("roundf") @weak @nostrip
fn float _roundf(float x) @cname("roundf") @weak @nostrip
{
uint u = bitcast(x, uint);
int e = (u >> 23) & 0xff;

View File

@@ -1,6 +1,6 @@
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
fn double _scalbn(double x, int n) @weak @extern("scalbn") @nostrip
fn double _scalbn(double x, int n) @weak @cname("scalbn") @nostrip
{
switch
{

View File

@@ -16,7 +16,7 @@ module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
* ====================================================
*/
fn float _sinf(float x) @weak @extern("sinf") @nostrip
fn float _sinf(float x) @weak @cname("sinf") @nostrip
{
uint ix = x.word();
int sign = ix >> 31;
@@ -84,7 +84,7 @@ fn float _sinf(float x) @weak @extern("sinf") @nostrip
* ====================================================
*/
fn double sin(double x) @extern("sin") @weak @nostrip
fn double sin(double x) @cname("sin") @weak @nostrip
{
// High word of x.
uint ix = x.high_word() & 0x7fffffff;

View File

@@ -16,7 +16,7 @@ module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
* ====================================================
*/
fn void sincosf(float x, float *sin, float *cos) @extern("__sincosf") @weak @nostrip
fn void sincosf(float x, float *sin, float *cos) @cname("__sincosf") @weak @nostrip
{
uint ix = x.word();
uint sign = ix >> 31;
@@ -104,7 +104,7 @@ fn void sincosf(float x, float *sin, float *cos) @extern("__sincosf") @weak @nos
}
fn void sincos(double x, double *sin, double *cos) @extern("__sincos") @weak @nostrip
fn void sincos(double x, double *sin, double *cos) @cname("__sincos") @weak @nostrip
{
// High word of x.
uint ix = x.high_word() & 0x7fffffff;

View File

@@ -12,7 +12,7 @@ module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
* ====================================================
*/
fn double tan(double x) @extern("tan") @weak @nostrip
fn double tan(double x) @cname("tan") @weak @nostrip
{
uint ix = x.high_word();
ix &= 0x7fffffff;
@@ -57,7 +57,7 @@ fn double tan(double x) @extern("tan") @weak @nostrip
* ====================================================
*/
fn float tanf(float x) @extern("tanf") @weak @nostrip
fn float tanf(float x) @cname("tanf") @weak @nostrip
{
uint ix = x.word();
uint sign = ix >> 31;

View File

@@ -1,6 +1,6 @@
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
fn double sincos_broken(double x) @extern("sincos") @weak @nostrip
fn double sincos_broken(double x) @cname("sincos") @weak @nostrip
{
unreachable("'sinccos' not supported");
}

View File

@@ -1,6 +1,6 @@
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
fn double _trunc(double x) @weak @extern("trunc") @nostrip
fn double _trunc(double x) @weak @cname("trunc") @nostrip
{
ulong i = bitcast(x, ulong);
int e = (int)((i >> 52) & 0x7ff) - 0x3ff + 12;
@@ -13,7 +13,7 @@ fn double _trunc(double x) @weak @extern("trunc") @nostrip
return bitcast(i, double);
}
fn float _truncf(float x) @weak @extern("truncf") @nostrip
fn float _truncf(float x) @weak @cname("truncf") @nostrip
{
uint i = bitcast(x, uint);
int e = (int)((i >> 23) & 0xff) - 0x7f + 9;

View File

@@ -32,12 +32,15 @@ macro QuaternionNumber QuaternionNumber.sub(self, QuaternionNumber b) @operator(
macro QuaternionNumber QuaternionNumber.negate(self) @operator(-) => { .v = -self.v };
macro QuaternionNumber QuaternionNumber.sub_each(self, Real b) => { .v = self.v - b };
macro QuaternionNumber QuaternionNumber.scale(self, Real s) @operator_s(*) => { .v = self.v * s };
macro QuaternionNumber.to_angle(self) => 2 * math::acos(self.v.w);
macro QuaternionNumber QuaternionNumber.normalize(self) => { .v = self.v.normalize() };
macro Real QuaternionNumber.length(self) => self.v.length();
macro QuaternionNumber QuaternionNumber.lerp(self, QuaternionNumber q2, Real amount) => { .v = self.v.lerp(q2.v, amount) };
fn QuaternionNumber QuaternionNumber.nlerp(self, QuaternionNumber q2, Real amount) => { .v = self.v.lerp(q2.v, amount).normalize() };
macro Matrix4f QuaternionNumber.to_matrixf(&self) => into_matrix(self, Matrix4f);
macro Matrix4 QuaternionNumber.to_matrix(&self) => into_matrix(self, Matrix4);
fn QuaternionNumber QuaternionNumber.nlerp(self, QuaternionNumber q2, Real amount) => { .v = self.v.lerp(q2.v, amount).normalize() };
fn QuaternionNumber QuaternionNumber.invert(self)
{
@@ -47,6 +50,8 @@ fn QuaternionNumber QuaternionNumber.invert(self)
return { self.v[0] * -inv_length, self.v[1] * -inv_length, self.v[2] * -inv_length, self.v[3] * inv_length };
}
fn QuaternionNumber QuaternionNumber.conjugate(&self) => { -self.v.x, -self.v.y, -self.v.z, self.v.w };
fn QuaternionNumber QuaternionNumber.slerp(self, QuaternionNumber q2, Real amount)
{
QuaternionNumber result = {};
@@ -77,13 +82,35 @@ fn QuaternionNumber QuaternionNumber.slerp(self, QuaternionNumber q2, Real amoun
}
fn QuaternionNumber QuaternionNumber.mul(self, QuaternionNumber b) @operator(*)
{
return { self.i * b.l + self.l * b.i + self.j * b.k - self.k * b.j,
self.j * b.l + self.l * b.j + self.k * b.i - self.i * b.k,
self.k * b.l + self.l * b.k + self.i * b.j - self.j * b.i,
self.l * b.l - self.i * b.i - self.j * self.j - self.k * self.k };
{
Real[<3>] q1_axis = { self.v.x, self.v.y, self.v.z };
Real[<3>] q2_axis = { b.v.x, b.v.y, b.v.z };
Real scalar = (self.v.w * b.v.w - q1_axis.dot(q2_axis));
Real[<3>] axis = self.v.w * q2_axis + b.v.w * q1_axis + q1_axis.cross(q2_axis);
return { ...axis, scalar };
}
fn QuaternionNumber from_axis_angle(Real[<3>] axis, Real angle)
{
Real[<3>] normal_axis = axis.normalize();
Real half_angle = angle * 0.5;
Real sin_half = math::sin(half_angle);
return { ...(normal_axis * sin_half), math::cos(half_angle) };
}
fn Real[<3>] QuaternionNumber.rotate_vec3(self, Real[<3>] vector) @operator(*)
{
QuaternionNumber p = { ...vector, 0 };
QuaternionNumber result = self * p * self.conjugate();
return result.v.xyz;
}
macro into_matrix(QuaternionNumber* q, $Type) @private
{
QuaternionNumber rotation = q.normalize();
@@ -93,9 +120,9 @@ macro into_matrix(QuaternionNumber* q, $Type) @private
var w = rotation.l;
return ($Type) {
1 - 2*y*y - 2*z*z, 2*x*y - 2*z*w, 2*x*z + 2*y*w, 0,
2*x*y + 2*z*w, 1 - 2*x*x - 2*z*z, 2*y*z - 2*x*w, 0,
2*x*z - 2*y*w, 2*y*z + 2*x*w , 1 - 2*x*x - 2*y*y, 0,
0.0, 0.0, 0.0, 1.0,
1 - 2*y*y - 2*z*z, 2*x*y - 2*z*w, 2*x*z + 2*y*w, 0,
2*x*y + 2*z*w, 1 - 2*x*x - 2*z*z, 2*y*z - 2*x*w, 0,
2*x*z - 2*y*w, 2*y*z + 2*x*w, 1 - 2*x*x - 2*y*y, 0,
0.0, 0.0, 0.0, 1.0,
};
}

View File

@@ -1,6 +1,6 @@
module std::math::math_rt;
fn int128 __divti3(int128 a, int128 b) @extern("__divti3") @weak @nostrip
fn int128 __divti3(int128 a, int128 b) @cname("__divti3") @weak @nostrip
{
int128 sign_a = a >> 127; // -1 : 0
int128 sign_b = b >> 127; // -1 : 0
@@ -182,17 +182,17 @@ macro uint128 @__udivmodti4(uint128 a, uint128 b, bool $return_rem)
$endif
}
fn uint128 __umodti3(uint128 n, uint128 d) @extern("__umodti3") @weak @nostrip
fn uint128 __umodti3(uint128 n, uint128 d) @cname("__umodti3") @weak @nostrip
{
return @__udivmodti4(n, d, true);
}
fn uint128 __udivti3(uint128 n, uint128 d) @extern("__udivti3") @weak @nostrip
fn uint128 __udivti3(uint128 n, uint128 d) @cname("__udivti3") @weak @nostrip
{
return @__udivmodti4(n, d, false);
}
fn int128 __modti3(int128 a, int128 b) @extern("__modti3") @weak @nostrip
fn int128 __modti3(int128 a, int128 b) @cname("__modti3") @weak @nostrip
{
int128 sign = b >> 127;
uint128 unsigned_b = (uint128)(b ^ sign) + (-sign);
@@ -212,7 +212,7 @@ union Int128bits @private
uint128 all;
}
fn uint128 __lshrti3(uint128 a, uint b) @extern("__lshrti3") @weak @nostrip
fn uint128 __lshrti3(uint128 a, uint b) @cname("__lshrti3") @weak @nostrip
{
Int128bits result;
result.all = a;
@@ -230,7 +230,7 @@ fn uint128 __lshrti3(uint128 a, uint b) @extern("__lshrti3") @weak @nostrip
return result.all;
}
fn int128 __ashrti3(int128 a, uint b) @extern("__ashrti3") @weak @nostrip
fn int128 __ashrti3(int128 a, uint b) @cname("__ashrti3") @weak @nostrip
{
Int128bits result;
result.all = a;
@@ -248,7 +248,7 @@ fn int128 __ashrti3(int128 a, uint b) @extern("__ashrti3") @weak @nostrip
return result.all;
}
fn int128 __ashlti3(int128 a, uint b) @extern("__ashlti3") @weak @nostrip
fn int128 __ashlti3(int128 a, uint b) @cname("__ashlti3") @weak @nostrip
{
Int128bits result;
result.all = a;
@@ -287,7 +287,7 @@ fn int128 __mulddi3(ulong a, ulong b) @private
return r.all;
}
fn int128 __multi3(int128 a, int128 b) @extern("__multi3") @weak @nostrip
fn int128 __multi3(int128 a, int128 b) @cname("__multi3") @weak @nostrip
{
Int128bits x = { .all = a };
Int128bits y = { .all = b };
@@ -296,14 +296,14 @@ fn int128 __multi3(int128 a, int128 b) @extern("__multi3") @weak @nostrip
return r.all;
}
fn float __floattisf(int128 a) @extern("__floattisf") @weak @nostrip => float_from_i128(float, a);
fn double __floattidf(int128 a) @extern("__floattidf") @weak @nostrip => float_from_i128(double, a);
fn float __floatuntisf(uint128 a) @extern("__floatuntisf") @weak @nostrip => float_from_u128(float, a);
fn double __floatuntidf(uint128 a) @extern("__floatuntidf") @weak @nostrip => float_from_u128(double, a);
fn uint128 __fixunsdfti(double a) @weak @extern("__fixunsdfti") @nostrip => fixuint(a);
fn uint128 __fixunssfti(float a) @weak @extern("__fixunssfti") @nostrip => fixuint(a);
fn int128 __fixdfti(double a) @weak @extern("__fixdfti") @nostrip => fixint(a);
fn int128 __fixsfti(float a) @weak @extern("__fixsfti") @nostrip => fixint(a);
fn float __floattisf(int128 a) @cname("__floattisf") @weak @nostrip => float_from_i128(float, a);
fn double __floattidf(int128 a) @cname("__floattidf") @weak @nostrip => float_from_i128(double, a);
fn float __floatuntisf(uint128 a) @cname("__floatuntisf") @weak @nostrip => float_from_u128(float, a);
fn double __floatuntidf(uint128 a) @cname("__floatuntidf") @weak @nostrip => float_from_u128(double, a);
fn uint128 __fixunsdfti(double a) @weak @cname("__fixunsdfti") @nostrip => fixuint(a);
fn uint128 __fixunssfti(float a) @weak @cname("__fixunssfti") @nostrip => fixuint(a);
fn int128 __fixdfti(double a) @weak @cname("__fixdfti") @nostrip => fixint(a);
fn int128 __fixsfti(float a) @weak @cname("__fixsfti") @nostrip => fixint(a);
macro float_from_i128($Type, a) @private

View File

@@ -8,7 +8,7 @@ macro force_eval_add(x, v)
@volatile_store(temp, x + v);
}
fn double __roundeven(double x) @extern("roundeven") @weak @nostrip
fn double __roundeven(double x) @cname("roundeven") @weak @nostrip
{
ulong u = bitcast(x, ulong);
int e = (int)((u >> 52) & 0x7ff);
@@ -42,7 +42,7 @@ fn double __roundeven(double x) @extern("roundeven") @weak @nostrip
return y;
}
fn float __roundevenf(float x) @extern("roundevenf") @weak @nostrip
fn float __roundevenf(float x) @cname("roundevenf") @weak @nostrip
{
uint u = bitcast(x, uint);
int e = (u >> 23) & 0xff;
@@ -75,7 +75,7 @@ fn float __roundevenf(float x) @extern("roundevenf") @weak @nostrip
return y;
}
fn double __powidf2(double a, int b) @extern("__powidf2") @weak @nostrip
fn double __powidf2(double a, int b) @cname("__powidf2") @weak @nostrip
{
bool recip = b < 0;
double r = 1;

View File

@@ -41,8 +41,8 @@ fn double double[<3>].angle(self, double[<3>] v2) => angle3(self, v2);
fn float[<3>] float[<3>].refract(self, float[<3>] n, float r) => refract3(self, n, r);
fn double[<3>] double[<3>].refract(self, double[<3>] n, double r) => refract3(self, n, r);
fn float[<3>] float[<3>].rotate_quat(self, Quaternionf q) => rotate_by_quat3(self, q);
fn double[<3>] double[<3>].rotate_quat(self, Quaternion q) => rotate_by_quat3(self, q);
fn float[<3>] float[<3>].rotate_quat(self, Quaternionf q) => q * self;
fn double[<3>] double[<3>].rotate_quat(self, Quaternion q) => q * self;
fn float[<3>] float[<3>].rotate_axis(self, float[<3>] axis, float angle) => rotate_axis_angle(self, axis, angle);
fn double[<3>] double[<3>].rotate_axis(self, double[<3>] axis, double angle) => rotate_axis_angle(self, axis, angle);
@@ -144,21 +144,6 @@ macro void ortho_normalize3(v1, v2) @private
*v2 = v1n.cross(vn1);
}
macro rotate_by_quat3(v, q) @private
{
return ($typeof(v)){
v[0] * (q.i * q.i + q.l * q.l - q.j * q.j - q.k * q.k)
+ v[1] * (2 * q.i * q.j - 2 * q.l * q.k)
+ v[2] * (2 * q.i * q.k - 2 * q.l * q.j),
v[0] * (2 * q.l * q.k + 2 * q.i * q.j)
+ v[1] * (q.l * q.l - q.i * q.i + q.j * q.j - q.k * q.k)
+ v[2] * (-2 * q.l * q.i + 2 * q.j * q.k),
v[0] * (-2 * q.l * q.j + 2 * q.i * q.k)
+ v[1] * (2 * q.l * q.i + 2 * q.j * q.k)
+ v[2] * (q.l * q.l - q.i * q.i - q.j * q.j + q.k * q.k)
};
}
macro rotate_axis_angle(v, axis, angle) @private
{
axis = axis.normalize();

View File

@@ -22,6 +22,7 @@ extern fn CInt bind(NativeSocket socket, SockAddrPtr address, Socklen_t address_
extern fn CInt listen(NativeSocket socket, CInt backlog);
extern fn NativeSocket accept(NativeSocket socket, SockAddrPtr address, Socklen_t* address_len);
extern fn CInt poll(Posix_pollfd* fds, Posix_nfds_t nfds, CInt timeout);
extern fn CInt socketpair(AIFamily domain, AISockType type, CInt protocol, NativeSocket[2]* sv);
const CUShort POLLIN = 0x0001;
const CUShort POLLPRI = 0x0002;

View File

@@ -1,5 +1,9 @@
module std::net::os @if(env::WIN32);
import std::os, std::io, libc;
import std::os, std::io, libc, std::thread;
import std::core::mem;
import std::os::win32;
const AIFamily PLATFORM_AF_IPX = 6;
const AIFamily PLATFORM_AF_APPLETALK = 16;
@@ -21,6 +25,33 @@ extern fn int connect(NativeSocket, SockAddrPtr address, Socklen_t address_len);
extern fn int bind(NativeSocket, SockAddrPtr address, Socklen_t address_len);
extern fn int listen(NativeSocket, int backlog);
extern fn NativeSocket accept(NativeSocket, SockAddrPtr address, Socklen_t* address_len);
extern fn CInt getsockname(NativeSocket socket, SockAddrPtr address, Socklen_t* address_len);
char[408] wsa_data @local;
int wsa_init @local;
macro void? start_wsa()
{
if (mem::compare_exchange(&wsa_init, 0, 1) == 0)
{
Win32_WORD version = 0x0202;
CInt wsa_error = win32::wsaStartup(version, &wsa_data);
if (wsa_error > 0)
{
mem::@atomic_store(wsa_init, 0);
return os::socket_error()?;
}
}
}
fn void close_wsa()
{
if (mem::compare_exchange(&wsa_init, 1, 0) == 1)
{
win32::wsaCleanup();
mem::@atomic_store(wsa_init, 0);
}
}
macro bool NativeSocket.is_valid(self)
{

View File

@@ -1,5 +1,9 @@
module std::net @if(os::SUPPORTS_INET);
import std::time, libc, std::os;
import std::core::env;
import std::net::os;
macro void? apply_sockoptions(sockfd, options) @private
{
@@ -9,6 +13,9 @@ macro void? apply_sockoptions(sockfd, options) @private
fn Socket? connect_from_addrinfo(AddrInfo* addrinfo, SocketOption[] options) @private
{
$if env::WIN32:
os::start_wsa()!;
$endif
@loop_over_ai(addrinfo; NativeSocket sockfd, AddrInfo* ai)
{
apply_sockoptions(sockfd, options)!;
@@ -37,6 +44,9 @@ fn bool last_error_is_delayed_connect()
fn Socket? connect_with_timeout_from_addrinfo(AddrInfo* addrinfo, SocketOption[] options, Duration timeout) @private
{
$if env::WIN32:
os::start_wsa()!;
$endif
Clock c = 0;
@loop_over_ai(addrinfo; NativeSocket sockfd, AddrInfo* ai)
{
@@ -82,6 +92,9 @@ fn Socket? connect_with_timeout_from_addrinfo(AddrInfo* addrinfo, SocketOption[]
fn Socket? connect_async_from_addrinfo(AddrInfo* addrinfo, SocketOption[] options) @private
{
$if env::WIN32:
os::start_wsa()!;
$endif
@loop_over_ai(addrinfo; NativeSocket sockfd, AddrInfo* ai)
{
apply_sockoptions(sockfd, options)!;
@@ -98,6 +111,9 @@ fn Socket? connect_async_from_addrinfo(AddrInfo* addrinfo, SocketOption[] option
macro void @network_loop_over_ai(network, host, port; @body(fd, ai)) @private
{
$if env::WIN32:
os::start_wsa()!;
$endif
AddrInfo* ai = network.addrinfo(host, port)!;
AddrInfo* first = ai;
defer os::freeaddrinfo(first);

View File

@@ -1,6 +1,11 @@
module std::net::tcp @if(os::SUPPORTS_INET);
import std::net @public;
import std::time, libc;
import std::os::win32;
import std::core::env;
import std::net::os;
typedef TcpSocket = inline Socket;
typedef TcpServerSocket = inline Socket;
@@ -44,6 +49,9 @@ fn TcpSocket? accept(TcpServerSocket* server_socket)
{
TcpSocket socket;
socket.ai_addrlen = socket.ai_addr_storage.len;
$if env::WIN32:
os::start_wsa()!;
$endif
socket.sock = os::accept(server_socket.sock, (SockAddrPtr)&socket.ai_addr_storage, &socket.ai_addrlen);
if (!socket.sock.is_valid()) return net::ACCEPT_FAILED?;
return socket;
@@ -51,6 +59,9 @@ fn TcpSocket? accept(TcpServerSocket* server_socket)
fn TcpServerSocket? listen_to(AddrInfo* ai, uint backlog, SocketOption... options)
{
$if env::WIN32:
os::start_wsa()!;
$endif
net::@loop_over_ai(ai; NativeSocket sockfd, AddrInfo* ai_candidate)
{
net::apply_sockoptions(sockfd, options)!;
@@ -60,4 +71,55 @@ fn TcpServerSocket? listen_to(AddrInfo* ai, uint backlog, SocketOption... option
return os::socket_error()?;
}
struct TcpSocketPair
{
TcpSocket send;
TcpSocket recv;
}
fn TcpSocketPair*? TcpSocketPair.init(&self)
{
$if env::WIN32:
os::start_wsa()!;
TcpServerSocket listen_sock = tcp::listen("127.0.0.1", 0, 0)!;
TcpSocket listen_sock_info;
listen_sock_info.ai_addrlen = listen_sock.ai_addr_storage.len;
int sock_result = os::getsockname(listen_sock.sock, (SockAddrPtr) &listen_sock_info.ai_addr_storage, &listen_sock_info.ai_addrlen);
if (sock_result < 0) return os::socket_error()?;
char[] listen_port_bytes = listen_sock_info.ai_addr_storage[2:2];
char msb = listen_port_bytes[0];
char lsb = listen_port_bytes[1];
int listen_port = (msb << 8) | lsb;
defer (void)listen_sock.close();
TcpSocket tcp_send_sock = tcp::connect_async("127.0.0.1", listen_port)!;
TcpSocket tcp_recv_sock = tcp::accept(&listen_sock)!;
$else
NativeSocket[2] sockets;
isz sockpair_result = os::socketpair(os::AF_UNIX, os::SOCK_STREAM, 0, &sockets);
if (sockpair_result < 0) return os::socket_error()?;
Socket send_sock = { .sock = sockets[0] };
TcpSocket tcp_send_sock = (TcpSocket) send_sock;
Socket recv_sock = { .sock = sockets[1] };
TcpSocket tcp_recv_sock = (TcpSocket) recv_sock;
$endif
*self = { .send = tcp_send_sock, .recv = tcp_recv_sock };
return self;
}
fn void? TcpSocketPair.destroy(&self)
{
{
defer catch (void)self.recv.close();
self.send.close()!;
}
self.recv.close()!;
}

View File

@@ -40,30 +40,30 @@ struct LogMessage @packed
ZString message;
}
extern fn CInt log_write(LogPriority prio, ZString tag, ZString text) @extern("__android_log_write");
extern fn CInt log_print(LogPriority prio, ZString tag, ZString fmt, ...) @extern("__android_log_print");
extern fn void log_assert(ZString cond, ZString tag, ZString fmt, ...) @extern("__android_log_assert");
extern fn CInt log_write(LogPriority prio, ZString tag, ZString text) @cname("__android_log_write");
extern fn CInt log_print(LogPriority prio, ZString tag, ZString fmt, ...) @cname("__android_log_print");
extern fn void log_assert(ZString cond, ZString tag, ZString fmt, ...) @cname("__android_log_assert");
fn bool log_id_is_valid(LogId id)
{
return id >= LOG_ID_MIN && id < LOG_ID_MAX;
}
extern fn CInt log_buf_write(CInt bufID, CInt prio, ZString tag, ZString text) @extern("__android_log_buf_write");
extern fn CInt log_buf_print(CInt bufID, CInt prio, ZString tag, ZString fmt, ...) @extern("__android_log_buf_print");
extern fn CInt log_buf_write(CInt bufID, CInt prio, ZString tag, ZString text) @cname("__android_log_buf_write");
extern fn CInt log_buf_print(CInt bufID, CInt prio, ZString tag, ZString fmt, ...) @cname("__android_log_buf_print");
alias LoggerFunction = fn void(LogMessage* log_message);
alias AborterFunction = fn void(ZString abort_message);
extern fn void log_write_log_message(LogMessage log_message) @extern("__android_log_write_log_message");
extern fn void log_set_logger(LoggerFunction logger) @extern("__android_log_set_logger");
extern fn void log_logd_logger(LogMessage log_message) @extern("__android_log_logd_logger");
extern fn void log_stderr_logger(LogMessage log_message) @extern("__android_log_stderr_logger");
extern fn void log_set_aborter(AborterFunction aborter) @extern("__android_log_set_aborter");
extern fn void log_call_aborter(ZString abort_message) @extern("__android_log_call_aborter");
extern fn void log_default_aborter(ZString abort_message) @extern("__android_log_default_aborter");
extern fn CInt log_is_loggable(CInt prio, ZString tag, CInt default_prio) @extern("__android_log_is_loggable");
extern fn CInt log_is_loggable_len(CInt prio, ZString tag, isz len, CInt default_prio) @extern("__android_log_is_loggable_len");
extern fn CInt log_set_minimum_priority(CInt priority) @extern("__android_log_set_minimum_priority");
extern fn CInt log_get_minimum_priority() @extern("__android_log_get_minimum_priority");
extern fn void log_set_default_tag(ZString tag) @extern("__android_log_set_default_tag");
extern fn void log_write_log_message(LogMessage log_message) @cname("__android_log_write_log_message");
extern fn void log_set_logger(LoggerFunction logger) @cname("__android_log_set_logger");
extern fn void log_logd_logger(LogMessage log_message) @cname("__android_log_logd_logger");
extern fn void log_stderr_logger(LogMessage log_message) @cname("__android_log_stderr_logger");
extern fn void log_set_aborter(AborterFunction aborter) @cname("__android_log_set_aborter");
extern fn void log_call_aborter(ZString abort_message) @cname("__android_log_call_aborter");
extern fn void log_default_aborter(ZString abort_message) @cname("__android_log_default_aborter");
extern fn CInt log_is_loggable(CInt prio, ZString tag, CInt default_prio) @cname("__android_log_is_loggable");
extern fn CInt log_is_loggable_len(CInt prio, ZString tag, isz len, CInt default_prio) @cname("__android_log_is_loggable_len");
extern fn CInt log_set_minimum_priority(CInt priority) @cname("__android_log_set_minimum_priority");
extern fn CInt log_get_minimum_priority() @cname("__android_log_get_minimum_priority");
extern fn void log_set_default_tag(ZString tag) @cname("__android_log_set_default_tag");

View File

@@ -10,9 +10,9 @@ macro void* CFAllocatorRef.alloc(CFAllocatorRef allocator, usz size) => macos_CF
macro usz CFAllocatorRef.get_preferred_size(CFAllocatorRef allocator, usz req_size) => macos_CFAllocatorGetPreferredSizeForSize(allocator, req_size, 0);
macro void CFAllocatorRef.set_default(CFAllocatorRef allocator) => macos_CFAllocatorSetDefault(allocator);
extern fn CFAllocatorRef macos_CFAllocatorCreate(CFAllocatorRef allocator, CFAllocatorContextRef context) @extern("CFAllocatorCreate") @builtin;
extern fn void macos_CFAllocatorDeallocate(CFAllocatorRef allocator, void* ptr) @extern("CFAllocatorDeallocate") @builtin;
extern fn CFAllocatorRef macos_CFAllocatorGetDefault() @extern("CFAllocatorGetDefault") @builtin;
extern fn void macos_CFAllocatorSetDefault(CFAllocatorRef allocator) @extern("CFAllocatorSetDefault") @builtin;
extern fn void* macos_CFAllocatorAllocate(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) @extern("CFAllocatorAllocate") @builtin;
extern fn CFIndex macos_CFAllocatorGetPreferredSizeForSize(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) @extern("CFAllocatorGetPreferredSizeForSize") @builtin;
extern fn CFAllocatorRef macos_CFAllocatorCreate(CFAllocatorRef allocator, CFAllocatorContextRef context) @cname("CFAllocatorCreate") @builtin;
extern fn void macos_CFAllocatorDeallocate(CFAllocatorRef allocator, void* ptr) @cname("CFAllocatorDeallocate") @builtin;
extern fn CFAllocatorRef macos_CFAllocatorGetDefault() @cname("CFAllocatorGetDefault") @builtin;
extern fn void macos_CFAllocatorSetDefault(CFAllocatorRef allocator) @cname("CFAllocatorSetDefault") @builtin;
extern fn void* macos_CFAllocatorAllocate(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) @cname("CFAllocatorAllocate") @builtin;
extern fn CFIndex macos_CFAllocatorGetPreferredSizeForSize(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) @cname("CFAllocatorGetPreferredSizeForSize") @builtin;

View File

@@ -6,13 +6,13 @@ typedef CFArrayCallBacksRef = void*;
typedef CFMutableArray = inline CFArray;
typedef CFMutableArrayRef = CFMutableArray*;
extern fn CFIndex CFArray.getCount(&self) @extern("CFArrayGetCount");
extern fn void* CFArray.getValueAtIndex(&self, CFIndex i) @extern("CFArrayGetValueAtIndex");
extern fn CFIndex CFArray.getCount(&self) @cname("CFArrayGetCount");
extern fn void* CFArray.getValueAtIndex(&self, CFIndex i) @cname("CFArrayGetValueAtIndex");
extern fn CFArrayRef macos_CFArrayCreate(CFAllocatorRef allocator, void** values, CFIndex num_values, CFArrayCallBacksRef callBacks) @extern("CFArrayCreate") @builtin;
extern fn CFArrayRef macos_CFArrayCopy(CFAllocatorRef allocator, CFArrayRef array) @extern("CFArrayCopy") @builtin;
extern fn void CFMutableArray.appendArray(&self, CFArrayRef otherArray, CFRange otherRange) @extern("CFArrayAppendArray");
extern fn void CFMutableArray.appendValue(&self, void *value) @extern("CFArrayAppendValue");
extern fn CFArrayRef macos_CFArrayCreate(CFAllocatorRef allocator, void** values, CFIndex num_values, CFArrayCallBacksRef callBacks) @cname("CFArrayCreate") @builtin;
extern fn CFArrayRef macos_CFArrayCopy(CFAllocatorRef allocator, CFArrayRef array) @cname("CFArrayCopy") @builtin;
extern fn void CFMutableArray.appendArray(&self, CFArrayRef otherArray, CFRange otherRange) @cname("CFArrayAppendArray");
extern fn void CFMutableArray.appendValue(&self, void *value) @cname("CFArrayAppendValue");
extern fn CFMutableArrayRef macos_CFArrayCreateMutable(CFAllocatorRef allocator, CFIndex capacity, CFArrayCallBacksRef callBacks) @extern("CFArrayCreateMutable") @builtin;
extern fn CFMutableArrayRef macos_CFArrayCreateMutable(CFAllocatorRef allocator, CFIndex capacity, CFArrayCallBacksRef callBacks) @cname("CFArrayCreateMutable") @builtin;

View File

@@ -1,3 +1,3 @@
module std::os::darwin::cocoa @if(env::OS_TYPE == MACOS) @link("Cocoa.framework");
extern fn int nsApplicationMain(int argc, char **argv) @extern("NSApplicationMain");
extern fn int nsApplicationMain(int argc, char **argv) @cname("NSApplicationMain");

View File

@@ -13,12 +13,32 @@ struct CFRange
CFIndex length;
}
extern fn ZString CFString.getCStringPtr(&self, CFStringEncoding encoding) @extern("CFStringGetCStringPtr");
extern fn ZString CFString.getCString(&self, char* buffer, usz len, CFStringEncoding encoding) @extern("CFStringGetCString");
alias CGFloat = $typefrom(env::ARCH_64_BIT ??? double : float);
extern fn CFTypeRef CFType.retain(&self) @extern("CFRetain");
extern fn void CFType.release(&self) @extern("CFRelease");
extern fn CFIndex CFType.getRetainCount(&self) @extern("CFGetRetainCount");
struct CGPoint
{
CGFloat x;
CGFloat y;
}
struct CGSize
{
CGFloat width;
CGFloat height;
}
struct CGRect
{
CGPoint origin;
CGSize size;
}
extern fn ZString CFString.getCStringPtr(&self, CFStringEncoding encoding) @cname("CFStringGetCStringPtr");
extern fn ZString CFString.getCString(&self, char* buffer, usz len, CFStringEncoding encoding) @cname("CFStringGetCString");
extern fn CFTypeRef CFType.retain(&self) @cname("CFRetain");
extern fn void CFType.release(&self) @cname("CFRelease");
extern fn CFIndex CFType.getRetainCount(&self) @cname("CFGetRetainCount");
enum CFStringEncoding : const uint
{

View File

@@ -37,7 +37,7 @@ const HW_L3CACHESIZE = 22; /* int: L3 Cache Size in Bytes */
const HW_MAXID = 23; /* number of valid hw ids */
extern fn CInt sysctl(CInt *name, CUInt namelen, void *oldp, usz *oldlenp, void *newp, usz newlen);
extern fn CInt darwin_NSGetExecutablePath(char* buffer, uint *size) @extern("_NSGetExecutablePath") @builtin;
extern fn CInt darwin_NSGetExecutablePath(char* buffer, uint *size) @cname("_NSGetExecutablePath") @builtin;
extern fn Darwin_segment_command_64* getsegbyname(ZString segname);
extern fn uint _dyld_image_count();
extern fn ZString _dyld_get_image_name(uint image_index);
@@ -88,8 +88,8 @@ fn String? executable_path()
char[4096] buf;
uint temp_len = buf.len;
if (darwin_NSGetExecutablePath(&buf, &temp_len) < 0) return NOT_FOUND?;
path[:len] = buf[:len];
len = (int)((ZString)&buf).len();
path[:len] = buf[:len];
}
return (String)path[:len];
}

View File

@@ -42,7 +42,7 @@ enum NSSearchPathDirectory : const NSUInteger
}
// real signature in Foundation
extern fn CFArrayRef nsSearchPathForDirectoriesInDomains(NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask, bool expandTilde) @extern("NSSearchPathForDirectoriesInDomains");
extern fn CFArrayRef nsSearchPathForDirectoriesInDomains(NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask, bool expandTilde) @cname("NSSearchPathForDirectoriesInDomains");

View File

@@ -18,7 +18,7 @@ macro bool ObjcSelector.equals(ObjcSelector a, ObjcSelector b) => a == b;
macro bool ObjcClass.equals(ObjcClass a, ObjcClass b) => a == b;
fn ObjcId alloc(ObjcClass cls) => objc::msg_send(cls, SendVoid, "alloc");
fn void release(ObjcId id) => objc::msg_send(id, SendVoid, "release");
fn void release(ObjcId id) => objc::msg_send(id, SendVoid, "release");
alias NSUInteger = $typefrom(env::ARCH_64_BIT ??? ulong : uint);
alias NSInteger = $typefrom(env::ARCH_64_BIT ??? long : int);
@@ -38,7 +38,7 @@ macro ObjcClass[] class_get_list(Allocator allocator)
return entries;
}
extern fn void msgSend(...) @extern("objc_msgSend") @builtin;
extern fn void msgSend(...) @cname("objc_msgSend") @builtin;
extern fn ObjcSelector sel_getUid(ZString);
macro msg_send(id, $FunctionType, ZString $selector, ...)
@@ -55,9 +55,9 @@ macro void @autoreleasepool(;@body())
extern fn void* objc_autoreleasePoolPush();
extern fn void objc_autoreleasePoolPop(void* context);
extern fn ObjcClass getClass(ZString name) @extern("objc_getClass");
extern fn int getClassList(ObjcClass* buffer, int buffer_count) @extern("objc_getClassList");
extern fn ObjcClass lookUpClass(ZString name) @extern("objc_lookUpClass") @builtin;
extern fn ObjcClass getClass(ZString name) @cname("objc_getClass");
extern fn int getClassList(ObjcClass* buffer, int buffer_count) @cname("objc_getClassList");
extern fn ObjcClass lookUpClass(ZString name) @cname("objc_lookUpClass") @builtin;
extern fn ZString class_getName(ObjcClass cls);
extern fn ObjcClass class_getSuperclass(ObjcClass cls);
@@ -67,24 +67,35 @@ extern fn ObjcSelector sel_registerName(ZString str);
extern fn bool class_addIvar(ObjcClass cls, ZString name, int size, double alignment, ZString types);
extern fn bool class_addMethod(ObjcClass cls, ObjcSelector name, void* imp, ZString types);
extern fn ObjcIvar getInstanceVariable(ObjcId id, ZString name, void* outValue) @extern("object_getInstanceVariable");
extern fn ObjcIvar setInstanceVariable(ObjcId id, ZString name, void* value) @extern("object_setInstanceVariable");
extern fn ObjcClass allocateClassPair(ObjcClass cls, ZString name, uint extraBytes) @extern("objc_allocateClassPair");
extern fn ObjcIvar getInstanceVariable(ObjcId id, ZString name, void* outValue) @cname("object_getInstanceVariable");
extern fn ObjcIvar setInstanceVariable(ObjcId id, ZString name, void* value) @cname("object_setInstanceVariable");
extern fn ObjcClass allocateClassPair(ObjcClass cls, ZString name, uint extraBytes) @cname("objc_allocateClassPair");
extern fn void registerClassPair(ObjcClass cls) @cname("objc_registerClassPair");
enum StatusItemLength : (double val)
module std::os::macos::objc::ns @if(env::DARWIN) @link(env::DARWIN, "CoreFoundation.framework");
import std::os::macos::cf;
enum StatusItemLength : (double val) @deprecated("Use NSStatusItemLength.")
{
VARIABLE = -1.0,
SQUARE = -2.0,
}
enum ApplicationActivationPolicy : (int val)
enum ApplicationActivationPolicy : (int val) @deprecated("Use NSApplicationActivationPolicy.")
{
REGULAR = 0,
ACCESSORY = 1,
PROHIBITED = 2,
}
enum WindowStyleMask : (int val)
enum NSApplicationActivationPolicy : const inline NSInteger
{
REGULAR = 0,
ACCESSORY = 1,
PROHIBITED = 2,
}
enum WindowStyleMask : (int val) @deprecated("Use NSWindowStyleMask.")
{
BORDERLESS = 0,
TITLED = 1 << 0,
@@ -101,14 +112,21 @@ enum WindowStyleMask : (int val)
HUD_WINDOW = 1 << 13
}
enum BackingStore : (int val)
enum BackingStore : (int val) @deprecated("Use NSBackingStoreType.")
{
RETAINED = 0,
NONRETAINED = 1,
BUFFERED = 2
}
enum EventType : (long val)
enum NSBackingStoreType : const inline NSUInteger
{
RETAINED = 0,
NONRETAINED = 1,
BUFFERED = 2
}
enum EventType : (long val) @deprecated("Use NSEventType.")
{
LEFT_MOUSE_DOWN = 1,
LEFT_MOUSE_UP = 2,
@@ -146,7 +164,45 @@ enum EventType : (long val)
CHANGE_MODE = 38,
}
fn EventType? event_type_from(int val)
enum NSEventType : const inline NSUInteger
{
LEFT_MOUSE_DOWN = 1,
LEFT_MOUSE_UP = 2,
RIGHT_MOUSE_DOWN = 3,
RIGHT_MOUSE_UP = 4,
MOUSE_MOVED = 5,
LEFT_MOUSE_DRAGGED = 6,
RIGHT_MOUSE_DRAGGED = 7,
MOUSE_ENTERED = 8,
MOUSE_EXITED = 9,
KEY_DOWN = 10,
KEY_UP = 11,
FLAGS_CHANGED = 12,
APPKIT_DEFINED = 13,
SYSTEM_DEFINED = 14,
APPLICATION_DEFINED = 15,
PERIODIC = 16,
CURSOR_UPDATE = 17,
SCROLL_WHEEL = 22,
TABLET_POINT = 23,
TABLET_PROXIMITY = 24,
OTHER_MOUSE_DOWN = 25,
OTHER_MOUSE_UP = 26,
OTHER_MOUSE_DRAGGED = 27,
GESTURE = 29,
MAGNIFY = 30,
SWIPE = 31,
ROTATE = 18,
BEGIN_GESTURE = 19,
END_GESTURE = 20,
SMART_MAGNIFY = 32,
QUICK_LOOK = 33,
PRESSURE = 34,
DIRECT_TOUCH = 37,
CHANGE_MODE = 38,
}
fn EventType? event_type_from(int val) @deprecated("Use NSEventType directly.")
{
switch(val)
{
@@ -184,11 +240,11 @@ fn EventType? event_type_from(int val)
case EventType.PRESSURE.val: return PRESSURE;
case EventType.DIRECT_TOUCH.val: return DIRECT_TOUCH;
case EventType.CHANGE_MODE.val: return CHANGE_MODE;
default: return UNKNOWN_EVENT?;
default: return objc::UNKNOWN_EVENT?;
}
}
enum EventMask : (long val)
enum EventMask : (long val) @deprecated("Use NSEventMask.")
{
LEFT_MOUSE_DOWN = 1 << EventType.LEFT_MOUSE_DOWN.val,
LEFT_MOUSE_UP = 1 << EventType.LEFT_MOUSE_UP.val,
@@ -224,7 +280,48 @@ enum EventMask : (long val)
ANY = long.max,
}
enum EventModifierFlag : (int val)
enum NSEventMask : const inline ulong
{
LEFT_MOUSE_DOWN = 1ul << NSEventType.LEFT_MOUSE_DOWN,
LEFT_MOUSE_UP = 1ul << NSEventType.LEFT_MOUSE_UP,
RIGHT_MOUSE_DOWN = 1ul << NSEventType.RIGHT_MOUSE_DOWN,
RIGHT_MOUSE_UP = 1ul << NSEventType.RIGHT_MOUSE_UP,
MOUSE_MOVED = 1ul << NSEventType.MOUSE_MOVED,
LEFT_MOUSE_DRAGGED = 1ul << NSEventType.LEFT_MOUSE_DRAGGED,
RIGHT_MOUSE_DRAGGED = 1ul << NSEventType.RIGHT_MOUSE_DRAGGED,
MOUSE_ENTERED = 1ul << NSEventType.MOUSE_ENTERED,
MOUSE_EXITED = 1ul << NSEventType.MOUSE_EXITED,
KEY_DOWN = 1ul << NSEventType.KEY_DOWN,
KEY_UP = 1ul << NSEventType.KEY_UP,
FLAGS_CHANGED = 1ul << NSEventType.FLAGS_CHANGED,
APPKIT_DEFINED = 1ul << NSEventType.APPKIT_DEFINED,
SYSTEM_DEFINED = 1ul << NSEventType.SYSTEM_DEFINED,
APPLICATION_DEFINED = 1ul << NSEventType.APPLICATION_DEFINED,
PERIODIC = 1ul << NSEventType.PERIODIC,
CURSOR_UPDATE = 1ul << NSEventType.CURSOR_UPDATE,
ROTATE = 1ul << NSEventType.ROTATE,
BEGIN_GESTURE = 1ul << NSEventType.BEGIN_GESTURE,
END_GESTURE = 1ul << NSEventType.END_GESTURE,
SCROLL_WHEEL = 1ul << NSEventType.SCROLL_WHEEL,
TABLET_POINT = 1ul << NSEventType.TABLET_POINT,
TABLET_PROXIMITY = 1ul << NSEventType.TABLET_PROXIMITY,
OTHER_MOUSE_DOWN = 1ul << NSEventType.OTHER_MOUSE_DOWN,
OTHER_MOUSE_UP = 1ul << NSEventType.OTHER_MOUSE_UP,
OTHER_MOUSE_DRAGGED = 1ul << NSEventType.OTHER_MOUSE_DRAGGED,
GESTURE = 1ul << NSEventType.GESTURE,
MAGNIFY = 1ul << NSEventType.MAGNIFY,
SWIPE = 1ul << NSEventType.SWIPE,
SMART_MAGNIFY = 1ul << NSEventType.SMART_MAGNIFY,
QUICK_LOOK = 1ul << NSEventType.QUICK_LOOK,
PRESSURE = 1ul << NSEventType.PRESSURE,
DIRECT_TOUCH = 1ul << NSEventType.DIRECT_TOUCH,
CHANGE_MODE = 1ul << NSEventType.CHANGE_MODE,
ANY = ulong.max,
}
fn NSEventMask event_mask_from_type(NSEventType type) => (NSEventMask)1ul << type;
enum EventModifierFlag : (int val) @deprecated("Use NSEventModifierFlags.")
{
CAPS_LOCK = 1 << 16,
SHIFT = 1 << 17,
@@ -236,3 +333,85 @@ enum EventModifierFlag : (int val)
HELP = 1 << 22,
}
enum NSEventModifierFlags : const inline NSUInteger
{
CAPS_LOCK = 1 << 16,
SHIFT = 1 << 17,
CONTROL = 1 << 18,
OPTION = 1 << 19,
COMMAND = 1 << 20,
NUMERIC_PAD = 1 << 21,
HELP = 1 << 22,
FUNCTION = 1 << 23,
DEVICE_INDEPENDENT_FLAGS_MASK = 0xffff0000UL,
}
enum NSWindowCollectionBehavior : const inline NSUInteger
{
DEFAULT = 0,
CAN_JOIN_ALL_SPACES = 1 << 0,
MOVE_TO_ACTIVE_SPACE = 1 << 1,
MANAGED = 1 << 2,
TRANSIENT = 1 << 3,
STATIONARY = 1 << 4,
PARTICIPATES_IN_CYCLE = 1 << 5,
IGNORES_CYCLE = 1 << 6,
FULL_SCREEN_PRIMARY = 1 << 7,
FULL_SCREEN_AUXILIARY = 1 << 8,
FULL_SCREEN_NONE = 1 << 9,
FULL_SCREEN_ALLOWS_TILING = 1 << 11,
FULL_SCREEN_DISALLOWS_TILING = 1 << 12,
PRIMARY = 1 << 16,
AUXILIARY = 1 << 17,
CAN_JOIN_ALL_APPLICATIONS = 1 << 18,
}
enum NSWindowLevel : const inline NSInteger
{
NORMAL = 0,
FLOATING = 3,
SUBMENU = 3,
TORN_OFF_MENU = 3,
MODAL_PANEL = 8,
MAIN_MENU = 24,
STATUS = 25,
POP_UP_MENU = 101,
SCREEN_SAVER = 1000,
}
enum NSWindowStyleMask : const inline NSUInteger
{
BORDERLESS = 0,
TITLED = 1 << 0,
CLOSABLE = 1 << 1,
MINIATURIZABLE = 1 << 2,
RESIZABLE = 1 << 3,
TEXTURED_BACKGROUND = 1 << 8,
UNIFIED_TITLE_AND_TOOLBAR = 1 << 12,
FULL_SCREEN = 1 << 14,
FULL_SIZE_CONTENT_VIEW = 1 << 15,
UTILITY_WINDOW = 1 << 4,
DOC_MODAL_WINDOW = 1 << 6,
NONACTIVATING_PANEL = 1 << 7,
HUD_WINDOW = 1 << 13
}
enum NSWindowTabbingMode : const inline NSInteger
{
AUTOMATIC = 0,
DISALLOWED = 2,
PREFERRED = 1,
}
enum NSStatusItemLength : const inline CGFloat
{
VARIABLE = -1.0,
SQUARE = -2.0
}
enum NSApplicationTerminateReply : const inline NSUInteger
{
CANCEL = 0,
NOW = 1,
LATER = 2,
}

View File

@@ -0,0 +1,44 @@
module std::os::darwin @if(env::DARWIN);
alias __Darwin_sigset_t = uint;
alias __Darwin_size_t = usz;
struct __Darwin_arm_exception_state64
{
ulong __far; /* Virtual Fault Address */
uint __esr; /* Exception syndrome */
uint __exception; /* number of arm exception taken */
}
struct __Darwin_arm_thread_state64
{
ulong[29] __x; /* General purpose registers x0-x28 */
ulong __fp; /* Frame pointer x29 */
ulong __lr; /* Link register x30 */
ulong __sp; /* Stack pointer x31 */
ulong __pc; /* Program counter */
ulong __cpsr; /* Current program status register */
ulong __pad; /* Same size for 32-bit or 64-bit clients */
}
struct __Darwin_arm_neon_state64
{
uint128[32] __v;
uint __fpsr;
uint __fpcr;
}
struct __Darwin_mcontext64
{
__Darwin_arm_exception_state64 __es;
__Darwin_arm_thread_state64 __ss;
__Darwin_arm_neon_state64 __ns;
}
struct __Darwin_sigaltstack
{
void* ss_sp; /* signal stack base */
__Darwin_size_t ss_size; /* signal stack length */
int ss_flags; /* SA_DISABLE and/or SA_ONSTACK */
}

View File

@@ -1,6 +1,6 @@
module std::math::nolibc @if(env::NO_LIBC);
fn void __stack_chk_fail() @extern("__stack_chk_fail") @nostrip @noreturn @weak
fn void __stack_chk_fail() @cname("__stack_chk_fail") @nostrip @noreturn @weak
{
$$trap();
}

View File

@@ -32,7 +32,7 @@ extern fn ZString getcwd(char* pwd, usz len);
extern fn CInt pipe(CInt[2]* pipes);
extern fn CFile fdopen(CInt fd, ZString mode);
extern fn CInt access(ZString path, CInt mode);
extern fn Posix_dirent* readdir(DIRPtr) @extern("readdir") @if(!USE_DARWIN_INODE64) ;
extern fn Posix_dirent* readdir(DIRPtr) @cname("readdir") @if(!USE_DARWIN_INODE64) ;
extern fn DIRPtr opendir(ZString);
extern fn void closedir(DIRPtr);
@@ -47,4 +47,4 @@ const DT_SOCK = 12;
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);
extern fn Posix_dirent* readdir(DIRPtr) @cname("readdir$INODE64") @if(USE_DARWIN_INODE64);

View File

@@ -1,5 +1,5 @@
module std::os::posix @if(env::POSIX);
import libc;
import libc, std::os::darwin;
struct Posix_spawn_file_actions_t
{
@@ -60,6 +60,15 @@ alias BacktraceFn = fn CInt(void** buffer, CInt size);
extern fn CInt backtrace(void** buffer, CInt size) @if(env::OPENBSD);
fn void install_signal_handler(CInt signal, SigActionFunction func)
{
Sigaction action = {
.sa_sigaction = func,
};
Sigaction old;
libc::sigaction(signal, &action, &old);
}
fn CInt backtrace(void** buffer, CInt size) @if(!env::OPENBSD)
{
if (size < 1) return 0;
@@ -75,12 +84,13 @@ fn CInt backtrace(void** buffer, CInt size) @if(!env::OPENBSD)
}
// Loop through the return addresses until we hit a signal.
// This avoids using the frame address.
SignalFunction restore_backtrace = fn void(CInt) {
libc::longjmp(&backtrace_jmpbuf, 1);
};
SignalFunction sig_bus = libc::signal(libc::SIGBUS, restore_backtrace);
SignalFunction sig_segv = libc::signal(libc::SIGSEGV, restore_backtrace);
SignalFunction sig_ill = libc::signal(libc::SIGILL, restore_backtrace);
Sigaction restore_backtrace = {
.sa_sigaction = fn void(CInt, void*, void*) { libc::longjmp(&backtrace_jmpbuf, 1); },
};
Sigaction sig_bus, sig_segv, sig_ill;
libc::sigaction(libc::SIGBUS, &restore_backtrace, &sig_bus);
libc::sigaction(libc::SIGSEGV, &restore_backtrace, &sig_segv);
libc::sigaction(libc::SIGILL, &restore_backtrace, &sig_ill);
void*[128] buffer_first;
int i = 0;
@@ -90,8 +100,47 @@ fn CInt backtrace(void** buffer, CInt size) @if(!env::OPENBSD)
buffer[i] = builtin::get_returnaddress(i);
if (!buffer[i]) break;
}
libc::signal(libc::SIGBUS, sig_bus);
libc::signal(libc::SIGSEGV, sig_segv);
libc::signal(libc::SIGILL, sig_ill);
Sigaction old;
libc::sigaction(libc::SIGBUS, &sig_bus, &old);
libc::sigaction(libc::SIGSEGV, &sig_segv, &old);
libc::sigaction(libc::SIGILL, &sig_ill, &old);
return i;
}
struct PosixUContext_t @if(env::DARWIN)
{
int uc_onstack;
__Darwin_sigset_t uc_sigmask; /* signal mask used by this context */
__Darwin_sigaltstack uc_stack; /* stack used by this context */
PosixUContext_t* uc_link; /* pointer to resuming context */
__Darwin_size_t uc_mcsize; /* size of the machine context passed in */
__Darwin_mcontext64* uc_mcontext; /* pointer to machine specific context */
}
alias PosixUContext_t @if(!env::DARWIN) = void;
macro void* stack_instruction(PosixUContext_t* uc)
{
$switch:
$case env::DARWIN && env::AARCH64:
return (void*)uc.uc_mcontext.__ss.__pc + 1;
/* $case env::DARWIN && env::X86_64:
return uc.uc_mcontext.__ss.__rip;
$case env::LINUX && env::X86:
return uc.uc_mcontext.gregs[REG_EIP];
$case env::LINUX && env::X86_64:
return uc.uc_mcontext.gregs[REG_RIP];
$case env::LINUX && env::AARCH64:
return uc.uc_mcontext.pc;
$case env::FREEBSD && env::X86_64:
return uc.uc_mcontext.mc_rip;
$case env::OPENBSD && env::X86_64:
return uc.sc_rip;
$case env::NETBSD:
uc.uc_mcontext.__gregs[_REG_RIP];*/
$default:
return null;
$endswitch
}

View File

@@ -1,6 +1,6 @@
module std::os::win32 @if(env::WIN32);
import std::math;
extern fn void getSystemTimeAsFileTime(Win32_FILETIME* time) @extern("GetSystemTimeAsFileTime");
extern fn Win32_BOOL queryPerformanceFrequency(Win32_LARGE_INTEGER* lpFrequency) @extern("QueryPerformanceFrequency");
extern fn Win32_BOOL queryPerformanceCounter(Win32_LARGE_INTEGER* lpPerformanceCount) @extern("QueryPerformanceCounter");
extern fn void getSystemTimeAsFileTime(Win32_FILETIME* time) @cname("GetSystemTimeAsFileTime");
extern fn Win32_BOOL queryPerformanceFrequency(Win32_LARGE_INTEGER* lpFrequency) @cname("QueryPerformanceFrequency");
extern fn Win32_BOOL queryPerformanceCounter(Win32_LARGE_INTEGER* lpPerformanceCount) @cname("QueryPerformanceCounter");

View File

@@ -0,0 +1,188 @@
module std::os::win32 @if(env::WIN32);
import std::io;
const EXCEPTION_MAXIMUM_PARAMETERS = 15;
struct ExceptionRecord
{
Win32_DWORD exception_code;
Win32_DWORD exception_flags;
ExceptionRecord* exception_record;
void* exception_address;
Win32_DWORD number_parameters;
Win32_ULONG_PTR[EXCEPTION_MAXIMUM_PARAMETERS] exception_information;
}
struct ExceptionContext @align(16)
{
Win32_DWORD64 p1_home;
Win32_DWORD64 p2_home;
Win32_DWORD64 p3_home;
Win32_DWORD64 p4_home;
Win32_DWORD64 p5_home;
Win32_DWORD64 p6_home;
Win32_DWORD context_flags;
Win32_DWORD mx_csr;
Win32_WORD seg_cs;
Win32_WORD seg_ds;
Win32_WORD seg_es;
Win32_WORD seg_fs;
Win32_WORD seg_gs;
Win32_WORD seg_ss;
Win32_DWORD eflags;
Win32_DWORD64 dr0;
Win32_DWORD64 dr1;
Win32_DWORD64 dr2;
Win32_DWORD64 dr3;
Win32_DWORD64 dr6;
Win32_DWORD64 dr7;
Win32_DWORD64 rax;
Win32_DWORD64 rcx;
Win32_DWORD64 rdx;
Win32_DWORD64 rbx;
Win32_DWORD64 rsp;
Win32_DWORD64 rbp;
Win32_DWORD64 rsi;
Win32_DWORD64 rdi;
Win32_DWORD64 r8;
Win32_DWORD64 r9;
Win32_DWORD64 r10;
Win32_DWORD64 r11;
Win32_DWORD64 r12;
Win32_DWORD64 r13;
Win32_DWORD64 r14;
Win32_DWORD64 r15;
Win32_DWORD64 rip;
union
{
struct flt_save @align(16)
{
Win32_WORD control_word;
Win32_WORD status_word;
Win32_BYTE tag_word;
Win32_BYTE reserved1;
Win32_WORD error_opcode;
Win32_DWORD error_offset;
Win32_WORD error_selector;
Win32_WORD reserved2;
Win32_DWORD data_offset;
Win32_WORD data_selector;
Win32_WORD reserved3;
Win32_DWORD mx_csr;
Win32_DWORD mx_csr_mask;
Win32_M128A[16] xmm_registers;
Win32_BYTE[96] reserved4;
}
struct
{
Win32_M128A[2] header;
Win32_M128A[8] legacy;
Win32_M128A xmm0;
Win32_M128A xmm1;
Win32_M128A xmm2;
Win32_M128A xmm3;
Win32_M128A xmm4;
Win32_M128A xmm5;
Win32_M128A xmm6;
Win32_M128A xmm7;
Win32_M128A xmm8;
Win32_M128A xmm9;
Win32_M128A xmm10;
Win32_M128A xmm11;
Win32_M128A xmm12;
Win32_M128A xmm13;
Win32_M128A xmm14;
Win32_M128A xmm15;
}
}
Win32_M128A[26] vector_registers;
Win32_DWORD64 vector_control;
Win32_DWORD64 debug_control;
Win32_DWORD64 last_branch_to_rip;
Win32_DWORD64 last_branch_from_rip;
Win32_DWORD64 last_exception_to_rip;
Win32_DWORD64 last_exception_from_rip;
}
struct ExceptionPointers
{
ExceptionRecord* exception_record;
ExceptionContext* context_record;
}
alias UnhandledExceptionFilter = fn Win32_LONG (ExceptionPointers* exception_info);
const EXCEPTION_EXECUTE_HANDLER = 1;
extern fn void debugBreak() @extern("DebugBreak") @if(env::WIN32);
extern fn bool isDebuggerPresent() @extern("IsDebuggerPresent") @if(env::WIN32);
extern fn UnhandledExceptionFilter setUnhandledExceptionFilter(UnhandledExceptionFilter filter) @extern("SetUnhandledExceptionFilter") @if(env::WIN32);
UnhandledExceptionFilter previous_filter;
PanicFn previous_panic;
bool has_panicked;
fn Win32_LONG exception_handler(ExceptionPointers* exception_info)
{
if (!has_panicked)
{
@stack_mem(512; Allocator allocator)
{
DString s;
s.init(allocator: allocator);
Win32_DWORD code = exception_info.exception_record.exception_code;
void* addr = exception_info.exception_record.exception_address;
switch (code)
{
case 0x80000001: s.appendf("Guard page violation at address %p", addr);
case 0x80000002: s.appendf("Datatype misalignment at address %p", addr);
case 0xC0000005: s.appendf("Access Violation at address %p", addr);
case 0xC0000006: s.appendf("In page error at address %p", addr);
case 0xC000001D: s.appendf("Illegal instruction at address %p", addr);
case 0xC000008C: s.appendf("Array bounds exceeded at address %p", addr);
case 0xC000008D: s.appendf("Flt denormal operand at address %p", addr);
case 0xC000008E: s.appendf("Flt divide by zero at address %p", addr);
case 0xC0000090: s.appendf("Flt invalid operation at address %p", addr);
case 0xC0000094: s.appendf("Integer divide by zero at address %p", addr);
case 0xC00000FD: s.appendf("Stack overflow at address %p", addr);
case 0xC0000096: s.appendf("Privileged instruction at address %p", addr);
case 0xC0000374: s.appendf("Heap corruption detected at address %p", addr);
case 0xC0000409: s.appendf("Stack buffer overflow at address %p", addr);
case 0xC00004A2: s.appendf("Enclave violation at address %p", addr);
default:
s.appendf("Unhandled exception (%X) at %p", code, addr);
}
if (!builtin::print_backtrace(s.str_view(), 8))
{
io::eprintfn("\nERROR: %s", s.str_view());
}
};
}
if (previous_filter)
{
return previous_filter(exception_info);
}
return EXCEPTION_EXECUTE_HANDLER;
}
fn void panic_tracker(String message, String file, String function, uint line)
{
has_panicked = true;
previous_panic(message, file, function, line);
}
fn void init_exception_handler() @init
{
previous_filter = setUnhandledExceptionFilter(&exception_handler);
previous_panic = builtin::panic;
builtin::panic = &panic_tracker;
}

View File

@@ -41,18 +41,18 @@ struct Win32_WIN32_FIND_DATAW
alias Win32_LPWIN32_FIND_DATAW = Win32_WIN32_FIND_DATAW*;
extern fn Win32_BOOL closeHandle(Win32_HANDLE) @extern("CloseHandle");
extern fn Win32_BOOL createPipe(Win32_PHANDLE hReadPipe, Win32_PHANDLE hWritePipe, Win32_LPSECURITY_ATTRIBUTES lpPipeAttributes, Win32_DWORD nSize) @extern("CreatePipe");
extern fn Win32_BOOL getFileAttributesExW(Win32_LPCWSTR, Win32_GET_FILEEX_INFO_LEVELS, Win32_LPVOID) @extern("GetFileAttributesExW");
extern fn Win32_BOOL pathFileExistsW(Win32_LPCWSTR) @extern("PathFileExistsW");
extern fn Win32_DWORD getTempPathW(Win32_DWORD nBufferLength, Win32_LPWSTR lpBuffer) @extern("GetTempPathW");
extern fn Win32_BOOL setCurrentDirectoryW(Win32_LPCTSTR buffer) @extern("SetCurrentDirectoryW");
extern fn Win32_BOOL removeDirectoryW(Win32_LPCWSTR lpPathName) @extern("RemoveDirectoryW");
extern fn Win32_BOOL createDirectoryW(Win32_LPCWSTR lpPathName, Win32_LPSECURITY_ATTRIBUTES lpPipeAttributes) @extern("CreateDirectoryW");
extern fn Win32_BOOL deleteFileW(Win32_LPCWSTR lpFileName) @extern("DeleteFileW");
extern fn Win32_HANDLE findFirstFileW(Win32_LPCWSTR lpFileName, Win32_LPWIN32_FIND_DATAW lpFindFileData) @extern("FindFirstFileW");
extern fn Win32_BOOL findNextFileW(Win32_HANDLE hFindFile, Win32_LPWIN32_FIND_DATAW lpFindFileData) @extern("FindNextFileW");
extern fn Win32_BOOL findClose(Win32_HANDLE hFindFile) @extern("FindClose");
extern fn Win32_BOOL closeHandle(Win32_HANDLE) @cname("CloseHandle");
extern fn Win32_BOOL createPipe(Win32_PHANDLE hReadPipe, Win32_PHANDLE hWritePipe, Win32_LPSECURITY_ATTRIBUTES lpPipeAttributes, Win32_DWORD nSize) @cname("CreatePipe");
extern fn Win32_BOOL getFileAttributesExW(Win32_LPCWSTR, Win32_GET_FILEEX_INFO_LEVELS, Win32_LPVOID) @cname("GetFileAttributesExW");
extern fn Win32_BOOL pathFileExistsW(Win32_LPCWSTR) @cname("PathFileExistsW");
extern fn Win32_DWORD getTempPathW(Win32_DWORD nBufferLength, Win32_LPWSTR lpBuffer) @cname("GetTempPathW");
extern fn Win32_BOOL setCurrentDirectoryW(Win32_LPCTSTR buffer) @cname("SetCurrentDirectoryW");
extern fn Win32_BOOL removeDirectoryW(Win32_LPCWSTR lpPathName) @cname("RemoveDirectoryW");
extern fn Win32_BOOL createDirectoryW(Win32_LPCWSTR lpPathName, Win32_LPSECURITY_ATTRIBUTES lpPipeAttributes) @cname("CreateDirectoryW");
extern fn Win32_BOOL deleteFileW(Win32_LPCWSTR lpFileName) @cname("DeleteFileW");
extern fn Win32_HANDLE findFirstFileW(Win32_LPCWSTR lpFileName, Win32_LPWIN32_FIND_DATAW lpFindFileData) @cname("FindFirstFileW");
extern fn Win32_BOOL findNextFileW(Win32_HANDLE hFindFile, Win32_LPWIN32_FIND_DATAW lpFindFileData) @cname("FindNextFileW");
extern fn Win32_BOOL findClose(Win32_HANDLE hFindFile) @cname("FindClose");
const Win32_DWORD GENERIC_WRITE = 0x40000000;
const Win32_DWORD OPEN_EXISTING = 3;
@@ -87,10 +87,10 @@ extern fn Win32_HANDLE createFileA(
Win32_DWORD dwCreationDisposition,
Win32_DWORD dwFlagsAndAttributes,
Win32_HANDLE hTemplateFile
) @extern("CreateFileA");
) @cname("CreateFileA");
extern fn Win32_BOOL readFile(Win32_HANDLE hFile, Win32_LPVOID lpBuffer, Win32_DWORD nNumberOfBytesToRead,
Win32_LPDWORD lpNumberOfBytesRead, Win32_LPOVERLAPPED lpOverlapped
) @extern("ReadFile");
) @cname("ReadFile");
extern fn WString _wgetcwd(Char16* buffer, int maxlen);
extern fn usz wcslen(WString str);
@@ -104,8 +104,8 @@ extern fn CInt _waccess(WString path, CInt mode);
extern fn WString _wfullpath(WString absPath, WString relPath, usz maxLength);
/*
extern ulong _win32_GetCurrentDirectoryW(ulong, Char16* buffer) @extern("GetCurrentDirectoryW");
extern bool _win32_CreateSymbolicLinkW(WString symlink_file, WString target_file, ulong flags) @extern("CreateSymbolicLinkW");
extern bool _win32_CopyFileW(WString from_file, WString to_file, bool no_overwrite) @extern("CopyFileW");
extern ulong _win32_GetFullPathNameW(WString file_name, ulong buffer_len, Char16* buffer, WString* file_part) @extern("GetFullPathNameW");
extern ulong _win32_GetCurrentDirectoryW(ulong, Char16* buffer) @cname("GetCurrentDirectoryW");
extern bool _win32_CreateSymbolicLinkW(WString symlink_file, WString target_file, ulong flags) @cname("CreateSymbolicLinkW");
extern bool _win32_CopyFileW(WString from_file, WString to_file, bool no_overwrite) @cname("CopyFileW");
extern ulong _win32_GetFullPathNameW(WString file_name, ulong buffer_len, Char16* buffer, WString* file_part) @cname("GetFullPathNameW");
*/

View File

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

View File

@@ -1,6 +1,6 @@
module std::os::win32 @if(env::WIN32);
extern fn Win32_DWORD getLastError() @extern("GetLastError");
extern fn Win32_DWORD getLastError() @cname("GetLastError");
const Win32_DWORD ERROR_INVALID_FUNCTION = 0x1;
const Win32_DWORD ERROR_FILE_NOT_FOUND = 0x2;

View File

@@ -3,25 +3,25 @@ module std::os::win32 @if(env::WIN32);
typedef Win32_DLL_DIRECTORY_COOKIE = void*;
alias Win32_PDLL_DIRECTORY_COOKIE = Win32_DLL_DIRECTORY_COOKIE*;
extern fn Win32_HMODULE loadLibraryA(Win32_LPCSTR lpLibFileName) @extern("LoadLibraryA");
extern fn Win32_HMODULE loadLibraryW(Win32_LPCWSTR lpLibFileName) @extern("LoadLibraryW");
extern fn Win32_HMODULE loadLibraryExA(Win32_LPCSTR lpLibFileName, Win32_HANDLE hFile, Win32_DWORD dwFlags) @extern("LoadLibraryExA");
extern fn Win32_HMODULE loadLibraryExW(Win32_LPCWSTR lpLibFileName, Win32_HANDLE hFile, Win32_DWORD dwFlags) @extern("LoadLibraryExW");
extern fn Win32_HMODULE loadLibraryA(Win32_LPCSTR lpLibFileName) @cname("LoadLibraryA");
extern fn Win32_HMODULE loadLibraryW(Win32_LPCWSTR lpLibFileName) @cname("LoadLibraryW");
extern fn Win32_HMODULE loadLibraryExA(Win32_LPCSTR lpLibFileName, Win32_HANDLE hFile, Win32_DWORD dwFlags) @cname("LoadLibraryExA");
extern fn Win32_HMODULE loadLibraryExW(Win32_LPCWSTR lpLibFileName, Win32_HANDLE hFile, Win32_DWORD dwFlags) @cname("LoadLibraryExW");
extern fn Win32_BOOL freeLibrary(Win32_HMODULE hLibModule) @extern("FreeLibrary");
extern fn void freeLibraryAndExitThread(Win32_HMODULE hLibModule, Win32_DWORD dwExitCode) @extern("FreeLibraryAndExitThread");
extern fn Win32_BOOL freeLibrary(Win32_HMODULE hLibModule) @cname("FreeLibrary");
extern fn void freeLibraryAndExitThread(Win32_HMODULE hLibModule, Win32_DWORD dwExitCode) @cname("FreeLibraryAndExitThread");
extern fn Win32_DWORD getModuleFileNameA(Win32_HMODULE hModule, Win32_LPSTR lpFilename, Win32_DWORD nSize) @extern("GetModuleFileNameA");
extern fn Win32_DWORD getModuleFileNameW(Win32_HMODULE hModule, Win32_LPWSTR lpFilename, Win32_DWORD nSize) @extern("GetModuleFileNameW");
extern fn Win32_DWORD getModuleFileNameA(Win32_HMODULE hModule, Win32_LPSTR lpFilename, Win32_DWORD nSize) @cname("GetModuleFileNameA");
extern fn Win32_DWORD getModuleFileNameW(Win32_HMODULE hModule, Win32_LPWSTR lpFilename, Win32_DWORD nSize) @cname("GetModuleFileNameW");
extern fn Win32_HMODULE getModuleHandleA(Win32_LPCSTR lpModuleName) @extern("GetModuleHandleA");
extern fn Win32_HMODULE getModuleHandleW(Win32_LPCWSTR lpModuleName) @extern("GetModuleHandleW");
extern fn Win32_BOOL getModuleHandleExA(Win32_DWORD dwFlags, Win32_LPCSTR lpModuleName, Win32_HMODULE* phModule) @extern("GetModuleHandleExA");
extern fn Win32_BOOL getModuleHandleExW(Win32_DWORD dwFlags, Win32_LPCWSTR lpModuleName, Win32_HMODULE* phModule) @extern("GetModuleHandleExW");
extern fn Win32_HMODULE getModuleHandleA(Win32_LPCSTR lpModuleName) @cname("GetModuleHandleA");
extern fn Win32_HMODULE getModuleHandleW(Win32_LPCWSTR lpModuleName) @cname("GetModuleHandleW");
extern fn Win32_BOOL getModuleHandleExA(Win32_DWORD dwFlags, Win32_LPCSTR lpModuleName, Win32_HMODULE* phModule) @cname("GetModuleHandleExA");
extern fn Win32_BOOL getModuleHandleExW(Win32_DWORD dwFlags, Win32_LPCWSTR lpModuleName, Win32_HMODULE* phModule) @cname("GetModuleHandleExW");
extern fn Win32_BOOL disableThreadLibraryCalls(Win32_HMODULE hLibModule) @extern("DisableThreadLibraryCalls");
extern fn Win32_BOOL disableThreadLibraryCalls(Win32_HMODULE hLibModule) @cname("DisableThreadLibraryCalls");
extern fn Win32_FARPROC getProcAddress(Win32_HMODULE hModule, Win32_LPCSTR lpProcName) @extern("GetProcAddress");
extern fn Win32_DLL_DIRECTORY_COOKIE addDllDirectory(Win32_PCWSTR newDirectory) @extern("AddDllDirectory");
extern fn Win32_BOOL removeDllDirectory(Win32_DLL_DIRECTORY_COOKIE cookie) @extern("RemoveDllDirectory");
extern fn Win32_BOOL setDefaultDllDirectories(Win32_DWORD directoryFlags) @extern("SetDefaultDllDirectories");
extern fn Win32_FARPROC getProcAddress(Win32_HMODULE hModule, Win32_LPCSTR lpProcName) @cname("GetProcAddress");
extern fn Win32_DLL_DIRECTORY_COOKIE addDllDirectory(Win32_PCWSTR newDirectory) @cname("AddDllDirectory");
extern fn Win32_BOOL removeDllDirectory(Win32_DLL_DIRECTORY_COOKIE cookie) @cname("RemoveDllDirectory");
extern fn Win32_BOOL setDefaultDllDirectories(Win32_DWORD directoryFlags) @cname("SetDefaultDllDirectories");

View File

@@ -36,10 +36,10 @@ enum Win32_FreeType : const Win32_DWORD
MEM_COALESCE_PLACEHOLDERS = 0x00000001,
MEM_PRESERVE_PLACEHOLDER = 0x00000002,
}
extern fn Win32_LPVOID virtualAlloc(Win32_LPVOID lpAddress, Win32_SIZE_T dwSize, Win32_AllocationType flAllocationType, Win32_Protect flProtect) @extern("VirtualAlloc");
extern fn Win32_PVOID virtualAlloc2(Win32_HANDLE process, Win32_PVOID baseAddress, Win32_SIZE_T size, Win32_AllocationType allocationType, Win32_ULONG pageProtection, Win32_MEM_EXTENDED_PARAMETER* extendedParameters, Win32_ULONG parameterCount) @extern("VirtualAlloc2");
extern fn Win32_BOOL virtualFree(Win32_LPVOID lpAddress, Win32_SIZE_T dwSize, Win32_FreeType dwFreeType) @extern("VirtualFree");
extern fn Win32_BOOL virtualProtect(Win32_LPVOID lpAddress, Win32_SIZE_T dwSize, Win32_Protect flNewProtect, Win32_Protect* lpflOldProtect) @extern("VirtualProtect");
extern fn Win32_LPVOID virtualAlloc(Win32_LPVOID lpAddress, Win32_SIZE_T dwSize, Win32_AllocationType flAllocationType, Win32_Protect flProtect) @cname("VirtualAlloc");
extern fn Win32_PVOID virtualAlloc2(Win32_HANDLE process, Win32_PVOID baseAddress, Win32_SIZE_T size, Win32_AllocationType allocationType, Win32_ULONG pageProtection, Win32_MEM_EXTENDED_PARAMETER* extendedParameters, Win32_ULONG parameterCount) @cname("VirtualAlloc2");
extern fn Win32_BOOL virtualFree(Win32_LPVOID lpAddress, Win32_SIZE_T dwSize, Win32_FreeType dwFreeType) @cname("VirtualFree");
extern fn Win32_BOOL virtualProtect(Win32_LPVOID lpAddress, Win32_SIZE_T dwSize, Win32_Protect flNewProtect, Win32_Protect* lpflOldProtect) @cname("VirtualProtect");
fn usz allocation_granularity()
{

View File

@@ -48,76 +48,76 @@ const UNDNAME_COMPLETE = 0x0000;
alias Win32_INIT_ONCE_FN = fn Win32_BOOL(Win32_INIT_ONCE* initOnce, void* parameter, void** context);
extern fn void initializeCriticalSection(Win32_CRITICAL_SECTION* section) @extern("InitializeCriticalSection");
extern fn void deleteCriticalSection(Win32_CRITICAL_SECTION* section) @extern("DeleteCriticalSection");
extern fn Win32_HANDLE createMutex(void*, Win32_BOOL, void*) @extern("CreateMutexA");
extern fn Win32_BOOL releaseMutex(Win32_HANDLE) @extern("ReleaseMutex");
extern fn void enterCriticalSection(Win32_CRITICAL_SECTION* section) @extern("EnterCriticalSection");
extern fn void leaveCriticalSection(Win32_CRITICAL_SECTION* section) @extern("LeaveCriticalSection");
extern fn Win32_BOOL tryEnterCriticalSection(Win32_CRITICAL_SECTION* section) @extern("TryEnterCriticalSection");
extern fn void initializeSRWLock(Win32_SRWLOCK* lock) @extern("InitializeSRWLock");
extern fn void acquireSRWLockExclusive(Win32_SRWLOCK* lock) @extern("AcquireSRWLockExclusive");
extern fn void acquireSRWLockShared(Win32_SRWLOCK* lock) @extern("AcquireSRWLockShared");
extern fn void releaseSRWLockExclusive(Win32_SRWLOCK* lock) @extern("ReleaseSRWLockExclusive");
extern fn void releaseSRWLockShared(Win32_SRWLOCK* lock) @extern("ReleaseSRWLockShared");
extern fn Win32_BOOL tryAcquireSRWLockExclusive(Win32_SRWLOCK* lock) @extern("TryAcquireSRWLockExclusive");
extern fn Win32_BOOL tryAcquireSRWLockShared(Win32_SRWLOCK* lock) @extern("TryAcquireSRWLockShared");
extern fn void initializeConditionVariable(Win32_CONDITION_VARIABLE* conditionVariable) @extern("InitializeConditionVariable");
extern fn void wakeConditionVariable(Win32_CONDITION_VARIABLE* conditionVariable) @extern("WakeConditionVariable");
extern fn void wakeAllConditionVariable(Win32_CONDITION_VARIABLE* conditionVariable) @extern("WakeAllConditionVariable");
extern fn Win32_BOOL sleepConditionVariableCS(Win32_CONDITION_VARIABLE* conditionVariable, Win32_CRITICAL_SECTION* section, Win32_DWORD dwMilliseconds) @extern("SleepConditionVariableCS");
extern fn Win32_BOOL sleepConditionVariableSRW(Win32_CONDITION_VARIABLE* conditionVariable, Win32_SRWLOCK* lock, Win32_DWORD dwMilliseconds, Win32_ULONG flags) @extern("SleepConditionVariableSRW");
extern fn Win32_BOOL initOnceExecuteOnce(Win32_INIT_ONCE* initOnce, Win32_INIT_ONCE_FN initFn, void* parameter, void** context) @extern("InitOnceExecuteOnce");
extern fn Win32_DWORD waitForSingleObject(Win32_HANDLE hHandle, Win32_DWORD dwMilliseconds) @extern("WaitForSingleObject");
extern fn Win32_DWORD waitForSingleObjectEx(Win32_HANDLE hHandle, Win32_DWORD dwMilliseconds, Win32_BOOL bAlertable) @extern("WaitForSingleObjectEx");
extern fn Win32_DWORD waitForMultipleObjects(Win32_DWORD nCount, Win32_HANDLE* lpHandles, Win32_BOOL bWaitAll, Win32_DWORD dwMilliseconds) @extern("WaitForMultipleObjects");
extern fn Win32_DWORD waitForMultipleObjectsEx(Win32_DWORD nCount, Win32_HANDLE* lpHandles, Win32_BOOL bWaitAll, Win32_DWORD dwMilliseconds, Win32_BOOL bAlertable) @extern("WaitForMultipleObjectsEx");
extern fn void sleep(uint ms) @extern("Sleep");
extern fn Win32_BOOL resetEvent(Win32_HANDLE event) @extern("ResetEvent");
extern fn Win32_BOOL setEvent(Win32_HANDLE handle) @extern("SetEvent");
extern fn long interlockedCompareExchange(int* dest, int exchange, int comperand) @extern("InterlockedCompareExchange");
extern fn Win32_DWORD sleepEx(Win32_DWORD ms, Win32_BOOL alertable) @extern("SleepEx");
extern fn Win32_HANDLE createThread(void* attributes, usz stack, ThreadFn func, Win32_LPVOID arg, Win32_DWORD flags, Win32_LPDWORD thread_id) @extern("CreateThread");
extern fn Win32_BOOL getExitCodeThread(Win32_HANDLE handle, Win32_LPDWORD exit_code) @extern("GetExitCodeThread");
extern fn Win32_BOOL getExitCodeProcess(Win32_HANDLE hProcess, Win32_LPDWORD lpExitCode) @extern("GetExitCodeProcess");
extern fn Win32_DWORD getThreadId(Win32_HANDLE) @extern("GetThreadId");
extern fn void exitThread(Win32_DWORD dwExitCode) @noreturn @extern("ExitThread");
extern fn Win32_HANDLE getCurrentThread() @extern("GetCurrentThread");
extern fn Win32_BOOL terminateProcess(Win32_HANDLE hProcess, Win32_UINT uExitCode) @extern("TerminateProcess");
extern fn Win32_DWORD getCurrentProcessId() @extern("GetCurrentProcessId");
extern fn Win32_HANDLE getCurrentProcess() @extern("GetCurrentProcess");
extern fn Win32_DWORD getCurrentThreadId() @extern("GetCurrentThreadId");
extern fn Win32_BOOL setHandleInformation(Win32_HANDLE hObject, Win32_DWORD dwMask, Win32_DWORD dwFlags) @extern("SetHandleInformation");
extern fn Win32_HANDLE createEventA(Win32_LPSECURITY_ATTRIBUTES lpEventAttributes, Win32_BOOL bManualReset, Win32_BOOL bInitialState, Win32_LPCSTR lpName) @extern("CreateEventA");
extern fn Win32_BOOL createProcessW(Win32_LPCWSTR lpApplicationName, Win32_LPWSTR lpCommandLine, Win32_LPSECURITY_ATTRIBUTES lpProcessAttributes, Win32_LPSECURITY_ATTRIBUTES lpThreadAttributes, Win32_BOOL bInheritHandles, Win32_DWORD dwCreationFlags, Win32_LPVOID lpEnvironment, Win32_LPCWSTR lpCurrentDirectory, Win32_LPSTARTUPINFOW lpStartupInfo, Win32_LPPROCESS_INFORMATION lpProcessInformation) @extern("CreateProcessW");
extern fn Win32_HANDLE createNamedPipeA(Win32_LPCSTR lpName, Win32_DWORD dwOpenMode, Win32_DWORD dwPipeMode, Win32_DWORD nMaxInstances, Win32_DWORD nOutBufferSize, Win32_DWORD nInBufferSize, Win32_DWORD nDefaultTimeOut, Win32_LPSECURITY_ATTRIBUTES lpSecurityAttributes) @extern("CreateNamedPipeA");
extern fn Win32_BOOL getOverlappedResult(Win32_HANDLE hFile, Win32_LPOVERLAPPED lpOverlapped, Win32_LPDWORD lpNumberOfBytesTransferred, Win32_BOOL bWait) @extern("GetOverlappedResult");
extern fn Win32_DWORD getEnvironmentVariableW(Win32_LPCWSTR lpName, Win32_LPWSTR lpBuffer, Win32_DWORD nSize) @extern("GetEnvironmentVariableW");
extern fn Win32_BOOL setEnvironmentVariableW(Win32_LPCWSTR lpName, Win32_LPCWSTR lpValue) @extern("SetEnvironmentVariableW");
extern fn void getSystemInfo(Win32_LPSYSTEM_INFO lpSystemInfo) @extern("GetSystemInfo");
extern fn Win32_BOOL enumProcessModules(Win32_HANDLE hProcess, Win32_HMODULE* lphModule, Win32_DWORD cb, Win32_LPDWORD lpcbNeeded) @extern("K32EnumProcessModules");
extern fn Win32_BOOL getModuleInformation(Win32_HANDLE hProcess, Win32_HMODULE hModule, Win32_LPMODULEINFO lpmodinfo, Win32_DWORD cb) @extern("K32GetModuleInformation");
extern fn Win32_DWORD symAddrIncludeInlineTrace(Win32_HANDLE hProcess, Win32_DWORD64 address) @extern("SymAddrIncludeInlineTrace");
extern fn Win32_BOOL symQueryInlineTrace(Win32_HANDLE hProcess, Win32_DWORD64 startAddress, Win32_DWORD startContext, Win32_DWORD64 startRetAddress, Win32_DWORD64 curAddress, Win32_LPDWORD curContext, Win32_LPDWORD curFrameIndex) @extern("SymQueryInlineTrace");
extern fn Win32_BOOL symFromInlineContext(Win32_HANDLE hProcess, Win32_DWORD64 address, Win32_ULONG inlineContext, Win32_PDWORD64 displacement, Win32_PSYMBOL_INFO symbol) @extern("SymFromInlineContext");
extern fn Win32_BOOL symGetLineFromInlineContext(Win32_HANDLE hProcess, Win32_DWORD64 qwAddr, Win32_ULONG inlineContext, Win32_DWORD64 qwModuleBaseAddress, Win32_PDWORD pdwDisplacement, Win32_PIMAGEHLP_LINE64 line64) @extern("SymGetLineFromInlineContext");
extern fn Win32_ULONG rtlWalkFrameChain(Win32_PVOID*, Win32_ULONG, Win32_ULONG) @extern("RtlWalkFrameChain");
extern fn Win32_BOOL symInitialize(Win32_HANDLE hProcess, Win32_PCSTR userSearchPath, Win32_BOOL fInvadeProcess) @extern("SymInitialize");
extern fn Win32_BOOL symCleanup(Win32_HANDLE hProcess) @extern("SymCleanup");
extern fn Win32_DWORD64 symLoadModuleEx(Win32_HANDLE hProcess, Win32_HANDLE hFile, Win32_PCSTR imageName, Win32_PCSTR moduleName, Win32_DWORD64 baseOfDll, Win32_DWORD dllSize, Win32_PMODLOAD_DATA data, Win32_DWORD flags) @extern("SymLoadModule");
extern fn Win32_BOOL stackWalk64(Win32_DWORD machineType, Win32_HANDLE hProcess, Win32_HANDLE hThread, Win32_LPSTACKFRAME64 stackFrame, Win32_PVOID contextRecord, Win32_PREAD_PROCESS_MEMORY_ROUTINE64 readMemoryRoutine, Win32_PFUNCTION_TABLE_ACCESS_ROUTINE64 functionTableAccessRoutine, Win32_PGET_MODULE_BASE_ROUTINE64 getModuleBaseRoutine, Win32_PTRANSLATE_ADDRESS_ROUTINE64 translateAddress) @extern("StackWalk64");
extern fn void rtlCaptureContext(Win32_PCONTEXT contextRecord) @extern("RtlCaptureContext");
extern fn void* symFunctionTableAccess64(Win32_HANDLE hProcess, Win32_DWORD64 addrBase) @extern("SymFunctionTableAccess64");
extern fn Win32_DWORD64 symGetModuleBase64(Win32_HANDLE hProcess, Win32_DWORD64 qwAddr) @extern("SymGetModuleBase64");
extern fn Win32_DWORD getModuleBaseNameA(Win32_HANDLE hProcess, Win32_HMODULE hModule, Win32_LPSTR lpBaseName, Win32_DWORD nSize) @extern("K32GetModuleBaseNameA");
extern fn Win32_DWORD symGetOptions() @extern("SymGetOptions");
extern fn Win32_DWORD symSetOptions(Win32_DWORD symOptions) @extern("SymSetOptions");
extern fn Win32_PIMAGE_NT_HEADERS imageNtHeader(Win32_PVOID base) @extern("ImageNtHeader");
extern fn Win32_DWORD unDecorateSymbolName(Win32_PCSTR name, Win32_PSTR outputString, Win32_DWORD maxStringLength, Win32_DWORD flags) @extern("UnDecorateSymbolName");
extern fn Win32_BOOL symFromAddr(Win32_HANDLE hProcess, Win32_DWORD64 address, Win32_PDWORD64 displacement, Win32_PSYMBOL_INFO symbol) @extern("SymFromAddr");
extern fn Win32_BOOL symGetLineFromAddr64(Win32_HANDLE hProcess, Win32_DWORD64 dwAddr, Win32_PDWORD pdwDisplacement, Win32_PIMAGEHLP_LINE64 line) @extern("SymGetLineFromAddr64");
extern fn Win32_WORD rtlCaptureStackBackTrace(Win32_DWORD framesToSkip, Win32_DWORD framesToCapture, Win32_PVOID *backTrace, Win32_PDWORD backTraceHash) @extern("RtlCaptureStackBackTrace");
extern fn Win32_BOOL symGetModuleInfo64(Win32_HANDLE hProcess, Win32_DWORD64 qwAddr, Win32_PIMAGEHLP_MODULE64 moduleInfo) @extern("SymGetModuleInfo64");
extern fn void initializeCriticalSection(Win32_CRITICAL_SECTION* section) @cname("InitializeCriticalSection");
extern fn void deleteCriticalSection(Win32_CRITICAL_SECTION* section) @cname("DeleteCriticalSection");
extern fn Win32_HANDLE createMutex(void*, Win32_BOOL, void*) @cname("CreateMutexA");
extern fn Win32_BOOL releaseMutex(Win32_HANDLE) @cname("ReleaseMutex");
extern fn void enterCriticalSection(Win32_CRITICAL_SECTION* section) @cname("EnterCriticalSection");
extern fn void leaveCriticalSection(Win32_CRITICAL_SECTION* section) @cname("LeaveCriticalSection");
extern fn Win32_BOOL tryEnterCriticalSection(Win32_CRITICAL_SECTION* section) @cname("TryEnterCriticalSection");
extern fn void initializeSRWLock(Win32_SRWLOCK* lock) @cname("InitializeSRWLock");
extern fn void acquireSRWLockExclusive(Win32_SRWLOCK* lock) @cname("AcquireSRWLockExclusive");
extern fn void acquireSRWLockShared(Win32_SRWLOCK* lock) @cname("AcquireSRWLockShared");
extern fn void releaseSRWLockExclusive(Win32_SRWLOCK* lock) @cname("ReleaseSRWLockExclusive");
extern fn void releaseSRWLockShared(Win32_SRWLOCK* lock) @cname("ReleaseSRWLockShared");
extern fn Win32_BOOL tryAcquireSRWLockExclusive(Win32_SRWLOCK* lock) @cname("TryAcquireSRWLockExclusive");
extern fn Win32_BOOL tryAcquireSRWLockShared(Win32_SRWLOCK* lock) @cname("TryAcquireSRWLockShared");
extern fn void initializeConditionVariable(Win32_CONDITION_VARIABLE* conditionVariable) @cname("InitializeConditionVariable");
extern fn void wakeConditionVariable(Win32_CONDITION_VARIABLE* conditionVariable) @cname("WakeConditionVariable");
extern fn void wakeAllConditionVariable(Win32_CONDITION_VARIABLE* conditionVariable) @cname("WakeAllConditionVariable");
extern fn Win32_BOOL sleepConditionVariableCS(Win32_CONDITION_VARIABLE* conditionVariable, Win32_CRITICAL_SECTION* section, Win32_DWORD dwMilliseconds) @cname("SleepConditionVariableCS");
extern fn Win32_BOOL sleepConditionVariableSRW(Win32_CONDITION_VARIABLE* conditionVariable, Win32_SRWLOCK* lock, Win32_DWORD dwMilliseconds, Win32_ULONG flags) @cname("SleepConditionVariableSRW");
extern fn Win32_BOOL initOnceExecuteOnce(Win32_INIT_ONCE* initOnce, Win32_INIT_ONCE_FN initFn, void* parameter, void** context) @cname("InitOnceExecuteOnce");
extern fn Win32_DWORD waitForSingleObject(Win32_HANDLE hHandle, Win32_DWORD dwMilliseconds) @cname("WaitForSingleObject");
extern fn Win32_DWORD waitForSingleObjectEx(Win32_HANDLE hHandle, Win32_DWORD dwMilliseconds, Win32_BOOL bAlertable) @cname("WaitForSingleObjectEx");
extern fn Win32_DWORD waitForMultipleObjects(Win32_DWORD nCount, Win32_HANDLE* lpHandles, Win32_BOOL bWaitAll, Win32_DWORD dwMilliseconds) @cname("WaitForMultipleObjects");
extern fn Win32_DWORD waitForMultipleObjectsEx(Win32_DWORD nCount, Win32_HANDLE* lpHandles, Win32_BOOL bWaitAll, Win32_DWORD dwMilliseconds, Win32_BOOL bAlertable) @cname("WaitForMultipleObjectsEx");
extern fn void sleep(uint ms) @cname("Sleep");
extern fn Win32_BOOL resetEvent(Win32_HANDLE event) @cname("ResetEvent");
extern fn Win32_BOOL setEvent(Win32_HANDLE handle) @cname("SetEvent");
extern fn long interlockedCompareExchange(int* dest, int exchange, int comperand) @cname("InterlockedCompareExchange");
extern fn Win32_DWORD sleepEx(Win32_DWORD ms, Win32_BOOL alertable) @cname("SleepEx");
extern fn Win32_HANDLE createThread(void* attributes, usz stack, ThreadFn func, Win32_LPVOID arg, Win32_DWORD flags, Win32_LPDWORD thread_id) @cname("CreateThread");
extern fn Win32_BOOL getExitCodeThread(Win32_HANDLE handle, Win32_LPDWORD exit_code) @cname("GetExitCodeThread");
extern fn Win32_BOOL getExitCodeProcess(Win32_HANDLE hProcess, Win32_LPDWORD lpExitCode) @cname("GetExitCodeProcess");
extern fn Win32_DWORD getThreadId(Win32_HANDLE) @cname("GetThreadId");
extern fn void exitThread(Win32_DWORD dwExitCode) @noreturn @cname("ExitThread");
extern fn Win32_HANDLE getCurrentThread() @cname("GetCurrentThread");
extern fn Win32_BOOL terminateProcess(Win32_HANDLE hProcess, Win32_UINT uExitCode) @cname("TerminateProcess");
extern fn Win32_DWORD getCurrentProcessId() @cname("GetCurrentProcessId");
extern fn Win32_HANDLE getCurrentProcess() @cname("GetCurrentProcess");
extern fn Win32_DWORD getCurrentThreadId() @cname("GetCurrentThreadId");
extern fn Win32_BOOL setHandleInformation(Win32_HANDLE hObject, Win32_DWORD dwMask, Win32_DWORD dwFlags) @cname("SetHandleInformation");
extern fn Win32_HANDLE createEventA(Win32_LPSECURITY_ATTRIBUTES lpEventAttributes, Win32_BOOL bManualReset, Win32_BOOL bInitialState, Win32_LPCSTR lpName) @cname("CreateEventA");
extern fn Win32_BOOL createProcessW(Win32_LPCWSTR lpApplicationName, Win32_LPWSTR lpCommandLine, Win32_LPSECURITY_ATTRIBUTES lpProcessAttributes, Win32_LPSECURITY_ATTRIBUTES lpThreadAttributes, Win32_BOOL bInheritHandles, Win32_DWORD dwCreationFlags, Win32_LPVOID lpEnvironment, Win32_LPCWSTR lpCurrentDirectory, Win32_LPSTARTUPINFOW lpStartupInfo, Win32_LPPROCESS_INFORMATION lpProcessInformation) @cname("CreateProcessW");
extern fn Win32_HANDLE createNamedPipeA(Win32_LPCSTR lpName, Win32_DWORD dwOpenMode, Win32_DWORD dwPipeMode, Win32_DWORD nMaxInstances, Win32_DWORD nOutBufferSize, Win32_DWORD nInBufferSize, Win32_DWORD nDefaultTimeOut, Win32_LPSECURITY_ATTRIBUTES lpSecurityAttributes) @cname("CreateNamedPipeA");
extern fn Win32_BOOL getOverlappedResult(Win32_HANDLE hFile, Win32_LPOVERLAPPED lpOverlapped, Win32_LPDWORD lpNumberOfBytesTransferred, Win32_BOOL bWait) @cname("GetOverlappedResult");
extern fn Win32_DWORD getEnvironmentVariableW(Win32_LPCWSTR lpName, Win32_LPWSTR lpBuffer, Win32_DWORD nSize) @cname("GetEnvironmentVariableW");
extern fn Win32_BOOL setEnvironmentVariableW(Win32_LPCWSTR lpName, Win32_LPCWSTR lpValue) @cname("SetEnvironmentVariableW");
extern fn void getSystemInfo(Win32_LPSYSTEM_INFO lpSystemInfo) @cname("GetSystemInfo");
extern fn Win32_BOOL enumProcessModules(Win32_HANDLE hProcess, Win32_HMODULE* lphModule, Win32_DWORD cb, Win32_LPDWORD lpcbNeeded) @cname("K32EnumProcessModules");
extern fn Win32_BOOL getModuleInformation(Win32_HANDLE hProcess, Win32_HMODULE hModule, Win32_LPMODULEINFO lpmodinfo, Win32_DWORD cb) @cname("K32GetModuleInformation");
extern fn Win32_DWORD symAddrIncludeInlineTrace(Win32_HANDLE hProcess, Win32_DWORD64 address) @cname("SymAddrIncludeInlineTrace");
extern fn Win32_BOOL symQueryInlineTrace(Win32_HANDLE hProcess, Win32_DWORD64 startAddress, Win32_DWORD startContext, Win32_DWORD64 startRetAddress, Win32_DWORD64 curAddress, Win32_LPDWORD curContext, Win32_LPDWORD curFrameIndex) @cname("SymQueryInlineTrace");
extern fn Win32_BOOL symFromInlineContext(Win32_HANDLE hProcess, Win32_DWORD64 address, Win32_ULONG inlineContext, Win32_PDWORD64 displacement, Win32_PSYMBOL_INFO symbol) @cname("SymFromInlineContext");
extern fn Win32_BOOL symGetLineFromInlineContext(Win32_HANDLE hProcess, Win32_DWORD64 qwAddr, Win32_ULONG inlineContext, Win32_DWORD64 qwModuleBaseAddress, Win32_PDWORD pdwDisplacement, Win32_PIMAGEHLP_LINE64 line64) @cname("SymGetLineFromInlineContext");
extern fn Win32_ULONG rtlWalkFrameChain(Win32_PVOID*, Win32_ULONG, Win32_ULONG) @cname("RtlWalkFrameChain");
extern fn Win32_BOOL symInitialize(Win32_HANDLE hProcess, Win32_PCSTR userSearchPath, Win32_BOOL fInvadeProcess) @cname("SymInitialize");
extern fn Win32_BOOL symCleanup(Win32_HANDLE hProcess) @cname("SymCleanup");
extern fn Win32_DWORD64 symLoadModuleEx(Win32_HANDLE hProcess, Win32_HANDLE hFile, Win32_PCSTR imageName, Win32_PCSTR moduleName, Win32_DWORD64 baseOfDll, Win32_DWORD dllSize, Win32_PMODLOAD_DATA data, Win32_DWORD flags) @cname("SymLoadModule");
extern fn Win32_BOOL stackWalk64(Win32_DWORD machineType, Win32_HANDLE hProcess, Win32_HANDLE hThread, Win32_LPSTACKFRAME64 stackFrame, Win32_PVOID contextRecord, Win32_PREAD_PROCESS_MEMORY_ROUTINE64 readMemoryRoutine, Win32_PFUNCTION_TABLE_ACCESS_ROUTINE64 functionTableAccessRoutine, Win32_PGET_MODULE_BASE_ROUTINE64 getModuleBaseRoutine, Win32_PTRANSLATE_ADDRESS_ROUTINE64 translateAddress) @cname("StackWalk64");
extern fn void rtlCaptureContext(Win32_PCONTEXT contextRecord) @cname("RtlCaptureContext");
extern fn void* symFunctionTableAccess64(Win32_HANDLE hProcess, Win32_DWORD64 addrBase) @cname("SymFunctionTableAccess64");
extern fn Win32_DWORD64 symGetModuleBase64(Win32_HANDLE hProcess, Win32_DWORD64 qwAddr) @cname("SymGetModuleBase64");
extern fn Win32_DWORD getModuleBaseNameA(Win32_HANDLE hProcess, Win32_HMODULE hModule, Win32_LPSTR lpBaseName, Win32_DWORD nSize) @cname("K32GetModuleBaseNameA");
extern fn Win32_DWORD symGetOptions() @cname("SymGetOptions");
extern fn Win32_DWORD symSetOptions(Win32_DWORD symOptions) @cname("SymSetOptions");
extern fn Win32_PIMAGE_NT_HEADERS imageNtHeader(Win32_PVOID base) @cname("ImageNtHeader");
extern fn Win32_DWORD unDecorateSymbolName(Win32_PCSTR name, Win32_PSTR outputString, Win32_DWORD maxStringLength, Win32_DWORD flags) @cname("UnDecorateSymbolName");
extern fn Win32_BOOL symFromAddr(Win32_HANDLE hProcess, Win32_DWORD64 address, Win32_PDWORD64 displacement, Win32_PSYMBOL_INFO symbol) @cname("SymFromAddr");
extern fn Win32_BOOL symGetLineFromAddr64(Win32_HANDLE hProcess, Win32_DWORD64 dwAddr, Win32_PDWORD pdwDisplacement, Win32_PIMAGEHLP_LINE64 line) @cname("SymGetLineFromAddr64");
extern fn Win32_WORD rtlCaptureStackBackTrace(Win32_DWORD framesToSkip, Win32_DWORD framesToCapture, Win32_PVOID *backTrace, Win32_PDWORD backTraceHash) @cname("RtlCaptureStackBackTrace");
extern fn Win32_BOOL symGetModuleInfo64(Win32_HANDLE hProcess, Win32_DWORD64 qwAddr, Win32_PIMAGEHLP_MODULE64 moduleInfo) @cname("SymGetModuleInfo64");
fn Win32_DWORD? load_modules()
{

View File

@@ -2,7 +2,7 @@ module std::os::win32 @if(env::WIN32) @link("shell32");
typedef Win32_REFKNOWNFOLDERID = Win32_KNOWNFOLDERID*;
typedef Win32_KNOWNFOLDERID = Win32_GUID;
extern fn Win32_HRESULT shGetKnownFolderPath(Win32_REFKNOWNFOLDERID rfid, Win32_DWORD dwFlags, Win32_HANDLE hToken, Win32_PWSTR* ppszPath) @extern("SHGetKnownFolderPath");
extern fn Win32_HRESULT shGetKnownFolderPath(Win32_REFKNOWNFOLDERID rfid, Win32_DWORD dwFlags, Win32_HANDLE hToken, Win32_PWSTR* ppszPath) @cname("SHGetKnownFolderPath");
const Win32_KNOWNFOLDERID FOLDERID_PROFILE = { 0x5E6C858F, 0x0E22, 0x4760, x"9AFEEA3317B67173" };
const Win32_KNOWNFOLDERID FOLDERID_DESKTOP = { 0xB4BFCC3A, 0xDB2C, 0x424C, x"B0297FE99A87C641" };

View File

@@ -110,26 +110,26 @@ const GWLP_HWNDPARENT = -8;
const GWLP_USERDATA = -21;
const GWLP_ID = -12;
extern fn Win32_HDC beginPaint(Win32_HWND, Win32_LPPAINTSTRUCT) @extern("BeginPaint");
extern fn Win32_LRESULT callWindowProcW(Win32_WNDPROC lpPrevWndFunc, Win32_HWND hWnd, Win32_UINT msg, Win32_WPARAM wParam, Win32_LPARAM lParam) @extern("CallWindowProcW");
extern fn Win32_HWND createWindowExW(Win32_DWORD, Win32_LPCWSTR, Win32_LPCWSTR, Win32_DWORD, CInt, CInt, CInt, CInt, Win32_HWND, Win32_HMENU, Win32_HINSTANCE, Win32_LPVOID) @extern("CreateWindowExW");
extern fn Win32_LRESULT defWindowProcW(Win32_HWND, Win32_UINT, Win32_WPARAM, Win32_LPARAM) @extern("DefWindowProcW");
extern fn Win32_BOOL dispatchMessage(Win32_MSG* lpMsg) @extern("DispatchMessageW");
extern fn Win32_BOOL endPaint(Win32_HWND, Win32_LPPAINTSTRUCT) @extern("EndPaint");
extern fn Win32_BOOL getMessageW(Win32_LPMSG, Win32_HWND, Win32_UINT, Win32_UINT) @extern("GetMessageW");
extern fn Win32_BOOL getUpdateRect(Win32_HWND hWnd, Win32_LPRECT lpRect, Win32_BOOL bErase) @extern("GetUpdateRect");
extern fn Win32_LONG_PTR getWindowLongPtrW(Win32_HWND hWnd, CInt nIndex) @extern("GetWindowLongPtrW");
extern fn Win32_LONG getWindowLongW(Win32_HWND hWnd, CInt nIndex) @extern("GetWindowLongW");
extern fn Win32_HCURSOR loadCursorW(Win32_HINSTANCE instance, Win32_LPCWSTR cursorName) @extern("LoadCursorW");
extern fn Win32_HICON loadIconW(Win32_HINSTANCE instance, Win32_LPCWSTR iconName) @extern("LoadIconW");
extern fn int messageBoxW(Win32_HWND hWnd, Win32_LPCWSTR lpText, Win32_LPCWSTR lpCaption, Win32_UINT uType) @extern("MessageBoxW");
extern fn void postQuitMessage(CInt) @extern("PostQuitMessage");
extern fn Win32_ATOM registerClassExW(Win32_WNDCLASSEXW*) @extern("RegisterClassExW");
extern fn Win32_LONG_PTR setWindowLongPtrW(Win32_HWND hWnd, CInt nIndex, Win32_LONG_PTR dwNewLong) @extern("SetWindowLongPtrW");
extern fn Win32_LONG setWindowLongW(Win32_HWND hWnd, CInt nIndex, Win32_LONG dwNewLong) @extern("SetWindowLongW");
extern fn Win32_BOOL showWindow(Win32_HWND, CInt) @extern("ShowWindow");
extern fn Win32_BOOL translateMessage(Win32_MSG* lpMsg) @extern("TranslateMessage");
extern fn Win32_BOOL updateWindow(Win32_HWND) @extern("UpdateWindow");
extern fn Win32_HDC beginPaint(Win32_HWND, Win32_LPPAINTSTRUCT) @cname("BeginPaint");
extern fn Win32_LRESULT callWindowProcW(Win32_WNDPROC lpPrevWndFunc, Win32_HWND hWnd, Win32_UINT msg, Win32_WPARAM wParam, Win32_LPARAM lParam) @cname("CallWindowProcW");
extern fn Win32_HWND createWindowExW(Win32_DWORD, Win32_LPCWSTR, Win32_LPCWSTR, Win32_DWORD, CInt, CInt, CInt, CInt, Win32_HWND, Win32_HMENU, Win32_HINSTANCE, Win32_LPVOID) @cname("CreateWindowExW");
extern fn Win32_LRESULT defWindowProcW(Win32_HWND, Win32_UINT, Win32_WPARAM, Win32_LPARAM) @cname("DefWindowProcW");
extern fn Win32_BOOL dispatchMessage(Win32_MSG* lpMsg) @cname("DispatchMessageW");
extern fn Win32_BOOL endPaint(Win32_HWND, Win32_LPPAINTSTRUCT) @cname("EndPaint");
extern fn Win32_BOOL getMessageW(Win32_LPMSG, Win32_HWND, Win32_UINT, Win32_UINT) @cname("GetMessageW");
extern fn Win32_BOOL getUpdateRect(Win32_HWND hWnd, Win32_LPRECT lpRect, Win32_BOOL bErase) @cname("GetUpdateRect");
extern fn Win32_LONG_PTR getWindowLongPtrW(Win32_HWND hWnd, CInt nIndex) @cname("GetWindowLongPtrW");
extern fn Win32_LONG getWindowLongW(Win32_HWND hWnd, CInt nIndex) @cname("GetWindowLongW");
extern fn Win32_HCURSOR loadCursorW(Win32_HINSTANCE instance, Win32_LPCWSTR cursorName) @cname("LoadCursorW");
extern fn Win32_HICON loadIconW(Win32_HINSTANCE instance, Win32_LPCWSTR iconName) @cname("LoadIconW");
extern fn int messageBoxW(Win32_HWND hWnd, Win32_LPCWSTR lpText, Win32_LPCWSTR lpCaption, Win32_UINT uType) @cname("MessageBoxW");
extern fn void postQuitMessage(CInt) @cname("PostQuitMessage");
extern fn Win32_ATOM registerClassExW(Win32_WNDCLASSEXW*) @cname("RegisterClassExW");
extern fn Win32_LONG_PTR setWindowLongPtrW(Win32_HWND hWnd, CInt nIndex, Win32_LONG_PTR dwNewLong) @cname("SetWindowLongPtrW");
extern fn Win32_LONG setWindowLongW(Win32_HWND hWnd, CInt nIndex, Win32_LONG dwNewLong) @cname("SetWindowLongW");
extern fn Win32_BOOL showWindow(Win32_HWND, CInt) @cname("ShowWindow");
extern fn Win32_BOOL translateMessage(Win32_MSG* lpMsg) @cname("TranslateMessage");
extern fn Win32_BOOL updateWindow(Win32_HWND) @cname("UpdateWindow");
macro getWindowLongPtr(Win32_HWND hWnd, CInt nIndex)
{

View File

@@ -1,4 +1,4 @@
module std::os::win32 @if(env::WIN32);
module std::os::win32 @if(env::WIN32) @link("ws2_32");
// See https://github.com/wine-mirror/wine/blob/master/include/winsock2.h
@@ -122,11 +122,11 @@ const SD_RECEIVE = 0x00;
const SD_SEND = 0x01;
const SD_BOTH = 0x02;
extern fn CInt wsaPoll(Win32_LPWSAPOLLFD fdArray, Win32_ULONG fds, Win32_INT timeout) @extern("WSAPoll");
extern fn WSAError wsaGetLastError() @extern("WSAGetLastError");
extern fn void wsaSetLastError(WSAError error) @extern("WSASetLastError");
extern fn CInt wsaStartup(Win32_WORD, void*) @extern("WSAStartup");
extern fn CInt wsaCleanup() @extern("WSACleanup");
extern fn CInt wsaPoll(Win32_LPWSAPOLLFD fdArray, Win32_ULONG fds, Win32_INT timeout) @cname("WSAPoll");
extern fn WSAError wsaGetLastError() @cname("WSAGetLastError");
extern fn void wsaSetLastError(WSAError error) @cname("WSASetLastError");
extern fn CInt wsaStartup(Win32_WORD, void*) @cname("WSAStartup");
extern fn CInt wsaCleanup() @cname("WSACleanup");
const int FIONBIO = -2147195266;
const int FIONREAD = 1074030207;

View File

@@ -3,6 +3,8 @@ module std::sort;
<*
Perform a binary search over the sorted array and return the index
in [0, array.len) where x would be inserted or cmp(i) is true and cmp(j) is true for j in [i, array.len).
@require @list_is_by_ref(list) : "Expected a list passed by reference or a slice"
@require @is_sortable(list) : "The list must be sortable"
@require @is_valid_cmp_fn(cmp, list, context) : "Expected a comparison function which compares values"
@require @is_valid_context(cmp, context) : "Expected a valid context"
@@ -10,42 +12,81 @@ in [0, array.len) where x would be inserted or cmp(i) is true and cmp(j) is true
macro usz binarysearch(list, x, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLOT) @builtin
{
usz i;
usz len = lengthof(list);
var $no_cmp = @is_empty_macro_slot(cmp);
var $has_context = @is_valid_macro_slot(context);
for (usz j = len; i < j;)
{
usz half = i + (j - i) / 2;
$if $no_cmp:
switch
{
case greater(list[half], x): j = half;
case less(list[half], x): i = half + 1;
default: return half;
}
$else
$switch:
$case $defined(cmp(list[0], list[0], context)):
int res = cmp(list[half], x, context);
$case $defined(cmp(list[0], list[0])):
assert(!$has_context);
int res = cmp(list[half], x);
$case $defined(cmp(&list[0], &list[0], context)):
int res = cmp(&list[half], &x, context);
$case $defined(cmp(&list[0], &list[0])):
assert(!$has_context);
int res = cmp(&list[half], &x);
$default:
assert(false, "Invalid comparison function");
$endswitch
switch
{
case res > 0: j = half;
case res < 0: i = half + 1;
default: return half;
}
$endif
}
return i;
$if $kindof(list) == SLICE:
usz len = lengthof(list);
for (usz j = len; i < j;)
{
usz half = i + (j - i) / 2;
$if $no_cmp:
switch
{
case greater(list[half], x): j = half;
case less(list[half], x): i = half + 1;
default: return half;
}
$else
$switch:
$case $defined(cmp(list[0], list[0], context)):
int res = cmp(list[half], x, context);
$case $defined(cmp(list[0], list[0])):
assert(!$has_context);
int res = cmp(list[half], x);
$case $defined(cmp(&list[0], &list[0], context)):
int res = cmp(&list[half], &x, context);
$case $defined(cmp(&list[0], &list[0])):
assert(!$has_context);
int res = cmp(&list[half], &x);
$default:
assert(false, "Invalid comparison function");
$endswitch
switch
{
case res > 0: j = half;
case res < 0: i = half + 1;
default: return half;
}
$endif
}
$else
usz len = lengthof(*list);
for (usz j = len; i < j;)
{
usz half = i + (j - i) / 2;
$if $no_cmp:
switch
{
case greater((*list)[half], x): j = half;
case less((*list)[half], x): i = half + 1;
default: return half;
}
$else
$switch:
$case $defined(cmp((*list)[0], (*list)[0], context)):
int res = cmp(list[half], x, context);
$case $defined(cmp((*list)[0], (*list)[0])):
assert(!$has_context);
int res = cmp((*list)[half], x);
$case $defined(cmp(&(*list)[0], &(*list)[0], context)):
int res = cmp(&(*list)[half], &x, context);
$case $defined(cmp(&(*list)[0], &(*list)[0])):
assert(!$has_context);
int res = cmp(&(*list)[half], &x);
$default:
assert(false, "Invalid comparison function");
$endswitch
switch
{
case res > 0: j = half;
case res < 0: i = half + 1;
default: return half;
}
$endif
}
$endif
return i;
}

View File

@@ -4,24 +4,39 @@ import std::sort::cs;
import std::sort::qs;
<*
Sort list using the counting sort algorithm.
Sort list using the counting sort algorithm.
@require @list_is_by_ref(list) : "Expected the list to be passed by reference"
@require @is_sortable(list) : "The list must be indexable and support .len or .len()"
@require @is_cmp_key_fn(key_fn, list) : "Expected a transformation function which returns an unsigned integer."
*>
macro void countingsort(list, key_fn = EMPTY_MACRO_SLOT) @builtin
{
usz len = lengthof(list);
cs::csort{$typeof(list), $typeof(key_fn)}(list, 0, len, key_fn, ~((uint)0));
$if $kindof(list) == SLICE:
cs::csort{$typeof(list), $typeof(key_fn)}(list, 0, list.len, key_fn, ~((uint)0));
$else
cs::csort{$typeof(*list), $typeof(key_fn)}(list, 0, lengthof(*list), key_fn, ~((uint)0));
$endif
}
macro void insertionsort_indexed(list, start, end, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLOT) @builtin
{
is::isort{$typeof(list), $typeof(cmp), $typeof(context)}(list, (usz)start, (usz)end, cmp, context);
$if $kindof(list) == SLICE:
is::isort{$typeof((list)), $typeof(cmp), $typeof(context)}(list, (usz)start, (usz)end, cmp, context);
$else
is::isort{$typeof((*list)), $typeof(cmp), $typeof(context)}(list, (usz)start, (usz)end, cmp, context);
$endif
}
macro void quicksort_indexed(list, start, end, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLOT) @builtin
{
qs::qsort{$typeof(list), $typeof(cmp), $typeof(context)}(list, (isz)start, (isz)(end-1), cmp, context);
$if $kindof(list) == SLICE:
qs::qsort{$typeof((list)), $typeof(cmp), $typeof(context)}(list, (isz)start, (isz)(end-1), cmp, context);
$else
qs::qsort{$typeof((*list)), $typeof(cmp), $typeof(context)}(list, (isz)start, (isz)(end-1), cmp, context);
$endif
}
module std::sort::cs{Type, KeyFn};
@@ -42,7 +57,14 @@ alias CmpCallback @if(!KEY_BY_VALUE && NO_KEY_FN) = fn int(ElementType*, Element
alias CmpCallback @if(KEY_BY_VALUE && !NO_KEY_FN) = fn int(ElementType, ElementType, KeyFn);
alias CmpCallback @if(!KEY_BY_VALUE && !NO_KEY_FN) = fn int(ElementType*, ElementType*, KeyFn);
fn void csort(Type list, usz low, usz high, KeyFn key_fn, uint byte_idx)
const bool IS_SLICE = Type.kindof == SLICE;
alias ListType = $typefrom(IS_SLICE ??? Type : Type*);
macro list_get(ListType l, i) @if(!IS_SLICE) => (*l)[i];
macro list_get(ListType l, i) @if(IS_SLICE) => l[i];
macro list_get_ref(ListType l, i) @if(!IS_SLICE) => &(*l)[i];
macro list_get_ref(ListType l, i) @if(IS_SLICE) => &l[i];
fn void csort(ListType list, usz low, usz high, KeyFn key_fn, uint byte_idx)
{
if (high <= low) return;
$if NO_KEY_FN:
@@ -67,13 +89,13 @@ fn void csort(Type list, usz low, usz high, KeyFn key_fn, uint byte_idx)
{
$switch:
$case NO_KEY_FN:
KeyFnReturnType k = list[i];
KeyFnReturnType k = list_get(list, i);
$case KEY_BY_VALUE:
KeyFnReturnType k = key_fn(list[i]);
KeyFnReturnType k = key_fn(list_get(list, i));
$case LIST_HAS_REF:
KeyFnReturnType k = key_fn(&list[i]);
KeyFnReturnType k = key_fn(list_get_ref(list, i));
$default:
KeyFnReturnType k = key_fn(&&list[i]);
KeyFnReturnType k = key_fn(&&list_get(list, i));
$endswitch;
char key_byte = (char)((k >> (byte_idx * 8)) & 0xff);
@@ -131,17 +153,21 @@ fn void csort(Type list, usz low, usz high, KeyFn key_fn, uint byte_idx)
{
$switch:
$case NO_KEY_FN:
KeyFnReturnType k = list[low + s];
KeyFnReturnType k = list_get(list, low + s);
$case KEY_BY_VALUE:
KeyFnReturnType k = key_fn(list[low + s]);
KeyFnReturnType k = key_fn(list_get(list, low + s));
$case LIST_HAS_REF:
KeyFnReturnType k = key_fn(&list[low + s]);
KeyFnReturnType k = key_fn(list_get_ref(list, low + s));
$default:
KeyFnReturnType k = key_fn(&&list[low + s]);
KeyFnReturnType k = key_fn(&&list_get(list, low + s));
$endswitch;
char k_idx = (char)(k >> (byte_idx * 8));
usz target_idx = counts[k_idx];
@swap(list[low + s], list[low + target_idx]);
$if IS_SLICE:
@swap(list[low + s], list[low + target_idx]);
$else
@swap((*list)[low + s], (*list)[low + target_idx]);
$endif
counts[k_idx]++;
}
}

View File

@@ -4,38 +4,41 @@ import std::sort::is;
<*
Sort list using the quick sort algorithm.
@require @list_is_by_ref(list) : "Expected a list passed by reference, or slice passed by value"
@require @is_sortable(list) : "The list must be indexable and support .len or .len()"
@require @is_valid_cmp_fn(cmp, list, context) : "Expected a comparison function which compares values"
*>
macro void insertionsort(list, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLOT) @builtin @safemacro
{
$if $kindof(list) == POINTER &&& ($kindof(*list) == ARRAY || $kindof(*list) == VECTOR):
$typeof((*list)[0])[] list2 = list;
is::isort{$typeof(list2), $typeof(cmp), $typeof(context)}(list2, 0, list.len, cmp, context);
$if $kindof(list) == SLICE:
is::isort{$typeof(list), $typeof(cmp), $typeof(context)}(list, 0, lengthof(list), cmp, context);
$else
usz len = lengthof(list);
is::isort{$typeof(list), $typeof(cmp), $typeof(context)}(list, 0, (isz)len, cmp, context);
is::isort{$typeof(*list), $typeof(cmp), $typeof(context)}(list, 0, lengthof(*list), cmp, context);
$endif
}
module std::sort::is{Type, CmpFn, Context};
alias ElementType = $typeof(((Type){})[0]);
const bool IS_SLICE = Type.kindof == SLICE;
alias ListType = $typefrom(IS_SLICE ??? Type : Type*);
macro ElementType list_get(ListType l, i) => IS_SLICE ??? l[i] : (*l)[i];
macro ElementType* list_get_ref(ListType l, i) => IS_SLICE ??? &l[i] : &(*l)[i];
fn void isort(Type list, usz low, usz high, CmpFn comp, Context context)
fn void isort(ListType 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 &&& $defined($typefrom(CmpFn.paramsof[0].type) p = list[0]);
var $has_get_ref = $defined(&list[0]);
var $cmp_by_value = $has_cmp &&& $defined($typefrom(CmpFn.paramsof[0].type) p = list_get(list, 0));
var $has_get_ref = IS_SLICE ||| $defined(&(*list)[0]);
for (usz i = low; i < high; ++i)
{
usz j = i;
for (;j > low;)
{
$if $has_get_ref:
ElementType *rhs = &list[j];
ElementType *lhs = &list[--j];
ElementType *rhs = list_get_ref(list, j);
ElementType *lhs = list_get_ref(list, --j);
$switch:
$case $cmp_by_value && $has_context:
if (comp(*rhs, *lhs, context) >= 0) break;
@@ -54,17 +57,21 @@ fn void isort(Type list, usz low, usz high, CmpFn comp, Context context)
--j;
$switch:
$case $cmp_by_value && $has_context:
if (comp(list[r], list[j], context) >= 0) break;
if (comp(list_get(list, r), list_get(j), context) >= 0) break;
$case $cmp_by_value:
if (comp(list[r], list[j]) >= 0) break;
if (comp(list_get(list, r), list_get(j)) >= 0) break;
$case $has_cmp && $has_context:
if (comp(&list[r], &list[j], context) >= 0) break;
if (comp(list_get_ref(list, r), list_get_ref(j), context) >= 0) break;
$case $has_cmp:
if (comp(&list[r], &list[j]) >= 0) break;
if (comp(list_get_ref(list, r), list_get_ref(j)) >= 0) break;
$default:
if (!less(list[r], list[j])) break;
if (!less(list_get(list, r), list_get(j))) break;
$endswitch
@swap(list[r], list[j]);
$if IS_SLICE:
@swap(list[r], list[j]);
$else
@swap((*list)[r], (*list)[j]);
$endif
$endif
}
}

View File

@@ -4,39 +4,50 @@ import std::sort::qs;
<*
Sort list using the quick sort algorithm.
@require @list_is_by_ref(list) : "Expected a list passed by reference or be a slice"
@require @is_sortable(list) : "The list must be indexable and support .len or .len()"
@require @is_valid_cmp_fn(cmp, list, context) : "Expected a comparison function which compares values"
@require @is_valid_context(cmp, context) : "Expected a valid context"
*>
macro void quicksort(list, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLOT) @builtin
{
$if $kindof(list) == POINTER &&& ($kindof(*list) == ARRAY || $kindof(*list) == VECTOR):
$typeof((*list)[0])[] list2 = list;
qs::qsort{$typeof(list2), $typeof(cmp), $typeof(context)}(list2, 0, (isz)list.len - 1, cmp, context);
$if $kindof(list) == SLICE:
qs::qsort{$typeof(list), $typeof(cmp), $typeof(context)}(list, 0, (isz)list.len - 1, cmp, context);
$else
usz len = lengthof(list);
qs::qsort{$typeof(list), $typeof(cmp), $typeof(context)}(list, 0, (isz)len - 1, cmp, context);
qs::qsort{$typeof(*list), $typeof(cmp), $typeof(context)}(list, 0, (isz)lengthof(*list) - 1, cmp, context);
$endif
}
<*
Select the (k+1)th smallest element in an unordered list using Hoare's
selection algorithm (Quickselect). k should be between 0 and len-1. The data
list will be partially sorted.
Select the (k+1)th smallest element in an unordered list using Hoare's
selection algorithm (Quickselect). k should be between 0 and len-1. The data
list will be partially sorted.
@require @list_is_by_ref(list) : "Expected a list passed by reference or be a slice"
@require @is_sortable(list) : "The list must be indexable and support .len or .len()"
@require @is_valid_cmp_fn(cmp, list, context) : "expected a comparison function which compares values"
@require @is_valid_context(cmp, context) : "Expected a valid context"
*>
macro quickselect(list, isz k, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLOT) @builtin
{
usz len = lengthof(list);
return qs::qselect{$typeof(list), $typeof(cmp), $typeof(context)}(list, 0, (isz)len - 1, k, cmp, context);
$if $kindof(list) == SLICE:
return qs::qselect{$typeof(list), $typeof(cmp), $typeof(context)}(list, 0, (isz)list.len - 1, k, cmp, context);
$else
return qs::qselect{$typeof(*list), $typeof(cmp), $typeof(context)}(list, 0, (isz)lengthof(*list) - 1, k, cmp, context);
$endif
}
module std::sort::qs{Type, CmpFn, Context};
alias ElementType = $typeof(((Type){})[0]);
const bool IS_SLICE = Type.kindof == SLICE;
alias ListType = $typefrom(IS_SLICE ??? Type : Type*);
macro list_get(ListType l, i) @if(!IS_SLICE) => (*l)[i];
macro list_get(ListType l, i) @if(IS_SLICE) => l[i];
macro list_get_ref(ListType l, i) @if(!IS_SLICE) => &(*l)[i];
macro list_get_ref(ListType l, i) @if(IS_SLICE) => &l[i];
macro list_set(ListType l, i, v) @if(!IS_SLICE) => (*l)[i] = v;
macro list_set(ListType l, i, v) @if(IS_SLICE) => l[i] = v;
struct StackElementItem @private
{
@@ -48,7 +59,7 @@ alias Stack @private = StackElementItem[64];
// Based on https://alienryderflex.com/quicksort by Darel Rex Finley, Public Domain.
fn void qsort(Type list, isz low, isz high, CmpFn cmp, Context context)
fn void qsort(ListType list, isz low, isz high, CmpFn cmp, Context context)
{
if (low >= 0 && high >= 0 && low < high)
{
@@ -86,7 +97,7 @@ fn void qsort(Type list, isz low, isz high, CmpFn cmp, Context context)
@require low <= k : "kth smallest element is smaller than lower bounds"
@require k <= high : "kth smallest element is larger than upper bounds"
*>
fn ElementType? qselect(Type list, isz low, isz high, isz k, CmpFn cmp, Context context)
fn ElementType? qselect(ListType list, isz low, isz high, isz k, CmpFn cmp, Context context)
{
if (low >= 0 && high >= 0 && low < high)
{
@@ -98,7 +109,7 @@ fn ElementType? qselect(Type list, isz low, isz high, isz k, CmpFn cmp, Context
while (l <= h && max_retries--)
{
pivot = @partition(list, l, h, cmp, context);
if (k == pivot) return list[k];
if (k == pivot) return list_get(list, k);
if (k < pivot)
{
h = pivot - 1;
@@ -112,40 +123,40 @@ fn ElementType? qselect(Type list, isz low, isz high, isz k, CmpFn cmp, Context
return NOT_FOUND?;
}
macro isz @partition(Type list, isz l, isz h, CmpFn cmp, Context context)
macro isz @partition(ListType list, isz l, isz h, CmpFn cmp, Context context)
{
var $has_cmp = @is_valid_macro_slot(cmp);
var $has_context = @is_valid_macro_slot(context);
var $cmp_by_value = $has_cmp &&& $defined($typefrom(CmpFn.paramsof[0].type) v = list[0]);
var $cmp_by_value = $has_cmp &&& $defined($typefrom(CmpFn.paramsof[0].type) v = list_get(list, 0));
ElementType pivot = list[l];
ElementType pivot = list_get(list, l);
while (l < h)
{
$switch:
$case $cmp_by_value && $has_context:
while (cmp(list[h], pivot, context) >= 0 && l < h) h--;
if (l < h) list[l++] = list[h];
while (cmp(list[l], pivot, context) <= 0 && l < h) l++;
while (cmp(list_get(list, h), pivot, context) >= 0 && l < h) h--;
if (l < h) list_set(list, l++, list_get(list, h));
while (cmp(list_get(list, l), pivot, context) <= 0 && l < h) l++;
$case $cmp_by_value:
while (cmp(list[h], pivot) >= 0 && l < h) h--;
if (l < h) list[l++] = list[h];
while (cmp(list[l], pivot) <= 0 && l < h) l++;
while (cmp(list_get(list, h), pivot) >= 0 && l < h) h--;
if (l < h) list_set(list, l++, list_get(list, h));
while (cmp(list_get(list, l), pivot) <= 0 && l < h) l++;
$case $has_cmp && $has_context:
while (cmp(&list[h], &pivot, context) >= 0 && l < h) h--;
if (l < h) list[l++] = list[h];
while (cmp(&list[l], &pivot, context) <= 0 && l < h) l++;
while (cmp(list_get_ref(list, h), &pivot, context) >= 0 && l < h) h--;
if (l < h) list_set(list, l++, list_get(list, h));
while (cmp(list_get_ref(list, l), &pivot, context) <= 0 && l < h) l++;
$case $has_cmp:
while (cmp(&list[h], &pivot) >= 0 && l < h) h--;
if (l < h) list[l++] = list[h];
while (cmp(&list[l], &pivot) <= 0 && l < h) l++;
while (cmp(list_get_ref(list, h), &pivot) >= 0 && l < h) h--;
if (l < h) list_set(list, l++, list_get(list, h));
while (cmp(list_get_ref(list, l), &pivot) <= 0 && l < h) l++;
$default:
while (greater_eq(list[h], pivot) && l < h) h--;
if (l < h) list[l++] = list[h];
while (less_eq(list[l], pivot) && l < h) l++;
while (greater_eq(list_get(list, h), pivot) && l < h) h--;
if (l < h) list_set(list, l++, list_get(list, h));
while (less_eq(list_get(list, l), pivot) && l < h) l++;
$endswitch
if (l < h) list[h--] = list[l];
if (l < h) list_set(list, h--, list_get(list, l));
}
list[l] = pivot;
list_set(list, l, pivot);
return l;
}

View File

@@ -1,50 +1,132 @@
module std::sort;
macro bool @list_is_by_ref(#list) @const
{
return $kindof(#list) == SLICE ||| ($kindof(#list) == POINTER &&& $kindof(*#list) != SLICE);
}
macro bool @is_sortable(#list)
<*
@require @list_is_by_ref(#list) : "Expected the list to be passed by ref or be a slice"
*>
macro bool @is_sortable(#list) @const
{
$switch:
$case !$defined(#list[0]):
$case $kindof(#list) == SLICE:
return true;
$case !$defined(*#list):
return false;
$case !$defined(#list.len):
$case !$defined((*#list)[0]):
return false;
$case $kindof(#list) == VECTOR || $kindof(#list) == ARRAY:
$case !$defined(lengthof(*#list)):
return false;
$case $defined(&#list[0]) &&& !types::is_same($typeof(&#list[0]), $typeof(#list[0])*):
$case $defined(&(*#list)[0]) &&& $typeof(&(*#list)[0]) != $typeof((*#list)[0])*:
return false;
$default:
return true;
$endswitch
}
macro bool @is_any_sortable(#list) @const
{
$switch $kindof(#list):
$case SLICE:
return true;
$case POINTER:
return @is_sortable(#list);
$default:
return $defined(#list[0]) &&& $defined(lengthof(#list))
&&& !($defined(&#list[0]) &&& $typeof(&#list[0]) != $typeof(#list[0])*);
$endswitch
}
macro bool @is_valid_context(#cmp, #context)
{
return @is_valid_macro_slot(#cmp) || @is_empty_macro_slot(#context);
}
macro bool @is_valid_cmp_fn(#cmp, #list, #context)
<*
@require @list_is_by_ref(#list) : "Expected the list to be passed by ref or be a slice"
*>
macro bool @is_valid_cmp_fn(#cmp, #list, #context) @const
{
var $Type = $typeof(#cmp);
var $no_context = @is_empty_macro_slot(#context);
$switch:
$case @is_empty_macro_slot(#cmp): return true;
$case $Type.kindof != FUNC ||| $Type.returns.kindof != SIGNED_INT: return false;
$case $defined(#cmp(#list[0], #list[0], #context)): return true;
$case $defined(#cmp(#list[0], #list[0])): return $no_context;
$case $defined(#cmp(&#list[0], &#list[0], #context)): return true;
$case $defined(#cmp(&#list[0], &#list[0])): return $no_context;
$default: return false;
$default:
$if $kindof(#list) == SLICE:
$switch:
$case $defined(#cmp((#list)[0], (#list)[0], #context)): return true;
$case $defined(#cmp((#list)[0], (#list)[0])): return $no_context;
$case $defined(#cmp(&(#list)[0], &(#list)[0], #context)): return true;
$case $defined(#cmp(&(#list)[0], &(#list)[0])): return $no_context;
$default: return false;
$endswitch
$else
$switch:
$case $defined(#cmp((*#list)[0], (*#list)[0], #context)): return true;
$case $defined(#cmp((*#list)[0], (*#list)[0])): return $no_context;
$case $defined(#cmp(&(*#list)[0], &(*#list)[0], #context)): return true;
$case $defined(#cmp(&(*#list)[0], &(*#list)[0])): return $no_context;
$default: return false;
$endswitch
$endif
$endswitch
}
macro bool @is_cmp_key_fn(#key_fn, #list)
macro bool @is_any_valid_cmp_fn(#cmp, #list, #context) @const
{
var $Type = $typeof(#cmp);
var $no_context = @is_empty_macro_slot(#context);
$switch:
$case @is_empty_macro_slot(#cmp): return true;
$case $Type.kindof != FUNC ||| $Type.returns.kindof != SIGNED_INT: return false;
$default:
$if $kindof(#list) != POINTER:
$switch:
$case $defined(#cmp((#list)[0], (#list)[0], #context)): return true;
$case $defined(#cmp((#list)[0], (#list)[0])): return $no_context;
$case $defined(#cmp(&(#list)[0], &(#list)[0], #context)): return true;
$case $defined(#cmp(&(#list)[0], &(#list)[0])): return $no_context;
$default: return false;
$endswitch
$else
$switch:
$case $defined(#cmp((*#list)[0], (*#list)[0], #context)): return true;
$case $defined(#cmp((*#list)[0], (*#list)[0])): return $no_context;
$case $defined(#cmp(&(*#list)[0], &(*#list)[0], #context)): return true;
$case $defined(#cmp(&(*#list)[0], &(*#list)[0])): return $no_context;
$default: return false;
$endswitch
$endif
$endswitch
}
<*
@require @list_is_by_ref(#list) : "Expected the list to be passed by ref or be a slice"
*>
macro bool @is_cmp_key_fn(#key_fn, #list) @const
{
$switch:
$case @is_empty_macro_slot(#key_fn): return true;
$case $kindof(#key_fn) != FUNC: return false;
$case $typeof(#key_fn).returns.kindof != UNSIGNED_INT: return false;
$case $defined(#key_fn(#list[0])): return true;
$case $defined(#key_fn(&&(#list[0]))): return true;
$default: return false;
$default:
$if $kindof(#list) == SLICE:
$switch:
$case $defined(#key_fn((#list)[0])): return true;
$case $defined(#key_fn(&&((#list)[0]))): return true;
$default: return false;
$endswitch
$else
$switch:
$case $defined(#key_fn((*#list)[0])): return true;
$case $defined(#key_fn(&&((*#list)[0]))): return true;
$default: return false;
$endswitch
$endif
$endswitch
}

View File

@@ -1,13 +1,15 @@
module std::sort;
<*
Returns true if list is sorted in either ascending or descending order.
@require @is_sortable(list) : "The list must be indexable and support .len or .len()"
@require @is_valid_cmp_fn(cmp, list, ctx) : "Expected a comparison function which compares values"
Returns true if list is sorted in either ascending or descending order.
@require @is_any_sortable(list) : "The list must be indexable and support .len or .len()"
@require @is_any_valid_cmp_fn(cmp, list, ctx) : "Expected a comparison function which compares values"
@require @is_valid_context(cmp, ctx) : "Expected a valid context"
*>
macro bool is_sorted(list, cmp = EMPTY_MACRO_SLOT, ctx = EMPTY_MACRO_SLOT) @builtin
{
$if ($kindof(list) != POINTER):
var $Type = $typeof(list);
usz len = lengthof(list);
if (len <= 1) return true;
@@ -16,6 +18,33 @@ macro bool is_sorted(list, cmp = EMPTY_MACRO_SLOT, ctx = EMPTY_MACRO_SLOT) @buil
usz i;
int sort_order;
// determine sort order (ascending or descending)
for (i = start; i < end && sort_order == 0; i++)
{
sort_order = @sort_cmp_slice(list, i, cmp, ctx);
}
// no sort order found, all elements are the same, consider list sorted
if (sort_order == 0) return true;
// compare adjacent elements to the sort order
for (; i < end; i++)
{
if (sort_order * @sort_cmp_slice(list, i, cmp, ctx) < 0) return false;
}
return true;
};
return check_sort(list, 0, len - 1, cmp, ctx);
$else
var $Type = $typeof(*list);
usz len = lengthof(*list);
if (len <= 1) return true;
var check_sort = fn bool($Type* list, usz start, usz end, $typeof(cmp) cmp, $typeof(ctx) ctx)
{
usz i;
int sort_order;
// determine sort order (ascending or descending)
for (i = start; i < end && sort_order == 0; i++)
{
@@ -33,9 +62,33 @@ macro bool is_sorted(list, cmp = EMPTY_MACRO_SLOT, ctx = EMPTY_MACRO_SLOT) @buil
return true;
};
return check_sort(list, 0, len - 1, cmp, ctx);
$endif
}
macro int @sort_cmp(list, pos, cmp, ctx) @local
{
var $has_cmp = @is_valid_macro_slot(cmp);
var $has_context = @is_valid_macro_slot(ctx);
var $cmp_by_value = $has_cmp &&& $defined($typefrom($typeof(cmp).paramsof[0].type) v = (*list)[0]);
var a = (*list)[pos];
var b = (*list)[pos+1];
$switch:
$case $cmp_by_value && $has_context:
return cmp(a, b);
$case $cmp_by_value:
return cmp(a, b);
$case $has_cmp && $has_context:
return cmp(&a, &b, ctx);
$case $has_cmp:
return cmp(&a, &b);
$default:
return compare_to(a,b);
$endswitch
}
macro int @sort_cmp_slice(list, pos, cmp, ctx) @local
{
var $has_cmp = @is_valid_macro_slot(cmp);
var $has_context = @is_valid_macro_slot(ctx);

View File

@@ -9,13 +9,13 @@
rev,
debug ? false,
checks ? false,
}: let
}: let
inherit (builtins) readFile elemAt;
# inherit (lib.sources) cleanSourceWith cleanSource;
inherit (lib.lists) findFirst;
inherit (lib.asserts) assertMsg;
inherit (lib.strings) hasInfix splitString removeSuffix removePrefix optionalString;
in llvmPackages.stdenv.mkDerivation (_:
in llvmPackages.stdenv.mkDerivation (_:
{
pname = "c3c${optionalString debug "-debug"}";
@@ -33,7 +33,7 @@ in llvmPackages.stdenv.mkDerivation (_:
# Here we substitute GIT_HASH which is not set for cmake in nix builds.
# Similar situation is with __DATE__ and __TIME__ macros, which are
# set to "Jan 01 1980 00:00:00" by default.
patchPhase = ''
postPatch = ''
substituteInPlace git_hash.cmake --replace-fail "\''${GIT_HASH}" "${rev}"
local FILE_NAMES="$(find src -type f)"
@@ -49,8 +49,8 @@ in llvmPackages.stdenv.mkDerivation (_:
"-DLLVM_CRT_LIBRARY_DIR=${llvmPackages.compiler-rt}/lib/darwin"
];
nativeBuildInputs = [
cmake
nativeBuildInputs = [
cmake
llvmPackages.llvm
llvmPackages.lld
llvmPackages.compiler-rt
@@ -71,6 +71,7 @@ in llvmPackages.stdenv.mkDerivation (_:
# In check phase we preserve BUILD directory as
# we need to return to it before install phase
checkPhase = ''
runHook preCheck
local BUILD_DIR=$(pwd)
cd ../resources/testproject
@@ -80,6 +81,7 @@ in llvmPackages.stdenv.mkDerivation (_:
../build/c3c compile-run -O1 src/test_suite_runner.c3 -- ../build/c3c ./test_suite
cd $BUILD_DIR
runHook postCheck
'';
meta = with lib; {

View File

@@ -1,5 +1,113 @@
# C3C Release Notes
## 0.7.8 Change list
### Changes / improvements
- Improve multiline string parser inside compiler #2552.
- Missing imports allowed if module `@if` evaluates to false #2251.
- Add default exception handler to Win32 #2557.
- Accept `"$schema"` as key in `project.json` #2554.
- Function referencing in `@return?` for simplified fault declarations. Check `@return?` eagerly #2340.
- Enums now work with `membersof` to return the associated values. #2571
- Deprecated `SomeEnum.associated` in favour of `SomeEnum.membersof`
- Refactored `@simd` implementation.
- Improve error message for `Foo{}` when `Foo` is not a generic type #2574.
- Support `@param` directives for `...` parameters. #2578
- Allow splatting of structs. #2555
- Deprecate `--test-nocapture` in favour of `--test-show-output` #2588.
- Xtensa target no longer enabled by default on LLVM 22, Compile with `-DXTENSA_ENABLE` to enable it instead
- Add `float[<3>] x = { .xy = 1.2, .z = 3.3 }` swizzle initialization for vectors. #2599
- Support `int $foo...` arguments. #2601
- Add musl support with `--linux-libc=musl`.
### Fixes
- `Foo.is_eq` would return false if the type was a `typedef` and had an overload, but the underlying type was not comparable.
- Remove division-by-zero checks for floating point in safe mode #2556.
- Fix division-by-zero checks on `a /= 0` and `b /= 0f` #2558.
- Fix fmod `a %= 0f`.
- Regression vector ABI: initializing a struct containing a NPOT vector with a constant value would crash LLVM. #2559
- Error message with hashmap shows "mangled" name instead of original #2562.
- Passing a compile time type implicitly converted to a typeid would crash instead of producing an error. #2568
- Compiler assert with const enum based on vector #2566
- Fix to `Path` handling `c:\foo` and `\home` parent. #2569
- Fix appending to `c:\` or `\` #2569.
- When encountering a foreach over a `ZString*` it would not properly emit a compilation error, but hit an assert #2573.
- Casting a distinct type based on a pointer to an `any` would accidentally be permitted. #2575
- `overflow_*` vector ops now correctly return a bool vector.
- Regression vector ABI: npot vectors would load incorrectly from pointers and other things. #2576
- Using `defer catch` with a (void), would cause an assertion. #2580
- Fix decl attribute in the wrong place causing an assertion. #2581
- Passing a single value to `@wasm` would ignore the renaming.
- `*(int*)1` incorrectly yielded an assert in LLVM IR lowering #2584.
- Fix issue when tests encounter a segmentation fault or similar.
- With project.json, when overriding with an empty list the base settings would still be used. #2583
- Add sigsegv stacktrace in test and regular errors for Darwin Arm64. #1105
- Incorrect error message when using generic type that isn't imported #2589
- `String.to_integer` does not correctly return in some cases where it should #2590.
- Resolving a missing property on a const enum with inline, reached an assert #2597.
- Unexpected maybe-deref subscript error with out parameter #2600.
- Bug on rethrow in return with defer #2603.
- Fix bug when converting from vector to distinct type of wider vector. #2604
- `$defined(hashmap.init(mem))` causes compiler segfault #2611.
- Reference macro parameters syntax does not error in certain cases. #2612
- @param name parsing too lenient #2614.
### Stdlib changes
- Add `CGFloat` `CGPoint` `CGSize` `CGRect` types to core_foundation (macOS).
- Add `NSStatusItem` const enum to ns module (macOS).
- Add `NSWindowCollectionBehavior` `NSWindowLevel` `NSWindowTabbingMode` to ns module (macOS).
- Add `ns::eventmask_from_type` function to objc (macOS).
- Deprecate objc enums in favour of const inline enums backed by NS numerical types, and with the NS prefix, to better align with the objc api (macOS).
- Deprecate `event_type_from` function in favour of using NSEvent directly, to better align with the objc api (macOS).
- Add unit tests for objc and core_foundation (macOS).
- Make printing typeids give some helpful typeid data.
- Add `NSApplicationTerminateReply` to ns module (macOS).
- Add `registerClassPair` function to objc module (macOS).
- Somewhat faster BigInt output.
- Cache printf output.
## 0.7.7 Change list
### Changes / improvements
- Error when using $vaarg/$vacount/$vasplat and similar in a macro without vaargs #2510.
- Add splat defaults for designated initialization #2441.
- Add new builtins `$$str_snakecase` `$$str_replace` and `$$str_pascalcase`.
- `"build-dir"` option now available for `project.json`, added to project. #2323
- Allow `..` ranges to use "a..a-1" in order to express zero length.
- Disallow aliasing of `@local` symbols with a higher visibility in the alias.
- Add `--max-macro-iterations` to set macro iteration limit.
- Improved generic inference in initializers #2541.
- "Maybe-deref" subscripting `foo.[i] += 1` #2540.
- ABI change for vectors: store and pass them as arrays #2542.
- Add @simd and @align attributes to typedef #2543.
- Rename `@extern` to `@cname`, deprecating the old name #2493.
- Allow `(Foo)0` bitstruct casts even if type sizes do not match.
- The option `--riscvfloat` renamed `--riscv-abi`.
- Add initial `--cpu-flags` allowing fine grained control over CPU features.
- Add `--riscv-cpu` settings for RISC-V processors #2549.
### Fixes
- Bug in `io::write_using_write_byte`.
- Bitstruct value cannot be used to index a const array in compile time. #2512
- Compiler fails to stop error print in recursive macro, and also prints unnecessary "inline at" #2513.
- Bitstruct truncated constant error escapes `$defined` #2515.
- Compiler segfault when accessing member of number cast to bitstruct #2516.
- Compiler assert when getting a member of a `bitstruct : char @bigendian` #2517.
- Add ??? and +++= to list-precedence.
- Fix issues with linking when using symbol aliases. #2519
- Splatting optional compile-time macro parameter from inside lambda expression does not work #2532.
- Compiler segfault when getting a nonexistant member from an unnamed struct #2533.
- Correctly mention aliased type when method is not implemented #2534.
- Regression: Not printing backtrace when tests fail for MacOS #2536.
- Name property would be used even under `c3c test` #2587.
### Stdlib changes
- Sorting functions correctly took slices by value, but also other types by value. Now, only slices are accepted by value, other containers are always by ref.
- Added `@str_snakecase`, `@str_replace` and `@str_pascalcase` builtin compile time macros based on the `$$` builtins.
- Add TcpSocketPair to create a bidirectional local socket pair.
- Add `extern fn CInt socketpair(AIFamily domain, AISockType type, CInt protocol, NativeSocket[2]* sv)` binding to posix.
- Add `extern fn getsockname(NativeSocket socket, SockAddrPtr address, Socklen_t* address_len)` binding to win32.
## 0.7.6 Change list
### Changes / improvements

View File

@@ -6,10 +6,12 @@ hello.a: $(SRCS_C3)
$(C3C_PATH)c3c -g --use-stdlib=no --no-entry --target elf-riscv32 static-lib $(SRCS_C3)
start.o: start.s
riscv64-unknown-elf-as -g -march=rv32i -mabi=ilp32 -misa-spec=20191213 -o start.o start.s
riscv64-unknown-elf-as -g -march=rv32i -mabi=ilp32 -misa-spec=20191213 -o start.o start.s \
|| riscv-none-elf-as -g -march=rv32i -mabi=ilp32 -misa-spec=20191213 -o start.o start.s
hello.elf: hello.a start.o baremetal.ld
riscv64-unknown-elf-ld -T baremetal.ld -m elf32lriscv -o hello.elf hello.a start.o
riscv64-unknown-elf-ld -T baremetal.ld -m elf32lriscv -o hello.elf hello.a start.o \
|| riscv-none-elf-ld -T baremetal.ld -m elf32lriscv -o hello.elf hello.a start.o
run: hello.elf
qemu-system-riscv32 -nographic -serial mon:stdio -machine virt -semihosting -bios hello.elf

View File

@@ -1,22 +1,26 @@
fn void print(String msg)
{
$$syscall(1, 1, (uptr)msg.ptr, msg.len); // __NR_write, STDOUT
}
fn void printn(String msg)
{
print(msg);
print("\n");
}
fn void exit(int exit_code)
{
$$syscall(60, exit_code); // __NR_exit
}
fn int main()
{
String msg = "Hello, C3 World!\n";
$$syscall(1, 1, (uptr)msg.ptr, msg.len); // __NR_write, STDOUT
return 0;
printn("Hello, C3 World!");
return 0;
}
fn void _start() @export("_start")
{
int ret = main();
$$syscall(60, ret); // __NR_exit
}
module std::core::builtin;
alias 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)
{
exit(main());
}

View File

@@ -13,6 +13,8 @@
"version": "0.1.0",
// Sources compiled for all targets.
"sources": [ "./**" ],
// Test sources compiled for all targets.
"test-sources": [ "test/**" ],
// C sources if the project also compiles C sources
// relative to the project file.
// "c-sources": [ "csource/**" ],
@@ -24,31 +26,21 @@
// Targets.
"targets": {
"hello_world": {
// Executable or library.
"type": "executable",
"debug-info": "none",
"link-libc": false,
"opt": "O0",
"safe": false,
"linker": "builtin",
"use-stdlib": false,
// Additional libraries, sources
// and overrides of global settings here.
},
},
// 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,
"link-libc": false,
// Memory environment: "normal", "small", "tiny", "none".
"memory-env": "normal",
"memory-env": "small",
// Optimization: "O0", "O1", "O2", "O3", "O4", "O5", "Os", "Oz".
"opt": "O0",
"opt": "Os",
// Code optimization level: "none", "less", "more", "max".
"optlevel": "none",
// Code size optimization: "none", "small", "tiny".
@@ -58,7 +50,7 @@
// 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,
"safe": false,
// Compile all modules together, enables more inlining.
"single-module": true,
// Use / don't use soft float, value is otherwise target default.
@@ -69,11 +61,7 @@
// of symbols that can be used. Should usually not be changed.
"symtab": 1048576,
// Select linker.
"linker": "cc",
"linker": "builtin",
// 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",
"use-stdlib": false,
}

View File

@@ -23,14 +23,14 @@ enum Primitive : int (int value)
POLYGON = 9,
}
extern fn void clear(BitField mask) @extern("glClear") @public;
extern fn void clear(BitField mask) @cname("glClear") @public;
extern fn void begin(BitField mask) @extern("glBegin") @public;
extern fn void begin(BitField mask) @cname("glBegin") @public;
extern fn void end() @extern("glEnd") @public;
extern fn void end() @cname("glEnd") @public;
extern fn void flush() @extern("glFlush") @public;
extern fn void flush() @cname("glFlush") @public;
extern fn void color3f(float r, float g, float b) @extern("glColor3f") @public;
extern fn void color3f(float r, float g, float b) @cname("glColor3f") @public;
extern fn void vertex3f(float x, float y, float z) @extern("glVertex3f") @public;
extern fn void vertex3f(float x, float y, float z) @cname("glVertex3f") @public;

View File

@@ -31,21 +31,21 @@ fn void Window.makeContextCurrent(self) @public
return _glfwMakeContextCurrent((_Window*)self);
}
extern fn void initialize() @extern("glfwInit") @public;
extern fn void initialize() @cname("glfwInit") @public;
extern fn void terminate() @extern("glfwTerminate") @public;
extern fn void terminate() @cname("glfwTerminate") @public;
extern fn void pollEvents() @extern("glfwPollEvents") @public;
extern fn void pollEvents() @cname("glfwPollEvents") @public;
typedef _Window @private = void;
typedef _Monitor @private = void;
extern fn _Window* _glfwCreateWindow(int width, int height, char* title, _Monitor* monitor, _Window* share) @extern("glfwCreateWindow") @private;
extern fn _Window* _glfwCreateWindow(int width, int height, char* title, _Monitor* monitor, _Window* share) @cname("glfwCreateWindow") @private;
extern fn bool _glfwWindowShouldClose(_Window* window) @extern("glfwWindowShouldClose") @private;
extern fn bool _glfwWindowShouldClose(_Window* window) @cname("glfwWindowShouldClose") @private;
extern fn void _glfwDestroyWindow(_Window* window) @extern("glfwDestroyWindow") @private;
extern fn void _glfwDestroyWindow(_Window* window) @cname("glfwDestroyWindow") @private;
extern fn void _glfwSwapBuffers(_Window* window) @extern("glfwSwapBuffers") @private;
extern fn void _glfwSwapBuffers(_Window* window) @cname("glfwSwapBuffers") @private;
extern fn void _glfwMakeContextCurrent(_Window* window) @extern("glfwMakeContextCurrent") @private;
extern fn void _glfwMakeContextCurrent(_Window* window) @cname("glfwMakeContextCurrent") @private;

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 466 B

View File

@@ -0,0 +1,292 @@
/*******************************************************************************************
*
* raylib [core] example - 2d camera platformer
*
* Example complexity rating: [★★★☆] 3/4
*
* Example originally created with raylib 2.5, last time updated with raylib 3.0
*
* Example contributed by arvyy (@arvyy) and reviewed by Ramon Santamaria (@raysan5)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2019-2025 arvyy (@arvyy)
* converted to C3 by Christoffer Lerno
*
********************************************************************************************/
module raylib_camera_platformer;
import raylib55;
const G = 400;
const float PLAYER_JUMP_SPD = 350;
const float PLAYER_HOR_SPD = 200;
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
struct Player
{
RLVector2 position;
float speed;
bool can_jump;
}
struct EnvItem
{
RLRectangle rect;
int blocking;
RLColor color;
}
alias CameraUpdateFn = fn void(RLCamera2D* camera, Player* player, EnvItem[] env_items, float delta, int width, int height);
enum CameraUpdateType : (ZString text, CameraUpdateFn func)
{
CENTER = { "Follow player center", &update_camera_center },
CENTER_INSIDE_MAP = { "Follow player center, but clamp to map edges", &update_camera_center_inside_map },
CENTER_SMOOTH_FOLLOW = { "Follow player center; smoothed", &update_camera_center_smooth_follow },
EVEN_OUT_ON_LANDING = { "Follow player center horizontally; update player center vertically after landing", &update_camera_even_out_on_landing },
PLAYER_BOUNDS_PUSH = { "Player push camera on getting too close to screen edge", &update_camera_player_bounds_push }
}
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
fn int main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 450;
rl::init_window(SCREEN_WIDTH, SCREEN_HEIGHT, "raylib [core] example - 2d camera platformer");
Player player = {
.position = { 400, 280 },
.speed = 0,
.can_jump = false
};
EnvItem[*] env_items = {
{{ 0, 0, 1000, 400 }, 0, rl::LIGHTGRAY },
{{ 0, 400, 1000, 200 }, 1, rl::GRAY },
{{ 300, 200, 400, 10 }, 1, rl::GRAY },
{{ 250, 300, 100, 10 }, 1, rl::GRAY },
{{ 650, 300, 100, 10 }, 1, rl::GRAY }
};
RLCamera2D camera = {
.target = player.position,
.offset = { SCREEN_WIDTH / 2.0f, SCREEN_HEIGHT / 2.0f },
.rotation = 0.0f,
.zoom = 1.0f
};
CameraUpdateType camera_option = CENTER;
rl::set_target_fps(60);
//--------------------------------------------------------------------------------------
// Main game loop
while (!rl::window_should_close())
{
// Update
//----------------------------------------------------------------------------------
float delta_time = rl::get_frame_time();
update_player(&player, &env_items, delta_time);
camera.zoom += ((float)rl::get_mouse_wheel_move() * 0.05f);
switch
{
case camera.zoom > 3.0f: camera.zoom = 3.0f;
case camera.zoom < 0.25f: camera.zoom = 0.25f;
}
if (rl::is_key_pressed(R))
{
camera.zoom = 1.0f;
player.position = { 400, 280 };
}
if (rl::is_key_pressed(C)) camera_option = CameraUpdateType.from_ordinal(((int)camera_option + 1) % (int)CameraUpdateType.len);
// Call update camera function by its pointer
camera_option.func(&camera, &player, &env_items, delta_time, SCREEN_WIDTH, SCREEN_HEIGHT);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
rl::@drawing()
{
rl::clear_background(rl::LIGHTGRAY);
rl::@mode2d(camera)
{
foreach (item : env_items) rl::draw_rectangle_rec(item.rect, item.color);
RLRectangle player_rect = { player.position.x - 20, player.position.y - 40, 40.0f, 40.0f };
rl::draw_rectangle_rec(player_rect, rl::RED);
rl::draw_circle_v(player.position, 5.0f, rl::GOLD);
};
rl::draw_text("Controls:", 20, 20, 10, rl::BLACK);
rl::draw_text("- Right/Left to move", 40, 40, 10, rl::DARKGRAY);
rl::draw_text("- Space to jump", 40, 60, 10, rl::DARKGRAY);
rl::draw_text("- Mouse Wheel to Zoom in-out, R to reset zoom", 40, 80, 10, rl::DARKGRAY);
rl::draw_text("- C to change camera mode", 40, 100, 10, rl::DARKGRAY);
rl::draw_text("Current camera mode:", 20, 120, 10, rl::BLACK);
rl::draw_text(camera_option.text, 40, 140, 10, rl::DARKGRAY);
};
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
rl::close_window(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
fn void update_player(Player* player, EnvItem[] env_items, float delta)
{
if (rl::is_key_down(LEFT)) player.position.x -= PLAYER_HOR_SPD * delta;
if (rl::is_key_down(RIGHT)) player.position.x += PLAYER_HOR_SPD * delta;
if (rl::is_key_down(SPACE) && player.can_jump)
{
player.speed = -PLAYER_JUMP_SPD;
player.can_jump = false;
}
bool hit_obstacle = false;
foreach (item : env_items)
{
RLVector2* p = &player.position;
if (item.blocking
&& item.rect.x <= p.x
&& item.rect.x + item.rect.width >= p.x
&& item.rect.y >= p.y
&& item.rect.y <= p.y + player.speed * delta)
{
hit_obstacle = true;
player.speed = 0.0f;
p.y = item.rect.y;
break;
}
}
if (hit_obstacle)
{
player.can_jump = true;
}
else
{
player.position.y += player.speed * delta;
player.speed += G * delta;
player.can_jump = false;
}
}
fn void update_camera_center(RLCamera2D* camera, Player* player, EnvItem[] env_items, float delta, int width, int height)
{
camera.offset = { width / 2.0f, height / 2.0f };
camera.target = player.position;
}
fn void update_camera_center_inside_map(RLCamera2D* camera, Player* player, EnvItem[] env_items, float delta, int width, int height)
{
camera.target = player.position;
camera.offset = { width / 2.0f, height / 2.0f };
float min_x = 1000;
float min_y = 1000;
float max_x = -1000;
float max_y = -1000;
foreach (item : env_items)
{
min_x = min(item.rect.x, min_x);
max_x = max(item.rect.x + item.rect.width, max_x);
min_y = min(item.rect.y, min_y);
max_y = max(item.rect.y + item.rect.height, max_y);
}
RLVector2 max = rl::get_world_to_screen2d({ max_x, max_y }, *camera);
RLVector2 min = rl::get_world_to_screen2d({ min_x, min_y }, *camera);
if (max.x < width) camera.offset.x = width - (max.x - width / 2.0f);
if (max.y < height) camera.offset.y = height - (max.y - height / 2.0f);
if (min.x > 0) camera.offset.x = width / 2.0f - min.x;
if (min.y > 0) camera.offset.y = height / 2.0f - min.y;
}
fn void update_camera_center_smooth_follow(RLCamera2D* camera, Player* player, EnvItem[] env_items, float delta, int width, int height)
{
const float MIN_SPEED = 30;
const float MIN_EFFECT_LENGTH = 10;
const float FRACTION_SPEED = 0.8f;
camera.offset = { width / 2.0f, height / 2.0f };
float length = player.position.distance(camera.target);
if (length > MIN_EFFECT_LENGTH)
{
float speed = max(FRACTION_SPEED * length, MIN_SPEED);
camera.target += (player.position - camera.target) * speed * delta / length;
}
}
fn void update_camera_even_out_on_landing(RLCamera2D* camera, Player* player, EnvItem[] env_items, float delta, int width, int height)
{
const float EVEN_OUT_SPEED = 700;
static bool evening_out = false;
static float even_out_target;
camera.offset = { width / 2.0f, height / 2.0f };
camera.target.x = player.position.x;
if (evening_out)
{
if (even_out_target > camera.target.y)
{
camera.target.y += EVEN_OUT_SPEED * delta;
if (camera.target.y > even_out_target)
{
camera.target.y = even_out_target;
evening_out = false;
}
}
else
{
camera.target.y -= EVEN_OUT_SPEED * delta;
if (camera.target.y < even_out_target)
{
camera.target.y = even_out_target;
evening_out = false;
}
}
}
else
{
if (player.can_jump && player.speed == 0 && player.position.y != camera.target.y)
{
evening_out = true;
even_out_target = player.position.y;
}
}
}
fn void update_camera_player_bounds_push(RLCamera2D* camera, Player* player, EnvItem[] env_items, float delta, int width, int height)
{
const RLVector2 BBOX = { 0.2f, 0.2f };
RLVector2 bboxWorldMin = rl::get_screen_to_world2d({ (1 - BBOX.x) * 0.5f * width, (1 - BBOX.y) * 0.5f*height }, *camera);
RLVector2 bboxWorldMax = rl::get_screen_to_world2d({ (1 + BBOX.x) * 0.5f * width, (1 + BBOX.y) * 0.5f*height }, *camera);
camera.offset = { (1 - BBOX.x) * 0.5f * width, (1 - BBOX.y) * 0.5f * height };
if (player.position.x < bboxWorldMin.x) camera.target.x = player.position.x;
if (player.position.y < bboxWorldMin.y) camera.target.y = player.position.y;
if (player.position.x > bboxWorldMax.x) camera.target.x = bboxWorldMin.x + (player.position.x - bboxWorldMax.x);
if (player.position.y > bboxWorldMax.y) camera.target.y = bboxWorldMin.y + (player.position.y - bboxWorldMax.y);
}

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