Compare commits

..

159 Commits

Author SHA1 Message Date
Christoffer Lerno
84e10cf635 0.6.3 Release version. 2024-10-03 10:11:31 +02:00
Christoffer Lerno
1b8f8c5f5a Compiler crash when compiling c code in a library without --obj-out #1503. 2024-10-03 00:56:01 +02:00
Fernando López Guevara
131a783e89 feat(hash): added test for sha256 2024-10-02 16:55:17 +02:00
chri-k
2233f24c8f Add variants of DString.insert_at to match .append (#1510) 2024-10-02 10:22:59 +02:00
Christoffer Lerno
607a625641 Updated bigint. 2024-10-02 01:13:34 +02:00
Christoffer Lerno
9b49d19224 DString reverse and an initial BigInt implementation (untested), 2024-10-01 22:51:48 +02:00
Christoffer Lerno
46ae4353e0 Assume XTensa in 21+ instead. 2024-10-01 16:06:23 +02:00
Christoffer Lerno
44fcba2e3a Remove LLVM 20 2024-10-01 15:58:23 +02:00
Christoffer Lerno
f434795ee5 Test enable 19 and 20 2024-10-01 15:51:44 +02:00
Christoffer Lerno
0ea423d022 Foreach over distinct iterable would ignore operator(len). 2024-10-01 13:00:54 +02:00
Fernando López Guevara
c9b9de2838 fix(string): remove allocator argument on temp_ascii_to_lower 2024-09-30 22:01:44 +02:00
Christoffer Lerno
5918d5120f Foreach over distinct pointer failed to be caught as error #1506. 2024-09-30 21:32:33 +02:00
DanyDollaro
0d73f2fffa Added mutex tests (#1501)
* Added mutex tests. Add errorcheck in safe mode for Posix threads. Make non-recursive locks fail when used recursively on Windows. Fix thread pool tests. Simple locking count.

---------

Co-authored-by: Christoffer Lerno <christoffer@aegik.com>
2024-09-30 20:57:16 +02:00
Christoffer Lerno
c8018c5543 Added generic PBKDF2 implementation. 2024-09-30 00:07:49 +02:00
Christoffer Lerno
071bd0ebf2 Fix bug when reading zip manifest, that would not return a zero terminated string. #1490 2024-09-29 21:14:03 +02:00
Christoffer Lerno
a00fce516e Added test and releasenotes for #1498. 2024-09-29 11:23:40 +02:00
chri-k
94abb3bd0c Fix escape sequence handling in encoding::json 2024-09-29 11:22:15 +02:00
Christoffer Lerno
2e94ea1a0d Improved error messages on Foo a = foo { 1 }; #1496 2024-09-28 23:53:31 +02:00
Christoffer Lerno
3b009e0b50 Added generic HMAC. 2024-09-28 23:28:11 +02:00
Christoffer Lerno
cc130e04dd Added MD5 and crypto::safe_compare. 2024-09-28 22:16:25 +02:00
Christoffer Lerno
2eca868540 Add UUID generation. 2024-09-28 20:58:03 +02:00
Christoffer Lerno
eeba5f020a Bad error on parameterized type without parameter #1495. 2024-09-28 19:44:57 +02:00
Christoffer Lerno
ded8bce8e6 Change no recursive import to use attribute. 2024-09-28 13:48:43 +02:00
Christoffer Lerno
8e7efaae99 ThreadPool is now adhoc available. 2024-09-28 13:28:39 +02:00
Alex Ling
fe9e434020 Fix incorrect to_gmt_offset result 2024-09-28 13:23:48 +02:00
Christoffer Lerno
8a0b0f5cf5 Disable fixed_pool where no threads are available. 2024-09-28 03:50:22 +02:00
Christoffer Lerno
5df321816b Unintended commit reverse. 2024-09-28 01:42:06 +02:00
Christoffer Lerno
7ff645c423 Free if broadcast fails. 2024-09-28 01:33:12 +02:00
Christoffer Lerno
93f290d57c Added a simple fixed threadpool which allocates. 2024-09-28 01:25:08 +02:00
Rachad ADEKAMBI
2146a76795 fix typo#1492 (#1493)
* fix typo#1492 
* Fix missing update in sema_decls

---------

Co-authored-by: Christoffer Lerno <christoffer@aegik.com>
2024-09-28 00:22:15 +02:00
chopsticks-user
b071e24d7e Minimal GL and GLFW bindings to render a triangle 2024-09-27 13:12:32 +02:00
Christoffer Lerno
a99e4b602a Error when slicing a struct with an inline array #1488. 2024-09-27 13:10:48 +02:00
Alex Ling
4cdea865f0 TzDateTime enhancements #1473 2024-09-26 12:32:05 +02:00
Christoffer Lerno
bf9ae2f0d3 Bad error message aliasing an ident with a path. #1481. 2024-09-25 21:41:40 +02:00
alex_s168
da2f958614 add x86 APX features (#1482)
add apx features Update cpu_detect.c3
2024-09-25 21:11:01 +02:00
Christoffer Lerno
b47201fe61 Fix handling of default target with libc. 2024-09-25 21:09:33 +02:00
Christoffer Lerno
a8932910d9 wasm32 / wasm64 targets are use-libc=no by default. 2024-09-25 21:01:00 +02:00
Christoffer Lerno
413877b59d Allow ^ suffix for non-recursive imports #1480. 2024-09-25 15:23:21 +02:00
Christoffer Lerno
da47588502 Make methods be available in earlier stages of analysis. Add @adhoc attribute to allow types with ad hoc generic declarations. 2024-09-25 14:26:49 +02:00
Christoffer Lerno
6f7ffbeb3c Add rand_in_range random function. Fix methodsof to apply to more types. Prevent methodsof in the wrong stage. 2024-09-25 00:18:11 +02:00
Christoffer Lerno
a258f2084f Allow specifying an import module using @wasm #1305. 2024-09-24 21:31:48 +02:00
Christoffer Lerno
d067a31ce6 Fix entropy 2024-09-24 20:15:10 +02:00
Christoffer Lerno
c6e4eee789 Added rnd function. 2024-09-24 19:02:03 +02:00
Christoffer Lerno
07c49f832e Safer seed of rand with WASM. 2024-09-24 18:38:11 +02:00
Christoffer Lerno
01b087238a Const initializer refactoring. Improve error on "Foo![]" #1477 2024-09-24 18:04:39 +02:00
Christoffer Lerno
d4832812ef Fix regression. 2024-09-23 14:13:55 +02:00
Christoffer Lerno
9c098fd79f Always flatten cont initializer inner type. 2024-09-23 02:51:53 +02:00
Christoffer Lerno
029d5e9068 Const initializer further cleanup. 2024-09-23 00:29:43 +02:00
Christoffer Lerno
f30486adf9 Const initializer cleanup. 2024-09-22 22:31:33 +02:00
Brian Sinquin
e21c337d3d Project fetch missing libraries (#1469)
Project fetch missing libs
2024-09-21 23:49:26 +02:00
Christoffer Lerno
f66f324e0e Suppor slicing of bytes. 2024-09-21 22:56:27 +02:00
Christoffer Lerno
885acdac24 Support compile time slicing of untyped lists. 2024-09-21 20:20:56 +02:00
Christoffer Lerno
ccb04c317c Fix bug due to enum associated values not being checked for liveness. 2024-09-21 18:05:20 +02:00
Christoffer Lerno
abbedeec4f Allow the "self" parameter to be $/# for macro methods. Fix bug when passing a type as a compile time value. 2024-09-21 15:55:39 +02:00
Christoffer Lerno
cdae3ec936 Some refactoring of the bitstruct representation. Correctly represent inner types. #1471 2024-09-21 13:43:52 +02:00
Christoffer Lerno
d727696830 Segfault using ternary with no assignment #1468. 2024-09-21 00:57:36 +02:00
Christoffer Lerno
2a9078a3b4 Also depend on Ubuntu20 2024-09-20 23:14:19 +02:00
Christoffer Lerno
ac479c7e40 llvm issue with try when bool is combined #1467 2024-09-20 20:15:44 +02:00
Christoffer Lerno
cda6ffea1e Slicing constant strings at compile time works. 2024-09-20 19:34:00 +02:00
Caleb-o
0900f401c0 Add Enum constraint to enummap
Fix typo in enumset require
2024-09-20 19:17:09 +02:00
Christoffer Lerno
d5a96ed637 Disabling LLVM 19 again. 2024-09-20 19:16:33 +02:00
Christoffer Lerno
8d9eff5297 Re-enable LLVM 19 2024-09-20 16:22:04 +02:00
Christoffer Lerno
19c1511901 Support linking .o files in compilation command. #1417 2024-09-20 16:21:29 +02:00
Christoffer Lerno
8e37e54645 Add env::COMPILER_BUILD_HASH and env::COMPILER_BUILD_DATE 2024-09-20 12:29:23 +02:00
Christoffer Lerno
c25645eab1 Add .gitkeep files to project subfolders. 2024-09-20 10:47:13 +02:00
Chandler
b9f7711f21 Update Arch Linux install instructions
c3c was recently added to the official Arch 'extra' repo. Updated the README to reflect this.
2024-09-20 00:40:58 +02:00
Christoffer Lerno
9447913de6 Use arena with JSON parser. Slightly altered output for json printing. 2024-09-20 00:39:10 +02:00
Brian Sinquin
8a9834cac0 Vendor-fetch download to lib directory specified in project.json (#1422) (#1441)
Vendor-fetch download default destination set to dependency-search-path in project.json Add fetched libraries in the project configuration file dependency entry.
2024-09-19 23:44:05 +02:00
Christoffer Lerno
2fec1c83a4 Enum attributes would be overwritten by enum value attributes. 2024-09-19 23:02:06 +02:00
Christoffer Lerno
ff36380ddf Allow user-defined attributes to have typed parameters. Folding a constant array of structs at compile time would cause an assert. 2024-09-19 22:21:29 +02:00
Christoffer Lerno
f2cfa61a39 User defined attributes could not have more than 1 parameter due to bug. 2024-09-19 21:14:08 +02:00
Christoffer Lerno
41156cc45d Temp allocator overwrites data when doing reset on extra allocated pages. #1462 2024-09-19 20:50:14 +02:00
Christoffer Lerno
9f51bfcc10 Support casting bitstructs to bool. 2024-09-19 01:03:06 +02:00
Christoffer Lerno
9426e813be Add test. 2024-09-18 23:16:07 +02:00
Christoffer Lerno
20fd7aba9b Regression when passing types as #expr arguments. #1461 2024-09-18 22:16:26 +02:00
Christoffer Lerno
3bada4560e Correctly print interfaces. 2024-09-18 14:53:55 +02:00
Christoffer Lerno
9719abe99a Better slice error message, and enable slice on non-vaarg. 2024-09-18 10:55:18 +02:00
Christoffer Lerno
5540519e52 Cleanup. 2024-09-18 10:20:57 +02:00
Christoffer Lerno
0b94e73c0b Regression fix arguments needed when presenting error on a method. 2024-09-18 10:07:39 +02:00
Christoffer Lerno
5e2a06bfd6 Update shell argument escape. 2024-09-18 00:48:39 +02:00
Christoffer Lerno
ac95e411bc Make str_eq safe to use with NULL. 2024-09-17 23:48:36 +02:00
Christoffer Lerno
08219fc57e Fix reordering semantics in struct assignment. 2024-09-17 22:41:49 +02:00
Josh Ring
09643f3c8b fix install instructions on ubuntu's latest LTS (#1449)
* fix install instructions on ubuntu's latest LTS
* cleanup arch linux and fixed some typos
2024-09-17 01:38:50 +02:00
Christoffer Lerno
08a575fa82 Crash invoking a @body argument with the wrong number of parameters. 2024-09-17 00:33:38 +02:00
Christoffer Lerno
62887a6ce8 Temporarily disable building with LLVM 19 and 20 2024-09-17 00:28:53 +02:00
Christoffer Lerno
297a6c9348 Support C3C_LIB and C3C_CC environment variables. Enable compiling against 20 to see if it works. 2024-09-17 00:12:50 +02:00
Christoffer Lerno
1181edc48e Fix error message when not finding a particular function 2024-09-16 22:43:30 +02:00
Christoffer Lerno
81f1930349 Code cleanup. Correct deprecation notice on '$or'. Allow "self" param on macro method to be constant. 2024-09-16 10:40:34 +02:00
RealPacket
54a1819d46 chore: Remove overrides for C3 files (#1450) 2024-09-16 10:21:41 +02:00
Christoffer Lerno
1b5472cc94 Add paramsof. 2024-09-15 23:43:09 +02:00
Christoffer Lerno
06a083bafc Lambda / function type would accidentally be processed as a method. 2024-09-15 22:12:03 +02:00
Christoffer Lerno
9bb45cb6a3 Add missing concat. Fix error message location on not enough arguments. 2024-09-15 15:56:13 +02:00
Real-Packet
1bfe9c568e chore(ci): Update actions/*-artifact to v4 (simple find & replace)
Because v3 is being deprecated and uses Node 16 instead of Node 20.
v4 is also a drop in replacement so we can just find & replace the usages without any changes to easily upgrade to v4.
2024-09-15 02:11:00 +02:00
Christoffer Lerno
4f5e5fcdba Remove mem tap. 2024-09-15 02:10:19 +02:00
Christoffer Lerno
bca44d1c14 Bug with casting anyfault to error. 2024-09-15 00:55:22 +02:00
Christoffer Lerno
e6d1d66c8f Updated grammar script and fix concat op 2024-09-14 23:13:06 +02:00
Christoffer Lerno
c3a5f5c0f0 Build macos version with LLVM 17 2024-09-14 22:18:33 +02:00
Christoffer Lerno
c0875d7987 Fix macos release. 2024-09-14 22:15:16 +02:00
Christoffer Lerno
6b6ac2bcb3 Rename release files. 2024-09-14 20:19:12 +02:00
Christoffer Lerno
f78466452a Updated grammar.y 2024-09-14 19:24:21 +02:00
Christoffer Lerno
f51230e793 Fix bugs in "trap-on-wrap" #1434. 2024-09-14 16:19:40 +02:00
Christoffer Lerno
3ab201ce10 Use atexit to fix finalizers on Windows #1361. 2024-09-14 16:17:57 +02:00
Christoffer Lerno
45a94cfe86 Asserts are now correctly included and traced in when running tests. Removed accidental debug trace. 2024-09-14 13:48:27 +02:00
Christoffer Lerno
f16cc999bd Fix bug where inline index access to array in a struct would crash the compiler. 2024-09-14 12:58:37 +02:00
Christoffer Lerno
d39f25efd3 Support inline struct designated init as if inline was anonymous. 2024-09-13 20:31:21 +02:00
Christoffer Lerno
6b2ce6de6f Fix unreachable. 2024-09-13 15:32:26 +02:00
Christoffer Lerno
3f1738e0fe Unified constant handling. 2024-09-13 15:11:15 +02:00
Real-Packet
3ceaf2ab81 chore: migrate to softprops/action-gh-release
Hopefully this works. Had to generate a new GPG key because GPG requires a password for signing stuff with GPG and I forgot to use it to sign something so I could save it in the password manager.
Fixes c3lang/c3c#1437
2024-09-13 15:07:45 +02:00
wilsonk
4c7d61ae82 Bsd family fixes (#1435)
Some small fixes for the BSD's
Try fcntl for NetBSD
Fixes for stdin, etc. and setjmp/longjmp
2024-09-13 14:49:51 +02:00
Alexey Kutepov
d53dd57b84 Introduce os::native_fputc() abstraction layer for File.write_byte() (#1440)
Introduce os::native_fputc() abstraction layer for File.write_byte()
2024-09-13 12:25:41 +02:00
Christoffer Lerno
6ff5ac5592 Removed unused functions. 2024-09-12 15:28:19 +02:00
Christoffer Lerno
9ce1bbe3cd Update README.md
Fix link
2024-09-12 14:02:10 +02:00
Christoffer Lerno
65c48419d0 Minor refactorings. Added "Thank you" section to readme. Some fixes to hostinfo. 2024-09-12 13:47:49 +02:00
alex_s168
d376ee6671 ability to disable llvm at compile time (#1433)
ability to disable llvm at compile time
2024-09-12 13:36:00 +02:00
Christoffer Lerno
eaa419a48d Correct '.so' suffix on dynamic libraries on Linux. 2024-09-12 09:21:23 +02:00
Christoffer Lerno
1b6ec34c61 Refactor alignment code. Change deprecated function in test. 2024-09-12 08:30:01 +02:00
Christoffer Lerno
9f4da339c3 Support int[*] { 1, 2, 3 } expressions. 2024-09-12 00:11:09 +02:00
wilsonk
1b54a99f6a Add initial FreeBSD support (#1430)
Add initial FreeBSD support
2024-09-11 22:38:53 +02:00
ElaDeCode
2b0d2892af move macro matrix_look_at to matrix module 2024-09-11 14:58:42 +02:00
Fernando López Guevara
27f2d201ed fix: cast native thread 2024-09-11 10:12:33 +02:00
Christoffer Lerno
d6cf622e49 Make subscript use its own "index" type rather than reuse Range. 2024-09-10 22:11:19 +02:00
Christoffer Lerno
2092e2167e Add io::read_new_fully for reading to the end of a stream. Add io::wrap_bytes for reading bytes with io functions. 2024-09-10 13:21:07 +02:00
Christoffer Lerno
503032cbcf Update range checking. 2024-09-10 13:21:07 +02:00
Christoffer Lerno
6f90e13502 Fix regression for $include. 2024-09-10 12:15:45 +02:00
Christoffer Lerno
b22bd459dd Fix regression for splat. 2024-09-10 00:21:01 +02:00
Christoffer Lerno
f67147a405 Fix bug in new splat code, fixes #1423. 2024-09-09 22:12:30 +02:00
Christoffer Lerno
df4eb3d0f0 Allow var in lambdas in macros. Allow ad hoc generic declaration in lambdas and type definitions. Fix deprecation flag. 2024-09-09 21:46:06 +02:00
Christoffer Lerno
32cc4bcd03 Fix issues for compiling on 32-bit. 2024-09-09 00:55:50 +02:00
Christoffer Lerno
1502c6d660 Limit object filename lengths. #1415 2024-09-07 23:38:20 +02:00
Christoffer Lerno
d4fb5b747b Update QOI type names. 2024-09-07 16:10:15 +02:00
Hema2
7581651011 Add QOI to the standard library (#1409)
Add QOI to the standard library
2024-09-07 15:55:26 +02:00
Christoffer Lerno
4f54e273ab Asserts are retained regardless of optimization when running tests. 2024-09-07 15:40:32 +02:00
Christoffer Lerno
1cc1b83b6f format functions are now functions and work better with splat. 2024-09-07 14:34:30 +02:00
Christoffer Lerno
8e9199f453 Untyped splat. 2024-09-07 14:26:42 +02:00
Christoffer Lerno
223501eeca Support splat for varargs #1352. 2024-09-07 05:26:43 +02:00
Christoffer Lerno
7649738618 Improve lvalue handling in the compiler. #1357 2024-09-07 03:19:35 +02:00
Christoffer Lerno
78c60ae695 Increase stack size for msys. 2024-09-07 01:37:45 +02:00
Christoffer Lerno
f5f122d5a5 Reduce recursion depth. Improve error message. 2024-09-07 00:48:16 +02:00
Christoffer Lerno
4b27a33a10 Refactor vasplat. 2024-09-07 00:29:41 +02:00
id3nom
15aca2eb84 Add CMake option C3_ENABLE_CLANGD_LSP (#1414)
* CMake option C3_ENABLE_CLANGD_LSP

The CMake option enables the generation of compile_commands.json in
the build directory and the creation of a symlink in the root
directory targeting the new file,
this will allow the Clangd Language Server Protocol (LSP) to
function properly.

* Added .editorconfig

EditorConfig helps maintain consistent coding styles:
https://editorconfig.org/
2024-09-06 23:06:09 +02:00
Christoffer Lerno
1cb91c0ac9 Fold default args in non-debug. 2024-09-06 23:04:09 +02:00
Christoffer Lerno
840b3b3161 "optsize" did not work correctly in project.json. 2024-09-06 22:55:15 +02:00
Christoffer Lerno
a5cf3ce2f1 Update releasenotes. 2024-09-06 20:56:38 +02:00
Lars Nilsson
04c85eb9ce Adding hashmap and map initialization functions with data (#1402)
Adding hashmap and map initialization functions with data to populate them with
2024-09-06 20:55:42 +02:00
Christoffer Lerno
82364d2e3c Function vasplat refactoring. 2024-09-06 20:54:28 +02:00
Christoffer Lerno
3db7bf5dfd Crash when reading an empty 'manifest.json'. 2024-09-06 18:05:43 +02:00
Christoffer Lerno
de13023981 Converting a slice to a vector/array would copy too little data. 2024-09-06 15:36:43 +02:00
Christoffer Lerno
35b825c78a Function vasplat refactoring. 2024-09-06 11:44:48 +02:00
Christoffer Lerno
28428fcf30 Handle "splice splat" in the vararg slot as an expression. 2024-09-06 10:43:03 +02:00
Christoffer Lerno
1e570bf506 Rename vec_erase_ptr_at to vec_erase_at. 2024-09-06 00:41:07 +02:00
Christoffer Lerno
ad0e97ab7b Deprecated inline generic types, deprecated tuple / triple types. 2024-09-05 23:42:20 +02:00
Christoffer Lerno
ed5d338a39 Added new style named arguments. 2024-09-05 22:13:22 +02:00
Christoffer Lerno
e795745e43 lvalue refactoring. 2024-09-05 22:09:35 +02:00
Christoffer Lerno
5e4d790fc3 Fixing incorrectly solved generic module name collision bug. 2024-09-04 21:51:03 +02:00
Christoffer Lerno
7e47f4ed08 Generic methods were incorrectly registered as functions, leading to naming collisions. #1402 2024-09-04 15:13:29 +02:00
Christoffer Lerno
63fc77a861 Move of const to separate file and removal of old concat code. 2024-09-04 09:34:51 +02:00
Christoffer Lerno
59ff94c005 Issue where a lambda wasn't correctly registered as external. #1408 2024-09-03 23:25:47 +02:00
Christoffer Lerno
bbc199cda3 Some cleanup of asm and assert 2024-09-03 13:53:15 +02:00
Christoffer Lerno
df91ee3d2a Update version. 2024-09-03 11:48:43 +02:00
237 changed files with 11630 additions and 4603 deletions

28
.editorconfig Normal file
View File

@@ -0,0 +1,28 @@
# EditorConfig is awesome: https://editorconfig.org
root = true
[*]
charset = utf-8
end_of_line = lf
[CMakeLists.txt]
indent_style = space
indent_size = 4
[*.{c,cc,h}]
indent_style = space
indent_size = 4
[*.{c3}]
indent_style = space
indent_size = 4
[*.{json,toml,yml,gyp}]
indent_style = space
indent_size = 2
[*.{py,pyi}]
indent_style = space
indent_size = 2

2
.gitattributes vendored
View File

@@ -1,4 +1,2 @@
$ cat .gitattributes
* text=auto
*.c3 linguist-language=C
*.c3t linguist-language=C

View File

@@ -8,7 +8,7 @@ on:
env:
LLVM_RELEASE_VERSION_WINDOWS: 18
LLVM_RELEASE_VERSION_MAC: 18
LLVM_RELEASE_VERSION_MAC: 17
LLVM_RELEASE_VERSION_LINUX: 17
LLVM_RELEASE_VERSION_UBUNTU20: 17
LLVM_DEV_VERSION: 20
@@ -91,7 +91,7 @@ jobs:
dir msvc_sdk
- name: upload artifacts
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: c3-windows-${{ matrix.build_type }}
path: |
@@ -216,7 +216,7 @@ jobs:
fail-fast: false
matrix:
build_type: [Release, Debug]
llvm_version: [17, 18, 19, 20]
llvm_version: [17, 18, 19]
steps:
- uses: actions/checkout@v4
@@ -324,7 +324,7 @@ jobs:
- name: Test WASM
run: |
cd resources/testfragments
../../build/c3c compile --reloc=none --target wasm32 -g0 --link-libc=no --no-entry -Os wasm4.c3
../../build/c3c compile --target wasm32 -g0 --no-entry -Os wasm4.c3
- name: Install QEMU and Risc-V toolchain
run: |
@@ -363,7 +363,7 @@ jobs:
- name: upload artifacts
if: matrix.llvm_version == env.LLVM_RELEASE_VERSION_LINUX
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: c3-linux-${{matrix.build_type}}
path: c3-linux-${{matrix.build_type}}.tar.gz
@@ -484,7 +484,7 @@ jobs:
- name: upload artifacts
if: matrix.llvm_version == env.LLVM_RELEASE_VERSION_UBUNTU20
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: c3-ubuntu-20-${{matrix.build_type}}
path: c3-ubuntu-20-${{matrix.build_type}}.tar.gz
@@ -496,7 +496,7 @@ jobs:
matrix:
ubuntu_version: [20.04, 22.04]
build_type: [Release, Debug]
llvm_version: [17, 18, 19, 20]
llvm_version: [17, 18, 19]
steps:
- uses: actions/checkout@v4
@@ -558,7 +558,7 @@ jobs:
- name: Test WASM
run: |
cd resources/testfragments
../../build/c3c compile --reloc=none --target wasm32 -g0 --link-libc=no --no-entry -Os wasm4.c3
../../build/c3c compile --reloc=none --target wasm32 -g0 --no-entry -Os wasm4.c3
- name: Build testproject direct linker
run: |
@@ -657,7 +657,7 @@ jobs:
- name: upload artifacts
if: matrix.llvm_version == env.LLVM_RELEASE_VERSION_MAC
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: c3-macos-${{matrix.build_type}}
path: c3-macos-${{matrix.build_type}}.zip
@@ -665,7 +665,7 @@ jobs:
release:
runs-on: ubuntu-latest
needs: [build-msvc, build-linux, build-mac]
needs: [build-msvc, build-linux, build-mac, build-linux-ubuntu20]
if: github.ref == 'refs/heads/master'
steps:
@@ -692,16 +692,22 @@ jobs:
sha: context.sha
})
- uses: actions/download-artifact@v3
- uses: actions/download-artifact@v4
- run: cp -r lib c3-windows-Release
- run: cp -r lib c3-windows-Debug
- run: cp msvc_build_libraries.py c3-windows-Release
- run: cp msvc_build_libraries.py c3-windows-Debug
- run: zip -r c3-windows-Release.zip c3-windows-Release
- run: zip -r c3-windows-Debug.zip c3-windows-Debug
- run: zip -r c3-windows.zip c3-windows-Release
- run: zip -r c3-windows-debug.zip c3-windows-Debug
- run: mv c3-linux-Release/c3-linux-Release.tar.gz c3-linux-Release/c3-linux.tar.gz
- run: mv c3-linux-Debug/c3-linux-Debug.tar.gz c3-linux-Debug/c3-linux-debug.tar.gz
- run: mv c3-ubuntu-20-Release/c3-ubuntu-20-Release.tar.gz c3-ubuntu-20-Release/c3-ubuntu-20.tar.gz
- run: mv c3-ubuntu-20-Debug/c3-ubuntu-20-Debug.tar.gz c3-ubuntu-20-Debug/c3-ubuntu-20-debug.tar.gz
- run: mv c3-macos-Release/c3-macos-Release.zip c3-macos-Release/c3-macos.zip
- run: mv c3-macos-Debug/c3-macos-Debug.zip c3-macos-Debug/c3-macos-debug.zip
- id: create_release
uses: actions/create-release@v1
uses: softprops/action-gh-release@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
@@ -709,84 +715,12 @@ jobs:
release_name: latest
draft: false
prerelease: true
- name: upload windows
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: c3-windows-Release.zip
asset_name: c3-windows.zip
asset_content_type: application/zip
- name: upload windows debug
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: c3-windows-Debug.zip
asset_name: c3-windows-debug.zip
asset_content_type: application/zip
- name: upload linux
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: c3-linux-Release/c3-linux-Release.tar.gz
asset_name: c3-linux.tar.gz
asset_content_type: application/gzip
- name: upload linux debug
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: c3-linux-Debug/c3-linux-Debug.tar.gz
asset_name: c3-linux-debug.tar.gz
asset_content_type: application/gzip
- name: upload ubuntu 20
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: c3-ubuntu-20-Release/c3-ubuntu-20-Release.tar.gz
asset_name: c3-ubuntu-20.tar.gz
asset_content_type: application/gzip
- name: upload ubuntu 20 debug
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: c3-ubuntu-20-Debug/c3-ubuntu-20-Debug.tar.gz
asset_name: c3-ubuntu-20-debug.tar.gz
asset_content_type: application/gzip
- name: upload macos
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: c3-macos-Release/c3-macos-Release.zip
asset_name: c3-macos.zip
asset_content_type: application/zip
- name: upload macos debug
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: c3-macos-Debug/c3-macos-Debug.zip
asset_name: c3-macos-debug.zip
asset_content_type: application/zip
files: |
c3-windows.zip
c3-windows-debug.zip
c3-linux-Release/c3-linux.tar.gz
c3-linux-Debug/c3-linux-debug.tar.gz
c3-ubuntu-20-Release/c3-ubuntu-20.tar.gz
c3-ubuntu-20-Debug/c3-ubuntu-20-debug.tar.gz
c3-macos-Release/c3-macos.zip
c3-macos-Debug/c3-macos-debug.zip

5
.gitignore vendored
View File

@@ -70,3 +70,8 @@ out/
# Emacs files
TAGS
# Clangd LSP files
/.cache/
/compile_commands.json

View File

@@ -63,6 +63,7 @@ set(C3_LLVM_VERSION "auto" CACHE STRING "Use LLVM version [default: auto]")
option(C3_USE_MIMALLOC "Use built-in mimalloc" OFF)
option(C3_USE_TB "Use TB" OFF)
set(C3_MIMALLOC_TAG "v1.7.3" CACHE STRING "Used version of mimalloc")
option(C3_WITH_LLVM "Build with LLVM" ON)
set(C3_USE_MIMALLOC OFF)
if(C3_USE_MIMALLOC)
@@ -80,9 +81,11 @@ endif()
if (NOT WIN32)
find_package(CURL)
endif()
if (NOT C3_LLVM_VERSION STREQUAL "auto")
if (${C3_LLVM_VERSION} VERSION_LESS 17 OR ${C3_LLVM_VERSION} VERSION_GREATER 20)
message(FATAL_ERROR "LLVM ${C3_LLVM_VERSION} is not supported!")
if(C3_WITH_LLVM)
if (NOT C3_LLVM_VERSION STREQUAL "auto")
if (${C3_LLVM_VERSION} VERSION_LESS 17 OR ${C3_LLVM_VERSION} VERSION_GREATER 20)
message(FATAL_ERROR "LLVM ${C3_LLVM_VERSION} is not supported!")
endif()
endif()
endif()
@@ -101,113 +104,126 @@ if(C3_USE_TB AND GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
endif()
endif()
if(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
if (C3_LLVM_VERSION STREQUAL "auto")
set(C3_LLVM_VERSION "18")
endif()
FetchContent_Declare(
LLVM_Windows
URL https://github.com/c3lang/win-llvm/releases/download/llvm_18_1_8_with_rt/llvm-18.1.8-windows-amd64-msvc17-libcmt.7z
# Clangd LSP support
option(C3_ENABLE_CLANGD_LSP "Enable/Disable output of compile commands during generation." OFF)
if(C3_ENABLE_CLANGD_LSP)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
execute_process(
COMMAND ${CMAKE_COMMAND} -E create_symlink
${CMAKE_BINARY_DIR}/compile_commands.json
${CMAKE_SOURCE_DIR}/compile_commands.json
)
FetchContent_Declare(
LLVM_Windows_debug
URL https://github.com/c3lang/win-llvm/releases/download/llvm_18_1_8_with_rt/llvm-18.1.8-windows-amd64-msvc17-libcmt-dbg.7z
)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
message("Loading Windows LLVM debug libraries, this may take a while...")
FetchContent_MakeAvailable(LLVM_Windows_debug)
set(llvm_dir ${llvm_windows_debug_SOURCE_DIR})
else()
message("Loading Windows LLVM libraries, this may take a while...")
FetchContent_MakeAvailable(LLVM_Windows)
set(llvm_dir ${llvm_windows_SOURCE_DIR})
endif()
set(CMAKE_SYSTEM_PREFIX_PATH ${llvm_dir} ${CMAKE_SYSTEM_PREFIX_PATH})
endif(C3_ENABLE_CLANGD_LSP)
if(C3_WITH_LLVM)
if(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
if (C3_LLVM_VERSION STREQUAL "auto")
set(C3_LLVM_VERSION "18")
endif()
FetchContent_Declare(
LLVM_Windows
URL https://github.com/c3lang/win-llvm/releases/download/llvm_18_1_8_with_rt/llvm-18.1.8-windows-amd64-msvc17-libcmt.7z
)
FetchContent_Declare(
LLVM_Windows_debug
URL https://github.com/c3lang/win-llvm/releases/download/llvm_18_1_8_with_rt/llvm-18.1.8-windows-amd64-msvc17-libcmt-dbg.7z
)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
message("Loading Windows LLVM debug libraries, this may take a while...")
FetchContent_MakeAvailable(LLVM_Windows_debug)
set(llvm_dir ${llvm_windows_debug_SOURCE_DIR})
else()
message("Loading Windows LLVM libraries, this may take a while...")
FetchContent_MakeAvailable(LLVM_Windows)
set(llvm_dir ${llvm_windows_SOURCE_DIR})
endif()
set(CMAKE_SYSTEM_PREFIX_PATH ${llvm_dir} ${CMAKE_SYSTEM_PREFIX_PATH})
find_package(LLVM REQUIRED CONFIG)
find_package(LLD REQUIRED CONFIG)
else()
if (NOT C3_LLVM_VERSION STREQUAL "auto")
find_package(LLVM ${C3_LLVM_VERSION} REQUIRED CONFIG)
else()
find_package(LLVM REQUIRED CONFIG)
find_package(LLD REQUIRED CONFIG)
else()
if (NOT C3_LLVM_VERSION STREQUAL "auto")
find_package(LLVM ${C3_LLVM_VERSION} REQUIRED CONFIG)
else()
find_package(LLVM REQUIRED CONFIG)
endif()
endif()
endif()
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
message(STATUS "Libraries located in: ${LLVM_LIBRARY_DIRS}")
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
message(STATUS "Libraries located in: ${LLVM_LIBRARY_DIRS}")
if (NOT LLVM_PACKAGE_VERSION VERSION_GREATER_EQUAL 15.0)
message(FATAL_ERROR "LLVM version 15.0 or later is required.")
endif()
if (NOT LLVM_PACKAGE_VERSION VERSION_GREATER_EQUAL 15.0)
message(FATAL_ERROR "LLVM version 15.0 or later is required.")
endif()
if(LLVM_ENABLE_RTTI)
message(STATUS "LLVM was built with RTTI")
else()
message(STATUS "LLVM was not built with RTTI")
endif()
if(LLVM_ENABLE_RTTI)
message(STATUS "LLVM was built with RTTI")
else()
message(STATUS "LLVM was not built with RTTI")
endif()
string(REPLACE "." ";" VERSION_LIST ${LLVM_PACKAGE_VERSION})
list(GET VERSION_LIST 0 LLVM_MAJOR_VERSION)
string(REPLACE "." ";" VERSION_LIST ${LLVM_PACKAGE_VERSION})
list(GET VERSION_LIST 0 LLVM_MAJOR_VERSION)
include_directories(${LLVM_INCLUDE_DIRS})
link_directories(${LLVM_LIBRARY_DIRS})
add_definitions(${LLVM_DEFINITIONS})
include_directories(${LLVM_INCLUDE_DIRS})
link_directories(${LLVM_LIBRARY_DIRS})
add_definitions(${LLVM_DEFINITIONS})
if(NOT C3_LINK_DYNAMIC)
set(LLVM_LINK_COMPONENTS
AllTargetsAsmParsers
AllTargetsCodeGens
AllTargetsDescs
AllTargetsDisassemblers
AllTargetsInfos
Analysis
AsmPrinter
BitReader
Core
DebugInfoPDB
InstCombine
IrReader
LibDriver
Linker
LTO
MC
MCDisassembler
native
nativecodegen
Object
Option
ScalarOpts
Support
Target
TransformUtils
WindowsManifest
WindowsDriver
)
if(NOT C3_LINK_DYNAMIC)
set(LLVM_LINK_COMPONENTS
AllTargetsAsmParsers
AllTargetsCodeGens
AllTargetsDescs
AllTargetsDisassemblers
AllTargetsInfos
Analysis
AsmPrinter
BitReader
Core
DebugInfoPDB
InstCombine
IrReader
LibDriver
Linker
LTO
MC
MCDisassembler
native
nativecodegen
Object
Option
ScalarOpts
Support
Target
TransformUtils
WindowsManifest
WindowsDriver
)
llvm_map_components_to_libnames(llvm_libs ${LLVM_LINK_COMPONENTS})
llvm_map_components_to_libnames(llvm_libs ${LLVM_LINK_COMPONENTS})
# These don't seem to be reliable on windows.
message(STATUS "using find_library")
find_library(LLD_COFF NAMES lldCOFF.lib lldCOFF.a liblldCOFF.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
find_library(LLD_COMMON NAMES lldCommon.lib lldCommon.a liblldCommon.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
find_library(LLD_ELF NAMES lldELF.lib lldELF.a liblldELF.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
find_library(LLD_MACHO NAMES lldMachO.lib lldMachO.a liblldMachO.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
find_library(LLD_MINGW NAMES lldMinGW.lib lldMinGW.a liblldMinGW.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
find_library(LLD_WASM NAMES lldWasm.lib lldWasm.a liblldWasm.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
else()
find_library(LLVM NAMES libLLVM.so PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
set(llvm_libs ${LLVM})
# These don't seem to be reliable on windows.
message(STATUS "using find_library")
find_library(LLD_COFF NAMES lldCOFF.lib lldCOFF.a liblldCOFF.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
find_library(LLD_COMMON NAMES lldCommon.lib lldCommon.a liblldCommon.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
find_library(LLD_ELF NAMES lldELF.lib lldELF.a liblldELF.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
find_library(LLD_MACHO NAMES lldMachO.lib lldMachO.a liblldMachO.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
find_library(LLD_MINGW NAMES lldMinGW.lib lldMinGW.a liblldMinGW.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
find_library(LLD_WASM NAMES lldWasm.lib lldWasm.a liblldWasm.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
else()
find_library(LLVM NAMES libLLVM.so PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
set(llvm_libs ${LLVM})
# These don't seem to be reliable on windows.
message(STATUS "using find_library")
find_library(LLD_COFF NAMES liblldCOFF.so PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
find_library(LLD_COMMON NAMES liblldCommon.so PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
find_library(LLD_ELF NAMES liblldELF.so PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
find_library(LLD_MACHO NAMES liblldMachO.so PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
find_library(LLD_MINGW NAMES liblldMinGW.so PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
find_library(LLD_WASM NAMES liblldWasm.so PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
# These don't seem to be reliable on windows.
message(STATUS "using find_library")
find_library(LLD_COFF NAMES liblldCOFF.so PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
find_library(LLD_COMMON NAMES liblldCommon.so PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
find_library(LLD_ELF NAMES liblldELF.so PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
find_library(LLD_MACHO NAMES liblldMachO.so PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
find_library(LLD_MINGW NAMES liblldMinGW.so PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
find_library(LLD_WASM NAMES liblldWasm.so PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
endif()
endif()
if (NOT(${CMAKE_BINARY_DIR} EQUAL ${CMAKE_SOURCE_DIR}))
@@ -215,36 +231,36 @@ if (NOT(${CMAKE_BINARY_DIR} EQUAL ${CMAKE_SOURCE_DIR}))
file(COPY ${CMAKE_SOURCE_DIR}/lib DESTINATION ${CMAKE_BINARY_DIR})
endif()
find_library(LLD_LOONG NAMES libLLVMLoongArchCodeGen.lib libLLVMLoongArchAsmParser.lib libLLVMLoongArchCodeGen.a libLLVMLoongArchAsmParser.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
set(lld_libs
${LLD_COFF}
${LLD_COMMON}
${LLD_WASM}
${LLD_MINGW}
${LLD_ELF}
${LLD_MACHO}
)
if (APPLE)
set(lld_libs ${lld_libs} xar)
find_file(RT_ASAN_DYNAMIC NAMES libclang_rt.asan_osx_dynamic.dylib PATHS "${LLVM_LIBRARY_DIRS}/clang/${LLVM_MAJOR_VERSION}/lib/darwin")
find_file(RT_TSAN_DYNAMIC NAMES libclang_rt.tsan_osx_dynamic.dylib PATHS "${LLVM_LIBRARY_DIRS}/clang/${LLVM_MAJOR_VERSION}/lib/darwin")
find_file(RT_UBSAN_DYNAMIC NAMES libclang_rt.ubsan_osx_dynamic.dylib PATHS "${LLVM_LIBRARY_DIRS}/clang/${LLVM_MAJOR_VERSION}/lib/darwin")
find_file(RT_LSAN_DYNAMIC NAMES libclang_rt.lsan_osx_dynamic.dylib PATHS "${LLVM_LIBRARY_DIRS}/clang/${LLVM_MAJOR_VERSION}/lib/darwin")
set(sanitizer_runtime_libraries
${RT_ASAN_DYNAMIC}
${RT_TSAN_DYNAMIC}
# Unused
# ${RT_UBSAN_DYNAMIC}
# ${RT_LSAN_DYNAMIC}
if(C3_WITH_LLVM)
find_library(LLD_LOONG NAMES libLLVMLoongArchCodeGen.lib libLLVMLoongArchAsmParser.lib libLLVMLoongArchCodeGen.a libLLVMLoongArchAsmParser.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
set(lld_libs
${LLD_COFF}
${LLD_COMMON}
${LLD_WASM}
${LLD_MINGW}
${LLD_ELF}
${LLD_MACHO}
)
if (APPLE)
set(lld_libs ${lld_libs} xar)
find_file(RT_ASAN_DYNAMIC NAMES libclang_rt.asan_osx_dynamic.dylib PATHS "${LLVM_LIBRARY_DIRS}/clang/${LLVM_MAJOR_VERSION}/lib/darwin")
find_file(RT_TSAN_DYNAMIC NAMES libclang_rt.tsan_osx_dynamic.dylib PATHS "${LLVM_LIBRARY_DIRS}/clang/${LLVM_MAJOR_VERSION}/lib/darwin")
find_file(RT_UBSAN_DYNAMIC NAMES libclang_rt.ubsan_osx_dynamic.dylib PATHS "${LLVM_LIBRARY_DIRS}/clang/${LLVM_MAJOR_VERSION}/lib/darwin")
find_file(RT_LSAN_DYNAMIC NAMES libclang_rt.lsan_osx_dynamic.dylib PATHS "${LLVM_LIBRARY_DIRS}/clang/${LLVM_MAJOR_VERSION}/lib/darwin")
set(sanitizer_runtime_libraries
${RT_ASAN_DYNAMIC}
${RT_TSAN_DYNAMIC}
# Unused
# ${RT_UBSAN_DYNAMIC}
# ${RT_LSAN_DYNAMIC}
)
endif()
message(STATUS "linking to llvm libs ${lld_libs}")
message(STATUS "Found lld libs ${lld_libs}")
endif()
message(STATUS "linking to llvm libs ${lld_libs}")
message(STATUS "Found lld libs ${lld_libs}")
add_library(c3c_wrappers STATIC wrapper/src/wrapper.cpp)
add_library(miniz STATIC dependencies/miniz/miniz.c)
add_executable(c3c
@@ -268,7 +284,6 @@ add_executable(c3c
src/compiler/json_output.c
src/compiler/lexer.c
src/compiler/linker.c
src/compiler/llvm_codegen.c
src/compiler/abi/c_abi_aarch64.c
src/compiler/abi/c_abi.c
src/compiler/abi/c_abi_riscv.c
@@ -276,14 +291,6 @@ add_executable(c3c
src/compiler/abi/c_abi_win64.c
src/compiler/abi/c_abi_x64.c
src/compiler/abi/c_abi_x86.c
src/compiler/llvm_codegen_debug_info.c
src/compiler/llvm_codegen_expr.c
src/compiler/llvm_codegen_function.c
src/compiler/llvm_codegen_instr.c
src/compiler/llvm_codegen_module.c
src/compiler/llvm_codegen_stmt.c
src/compiler/llvm_codegen_type.c
src/compiler/llvm_codegen_value.c
src/compiler/module.c
src/compiler/number.c
src/compiler/parse_expr.c
@@ -326,18 +333,18 @@ add_executable(c3c
src/utils/cpus.c
src/utils/unzipper.c
src/compiler/decltable.c
src/compiler/mac_support.c
src/compiler/llvm_codegen_storeload.c
src/compiler/mac_support.c
src/compiler/windows_support.c
src/compiler/codegen_asm.c
src/compiler/asm_target.c
src/compiler/llvm_codegen_builtins.c
src/compiler/asm_target.c
src/compiler/expr.c
src/utils/time.c
src/utils/http.c
src/compiler/sema_liveness.c
src/build/common_build.c
${CMAKE_BINARY_DIR}/git_hash.h)
src/compiler/sema_const.c
${CMAKE_BINARY_DIR}/git_hash.h
)
if(GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
# We are inside of a git repository so rebuilding the hash every time something changes.
@@ -352,6 +359,34 @@ else()
COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_LIST_DIR}/git_hash.cmake")
endif()
if(C3_WITH_LLVM)
target_sources(c3c PRIVATE
src/compiler/llvm_codegen.c
src/compiler/llvm_codegen_debug_info.c
src/compiler/llvm_codegen_expr.c
src/compiler/llvm_codegen_function.c
src/compiler/llvm_codegen_instr.c
src/compiler/llvm_codegen_module.c
src/compiler/llvm_codegen_stmt.c
src/compiler/llvm_codegen_type.c
src/compiler/llvm_codegen_value.c
src/compiler/llvm_codegen_storeload.c
src/compiler/llvm_codegen_builtins.c)
target_compile_definitions(c3c PUBLIC LLVM_AVAILABLE=1)
add_library(c3c_wrappers STATIC wrapper/src/wrapper.cpp)
else()
target_sources(c3c PRIVATE src/utils/hostinfo.c)
target_compile_definitions(c3c PUBLIC LLVM_AVAILABLE=0)
endif()
target_include_directories(c3c PRIVATE
"${CMAKE_SOURCE_DIR}/src/"
"${CMAKE_BINARY_DIR}")
target_include_directories(miniz PUBLIC
"${CMAKE_SOURCE_DIR}/dependencies/miniz/")
if (C3_USE_TB)
file(GLOB tilde-sources
tilde-backend/src/tb/*.c
@@ -384,25 +419,29 @@ if (C3_USE_TB)
target_include_directories(c3c PRIVATE
"${CMAKE_SOURCE_DIR}/tilde-backend/include/")
else()
target_compile_definitions(c3c PUBLIC TB_AVAILABLE=0)
endif()
if(C3_WITH_LLVM)
target_link_libraries(c3c ${llvm_libs} miniz c3c_wrappers ${lld_libs})
target_include_directories(c3c PRIVATE
"${CMAKE_SOURCE_DIR}/src/"
"${CMAKE_SOURCE_DIR}/wrapper/include/"
"${CMAKE_BINARY_DIR}")
target_include_directories(c3c PRIVATE
"${CMAKE_SOURCE_DIR}/wrapper/include/")
target_include_directories(c3c_wrappers PRIVATE
"${CMAKE_SOURCE_DIR}/wrapper/include/")
target_include_directories(c3c_wrappers PRIVATE
"${CMAKE_SOURCE_DIR}/wrapper/include/")
target_link_libraries(c3c_wrappers ${llvm_libs} ${lld_libs})
target_include_directories(miniz PUBLIC
"${CMAKE_SOURCE_DIR}/dependencies/miniz/")
else()
target_link_libraries(c3c_wrappers ${llvm_libs} ${lld_libs})
target_link_libraries(c3c ${llvm_libs} miniz c3c_wrappers ${lld_libs})
target_link_libraries(c3c ${llvm_libs} miniz ${lld_libs})
endif()
if(C3_USE_MIMALLOC)
target_link_libraries(c3c mimalloc-static)
@@ -412,6 +451,11 @@ if (WIN32)
target_link_libraries(c3c Winhttp.lib)
endif()
if(MINGW)
message("Increase stack for msys")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--stack,8388608")
endif ()
if (CURL_FOUND)
target_link_libraries(c3c ${CURL_LIBRARIES})
target_include_directories(c3c PRIVATE ${CURL_INCLUDES})
@@ -420,39 +464,48 @@ else()
target_compile_definitions(c3c PUBLIC CURL_FOUND=0)
endif()
if(MSVC)
message("Adding MSVC options")
target_compile_options(c3c PRIVATE /wd4068 /wd4090 /WX /Wv:18)
target_compile_options(c3c_wrappers PUBLIC /wd4624 /wd4267 /wd4244 /WX /Wv:18)
if (NOT LLVM_ENABLE_RTTI)
target_compile_options(c3c_wrappers PUBLIC /GR-)
if(C3_WITH_LLVM)
target_compile_options(c3c_wrappers PUBLIC /wd4624 /wd4267 /wd4244 /WX /Wv:18)
if(NOT LLVM_ENABLE_RTTI)
target_compile_options(c3c_wrappers PUBLIC /GR-)
endif()
target_link_options(c3c_wrappers PUBLIC /ignore:4099)
endif()
target_link_options(c3c_wrappers PUBLIC /ignore:4099)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
target_compile_options(c3c PUBLIC /MTd)
target_compile_options(c3c_wrappers PUBLIC /MTd)
if (C3_WITH_LLVM)
target_compile_options(c3c_wrappers PUBLIC /MTd)
endif()
target_compile_options(miniz PUBLIC /MTd)
if (C3_USE_TB)
target_compile_options(tilde-backend PUBLIC /MTd)
endif()
else()
target_compile_options(c3c PUBLIC /MT)
target_compile_options(c3c_wrappers PUBLIC /MT)
if (C3_WITH_LLVM)
target_compile_options(c3c_wrappers PUBLIC /MT)
endif()
target_compile_options(miniz PUBLIC /MT)
if (C3_USE_TB)
target_compile_options(tilde-backend PUBLIC /MT)
endif()
endif()
set(clang_lib_dir ${llvm_dir}/lib/clang/${C3_LLVM_VERSION}/lib/windows)
set(sanitizer_runtime_libraries
${clang_lib_dir}/clang_rt.asan-x86_64.lib
${clang_lib_dir}/clang_rt.asan_dynamic-x86_64.lib
${clang_lib_dir}/clang_rt.asan_dynamic-x86_64.dll
${clang_lib_dir}/clang_rt.asan_dynamic_runtime_thunk-x86_64.lib)
if(C3_WITH_LLVM)
set(clang_lib_dir ${llvm_dir}/lib/clang/${C3_LLVM_VERSION}/lib/windows)
set(sanitizer_runtime_libraries
${clang_lib_dir}/clang_rt.asan-x86_64.lib
${clang_lib_dir}/clang_rt.asan_dynamic-x86_64.lib
${clang_lib_dir}/clang_rt.asan_dynamic-x86_64.dll
${clang_lib_dir}/clang_rt.asan_dynamic_runtime_thunk-x86_64.lib)
endif()
else()
message(STATUS "using gcc/clang warning switches")
target_link_options(c3c PRIVATE -pthread)
if (NOT LLVM_ENABLE_RTTI)
if (C3_WITH_LLVM AND NOT LLVM_ENABLE_RTTI)
target_compile_options(c3c_wrappers PRIVATE -fno-rtti)
endif()
target_compile_options(c3c PRIVATE -pthread -Wall -Werror -Wno-unknown-pragmas -Wno-unused-result
@@ -462,7 +515,7 @@ endif()
install(TARGETS c3c DESTINATION bin)
install(DIRECTORY lib/ DESTINATION lib/c3)
if (DEFINED sanitizer_runtime_libraries)
if (C3_WITH_LLVM AND DEFINED sanitizer_runtime_libraries)
add_custom_command(TARGET c3c POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E rm -rf -- $<TARGET_FILE_DIR:c3c>/c3c_rt
COMMAND "${CMAKE_COMMAND}" -E make_directory $<TARGET_FILE_DIR:c3c>/c3c_rt

View File

@@ -10,7 +10,8 @@ Precompiled binaries for the following operating systems are available:
- Windows x64 [download](https://github.com/c3lang/c3c/releases/download/latest/c3-windows.zip), [install instructions](#installing-on-windows-with-precompiled-binaries).
- Debian x64 [download](https://github.com/c3lang/c3c/releases/download/latest/c3-linux.tar.gz), [install instructions](#installing-on-debian-with-precompiled-binaries).
- MacOS x64 [download](https://github.com/c3lang/c3c/releases/download/latest/c3-macos.zip), [install instructions](#installing-on-mac-with-precompiled-binaries).
- Ubuntu x86 [download](https://github.com/c3lang/c3c/releases/download/latest/c3-ubuntu-20.tar.gz), [install instructions](#installing-on-ubuntu-with-precompiled-binaries).
- MacOS Arm64 [download](https://github.com/c3lang/c3c/releases/download/latest/c3-macos.zip), [install instructions](#installing-on-mac-with-precompiled-binaries).
The manual for C3 can be found at [www.c3-lang.org](http://www.c3-lang.org).
@@ -34,7 +35,7 @@ whole new language.
The following code shows [generic modules](https://c3-lang.org/references/docs/generics/) (more examples can be found at https://c3-lang.org/references/docs/examples/).
```c++
```cpp
module stack (<Type>);
// Above: the parameterized type is applied to the entire module.
@@ -137,7 +138,7 @@ fn void main()
### Current status
The current stable version of the compiler is **version 0.6.1**.
The current stable version of the compiler is **version 0.6.2**.
The upcoming 0.6.x releases will focus on expanding the standard library.
Follow the issues [here](https://github.com/c3lang/c3c/issues).
@@ -205,7 +206,13 @@ More platforms will be supported in the future.
2. Unpack executable and standard lib.
3. Run `./c3c`.
#### Installing on Mac with precompiled binaries
#### Installing on Ubuntu with precompiled binaries
1. Download tar file: [https://github.com/c3lang/c3c/releases/download/latest/c3-ubuntu-20.tar.gz](https://github.com/c3lang/c3c/releases/download/latest/c3-ubuntu-20.tar.gz)
(debug version [here](https://github.com/c3lang/c3c/releases/download/latest/c3-ubuntu-20-debug.tar.gz))
2. Unpack executable and standard lib.
3. Run `./c3c`.
#### Installing on MacOS with precompiled binaries
1. Make sure you have XCode with command line tools installed.
2. Download the zip file: [https://github.com/c3lang/c3c/releases/download/latest/c3-macos.zip](https://github.com/c3lang/c3c/releases/download/latest/c3-macos.zip)
(debug version [here](https://github.com/c3lang/c3c/releases/download/latest/c3-macos-debug.zip))
@@ -215,9 +222,16 @@ More platforms will be supported in the future.
(*Note that there is a known issue with debug symbol generation on MacOS 13, see [issue #1086](https://github.com/c3lang/c3c/issues/1086))
#### Installing on Arch Linux
There is an AUR package for the c3c compiler : [c3c-git](https://aur.archlinux.org/packages/c3c-git).
Arch includes c3c in the official 'extra' repo. It can be easily installed the usual way:
Due to some issues with the LLVM packaged for Arch Linux, the AUR package will download and use LLVM 16 for Ubuntu-23.04 to compile the c3c compiler.
```sh
sudo pacman -S c3c
# or paru -S c3c
# or yay -S c3c
# or aura -A c3c
```
There is also an AUR package for the c3c compiler : [c3c-git](https://aur.archlinux.org/packages/c3c-git).
You can use your AUR package manager:
```sh
@@ -304,17 +318,16 @@ You can try it out by running some sample code: `c3c.exe compile ../resources/ex
*Note that if you run into linking issues when building, make sure that you are using the latest version of VS17.*
#### Compiling on Ubuntu 20.10
#### Compiling on Ubuntu 24.04 LTS
1. Make sure you have a C compiler that handles C11 and a C++ compiler, such as GCC or Clang. Git also needs to be installed.
2. Install CMake: `sudo apt install cmake`
3. Install LLVM 17+ (or greater: C3C supports LLVM 17+): `sudo apt-get install clang-17 zlib1g zlib1g-dev libllvm17 llvm-17 llvm-17-dev llvm-17-runtime liblld-17-dev liblld-17`
4. Clone the C3C github repository: `git clone https://github.com/c3lang/c3c.git`
5. Enter the C3C directory `cd c3c`.
6. Create a build directory `mkdir build`
7. Change directory to the build directory `cd build`
8. Set up CMake build: `cmake ..`
9. Build: `cmake --build .`
2. Install LLVM 18 `sudo apt-get install cmake git clang zlib1g zlib1g-dev libllvm18 llvm llvm-dev llvm-runtime liblld-dev liblld-18 libpolly-18-dev`
3. Clone the C3C github repository: `git clone https://github.com/c3lang/c3c.git`
4. Enter the C3C directory `cd c3c`.
5. Create a build directory `mkdir build`
6. Change directory to the build directory `cd build`
7. Set up CMake build: `cmake ..`
8. Build: `cmake --build .`
You should now have a `c3c` executable.
@@ -369,3 +382,9 @@ Editor plugins can be found at https://github.com/c3lang/editor-plugins.
3. Run tests and see that they pass. (Recommended settings: `c3c compile-test -O0 test/unit`.
- in this example `test/unit/` is the relative path to the test directory, so adjust as required)
4. Make a pull request for the new tests.
## Thank yous
A huge "thank you" goes out to all contributors and sponsors.
A special thank you to sponsor [Caleb-o](https://github.com/Caleb-o) for going the extra mile.

View File

@@ -78,13 +78,13 @@ fn usz! AnyList.to_format(&self, Formatter* formatter) @dynamic
fn String AnyList.to_new_string(&self, Allocator allocator = null) @dynamic
{
return string::format("%s", *self, .allocator = allocator ?: allocator::heap());
return string::format("%s", *self, allocator: allocator ?: allocator::heap());
}
fn String AnyList.to_string(&self, Allocator allocator) @dynamic
{
return string::format("%s", *self, .allocator = allocator);
return string::format("%s", *self, allocator: allocator);
}
fn String AnyList.to_tstring(&self) => string::tformat("%s", *self);

View File

@@ -41,12 +41,12 @@ fn usz! ElasticArray.to_format(&self, Formatter* formatter) @dynamic
fn String ElasticArray.to_string(&self, Allocator allocator) @dynamic
{
return string::format("%s", *self, .allocator = allocator);
return string::format("%s", *self, allocator: allocator);
}
fn String ElasticArray.to_new_string(&self, Allocator allocator = nul) @dynamic
{
return string::format("%s", *self, .allocator = allocator ?: allocator::heap());
return string::format("%s", *self, allocator: allocator ?: allocator::heap());
}
fn String ElasticArray.to_tstring(&self)

View File

@@ -1,3 +1,6 @@
/**
* @require Enum.kindof == TypeKind.ENUM : "Only enums may be used with an enummap"
**/
module std::collections::enummap(<Enum, ValueType>);
import std::io;
struct EnumMap (Printable)
@@ -27,12 +30,12 @@ fn usz! EnumMap.to_format(&self, Formatter* formatter) @dynamic
fn String EnumMap.to_string(&self, Allocator allocator) @dynamic
{
return string::format("%s", *self, .allocator = allocator);
return string::format("%s", *self, allocator: allocator);
}
fn String EnumMap.to_new_string(&self, Allocator allocator = null) @dynamic
{
return string::format("%s", *self, .allocator = allocator ?: allocator::heap());
return string::format("%s", *self, allocator: allocator ?: allocator::heap());
}
fn String EnumMap.to_tstring(&self) @dynamic

View File

@@ -3,7 +3,7 @@
// a copy of which can be found in the LICENSE_STDLIB file.
/**
* @require Enum.kindof == TypeKind.ENUM : "Only enums maybe be used with an enumset"
* @require Enum.kindof == TypeKind.ENUM : "Only enums may be used with an enumset"
**/
module std::collections::enumset(<Enum>);
import std::io;
@@ -143,12 +143,12 @@ fn usz! EnumSet.to_format(&set, Formatter* formatter) @dynamic
fn String EnumSet.to_new_string(&set, Allocator allocator = allocator::heap()) @dynamic
{
return string::format("%s", *set, .allocator = allocator);
return string::format("%s", *set, allocator: allocator);
}
fn String EnumSet.to_string(&set, Allocator allocator) @dynamic
{
return string::format("%s", *set, .allocator = allocator);
return string::format("%s", *set, allocator: allocator);
}
fn String EnumSet.to_tstring(&set) @dynamic

View File

@@ -53,6 +53,80 @@ fn HashMap* HashMap.temp_init(&self, uint capacity = DEFAULT_INITIAL_CAPACITY, f
return self.init(allocator::temp(), capacity, load_factor) @inline;
}
/**
* @param [&inout] allocator "The allocator to use"
* @require $vacount % 2 == 0 "There must be an even number of arguments provided for keys and values"
* @require capacity > 0 "The capacity must be 1 or higher"
* @require load_factor > 0.0 "The load factor must be higher than 0"
* @require !self.allocator "Map was already initialized"
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
**/
macro HashMap* HashMap.new_init_with_key_values(&self, ..., uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap())
{
self.new_init(capacity, load_factor, allocator);
$for (var $i = 0; $i < $vacount; $i += 2)
self.set($vaarg[$i], $vaarg[$i+1]);
$endfor
return self;
}
/**
* @param [in] keys "The keys for the HashMap entries"
* @param [in] values "The values for the HashMap entries"
* @param [&inout] allocator "The allocator to use"
* @require keys.len == values.len "Both keys and values arrays must be the same length"
* @require capacity > 0 "The capacity must be 1 or higher"
* @require load_factor > 0.0 "The load factor must be higher than 0"
* @require !self.allocator "Map was already initialized"
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
**/
fn HashMap* HashMap.new_init_from_keys_and_values(&self, Key[] keys, Value[] values, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap())
{
assert(keys.len == values.len);
self.new_init(capacity, load_factor, allocator);
for (usz i = 0; i < keys.len; i++)
{
self.set(keys[i], values[i]);
}
return self;
}
/**
* @require $vacount % 2 == 0 "There must be an even number of arguments provided for keys and values"
* @require capacity > 0 "The capacity must be 1 or higher"
* @require load_factor > 0.0 "The load factor must be higher than 0"
* @require !self.allocator "Map was already initialized"
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
**/
macro HashMap* HashMap.temp_init_with_key_values(&self, ..., uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR)
{
self.temp_init(capacity, load_factor);
$for (var $i = 0; $i < $vacount; $i += 2)
self.set($vaarg[$i], $vaarg[$i+1]);
$endfor
return self;
}
/**
* @param [in] keys "The keys for the HashMap entries"
* @param [in] values "The values for the HashMap entries"
* @param [&inout] allocator "The allocator to use"
* @require keys.len == values.len "Both keys and values arrays must be the same length"
* @require capacity > 0 "The capacity must be 1 or higher"
* @require load_factor > 0.0 "The load factor must be higher than 0"
* @require !self.allocator "Map was already initialized"
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
**/
fn HashMap* HashMap.temp_init_from_keys_and_values(&self, Key[] keys, Value[] values, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap())
{
assert(keys.len == values.len);
self.temp_init(capacity, load_factor);
for (usz i = 0; i < keys.len; i++)
{
self.set(keys[i], values[i]);
}
return self;
}
/**
* Has this hash map been initialized yet?

View File

@@ -102,7 +102,7 @@ fn usz! List.to_format(&self, Formatter* formatter) @dynamic
fn String List.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic
{
return string::format("%s", *self, .allocator = allocator);
return string::format("%s", *self, allocator: allocator);
}
fn String List.to_tstring(&self)
@@ -352,7 +352,7 @@ fn void List.ensure_capacity(&self, usz min_capacity) @local
min_capacity = math::next_power_of_2(min_capacity);
$if type_is_overaligned():
self.entries = allocator::realloc_aligned(self.allocator, self.entries, Type.sizeof * min_capacity, .alignment = Type[1].alignof)!!;
self.entries = allocator::realloc_aligned(self.allocator, self.entries, Type.sizeof * min_capacity, alignment: Type[1].alignof)!!;
$else
self.entries = allocator::realloc(self.allocator, self.entries, Type.sizeof * min_capacity);
$endif;

View File

@@ -45,6 +45,77 @@ fn Map temp(uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAUL
return (Map)map;
}
/**
* @param [&inout] allocator "The allocator to use"
* @require $vacount % 2 == 0 "There must be an even number of arguments provided for keys and values"
* @require capacity > 0 "The capacity must be 1 or higher"
* @require load_factor > 0.0 "The load factor must be higher than 0"
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
**/
macro Map new_init_with_key_values(..., uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap())
{
Map map = new(capacity, load_factor, allocator);
$for (var $i = 0; $i < $vacount; $i += 2)
map.set($vaarg[$i], $vaarg[$i+1]);
$endfor
return map;
}
/**
* @param [in] keys "Array of keys for the Map entries"
* @param [in] values "Array of values for the Map entries"
* @param [&inout] allocator "The allocator to use"
* @require keys.len == values.len "Both keys and values arrays must be the same length"
* @require capacity > 0 "The capacity must be 1 or higher"
* @require load_factor > 0.0 "The load factor must be higher than 0"
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
**/
fn Map new_init_from_keys_and_values(Key[] keys, Value[] values, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap())
{
assert(keys.len == values.len);
Map map = new(capacity, load_factor, allocator);
for (usz i = 0; i < keys.len; i++)
{
map.set(keys[i], values[i]);
}
return map;
}
/**
* @require $vacount % 2 == 0 "There must be an even number of arguments provided for keys and values"
* @require capacity > 0 "The capacity must be 1 or higher"
* @require load_factor > 0.0 "The load factor must be higher than 0"
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
**/
macro Map temp_new_with_key_values(..., uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR)
{
Map map = temp(capacity, load_factor);
$for (var $i = 0; $i < $vacount; $i += 2)
map.set($vaarg[$i], $vaarg[$i+1]);
$endfor
return map;
}
/**
* @param [in] keys "The keys for the HashMap entries"
* @param [in] values "The values for the HashMap entries"
* @param [&inout] allocator "The allocator to use"
* @require keys.len == values.len "Both keys and values arrays must be the same length"
* @require capacity > 0 "The capacity must be 1 or higher"
* @require load_factor > 0.0 "The load factor must be higher than 0"
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
**/
fn Map temp_init_from_keys_and_values(Key[] keys, Value[] values, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap())
{
assert(keys.len == values.len);
Map map = temp(capacity, load_factor);
for (usz i = 0; i < keys.len; i++)
{
map.set(keys[i], values[i]);
}
return map;
}
/**
* @param [&in] other_map "The map to copy from."
**/
@@ -53,7 +124,7 @@ fn Map new_from_map(Map other_map, Allocator allocator = null)
MapImpl* other_map_impl = (MapImpl*)other_map;
if (!other_map_impl)
{
if (allocator) return new(.allocator = allocator);
if (allocator) return new(allocator: allocator);
return null;
}
MapImpl* map = (MapImpl*)new(other_map_impl.table.len, other_map_impl.load_factor, allocator ?: allocator::heap());

View File

@@ -1,6 +1,6 @@
module std::collections::maybe(<Type>);
struct Maybe
struct Maybe @adhoc
{
Type value;
bool has_value;

View File

@@ -156,7 +156,7 @@ fn void Object.init_map_if_needed(&self) @private
if (self.is_empty())
{
self.type = ObjectInternalMap.typeid;
self.map.new_init(.allocator = self.allocator);
self.map.new_init(allocator: self.allocator);
}
}
@@ -168,7 +168,7 @@ fn void Object.init_array_if_needed(&self) @private
if (self.is_empty())
{
self.type = ObjectInternalList.typeid;
self.array.new_init(.allocator = self.allocator);
self.array.new_init(allocator: self.allocator);
}
}

View File

@@ -31,12 +31,12 @@ fn Type Range.get(&self, usz index) @operator([])
fn String Range.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic @deprecated
{
return string::format("[%s..%s]", self.start, self.end, .allocator = allocator);
return string::format("[%s..%s]", self.start, self.end, allocator: allocator);
}
fn String Range.to_string(&self, Allocator allocator) @dynamic
{
return string::format("[%s..%s]", self.start, self.end, .allocator = allocator);
return string::format("[%s..%s]", self.start, self.end, allocator: allocator);
}
fn String Range.to_tstring(&self)
@@ -78,7 +78,7 @@ fn String ExclusiveRange.to_new_string(&self, Allocator allocator = null) @dynam
fn String ExclusiveRange.to_string(&self, Allocator allocator) @dynamic
{
return string::format("[%s..<%s]", self.start, self.end, .allocator = allocator);
return string::format("[%s..<%s]", self.start, self.end, allocator: allocator);
}
fn String ExclusiveRange.to_tstring(&self)

View File

@@ -1,6 +1,6 @@
module std::collections::tuple(<Type1, Type2>);
struct Tuple
struct Tuple @adhoc
{
Type1 first;
Type2 second;
@@ -8,7 +8,7 @@ struct Tuple
module std::collections::triple(<Type1, Type2, Type3>);
struct Triple
struct Triple @adhoc
{
Type1 first;
Type2 second;

476
lib/std/compression/qoi.c3 Normal file
View File

@@ -0,0 +1,476 @@
module std::compression::qoi;
const uint PIXELS_MAX = 400000000;
/**
* Colorspace.
* Purely informative. It will be saved to the file header,
* but does not affect how chunks are en-/decoded.
*/
enum QOIColorspace : char (char id)
{
SRGB = 0, // sRGB with linear alpha
LINEAR = 1 // all channels linear
}
/**
* Channels.
* The channels used in an image.
* AUTO can be used when decoding to automatically determine
* the channels from the file's header.
*/
enum QOIChannels : char (char id)
{
AUTO = 0,
RGB = 3,
RGBA = 4
}
/**
* Descriptor.
* Contains information about an image.
*/
struct QOIDesc
{
uint width;
uint height;
QOIChannels channels;
QOIColorspace colorspace;
}
/**
* QOI Errors.
* These are all the possible bad outcomes.
*/
fault QOIError
{
INVALID_PARAMETERS,
FILE_OPEN_FAILED,
FILE_WRITE_FAILED,
INVALID_DATA,
TOO_MANY_PIXELS
}
// Let the user decide if they want to use std::io
module std::compression::qoi @if(!$feature(QOI_NO_STDIO));
import std::io;
/**
* Encode raw RGB or RGBA pixels into a QOI image and write it to the
* file system.
*
* The desc struct must be filled with the image width, height, the
* used channels (QOIChannels.RGB or RGBA) and the colorspace
* (QOIColorspace.SRGB or LINEAR).
*
* The function returns an optional, which can either be a QOIError
* or the number of bytes written on success.
*
* @param [in] filename `The file's name to write the image to`
* @param [in] input `The raw RGB or RGBA pixels to encode`
* @param [&in] desc `The descriptor of the image`
*/
fn usz! write(String filename, char[] input, QOIDesc* desc)
{
@pool() {
// encode data
char[] output = encode(input, desc)!;
// open file
File! f = file::open(filename, "wb");
if (catch f) { return QOIError.FILE_OPEN_FAILED?; }
// write data to file and close it
usz! written = f.write(output);
if (catch written) { return QOIError.FILE_WRITE_FAILED?; }
if (catch f.close()) { return QOIError.FILE_WRITE_FAILED?; }
return written;
};
}
/**
* Read and decode a QOI image from the file system.
*
* If channels is set to QOIChannels.AUTO, the function will
* automatically determine the channels from the file's header.
* However, if channels is RGB or RGBA, the output format will be
* forced into this number of channels.
*
* The desc struct will be filled with the width, height,
* channels and colorspace of the image.
*
* The function returns an optional, which can either be a QOIError
* or a char[] pointing to the decoded pixels on success.
*
* The returned pixel data should be free()d after use, or the decoding
* and use of the data should be wrapped in a @pool() { ... }; block.
*
* @param [in] filename `The file's name to read the image from`
* @param [&out] desc `The descriptor to fill with the image's info`
* @param channels `The channels to be used`
*/
fn char[]! read(String filename, QOIDesc* desc, QOIChannels channels = AUTO, Allocator allocator = allocator::heap())
{
// read file
char[]! data = file::load_new(filename);
if (catch data) return QOIError.FILE_OPEN_FAILED?;
defer mem::free(data);
// pass data to decode function
return decode(data, desc, channels, allocator);
}
// Back to basic non-stdio mode
module std::compression::qoi;
import std::bits;
/**
* Encode raw RGB or RGBA pixels into a QOI image in memory.
*
* The function returns an optional, which can either be a QOIError
* or a char[] pointing to the encoded data on success.
*
* The returned qoi data should be free()d after use, or the encoding
* and use of the data should be wrapped in a @pool() { ... }; block.
* See the write() function for an example.
*
* @param [in] input `The raw RGB or RGBA pixels to encode`
* @param [&in] desc `The descriptor of the image`
*/
fn char[]! encode(char[] input, QOIDesc* desc, Allocator allocator = allocator::heap())
{
// check info in desc
if (desc.width == 0 || desc.height == 0) return QOIError.INVALID_PARAMETERS?;
if (desc.channels == AUTO) return QOIError.INVALID_PARAMETERS?;
uint pixels = desc.width * desc.height;
if (pixels > PIXELS_MAX) return QOIError.TOO_MANY_PIXELS?;
// check input data size
uint image_size = pixels * desc.channels.id;
if (image_size != input.len) return QOIError.INVALID_DATA?;
// allocate memory for encoded data (output)
// header + chunk tag and RGB(A) data for each pixel + end of stream
uint max_size = Header.sizeof + pixels + image_size + END_OF_STREAM.len;
char[] output = allocator::alloc_array(allocator, char, max_size); // no need to init
defer catch allocator::free(allocator, output);
// write header
*(Header*)output.ptr = {
.be_magic = bswap('qoif'),
.be_width = bswap(desc.width),
.be_height = bswap(desc.height),
.channels = desc.channels.id,
.colorspace = desc.colorspace.id
};
uint pos = Header.sizeof; // Current position in output
uint loc; // Current position in image (top-left corner)
uint loc_end = image_size - desc.channels.id; // End of image data
char run_length = 0; // Length of the current run
Pixel[64] palette; // Zero-initialized by default
Pixel prev = { 0, 0, 0, 255 };
Pixel p = { 0, 0, 0, 255 };
ichar[<3>] diff; // pre-allocate for diff
ichar[<3>] luma; // ...and luma
// write chunks
for (loc = 0; loc < image_size; loc += desc.channels.id)
{
// set previous pixel
prev = p;
// get current pixel
p[:3] = input[loc:3]; // cutesy slices :3
if (desc.channels == RGBA) p.a = input[loc + 3];
// check if we can run the previous pixel
if (prev == p) {
run_length++;
if (run_length == 62 || loc == loc_end) {
*@extract(OpRun, output, &pos) = { OP_RUN, run_length - 1 };
run_length = 0;
}
} else {
// end last run if there was one
if (run_length > 0) {
*@extract(OpRun, output, &pos) = { OP_RUN, run_length - 1 };
run_length = 0;
}
switch {
// check if we can index the palette
case (palette[p.hash()] == p):
*@extract(OpIndex, output, &pos) = {
OP_INDEX,
p.hash()
};
// check if we can use diff or luma
case (prev != p && prev.a == p.a):
// diff the pixels
diff = p.rgb - prev.rgb;
if (
diff.r > -3 && diff.r < 2 &&
diff.g > -3 && diff.g < 2 &&
diff.b > -3 && diff.b < 2
) {
*@extract(OpDiff, output, &pos) = {
OP_DIFF,
(char)diff.r + 2,
(char)diff.g + 2,
(char)diff.b + 2
};
palette[p.hash()] = p;
} else {
// check luma eligibility
luma = { diff.r - diff.g, diff.g, diff.b - diff.g };
if (
luma.r >= -8 && luma.r <= 7 &&
luma.g >= -32 && luma.g <= 31 &&
luma.b >= -8 && luma.b <= 7
) {
*@extract(OpLuma, output, &pos) = {
OP_LUMA,
(char)luma.g + 32,
(char)luma.r + 8,
(char)luma.b + 8
};
palette[p.hash()] = p;
} else { nextcase; }
}
// worst case scenario: just encode the raw pixel
default:
if (prev.a != p.a) {
*@extract(OpRGBA, output, &pos) = { OP_RGBA, p.r, p.g, p.b, p.a };
} else {
*@extract(OpRGB, output, &pos) = { OP_RGB, p.r, p.g, p.b };
}
palette[p.hash()] = p;
}
}
}
// write end of stream
output[pos:END_OF_STREAM.len] = END_OF_STREAM;
pos += END_OF_STREAM.len;
return output[:pos];
}
/**
* Decode a QOI image from memory.
*
* If channels is set to QOIChannels.AUTO, the function will
* automatically determine the channels from the file's header.
* However, if channels is RGB or RGBA, the output format will be
* forced into this number of channels.
*
* The desc struct will be filled with the width, height,
* channels and colorspace of the image.
*
* The function returns an optional, which can either be a QOIError
* or a char[] pointing to the decoded pixels on success.
*
* The returned pixel data should be free()d after use, or the decoding
* and use of the data should be wrapped in a @pool() { ... }; block.
*
* @param [in] data `The QOI image data to decode`
* @param [&out] desc `The descriptor to fill with the image's info`
* @param channels `The channels to be used`
*/
fn char[]! decode(char[] data, QOIDesc* desc, QOIChannels channels = AUTO, Allocator allocator = allocator::heap())
{
// check input data
if (data.len < Header.sizeof + END_OF_STREAM.len) return QOIError.INVALID_DATA?;
// get header
Header* header = (Header*)data.ptr;
// check magic bytes (FourCC)
if (bswap(header.be_magic) != 'qoif') return QOIError.INVALID_DATA?;
// copy header data to desc
desc.width = bswap(header.be_width);
desc.height = bswap(header.be_height);
desc.channels = @enumcast(QOIChannels, header.channels)!; // Rethrow if invalid
desc.colorspace = @enumcast(QOIColorspace, header.colorspace)!; // Rethrow if invalid
if (desc.channels == AUTO) return QOIError.INVALID_DATA?; // Channels must be specified in the header
// check width and height
if (desc.width == 0 || desc.height == 0) return QOIError.INVALID_DATA?;
// check pixel count
ulong pixels = (ulong)desc.width * (ulong)desc.height;
if (pixels > PIXELS_MAX) return QOIError.TOO_MANY_PIXELS?;
uint pos = Header.sizeof; // Current position in data
uint loc; // Current position in image (top-left corner)
char run_length = 0; // Length of the current run
char tag; // Current chunk tag
Pixel[64] palette; // Zero-initialized by default
Pixel p = { 0, 0, 0, 255 };
if (channels == AUTO) channels = desc.channels;
// allocate memory for image data
usz image_size = (usz)pixels * channels.id;
char[] image = allocator::alloc_array(allocator, char, image_size);
defer catch allocator::free(allocator, image);
for (loc = 0; loc < image_size; loc += channels.id)
{
// get chunk tag
tag = data[pos];
// check for chunk type
switch
{
case run_length > 0:
run_length--;
case tag == OP_RGB:
OpRGB* op = @extract(OpRGB, data, &pos);
p = { op.red, op.green, op.blue, p.a };
palette[p.hash()] = p;
case tag == OP_RGBA:
OpRGBA* op = @extract(OpRGBA, data, &pos);
p = { op.red, op.green, op.blue, op.alpha };
palette[p.hash()] = p;
case tag >> 6 == OP_INDEX:
OpIndex* op = @extract(OpIndex, data, &pos);
p = palette[op.index];
case tag >> 6 == OP_DIFF:
OpDiff* op = @extract(OpDiff, data, &pos);
p.r += op.diff_red - 2;
p.g += op.diff_green - 2;
p.b += op.diff_blue - 2;
palette[p.hash()] = p;
case tag >> 6 == OP_LUMA:
OpLuma* op = @extract(OpLuma, data, &pos);
int diff_green = op.diff_green - 32;
p.r += (char)(op.diff_red_minus_green - 8 + diff_green);
p.g += (char)(diff_green);
p.b += (char)(op.diff_blue_minus_green - 8 + diff_green);
palette[p.hash()] = p;
case tag >> 6 == OP_RUN:
OpRun* op = @extract(OpRun, data, &pos);
run_length = op.run;
}
// draw the pixel
if (channels == RGBA) { image[loc:4] = p.rgba; } else { image[loc:3] = p.rgb; }
}
return image;
}
// ***************************************************************************
// *** ***
// *** Main functions are at the top to make the file more readable. ***
// *** From here on, helper functions and types are defined. ***
// *** ***
// ***************************************************************************
module std::compression::qoi @private;
// 8-bit opcodes
const OP_RGB = 0b11111110;
const OP_RGBA = 0b11111111;
// 2-bit opcodes
const OP_INDEX = 0b00;
const OP_DIFF = 0b01;
const OP_LUMA = 0b10;
const OP_RUN = 0b11;
struct Header @packed
{
uint be_magic; // magic bytes "qoif"
uint be_width; // image width in pixels (BE)
uint be_height; // image height in pixels (BE)
// informative fields
char channels; // 3 = RGB, 4 = RGB
char colorspace; // 0 = sRGB with linear alpha, 1 = all channels linear
}
const char[*] END_OF_STREAM = {0, 0, 0, 0, 0, 0, 0, 1};
// inefficient, but it's only run once at a time
macro @enumcast($Type, raw)
{
foreach (value : $Type.values) {
if (value.id == raw) return value;
}
return QOIError.INVALID_DATA?;
}
distinct Pixel = inline char[<4>];
macro char Pixel.hash(Pixel p) {
return (p.r * 3 + p.g * 5 + p.b * 7 + p.a * 11) % 64;
}
struct OpRGB // No need to use @packed here, the alignment is 1 anyways.
{
char tag;
char red;
char green;
char blue;
}
struct OpRGBA @packed
{
char tag;
char red;
char green;
char blue;
char alpha;
}
bitstruct OpIndex : char
{
char tag : 6..7;
char index : 0..5;
}
bitstruct OpDiff : char
{
char tag : 6..7;
char diff_red : 4..5;
char diff_green : 2..3;
char diff_blue : 0..1;
}
bitstruct OpLuma : ushort
{
char tag : 6..7;
char diff_green : 0..5;
char diff_red_minus_green : 12..15;
char diff_blue_minus_green : 8..11;
}
bitstruct OpRun : char
{
char tag : 6..7;
char run : 0..5;
}
// Macro used to locate chunks in data buffers.
// Can be used both for reading and writing.
macro @extract($Type, char[] data, uint* pos)
{
// slice data, then double cast
$Type* chunk = ($Type*)data[*pos : $Type.sizeof].ptr;
*pos += $Type.sizeof;
return chunk;
}

View File

@@ -24,7 +24,6 @@ fn void DynamicArenaAllocator.init(&self, usz page_size, Allocator allocator)
self.backing_allocator = allocator;
}
import std::io;
fn void DynamicArenaAllocator.free(&self)
{
DynamicArenaPage* page = self.page;

View File

@@ -3,15 +3,20 @@
// a copy of which can be found in the LICENSE_STDLIB file.
module std::core::mem::allocator @if(env::LIBC);
import std::io;
import libc;
const LibcAllocator LIBC_ALLOCATOR = {};
distinct LibcAllocator (Allocator) = uptr;
distinct LibcAllocator (Allocator, Printable) = uptr;
fn String LibcAllocator.to_string(&self, Allocator allocator) @dynamic => "Libc allocator".copy(allocator);
fn usz! LibcAllocator.to_format(&self, Formatter *format) @dynamic => format.print("Libc allocator");
module std::core::mem::allocator @if(env::POSIX);
import std::os;
import libc;
fn void*! LibcAllocator.acquire(&self, usz bytes, AllocInitType init_type, usz alignment) @dynamic
{
if (init_type == ZERO)

View File

@@ -68,6 +68,7 @@ fn void TempAllocator.reset(&self, usz mark) @dynamic
TempAllocatorPage *last_page = self.last_page;
while (last_page && last_page.mark > mark)
{
self.used = last_page.mark;
TempAllocatorPage *to_free = last_page;
last_page = last_page.prev_page;
self._free_page(to_free)!!;

View File

@@ -34,7 +34,7 @@ struct TrackingAllocator (Allocator)
fn void TrackingAllocator.init(&self, Allocator allocator)
{
*self = { .inner_allocator = allocator };
self.map.new_init(.allocator = allocator);
self.map.new_init(allocator: allocator);
}
/**

View File

@@ -55,7 +55,7 @@ macro rindex_of(array, element)
* @require @typeis(arr1[0], $typeof(arr2[0])) "Arrays must have the same type"
* @ensure result.len == arr1.len + arr2.len
**/
macro concat_new(arr1, arr2, Allocator allocator = allocator::heap())
macro concat(arr1, arr2, Allocator allocator) @nodiscard
{
var $Type = $typeof(arr1[0]);
$Type[] result = allocator::alloc_array(allocator, $Type, arr1.len + arr2.len);
@@ -69,6 +69,21 @@ macro concat_new(arr1, arr2, Allocator allocator = allocator::heap())
}
return result;
}
/**
* Concatenate two arrays or slices, returning a slice containing the concatenation of them.
*
* @param [in] arr1
* @param [in] arr2
* @param [&inout] allocator "The allocator to use, default is the heap allocator"
* @require @typekind(arr1) == SLICE || @typekind(arr1) == ARRAY
* @require @typekind(arr2) == SLICE || @typekind(arr2) == ARRAY
* @require @typeis(arr1[0], $typeof(arr2[0])) "Arrays must have the same type"
* @ensure result.len == arr1.len + arr2.len
**/
macro concat_new(arr1, arr2, Allocator allocator = allocator::heap()) @nodiscard
{
return concat(arr1, arr2, allocator);
}
/**
* Concatenate two arrays or slices, returning a slice containing the concatenation of them,
@@ -81,7 +96,7 @@ macro concat_new(arr1, arr2, Allocator allocator = allocator::heap())
* @require @typeis(arr1[0], $typeof(arr2[0])) "Arrays must have the same type"
* @ensure result.len == arr1.len + arr2.len
**/
macro tconcat(arr1, arr2) => concat(arr1, arr2, allocator::temp());
macro tconcat(arr1, arr2) @nodiscard => concat(arr1, arr2, allocator::temp());
module std::core::array::slice(<Type>);

View File

@@ -146,7 +146,7 @@ fn void panicf(String fmt, String file, String function, uint line, args...)
@stack_mem(512; Allocator allocator)
{
DString s;
s.new_init(.allocator = allocator);
s.new_init(allocator: allocator);
s.appendf(fmt, ...args);
in_panic = false;
panic(s.str_view(), file, function, line);

View File

@@ -154,13 +154,15 @@ fn String DString.str_view(self)
return (String)data.chars[:data.len];
}
fn void DString.append_utf32(&self, Char32[] chars)
fn usz DString.append_utf32(&self, Char32[] chars)
{
self.reserve(chars.len);
usz end = self.len();
foreach (Char32 c : chars)
{
self.append_char32(c);
}
return self.data().len - end;
}
/**
@@ -185,7 +187,7 @@ fn void DString.append_repeat(&self, char c, usz times)
/**
* @require c <= 0x10ffff
*/
fn void DString.append_char32(&self, Char32 c)
fn usz DString.append_char32(&self, Char32 c)
{
char[4] buffer @noinit;
char* p = &buffer;
@@ -194,6 +196,7 @@ fn void DString.append_char32(&self, Char32 c)
StringData* data = self.data();
data.chars[data.len:n] = buffer[:n];
data.len += n;
return n;
}
fn DString DString.tcopy(&self) => self.copy(allocator::temp());
@@ -387,7 +390,10 @@ macro void DString.append(&self, value)
$endswitch
}
fn void DString.insert_at(&self, usz index, String s)
/**
* @require index <= self.len()
**/
fn void DString.insert_chars_at(&self, usz index, String s)
{
if (s.len == 0) return;
self.reserve(s.len);
@@ -419,6 +425,103 @@ fn void DString.insert_at(&self, usz index, String s)
}
}
/**
* @require index <= self.len()
**/
fn void DString.insert_string_at(&self, usz index, DString str)
{
StringData* other = str.data();
if (!other) return;
self.insert_at(index, str.str_view());
}
/**
* @require index <= self.len()
**/
fn void DString.insert_char_at(&self, usz index, char c)
{
self.reserve(1);
StringData* data = self.data();
char* start = &data.chars[index];
mem::move(start + 1, start, self.len() - index);
data.chars[index] = c;
data.len++;
}
/**
* @require index <= self.len()
**/
fn usz DString.insert_char32_at(&self, usz index, Char32 c)
{
char[4] buffer @noinit;
char* p = &buffer;
usz n = conv::char32_to_utf8_unsafe(c, &p);
self.reserve(n);
StringData* data = self.data();
char* start = &data.chars[index];
mem::move(start + n, start, self.len() - index);
data.chars[index:n] = buffer[:n];
data.len += n;
return n;
}
/**
* @require index <= self.len()
**/
fn usz DString.insert_utf32_at(&self, usz index, Char32[] chars)
{
usz n = conv::utf8len_for_utf32(chars);
self.reserve(n);
StringData* data = self.data();
char* start = &data.chars[index];
mem::move(start + n, start, self.len() - index);
char[4] buffer @noinit;
foreach(c : chars)
{
char* p = &buffer;
usz m = conv::char32_to_utf8_unsafe(c, &p);
data.chars[index:m] = buffer[:m];
index += m;
}
data.len += n;
return n;
}
macro void DString.insert_at(&self, usz index, value)
{
var $Type = $typeof(value);
$switch ($Type)
$case char:
$case ichar:
self.insert_char_at(index, value);
$case DString:
self.insert_string_at(index, value);
$case String:
self.insert_chars_at(index, value);
$case Char32:
self.insert_char32_at(index, value);
$default:
$switch
$case $defined((Char32)value):
self.insert_char32_at(index, (Char32)value);
$case $defined((String)value):
self.insert_chars_at(index, (String)value);
$default:
$error "Unsupported type for insert";
$endswitch
$endswitch
}
fn usz! DString.appendf(&self, String format, args...) @maydiscard
{
if (!self.data()) self.new_init(format.len + 20);
@@ -467,6 +570,19 @@ fn void! out_string_append_fn(void* data, char c) @private
s.append_char(c);
}
fn void DString.reverse(self)
{
StringData *data = self.data();
if (!data) return;
isz mid = data.len / 2;
for (isz i = 0; i < mid; i++)
{
char temp = data.chars[i];
isz reverse_index = data.len - 1 - i;
data.chars[i] = data.chars[reverse_index];
data.chars[reverse_index] = temp;
}
}
fn StringData* DString.data(self) @inline @private
{

View File

@@ -115,6 +115,8 @@ enum ArchType
XTENSA, // Xtensa
}
const String COMPILER_BUILD_HASH = $$BUILD_HASH;
const String COMPILER_BUILD_DATE = $$BUILD_DATE;
const OsType OS_TYPE = (OsType)$$OS_TYPE;
const ArchType ARCH_TYPE = (ArchType)$$ARCH_TYPE;
const bool ARCH_32_BIT = $$REGISTER_SIZE == 32;
@@ -146,6 +148,7 @@ const bool POSIX = LIBC && os_is_posix();
const bool OPENBSD = LIBC && OS_TYPE == OPENBSD;
const bool FREEBSD = LIBC && OS_TYPE == FREEBSD;
const bool NETBSD = LIBC && OS_TYPE == NETBSD;
const bool BSD_FAMILY = env::FREEBSD || env::OPENBSD || env::NETBSD;
const bool WASI = LIBC && OS_TYPE == WASI;
const bool WASM_NOLIBC @builtin = !LIBC && ARCH_TYPE == ArchType.WASM32 || ARCH_TYPE == ArchType.WASM64;
const bool ADDRESS_SANITIZER = $$ADDRESS_SANITIZER;

View File

@@ -281,6 +281,11 @@ fn bool ptr_is_aligned(void* ptr, usz alignment) @inline
return (uptr)ptr & ((uptr)alignment - 1) == 0;
}
macro void zero_volatile(char[] data)
{
$$memset(data.ptr, (char)0, data.len, true, (usz)1);
}
macro void clear(void* dst, usz len, usz $dst_align = 0, bool $is_volatile = false, bool $inlined = false)
{
$$memset(dst, (char)0, len, $is_volatile, $dst_align);

View File

@@ -143,7 +143,7 @@ macro void free_aligned(Allocator allocator, void* ptr)
$if env::TESTING:
((char*)ptr)[0] = 0xBA;
$endif
allocator.release(ptr, .aligned = true);
allocator.release(ptr, aligned: true);
}
/**

View File

@@ -30,6 +30,7 @@ enum X86Feature
AMX_FP16,
AMX_INT8,
AMX_TILE,
APXF,
AVX,
AVX10_1_256,
AVX10_1_512,
@@ -156,6 +157,7 @@ fn void x86_initialize_cpu_features()
add_feature_if_bit(AMX_FP16, leaf7s1.eax, 21);
add_feature_if_bit(AMX_INT8, leaf7.edx, 25);
add_feature_if_bit(AMX_TILE, leaf7.edx, 24);
add_feature_if_bit(APXF, leaf7s1.edx, 21);
add_feature_if_bit(AVX, feat.ecx, 28);
add_feature_if_bit(AVX10_1_256, leaf7s1.edx, 19);
add_feature_if_bit(AVX10_1_512, leaf_24.ebx, 18);
@@ -255,4 +257,4 @@ fn void x86_initialize_cpu_features()
add_feature_if_bit(XSAVEOPT, leaf_d.eax, 0);
add_feature_if_bit(XSAVES, leaf_d.eax, 3);
}
}

View File

@@ -4,6 +4,12 @@
module std::core::runtime;
import libc, std::time, std::io, std::sort;
struct ReflectedParam @if(!$defined(ReflectedParam))
{
String name;
typeid type;
}
struct AnyRaw
{
void* ptr;
@@ -215,6 +221,7 @@ fn bool run_tests(TestUnit[] tests)
name.appendf("Testing %s ", unit.name);
name.append_repeat('.', max_name - unit.name.len + 2);
io::printf("%s ", name.str_view());
(void)io::stdout().flush();
if (libc::setjmp(&context.buf) == 0)
{
if (catch err = unit.func())

View File

@@ -38,10 +38,10 @@ fault NumberConversion
*
* @param [in] fmt `The formatting string`
**/
macro ZString tformat_zstr(String fmt, ...)
fn ZString tformat_zstr(String fmt, args...)
{
DString str = dstring::temp_with_capacity(fmt.len + $vacount * 8);
str.appendf(fmt, $vasplat);
DString str = dstring::temp_with_capacity(fmt.len + args.len * 8);
str.appendf(fmt, ...args);
return str.zstr_view();
}
@@ -51,12 +51,12 @@ macro ZString tformat_zstr(String fmt, ...)
* @param [inout] allocator `The allocator to use`
* @param [in] fmt `The formatting string`
**/
macro String format(String fmt, ..., Allocator allocator)
fn String format(String fmt, args..., Allocator allocator)
{
@pool(allocator)
{
DString str = dstring::temp_with_capacity(fmt.len + $vacount * 8);
str.appendf(fmt, $vasplat);
DString str = dstring::temp_with_capacity(fmt.len + args.len * 8);
str.appendf(fmt, ...args);
return str.copy_str(allocator);
};
}
@@ -66,17 +66,17 @@ macro String format(String fmt, ..., Allocator allocator)
*
* @param [in] fmt `The formatting string`
**/
macro String new_format(String fmt, ..., Allocator allocator = null) => format(fmt, $vasplat, .allocator = allocator ?: allocator::heap());
fn String new_format(String fmt, args..., Allocator allocator = null) => format(fmt, ...args, allocator: allocator ?: allocator::heap());
/**
* Return a temporary String created using the formatting function.
*
* @param [in] fmt `The formatting string`
**/
macro String tformat(String fmt, ...)
fn String tformat(String fmt, args...)
{
DString str = dstring::temp_with_capacity(fmt.len + $vacount * 8);
str.appendf(fmt, $vasplat);
DString str = dstring::temp_with_capacity(fmt.len + args.len * 8);
str.appendf(fmt, ...args);
return str.str_view();
}
@@ -86,12 +86,12 @@ macro String tformat(String fmt, ...)
* @param [in] fmt `The formatting string`
* @param [inout] allocator `The allocator to use`
**/
macro ZString new_format_zstr(String fmt, ..., Allocator allocator = allocator::heap())
fn ZString new_format_zstr(String fmt, args..., Allocator allocator = allocator::heap())
{
@pool(allocator)
{
DString str = dstring::temp_with_capacity(fmt.len + $vacount * 8);
str.appendf(fmt, $vasplat);
DString str = dstring::temp_with_capacity(fmt.len + args.len * 8);
str.appendf(fmt, ...args);
return str.copy_zstr(allocator);
};
}
@@ -540,7 +540,7 @@ fn String String.new_ascii_to_lower(s, Allocator allocator = allocator::heap())
return copy;
}
fn String String.temp_ascii_to_lower(s, Allocator allocator = allocator::heap())
fn String String.temp_ascii_to_lower(s)
{
return s.new_ascii_to_lower(allocator::temp());
}

View File

@@ -1,2 +1,12 @@
module std::crypto;
fn bool safe_compare(void* data1, void* data2, usz len)
{
char match = 0;
for (usz i = 0; i < len; i++)
{
match = match | (mem::@volatile_load(((char*)data1)[i]) ^ mem::@volatile_load(((char*)data2)[i]));
}
return match == 0;
}

12
lib/std/crypto/dh.c3 Normal file
View File

@@ -0,0 +1,12 @@
module std::crypto::dh;
import std::math::bigint;
fn BigInt generate_secret(BigInt p, BigInt x, BigInt y)
{
return y.mod_pow(x, p);
}
fn BigInt public_key(BigInt p, BigInt g, BigInt x)
{
return g.mod_pow(x, p);
}

View File

@@ -22,7 +22,7 @@ fn String[]! CsvReader.read_new_row_with_allocator(self, Allocator allocator = a
{
@pool(allocator)
{
return io::treadline(self.stream).split(self.separator, .allocator = allocator);
return io::treadline(self.stream).split(self.separator, allocator: allocator);
};
}
@@ -56,7 +56,7 @@ macro CsvReader.@each_row(self, int rows = int.max; @body(String[] row))
if (err == IoError.EOF) return;
return err?;
}
parts = s.split(sep, .allocator = mem);
parts = s.split(sep, allocator: mem);
};
@body(parts);
};

View File

@@ -106,7 +106,7 @@ fn JsonTokenType! lex_number(JsonContext *context, char c) @local
{
@stack_mem(256; Allocator mem)
{
DString t = dstring::new_with_capacity(32, .allocator = mem);
DString t = dstring::new_with_capacity(32, allocator: mem);
bool negate = c == '-';
if (negate)
{
@@ -386,6 +386,7 @@ fn JsonTokenType! lex_string(JsonContext* context)
default:
return JsonParsingError.INVALID_ESCAPE_SEQUENCE?;
}
context.last_string.append(c);
}
return STRING;
}

107
lib/std/hash/hmac.c3 Normal file
View File

@@ -0,0 +1,107 @@
module std::hash::hmac(<HashAlg, HASH_BYTES, BLOCK_BYTES>);
import std::crypto;
struct Hmac
{
HashAlg a, b;
}
fn char[HASH_BYTES] hash(char[] key, char[] message)
{
Hmac hmac @noinit;
hmac.init(key);
hmac.update(message);
return hmac.final();
}
/**
* @require output.len > 0 "Output must be greater than zero"
* @require output.len < int.max / HASH_BYTES "Output is too large"
**/
fn void pbkdf2(char[] pw, char[] salt, uint iterations, char[] output)
{
usz l = output.len / HASH_BYTES;
usz r = output.len % HASH_BYTES;
Hmac hmac;
hmac.init(pw);
char[] dst_curr = output;
for (usz i = 1; i <= l; i++)
{
@derive(&hmac, salt, iterations, i, dst_curr[:HASH_BYTES]);
dst_curr = dst_curr[HASH_BYTES..];
}
if (r > 0)
{
char[HASH_BYTES] tmp;
@derive(&hmac, salt, iterations, l + 1, &tmp);
dst_curr[..] = tmp[:dst_curr.len];
mem::zero_volatile(&tmp);
}
}
fn void Hmac.init(&self, char[] key)
{
char[BLOCK_BYTES] buffer;
if (key.len > BLOCK_BYTES)
{
self.a.init();
self.a.update(key);
buffer[:HASH_BYTES] = self.a.final()[..];
}
else
{
buffer[:key.len] = key[..];
}
foreach (&b : buffer) *b ^= IPAD;
self.a.init();
self.a.update(&buffer);
foreach (&b : buffer) *b ^= IPAD ^ OPAD;
self.b.init();
self.b.update(&buffer);
mem::zero_volatile(&buffer);
}
fn void Hmac.update(&self, char[] data)
{
self.a.update(data);
}
fn char[HASH_BYTES] Hmac.final(&self)
{
self.b.update(&&self.a.final());
return self.b.final();
}
const IPAD @private = 0x36;
const OPAD @private = 0x5C;
macro @derive(Hmac *hmac_start, char[] salt, uint iterations, usz index, char[] out)
{
assert(out.len == HASH_BYTES);
char[HASH_BYTES] tmp @noinit;
defer mem::zero_volatile(&tmp);
Hmac hmac = *hmac_start;
hmac.update(salt);
UIntBE be = { (uint)index };
hmac.update(&&bitcast(be, char[4]));
tmp = hmac.final();
out[..] = tmp;
for (int it = 1; it < iterations; it++)
{
hmac = *hmac_start;
hmac.update(&tmp);
tmp = hmac.final();
foreach (i, v : tmp)
{
out[i] ^= v;
}
}
}

225
lib/std/hash/md5.c3 Normal file
View File

@@ -0,0 +1,225 @@
module std::hash::md5;
import std::hash::hmac;
import std::bits;
const BLOCK_BYTES = 64;
const HASH_BYTES = 16;
struct Md5
{
uint lo, hi;
uint a, b, c, d;
char[64] buffer;
uint[16] block;
}
def HmacMd5 = Hmac(<Md5, HASH_BYTES, BLOCK_BYTES>);
def hmac = hmac::hash(<Md5, HASH_BYTES, BLOCK_BYTES>);
def pbkdf2 = hmac::pbkdf2(<Md5, HASH_BYTES, BLOCK_BYTES>);
fn char[HASH_BYTES] hash(char[] data)
{
Md5 md5;
md5.init();
md5.update(data);
return md5.final();
}
fn void Md5.init(&self)
{
self.a = 0x67452301;
self.b = 0xefcdab89;
self.c = 0x98badcfe;
self.d = 0x10325476;
self.lo = 0;
self.hi = 0;
}
fn void Md5.update(&ctx, char[] data)
{
uint saved_lo = ctx.lo;
if ((ctx.lo = (saved_lo + data.len) & 0x1fffffff) < saved_lo) ctx.hi++;
ctx.hi += data.len >> 29;
usz used = (usz)saved_lo & 0x3f;
if (used)
{
usz available = 64 - used;
if (data.len < available)
{
ctx.buffer[used:data.len] = data[..];
return;
}
ctx.buffer[used:available] = data[:available];
data = data[available..];
body(ctx, &ctx.buffer, 64);
}
if (data.len >= 64)
{
data = body(ctx, data, data.len & ~(usz)0x3f)[:data.len & 0x3f];
}
ctx.buffer[:data.len] = data[..];
}
fn char[HASH_BYTES] Md5.final(&ctx)
{
usz used = (usz)ctx.lo & 0x3f;
ctx.buffer[used++] = 0x80;
usz available = 64 - used;
if (available < 8)
{
ctx.buffer[used:available] = 0;
body(ctx, &ctx.buffer, 64);
used = 0;
available = 64;
}
ctx.buffer[used:available - 8] = 0;
ctx.lo <<= 3;
ctx.buffer[56:4] = bitcast(ctx.lo, char[4])[..];
ctx.buffer[60:4] = bitcast(ctx.hi, char[4])[..];
body(ctx, &ctx.buffer, 64);
char[16] res @noinit;
res[0:4] = bitcast(ctx.a, char[4]);
res[4:4] = bitcast(ctx.b, char[4]);
res[8:4] = bitcast(ctx.c, char[4]);
res[12:4] = bitcast(ctx.d, char[4]);
*ctx = {};
return res;
}
module std::hash::md5 @private;
// Implementation
macro @f(x, y, z) => z ^ (x & (y ^ z));
macro @g(x, y, z) => y ^ (z & (x ^ y));
macro @h(x, y, z) => (x ^ y) ^ z;
macro @h2(x, y, z) => x ^ (y ^ z);
macro @i(x, y, z) => y ^ (x | ~z);
macro @step(#f, &a, b, c, d, ptr, n, t, s)
{
*a += #f(b, c, d) + *(uint *)&ptr[n * 4] + t;
*a = (*a << s) | ((*a & 0xffffffff) >> (32 - s));
*a += b;
}
fn char* body(Md5* ctx, void* data, usz size)
{
char* ptr;
uint a, b, c, d;
uint saved_a, saved_b, saved_c, saved_d;
ptr = data;
a = ctx.a;
b = ctx.b;
c = ctx.c;
d = ctx.d;
do
{
saved_a = a;
saved_b = b;
saved_c = c;
saved_d = d;
/* Round 1 */
@step(@f, a, b, c, d, ptr, 0, 0xd76aa478, 7) ;
@step(@f, d, a, b, c, ptr, 1, 0xe8c7b756, 12) ;
@step(@f, c, d, a, b, ptr, 2, 0x242070db, 17) ;
@step(@f, b, c, d, a, ptr, 3, 0xc1bdceee, 22) ;
@step(@f, a, b, c, d, ptr, 4, 0xf57c0faf, 7) ;
@step(@f, d, a, b, c, ptr, 5, 0x4787c62a, 12) ;
@step(@f, c, d, a, b, ptr, 6, 0xa8304613, 17) ;
@step(@f, b, c, d, a, ptr, 7, 0xfd469501, 22) ;
@step(@f, a, b, c, d, ptr, 8, 0x698098d8, 7) ;
@step(@f, d, a, b, c, ptr, 9, 0x8b44f7af, 12) ;
@step(@f, c, d, a, b, ptr, 10, 0xffff5bb1, 17);
@step(@f, b, c, d, a, ptr, 11, 0x895cd7be, 22);
@step(@f, a, b, c, d, ptr, 12, 0x6b901122, 7) ;
@step(@f, d, a, b, c, ptr, 13, 0xfd987193, 12);
@step(@f, c, d, a, b, ptr, 14, 0xa679438e, 17);
@step(@f, b, c, d, a, ptr, 15, 0x49b40821, 22);
/* Round 2 */
@step(@g, a, b, c, d, ptr, 1, 0xf61e2562, 5) ;
@step(@g, d, a, b, c, ptr, 6, 0xc040b340, 9) ;
@step(@g, c, d, a, b, ptr, 11, 0x265e5a51, 14);
@step(@g, b, c, d, a, ptr, 0, 0xe9b6c7aa, 20) ;
@step(@g, a, b, c, d, ptr, 5, 0xd62f105d, 5) ;
@step(@g, d, a, b, c, ptr, 10, 0x02441453, 9) ;
@step(@g, c, d, a, b, ptr, 15, 0xd8a1e681, 14);
@step(@g, b, c, d, a, ptr, 4, 0xe7d3fbc8, 20) ;
@step(@g, a, b, c, d, ptr, 9, 0x21e1cde6, 5) ;
@step(@g, d, a, b, c, ptr, 14, 0xc33707d6, 9) ;
@step(@g, c, d, a, b, ptr, 3, 0xf4d50d87, 14) ;
@step(@g, b, c, d, a, ptr, 8, 0x455a14ed, 20) ;
@step(@g, a, b, c, d, ptr, 13, 0xa9e3e905, 5) ;
@step(@g, d, a, b, c, ptr, 2, 0xfcefa3f8, 9) ;
@step(@g, c, d, a, b, ptr, 7, 0x676f02d9, 14) ;
@step(@g, b, c, d, a, ptr, 12, 0x8d2a4c8a, 20);
/* Round 3 */
@step(@h, a, b, c, d, ptr, 5, 0xfffa3942, 4);
@step(@h2, d, a, b, c, ptr, 8, 0x8771f681, 11);
@step(@h, c, d, a, b, ptr, 11, 0x6d9d6122, 16);
@step(@h2, b, c, d, a, ptr, 14, 0xfde5380c, 23);
@step(@h, a, b, c, d, ptr, 1, 0xa4beea44, 4);
@step(@h2, d, a, b, c, ptr, 4, 0x4bdecfa9, 11);
@step(@h, c, d, a, b, ptr, 7, 0xf6bb4b60, 16);
@step(@h2, b, c, d, a, ptr, 10, 0xbebfbc70, 23);
@step(@h, a, b, c, d, ptr, 13, 0x289b7ec6, 4) ;
@step(@h2, d, a, b, c, ptr, 0, 0xeaa127fa, 11) ;
@step(@h, c, d, a, b, ptr, 3, 0xd4ef3085, 16) ;
@step(@h2, b, c, d, a, ptr, 6, 0x04881d05, 23) ;
@step(@h, a, b, c, d, ptr, 9, 0xd9d4d039, 4) ;
@step(@h2, d, a, b, c, ptr, 12, 0xe6db99e5, 11) ;
@step(@h, c, d, a, b, ptr, 15, 0x1fa27cf8, 16) ;
@step(@h2, b, c, d, a, ptr, 2, 0xc4ac5665, 23) ;
/* Round 4 */
@step(@i, a, b, c, d, ptr, 0, 0xf4292244, 6) ;
@step(@i, d, a, b, c, ptr, 7, 0x432aff97, 10) ;
@step(@i, c, d, a, b, ptr, 14, 0xab9423a7, 15) ;
@step(@i, b, c, d, a, ptr, 5, 0xfc93a039, 21) ;
@step(@i, a, b, c, d, ptr, 12, 0x655b59c3, 6) ;
@step(@i, d, a, b, c, ptr, 3, 0x8f0ccc92, 10) ;
@step(@i, c, d, a, b, ptr, 10, 0xffeff47d, 15) ;
@step(@i, b, c, d, a, ptr, 1, 0x85845dd1, 21) ;
@step(@i, a, b, c, d, ptr, 8, 0x6fa87e4f, 6) ;
@step(@i, d, a, b, c, ptr, 15, 0xfe2ce6e0, 10) ;
@step(@i, c, d, a, b, ptr, 6, 0xa3014314, 15) ;
@step(@i, b, c, d, a, ptr, 13, 0x4e0811a1, 21) ;
@step(@i, a, b, c, d, ptr, 4, 0xf7537e82, 6) ;
@step(@i, d, a, b, c, ptr, 11, 0xbd3af235, 10) ;
@step(@i, c, d, a, b, ptr, 2, 0x2ad7d2bb, 15) ;
@step(@i, b, c, d, a, ptr, 9, 0xeb86d391, 21) ;
a += saved_a;
b += saved_b;
c += saved_c;
d += saved_d;
ptr += 64;
} while (size -= 64);
ctx.a = a;
ctx.b = b;
ctx.c = c;
ctx.d = d;
return ptr;
}

View File

@@ -5,13 +5,29 @@
// Implementation was off Steve Reid's SHA-1 C implementation
module std::hash::sha1;
import std::hash::hmac;
import std::bits;
const BLOCK_BYTES = 64;
const HASH_BYTES = 20;
struct Sha1
{
uint[5] state;
uint[2] count;
char[64] buffer;
char[BLOCK_BYTES] buffer;
}
def HmacSha1 = Hmac(<Sha1, HASH_BYTES, BLOCK_BYTES>);
def hmac = hmac::hash(<Sha1, HASH_BYTES, BLOCK_BYTES>);
def pbkdf2 = hmac::pbkdf2(<Sha1, HASH_BYTES, BLOCK_BYTES>);
fn char[HASH_BYTES] hash(char[] data)
{
Sha1 sha1 @noinit;
sha1.init();
sha1.update(data);
return sha1.final();
}
fn void Sha1.init(&self)
@@ -55,7 +71,7 @@ fn void Sha1.update(&self, char[] data)
}
fn char[20] Sha1.final(&self)
fn char[HASH_BYTES] Sha1.final(&self)
{
char[8] finalcount;
for (uint i = 0; i < 8; i++)
@@ -69,21 +85,21 @@ fn char[20] Sha1.final(&self)
}
self.update(&finalcount);
char[20] digest;
for (uint i = 0; i < 20; i++)
char[HASH_BYTES] digest;
for (uint i = 0; i < HASH_BYTES; i++)
{
digest[i] = (char)((self.state[i >> 2] >> ((3 - (i & 3)) * 8)) & 0xFF);
}
// Clear mem
mem::clear(self, Sha1.sizeof);
*self = {};
finalcount = {};
return digest;
}
union Long16 @local
{
char[64] c;
char[BLOCK_BYTES] c;
uint[16] l;
}

176
lib/std/hash/sha256.c3 Normal file
View File

@@ -0,0 +1,176 @@
module std::hash::sha256;
import std::hash::hmac;
const BLOCK_SIZE = 64;
const HASH_SIZE = 32;
const uint[64] K @local = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
// Right rotate function
macro uint @rotr(uint x, uint n) @local => (((x) >> (n)) | ((x) << (32 - (n))));
// SHA-256 functions
macro uint @ch(uint x, uint y, uint z) @local => (x & y) ^ (~x & z);
macro uint @maj(uint x, uint y, uint z) @local => (x & y) ^ (x & z) ^ (y & z);
macro uint @_sigma0(uint x) @local => @rotr(x, 2) ^ @rotr(x, 13) ^ @rotr(x, 22);
macro uint @_sigma1(uint x) @local => @rotr(x, 6) ^ @rotr(x, 11) ^ @rotr(x, 25);
macro uint @sigma0(uint x) @local => @rotr(x, 7) ^ @rotr(x, 18) ^ (x >> 3);
macro uint @sigma1(uint x) @local => @rotr(x, 17) ^ @rotr(x, 19) ^ (x >> 10);
struct Sha256
{
uint[8] state;
ulong bitcount;
char[BLOCK_SIZE] buffer;
}
def HmacSha256 = Hmac(<Sha256, HASH_SIZE, BLOCK_SIZE>);
def hmac = hmac::hash(<Sha256, HASH_SIZE, BLOCK_SIZE>);
def pbkdf2 = hmac::pbkdf2(<Sha256, HASH_SIZE, BLOCK_SIZE>);
fn char[HASH_SIZE] hash(char[] data)
{
Sha256 sha256 @noinit;
sha256.init();
sha256.update(data);
return sha256.final();
}
fn void Sha256.init(&self)
{
// Sha256 initialization constants
*self = {
.state = {
0x6A09E667,
0xBB67AE85,
0x3C6EF372,
0xA54FF53A,
0x510E527F,
0x9B05688C,
0x1F83D9AB,
0x5BE0CD19
}
};
}
/**
* @param [in] data
* @require data.len <= uint.max
**/
fn void Sha256.update(&self, char[] data) {
uint i = 0;
uint len = data.len;
uint buffer_pos = (uint)(self.bitcount / 8) % BLOCK_SIZE;
self.bitcount += (ulong)(len * 8);
while (len--) {
self.buffer[buffer_pos++] = data[i++];
if (buffer_pos == BLOCK_SIZE) {
sha256_transform(&self.state, &self.buffer);
buffer_pos = 0; // Reset buffer position
}
}
}
fn char[HASH_SIZE] Sha256.final(&self) {
char[HASH_SIZE] hash;
ulong i = (self.bitcount / 8) % BLOCK_SIZE;
// Append 0x80 to the buffer
self.buffer[i++] = 0x80;
// Pad the buffer with zeros
if (i > BLOCK_SIZE - 8) {
while (i < BLOCK_SIZE) {
self.buffer[i++] = 0x00;
}
sha256_transform(&self.state, &self.buffer);
i = 0; // Reset buffer index after transformation
}
while (i < BLOCK_SIZE - 8) {
self.buffer[i++] = 0x00;
}
// Append the bitcount in big-endian format
for (int j = 0; j < 8; ++j) {
self.buffer[BLOCK_SIZE - 8 + j] = (char)((self.bitcount >> (56 - j * 8)) & 0xFF);
}
sha256_transform(&self.state, &self.buffer);
// Convert state to the final hash
for (i = 0; i < 8; ++i) {
hash[i * 4] = (char)((self.state[i] >> 24) & 0xFF);
hash[i * 4 + 1] = (char)((self.state[i] >> 16) & 0xFF);
hash[i * 4 + 2] = (char)((self.state[i] >> 8) & 0xFF);
hash[i * 4 + 3] = (char)(self.state[i] & 0xFF);
}
return hash;
}
/**
* @param [&inout] state
* @param [&in] buffer
**/
fn void sha256_transform(uint* state, char* buffer) @local {
uint a, b, c, d, e, f, g, h, t1, t2;
uint[64] m;
int i;
// Prepare the message schedule
for (i = 0; i < 16; ++i) {
m[i] = ((uint)buffer[i * 4] << 24) | ((uint)buffer[i * 4 + 1] << 16) |
((uint)buffer[i * 4 + 2] << 8) | ((uint)buffer[i * 4 + 3]); // Ensure values are cast to uint for correct shifts
}
for (i = 16; i < 64; ++i) {
m[i] = @sigma1(m[i - 2]) + m[i - 7] + @sigma0(m[i - 15]) + m[i - 16];
}
// Initialize working variables
a = state[0];
b = state[1];
c = state[2];
d = state[3];
e = state[4];
f = state[5];
g = state[6];
h = state[7];
// Perform the main SHA-256 compression function
for (i = 0; i < 64; ++i) {
t1 = h + @_sigma1(e) + @ch(e, f, g) + K[i] + m[i];
t2 = @_sigma0(a) + @maj(a, b, c);
h = g;
g = f;
f = e;
e = d + t1;
d = c;
c = b;
b = a;
a = t1 + t2;
}
// Update the state
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
state[4] += e;
state[5] += f;
state[6] += g;
state[7] += h;
a = b = c = d = e = f = g = h = t1 = t2 = i = 0;
m[:64] = buffer[:64] = 0;
}

View File

@@ -76,7 +76,7 @@ fn void! File.memopen(File* file, char[] data, String mode)
*/
fn void! File.write_byte(&self, char c) @dynamic
{
if (!libc::fputc(c, self.file)) return IoError.EOF?;
return os::native_fputc(c, self.file);
}
/**

View File

@@ -117,6 +117,7 @@ fn usz! Formatter.out_str(&self, any arg) @private
case ANYFAULT:
case FAULT:
return self.out_substr((*(anyfault*)arg.ptr).nameof);
case INTERFACE:
case ANY:
return self.out_str(*(any*)arg);
case OPTIONAL:
@@ -158,6 +159,12 @@ fn usz! Formatter.out_str(&self, any arg) @private
assert(i < arg.type.names.len, "Illegal enum value found, numerical value was %d.", i);
return self.out_substr(arg.type.names[i]);
case STRUCT:
if (arg.type == ReflectedParam.typeid)
{
ReflectedParam* param = arg.ptr;
return self.out_substr("[Parameter '")
+ self.out_substr(param.name) + self.out_substr("']");
}
return self.out_substr("<struct>");
case UNION:
return self.out_substr("<union>");
@@ -276,6 +283,9 @@ fn usz! Formatter.out_str(&self, any arg) @private
}
len += self.out(']')!;
return len;
case ANY:
case INTERFACE:
unreachable("Already handled");
default:
}
return self.out_substr("Invalid type");

View File

@@ -401,3 +401,11 @@ fn File* stdin()
{
return &stdin_file;
}
/**
* Wrap bytes for reading using io functions.
**/
fn ByteReader wrap_bytes(char[] bytes)
{
return { bytes, 0 };
}

View File

@@ -75,6 +75,11 @@ fn usz! native_fwrite(CFile file, char[] buffer) @inline
return libc::fwrite(buffer.ptr, 1, buffer.len, file);
}
fn void! native_fputc(CInt c, CFile stream) @inline
{
if (!libc::fputc(c, stream)) return IoError.EOF?;
}
fn usz! native_fread(CFile file, char[] buffer) @inline
{
return libc::fread(buffer.ptr, 1, buffer.len, file);

View File

@@ -9,6 +9,7 @@ def FtellFn = fn usz!(void*);
def FwriteFn = fn usz!(void*, char[] buffer);
def FreadFn = fn usz!(void*, char[] buffer);
def RemoveFn = fn void!(String);
def FputcFn = fn void!(int, void*);
FopenFn native_fopen_fn @weak @if(!$defined(native_fopen_fn));
FcloseFn native_fclose_fn @weak @if(!$defined(native_fclose_fn));
@@ -18,6 +19,7 @@ FtellFn native_ftell_fn @weak @if(!$defined(native_ftell_fn));
FwriteFn native_fwrite_fn @weak @if(!$defined(native_fwrite_fn));
FreadFn native_fread_fn @weak @if(!$defined(native_fread_fn));
RemoveFn native_remove_fn @weak @if(!$defined(native_remove_fn));
FputcFn native_fputc_fn @weak @if(!$defined(native_fputc_fn));
/**
* @require mode.len > 0
@@ -73,3 +75,9 @@ fn usz! native_fread(CFile file, char[] buffer) @inline
if (native_fread_fn) return native_fread_fn(file, buffer);
return IoError.UNSUPPORTED_OPERATION?;
}
fn void! native_fputc(CInt c, CFile stream) @inline
{
if (native_fputc_fn) return native_fputc_fn(c, stream);
return IoError.UNSUPPORTED_OPERATION?;
}

View File

@@ -1,11 +1,11 @@
module std::io::os;
import libc, std::os, std::io;
fn void! native_stat(Stat* stat, String path) @if(env::DARWIN || env::LINUX)
fn void! native_stat(Stat* stat, String path) @if(env::DARWIN || env::LINUX || env::BSD_FAMILY)
{
@pool()
{
$if env::DARWIN || env::LINUX:
$if env::DARWIN || env::LINUX || env::BSD_FAMILY:
int res = libc::stat(path.zstr_tcopy(), stat);
$else
unreachable("Stat unimplemented");
@@ -71,6 +71,9 @@ fn bool native_file_or_dir_exists(String path)
{
$switch
$case env::DARWIN:
$case env::FREEBSD:
$case env::NETBSD:
$case env::OPENBSD:
$case env::LINUX:
Stat stat;
return @ok(native_stat(&stat, path));
@@ -93,6 +96,9 @@ fn bool native_is_file(String path)
{
$switch
$case env::DARWIN:
$case env::FREEBSD:
$case env::NETBSD:
$case env::OPENBSD:
$case env::LINUX:
Stat stat;
return @ok(native_stat(&stat, path)) && libc_S_ISTYPE(stat.st_mode, libc::S_IFREG);
@@ -105,7 +111,7 @@ fn bool native_is_file(String path)
fn bool native_is_dir(String path)
{
$if env::DARWIN || env::LINUX:
$if env::DARWIN || env::LINUX || env::BSD_FAMILY:
Stat stat;
return @ok(native_stat(&stat, path)) && libc_S_ISTYPE(stat.st_mode, libc::S_IFDIR);
$else

View File

@@ -4,7 +4,7 @@ import std::io, std::os;
fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Allocator allocator)
{
PathList list;
list.new_init(.allocator = allocator);
list.new_init(allocator: allocator);
DIRPtr directory = posix::opendir(dir.str_view() ? dir.as_zstr() : (ZString)".");
defer if (directory) posix::closedir(directory);
if (!directory) return (path::is_dir(dir) ? IoError.CANNOT_READ_DIR : IoError.FILE_NOT_DIR)?;
@@ -27,7 +27,7 @@ import std::time, std::os, std::io;
fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Allocator allocator)
{
PathList list;
list.new_init(.allocator = allocator);
list.new_init(allocator: allocator);
@pool(allocator)
{

View File

@@ -141,7 +141,7 @@ fn Path! new_win32_wstring(WString path, Allocator allocator = allocator::heap()
{
@pool(allocator)
{
return path::new(string::temp_from_wstring(path)!, .allocator = allocator);
return path::new(string::temp_from_wstring(path)!, allocator: allocator);
};
}
@@ -520,7 +520,7 @@ fn bool! Path.walk(self, PathWalker w, void* data)
@stack_mem(PATH_MAX; Allocator allocator)
{
Path abs = self.new_absolute(allocator)!;
PathList files = new_ls(abs, .allocator = allocator)!;
PathList files = new_ls(abs, allocator: allocator)!;
foreach (f : files)
{
if (f.str_view() == "." || f.str_view() == "..") continue;

View File

@@ -77,6 +77,22 @@ macro usz! read_all(stream, char[] buffer)
return n;
}
/**
* @require @is_instream(stream)
*/
macro char[]! read_new_fully(stream, Allocator allocator = allocator::heap())
{
usz len = available(stream)!;
char* data = allocator::malloc_try(allocator, len)!;
defer catch allocator::free(allocator, data);
usz read = 0;
while (read < len)
{
read += stream.read(data[read:len - read])!;
}
return data[:len];
}
/**
* @require @is_outstream(stream)
*/

View File

@@ -131,7 +131,7 @@ fn usz! ByteBuffer.available(&self) @inline @dynamic
fn void! ByteBuffer.grow(&self, usz n)
{
n = math::next_power_of_2(n);
char* p = allocator::realloc_aligned(self.allocator, self.bytes, n, .alignment = char.alignof)!;
char* p = allocator::realloc_aligned(self.allocator, self.bytes, n, alignment: char.alignof)!;
self.bytes = p[:n];
}

View File

@@ -3,7 +3,6 @@
// a copy of which can be found in the LICENSE_STDLIB file.
module libc;
// Constants need to be per os/arch
const int EXIT_FAILURE = 1;
const int EXIT_SUCCESS = 0;
@@ -59,7 +58,7 @@ const CInt SIGTSTP = BSD_FLAVOR_SIG ? 18 : 20;
const CInt SIGCONT = BSD_FLAVOR_SIG ? 19 : 18;
const CInt SIGCHLD = BSD_FLAVOR_SIG ? 20 : 17;
const bool BSD_FLAVOR_SIG @local = env::OPENBSD || env::DARWIN || env::FREEBSD || env::NETBSD;
const bool BSD_FLAVOR_SIG @local = env::DARWIN || env::BSD_FAMILY;
def Time_t = $typefrom(env::WIN32 ? long.typeid : CLong.typeid);
def Off_t = $typefrom(env::WIN32 ? int.typeid : usz.typeid);
@@ -119,7 +118,7 @@ extern fn CLong labs(CLong x);
extern fn LongDivResult ldiv(CLong number, CLong denom);
extern fn Tm* localtime(Time_t* timer);
extern fn Tm* localtime_r(Time_t* timer, Tm* result) @if(!env::WIN32);
extern fn void longjmp(JmpBuf* buffer, CInt value);
extern fn void longjmp(JmpBuf* buffer, CInt value) @if(!env::NETBSD && !env::OPENBSD);
extern fn void* malloc(usz size);
extern fn void* memchr(void* str, CInt c, usz n);
extern fn CInt memcmp(void* buf1, void* buf2, usz count);
@@ -143,7 +142,7 @@ extern fn void rewind(CFile stream);
extern fn CInt scanf(ZString format, ...);
extern fn void setbuf(CFile stream, char* buffer);
extern fn int setenv(ZString name, ZString value, CInt overwrite);
extern fn CInt setjmp(JmpBuf* buffer) @if(!env::WIN32);
extern fn CInt setjmp(JmpBuf* buffer) @if(!env::WIN32 && !env::NETBSD && !env::OPENBSD);
extern fn void setvbuf(CFile stream, char* buf, CInt type, usz size);
extern fn SignalFunction signal(CInt sig, SignalFunction function);
extern fn CInt snprintf(char* buffer, usz size, ZString format, ...);
@@ -203,23 +202,39 @@ macro CFile stdin() => __stdin;
macro CFile stdout() => __stdout;
macro CFile stderr() => __stderr;
module libc @if(env::DARWIN);
module libc @if(env::NETBSD || env::OPENBSD);
extern fn int fcntl(CInt socket, int cmd, ...);
extern fn int _setjmp(void*);
macro int setjmp(void* ptr) => _setjmp(ptr);
extern fn int _longjmp(void*, int);
macro usz longjmp(void* ptr, CInt i) => _longjmp(ptr, i);
extern fn usz malloc_size(void* ptr);
extern fn void* aligned_alloc(usz align, usz size);
macro CFile stdin() { return fdopen(0, "r"); }
macro CFile stdout() { return fdopen(1, "w"); }
macro CFile stderr() { return fdopen(2, "w"); }
module libc @if(env::DARWIN || env::FREEBSD);
extern CFile __stdinp;
extern CFile __stdoutp;
extern CFile __stderrp;
extern fn usz malloc_size(void* ptr);
extern fn usz malloc_size(void* ptr) @if(!env::FREEBSD);
extern fn void* aligned_alloc(usz align, usz size);
macro CFile stdin() => __stdinp;
macro CFile stdout() => __stdoutp;
macro CFile stderr() => __stderrp;
module libc @if(env::FREEBSD);
extern fn usz malloc_usable_size(void* ptr);
macro usz malloc_size(void* ptr) => malloc_usable_size(ptr);
module libc @if(env::WIN32);
macro usz malloc_size(void* ptr) => _msize(ptr);
macro CFile stdin() => __acrt_iob_func(STDIN_FD);
macro CFile stdout() => __acrt_iob_func(STDOUT_FD);
macro CFile stderr() => __acrt_iob_func(STDERR_FD);
module libc @if(env::LIBC && !env::WIN32 && !env::LINUX && !env::DARWIN);
module libc @if(env::LIBC && !env::WIN32 && !env::LINUX && !env::DARWIN && !env::BSD_FAMILY);
macro CFile stdin() { return (CFile*)(uptr)STDIN_FD; }
macro CFile stdout() { return (CFile*)(uptr)STDOUT_FD; }
macro CFile stderr() { return (CFile*)(uptr)STDERR_FD; }

View File

@@ -0,0 +1,62 @@
module libc @if(env::FREEBSD);
// Checked for x86_64, this is notoriously incorrect when comparing with Rust code etc
def Blksize_t = $typefrom(env::X86_64 ? long.typeid : CInt.typeid);
def Nlink_t = $typefrom(env::X86_64 ? ulong.typeid : CUInt.typeid);
def Blkcnt_t = long;
def Ino_t = ulong;
def Dev_t = ulong;
def Mode_t = uint;
def Ino64_t = ulong;
def Blkcnt64_t = long;
struct Stat @if(env::X86_64)
{
Dev_t st_dev;
Ino_t st_ino;
Nlink_t st_nlink;
Mode_t st_mode;
Uid_t st_uid;
Gid_t st_gid;
CInt __pad0;
Dev_t st_rdev;
Off_t st_size;
Blksize_t st_blksize;
Blkcnt_t st_blocks;
Time_t st_atime;
long st_atime_nsec;
Time_t st_mtime;
long st_mtime_nsec;
Time_t st_ctime;
long st_ctime_nsec;
long[3] __unused;
}
struct Stat @if(!env::X86_64)
{
Dev_t st_dev;
Ino_t st_ino;
Mode_t st_mode;
Nlink_t st_nlink;
Uid_t st_uid;
Gid_t st_gid;
Dev_t st_rdev;
CInt __pad1;
Off_t st_size;
Blksize_t st_blksize;
CInt __pad2;
Blkcnt_t st_blocks;
Time_t st_atime;
long st_atime_nsec;
Time_t st_mtime;
long st_mtime_nsec;
Time_t st_ctime;
long st_ctime_nsec;
CInt[2] __unused;
}
extern fn CInt stat(ZString path, Stat* stat);
extern fn CInt get_nprocs();
extern fn CInt get_nprocs_conf();

View File

@@ -32,9 +32,9 @@ struct Sigaction
SignalFunction sa_handler;
SigActionFunction sa_sigaction;
}
CInt sa_flags @if(env::FREEBSD);
CInt sa_flags @if(env::BSD_FAMILY);
Sigset_t sa_mask; // 128
CInt sa_flags @if(!env::FREEBSD);
CInt sa_flags @if(!env::BSD_FAMILY);
void* sa_restorer @if(env::LINUX);
}

1120
lib/std/math/bigint.c3 Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,5 @@
module std::math::matrix(<Real>);
import std::math::vector;
struct Matrix2x2
{
@@ -132,6 +133,7 @@ fn Matrix2x2 Matrix2x2.sub(&self, Matrix2x2 mat2) => matrix_sub(self, mat2);
fn Matrix3x3 Matrix3x3.sub(&self, Matrix3x3 mat2) => matrix_sub(self, mat2);
fn Matrix4x4 Matrix4x4.sub(&self, Matrix4x4 mat2) => matrix_sub(self, mat2);
fn Matrix4x4 look_at(Real[<3>] eye, Real[<3>] target, Real[<3>] up) => matrix_look_at(Matrix4x4, eye, target, up);
fn Matrix2x2 Matrix2x2.transpose(&self)
@@ -432,3 +434,17 @@ macro matrix_sub(mat, mat2) @private
var $Type = Real[<$typeof(mat.m).len>];
return $typeof(*mat) { .m = ($Type)mat.m - ($Type)mat2.m };
}
macro matrix_look_at($Type, eye, target, up) @private
{
var vz = (eye - target).normalize();
var vx = up.cross(vz).normalize();
var vy = vz.cross(vx);
return $Type {
vx[0], vx[1], vx[2], - (Real)vx.dot(eye),
vy[0], vy[1], vy[2], - (Real)vy.dot(eye),
vz[0], vz[1], vz[2], - (Real)vz.dot(eye),
0.0, 0.0, 0.0, 1
};
}

View File

@@ -29,30 +29,75 @@ macro void seed_entropy(random)
}
/**
* Get the next value between 0 and max (not including max).
* Get the next value between 0 and range (not including range).
*
* @require is_random(random)
* @require range > 0
**/
macro int next(random, int max)
macro int next(random, uint range)
{
return (int)(next_double(random) * max);
if (range == 1) return 0;
uint mask = ~0U;
range--;
mask >>= range.clz();
uint x @noinit;
do
{
x = random.next_int() & mask;
}
while (x > range);
return x;
}
/**
* Get a random in the range [min, max], both included.
*
* @require is_random(random)
* @require max >= min
**/
macro int next_in_range(random, int min, int max)
{
return next(random, max - min + 1) + min;
}
def DefaultRandom = Sfc64Random;
tlocal Sfc64Random default_random @private;
tlocal bool default_random_initialized @private = false;
/**
* Get a default random value between 0 and max (not including max)
**/
fn int rand(int max) @builtin
* Seed the default random function.
*/
fn void srand(ulong seed) @builtin
{
tlocal Sfc64Random default_random;
tlocal bool initialized = false;
if (!initialized)
{
seed_entropy(&default_random);
initialized = true;
}
return next(&default_random, max);
default_random.set_seed(@as_char_view(seed));
default_random_initialized = true;
}
/**
* Get a default random value between 0 and range (not including range)
**/
fn int rand(int range) @builtin
{
init_default_random();
return next(&default_random, range);
}
/**
* Get a random in the range, both included.
* @require max >= min
**/
fn int rand_in_range(int min, int max) @builtin
{
init_default_random();
return next_in_range(&default_random, min, max);
}
fn double rnd() @builtin
{
init_default_random();
ulong val = default_random.next_long() & (1UL << 53 - 1);
return val * 0x1.0p-53;
}
/**
@@ -127,3 +172,13 @@ interface Random
fn uint128 next_int128();
fn void next_bytes(char[] buffer);
}
macro init_default_random() @private
{
if (!default_random_initialized)
{
seed_entropy(&default_random);
default_random_initialized = true;
}
}

View File

@@ -66,8 +66,8 @@ fn Vec3 Vec3.refract(self, Vec3 n, double r) => refract3(self, n, r);
fn void ortho_normalize(Vec3f* v1, Vec3f* v2) => ortho_normalize3(v1, v2);
fn void ortho_normalized(Vec3* v1, Vec3* v2) => ortho_normalize3(v1, v2);
fn Matrix4f matrix4f_look_at(Vec3f eye, Vec3f target, Vec3f up) => matrix_look_at(Matrix4f, eye, target, up);
fn Matrix4 matrix4_look_at(Vec3 eye, Vec3 target, Vec3 up) => matrix_look_at(Matrix4, eye, target, up);
fn Matrix4f matrix4f_look_at(Vec3f eye, Vec3f target, Vec3f up) @deprecated => matrix::look_at(<float>)(eye, target, up);
fn Matrix4 matrix4_look_at(Vec3 eye, Vec3 target, Vec3 up) @deprecated => matrix::look_at(<double>)(eye, target, up);
fn Vec3f Vec3f.rotate_quat(self, Quaternionf q) => rotate_by_quat3(self, q);
fn Vec3 Vec3.rotate_quat(self, Quaternion q) => rotate_by_quat3(self, q);
@@ -196,20 +196,6 @@ macro rotate_axis_angle(v, axis, angle) @private
return v + wv + wwv;
}
macro matrix_look_at($Type, eye, target, up) @private
{
var vz = (eye - target).normalize();
var vx = up.cross(vz).normalize();
var vy = vz.cross(vx);
return $Type {
vx[0], vx[1], vx[2], - vx.dot(eye),
vy[0], vy[1], vy[2], - vy.dot(eye),
vz[0], vz[1], vz[2], - vz.dot(eye),
0.0, 0.0, 0.0, 1
};
}
macro unproject3(v, m1, m2) @private
{
return v;
@@ -256,4 +242,4 @@ macro refract3(v, n, r) @private
var d = 1 - r * r * (1 - dot * dot);
return d < 0 ? v : r * v - (r * dot + math::sqrt(d)) * n;
}
}

View File

@@ -72,8 +72,9 @@ macro uint hash(value) @local
return fnv32a::encode(&&bitcast(value, char[$sizeof(value)]));
}
fn char[8 * 4] entropy()
fn char[8 * 4] entropy() @if(!env::WASM_NOLIBC)
{
void* addr = malloc(1);
free(addr);
static uint random_int;
@@ -89,4 +90,21 @@ fn char[8 * 4] entropy()
hash(allocator::heap())
};
return bitcast(entropy_data, char[8 * 4]);
}
fn char[8 * 4] entropy() @if(env::WASM_NOLIBC)
{
static uint random_int;
random_int += 0xedf19156;
uint[8] entropy_data = {
hash($$TIME),
hash(&entropy),
random_int,
hash($$TIME),
hash(&entropy),
random_int,
hash($$TIME),
hash(&entropy),
};
return bitcast(entropy_data, char[8 * 4]);
}

41
lib/std/math/uuid.c3 Normal file
View File

@@ -0,0 +1,41 @@
module std::math::uuid;
import std::math::random @public;
import std::io;
distinct Uuid (Printable) = char[16];
/**
* Generate a version 4 UUID from the default random.
**/
fn Uuid generate()
{
random::init_default_random();
return generate_from_random(&random::default_random);
}
/**
* Generate a version 4 UUID from the given random.
**/
fn Uuid generate_from_random(Random random)
{
Uuid uuid;
random.next_bytes(&(char[16])uuid);
uuid[6] = (uuid[6] & 0b0000_1111) | 0b0100_0000;
uuid[8] = (uuid[8] & 0b0011_1111) | 0b1000_0000;
return uuid;
}
fn usz! Uuid.to_format(&self, Formatter* formatter) @dynamic
{
return formatter.printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
(*self)[0], (*self)[1], (*self)[2], (*self)[3],
(*self)[4], (*self)[5],
(*self)[6], (*self)[7],
(*self)[8], (*self)[9],
(*self)[10], (*self)[11], (*self)[12], (*self)[13], (*self)[14], (*self)[15]);
}
fn String Uuid.to_string(&self, Allocator allocator) @dynamic
{
return string::new_format("%s", *self, allocator: allocator);
}

View File

@@ -105,7 +105,7 @@ fn Path! new_get_config_dir(Allocator allocator = allocator::heap())
String s = get_var_temp("XDG_CONFIG_HOME") ?? get_var_temp("HOME")!;
const DIR = ".config";
$endif
return path::temp_new(s).new_append(DIR, .allocator = allocator);
return path::temp_new(s).new_append(DIR, allocator: allocator);
$endif
};
}

View File

@@ -7,15 +7,22 @@ distinct DIRPtr = void*;
struct Posix_dirent
{
Ino_t d_fileno;
Off_t d_off;
Off_t d_off @if(!env::NETBSD);
ushort d_reclen;
ushort d_namelen @if(env::DARWIN);
ushort d_namelen @if(env::DARWIN || env::NETBSD);
char d_type;
char d_namelen @if(env::FREEBSD || env::OPENBSD);
uint d_pad0 @if(env::FREEBSD);
char d_namelen @if(env::OPENBSD);
char[4] d_pad0 @if(env::OPENBSD);
char d_pad0 @if(env::FREEBSD);
ushort d_namelen @if(env::FREEBSD);
ushort d_pad1 @if(env::FREEBSD);
char[255+1] name @if(env::FREEBSD || env::OPENBSD);
char[511+1] name @if(env::NETBSD);
char[1024] name @if(env::DARWIN);
char[*] name @if(!env::DARWIN);
char[*] name @if(!env::DARWIN && !env::BSD_FAMILY);
}
extern fn int rmdir(ZString);
@@ -41,4 +48,3 @@ 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);

View File

@@ -3,8 +3,8 @@ import std::thread;
import libc;
const PTHREAD_MUTEX_NORMAL = 0;
const PTHREAD_MUTEX_ERRORCHECK = 1;
const PTHREAD_MUTEX_RECURSIVE = 2;
const PTHREAD_MUTEX_ERRORCHECK = env::LINUX ? 2 : 1;
const PTHREAD_MUTEX_RECURSIVE = env::LINUX ? 1 : 2;
def PosixThreadFn = fn void*(void*);
distinct Pthread_t = void*;

View File

@@ -193,10 +193,10 @@ fn Backtrace! resolve_backtrace(void* addr, Win32_HANDLE process, Allocator allo
ZString zname = (ZString)&name;
if (!symGetLineFromAddr64(process, (Win32_ULONG64)addr - 1, &offset, &line))
{
backtrace.init((uptr)addr, zname.str_view(), module_name.str_view(), .allocator = allocator);
backtrace.init((uptr)addr, zname.str_view(), module_name.str_view(), allocator: allocator);
return backtrace;
}
String filename = ((ZString)line.fileName).str_view();
backtrace.init((uptr)addr, zname.str_view(), module_name.str_view(), .file = filename, .line = line.lineNumber, .allocator = allocator);
backtrace.init((uptr)addr, zname.str_view(), module_name.str_view(), file: filename, line: line.lineNumber, allocator: allocator);
return backtrace;
}

View File

@@ -32,7 +32,7 @@ def Indexs = char[256] @private;
def ElementType = $typeof(Type{}[0]);
const bool NO_KEY_FN @private = types::is_same(KeyFn, EmptySlot);
const bool KEY_BY_VALUE @private = NO_KEY_FN ||| $assignable(Type{}[0], $typefrom(KeyFn.params[0]));
const bool KEY_BY_VALUE @private = NO_KEY_FN ||| $assignable(Type{}[0], $typefrom(KeyFn.paramsof[0].type));
const bool LIST_HAS_REF @private = $defined(&Type{}[0]);
def KeyFnReturnType = $typefrom(KeyFn.returns) @if(!NO_KEY_FN);

View File

@@ -20,7 +20,7 @@ fn void isort(Type list, usz low, usz high, CmpFn comp, Context context)
{
var $has_cmp = @is_valid_macro_slot(comp);
var $has_context = @is_valid_macro_slot(context);
var $cmp_by_value = $has_cmp &&& $assignable(list[0], $typefrom(CmpFn.params[0]));
var $cmp_by_value = $has_cmp &&& $assignable(list[0], $typefrom(CmpFn.paramsof[0].type));
var $has_get_ref = $defined(&list[0]);
for (usz i = low; i < high; ++i)
{

View File

@@ -31,7 +31,7 @@ fn void qsort(Type list, isz low, isz high, CmpFn cmp, Context context)
{
var $has_cmp = @is_valid_macro_slot(cmp);
var $has_context = @is_valid_macro_slot(context);
var $cmp_by_value = $has_cmp &&& $assignable(list[0], $typefrom(CmpFn.params[0]));
var $cmp_by_value = $has_cmp &&& $assignable(list[0], $typefrom(CmpFn.paramsof[0].type));
if (low >= 0 && high >= 0 && low < high)
{

View File

@@ -0,0 +1,178 @@
module std::thread::threadpool @if (env::POSIX || env::WIN32);
import std::thread;
// Please do not use this one in production.
fault ThreadPoolResult
{
QUEUE_FULL
}
def ThreadPoolFn = fn void(any[] args);
struct FixedThreadPool @adhoc
{
Mutex mu;
QueueItem[] queue;
usz qindex;
usz num_threads;
bitstruct : char {
bool initialized;
bool stop;
bool stop_now;
}
Thread[] pool;
ConditionVariable notify;
}
struct QueueItem @private
{
ThreadPoolFn func;
any[] args;
}
/**
* @require !self.initialized "ThreadPool must not be already initialized"
* @require threads > 0 && threads < 0x1000 `Threads should be greater than 0 and less than 0x1000`
* @require queue_size < 0x10000 `Queue size must be less than 65536`
**/
fn void! FixedThreadPool.init(&self, usz threads, usz queue_size = 0)
{
if (queue_size == 0) queue_size = threads * 32;
defer catch @ok(self.destroy());
assert(queue_size > 0);
*self = {
.num_threads = threads,
.initialized = true,
.queue = mem::alloc_array(QueueItem, queue_size),
.pool = mem::new_array(Thread, threads)
};
self.mu.init()!;
self.notify.init()!;
foreach (&thread : self.pool)
{
thread.create(&process_work, self)!;
// The thread resources will be cleaned up when the thread exits.
thread.detach()!;
}
}
/*
* Stop all the threads and cleanup the pool.
* Any pending work will be dropped.
*/
fn void! FixedThreadPool.destroy(&self)
{
return self.@shutdown(stop_now);
}
/*
* Stop all the threads and cleanup the pool.
* Any pending work will be processed.
*/
fn void! FixedThreadPool.stop_and_destroy(&self)
{
return self.@shutdown(stop);
}
macro void! FixedThreadPool.@shutdown(&self, #stop) @private
{
if (self.initialized)
{
self.mu.lock()!;
self.#stop = true;
self.notify.broadcast()!;
self.mu.unlock()!;
// Wait for all threads to shutdown.
while (true)
{
self.mu.lock()!;
defer self.mu.unlock()!!;
if (self.num_threads == 0)
{
break;
}
self.notify.signal()!;
}
self.mu.destroy()!;
self.initialized = false;
while (self.qindex)
{
free_qitem(self.queue[--self.qindex]);
}
free(self.queue);
self.queue = {};
}
}
/*
* Push a new job to the pool.
* Returns whether the queue is full, in which case the job is ignored.
*/
fn void! FixedThreadPool.push(&self, ThreadPoolFn func, args...)
{
self.mu.lock()!;
defer self.mu.unlock()!!;
if (self.qindex == self.queue.len) return ThreadPoolResult.QUEUE_FULL?;
any[] data;
if (args.len)
{
data = mem::alloc_array(any, args.len);
foreach (i, arg : args) data[i] = allocator::clone_any(allocator::heap(), arg);
}
self.queue[self.qindex] = { .func = func, .args = data };
self.qindex++;
defer catch
{
free_qitem(self.queue[--self.qindex]);
}
// Notify the threads that work is available.
self.notify.broadcast()!;
}
fn int process_work(void* self_arg) @private
{
FixedThreadPool* self = self_arg;
while (true)
{
self.mu.lock()!!;
if (self.stop_now)
{
// Shutdown requested.
self.num_threads--;
self.mu.unlock()!!;
return 0;
}
// Wait for work.
while (self.qindex == 0)
{
if (self.stop)
{
// Shutdown requested.
self.num_threads--;
self.mu.unlock()!!;
return 0;
}
self.notify.wait(&self.mu)!!;
if (self.stop_now)
{
// Shutdown requested.
self.num_threads--;
self.mu.unlock()!!;
return 0;
}
}
// Process the job.
self.qindex--;
QueueItem item = self.queue[self.qindex];
self.mu.unlock()!!;
defer free_qitem(item);
item.func(item.args);
}
}
fn void free_qitem(QueueItem item) @private
{
foreach (arg : item.args) free(arg.ptr);
free(item.args);
}

View File

@@ -24,6 +24,12 @@ fn void! NativeMutex.init(&self, MutexType type)
{
if (posix::pthread_mutexattr_settype(&attr, posix::PTHREAD_MUTEX_RECURSIVE)) return ThreadFault.INIT_FAILED?;
}
else
{
$if env::COMPILER_SAFE_MODE:
if (posix::pthread_mutexattr_settype(&attr, posix::PTHREAD_MUTEX_ERRORCHECK)) return ThreadFault.INIT_FAILED?;
$endif
}
if (posix::pthread_mutex_init(&self.mutex, &attr)) return ThreadFault.INIT_FAILED?;
self.initialized = true;
}

View File

@@ -12,7 +12,7 @@ struct NativeMutex
}
// Size is less than a Win32_HANDLE so due to alignment
// there is no benefit to pack these into a bitstruct.
bool already_locked;
uint locks;
bool recursive;
bool timed;
}
@@ -40,7 +40,7 @@ struct NativeConditionVariable
fn void! NativeMutex.init(&mtx, MutexType type)
{
mtx.already_locked = false;
mtx.locks = 0;
mtx.recursive = (bool)(type & thread::MUTEX_RECURSIVE);
mtx.timed = (bool)(type & thread::MUTEX_TIMED);
if (!mtx.timed)
@@ -53,6 +53,7 @@ fn void! NativeMutex.init(&mtx, MutexType type)
fn void! NativeMutex.destroy(&mtx)
{
mtx.locks = 0;
if (!mtx.timed)
{
win32::deleteCriticalSection(&mtx.critical_section);
@@ -79,11 +80,11 @@ fn void! NativeMutex.lock(&mtx)
}
}
if (!mtx.recursive)
if (!mtx.recursive && mtx.locks)
{
while (mtx.already_locked) win32::sleep(1);
return ThreadFault.LOCK_FAILED?;
}
mtx.already_locked = true;
mtx.locks++;
}
@@ -103,20 +104,11 @@ fn void! NativeMutex.lock_timeout(&mtx, ulong ms)
default:
return ThreadFault.LOCK_FAILED?;
}
if (!mtx.recursive)
if (!mtx.recursive && mtx.locks)
{
usz left_timeout = ms - 1;
while (mtx.already_locked)
{
if (left_timeout-- == 0)
{
win32::releaseMutex(mtx.handle);
return ThreadFault.LOCK_TIMEOUT?;
}
win32::sleep(1);
}
mtx.already_locked = true;
return ThreadFault.LOCK_FAILED?;
}
mtx.locks++;
}
fn bool NativeMutex.try_lock(&mtx)
@@ -128,7 +120,7 @@ fn bool NativeMutex.try_lock(&mtx)
if (!success) return false;
if (!mtx.recursive)
{
if (mtx.already_locked)
if (mtx.locks)
{
if (mtx.timed)
{
@@ -140,14 +132,15 @@ fn bool NativeMutex.try_lock(&mtx)
}
return false;
}
mtx.already_locked = true;
}
mtx.locks++;
return true;
}
fn void! NativeMutex.unlock(&mtx)
{
mtx.already_locked = false;
if (!mtx.locks) return ThreadFault.UNLOCK_FAILED?;
mtx.locks--;
if (!mtx.timed)
{
win32::leaveCriticalSection(&mtx.critical_section);

View File

@@ -1,7 +1,7 @@
module std::thread::pool(<SIZE>);
import std::thread;
struct ThreadPool
struct ThreadPool @adhoc
{
Mutex mu;
QueueItem[SIZE] queue;
@@ -17,7 +17,7 @@ struct ThreadPool
ConditionVariable notify;
}
struct QueueItem
struct QueueItem @private
{
ThreadFn func;
void* arg;

View File

@@ -67,7 +67,7 @@ macro bool Thread.equals(thread, Thread other) => NativeThread.equals((NativeThr
macro void OnceFlag.call(&flag, OnceFn func) => NativeOnceFlag.call_once((NativeOnceFlag*)flag, func);
macro void yield() => os::native_thread_yield();
macro Thread current() => os::native_thread_current();
macro Thread current() => (Thread)os::native_thread_current();
macro void exit(int result) => os::native_thread_exit(result);
macro void! sleep(Duration d) @maydiscard => os::native_sleep_nano(d.to_nano());
macro void! sleep_ms(ulong ms) @maydiscard => sleep(time::ms(ms));

View File

@@ -20,6 +20,19 @@ fn DateTime from_date(int year, Month month = JANUARY, int day = 1, int hour = 0
return dt;
}
/**
* @require day >= 1 && day < 32
* @require hour >= 0 && hour < 24
* @require min >= 0 && min < 60
* @require sec >= 0 && sec < 60
* @require us >= 0 && us < 999_999
* @require gmt_offset >= -12 * 3600 && gmt_offset <= 14 * 3600
**/
fn TzDateTime from_date_tz(int year, Month month = JANUARY, int day = 1, int hour = 0, int min = 0, int sec = 0, int us = 0, int gmt_offset = 0)
{
return from_date(year, month, day, hour, min, sec, us).with_gmt_offset(gmt_offset);
}
fn TzDateTime DateTime.to_local(&self)
{
Tm tm @noinit;
@@ -47,6 +60,58 @@ fn TzDateTime DateTime.to_local(&self)
return dt;
}
/**
* Update timestamp to gmt_offset while keeping the date and time
* values unchanged.
*
* @require gmt_offset >= -12 * 3600 && gmt_offset <= 14 * 3600
**/
fn TzDateTime DateTime.with_gmt_offset(self, int gmt_offset)
{
TzDateTime dt = { self, 0 };
return dt.with_gmt_offset(gmt_offset);
}
/**
* Update timestamp to gmt_offset while keeping the date and time
* values unchanged.
*
* @require gmt_offset >= -12 * 3600 && gmt_offset <= 14 * 3600
**/
fn TzDateTime TzDateTime.with_gmt_offset(self, int gmt_offset)
{
self.time -= (Time)(gmt_offset - self.gmt_offset) * (Time)time::SEC;
return { self.date_time, gmt_offset };
}
/**
* Update the date and time values to gmt_offset while keeping the
* timestamp unchanged.
*
* @require gmt_offset >= -12 * 3600 && gmt_offset <= 14 * 3600
* @ensure self.time == return.time
**/
fn TzDateTime DateTime.to_gmt_offset(self, int gmt_offset)
{
TzDateTime dt = { self, 0 };
return dt.to_gmt_offset(gmt_offset);
}
/**
* Update the date and time values to gmt_offset while keeping the
* timestamp unchanged.
*
* @require gmt_offset >= -12 * 3600 && gmt_offset <= 14 * 3600
* @ensure self.time == return.time
**/
fn TzDateTime TzDateTime.to_gmt_offset(self, int gmt_offset) {
if (self.gmt_offset == gmt_offset) return self;
Time time = self.time + (Time)gmt_offset * (Time)time::SEC;
DateTime dt = from_time(time);
dt.time = self.time;
return { dt, gmt_offset };
}
/**
* @require day >= 1 && day < 32
* @require hour >= 0 && hour < 24
@@ -121,6 +186,16 @@ fn DateTime DateTime.add_months(&self, int months)
return from_date(year, (Month)month, self.day, self.hour, self.min, self.sec, self.usec);
}
fn TzDateTime TzDateTime.add_seconds(&self, int seconds) => self.date_time.add_seconds(seconds).to_gmt_offset(self.gmt_offset);
fn TzDateTime TzDateTime.add_minutes(&self, int minutes) => self.date_time.add_minutes(minutes).to_gmt_offset(self.gmt_offset);
fn TzDateTime TzDateTime.add_hours(&self, int hours) => self.date_time.add_hours(hours).to_gmt_offset(self.gmt_offset);
fn TzDateTime TzDateTime.add_days(&self, int days) => self.date_time.add_days(days).to_gmt_offset(self.gmt_offset);
fn TzDateTime TzDateTime.add_weeks(&self, int weeks) => self.date_time.add_weeks(weeks).to_gmt_offset(self.gmt_offset);
fn TzDateTime TzDateTime.add_years(&self, int years) => self.date_time.add_years(years).with_gmt_offset(self.gmt_offset);
fn TzDateTime TzDateTime.add_months(&self, int months) => self.date_time.add_months(months).with_gmt_offset(self.gmt_offset);
fn DateTime from_time(Time time)
{
DateTime dt @noinit;
@@ -128,6 +203,15 @@ fn DateTime from_time(Time time)
return dt;
}
/**
* @require gmt_offset >= -12 * 3600 && gmt_offset <= 14 * 3600
* @ensure time == return.time
**/
fn TzDateTime from_time_tz(Time time, int gmt_offset)
{
return from_time(time).to_gmt_offset(gmt_offset);
}
fn Time DateTime.to_time(&self) @inline
{
return self.time;
@@ -167,4 +251,4 @@ fn double DateTime.diff_sec(self, DateTime from)
fn Duration DateTime.diff_us(self, DateTime from)
{
return self.time.diff_us(from.time);
}
}

View File

@@ -1,5 +1,92 @@
# C3C Release Notes
## 0.6.3 Change list
### Changes / improvements
- Introduce `arg: x` named arguments instead of `.arg = x`, deprecate old style.
- Support splat for varargs #1352.
- Allow `var` in lambdas in macros.
- Support `int[*] { 1, 2, 3 }` expressions.
- Support inline struct designated init as if inline was anonymous.
- Introduce the `.paramsof` property.
- Support environment variable 'C3C_LIB' to find the standard library.
- Support environment variable 'C3C_CC' to find the default C compiler.
- Support casting bitstructs to bool.
- Allow user-defined attributes to have typed parameters.
- Add `.gitkeep` files to project subfolders.
- Add `env::COMPILER_BUILD_HASH` and `env::COMPILER_BUILD_DATE`
- Support linking .o files in compilation command. #1417
- Slicing constant strings at compile time works.
- Add `project fetch` subcommand to fetch missing project dependencies (general and target specific)
- Ability of `vendor-fetch` to download the dependencies in the first specified path `dependencies-search-path`
- Ability of `vendor-fetch` to register the fetched dependencies in the project file.
- Allow the "self" parameter to be $/# for macro methods.
- Support compile time slicing of untyped lists.
- Allow specifying an import module using `@wasm` #1305.
- Deprecated inline generic types outside of struct definitions and macros unless marked `@adhoc`.
- Improved method detection in earlier stages of checking.
- Allow `@norecurse` attribute for non-recursive imports #1480.
- wasm32 / wasm64 targets are use-libc=no by default.
- Add hash/sha256 module
### Fixes
- Issue where a lambda wasn't correctly registered as external. #1408
- Generic methods were incorrectly registered as functions, leading to naming collisions. #1402
- Deprecated tuple / triple types.
- Converting a slice to a vector/array would copy too little data.
- Crash when reading an empty 'manifest.json'.
- "optsize" did not work correctly in project.json.
- `l[0].a = 1` now supported for overloads due to better lvalue handling #1357.
- Asserts are retained regardless of optimization when running tests.
- Limit object filename lengths. #1415
- Fix regression for `$include`.
- Correct '.so' suffix on dynamic libraries on Linux.
- Fix bug where inline index access to array in a struct would crash the compiler.
- Asserts are now correctly included and traced in when running tests.
- Use atexit to fix finalizers on Windows #1361.
- Fix bugs in "trap-on-wrap" #1434.
- Bug with casting anyfault to error.
- Lambda / function type would accidentally be processed as a method.
- Fix error message when not finding a particular function.
- Crash invoking a `@body` argument with the wrong number of parameters.
- Fix reordering semantics in struct assignment.
- Regression when passing types as `#expr` arguments. #1461
- Temp allocator overwrites data when doing reset on extra allocated pages. #1462
- User defined attributes could not have more than 1 parameter due to bug.
- Folding a constant array of structs at compile time would cause an assert.
- Enum attributes would be overwritten by enum value attributes.
- LLVM issue with try when bool is combined #1467.
- Segfault using ternary with no assignment #1468.
- Inner types make some errors misleading #1471.
- Fix bug when passing a type as a compile time value.
- Fix bug due to enum associated values not being checked for liveness.
- Regression when compile time accessing a union field not last assigned to.
- Safer seed of rand() for WASM without libc.
- Bad error message aliasing an ident with a path. #1481.
- Error when slicing a struct with an inline array #1488.
- Improved error messages on `Foo a = foo { 1 };` #1496
- Bug in json decoder escape handling.
- Fix bug when reading zip manifest, that would not return a zero terminated string. #1490
- Fix thread tests.
- Detect recursion errors on non-recursive mutexes in safe mode.
- Foreach over distinct pointer failed to be caught as error #1506.
- Foreach over distinct iterable would ignore operator(len).
- Compiler crash when compiling c code in a library without --obj-out #1503.
### Stdlib changes
- Additional init functions for hashmap.
- `format` functions are now functions and work better with splat.
- Add support for the QOI format.
- Add `io::read_new_fully` for reading to the end of a stream.
- Add `io::wrap_bytes` for reading bytes with `io` functions.
- Add `rnd` and `rand_in_range` default random functions.
- Additional timezone related functions for `datetime`.
- Added MD5 and crypto::safe_compare.
- Added generic HMAC.
- Added generic PBKDF2 implementation.
- DString `reverse`.
- `DString.insert_at` now has variants for other types.
## 0.6.2 Change list
### Changes / improvements

View File

@@ -2,8 +2,8 @@ import std::io;
fn void main()
{
Path path = path::getcwd()!!;
foreach (i, p : path::ls(path)!!)
Path path = path::new_cwd()!!;
foreach (i, p : path::new_ls(path)!!)
{
io::printfn("%02d %s", i, p.str_view());
}

View File

@@ -0,0 +1,22 @@
fn int main()
{
String msg = "Hello, C3 World!\n";
$$syscall(4, 1, (uptr)msg.ptr, msg.len); // __NR_write, STDOUT
return 0;
}
fn void _start() @export("_start")
{
int ret = main();
$$syscall(1, ret); // __NR_exit
}
module std::core::builtin;
def PanicFn = fn void(String message, String file, String function, uint line);
PanicFn panic = &default_panic;
fn void default_panic(String message, String file, String function, uint line)
{
}

View File

@@ -0,0 +1,79 @@
{
// Language version of C3.
"langrev": "1",
// Warnings used for all targets.
"warnings": [ "no-unused" ],
// Directories where C3 library files may be found.
"dependency-search-paths": [ ],
// Libraries to use for all targets.
"dependencies": [ ],
// Authors, optionally with email.
"authors": [ "John Doe <john.doe@example.com>" ],
// Version using semantic versioning.
"version": "0.1.0",
// Sources compiled for all targets.
"sources": [ "./**" ],
// C sources if the project also compiles C sources
// relative to the project file.
// "c-sources": [ "csource/**" ],
// Output location, relative to project file.
"output": ".",
// Architecture and OS target.
// You can use 'c3c --list-targets' to list all valid targets.
"target": "freebsd-x64",
// Targets.
"targets": {
"hello_world": {
"type": "executable",
"debug-info": "none",
"link-libc": false,
"opt": "O0",
"safe": false,
"linker": "builtin",
"use-stdlib": false,
},
},
// Global settings.
// C compiler if the project also compiles C sources
// defaults to 'cc'.
"cc": "cc",
// CPU name, used for optimizations in the LLVM backend.
"cpu": "generic",
// Debug information, may be "none", "full" and "line-tables".
"debug-info": "full",
// FP math behaviour: "strict", "relaxed", "fast".
"fp-math": "strict",
// Link libc other default libraries.
"link-libc": true,
// Memory environment: "normal", "small", "tiny", "none".
"memory-env": "normal",
// Optimization: "O0", "O1", "O2", "O3", "O4", "O5", "Os", "Oz".
"opt": "O0",
// Code optimization level: "none", "less", "more", "max".
"optlevel": "none",
// Code size optimization: "none", "small", "tiny".
"optsize": "none",
// Relocation model: "none", "pic", "PIC", "pie", "PIE".
"reloc": "none",
// Trap on signed and unsigned integer wrapping for testing.
"trap-on-wrap": false,
// Turn safety (contracts, runtime bounds checking, null pointer checks etc).
"safe": true,
// Compile all modules together, enables more inlining.
"single-module": true,
// Use / don't use soft float, value is otherwise target default.
"soft-float": false,
// Strip unused code and globals from the output.
"strip-unused": true,
// The size of the symtab, which limits the amount
// of symbols that can be used. Should usually not be changed.
"symtab": 1048576,
// Select linker.
"linker": "cc",
// Include the standard library.
"use-stdlib": true,
// Set general level of x64 cpu: "baseline", "ssse3", "sse4", "avx1", "avx2-v1", "avx2-v2", "avx512", "native".
"x86cpu": "native",
// Set max type of vector use: "none", "mmx", "sse", "avx", "avx512", "native".
"x86vec": "sse",
}

76
resources/examples/opengl/.gitignore vendored Normal file
View File

@@ -0,0 +1,76 @@
# Prerequisites
*.d
# Object files
*.o
*.ko
*.obj
*.elf
*.ll
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf
/build/
.idea/
/resources/grammar.tab.c
/resources/grammar.vcg
/resources/lex.yy.c
/resources/y.tab.c
/resources/y.tab.h
/bin/
#visual studio files
.vs/
.vscode/
out/
/cmake-build-debug/
/cmake-build-release/
# Emacs files
TAGS
# Clangd LSP files
/.cache/
/compile_commands.json

View File

View File

View File

View File

View File

@@ -0,0 +1,28 @@
{
"version": "0.1.0",
"authors": [
"John Doe <john.doe@example.com>"
],
"langrev": "1",
"warnings": [
"no-unused"
],
"sources": [
"./**"
],
"dependency-search-paths": [],
"dependencies": [],
"cc": "cc",
"c-sources": [],
"targets": {
"build/triangle": {
"type": "executable"
}
},
"linked-libraries": [
"glfw",
"GL"
],
"cpu": "generic",
"opt": "O0"
}

View File

@@ -0,0 +1,36 @@
module gl;
def BitField = int;
enum BufferBit : int(int value) {
COLOR = 0x00004000,
STENCIL = 0x00000400,
DEPTH = 0x00000100,
}
enum Primitive : int(int value) {
POINTS = 0,
LINES = 1,
LINE_LOOP = 2,
LINE_STRIP = 3,
TRIANGLES = 4,
TRIANGLE_STRIP = 5,
TRIANGLE_FAN = 6,
QUADS = 7,
QUAD_STRIP = 8,
POLYGON = 9,
}
extern fn void clear(BitField mask) @extern("glClear") @public;
extern fn void begin(BitField mask) @extern("glBegin") @public;
extern fn void end() @extern("glEnd") @public;
extern fn void flush() @extern("glFlush") @public;
extern fn void color3f(float r, float g, float b)
@extern("glColor3f") @public;
extern fn void vertex3f(float x, float y, float z)
@extern("glVertex3f") @public;

View File

@@ -0,0 +1,64 @@
module glfw;
import std::io;
distinct Window @public = _Window*;
distinct Monitor @public = _Monitor*;
fn void Window.create(
&self,
int width,
int height,
String title,
Monitor monitor = {},
Window share = {}
) @public {
*self = (Window)_glfwCreateWindow(
width,
height,
title,
(_Monitor*)monitor,
(_Window*)share
);
}
fn void Window.destroy(self) @public {
_glfwDestroyWindow((_Window*)self);
}
fn bool Window.shouldClose(self) @public {
return _glfwWindowShouldClose((_Window*)self);
}
fn void Window.swapBuffers(self) @public {
return _glfwSwapBuffers((_Window*)self);
}
fn void Window.makeContextCurrent(self) @public {
return _glfwMakeContextCurrent((_Window*)self);
}
extern fn void initialize() @extern("glfwInit") @public;
extern fn void terminate() @extern("glfwTerminate") @public;
extern fn void pollEvents() @extern("glfwPollEvents") @public;
distinct _Window @private = void;
distinct _Monitor @private = void;
extern fn _Window* _glfwCreateWindow(
int width, int height, char* title, _Monitor* monitor, _Window* share
) @extern("glfwCreateWindow") @private;
extern fn bool _glfwWindowShouldClose(_Window* window)
@extern("glfwWindowShouldClose") @private;
extern fn void _glfwDestroyWindow(_Window* window)
@extern("glfwDestroyWindow") @private;
extern fn void _glfwSwapBuffers(_Window* window)
@extern("glfwSwapBuffers") @private;
extern fn void _glfwMakeContextCurrent(_Window* window)
@extern("glfwMakeContextCurrent") @private;

View File

@@ -0,0 +1,30 @@
import std::io;
import glfw;
import gl;
fn void main() {
glfw::initialize();
Window window;
window.create(1280, 720, "Triangle example");
window.makeContextCurrent();
while(!window.shouldClose()) {
gl::clear(BufferBit.COLOR.value);
gl::begin(Primitive.TRIANGLES.value);
gl::color3f(1, 0, 0); gl::vertex3f(-0.6, -0.75, 0.5);
gl::color3f(0, 1, 0); gl::vertex3f(0.6, -0.75, 0);
gl::color3f(0, 0, 1); gl::vertex3f(0, 0.75, 0);
gl::end();
gl::flush();
window.swapBuffers();
glfw::pollEvents();
}
window.destroy();
glfw::terminate();
}

View File

View File

@@ -1,7 +1,7 @@
c3yacc: grammar.y c3.l
bison -d grammar.y; cc -c grammar.tab.c
flex c3.l; gcc -c lex.yy.c
cc -o c3yacc lex.yy.o grammar.tab.o
flex --header-file=lex.yy.h -8 c3.l
bison -d grammar.y;
cc -O2 -o c3yacc lex.yy.c grammar.tab.c
clean:
rm -f c3yacc grammar.output *.o grammar.tab.* lex.yy.c
rm -f c3yacc grammar.output *.o grammar.tab.* lex.yy.*

View File

@@ -1,4 +1,7 @@
%option yylineno
%option bison-locations
%option reentrant
%option bison-bridge
D [0-9]
DU [0-9_]
@@ -31,251 +34,250 @@ BINT {B}(_?{B})*
%{
#include <stdio.h>
#include "grammar.tab.h"
void count(void);
int comment_level = 0;
typedef struct {
int comment_level;
} YY_Extra_Type;
#define YY_EXTRA_TYPE YY_Extra_Type
#define YY_USER_ACTION \
yylloc->first_line = yylloc->last_line; \
yylloc->first_column = yylloc->last_column; \
for(int i = 0; yytext[i] != '\0'; i++) { \
if(yytext[i] == '\n') { \
yylloc->last_line++; \
yylloc->last_column = 0; \
} \
else { \
yylloc->last_column++; \
} \
}
%}
%%
"$alignof" { count(); return(CT_ALIGNOF); }
"$assert" { count(); return(CT_ASSERT); }
"$assignable" { count(); return(CT_ASSIGNABLE); }
"$case" { count(); return(CT_CASE); }
"$default" { count(); return(CT_DEFAULT); }
"$defined" { count(); return(CT_DEFINED); }
"$echo" { count(); return(CT_ECHO); }
"$else" { count(); return(CT_ELSE); }
"$endfor" { count(); return(CT_ENDFOR); }
"$endforeach" { count(); return(CT_ENDFOREACH); }
"$endif" { count(); return(CT_ENDIF); }
"$endswitch" { count(); return(CT_ENDSWITCH); }
"$error" { count(); return(CT_ERROR); }
"$eval" { count(); return(CT_EVAL); }
"$evaltype" { count(); return(CT_EVALTYPE); }
"$exec" { count(); return(CT_EXEC); }
"$extnameof" { count(); return(CT_EXTNAMEOF); }
"$feature" { count(); return(CT_FEATURE); }
"$for" { count(); return(CT_FOR); }
"$foreach" { count(); return(CT_FOREACH); }
"$if" { count(); return(CT_IF); }
"$is_const" { count(); return(CT_IS_CONST); }
"$include" { count(); return(CT_INCLUDE); }
"$nameof" { count(); return(CT_NAMEOF); }
"$offsetof" { count(); return(CT_OFFSETOF); }
"$qnameof" { count(); return(CT_QNAMEOF); }
"$sizeof" { count(); return(CT_SIZEOF); }
"$stringify" { count(); return(CT_STRINGIFY); }
"$switch" { count(); return(CT_SWITCH); }
"$typefrom" { count(); return(CT_TYPEFROM); }
"$typeof" { count(); return(CT_TYPEOF); }
"$vaarg" { count(); return(CT_VAARG); }
"$vaconst" { count(); return(CT_VACONST); }
"$vacount" { count(); return(CT_VACOUNT); }
"$vaexpr" { count(); return(CT_VAEXPR); }
"$varef" { count(); return(CT_VAREF); }
"$vasplat" { count(); return(CT_VASPLAT); }
"$vatype" { count(); return(CT_VATYPE); }
"/*" { count(); BEGIN(COMMENT); }
"$alignof" { return(CT_ALIGNOF); }
"$assert" { return(CT_ASSERT); }
"$assignable" { return(CT_ASSIGNABLE); }
"$case" { return(CT_CASE); }
"$default" { return(CT_DEFAULT); }
"$defined" { return(CT_DEFINED); }
"$echo" { return(CT_ECHO); }
"$else" { return(CT_ELSE); }
"$endfor" { return(CT_ENDFOR); }
"$endforeach" { return(CT_ENDFOREACH); }
"$endif" { return(CT_ENDIF); }
"$endswitch" { return(CT_ENDSWITCH); }
"$error" { return(CT_ERROR); }
"$eval" { return(CT_EVAL); }
"$evaltype" { return(CT_EVALTYPE); }
"$exec" { return(CT_EXEC); }
"$extnameof" { return(CT_EXTNAMEOF); }
"$feature" { return(CT_FEATURE); }
"$for" { return(CT_FOR); }
"$foreach" { return(CT_FOREACH); }
"$if" { return(CT_IF); }
"$is_const" { return(CT_IS_CONST); }
"$include" { return(CT_INCLUDE); }
"$nameof" { return(CT_NAMEOF); }
"$offsetof" { return(CT_OFFSETOF); }
"$qnameof" { return(CT_QNAMEOF); }
"$sizeof" { return(CT_SIZEOF); }
"$stringify" { return(CT_STRINGIFY); }
"$switch" { return(CT_SWITCH); }
"$typefrom" { return(CT_TYPEFROM); }
"$typeof" { return(CT_TYPEOF); }
"$vaarg" { return(CT_VAARG); }
"$vaconst" { return(CT_VACONST); }
"$vacount" { return(CT_VACOUNT); }
"$vaexpr" { return(CT_VAEXPR); }
"$varef" { return(CT_VAREF); }
"$vasplat" { return(CT_VASPLAT); }
"$vatype" { return(CT_VATYPE); }
"/*" { BEGIN(COMMENT); }
<COMMENT>{
"/*" { count(); comment_level++; }
"*"+"/" { count(); if (comment_level) { comment_level--; } else { BEGIN(INITIAL); } }
"*"+ { count(); }
[^/*\n]+ { count(); }
[/] { count(); }
\n { count(); }
"/*" { yyg->yyextra_r.comment_level++; }
"*"+"/" { if (yyg->yyextra_r.comment_level) { yyg->yyextra_r.comment_level--; } else { BEGIN(INITIAL); } }
"*"+ { }
[^/*\n]+ { }
[/] { }
\n { }
}
\/\/.* { count(); }
"any" { count(); return(ANY); }
"anyfault" { count(); return(ANYFAULT); }
"asm" { count(); return(ASM); }
"assert" { count(); return(ASSERT); }
"bitstruct" { count(); return(BITSTRUCT); }
"bool" { count(); return(BOOL); }
"break" { count(); return(BREAK); }
"case" { count(); return(CASE); }
"catch" { count(); return(CATCH); }
"char" { count(); return(CHAR); }
"const" { count(); return(CONST); }
"continue" { count(); return(CONTINUE); }
"def" { count(); return(DEF); }
"default" { count(); return(DEFAULT); }
"defer" { count(); return(DEFER); }
"distinct" { count(); return(DISTINCT); }
"do" { count(); return(DO); }
"double" { count(); return(DOUBLE); }
"else" { count(); return(ELSE); }
"enum" { count(); return(ENUM); }
"extern" { count(); return(EXTERN); }
"false" { count(); return(FALSE); }
"fault" { count(); return(FAULT); }
"float" { count(); return(FLOAT); }
"bfloat16" { count(); return(BFLOAT16); }
"float16" { count(); return(FLOAT16); }
"float128" { count(); return(FLOAT128); }
"fn" { count(); return(FN); }
"for" { count(); return(FOR); }
"foreach" { count(); return(FOREACH); }
"foreach_r" { count(); return(FOREACH_R); }
"ichar" { count(); return(ICHAR); }
"if" { count(); return(IF); }
"import" { count(); return(IMPORT); }
"inline" { count(); return(INLINE); }
"int" { count(); return(INT); }
"int128" { count(); return(INT128); }
"interface" { count(); return(INTERFACE); }
"iptr" { count(); return(IPTR); }
"isz" { count(); return(ISZ); }
"long" { count(); return(LONG); }
"macro" { count(); return(MACRO); }
"module" { count(); return(MODULE); }
"nextcase" { count(); return(NEXTCASE); }
"null" { count(); return(NUL); }
"return" { count(); return(RETURN); }
"short" { count(); return(SHORT); }
"struct" { count(); return(STRUCT); }
"static" { count(); return(STATIC); }
"switch" { count(); return(SWITCH); }
"tlocal" { count(); return(TLOCAL); }
"true" { count(); return(TRUE); }
"try" { count(); return(TRY); }
"typeid" { count(); return(TYPEID); }
"uint" { count(); return(UINT); }
"uint128" { count(); return(UINT128); }
"ulong" { count(); return(ULONG); }
"union" { count(); return(UNION); }
"uptr" { count(); return(UPTR); }
"ushort" { count(); return(USHORT); }
"usz" { count(); return(USZ); }
"var" { count(); return(VAR); }
"void" { count(); return(VOID); }
"while" { count(); return(WHILE); }
\/\/.* { }
"any" { return(ANY); }
"anyfault" { return(ANYFAULT); }
"asm" { return(ASM); }
"assert" { return(ASSERT); }
"bitstruct" { return(BITSTRUCT); }
"bool" { return(BOOL); }
"break" { return(BREAK); }
"case" { return(CASE); }
"catch" { return(CATCH); }
"char" { return(CHAR); }
"const" { return(CONST); }
"continue" { return(CONTINUE); }
"def" { return(DEF); }
"default" { return(DEFAULT); }
"defer" { return(DEFER); }
"distinct" { return(DISTINCT); }
"do" { return(DO); }
"double" { return(DOUBLE); }
"else" { return(ELSE); }
"enum" { return(ENUM); }
"extern" { return(EXTERN); }
"false" { return(FALSE); }
"fault" { return(FAULT); }
"float" { return(FLOAT); }
"bfloat16" { return(BFLOAT16); }
"float16" { return(FLOAT16); }
"float128" { return(FLOAT128); }
"fn" { return(FN); }
"for" { return(FOR); }
"foreach" { return(FOREACH); }
"foreach_r" { return(FOREACH_R); }
"ichar" { return(ICHAR); }
"if" { return(IF); }
"import" { return(IMPORT); }
"inline" { return(INLINE); }
"int" { return(INT); }
"int128" { return(INT128); }
"interface" { return(INTERFACE); }
"iptr" { return(IPTR); }
"isz" { return(ISZ); }
"long" { return(LONG); }
"macro" { return(MACRO); }
"module" { return(MODULE); }
"nextcase" { return(NEXTCASE); }
"null" { return(NUL); }
"return" { return(RETURN); }
"short" { return(SHORT); }
"struct" { return(STRUCT); }
"static" { return(STATIC); }
"switch" { return(SWITCH); }
"tlocal" { return(TLOCAL); }
"true" { return(TRUE); }
"try" { return(TRY); }
"typeid" { return(TYPEID); }
"uint" { return(UINT); }
"uint128" { return(UINT128); }
"ulong" { return(ULONG); }
"union" { return(UNION); }
"uptr" { return(UPTR); }
"ushort" { return(USHORT); }
"usz" { return(USZ); }
"var" { return(VAR); }
"void" { return(VOID); }
"while" { return(WHILE); }
@{CONST} { count(); return(AT_CONST_IDENT); }
#{CONST} { count(); return(HASH_CONST_IDENT); }
${CONST} { count(); return(CT_CONST_IDENT); }
{CONST} { count(); return(CONST_IDENT); }
@{TYPE} { count(); return(AT_TYPE_IDENT); }
#{TYPE} { count(); return(HASH_TYPE_IDENT); }
${TYPE} { count(); return(CT_TYPE_IDENT); }
{TYPE} { count(); return(TYPE_IDENT); }
@{IDENTIFIER} { count(); return(AT_IDENT); }
#{IDENTIFIER} { count(); return(HASH_IDENT); }
${IDENTIFIER} { count(); return(CT_IDENT); }
{IDENTIFIER} { count(); return(IDENT); }
0[xX]{HINT}{INTTYPE}? { count(); return(INTEGER); }
0[oO]{OINT}{INTTYPE}? { count(); return(INTEGER); }
0[bB]{BINT}{INTTYPE}? { count(); return(INTEGER); }
{INT}{INTTYPE}? { count(); return(INTEGER); }
x\'{HEX}\' { count(); return(BYTES); }
x\"{HEX}\" { count(); return(BYTES); }
x\`{HEX}\` { count(); return(BYTES); }
b64\'{B64}\' { count(); return(BYTES); }
b64\"{B64}\" { count(); return(BYTES); }
b64\`{B64}\` { count(); return(BYTES); }
@{CONST} { return(AT_CONST_IDENT); }
#{CONST} { return(HASH_CONST_IDENT); }
${CONST} { return(CT_CONST_IDENT); }
{CONST} { return(CONST_IDENT); }
@{TYPE} { return(AT_TYPE_IDENT); }
#{TYPE} { return(HASH_TYPE_IDENT); }
${TYPE} { return(CT_TYPE_IDENT); }
{TYPE} { return(TYPE_IDENT); }
@{IDENTIFIER} { return(AT_IDENT); }
#{IDENTIFIER} { return(HASH_IDENT); }
${IDENTIFIER} { return(CT_IDENT); }
{IDENTIFIER} { return(IDENT); }
0[xX]{HINT}{INTTYPE}? { return(INTEGER); }
0[oO]{OINT}{INTTYPE}? { return(INTEGER); }
0[bB]{BINT}{INTTYPE}? { return(INTEGER); }
{INT}{INTTYPE}? { return(INTEGER); }
x\'{HEX}\' { return(BYTES); }
x\"{HEX}\" { return(BYTES); }
x\`{HEX}\` { return(BYTES); }
b64\'{B64}\' { return(BYTES); }
b64\"{B64}\" { return(BYTES); }
b64\`{B64}\` { return(BYTES); }
{INT}{REALTYPE} { count(); return(REAL); }
{INT}{E}{REALTYPE}? { count(); return(REAL); }
0[xX]{HINT}{P}{REALTYPE}? { count(); return(REAL); }
{INT}"."{INT}{E}?{REALTYPE}? { count(); return(REAL); }
0[xX]{HINT}"."{HINT}{P}{REALTYPE}? { count(); return(REAL); }
{INT}{REALTYPE} { return(REAL); }
{INT}{E}{REALTYPE}? { return(REAL); }
0[xX]{HINT}{P}{REALTYPE}? { return(REAL); }
{INT}"."{INT}{E}?{REALTYPE}? { return(REAL); }
0[xX]{HINT}"."{HINT}{P}{REALTYPE}? { return(REAL); }
\"(\\.|[^\\"])*\" { count(); return(STRING_LITERAL); }
\'(\\[ux]{HEX}|\\.|[^\\'])\' { count(); return(CHAR_LITERAL); }
\"(\\.|[^\\"])*\" { return(STRING_LITERAL); }
\'(\\[ux]{HEX}|\\.|[^\\']+)\' { return(CHAR_LITERAL); }
"`" { count(); BEGIN(RAW_STRING); }
"`" { BEGIN(RAW_STRING); }
<RAW_STRING>{
"``" { count(); }
"`" { count(); BEGIN(INITIAL); return(STRING_LITERAL); }
"[^`]"+ { count(); }
"``" { }
"`" { BEGIN(INITIAL); return(STRING_LITERAL); }
"[^`]"+ { }
<<EOF>> { BEGIN(INITIAL); return(RAW_STRING); }
}
"!!" { count(); return(BANGBANG); }
"..." { count(); return(ELLIPSIS); }
".." { count(); return(DOTDOT); }
"&&&" { count(); return(CT_AND_OP); }
"|||" { count(); return(CT_OR_OP); }
"+++" { count(); return(CT_CONCAT_OP); }
">>=" { count(); return(SHR_ASSIGN); }
"<<=" { count(); return(SHL_ASSIGN); }
"+=" { count(); return(ADD_ASSIGN); }
"-=" { count(); return(SUB_ASSIGN); }
"*=" { count(); return(MUL_ASSIGN); }
"/=" { count(); return(DIV_ASSIGN); }
"%=" { count(); return(MOD_ASSIGN); }
"&=" { count(); return(AND_ASSIGN); }
"^=" { count(); return(XOR_ASSIGN); }
"|=" { count(); return(OR_ASSIGN); }
">>" { count(); return(SHR_OP); }
"<<" { count(); return(SHL_OP); }
"++" { count(); return(INC_OP); }
"--" { count(); return(DEC_OP); }
"&&" { count(); return(AND_OP); }
"||" { count(); return(OR_OP); }
"<=" { count(); return(LE_OP); }
">=" { count(); return(GE_OP); }
"==" { count(); return(EQ_OP); }
"!=" { count(); return(NE_OP); }
"??" { count(); return(OPTELSE); }
"::" { count(); return(SCOPE); }
"?:" { count(); return(ELVIS); }
"=>" { count(); return(IMPLIES); }
"[<" { count(); return(LVEC); }
">]" { count(); return(RVEC); }
"(<" { count(); return(LGENPAR); }
">)" { count(); return(RGENPAR); }
"$$" { count(); return(BUILTIN); }
";" { count(); return(';'); }
("{") { count(); return('{'); }
("}") { count(); return('}'); }
"," { count(); return(','); }
":" { count(); return(':'); }
"=" { count(); return('='); }
"(" { count(); return('('); }
")" { count(); return(')'); }
("[") { count(); return('['); }
("]") { count(); return(']'); }
"." { count(); return('.'); }
"&" { count(); return('&'); }
"!" { count(); return('!'); }
"~" { count(); return('~'); }
"-" { count(); return('-'); }
"+" { count(); return('+'); }
"*" { count(); return('*'); }
"/" { count(); return('/'); }
"%" { count(); return('%'); }
"<" { count(); return('<'); }
">" { count(); return('>'); }
"^" { count(); return('^'); }
"|" { count(); return('|'); }
"?" { count(); return('?'); }
"{|" { count(); return(LBRAPIPE); }
"|}" { count(); return(RBRAPIPE); }
[ \t\v\n\f] { count(); }
"!!" { return(BANGBANG); }
"..." { return(ELLIPSIS); }
".." { return(DOTDOT); }
"&&&" { return(CT_AND_OP); }
"|||" { return(CT_OR_OP); }
"+++" { return(CT_CONCAT_OP); }
">>=" { return(SHR_ASSIGN); }
"<<=" { return(SHL_ASSIGN); }
"+=" { return(ADD_ASSIGN); }
"-=" { return(SUB_ASSIGN); }
"*=" { return(MUL_ASSIGN); }
"/=" { return(DIV_ASSIGN); }
"%=" { return(MOD_ASSIGN); }
"&=" { return(AND_ASSIGN); }
"^=" { return(XOR_ASSIGN); }
"|=" { return(OR_ASSIGN); }
">>" { return(SHR_OP); }
"<<" { return(SHL_OP); }
"++" { return(INC_OP); }
"--" { return(DEC_OP); }
"&&" { return(AND_OP); }
"||" { return(OR_OP); }
"<=" { return(LE_OP); }
">=" { return(GE_OP); }
"==" { return(EQ_OP); }
"!=" { return(NE_OP); }
"??" { return(OPTELSE); }
"::" { return(SCOPE); }
"?:" { return(ELVIS); }
"=>" { return(IMPLIES); }
"[<" { return(LVEC); }
">]" { return(RVEC); }
"(<" { return(LGENPAR); }
">)" { return(RGENPAR); }
"$$" { return(BUILTIN); }
";" { return(';'); }
("{") { return('{'); }
("}") { return('}'); }
"," { return(','); }
":" { return(':'); }
"=" { return('='); }
"(" { return('('); }
")" { return(')'); }
("[") { return('['); }
("]") { return(']'); }
"." { return('.'); }
"&" { return('&'); }
"!" { return('!'); }
"~" { return('~'); }
"-" { return('-'); }
"+" { return('+'); }
"*" { return('*'); }
"/" { return('/'); }
"%" { return('%'); }
"<" { return('<'); }
">" { return('>'); }
"^" { return('^'); }
"|" { return('|'); }
"?" { return('?'); }
"{|" { return(LBRAPIPE); }
"|}" { return(RBRAPIPE); }
[ \t\v\n\f] { }
. { /* ignore bad characters */ }
%%
int yywrap(void)
int yywrap(yyscan_t yyscanner)
{
return 1;
}
int column = 0;
void count(void)
{
int i;
for (i = 0; yytext[i] != '\0'; i++)
if (yytext[i] == '\n')
column = 0;
else if (yytext[i] == '\t')
column += 8 - (column % 8);
else
column++;
ECHO;
}

View File

@@ -0,0 +1,5 @@
for fn in `find ../../../c3c -name '*.c3' | sort`
do
echo -n $fn
cat $fn | ./c3yacc
done

View File

@@ -1,14 +1,15 @@
%{
#include <stdio.h>
#include "grammar.tab.h"
#include "lex.yy.h"
#define YYERROR_VERBOSE
int yydebug = 1;
extern char yytext[];
extern int column, yylineno;
int yylex(void);
void yyerror(const char *s);
void yyerror(YYLTYPE * yylloc_param , yyscan_t yyscanner, const char *yymsgp);
%}
%locations
%pure-parser
%lex-param {void *scanner}
%parse-param {void *scanner}
%token IDENT HASH_IDENT CT_IDENT CONST_IDENT
%token TYPE_IDENT CT_TYPE_IDENT
@@ -85,7 +86,6 @@ ct_castable
ct_analyse
: CT_EVAL
| CT_DEFINED
| CT_SIZEOF
| CT_STRINGIFY
| CT_IS_CONST
@@ -149,6 +149,7 @@ base_expr_assignable
| ct_call '(' flat_path ')'
| ct_vaarg '[' expr ']'
| ct_analyse '(' expression_list ')'
| CT_DEFINED '(' arg_list ')'
| CT_VACOUNT
| CT_FEATURE '(' CONST_IDENT ')'
| ct_castable '(' expr ',' type ')'
@@ -289,6 +290,7 @@ bit_stmt_expr
additive_op
: '+'
| '-'
| CT_CONCAT_OP
;
additive_expr
@@ -443,12 +445,21 @@ param_path
| param_path param_path_element
;
arg_name
: IDENT
| CT_TYPE_IDENT
| HASH_IDENT
| CT_IDENT
;
arg
: param_path '=' expr
| param_path
| type
| param_path '=' type
| param_path
| arg_name ':' expr
| arg_name ':' type
| type
| expr
| CT_VASPLAT
| CT_VASPLAT '[' range_expr ']'
| ELLIPSIS expr
;
@@ -1214,7 +1225,7 @@ module
import_paths
: path_ident
| path_ident ',' path_ident
| import_paths ',' path_ident
;
import_decl
@@ -1264,15 +1275,25 @@ top_level
%%
void yyerror(const char *s)
void yyerror(YYLTYPE * yylloc_param , yyscan_t yyscanner, const char *yymsgp)
{
fflush(stdout);
printf(":%d:%d:\n%*s\n%*s\n", yylineno, column, column, "^", column, s);
printf(":%d:%d:\n%*s\n%*s\n", yylloc_param->first_line,
yylloc_param->first_column,
yylloc_param->first_column, "^", yylloc_param->first_column, yymsgp);
}
int main(int argc, char *argv[])
{
int rc = yyparse();
int rc;
yyscan_t scanner;
rc = yylex_init (&scanner);
if(rc) {
printf(" Failed to initialize the scanner: %d\n", rc);
return rc;
}
rc = yyparse (scanner);
yylex_destroy (scanner);
printf(" -> yyparse return %d\n", rc);
return rc;
}

View File

@@ -2,6 +2,12 @@ module test;
import std::io;
import std::collections::map;
import std::os;
import libc;
fn void bye() @finalizer
{
libc::puts("Bye from finalizer!");
}
fn void test1()
{

View File

@@ -34,7 +34,7 @@ fn void testStruct()
foo = { 11, 12 };
// Named arguments
foo = createFoo(.b = 13, .a = 14);
foo = createFoo(a: 14, b: 13);
printf("Foo a:%d b:%d\n", foo.a, foo.b);
Bar bar = bitcast(foo, Bar);

View File

@@ -4,9 +4,11 @@ struct Overalign
double[<33>] x;
}
def Olist = List(<Overalign>);
fn void main()
{
List(<Overalign>) l;
Olist l;
Overalign y;
for (int i = 0; i < 1000; i++)
{

View File

@@ -8,11 +8,12 @@
#include <stdint.h>
#define MAX_BUILD_LIB_DIRS 1024
#define MAX_COMMAND_LINE_FILES 2048
#define MAX_COMMAND_LINE_FILES 4096
#define MAX_COMMAND_LINE_RUN_ARGS 2048
#define MAX_THREADS 0xFFFF
#define DEFAULT_SYMTAB_SIZE (256 * 1024)
#define DEFAULT_SWITCHRANGE_MAX_SIZE (256)
#define DEFAULT_PATH "."
typedef enum
{
@@ -52,7 +53,8 @@ typedef enum
{
SUBCOMMAND_MISSING = 0,
SUBCOMMAND_VIEW,
SUBCOMMAND_ADD
SUBCOMMAND_ADD,
SUBCOMMAND_FETCH
} ProjectSubcommand;
typedef enum
@@ -433,6 +435,7 @@ typedef struct BuildOptions_
const char *project_name;
const char *target_select;
const char *path;
const char *vendor_download_path;
const char *template;
LinkerType linker_type;
const char *custom_linker_path;
@@ -551,6 +554,7 @@ typedef struct
const char **source_dirs;
const char **test_source_dirs;
const char **sources;
const char **object_files;
const char **libdirs;
const char **libs;
const char **linker_libdirs;
@@ -717,7 +721,7 @@ extern const char *manifest_default_keys[][2];
extern const int manifest_default_keys_count;
extern const char *manifest_target_keys[][2];
extern const int manifest_target_keys_count;
extern char *arch_os_target[ARCH_OS_TARGET_LAST + 1];
extern const char *arch_os_target[ARCH_OS_TARGET_LAST + 1];
BuildOptions parse_arguments(int argc, const char *argv[]);
ArchOsTarget arch_os_target_from_string(const char *target);
@@ -730,3 +734,4 @@ void create_library(BuildOptions *build_options);
void resolve_libraries(BuildTarget *build_target);
void view_project(BuildOptions *build_options);
void add_target_project(BuildOptions *build_options);
void fetch_project(BuildOptions* options);

View File

@@ -110,7 +110,6 @@ static const char *sanitize_modes[4] = {
Project *project_load(const char **filename_ref);
BuildTarget *project_select_target(const char *filename, Project *project, const char *optional_target);
void update_feature_flags(const char ***flags, const char ***removed_flag, const char *arg, bool add);
const char *get_string(const char *file, const char *category, JSONObject *table, const char *key,
const char *default_value);

View File

@@ -4,6 +4,7 @@
#include "../utils/whereami.h"
#include "build.h"
#include "project.h"
#include "build_internal.h"
#include "git_hash.h"
@@ -17,41 +18,25 @@ static const char *current_arg;
extern const char *llvm_version;
extern const char *llvm_target;
char *arch_os_target[ARCH_OS_TARGET_LAST + 1] = {
[ANDROID_AARCH64] = "android-aarch64",
[ELF_AARCH64] = "elf-aarch64",
[ELF_RISCV32] = "elf-riscv32",
[ELF_RISCV64] = "elf-riscv64",
[ELF_X86] = "elf-x86",
[ELF_X64] = "elf-x64",
[ELF_XTENSA] = "elf-xtensa",
[FREEBSD_X86] = "freebsd-x86",
[FREEBSD_X64] = "freebsd-x64",
[IOS_AARCH64] = "ios-aarch64",
[LINUX_AARCH64] = "linux-aarch64",
[LINUX_RISCV32] = "linux-riscv32",
[LINUX_RISCV64] = "linux-riscv64",
[LINUX_X86] = "linux-x86",
[LINUX_X64] = "linux-x64",
[MACOS_AARCH64] = "macos-aarch64",
[MACOS_X64] = "macos-x64",
[MCU_X86] = "mcu-x86",
[MINGW_X64] = "mingw-x64",
[NETBSD_X86] = "netbsd-x86",
[NETBSD_X64] = "netbsd-x64",
[OPENBSD_X86] = "openbsd-x86",
[OPENBSD_X64] = "openbsd-x64",
[WASM32] = "wasm32",
[WASM64] = "wasm64",
[WINDOWS_AARCH64] = "windows-aarch64",
[WINDOWS_X64] = "windows-x64",
};
static const char *check_dir(const char *path);
static inline bool at_end();
static inline const char *next_arg();
static inline bool next_is_opt();
INLINE bool match_longopt(const char *name);
static inline const char *match_argopt(const char *name);
static inline bool match_shortopt(const char *name);
void append_file(BuildOptions *build_options);
static inline const char *match_argopt(const char *name);
void append_arg(BuildOptions *build_options);
static bool arg_match(const char *candidate);
static void parse_optional_target(BuildOptions *options);
static void add_linker_arg(BuildOptions *options, const char *arg);
static void update_feature_flags(const char ***flags, const char ***removed_flag, const char *arg, bool add);
static void print_all_targets(void);
static int parse_multi_option(const char *start, unsigned count, const char **elements);
const char *trust_level[3] = {
[TRUST_NONE] = "none",
[TRUST_INCLUDE] = "include",
[TRUST_FULL] = "full",
};
const char *arch_os_target[ARCH_OS_TARGET_LAST + 1];
const char *trust_level[3];
#define EOUTPUT(string, ...) fprintf(stderr, string "\n", ##__VA_ARGS__) // NOLINT
#define PRINTF(string, ...) fprintf(stdout, string "\n", ##__VA_ARGS__) // NOLINT
@@ -196,92 +181,6 @@ static void usage(void)
PRINTF(" --sanitize=<option> - Enable sanitizer: address, memory, thread.");
}
static const char *check_dir(const char *path)
{
static char *original_path = NULL;
if (!original_path)
{
original_path = getcwd(NULL, 0);
}
if (!dir_change(path)) error_exit("The path \"%s\" does not point to a valid directory.", path);
if (!dir_change(original_path)) FAIL_WITH_ERR("Failed to change path to %s.", original_path);
return path;
}
static inline bool at_end()
{
return arg_index == arg_count - 1;
}
static inline const char *next_arg()
{
assert(!at_end());
current_arg = args[++arg_index];
return current_arg;
}
static inline bool next_is_opt()
{
return args[arg_index + 1][0] == '-';
}
INLINE bool match_longopt(const char *name)
{
return str_eq(&current_arg[2], name);
}
static inline const char *match_argopt(const char *name)
{
size_t len = strlen(name);
if (memcmp(&current_arg[2], name, len) != 0) return false;
if (current_arg[2 + len] != '=') return false;
return &current_arg[2 + len + 1];
}
static inline bool match_shortopt(const char *name)
{
return strcmp(&current_arg[1], name) == 0;
}
void append_file(BuildOptions *build_options)
{
if (vec_size(build_options->files) == MAX_COMMAND_LINE_FILES)
{
EOUTPUT("Max %d files may be specified.", MAX_COMMAND_LINE_FILES);
exit_compiler(EXIT_FAILURE);
}
vec_add(build_options->files, current_arg);
}
void append_arg(BuildOptions *build_options)
{
if (vec_size(build_options->args) == MAX_COMMAND_LINE_RUN_ARGS)
{
EOUTPUT("Max %d args may be specified.", MAX_COMMAND_LINE_RUN_ARGS);
exit_compiler(EXIT_FAILURE);
}
vec_add(build_options->args, current_arg);
}
static bool arg_match(const char *candidate)
{
return strcmp(current_arg, candidate) == 0;
}
static void parse_optional_target(BuildOptions *options)
{
if (at_end() || next_is_opt())
{
options->target_select = NULL;
}
else
{
options->target_select = next_arg();
}
}
static void project_usage()
{
PRINTF("Usage: %s [<options>] project <subcommand> [<args>]", args[0]);
@@ -289,6 +188,9 @@ static void project_usage()
PRINTF("Project Subcommands:");
PRINTF(" view view the current projects structure");
PRINTF(" add-target <name> <target_type> add a new target to the project");
#if FETCH_AVAILABLE
PRINTF(" fetch fetch missing project libraries");
#endif
}
static void parse_project_subcommand(BuildOptions *options)
@@ -310,9 +212,13 @@ static void parse_project_subcommand(BuildOptions *options)
return;
}
if (arg_match("fetch"))
{
options->project_options.command = SUBCOMMAND_FETCH;
return;
}
PROJECT_FAIL_WITH_ERR("Cannot process the unknown subcommand \"%s\".",
current_arg);
PROJECT_FAIL_WITH_ERR("Cannot process the unknown subcommand \"%s\".", current_arg);
}
static void parse_project_options(BuildOptions *options)
@@ -323,7 +229,6 @@ static void parse_project_options(BuildOptions *options)
project_usage();
return;
}
next_arg();
parse_project_subcommand(options);
}
@@ -464,14 +369,6 @@ static void parse_command(BuildOptions *options)
FAIL_WITH_ERR("Cannot process the unknown command \"%s\".", current_arg);
}
static void print_all_targets(void)
{
PRINTF("Available targets:");
for (unsigned i = 1; i <= ARCH_OS_TARGET_LAST; i++)
{
PRINTF(" %s", arch_os_target[i]);
}
}
static void print_version(void)
{
@@ -484,61 +381,22 @@ static void print_version(void)
#endif
PRINTF("Installed directory: %s", find_executable_path());
PRINTF("Git Hash: %s", GIT_HASH);
#if LLVM_AVAILABLE && TB_AVAILABLE
PRINTF("Backends: LLVM; TB");
#elif LLVM_AVAILABLE
PRINTF("Backends: LLVM");
#elif TB_AVAILABLE
PRINTF("Backends: TB");
#else
PRINTF("No backends available");
#endif
#if LLVM_AVAILABLE
PRINTF("LLVM version: %s", llvm_version);
PRINTF("LLVM default target: %s", llvm_target);
}
static void add_linker_arg(BuildOptions *options, const char *arg)
{
if (options->linker_arg_count == MAX_BUILD_LIB_DIRS)
{
error_exit("Too many linker arguments are given, more than %d\n", MAX_BUILD_LIB_DIRS);
}
options->linker_args[options->linker_arg_count++] = arg;
}
/**
* Update feature flags, adding to one list and removing it from the other.
* @param flags the "add" flags
* @param removed_flags the "undef" flags
* @param arg the argument to add or undef
* @param add true if we add, false to undef
*/
void update_feature_flags(const char ***flags, const char ***removed_flags, const char *arg, bool add)
{
// We keep two lists "remove" and "add" lists:
const char ***to_remove_from = add ? removed_flags : flags;
// Remove from opposite list using string equality
// More elegant would be using a Set or Map, but that's overkill
// for something that's likely just 1-2 values.
FOREACH_IDX(i, const char *, value, *to_remove_from)
{
if (str_eq(value, arg))
{
vec_erase_ptr_at(*to_remove_from, i);
break;
}
}
// First we check that it's not in the list
const char ***to_add_to_ref = add ? flags : removed_flags;
FOREACH(const char *, value, *to_add_to_ref)
{
// If we have a match, we don't add it.
if (str_eq(value, arg)) return;
}
// No match, so add it.
vec_add(*to_add_to_ref, arg);
}
static int parse_multi_option(const char *start, unsigned count, const char **elements)
{
const char *arg = current_arg;
int select = str_findlist(start, count, elements);
if (select < 0) error_exit("error: %.*s invalid option '%s' given.", (int)(start - arg), start, arg);
return select;
#endif
}
static void parse_option(BuildOptions *options)
@@ -1223,7 +1081,8 @@ BuildOptions parse_arguments(int argc, const char *argv[])
}
BuildOptions build_options = {
.path = ".",
.path = DEFAULT_PATH,
.vendor_download_path = DEFAULT_PATH,
.emit_llvm = false,
.optsetting = OPT_SETTING_NOT_SET,
.debug_info_override = DEBUG_INFO_NOT_SET,
@@ -1321,3 +1180,188 @@ ArchOsTarget arch_os_target_from_string(const char *target)
}
return ARCH_OS_TARGET_DEFAULT;
}
// -- helpers
static const char *check_dir(const char *path)
{
static char *original_path = NULL;
if (!original_path)
{
original_path = getcwd(NULL, 0);
}
if (!dir_change(path)) error_exit("The path \"%s\" does not point to a valid directory.", path);
if (!dir_change(original_path)) FAIL_WITH_ERR("Failed to change path to %s.", original_path);
return path;
}
static inline bool at_end()
{
return arg_index == arg_count - 1;
}
static inline const char *next_arg()
{
assert(!at_end());
current_arg = args[++arg_index];
return current_arg;
}
static inline bool next_is_opt()
{
return args[arg_index + 1][0] == '-';
}
INLINE bool match_longopt(const char *name)
{
return str_eq(&current_arg[2], name);
}
static inline bool match_shortopt(const char *name)
{
return str_eq(&current_arg[1], name);
}
void append_file(BuildOptions *build_options)
{
if (vec_size(build_options->files) == MAX_COMMAND_LINE_FILES)
{
EOUTPUT("Max %d files may be specified.", MAX_COMMAND_LINE_FILES);
exit_compiler(EXIT_FAILURE);
}
vec_add(build_options->files, current_arg);
}
static inline const char *match_argopt(const char *name)
{
size_t len = strlen(name);
if (memcmp(&current_arg[2], name, len) != 0) return false;
if (current_arg[2 + len] != '=') return false;
return &current_arg[2 + len + 1];
}
void append_arg(BuildOptions *build_options)
{
if (vec_size(build_options->args) == MAX_COMMAND_LINE_RUN_ARGS)
{
EOUTPUT("Max %d args may be specified.", MAX_COMMAND_LINE_RUN_ARGS);
exit_compiler(EXIT_FAILURE);
}
vec_add(build_options->args, current_arg);
}
static bool arg_match(const char *candidate)
{
return str_eq(current_arg, candidate);
}
static void parse_optional_target(BuildOptions *options)
{
if (at_end() || next_is_opt())
{
options->target_select = NULL;
}
else
{
options->target_select = next_arg();
}
}
static void add_linker_arg(BuildOptions *options, const char *arg)
{
if (options->linker_arg_count == MAX_BUILD_LIB_DIRS)
{
error_exit("Too many linker arguments are given, more than %d\n", MAX_BUILD_LIB_DIRS);
}
options->linker_args[options->linker_arg_count++] = arg;
}
/**
* Update feature flags, adding to one list and removing it from the other.
* @param flags the "add" flags
* @param removed_flags the "undef" flags
* @param arg the argument to add or undef
* @param add true if we add, false to undef
*/
static void update_feature_flags(const char ***flags, const char ***removed_flags, const char *arg, bool add)
{
// We keep two lists "remove" and "add" lists:
const char ***to_remove_from = add ? removed_flags : flags;
// Remove from opposite list using string equality
// More elegant would be using a Set or Map, but that's overkill
// for something that's likely just 1-2 values.
FOREACH_IDX(i, const char *, value, *to_remove_from)
{
if (str_eq(value, arg))
{
vec_erase_at(*to_remove_from, i);
break;
}
}
// First we check that it's not in the list
const char ***to_add_to_ref = add ? flags : removed_flags;
FOREACH(const char *, value, *to_add_to_ref)
{
// If we have a match, we don't add it.
if (str_eq(value, arg)) return;
}
// No match, so add it.
vec_add(*to_add_to_ref, arg);
}
static void print_all_targets(void)
{
PRINTF("Available targets:");
for (unsigned i = 1; i <= ARCH_OS_TARGET_LAST; i++)
{
PRINTF(" %s", arch_os_target[i]);
}
}
static int parse_multi_option(const char *start, unsigned count, const char **elements)
{
const char *arg = current_arg;
int select = str_findlist(start, count, elements);
if (select < 0) error_exit("error: %.*s invalid option '%s' given.", (int)(start - arg), start, arg);
return select;
}
const char *trust_level[3] = {
[TRUST_NONE] = "none",
[TRUST_INCLUDE] = "include",
[TRUST_FULL] = "full",
};
const char *arch_os_target[ARCH_OS_TARGET_LAST + 1] = {
[ANDROID_AARCH64] = "android-aarch64",
[ELF_AARCH64] = "elf-aarch64",
[ELF_RISCV32] = "elf-riscv32",
[ELF_RISCV64] = "elf-riscv64",
[ELF_X86] = "elf-x86",
[ELF_X64] = "elf-x64",
[ELF_XTENSA] = "elf-xtensa",
[FREEBSD_X86] = "freebsd-x86",
[FREEBSD_X64] = "freebsd-x64",
[IOS_AARCH64] = "ios-aarch64",
[LINUX_AARCH64] = "linux-aarch64",
[LINUX_RISCV32] = "linux-riscv32",
[LINUX_RISCV64] = "linux-riscv64",
[LINUX_X86] = "linux-x86",
[LINUX_X64] = "linux-x64",
[MACOS_AARCH64] = "macos-aarch64",
[MACOS_X64] = "macos-x64",
[MCU_X86] = "mcu-x86",
[MINGW_X64] = "mingw-x64",
[NETBSD_X86] = "netbsd-x86",
[NETBSD_X64] = "netbsd-x64",
[OPENBSD_X86] = "openbsd-x86",
[OPENBSD_X64] = "openbsd-x64",
[WASM32] = "wasm32",
[WASM64] = "wasm64",
[WINDOWS_AARCH64] = "windows-aarch64",
[WINDOWS_X64] = "windows-x64",
};

View File

@@ -229,6 +229,43 @@ void update_build_target_with_opt_level(BuildTarget *target, OptimizationSetting
COPY_IF_DEFAULT(target->single_module, single_module);
}
static LinkLibc libc_from_arch_os(ArchOsTarget target)
{
switch (target)
{
case ANDROID_AARCH64:
case FREEBSD_X86:
case FREEBSD_X64:
case IOS_AARCH64:
case LINUX_AARCH64:
case LINUX_RISCV32:
case LINUX_RISCV64:
case LINUX_X86:
case LINUX_X64:
case MACOS_AARCH64:
case MACOS_X64:
case MINGW_X64:
case NETBSD_X86:
case NETBSD_X64:
case OPENBSD_X86:
case OPENBSD_X64:
case WINDOWS_AARCH64:
case WINDOWS_X64:
case ARCH_OS_TARGET_DEFAULT:
return LINK_LIBC_ON;
case WASM32:
case WASM64:
case MCU_X86:
case ELF_AARCH64:
case ELF_RISCV32:
case ELF_RISCV64:
case ELF_X86:
case ELF_X64:
case ELF_XTENSA:
return LINK_LIBC_OFF;
}
UNREACHABLE
}
static void update_build_target_from_options(BuildTarget *target, BuildOptions *options)
{
@@ -288,7 +325,7 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
{
if (str_eq(feature, remove_feature))
{
vec_erase_ptr_at(target->feature_list, i);
vec_erase_at(target->feature_list, i);
break;
}
}
@@ -470,6 +507,10 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
}
if (target->optsetting == OPT_SETTING_NOT_SET) target->optsetting = OPT_SETTING_O0;
update_build_target_with_opt_level(target, target->optsetting);
if (target->link_libc == LINK_LIBC_NOT_SET)
{
target->link_libc = libc_from_arch_os(target->arch_os_target);
}
}
void init_default_build_target(BuildTarget *target, BuildOptions *options)

View File

@@ -7,9 +7,8 @@ void check_json_keys(const char* valid_keys[][2], size_t key_count, const char*
{
static bool failed_shown = false;
bool failed = false;
for (size_t i = 0; i < json->member_len; i++)
FOREACH(const char *, key, json->keys)
{
const char *key = json->keys[i];
for (size_t j = 0; j < key_count; j++)
{
if (str_eq(key, valid_keys[j][0])) goto OK;
@@ -36,7 +35,7 @@ void check_json_keys(const char* valid_keys[][2], size_t key_count, const char*
const char *get_optional_string(const char *file, const char *category, JSONObject *table, const char *key)
{
JSONObject *value = json_obj_get(table, key);
JSONObject *value = json_map_get(table, key);
if (!value) return NULL;
if (value->type != J_STRING)
{
@@ -67,7 +66,7 @@ const char *get_string(const char *file, const char *category, JSONObject *table
int get_valid_bool(const char *file, const char *target, JSONObject *json, const char *key, int default_val)
{
JSONObject *value = json_obj_get(json, key);
JSONObject *value = json_map_get(json, key);
if (!value) return default_val;
if (value->type != J_BOOL)
{
@@ -79,7 +78,7 @@ int get_valid_bool(const char *file, const char *target, JSONObject *json, const
const char **get_string_array(const char *file, const char *category, JSONObject *table, const char *key, bool mandatory)
{
JSONObject *value = json_obj_get(table, key);
JSONObject *value = json_map_get(table, key);
if (!value)
{
if (mandatory)
@@ -91,9 +90,8 @@ const char **get_string_array(const char *file, const char *category, JSONObject
}
if (value->type != J_ARRAY) goto NOT_ARRAY;
const char **values = NULL;
for (unsigned i = 0; i < value->array_len; i++)
FOREACH(JSONObject *, val, value->elements)
{
JSONObject *val = value->elements[i];
if (val->type != J_STRING) goto NOT_ARRAY;
vec_add(values, val->str);
}
@@ -163,7 +161,7 @@ void get_list_append_strings(const char *file, const char *target, JSONObject *j
int get_valid_string_setting(const char *file, const char *target, JSONObject *json, const char *key, const char** values, int first_result, int count, const char *expected)
{
JSONObject *value = json_obj_get(json, key);
JSONObject *value = json_map_get(json, key);
if (!value)
{
return -1;
@@ -193,7 +191,7 @@ int get_valid_enum_from_string(const char *str, const char *target, const char *
long get_valid_integer(JSONObject *table, const char *key, const char *category, bool mandatory)
{
JSONObject *value = json_obj_get(table, key);
JSONObject *value = json_map_get(table, key);
if (!value)
{
if (mandatory)

View File

@@ -49,9 +49,8 @@ static inline void parse_library_type(Library *library, LibraryTarget ***target_
{
if (!object) return;
if (object->type != J_OBJECT) error_exit("Expected a set of targets in %s.", library->dir);
for (size_t i = 0; i < object->member_len; i++)
FOREACH_IDX(i, JSONObject *, member, object->members)
{
JSONObject *member = object->members[i];
const char *key = object->keys[i];
if (member->type != J_OBJECT) error_exit("Expected a list of properties for a target in %s.", library->dir);
check_json_keys(manifest_target_keys, manifest_target_keys_count, manifest_deprecated_target_keys, manifest_deprecated_target_key_count, member, key, "--list-manifest-properties");
@@ -115,7 +114,7 @@ static Library *add_library(JSONObject *object, const char *dir)
library->win_crt = (WinCrtLinking)get_valid_string_setting(library->dir, NULL, object, "wincrt", wincrt_linking, 0, 3, "'none', 'static' or 'dynamic'.");
get_list_append_strings(library->dir, NULL, object, &library->csource_dirs, "c-sources", "c-sources-override", "c-sources-add");
get_list_append_strings(library->dir, NULL, object, &library->cinclude_dirs, "c-include-dirs", "c-include-dirs-override", "c-include-dirs-add");
parse_library_type(library, &library->targets, json_obj_get(object, "targets"));
parse_library_type(library, &library->targets, json_map_get(object, "targets"));
return library;
}
@@ -166,12 +165,16 @@ INLINE void zip_check_err(const char *lib, const char *error)
INLINE JSONObject* read_manifest(const char *lib, const char *manifest_data)
{
JsonParser parser;
json_init_string(&parser, manifest_data, &malloc_arena);
json_init_string(&parser, manifest_data);
JSONObject *json = json_parse(&parser);
if (parser.error_message)
{
error_exit("Error on line %d reading '%s':'%s'", parser.line, lib, parser.error_message);
}
if (!json)
{
error_exit("Empty 'manifest.json' for library '%s'.", lib);
}
return json;
}

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