Compare commits

...

371 Commits

Author SHA1 Message Date
Christoffer Lerno
04695489b4 Bump version to 0.2.27 2022-07-30 02:55:32 +02:00
Christoffer Lerno
331f9b23f8 Attributes correctly checks for recursive definitions now. Added a max bitstruct size. 2022-07-30 02:55:32 +02:00
Christoffer Lerno
9886d381c0 Update allocator and resolution. 2022-07-30 02:55:32 +02:00
Christoffer Lerno
12c17b62cf Allow any expression as default expression. 2022-07-30 02:55:32 +02:00
Christoffer Lerno
2698ba1a94 Fix of expr location in args. 2022-07-27 21:21:36 +02:00
Christoffer Lerno
6f5f5feb97 Fixing distinct, typedef and bitstruct copying. Fix where global constants did not need to be constant. Bump to 0.2.26 2022-07-27 18:12:27 +02:00
Christoffer Lerno
64d883cb99 Fix bug on runtime "nameof" with optional values. Fixed issues with integer to enum casts. 0.2.25. Added enum_by_name. 2022-07-27 00:46:02 +02:00
Christoffer Lerno
1adc8b8264 Moved bitcast to builtin module. 2022-07-26 23:42:03 +02:00
Christoffer Lerno
c02ce5ce2a Better error on all upper parameter names. "Upper case" -> "uppercase" 2022-07-26 22:01:23 +02:00
Christoffer Lerno
e36e4b60e4 Fprintf changes. 2022-07-26 16:12:22 +02:00
Christoffer Lerno
1d808be4b9 Fix stdout defaults. 2022-07-26 15:07:37 +02:00
Christoffer Lerno
7065c28a08 Some fixes to string. Added fprintf and String.printf. Updated boolerr example. 2022-07-26 13:44:08 +02:00
Christoffer Lerno
da4df9d626 Less libc in example. 2022-07-26 02:21:49 +02:00
Christoffer Lerno
a7e4dda360 Added examples. 2022-07-26 02:10:18 +02:00
Christoffer Lerno
4471ccff13 String works with printf. Example cleanup. 2022-07-26 01:15:36 +02:00
Christoffer Lerno
cdff5c3e26 Dev (#500)
Single code path for kind/inner/len/sizeof on type and typeid. Fix of #493. Bump to 0.2.24. Remove ´func´ deprecated keyword. Unify builtin access. Enum and fault name reflection.
2022-07-26 00:56:59 +02:00
Christoffer Lerno
cc1bc58ed0 Allow using enums for indexing. 2022-07-24 15:39:11 +02:00
Christoffer Lerno
812bd8b3d0 Added $converable / $castable. Simplify and corrected if try/catch parsing. Fix bug with { [A] = 1 } 2022-07-24 15:10:04 +02:00
Christoffer Lerno
7e0a29ef40 Fix constant typeid comparisons. Allow methods to use & and * and constants. Improved error messages. Updated String type with generic append. 2022-07-24 15:10:04 +02:00
Christoffer Lerno
c1de3f059e Updated error messages. 2022-07-23 21:08:17 +02:00
Christoffer Lerno
62c1d2ddb5 Slicing a distinct type now returns the distinct type. 2022-07-23 20:46:21 +02:00
Christoffer Lerno
b313bec69d Fix to "typeid.kind". Conversion unsigned int -> enum fixed. @autoimport -> @builtin. Comparison macros. Bump to 0.2.21 2022-07-22 17:09:49 +02:00
Zhang Li Hui
036859c0c8 Added installation info for arch linux 2022-07-22 01:20:30 +02:00
Christoffer Lerno
56a6e0b112 Fix bug preventing implicit & on optionals. Updated priority queue to return optionals. Changed the list API to have snake case on methods. Bump to 0.2.20 2022-07-21 22:21:50 +02:00
Christoffer Lerno
18f7f35e80 More tests. 2022-07-21 21:20:03 +02:00
Christoffer Lerno
1d572f3e7c Allow distinct printthrough in printf. Added tests. 2022-07-21 18:13:11 +02:00
Christoffer Lerno
002ee006c1 More efficient int[] a = {}; Disallow zero length arrays. Bump to 0.2.19 (#489)
More efficient int[] a = {}; Disallow zero length arrays. Bump to 0.2.19. Improve error on mistyped types.
2022-07-20 22:25:03 +02:00
Christoffer Lerno
8afbccd3fe Fix bug in extension methods for generic types and typedefs. 2022-07-20 13:24:55 +02:00
David Kopec
6576725ed8 Add Binary-Heap Based Priority Queue to Standard Library (#481)
Priorityqueue
2022-07-20 12:22:43 +02:00
Christoffer Lerno
d3a053e049 Updated mangling and bump to 0.2.18 2022-07-20 12:22:03 +02:00
Christoffer Lerno
4afec24434 More advanced introspection. 2022-07-20 12:22:03 +02:00
Christoffer Lerno
29edd6e54e Fix to extension methods in other modules. Version 0.2.17 2022-07-19 14:17:00 +02:00
Christoffer Lerno
547d30eb1e Disallow complist as a regular macro parameter. 2022-07-18 01:22:29 +02:00
Christoffer Lerno
6cf3c9f46b Fix in nested block handling. @maydiscard and @nodiscard annotations. If the common type of int[x] and int[y] is int[] 2022-07-17 19:48:24 +02:00
Christoffer Lerno
4beb7eff8f Add support for : slices. Version bumped to 0.2.16 2022-07-17 19:48:24 +02:00
Christoffer Lerno
48a31cfa48 Fix of error where {| |} with value return could have no final return. 2022-07-17 19:48:24 +02:00
Christoffer Lerno
cd1138447e Update math.matrix.c3
Change module to std::math.
2022-07-16 15:33:09 +02:00
PixelRifts
c29ad77cdb Matrix Math Library 2022-07-16 15:33:09 +02:00
Christoffer Lerno
1c15ebe6d2 Fix of bug using ".len" 2022-07-16 12:09:12 +02:00
Christoffer Lerno
a68efec5e8 Added swap and list swap to stdlib. 2022-07-14 14:58:11 +02:00
Christoffer Lerno
3f6b0646b3 An initial printf. Added type.inner and type.len. Bump to 0.2.15 2022-07-14 02:43:53 +02:00
Christoffer Lerno
28a8e17690 Vararg abi fix. Version bumped to 0.2.14 2022-07-13 14:19:09 +02:00
Christoffer Lerno
2a7d46844a Fix "libs" in project creation. 2022-07-13 09:50:51 +02:00
Christoffer Lerno
92542ac1f9 Fix bug with bit struct initialization and zeros. Allow float mod. Add float.max/min. Version bumped to 0.2.13 2022-07-13 00:13:34 +02:00
Christoffer Lerno
59b41f8deb Reduce size of memory pages used. 2022-07-12 13:09:45 +02:00
Christoffer Lerno
abfccb5576 Fix issues with union of const. Bump version 0.2.12 2022-07-11 17:58:11 +02:00
Christoffer Lerno
ea5d7cd2e7 Fixes initialization of anonymous structs. Bump version 0.2.11 2022-07-10 23:29:05 +02:00
Christoffer Lerno
ca21b1daac Allow [in] to be used on subarray types. Added more to "conv" module. 2022-07-09 19:32:39 +02:00
Christoffer Lerno
9fdd66af42 Fix of distinct void* and null. Version bumped to 0.2.10 2022-07-08 17:16:44 +02:00
Christoffer Lerno
d403912ec7 Add linker and linked dir arguments to build files. 2022-07-08 14:52:58 +02:00
Christoffer Lerno
05f222616e Fix of default project creation target format. 2022-07-07 18:17:41 +02:00
Christoffer Lerno
253dbf3603 Remove std::mem 2022-07-07 18:14:36 +02:00
Christoffer Lerno
cfbfc29e84 Fix of $sizeof(Type) => Type.sizeof 2022-07-07 15:51:40 +02:00
Christoffer Lerno
bb020a1752 Add a windows install instruction. 2022-07-07 15:02:48 +02:00
Christoffer Lerno
c8a614e43f LLVM 15 compatibility fixes (#465)
More variant code. Fixes to typekind. Fixes to macro with failable returns. Remove use of LLVMConstInsert etc. Version 0.2.8
2022-07-06 16:41:52 +02:00
Christoffer Lerno
bb28f6e61c Fix stack setting after error return. Some fixes to examples. 2022-07-02 10:54:40 +02:00
Christoffer Lerno
b1d83e2ccd Auto-import std::core. Fix module assignment of declarations. Introspection improvements. Deref null error panics in safe mode. Support for LLVM 15 2022-06-29 21:57:35 +02:00
Christoffer Lerno
df41caabdd Global @align fixed #446. 2022-06-04 23:19:27 +02:00
Christoffer Lerno
2f5d51c92c Attempt to add more native file handling for MSVC (#459)
* Fix clean and update MSVC function calls.
2022-06-04 21:32:35 +02:00
Christoffer Lerno
224390ce5a Make builtins loaded by default. 2022-06-04 01:41:23 +02:00
Christoffer Lerno
09d50ebf6c New import rules. 2022-06-04 01:41:23 +02:00
Christoffer Lerno
2d608a4d51 Change TB dir and do debug printout by default. 2022-05-22 14:54:18 +02:00
Christoffer Lerno
d511f150a7 Add lld linking for FreeBSD. 2022-05-22 14:54:18 +02:00
Christoffer Lerno
f4dc4f64f2 Change TB dir and do debug printout by default. 2022-05-21 20:09:09 +02:00
Christoffer Lerno
6035cb4600 Update TB 2022-05-21 19:57:11 +02:00
Christoffer Lerno
3d1eaad6b9 Update file_utils.c 2022-05-18 22:30:07 +02:00
Christoffer Lerno
ca2bb505b6 Merge pull request #453 from matkuki/patch-1
Update CMakeLists.txt
2022-05-16 15:07:07 +02:00
matkuki
8b4b4273cc Update CMakeLists.txt
Fixes compilation error on Visual Studio 2022
2022-05-16 14:10:28 +02:00
Christoffer Lerno
7c91c56f3d Updated cmake with latest win-llvm (#451)
Updated cmake with latest win-llvm
2022-05-15 19:41:12 +02:00
Christoffer Lerno
5edafc5b2f Test for #149 ct lists. 2022-05-12 19:13:49 +02:00
Christoffer Lerno
dbb0dc302d Add instructions for building on Unix variants. 2022-05-12 09:53:05 +02:00
Christoffer Lerno
e09e5c06d3 User defined attributes. 2022-05-11 20:55:09 +02:00
Christoffer Lerno
b0c55ff777 Support enum associated values. 2022-05-11 20:55:09 +02:00
Christoffer Lerno
60832019bd Merge pull request #445 from c3lang/dev
Updated enums, macro usage / naming
2022-05-09 14:06:34 +02:00
Christoffer Lerno
42b5445225 Fixes enum set with new ordinal based enums. 2022-05-09 12:25:33 +02:00
Christoffer Lerno
9691d50a6f @ is now part of the name of an attribute or a macro. Macros without '@' must be function-like. 2022-05-08 22:16:33 +02:00
Christoffer Lerno
29a9769651 Ordinal based enums. 2022-05-08 21:39:00 +02:00
Christoffer Lerno
15e1db78a7 Remove unused code. 2022-05-02 16:35:14 +02:00
Christoffer Lerno
2f23d56a12 0.2.1 Update
0.2.1 SysV ABI fix for passing certain things by struct. Fix implicit…
2022-04-27 17:06:26 +02:00
Christoffer Lerno
22ee082d00 0.2.1 SysV ABI fix for passing certain things by struct. Fix implicitly converting to float in the case of myfloat *= -1. Prefer inferred constant over global. Allow locals to shadow global variables. 2022-04-27 16:43:25 +02:00
Christoffer Lerno
212bc7d9af Merge pull request #437 from c3lang/dev
0.2.0. Build system improvements. Target changes x64-windows -> windo…
2022-04-26 13:40:43 +02:00
Christoffer Lerno
890c4bc435 0.2.0. Build system improvements. Target changes x64-windows -> windows-x64, x64-darwin -> macos-x64. Improved mac support. LLD linking for Mac, Windows, Linux. Cross linking for Mac, Windows. Clean up string use. Fix of debug handling of multiple compilation units per module. MSVC CI 2022-04-26 13:20:33 +02:00
Christoffer Lerno
7df7dd2933 Merge pull request #436 from data-man/ci_testing
Use Ninja in CI
2022-04-17 11:09:00 +02:00
data-man
ada8652209 Use Ninja in CI 2022-04-16 15:25:48 +05:00
Christoffer Lerno
bf8288ed1c Merge pull request #435 from data-man/fix_typo
Fix typo in sema_expr.c [skip ci]
2022-04-16 11:19:30 +02:00
data-man
9b6e4f9d11 Fix typo in sema_expr.c [skip ci] 2022-04-16 13:12:14 +05:00
Christoffer Lerno
ecdcd8f959 0.1.1: Add -L and -l parameters, also incomplete support of .c3i files. 2022-04-15 18:52:36 +02:00
Dmitry Atamanov
828724f593 Add more vector tests (#430)
* Add more vector tests
* Added .ll output.
Co-authored-by: Christoffer Lerno <christoffer@aegik.com>
2022-04-14 09:55:11 +02:00
data-man
f6eb20f725 Fix resource leak in check_file function 2022-04-13 10:17:14 +02:00
data-man
ade4065480 Add LLVM 13 to MacOS CI 2022-04-10 09:50:53 +02:00
Christoffer Lerno
b19cef4bc1 Removed some accidental commits. 2022-04-09 20:13:41 +02:00
Dmitry Atamanov
151cbfd706 Semi-implemented foreach for vectors (#423)
Implement foreach for vectors
2022-04-09 20:09:35 +02:00
Christoffer Lerno
b99db4be24 Allocators. Rename of "optenum" to fault. Memcpy and memset added. Cleanup of declaration use. 2022-04-09 20:07:59 +02:00
Christoffer Lerno
8743223dd6 Allocators. Rename of "optenum" to fault. Memcpy and memset added. Cleanup of declaration use. 2022-04-09 20:07:59 +02:00
Christoffer Lerno
2e2a1ca21a Fix defer with static variables. 2022-03-31 10:11:37 +02:00
Christoffer Lerno
34bd5fa6da Fix of macro defer with bodies. 2022-03-28 10:19:24 +02:00
Christoffer Lerno
131bf5ed34 Cleanup and change of varcast. 2022-03-27 13:22:04 +02:00
Christoffer Lerno
78134316b7 Addin @varcast 2022-03-27 13:09:06 +02:00
Christoffer Lerno
b31629c5e8 Removal of "or_else jump". Fixes to defer & macros/blocks, optimized failable return. @noscope macros removed. Disallow meaningless defer.
Correctly show error on return or rethrow inside of a defer. Fix copying an access expression. Removing scoped expr.
2022-03-26 20:16:36 +01:00
data-man
bbfc2fc8ab Update checkout action to v3 2022-03-23 21:15:52 +01:00
gdm85
1940f6967c Add support for podman
Use a tmpfs when running
Prefix podman images with 'localhost/'
2022-03-23 18:44:46 +01:00
data-man
adf2b2e818 Update build-with-docker.sh [skip ci] 2022-03-23 16:48:46 +01:00
Christoffer Lerno
6a9b14d107 Added regression test for errors. 2022-03-21 18:18:14 +01:00
Christoffer Lerno
8b8a8d81db Fix of issue with "a ?? false" 2022-03-21 13:22:59 +01:00
data-man
d1fadf6428 Don't replace digits to underscore in created files 2022-03-20 19:41:30 +01:00
Christoffer Lerno
05d8e6c7b8 Fix debug panic for vector shift and division. 2022-03-20 19:39:31 +01:00
Christoffer Lerno
6789fab93c Panic function that may be redefined. Trap and stacktrace builtins. Bug using builtin fixed. Fixes to using $$LINE and friends. Produces a stacktrace on error. 2022-03-18 12:43:17 +01:00
Christoffer Lerno
3490814d73 Simplify scope flags. 2022-03-13 22:49:10 +01:00
Christoffer Lerno
3799dbb082 Use declid instead of decl* in the decltable. 2022-03-12 14:45:54 +01:00
Christoffer Lerno
60d7c8aa14 Add timings. 2022-03-12 02:35:07 +01:00
Christoffer Lerno
55598b2de8 Remove multi-line strings. 2022-03-12 00:40:06 +01:00
Christoffer Lerno
4fe2a70ee1 Only add dll visibility on external functions for win32. 2022-03-11 13:27:01 +01:00
Christoffer Lerno
ab56b2d047 Only add dll visibility on non-local functions for win32. 2022-03-11 13:05:46 +01:00
Christoffer Lerno
1061b4e1dd Make doc an AST type. 2022-03-11 12:24:07 +01:00
Christoffer Lerno
e02362de0c Resolve contracts as they are encountered. 2022-03-11 11:17:39 +01:00
Christoffer Lerno
c414459075 Fix bug with missing debug location. 2022-03-10 15:55:44 +01:00
Christoffer Lerno
8f6fb8b7d7 Move body param as decl. Fix lexer bug with docs. 2022-03-10 14:54:52 +01:00
Christoffer Lerno
fc296ea579 Extracted macro declaration body to separately allocated field. 2022-03-10 14:54:52 +01:00
Christoffer Lerno
4258fe4d01 Simple check for [in] and [out] parameters. 2022-03-10 12:46:45 +01:00
Christoffer Lerno
0565e87e5e Support '@pure' and parse the optreturn tag. 2022-03-10 09:46:30 +01:00
Christoffer Lerno
6a48f81485 Smaller Decl and Expr. Compressed TypeInfo. 2022-03-09 19:10:11 +01:00
Christoffer Lerno
322d714305 Dev (#404)
Remove 'errtype' name and reduce Expr / TypeInfo memory footprint.
2022-03-08 23:38:27 +01:00
Christoffer Lerno
069a2d40cb Changing how defer works. Remove of undef. Simplify ensure. 2022-03-08 14:15:31 +01:00
Christoffer Lerno
9b0dfe8ba3 Cleanup: remove CT_ELIF ast node. 2022-03-04 17:08:47 +01:00
Christoffer Lerno
2802b2b96d Ensure, $eval and $evaltype, @unreachable() replaces $unreachable. <Type>.sizeof 2022-03-04 15:49:17 +01:00
Christoffer Lerno
4f4bc80953 Symtab has a new hash map type. New, small, sourcespan, external symbols simplified. Updated docs. 2022-03-01 10:32:52 +01:00
data-man
e45853c0cb Update README [skip ci] 2022-03-01 09:55:34 +01:00
Christoffer Lerno
f54a93890a Remove the EXPR_CONST_IDENTIFIER 2022-02-18 13:56:13 +01:00
Christoffer Lerno
6b4e4f6114 Update formatting to consistently use tabs. 2022-02-18 12:56:17 +01:00
Christoffer Lerno
bf5683b41c General cleanup, more native platform detection. 2022-02-18 09:54:12 +01:00
Christoffer Lerno
73351e0aa9 Updated version for implicit imports. 2022-02-16 20:42:39 +01:00
Christoffer Lerno
df3e51c17e Implicit imports. 2022-02-16 20:41:54 +01:00
data-man
d11d80e896 Update --list-precedence table 2022-02-15 18:55:02 +01:00
Christoffer Lerno
7226bff6ea Use JSON, unifying settings. 2022-02-15 18:53:54 +01:00
Christoffer Lerno
fd82f9685f Make target from string case dependent. 2022-02-15 18:53:54 +01:00
Christoffer Lerno
c70d6716da Added second missing unreachable. 2022-02-08 11:54:19 +01:00
Christoffer Lerno
e57c2710d9 Added missing unreachable. 2022-02-08 11:48:43 +01:00
Christoffer Lerno
d42193dbd6 Fixes the alloca alignment on x64 for alignment > 16. Improved indexing into ConstInitializer adding const indexing into a const array during compile time. Add a temporary enum values result. 2022-02-08 11:41:34 +01:00
Dmitry Atamanov
9f9f24c3cc CI config refactoring (#389) 2022-02-08 11:05:38 +01:00
data-man
f3e326fcd9 CI config refactoring 2022-02-05 22:26:53 +01:00
Christoffer Lerno
ee32a5fd47 Added $stringify. Remove of editor_plugin folder. 2022-02-02 15:22:28 +01:00
Christoffer Lerno
06917f2e65 Added "guess a number". Fix CT enum / int comparison. Fix some array pointer decay scenarios. Infer type of expression blocks. Correctly merge anyerr. 2022-02-01 22:46:32 +01:00
Christoffer Lerno
ba66aaaf12 Foreach overload is now done using attributes (@operator(elementat), @operator(elementref) and @operator(len)) rather than reserved functions. 2022-01-29 16:45:03 +01:00
data-man
9639ad6a73 Move fail-fast above 2022-01-29 10:38:19 +01:00
Christoffer Lerno
cf56825d26 Fixed bug when using indexing on a generic type. Made array::list::List work with [] and foreach. 2022-01-26 21:27:13 +01:00
Christoffer Lerno
e5bcb74822 Added levenshtein.c3 to working files. Fixes to reverse indexing. Added min/max functions. Tentatively removed "opaque" 2022-01-26 17:40:01 +01:00
Christoffer Lerno
8eb295bf5b Cleanup. 2022-01-25 17:01:49 +01:00
Christoffer Lerno
bd6c3db413 Disable MSYS tests and add MacOS tests. 2022-01-25 16:58:08 +01:00
Christoffer Lerno
21fd2c4485 Update to LLVM fix. 2022-01-25 15:14:22 +01:00
Christoffer Lerno
bc8fbdb54a Fix LLVM 14 compatibility 2022-01-25 15:11:02 +01:00
Christoffer Lerno
8922399c36 Add $for 2022-01-24 22:52:01 +01:00
Christoffer Lerno
1e7ad2e241 Add $foreach 2022-01-24 18:53:44 +01:00
Christoffer Lerno
4f212f7634 Remove a gazillion imports. 2022-01-24 14:53:38 +01:00
Christoffer Lerno
2c5ae858b8 Re-add () to ct constructs. 2022-01-24 00:52:43 +01:00
Christoffer Lerno
ef95c1a630 Fix $switch. And make top level $switch work. 2022-01-24 00:01:54 +01:00
Christoffer Lerno
b2be8349ed Add typeless varargs. 2022-01-23 19:43:57 +01:00
Christoffer Lerno
01e9086666 Add precedence listing. 2022-01-22 17:31:33 +01:00
Christoffer Lerno
66b763193d Use O1 on CXX release to avoid issues. 2022-01-21 02:22:58 +01:00
Christoffer Lerno
36e40e59cb Added enumset to stdlib. 2022-01-20 20:00:22 +01:00
Christoffer Lerno
dce33ba5b5 Fixing #380 where const aggregates were copied by value. 2022-01-20 16:52:28 +01:00
Christoffer Lerno
ec291d4a9d This allows testing optnum, optenum, errnum and resnum as alternatives to errtype. 2022-01-19 23:21:17 +01:00
Christoffer Lerno
e6ad9c324d This fixes the bug with "case 3 .. 1" #357 2022-01-19 23:11:03 +01:00
Christoffer Lerno
3450016978 This adds the ability to list keywords, operators etc. implementing #350. 2022-01-19 13:11:12 +01:00
Christoffer Lerno
827499ca80 Update version to reflect recent changes. 2022-01-18 23:32:59 +01:00
Christoffer Lerno
556be2ff7f "@autoimport" attribute #366 2022-01-18 23:16:48 +01:00
Christoffer Lerno
8adb0faa06 Multi module import support. #354 2022-01-18 22:53:31 +01:00
Christoffer Lerno
b6450861d2 Cast no longer needs (type)(expr) format. Ordinary C (type)expr now works. 2022-01-18 22:32:12 +01:00
Christoffer Lerno
1e56948a22 Prepare removing "func" 2022-01-18 14:15:44 +01:00
Christoffer Lerno
e4e8abbc6c Dev (#376)
Errno updates with errno for linux/win/macos. Updated $$ syntax to also match compiler constants.
2022-01-18 01:31:14 +01:00
Christoffer Lerno
3f60443d66 Update errno. 2022-01-17 22:28:06 +01:00
Christoffer Lerno
f53dd95aa7 Update errno. 2022-01-17 22:24:52 +01:00
Christoffer Lerno
1743036104 Added some File functionality. 2022-01-17 22:16:29 +01:00
Christoffer Lerno
a2fa61f58b Updated licensing information. 2022-01-17 17:18:22 +01:00
Christoffer Lerno
4059d22315 Remove unnecessary load in LLVM statement lowering. Added more tests from Clang. 2022-01-17 17:08:28 +01:00
Christoffer Lerno
05f0059b1b Fix float conversion. Strings as array initializers work much better. 2022-01-17 16:06:17 +01:00
Christoffer Lerno
bc3b58b3e3 Optimized ternary where both branches are empty. 2022-01-17 12:01:27 +01:00
Christoffer Lerno
99ea0afcbf Optimize multiple int casts on ptrtoint, into a single cast. Fixed incorrect widening cast from signed -> unsigned. 2022-01-17 00:45:26 +01:00
Christoffer Lerno
23461b179f More splitting of the AbiArgInfo to make it easier to find duplicate behaviour. 2022-01-16 16:21:55 +01:00
Christoffer Lerno
d916f111b3 Fixes a | b when a | b are boolean. Fixes to RISCV and x64 ABI implementations. 2022-01-16 01:13:43 +01:00
Christoffer Lerno
0f4a43717e Fixes to the aarch64 ABI. 2022-01-15 01:37:43 +01:00
Christoffer Lerno
c5a862f4d1 Fix to the x64 ABI. More tests. 2022-01-14 21:30:29 +01:00
Christoffer Lerno
fb22a36aa9 Fix of #374. Even more "or" LLVM 14 fixes. 2022-01-13 21:51:19 +01:00
Christoffer Lerno
889bc27800 Skip "or with zero" 2022-01-13 21:38:24 +01:00
Christoffer Lerno
eed5b7db54 Correctly call x64 varargs. 2022-01-13 21:22:50 +01:00
Christoffer Lerno
5683fe3f8c Add parsing for escaping and remove "fault" token name. Allow excluding stdlib. Fixes to the x64 abi: no narrowing done for i32 results, assuming too many registers, more tests. 2022-01-12 23:56:59 +01:00
data-man
684ad9e663 Disable mimalloc by the option 2022-01-11 17:32:06 +01:00
Christoffer Lerno
a6b29bccb7 Somewhat smaller SymEntry. Different mixing function in stables. 2022-01-10 22:05:56 +01:00
Christoffer Lerno
71623a1874 Minor bugfix. 2022-01-10 18:59:29 +01:00
Christoffer Lerno
16179d2513 Make it easier to match LLVM 14 output. 2022-01-10 14:50:57 +01:00
Dmitry Atamanov
fd8cd6a8e2 Use several LLVM versions in CI (#369)
* Use several LLVM versions in CI
2022-01-10 14:40:55 +01:00
Christoffer Lerno
180b17b213 Updated with latest TB. 2022-01-10 14:38:31 +01:00
Christoffer Lerno
4764981708 Update cols for warning and prev as well. 2022-01-10 14:08:23 +01:00
Disheng Su
3cf057ff95 Print file's full path and col number in compiler's error message 2022-01-10 14:06:29 +01:00
Christoffer Lerno
ea3b50d039 Codegen with better annotations on globals. 2022-01-10 13:58:15 +01:00
Christoffer Lerno
041c096801 Refactored some of the llvm lowering. Work on TB. Disabled mimalloc due to issues with LLVM. 2022-01-09 21:23:37 +01:00
Dmitry Atamanov
d942dfbc99 Support build with mimalloc (#348)
* Support build with mimalloc

* Use latest stable tag
2022-01-07 19:18:25 +01:00
Christoffer Lerno
a176ae353b Refactored function pointer. 2022-01-07 19:13:07 +01:00
Christoffer Lerno
8a840746f6 Compound statements are linked lists. Remove unused "global_symbols" "public_symbols" "qualified_symbols". Reduce max hash map load. 2022-01-05 19:40:44 +01:00
Christoffer Lerno
869aa7ed76 Do not store direct parameters that are only read. 2022-01-04 23:16:32 +01:00
Christoffer Lerno
1d5ff71b21 Rearchitecture contexts. Fixing macro resulution, hash arguments and defers. 2022-01-04 20:45:58 +01:00
Christoffer Lerno
439ae3e468 Satisfy GCC checks. 2022-01-03 12:35:42 +01:00
Christoffer Lerno
8f2ae41ea5 Removed allocation of AbiType. Separate string arena. 2022-01-03 12:19:46 +01:00
Christoffer Lerno
fd1353f0f1 Removed scratch hash table use for parameter checks. Faster symtab setup. Scrubbed the lexer somewhat without changing behaviour. 2022-01-01 22:08:07 +01:00
Christoffer Lerno
bbeed12600 Removing unused hash table functions. Removal of macro DECL_NEW. Smaller initial vector size. Remove unnecessary memclear. 2021-12-30 16:41:00 +01:00
Christoffer Lerno
0a7200ac24 Symtab default size change, some minor cleanup. 2021-12-29 23:36:15 +01:00
Christoffer Lerno
f509c85514 Update hello_world 2021-12-29 14:38:47 +01:00
Christoffer Lerno
06d3bc8915 Release symtab after use. 2021-12-29 13:34:36 +01:00
Christoffer Lerno
a0be188902 Lexing updated with simpler code. Note: may have bugs. 2021-12-27 15:45:54 +01:00
Christoffer Lerno
0a9a014e4a Builtins now properly work with $defined. A builtin may not be an rvalue. 2021-12-25 21:08:08 +01:00
Christoffer Lerno
85ee021585 Adding missing symtab size option. 2021-12-24 23:15:50 +01:00
Christoffer Lerno
f6de1f7b74 Somewhat clearer code around lexing. 2021-12-24 01:09:21 +01:00
Christoffer Lerno
cf61f427d4 Add noalias to sret. 2021-12-23 13:26:55 +01:00
Christoffer Lerno
eb54e46569 Add necessary header for cmalloc 2021-12-22 13:09:01 +01:00
Christoffer Lerno
cf0a04977a Prevent circular initializers. 2021-12-22 01:03:15 +01:00
thsm
1a9b8095b6 added {| |}, etc to vscode syntax highlighter 2021-12-22 00:41:36 +01:00
pyxel
012f258fa2 add vscode syntax plugin 2021-12-21 22:52:53 +01:00
Christoffer Lerno
eefe782dd6 Fix constant evaluation of | & ^ >> << 2021-12-20 21:35:36 +01:00
Christoffer Lerno
6f77fdf800 Update assert for WASM part 3 2021-12-20 02:43:36 +01:00
Christoffer Lerno
8f6dd64483 Update assert for WASM part 2 2021-12-20 02:35:01 +01:00
Christoffer Lerno
04c3efc3c3 Update assert for WASM 2021-12-20 00:32:27 +01:00
Christoffer Lerno
4575e3dd8d Fix fseek/ftell to work correctly. 2021-12-20 00:23:21 +01:00
Christoffer Lerno
b5b625e54a Make sure normal flags aren't ignored for release. 2021-12-20 00:05:51 +01:00
Christoffer Lerno
52cc4f8ba5 Move compiler plain malloc calls to function to make them easy to track. 2021-12-19 23:11:32 +01:00
Christoffer Lerno
4e559e886c Add some simple string functions. And fix bug relating to typedefs. 2021-12-19 21:04:43 +01:00
Dmitry Atamanov
802398dd44 Show option like clang (#355) 2021-12-19 17:23:42 +01:00
Christoffer Lerno
7c76fd02c6 Fix test data 2021-12-19 16:33:07 +01:00
Christoffer Lerno
dee0199f10 Add compiler options to simplify external tool usage. 2021-12-19 16:25:48 +01:00
Christoffer Lerno
5cbc619f13 .obj / .exe default suffix now depends on target, not compiler platform. 2021-12-19 13:11:43 +01:00
pyxel
01902b523a Use supplied output name if available 2021-12-19 12:21:32 +01:00
pyxel
157d1a959b Add output name to build options 2021-12-19 12:21:32 +01:00
Christoffer Lerno
4b3232ead6 Some initial wasm support. 2021-12-19 12:18:43 +01:00
Christoffer Lerno
cc8d266827 Temp fix of CI 2021-12-18 22:21:54 +01:00
Christoffer Lerno
6d6d410d13 Update nano type/keywords. 2021-12-18 17:19:09 +01:00
Hanna
6b34a8c82e add kakoune editor resource 2021-12-18 17:00:30 +01:00
data-man
c39c7c3147 Update actions/checkout to v2 2021-12-17 20:43:00 +01:00
data-man
d360e97439 CMakeLists.txt refactoring 2021-12-17 16:08:35 +01:00
Christoffer Lerno
d305f9da49 Remove manual addition of ConstGEP2 etc 2021-12-17 16:00:18 +01:00
Christoffer Lerno
572aafe8b9 Remove use of LLVMBuildCall 2021-12-17 15:45:09 +01:00
Christoffer Lerno
c52629d60f Main arguments are now slices if desired. 2021-12-17 01:28:57 +01:00
Christoffer Lerno
497eef5328 Removed code relating to empty structs. 2021-12-14 21:37:25 +01:00
Christoffer Lerno
680b077eb1 Flexible array member added, zero sized structs removed. 2021-12-14 19:00:33 +01:00
Christoffer Lerno
5ddbf50e83 Add unwrapping to variable for variant in switch. 2021-12-12 15:15:38 +01:00
thsm
908ac220c6 add cflags 2021-12-10 16:12:54 +01:00
Christoffer Lerno
958db2f594 Fix issue when compiling without cc set. 2021-12-09 23:54:57 +01:00
Christoffer Lerno
8aa00b015b Add support from compiling c from c3c. 2021-12-09 23:38:57 +01:00
Christoffer Lerno
379a66a14b Add switch(variant) 2021-12-09 22:52:48 +01:00
Christoffer Lerno
0887d1e7dc Allow /* without termination. 2021-12-09 10:32:30 +01:00
Christoffer Lerno
4a6f587c9f Incorrectly would do constant indexing into global when index was not constant. 2021-12-09 10:26:46 +01:00
Christoffer Lerno
e54679c01e Remove string literals. 2021-12-09 02:15:05 +01:00
Christoffer Lerno
4bc47a195b Introduce array pointer decay. 2021-12-09 00:49:50 +01:00
Christoffer Lerno
b003b05d5d Support variant.ptr and subarray.ptr 2021-12-08 16:14:29 +01:00
Christoffer Lerno
b066c25432 Remove reminder logs unless --debug-log on. Fix UB in test. 2021-12-07 22:20:35 +01:00
Christoffer Lerno
bbda3a679f Fixed issue where &foo[1] was not considered a constant when foo is a global. 2021-12-06 23:13:48 +01:00
Christoffer Lerno
49efa4fafc Missing \n in output. 2021-12-06 09:19:37 +01:00
Christoffer Lerno
4153cbe16d Change semantics of widening. 2021-12-05 23:41:45 +01:00
Christoffer Lerno
d6d4c0a912 Fix of init error. 2021-12-05 22:50:27 +01:00
Christoffer Lerno
06124ddb9f Support variant type. Add fault alias to anyerr. Fix missing .len on string literals. 2021-12-05 22:34:21 +01:00
Christoffer Lerno
e1fc028694 Remove eager readahead. 2021-12-04 01:20:27 +01:00
Christoffer Lerno
a9c2e59f60 Fix incorrect check in macro arguments. 2021-12-04 01:08:16 +01:00
Christoffer Lerno
eb81c00ada Fix failed parsing of ct_assert 2021-12-04 01:00:33 +01:00
Christoffer Lerno
26325f0fd2 Incorrect size of binop_preq_req array. 2021-12-04 00:30:47 +01:00
Christoffer Lerno
910b2179f9 Updates to base64 parsing. 2021-12-04 00:25:55 +01:00
Christoffer Lerno
e20e6071c8 Fix hex sequence escape. 2021-12-03 17:29:25 +01:00
Christoffer Lerno
cae1933f0f Early escape in reading invalid escape sequence. 2021-12-03 17:06:52 +01:00
Christoffer Lerno
bc2d789c2e Filter \r before lexing. 2021-12-03 16:43:37 +01:00
Christoffer Lerno
2c802878bb Fix overread on base64. 2021-12-03 16:00:20 +01:00
Christoffer Lerno
c4595d3024 Fix overread on failed string escape. 2021-12-03 15:55:22 +01:00
Christoffer Lerno
20ea6421cc Fix displaying error on first column. 2021-12-03 13:49:28 +01:00
Christoffer Lerno
f3c3636ac7 Fix bug in parsing exponent. 2021-12-03 13:07:05 +01:00
Christoffer Lerno
5a467f11ca Fix bug in parsing of binary, oct and hex 2021-12-03 11:41:44 +01:00
Christoffer Lerno
eef5e1b498 Fix detection of EOF and \n in string. 2021-12-03 00:48:12 +01:00
Christoffer Lerno
60b17004a4 Backtrack on finding ` with "next" 2021-12-03 00:31:46 +01:00
Christoffer Lerno
6ff05bae6d Backtrack on finding eof with "next" 2021-12-03 00:02:47 +01:00
Christoffer Lerno
5d30189626 Move float parsing to parser. 2021-12-02 23:42:52 +01:00
Christoffer Lerno
1bb9c2d249 Allow the compiler to be called multiple times (while leaking) 2021-12-02 22:50:38 +01:00
Christoffer Lerno
e31d189837 Fix of issue of with generic typedefs. 2021-12-01 16:24:59 +01:00
Christoffer Lerno
aa7da00323 Support for ranged case. 2021-11-30 15:35:56 +01:00
Theo
74fa81336f Smarter windows library path detection (#339)
add support for visual studio 2022 preview, switch to using smarter windows library path detection
2021-11-30 09:44:51 +01:00
Christoffer Lerno
3242bcabc0 Do-while uses for codegen and somewhat smaller llvm codegen 2021-11-28 01:35:09 +01:00
Christoffer Lerno
164a1ef59d Initial foreach implementation based on index 2021-11-27 00:57:27 +01:00
Christoffer Lerno
17a03bc104 Added rudimentary operator overload. 2021-11-27 00:57:27 +01:00
Christoffer Lerno
8d4d3b4d5b Ensure value semantics. 2021-11-22 22:11:03 +01:00
Christoffer Lerno
9a7b9bb7a4 Remove methods from "distinct" 2021-11-22 21:13:08 +01:00
Christoffer Lerno
1ba03f75c2 Fix debug parameter definition. Array foreach GEP. 2021-11-22 21:03:00 +01:00
Christoffer Lerno
7595f2e17b Fix of incorrect visibility. Use of LLVMInstructionRemoveFromParent. 2021-11-22 14:14:07 +01:00
C34A
90898d6ed6 add support for visual studio 2022 preview 2021-11-22 08:00:53 +01:00
Christoffer Lerno
aafa0d08a2 Removing -Wconversions 2021-11-22 00:07:06 +01:00
Christoffer Lerno
3c9761c946 Explicit insert 2021-11-22 00:04:01 +01:00
Christoffer Lerno
05c9b7cb33 More explicit conversion and width changes to some field. 2021-11-21 23:37:54 +01:00
Christoffer Lerno
bb39cf20c0 Removal of #pragma mark, explicit conversions. 2021-11-21 21:43:06 +01:00
Christoffer Lerno
dad8cd24b1 No implicit narrowing. 2021-11-21 21:19:12 +01:00
Christoffer Lerno
39b1b59011 Removal of #pragma mark for better compiler compatibility 2021-11-21 21:15:05 +01:00
Christoffer Lerno
685688f884 Change arena macro. 2021-11-21 21:11:19 +01:00
Christoffer Lerno
a1b69a3f50 Casting between vector and array. Check f16 overflow. 2021-11-20 03:44:50 +01:00
Christoffer Lerno
f1f268df4a Fix of test. 2021-11-19 15:39:02 +01:00
Christoffer Lerno
6febd8a143 Optimized assign of failable. 2021-11-19 13:29:43 +01:00
Christoffer Lerno
8cc8c321a2 Optimized rethrow expr. Fix to "Foo! x = {}" which would break. Remove unnecessary zeroing failables. Variables that are undefined do not have failable status zeroed. 2021-11-19 13:06:43 +01:00
Christoffer Lerno
0358724451 Minor updates to TB integration. 2021-11-19 10:15:08 +01:00
Christoffer Lerno
86072ae21f Start integration of tiny backend. 2021-11-19 09:52:14 +01:00
Christoffer Lerno
0af448ee71 Fix case of very long literal int type values. Fix to bigint compile time truncation. Check decl enum implicit overflow. 2021-11-19 09:11:58 +01:00
Christoffer Lerno
a4a6ea16ce Use element initialization for <= 16 bytes structs and arrays. 2021-11-18 23:23:55 +01:00
Christoffer Lerno
4d4bbbdebc Parses attribute defines. Removal of incremental array parsing. Labels in macros should now work correctly. Volatile and attribute are no longer keywords. Checked a few todos. On test failure, return -1 2021-11-18 20:36:45 +01:00
Christoffer Lerno
bfde58b9a5 Optimized macro codegen on simpler code. 2021-11-18 09:32:10 +01:00
Christoffer Lerno
7b04e7cf85 Added experimental "scoping" and fixed (simple) debug symbols 2021-11-17 23:56:09 +01:00
Christoffer Lerno
b7fa3549a3 Fixed method extern declaration for LLVM. 2021-11-17 11:46:50 +01:00
Christoffer Lerno
974cd0acc5 Rollback global. 2021-11-17 10:37:23 +01:00
Christoffer Lerno
b52b42d4da Complete transition to fn. Introduce global/threadlocal 2021-11-16 17:46:44 +01:00
Christoffer Lerno
e2621617f1 Changes to example. 2021-11-13 21:33:13 +01:00
Christoffer Lerno
d3fed67dbe Changes to example. 2021-11-13 21:30:09 +01:00
Christoffer Lerno
91996e5973 Updated with some additional explanatory comments. 2021-11-13 21:26:53 +01:00
Christoffer Lerno
3156fcb4aa Updated with some additional explanatory comments. 2021-11-13 21:24:59 +01:00
Christoffer Lerno
8309d84fdb Updated with some explanatory comments. 2021-11-13 20:58:24 +01:00
Christoffer Lerno
4efb433934 Updated README with example of generic modules. 2021-11-13 20:20:31 +01:00
Christoffer Lerno
7142ce2f0c Updated README 2021-11-13 19:43:50 +01:00
Christoffer Lerno
a436a9b069 Updated README 2021-11-13 19:31:01 +01:00
Christoffer Lerno
fb56d380cc Builtins work. Math library exposes some builtins. Volatile store / load. 2021-11-13 12:31:45 +01:00
Christoffer Lerno
7bd76c973c Placeholders for builtins. Updated character literal parsing, supporting 1-16 characters. More test cases. 2021-11-12 10:13:15 +01:00
Christoffer Lerno
42465039e9 Updated character parsing. 2021-11-10 21:58:17 +01:00
Christoffer Lerno
df0b1df1df Better compatibility with LLVM < 13 (#319)
* Update wrapper to add type attribute on LLVM < 13
2021-11-09 22:53:13 +01:00
Christoffer Lerno
137b474f44 Update tester to read utf-8 2021-11-08 22:22:01 +01:00
Christoffer Lerno
4662133893 Updates to bitstruct 2021-11-08 22:22:01 +01:00
Christoffer Lerno
15f902579b Removed virtual 2021-11-08 22:22:01 +01:00
Christoffer Lerno
4e47f0b624 Fixes to bitstruct and work on correct behaviour when embedded in structs. 2021-11-08 22:22:01 +01:00
Christoffer Lerno
4f09b0c351 Bitstruct implementation. 2021-11-05 11:59:30 +01:00
Christoffer Lerno
29e7af843a Remove old try-catch. Top down promotion for binary etc. Prevent non-simple widening. Introducing wildcard failable. Move LLVM GEP usage. Regcall test and fix. Optimized slice assign. 2021-10-26 18:40:41 +02:00
Christoffer Lerno
e2a3000c39 Cleanup of casts 2021-10-22 00:59:13 +02:00
Christoffer Lerno
9942be54dc More optimized memclear. Added helper function on array gep. 2021-10-21 23:37:14 +02:00
Christoffer Lerno
b87e14cba8 Enum const inlining. 2021-10-21 15:13:11 +02:00
Christoffer Lerno
4ca7ba048b Updated to use ?, ?? and !! instead of !!, else and "else $unreachable" 2021-10-20 23:27:13 +02:00
Christoffer Lerno
1b38e24a9f Make it an error to do x < 0 when x is an unsigned integer. 2021-10-20 18:53:43 +02:00
Christoffer Lerno
f284a1c575 Updated readme. 2021-10-20 17:50:38 +02:00
Christoffer Lerno
86723540f3 $switch over values. 2021-10-20 17:49:07 +02:00
Christoffer Lerno
aa239c6a87 Allow "fn" instead of "func". Rewrote $switch over types. 2021-10-20 16:30:45 +02:00
data-man
09d9968e97 Update dirent.h to latest 2021-10-20 13:36:29 +02:00
Christoffer Lerno
76e4eea4a8 Fix missing support for array[] as return types. Fix bug with &&-folding. Added tests. 2021-10-20 11:57:41 +02:00
Christoffer Lerno
43a4967987 Fix macro return value handling. #252 2021-10-20 00:59:44 +02:00
Christoffer Lerno
ab5bacc78a Fix MingW CI 2021-10-20 00:38:21 +02:00
Christoffer Lerno
af34eec61d Pushed small win fix. 2021-10-19 23:12:25 +02:00
Christoffer Lerno
f48661d35e Removed use of basename / dirname. 2021-10-19 23:09:05 +02:00
Christoffer Lerno
5592d19152 Widen VarDeclKind enum in VarDecl 2021-10-19 21:23:49 +02:00
Christoffer Lerno
55f676dd5c Fix to testscript. 2021-10-19 20:57:47 +02:00
Christoffer Lerno
96571e2b65 Update tester to avoid adding CR on win. 2021-10-19 20:48:48 +02:00
Christoffer Lerno
4a3f5c4eb3 Update gitattributes 2021-10-19 20:38:28 +02:00
Christoffer Lerno
1db23defbc Restore strcompare MSC 2021-10-19 18:32:31 +02:00
Christoffer Lerno
6c9b5fd30d Update MSVC path max. 2021-10-19 18:32:31 +02:00
Christoffer Lerno
8e93642535 LLVM 13 compatibility. Move Ubuntu CI to LLVM 12. 2021-10-19 18:32:31 +02:00
Christoffer Lerno
d36fc9b19e Formatting. 2021-10-19 16:47:25 +02:00
C34A
5dea48101f MSVC compatibility 2021-10-19 13:04:17 +02:00
Christoffer Lerno
b4df56db54 Removed original_type, pure, removed bigint, added i128 type, lots of fixes to $Foo, reassigning ct type, catch/macro, "!", removed type inference. 2021-10-19 10:39:02 +02:00
Christoffer Lerno
1b086e06f1 Fix of miscompilation 2021-10-07 13:53:11 +02:00
Christoffer Lerno
aca5adebd5 Fix for token widening and added clarifying casts for sema checks. 2021-10-03 22:18:26 +02:00
Christoffer Lerno
dc097fe130 Widen token type 2021-10-03 21:48:49 +02:00
Christoffer Lerno
ae371d105d Add vector ++ -- ! ~ - | & ^ ops and allow .c3t to be compiled. 2021-09-30 13:54:51 +02:00
data-man
de6ea0d1ae Better support LLD 14+ 2021-09-30 11:15:44 +02:00
Christoffer Lerno
020eba720b Added initial (incomplete) support for vectors. 2021-09-28 14:19:28 +02:00
Christoffer Lerno
0a4f35154a Addeded some hash functions. Fix of visibility resolution for macros. std lib is now loaded from a directory. 2021-09-22 10:27:10 +02:00
Christoffer Lerno
fb9be722bc Fix issue with default macro arguments. Test of ?? instead of else. Added libc 2021-09-20 22:25:01 +02:00
Christoffer Lerno
e4c7dde30b Fix of shadowing bug. Allow pointer and subarrays to be constant initialized. Compile time values may now pass around anything considered compile time constant. It's possible to index into an initializer list at compile time. (Some work still remains on this) 2021-09-18 01:13:42 +02:00
data-man
1b103a3e22 Support LLVM 14+ 2021-09-16 18:05:13 +02:00
Christoffer Lerno
b87b67ebbb Factorial macro example. 2021-09-11 02:34:09 +02:00
Christoffer Lerno
17dcb742c6 Fixed codegen for subarray global initializers. Adding fasta example. 2021-09-11 00:44:35 +02:00
Christoffer Lerno
b7e423adc2 Update .len for subarray to not require () 2021-09-10 19:44:27 +02:00
Christoffer Lerno
0aef2810c8 Added fasta example. 2021-09-10 19:27:42 +02:00
Christoffer Lerno
2b2be6b491 Added mandelbrot example code. 2021-09-10 16:12:54 +02:00
Christoffer Lerno
49d13c23bb Fix issue with grouped expressions in macros. Adding spectral norml code example. 2021-09-10 15:47:31 +02:00
Christoffer Lerno
bcda6d71c9 AST printout removed. Split initializer types. Const list functionality. 2021-09-10 15:47:23 +02:00
Christoffer Lerno
c76e8e0713 Added nbodies example 2021-09-10 10:30:20 +02:00
Christoffer Lerno
29b3535460 Added fannkuch example. 2021-09-10 09:20:27 +02:00
Christoffer Lerno
fd1eafe5bf Fix base64 and hash examples. 2021-09-08 23:54:56 +02:00
Christoffer Lerno
468921225d Compound literal uses Foo {} now. 2021-09-08 16:43:02 +02:00
Benjamin Stigsen
50853bb5de Create .gitattributes
Add C language syntax highlighting to C3
2021-09-08 10:52:20 +02:00
1142 changed files with 88093 additions and 28708 deletions

4
.gitattributes vendored Normal file
View File

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

View File

@@ -7,65 +7,104 @@ on:
branches: [ master ]
jobs:
build-msvc:
runs-on: windows-latest
strategy:
# Don't abort runners if a single one fails
fail-fast: false
matrix:
build_type: [ Release, Debug ]
defaults:
run:
shell: cmd
steps:
- uses: actions/checkout@v3
- name: CMake
run: |
cmake -B build -G "Visual Studio 17 2022" -A x64 -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
cmake --build build --config ${{ matrix.build_type }}
- name: Build testproject
run: |
cd resources/testproject
..\..\build\${{ matrix.build_type }}\c3c.exe --debug-log run hello_world_win32
- name: run compiler tests
run: |
cd test
python3.exe src/tester.py ..\build\${{ matrix.build_type }}\c3c.exe test_suite/
build-msys2-mingw:
runs-on: windows-latest
strategy:
# Don't abort runners if a single one fails
fail-fast: false
matrix:
build_type: [Release, Debug]
defaults:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- uses: msys2/setup-msys2@v2
with:
msystem: MINGW64
update: true
install: git binutils mingw-w64-x86_64-cmake mingw-w64-x86_64-toolchain mingw-w64-x86_64-llvm mingw-w64-x86_64-polly mingw-w64-x86_64-python mingw-w64-x86_64-lld
install: git binutils mingw-w64-x86_64-ninja mingw-w64-x86_64-cmake mingw-w64-x86_64-toolchain mingw-w64-x86_64-python
- shell: msys2 {0}
run: |
pacman --noconfirm -U https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-llvm-13.0.1-2-any.pkg.tar.zst
pacman --noconfirm -U https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-lld-13.0.1-2-any.pkg.tar.zst
- name: CMake
run: |
mkdir build && cd build
cmake .. -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
cmake --build .
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
cmake --build build
- name: Build testproject
run: |
cd resources/testproject
../../build/c3c build
../../build/c3c run --debug-log
- name: run compiler tests
run: |
cd test
python3 src/tester.py ../build/c3c.exe test_suite/
build-msys2-clang:
runs-on: windows-latest
if: ${{ false }}
strategy:
# Don't abort runners if a single one fails
fail-fast: false
matrix:
build_type: [Release, Debug]
defaults:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- uses: msys2/setup-msys2@v2
with:
msystem: CLANG64
update: true
update: false
install: git binutils mingw-w64-clang-x86_64-cmake mingw-w64-clang-x86_64-toolchain mingw-w64-clang-x86_64-python
- name: CMake
run: |
mkdir build && cd build
cmake .. -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
cmake --build .
cmake -B build -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
cmake --build build
- name: Build testproject
run: |
cd resources/testproject
../../build/c3c build
../../build/c3c run --debug-log
- name: run compiler tests
run: |
@@ -75,25 +114,88 @@ jobs:
build-linux:
runs-on: ubuntu-latest
strategy:
# Don't abort runners if a single one fails
fail-fast: false
matrix:
build_type: [Release, Debug]
llvm_version: [12, 13, 14, 15]
steps:
- uses: actions/checkout@v1
- name: (Ubuntu) Download LLVM
- uses: actions/checkout@v3
- name: Install common deps
run: |
sudo apt-get install zlib1g zlib1g-dev clang-11 libllvm11 llvm-11 llvm-11-dev llvm-11-runtime liblld-11-dev liblld-11 python3
sudo apt-get install zlib1g zlib1g-dev python3 ninja-build
- name: Install Clang ${{ matrix.llvm_version }}
run: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
if [[ "${{matrix.llvm_version}}" < 15 ]]; then
sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-${{matrix.llvm_version}} main"
else
sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal main"
fi
sudo apt-get update
sudo apt-get install -y clang-${{matrix.llvm_version}} llvm-${{matrix.llvm_version}} llvm-${{matrix.llvm_version}}-dev lld-${{matrix.llvm_version}} liblld-${{matrix.llvm_version}}-dev
if [[ "${{matrix.llvm_version}}" > 12 ]]; then
sudo apt-get install -y libmlir-${{matrix.llvm_version}} libmlir-${{matrix.llvm_version}}-dev mlir-${{matrix.llvm_version}}-tools
fi
- name: CMake
run: |
mkdir build && cd build
cmake .. -DLLVM_DIR=/usr/lib/llvm-11/cmake -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
cmake --build .
cmake -B build -G Ninja -DCMAKE_C_COMPILER=clang-${{matrix.llvm_version}} -DCMAKE_CXX_COMPILER=clang++-${{matrix.llvm_version}} -DC3_LLVM_VERSION=${{matrix.llvm_version}} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
cmake --build build
- name: Build testproject
run: |
cd resources/testproject
../../build/c3c build
../../build/c3c run --debug-log
- name: Build testproject direct linker
run: |
cd resources/testproject
../../build/c3c run --debug-log --forcelinker
- name: run compiler tests
run: |
cd test
if [[ "${{matrix.llvm_version}}" < 15 ]]; then
python3 src/tester.py ../build/c3c test_suite/
else
python3 src/tester.py ../build/c3c test_suite2/
fi
build-mac:
runs-on: macos-latest
strategy:
# Don't abort runners if a single one fails
fail-fast: false
matrix:
build_type: [Release, Debug]
llvm_version: [12, 13, 14]
steps:
- uses: actions/checkout@v3
- name: Download LLVM
run: |
brew install llvm@${{ matrix.llvm_version }} botan ninja
echo "/usr/local/opt/llvm@${{ matrix.llvm_version }}/bin" >> $GITHUB_PATH
TMP_PATH=$(xcrun --show-sdk-path)/user/include
echo "CPATH=$TMP_PATH" >> $GITHUB_ENV
- name: CMake
run: |
cmake -B build -G Ninja -DC3_LLVM_VERSION=${{matrix.llvm_version}} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
cmake --build build
- name: Build testproject
run: |
cd resources/testproject
../../build/c3c run --debug-log
- name: Build testproject direct linker
run: |
cd resources/testproject
../../build/c3c run --debug-log --forcelinker
- name: run compiler tests
run: |

9
.gitignore vendored
View File

@@ -52,7 +52,6 @@ Module.symvers
Mkfile.old
dkms.conf
/build/
/cmake-build-debug/
.idea/
/resources/grammar.tab.c
/resources/grammar.vcg
@@ -60,3 +59,11 @@ dkms.conf
/resources/y.tab.c
/resources/y.tab.h
/bin/
#visual studio files
.vs/
.vscode/
out/
/cmake-build-debug/
/cmake-build-release/

View File

@@ -1,68 +1,144 @@
cmake_minimum_required(VERSION 3.10)
cmake_minimum_required(VERSION 3.15)
project(c3c)
include(FetchContent)
include(FeatureSummary)
SET(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL)
SET(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)
set(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL)
set(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
#set(CMAKE_BUILD_TYPE Release)
#set(CMAKE_CXX_FLAGS_RELEASE "-O3")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -gdwarf-3 -O3")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -gdwarf-3")
#set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O1 -fsanitize=undefined")
#set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O1 -fsanitize=undefined")
#set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -gdwarf-3 -O3 -fsanitize=undefined")
#set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -gdwarf-3 -fsanitize=undefined")
#set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=undefined")
find_package(LLVM REQUIRED CONFIG)
option(C3_USE_TB "Enable TB" OFF)
set(C3_LLVM_VERSION "auto" CACHE STRING "Use LLVM version [default: auto]")
option(C3_USE_MIMALLOC "Use built-in mimalloc" OFF)
set(C3_MIMALLOC_TAG "v1.7.3" CACHE STRING "Used version of mimalloc")
set(C3_USE_MIMALLOC OFF)
if(C3_USE_MIMALLOC)
option(MI_BUILD_TESTS OFF)
option(MI_BUILD_SHARED OFF)
option(MI_PADDING OFF)
option(MI_DEBUG_FULL OFF)
FetchContent_Declare(
mimalloc
GIT_REPOSITORY https://github.com/microsoft/mimalloc.git
GIT_TAG ${C3_MIMALLOC_TAG}
)
FetchContent_MakeAvailable(mimalloc)
endif()
if (NOT C3_LLVM_VERSION STREQUAL "auto")
if (${C3_LLVM_VERSION} VERSION_LESS 12 OR ${C3_LLVM_VERSION} VERSION_GREATER 15)
message(FATAL_ERROR "LLVM ${C3_LLVM_VERSION} is not supported!")
endif()
endif()
if(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
if (C3_LLVM_VERSION STREQUAL "auto")
set(C3_LLVM_VERSION "14")
endif()
FetchContent_Declare(
LLVM_Windows
URL https://github.com/c3lang/win-llvm/releases/download/llvm-vs22/llvm-14.0.1-windows-amd64-msvc17-libcmt.7z
)
FetchContent_Declare(
LLVM_Windows_debug
URL https://github.com/c3lang/win-llvm/releases/download/llvm-vs22/llvm-14.0.1-windows-amd64-msvc17-libcmt-dbg.7z
)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
message("Loading Windows LLVM debug libraries, this may take a while...")
FetchContent_MakeAvailable(LLVM_Windows_debug)
set(CMAKE_SYSTEM_PREFIX_PATH ${llvm_windows_debug_SOURCE_DIR} ${CMAKE_SYSTEM_PREFIX_PATH})
else()
message("Loading Windows LLVM libraries, this may take a while...")
FetchContent_MakeAvailable(LLVM_Windows)
set(CMAKE_SYSTEM_PREFIX_PATH ${llvm_windows_SOURCE_DIR} ${CMAKE_SYSTEM_PREFIX_PATH})
endif()
find_package(LLVM REQUIRED CONFIG)
find_package(LLD REQUIRED CONFIG)
else()
if (NOT C3_LLVM_VERSION STREQUAL "auto")
find_package(LLVM ${C3_LLVM_VERSION} REQUIRED CONFIG)
else()
find_package(LLVM REQUIRED CONFIG)
endif()
endif()
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
message(STATUS "Libraries located in: ${LLVM_LIBRARY_DIRS}")
include_directories(${LLVM_INCLUDE_DIRS})
add_definitions(${LLVM_DEFINITIONS})
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(LLVM_LINK_COMPONENTS
AllTargetsAsmParsers
AllTargetsCodeGens
AllTargetsDescs
AllTargetsDisassemblers
AllTargetsInfos
AllTargetsCodeGens
Analysis
AsmPrinter
BitReader
Core
DebugInfoPDB
InstCombine
IrReader
LibDriver
Linker
LTO
MC
MCDisassembler
native
nativecodegen
Object
Option
ScalarOpts
Support
Target
TransformUtils
native
nativecodegen
AsmPrinter
Linker
LTO
WindowsManifest
DebugInfoPDB
LibDriver
Option
IrReader
)
)
if (${LLVM_PACKAGE_VERSION} VERSION_GREATER 14.1)
set(LLVM_LINK_COMPONENTS ${LLVM_LINK_COMPONENTS} WindowsDriver)
endif()
llvm_map_components_to_libnames(llvm_libs ${LLVM_LINK_COMPONENTS})
file(COPY ${CMAKE_SOURCE_DIR}/resources/lib DESTINATION ${CMAKE_BINARY_DIR})
file(COPY ${CMAKE_SOURCE_DIR}/lib DESTINATION ${CMAKE_BINARY_DIR})
find_library(LLD_COFF NAMES lldCOFF.a liblldCOFF.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_COMMON NAMES lldCommon.a liblldCommon.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_CORE NAMES lldCore.a liblldCore.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_WASM NAMES lldWasm.a liblldWasm.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_MINGW NAMES lldMinGW.a liblldMinGW.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_ELF NAMES lldELF.a liblldELF.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_DRIVER NAMES lldDriver.a liblldDriver.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_READER_WRITER NAMES lldReaderWriter.a liblldReaderWriter.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_MACHO NAMES lldMachO.a liblldMachO.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_YAML NAMES lldYAML.a liblldYAML.a PATHS ${LLVM_LIBRARY_DIRS})
# These don't seem to be reliable on windows.
message(STATUS "using find_library")
if(C3_USE_TB)
find_library(TB_LIB NAMES tildebackend.a tildebackend.lib PATHS ${CMAKE_SOURCE_DIR}/tb/)
endif()
find_library(LLD_COFF NAMES lldCOFF.lib lldCOFF.a liblldCOFF.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_COMMON NAMES lldCommon.lib lldCommon.a liblldCommon.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_ELF NAMES lldELF.lib lldELF.a liblldELF.a PATHS ${LLVM_LIBRARY_DIRS})
if (${LLVM_PACKAGE_VERSION} VERSION_LESS 14)
find_library(LLD_MACHO NAMES lldMachO2.lib lldMachO2.a liblldMachO2.a PATHS ${LLVM_LIBRARY_DIRS})
else ()
find_library(LLD_MACHO NAMES lldMachO.lib lldMachO.a liblldMachO.a PATHS ${LLVM_LIBRARY_DIRS})
endif ()
find_library(LLD_MINGW NAMES lldMinGW.lib lldMinGW.a liblldMinGW.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_WASM NAMES lldWasm.lib lldWasm.a liblldWasm.a PATHS ${LLVM_LIBRARY_DIRS})
if (${LLVM_PACKAGE_VERSION} VERSION_LESS 14)
find_library(LLD_CORE NAMES lldCore.lib lldCore.a liblldCore.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_DRIVER NAMES lldDriver.lib lldDriver.a liblldDriver.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_READER_WRITER NAMES lldReaderWriter.lib lldReaderWriter.a liblldReaderWriter.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_YAML NAMES lldYAML.lib lldYAML.a liblldYAML.a PATHS ${LLVM_LIBRARY_DIRS})
endif ()
set(lld_libs
${LLD_COFF}
@@ -76,90 +152,143 @@ set(lld_libs
${LLD_YAML}
${LLD_CORE}
)
if (APPLE)
set(lld_libs ${lld_libs} xar)
endif ()
message(STATUS "linking to llvm libs ${lld_libs}")
message(STATUS "Found lld libs ${lld_libs}")
add_library(c3c_wrappers STATIC wrapper/src/wrapper.cpp)
add_executable(c3c
src/main.c
src/build/builder.c
src/build/build_options.c
src/build/project_creation.c
src/utils/errors.c
src/utils/file_utils.c
src/compiler/lexer.c
src/compiler/tokens.c
src/compiler/symtab.c
src/compiler/parser.c
src/compiler_tests/tests.c
src/compiler_tests/benchmark.c
src/utils/malloc.c
src/compiler/compiler.c
src/compiler/semantic_analyser.c
src/compiler/source_file.c
src/compiler/diagnostics.c
src/compiler/ast.c
src/compiler/bigint.c
src/compiler/context.c
src/compiler/sema_expr.c
src/compiler/enums.h
src/compiler/sema_casts.c
src/compiler/target.c
src/compiler/c_abi_internal.h
src/compiler/codegen_general.c
src/compiler/compiler.c
src/compiler/compiler.h
src/compiler/types.c
src/compiler/module.c
src/compiler/llvm_codegen.c
src/utils/stringutils.c
src/compiler/dwarf.h
src/compiler/context.c
src/compiler/copying.c
src/compiler/llvm_codegen_stmt.c
src/compiler/llvm_codegen_expr.c
src/compiler/llvm_codegen_debug_info.c
src/compiler/llvm_codegen_module.c
src/compiler/llvm_codegen_type.c
src/compiler/llvm_codegen_function.c
src/compiler/diagnostics.c
src/compiler/dwarf.h
src/compiler/enums.h
src/compiler/float.c
src/compiler/headers.c
src/compiler/lexer.c
src/compiler/libraries.c
src/compiler/linker.c
src/compiler/llvm_codegen.c
src/compiler/llvm_codegen_c_abi_aarch64.c
src/compiler/llvm_codegen_c_abi.c
src/build/builder.c
src/utils/toml.c src/build/project.c
src/compiler/sema_name_resolution.c
src/target_info/target_info.c
src/compiler/llvm_codegen_c_abi_riscv.c
src/compiler/llvm_codegen_c_abi_wasm.c
src/compiler/llvm_codegen_c_abi_win64.c
src/compiler/llvm_codegen_c_abi_x64.c
src/compiler/llvm_codegen_c_abi_x86.c
src/compiler/llvm_codegen_debug_info.c
src/compiler/llvm_codegen_expr.c
src/compiler/llvm_codegen_function.c
src/compiler/llvm_codegen_instr.c
src/compiler/llvm_codegen_module.c
src/compiler/llvm_codegen_stmt.c
src/compiler/llvm_codegen_type.c
src/compiler/llvm_codegen_value.c
src/compiler/module.c
src/compiler/number.c
src/compiler/parse_expr.c
src/compiler/parse_global.c
src/compiler/parser.c
src/compiler/parser_internal.h
src/compiler/parse_stmt.c
src/compiler/parse_global.c
src/compiler/sema_passes.c
src/compiler/sema_internal.h
src/compiler/sema_casts.c
src/compiler/sema_decls.c
src/compiler/sema_types.c
src/compiler/sema_expr.c
src/compiler/sema_internal.h
src/compiler/sema_name_resolution.c
src/compiler/semantic_analyser.c
src/compiler/sema_passes.c
src/compiler/sema_stmts.c
src/compiler/number.c
src/compiler/linker.c
src/compiler/sema_types.c
src/compiler/source_file.c
src/compiler/symtab.c
src/compiler/target.c
src/compiler/tb_codegen.c
src/compiler/tilde_codegen.c
src/compiler/tilde_codegen_instr.c
src/compiler/tilde_codegen_value.c
src/compiler/tilde_codegen_storeload.c
src/compiler_tests/benchmark.c
src/compiler_tests/tests.c
src/compiler/tokens.c
src/compiler/types.c
src/main.c
src/utils/errors.c
src/utils/file_utils.c
src/utils/find_msvc.c
src/utils/malloc.c
src/utils/stringutils.c
src/utils/taskqueue.c
src/utils/json.c
src/build/project.c
src/utils/vmem.c
src/utils/vmem.h
src/utils/whereami.c
src/utils/taskqueue.c
src/compiler/llvm_codegen_c_abi_x86.c
src/compiler/c_abi_internal.h
src/compiler/llvm_codegen_c_abi_x64.c
src/compiler/llvm_codegen_c_abi_win64.c
src/compiler/llvm_codegen_c_abi_aarch64.c
src/compiler/headers.c
src/compiler/llvm_codegen_c_abi_riscv.c
src/compiler/llvm_codegen_c_abi_wasm.c)
target_compile_options(c3c PRIVATE -Wall -Werror -Wno-unknown-pragmas -Wno-unused-result
-Wno-unused-function -Wno-unused-variable -Wno-unused-parameter)
src/compiler/decltable.c
src/compiler/mac_support.c
src/compiler/tilde_codegen_storeload.c
src/compiler/llvm_codegen_storeload.c
src/compiler/tilde_codegen_expr.c
src/compiler/tilde_codegen_stmt.c
src/compiler/tilde_codegen_type.c
src/compiler/windows_support.c)
if(NOT CMAKE_C_COMPILER_ID STREQUAL "MSVC")
message(STATUS "using gcc/clang warning switches")
target_compile_options(c3c PRIVATE -Wall -Werror -Wno-unknown-pragmas -Wno-unused-result
-Wno-unused-function -Wno-unused-variable -Wno-unused-parameter)
endif()
target_include_directories(c3c PRIVATE
"${CMAKE_SOURCE_DIR}/src/")
target_include_directories(c3c PRIVATE
"${CMAKE_SOURCE_DIR}/tb/")
target_include_directories(c3c_wrappers PRIVATE
"${CMAKE_SOURCE_DIR}/wrapper/src/")
message(STATUS "Found LLD ${lld_libs}")
target_link_libraries(c3c_wrappers ${llvm_libs} ${lld_libs})
#target_link_libraries(c3c m ${llvm_libs} c3c_wrappers lldCommon lldCore lldCOFF lldWASM lldMinGW lldELF lldDriver lldReaderWriter lldMachO lldYAML)
target_link_libraries(c3c m ${llvm_libs} c3c_wrappers ${lld_libs})
target_link_libraries(c3c ${llvm_libs} c3c_wrappers ${lld_libs})
if(C3_USE_TB)
target_link_libraries(c3c c3c_wrappers ${TB_LIB})
target_compile_definitions(c3c PUBLIC TB_BACKEND=1)
else()
target_compile_definitions(c3c PUBLIC TB_BACKEND=0)
endif()
if(C3_USE_MIMALLOC)
target_link_libraries(c3c mimalloc-static)
endif()
if(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
message("Adding MSVC options")
target_compile_options(c3c PRIVATE /wd4068 /wd4090 /WX /Wv:18)
target_compile_options(c3c_wrappers PUBLIC /wd4624 /wd4267 /wd4244 /WX /Wv:18)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
target_compile_options(c3c PUBLIC /MTd)
target_compile_options(c3c_wrappers PUBLIC /MTd)
else()
target_compile_options(c3c PUBLIC /MT)
target_compile_options(c3c_wrappers PUBLIC /MT)
endif()
endif()
if (WIN32)
if (CMAKE_C_COMPILER_ID STREQUAL "Clang" OR CMAKE_C_COMPILE_ID STREQUAL "GNU")
@@ -171,3 +300,4 @@ endif()
install(TARGETS c3c DESTINATION bin)
feature_summary(WHAT ALL)

15
CMakeSettings.json Normal file
View File

@@ -0,0 +1,15 @@
{
"configurations": [
{
"name": "build",
"generator": "Ninja",
"configurationType": "Release",
"inheritEnvironments": [ "msvc_x64_x64" ],
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "-DLLVM_DIR=C:\\llvm\\llvm\\build\\lib\\cmake\\llvm -DCMAKE_CXX_FLAGS:STRING=\"${CMAKE_CXX_FLAGS} /J\"",
"buildCommandArgs": "-v",
"ctestCommandArgs": ""
}
]
}

20
LICENSE_STDLIB Normal file
View File

@@ -0,0 +1,20 @@
Copyright (c) 2022 Christoffer Lernö and contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

270
README.md
View File

@@ -1,10 +1,14 @@
# C3 Language
C3 is a C-like language trying to be "an incremental improvement over C" rather than a whole new language.
C3 owes a lot to the ideas of the [C2 language](http://c2lang.org): to iterate on top of C without trying to be a
whole new language.
C3 is a C-like language striving to be an evolution of C, rather than a
completely new language. As an alternative in the C/C++ niche it
aims to be fast and close to the metal.
C3 tries to be an alternative in the C/C++ niche: fast and close to the metal.
The manual for C3 can be found at [www.c3-lang.org](http://www.c3-lang.org).
![vkQuake](https://github.com/c3lang/c3c/blob/master/resources/images/vkQuake.png?raw=true)
Thanks to full ABI compatibility with C, it's possible to mix C and C3 in the same project with no effort. As a demonstration, vkQuake was compiled with a small portion of the code converted to C3 and compiled with the c3c compiler. (The fork can be found at https://github.com/c3lang/vkQuake)
### Design Principles
- Procedural "get things done"-type of language.
@@ -15,28 +19,95 @@ C3 tries to be an alternative in the C/C++ niche: fast and close to the metal.
- Avoid "big ideas" & the "more is better" fallacy.
- Introduce some higher level conveniences where the value is great.
C3 owes its inspiration to the [C2 language](http://c2lang.org): to iterate on top of C without trying to be a
whole new language.
### Example code
Create a `main.c3` file with:
```c++
module hello_world;
import std::io;
The following code shows [generic modules](http://www.c3-lang.org/generics/) (more examples can be found at http://www.c3-lang.org/examples/).
func void main()
```c++
module stack <Type>;
// Above: the parameterized type is applied to the entire module.
struct Stack
{
io::printf("Hello, world!\n");
usize capacity;
usize size;
Type* elems;
}
// The type methods offers dot syntax calls,
// so this function can either be called
// Stack.push(&my_stack, ...) or
// my_stack.push(...)
fn void Stack.push(Stack* this, Type element)
{
if (this.capacity == this.size)
{
this.capacity *= 2;
this.elems = mem::realloc(this.elems, Type.sizeof * this.capacity);
}
this.elems[this.size++] = element;
}
fn Type Stack.pop(Stack* this)
{
assert(this.size > 0);
return this.elems[--this.size];
}
fn bool Stack.empty(Stack* this)
{
return !this.size;
}
```
Make sure you have the standard libraries at either `../lib/std/` or `/lib/std/`.
Testing it out:
Then run
```sh
c3c compile main.c3
```cpp
import stack;
// Define our new types, the first will implicitly create
// a complete copy of the entire Stack module with "Type" set to "int"
define IntStack = Stack<int>;
// The second creates another copy with "Type" set to "double"
define DoubleStack = Stack<double>;
// If we had added "define IntStack2 = Stack<int>"
// no additional copy would have been made (since we already
// have an parameterization of Stack<int>) so it would
// be same as declaring IntStack2 an alias of IntStack
// Importing an external C function is straightforward
// here is an example of importing libc's printf:
extern fn int printf(char* format, ...);
fn void test()
{
IntStack stack;
// Note that C3 uses zero initialization by default
// so the above is equivalent to IntStack stack = {};
stack.push(1);
// The above can also be written IntStack.push(&stack, 1);
stack.push(2);
// Prints pop: 2
printf("pop: %d\n", stack.pop());
// Prints pop: 1
printf("pop: %d\n", stack.pop());
DoubleStack dstack;
dstack.push(2.3);
dstack.push(3.141);
dstack.push(1.1235);
// Prints pop: 1.1235
printf("pop: %f\n", dstack.pop());
}
```
The generated binary will be called `a.out`.
### In what ways do C3 differ from C?
- No mandatory header files
@@ -50,7 +121,6 @@ The generated binary will be called `a.out`.
- Defer
- Value methods
- Associated enum data
- Built-in hooks for convenient string handling
- No preprocessor
- Less undefined behaviour and runtime checks in "safe" mode
- Limited operator overloading to enable userland dynamic arrays
@@ -58,107 +128,68 @@ The generated binary will be called `a.out`.
### Current status
The current version of the compiler is alpha release 0.2.
It's possible to try out the current C3 compiler in the browser: https://ide.judge0.com/ this is courtesy of the
developer of Judge0.
Design work is still being done in the design draft here: https://c3lang.github.io/c3docs/. If you have any suggestions, send a mail to [christoffer@aegik.com](mailto:christoffer@aegik.com), [file an issue](https://github.com/c3lang/c3c/issues) or discuss
C3 on its dedicated Discord: https://discord.gg/qN76R87
Design work on C3 complete aside from fleshing out details, such as
inline asm. As the standard library work progresses, changes and improvements
to the language will happen continuously.
Follow the issues [here](https://github.com/c3lang/c3c/issues).
The compiler should compile on Linux, Windows (under Mingw or MSYS2) and MacOS,
but needs some install documentation for Windows.
If you have suggestions on how to improve the language, either [file an issue](https://github.com/c3lang/c3c/issues)
or discuss C3 on its dedicated Discord: [https://discord.gg/qN76R87](https://discord.gg/qN76R87).
Due to its ABI compatibility with C, it's possible to mix C and C3 in the same project.
As a demonstration, vkQuake was compiled with a small portion of the code converted
to C3 and compiled with the c3c compiler:
The compiler is currently verified to compile on Linux, Windows and MacOS.
![vkQuake](https://github.com/c3lang/c3c/blob/master/resources/images/vkQuake.png?raw=true)
(The vkFork is at https://github.com/c3lang/vkQuake)
#### Todo / done
- [x] For/while/do
- [x] `if`/ternary
- [x] Structs
- [x] Union
- [x] Enums
- [x] Value methods
- [x] Compound literals
- [x] Designated initalizers
- [x] Slicing syntax
- [x] Arrays and subarrays
- [x] Modules
- [x] `$unreachable`
- [x] Compile time assert with `$assert`
- [x] Compiler guiding `assert`
- [x] C code calling by declaring methods `extern`
- [x] Compile time variables
- [x] Basic macros
- [x] 4cc, 8cc, 2cc
- [x] Enum type inference in switch/assignment
- [x] Integer type inference
- [x] Error type
- [x] Failable error handling
- [x] `try` for conditional execution
- [x] `catch` for error handling
- [x] Implicit unwrap after `catch`
- [x] `sizeof`
- [x] `typeof`
- [x] 2s complement wrapping operators
- [x] Labelled break / continue
- [x] `nextcase` statement
- [x] Expression blocks
- [x] Do-without-while
- [x] Foreach statement
- [x] Templates
- [x] Distinct types
- [x] Built-in linking
- [x] CT only macros evaluating to constants
- [x] range initializers e.g. `{ [1..2] = 2 }`
- [x] Trailing body macros e.g. `@foo(1, 100; int a) { bar(a); };`
- [x] Complex macros
- [x] CT type constants
- [ ] Anonymous structs
- [ ] Complete C ABI conformance *in progress*
- [ ] Debug info *in progress*
- [ ] Virtual type *in progress*
- [ ] Enum associated data support
- [ ] Windows support *in progress*
- [ ] All attributes *in progress*
- [ ] Associative array literals
- [ ] Reflection methods
- [ ] LTO/ThinLTO setup
- [ ] `global` / `shared` for globals
- [ ] Escape macros
- [ ] Implicit capturing macros
- [ ] Subarray initializers
- [ ] Bitstructs
- [ ] `asm` section
- [ ] `$switch`
- [ ] `$for`
- [ ] Pre-post conditions
- [ ] Stdlib inclusion
- [ ] String functions
- [ ] Simd vector types
#### What can you help with?
- If you wish to contribute with ideas, please file issues on the c3docs: https://github.com/c3lang/c3docs instead of the compiler.
- Discuss the language on discord to help iron out syntax.
- If you wish to contribute with ideas, please file issues or discuss on Discord.
- Interested in contributing to the stdlib? Please get in touch on Discord.
- Are you a Windows dev? Please help make the compiler work on Windows!
- Install instructions for other Linux and Unix variants are appreciated.
- Would you like to contribute bindings to some library? It would be nice to have support for SDL, Raylib and more.
- Build something with C3 and show it off and give feedback. The language is still open for significant tweaks.
- Start work on the C -> C3 converter which takes C code and does a "best effort" to translate it to C3. The first version only needs to work on C headers.
- Do you have some specific area you have deep knowledge of and could help make C3 even better at doing? File or comment on issues.
### Installing
#### Installing on Windows
1. Make sure you have Visual Studio 17 2022 installed.
2. Install CMake
3. Clone the C3C github repository: `git clone https://github.com/c3lang/c3c.git`
4. Enter the C3C directory `cd c3c`.
5. Set up the CMake build `cmake -B build -G "Visual Studio 17 2022" -A x64 -DCMAKE_BUILD_TYPE=Release`
6. Build: `cmake --build build --config Release`
7. You should now have the c3c.exe
You should now have a `c3c` executable.
You can try it out by running some sample code: `c3c.exe compile ../resources/examples/hash.c3`
#### Installing on Arch Linux
There is an AUR package for the C3C compiler : [c3c-git](https://aur.archlinux.org/packages/c3c-git)
You can use your AUR package manager or clone it manually:
```sh
git clone https://aur.archlinux.org/c3c-git.git
cd c3c-git
makepkg -si
```
#### Installing on Ubuntu 20.10
1. Make sure you have a C compiler that handles C11 and a C++ compiler, such as GCC or Clang. Git also needs to be installed.
2. Install CMake: `sudo apt install cmake`
3. Install LLVM 11: `sudo apt-get install clang-11 zlib1g zlib1g-dev libllvm11 llvm-11 llvm-11-dev llvm-11-runtime liblld-11-dev liblld-11`
3. Install LLVM 12 (or greater: C3C supports LLVM 12-15): `sudo apt-get install clang-12 zlib1g zlib1g-dev libllvm12 llvm-12 llvm-12-dev llvm-12-runtime liblld-12-dev liblld-12`
4. Clone the C3C github repository: `git clone https://github.com/c3lang/c3c.git`
5. Enter the C3C directory `cd c3c`.
6. Create a build directory `mkdir build`
7. Change directory to the build directory `cd build`
8. Set up CMake build for debug: `cmake -DLLVM_DIR=/usr/lib/llvm-11/cmake -DCMAKE_BUILD_TYPE=Debug ..`
8. Set up CMake build: `cmake ..`
9. Build: `cmake --build .`
You should now have a `c3c` executable.
@@ -185,10 +216,53 @@ A `c3c` executable will be found under `bin/`.
#### Installing on OS X using Homebrew
2. Install CMake: `brew install cmake`
3. Install LLVM 11: `brew install llvm`
3. Install LLVM 13: `brew install llvm`
4. Clone the C3C github repository: `git clone https://github.com/c3lang/c3c.git`
5. Enter the C3C directory `cd c3c`.
6. Create a build directory `mkdir build`
7. Change directory to the build directory `cd build`
8. Set up CMake build for debug: `cmake ..`
9. Build: `cmake --build .`
#### Installing on other Linux / Unix variants
1. Install CMake.
2. Install or compile LLVM and LLD *libraries* (version 12+ or higher)
3. Clone the C3C github repository: `git clone https://github.com/c3lang/c3c.git`
4. Enter the C3C directory `cd c3c`.
5. Create a build directory `mkdir build`
6. Change directory to the build directory `cd build`
7. Set up CMake build for debug: `cmake ..`. At this point you may need to manually
provide the link path to the LLVM CMake directories, e.g. `cmake -DLLVM_DIR=/usr/local/opt/llvm/lib/cmake/llvm/ ..`
8. Build: `cmake --build .`
#### Getting started with a "hello world"
Create a `main.c3` file with:
```c++
module hello_world;
import std::io;
fn void main()
{
io::println("Hello, world!");
}
```
Make sure you have the standard libraries at either `../lib/std/` or `/lib/std/`.
Then run
```sh
c3c compile main.c3
```
The generated binary will be called `a.out`.
#### Licensing
The C3 compiler is licensed under LGPL 3.0, the standard library itself is
MIT licensed.
#### Editor plugins
Editor plugins can be found at https://github.com/c3lang/editor-plugins.

View File

@@ -2,17 +2,26 @@
## build-with-docker.sh
## @author gdm85
##
## Script to build c3c for either Ubuntu 18 or Ubuntu 20.
## Script to build c3c for either Ubuntu 20, 21 or 22.
##
#
if [ $# -ne 1 -a $# -ne 2 ]; then
echo "Usage: build-with-docker.sh (18|20) [Debug|Release]" 1>&2
echo "Usage: build-with-docker.sh (20|21|22) [Debug|Release]" 1>&2
exit 1
fi
set -e
DOCKER=docker
DOCKER_RUN=""
IMAGE="c3c-builder"
if type podman 2>/dev/null >/dev/null; then
DOCKER=podman
DOCKER_RUN="--userns=keep-id"
IMAGE="localhost/$IMAGE"
fi
if [ -z "$2" ]; then
CMAKE_BUILD_TYPE=Debug
else
@@ -20,23 +29,28 @@ else
fi
TAG="$1"
if [ "$1" = 18 ]; then
UBUNTU_VERSION="18.04"
DEPS="llvm-10-dev liblld-10-dev libclang-10-dev"
elif [ "$1" = 20 ]; then
if [ "$1" = 20 ]; then
UBUNTU_VERSION="20.04"
DEPS="llvm-11-dev liblld-11-dev clang-11 libllvm11 llvm-11-runtime"
LLVM_VERSION="12"
elif [ "$1" = 21 ]; then
UBUNTU_VERSION="21.10"
LLVM_VERSION="13"
elif [ "$1" = 22 ]; then
UBUNTU_VERSION="22.04"
LLVM_VERSION="14"
else
echo "ERROR: expected 18 or 20 as Ubuntu version argument" 1>&2
echo "ERROR: expected 20, 21 or 22 as Ubuntu version argument" 1>&2
exit 2
fi
IMAGE="$IMAGE:$TAG"
cd docker && docker build -t c3c-builder:$TAG --build-arg UID=$(id -u) --build-arg GID=$(id -g) \
--build-arg DEPS="$DEPS" --build-arg UBUNTU_VERSION="$UBUNTU_VERSION" .
cd docker && $DOCKER build -t $IMAGE --build-arg UID=$(id -u) --build-arg GID=$(id -g) \
--build-arg DEPS="llvm-$LLVM_VERSION-dev liblld-$LLVM_VERSION-dev clang-$LLVM_VERSION libllvm$LLVM_VERSION llvm-$LLVM_VERSION-runtime" \
--build-arg UBUNTU_VERSION="$UBUNTU_VERSION" .
cd ..
rm -rf build bin lib
rm -rf build bin
mkdir -p build bin
exec docker run -ti --rm -v "$PWD":/home/c3c/source -w /home/c3c/source c3c-builder:$TAG bash -c \
"cd build && cmake -DLLVM_DIR=/usr/lib/llvm-11/cmake -DCMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE .. && cmake --build . && mv c3c ../bin/ && mv lib ../lib"
exec $DOCKER run -ti --rm --tmpfs=/tmp $DOCKER_RUN -v "$PWD":/home/c3c/source -w /home/c3c/source $IMAGE bash -c \
"cd build && cmake -DCMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE -DC3_LLVM_VERSION=$LLVM_VERSION .. && cmake --build . && mv c3c lib ../bin/"

5
lib/std/atomic.c3 Normal file
View File

@@ -0,0 +1,5 @@
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::atomic;

View File

@@ -0,0 +1,182 @@
module std::core::mem::allocator;
private struct DynamicArenaPage
{
void* memory;
void* prev_arena;
usize total;
usize used;
void* last_ptr;
}
/**
* @require ptr && this
* @require this.page `tried to free pointer on invalid allocator`
*/
private fn void DynamicArenaAllocator.free(DynamicArenaAllocator* this, void* ptr)
{
DynamicArenaPage* current_page = this.page;
if (ptr == current_page.last_ptr)
{
current_page.used = (usize)((ptr - DEFAULT_SIZE_PREFIX) - current_page.memory);
}
current_page.last_ptr = null;
}
/**
* @require old_pointer && size > 0
* @require this.page `tried to realloc pointer on invalid allocator`
*/
private fn void*! DynamicArenaAllocator.realloc(DynamicArenaAllocator* this, void* old_pointer, usize size, usize alignment)
{
DynamicArenaPage* current_page = this.page;
alignment = alignment_for_allocation(alignment);
usize* old_size_ptr = old_pointer - DEFAULT_SIZE_PREFIX;
usize old_size = *old_size_ptr;
// We have the old pointer and it's correctly aligned.
if (old_size >= size && mem::ptr_is_aligned(old_pointer, alignment))
{
*old_size_ptr = size;
if (current_page.last_ptr == old_pointer)
{
current_page.used = (usize)((old_pointer - DEFAULT_SIZE_PREFIX) - current_page.memory);
}
return old_pointer;
}
if REUSE: (current_page.last_ptr == old_pointer && mem::ptr_is_aligned(old_pointer, alignment))
{
assert(size > old_size);
usize add_size = size - old_size;
if (add_size + current_page.used > current_page.total) break REUSE;
*old_size_ptr = size;
current_page.used += add_size;
return old_pointer;
}
void* new_mem = this.alloc(size, alignment)?;
mem::copy(new_mem, old_pointer, old_size);
return new_mem;
}
private fn void DynamicArenaAllocator.reset(DynamicArenaAllocator* this)
{
DynamicArenaPage* page = this.page;
DynamicArenaPage** unused_page_ptr = &this.unused_page;
while (page)
{
DynamicArenaPage* next_page = page.prev_arena;
page.used = 0;
DynamicArenaPage* prev_unused = *unused_page_ptr;
*unused_page_ptr = page;
page.prev_arena = prev_unused;
page = next_page;
}
this.page = page;
}
/**
* @require math::is_power_of_2(alignment)
* @require size > 0
*/
private fn void*! DynamicArenaAllocator.alloc_new(DynamicArenaAllocator* this, usize size, usize alignment)
{
usize page_size = max(this.page_size, size + DEFAULT_SIZE_PREFIX + alignment);
void* mem = this.backing_allocator.alloc(page_size)?;
DynamicArenaPage*! page = this.backing_allocator.alloc(DynamicArenaPage.sizeof);
if (catch err = page)
{
this.backing_allocator.free(mem)?;
return err!;
}
page.memory = mem;
usize offset = mem::aligned_offset((usize)mem + DEFAULT_SIZE_PREFIX, alignment) - (usize)mem;
usize* size_ptr = mem + offset - DEFAULT_SIZE_PREFIX;
*size_ptr = size;
page.prev_arena = this.page;
page.total = page_size;
page.used = size + offset;
this.page = page;
return page.last_ptr = page.memory + offset;
}
/**
* @require !alignment || math::is_power_of_2(alignment)
* @require size > 0
* @require this
*/
private fn void*! DynamicArenaAllocator.alloc(DynamicArenaAllocator* this, usize size, usize alignment)
{
alignment = alignment_for_allocation(alignment);
DynamicArenaPage* page = this.page;
if (!page && this.unused_page)
{
this.page = page = this.unused_page;
this.unused_page = page.prev_arena;
page.prev_arena = null;
}
if (!page) return this.alloc_new(size, alignment);
usize start = mem::aligned_offset((uptr)page.memory + page.used + DEFAULT_SIZE_PREFIX, alignment) - (usize)page.memory;
usize new_used = start + size;
if ALLOCATE_NEW: (new_used > page.total)
{
if ((page = this.unused_page))
{
start = mem::aligned_offset((uptr)page.memory + DEFAULT_SIZE_PREFIX, alignment) - (usize)page.memory;
new_used = start + size;
if (page.total >= new_used)
{
this.unused_page = page.prev_arena;
page.prev_arena = this.page;
this.page = page;
break ALLOCATE_NEW;
}
}
return this.alloc_new(size, alignment);
}
page.used = new_used;
void* mem = page.memory + start;
usize* size_offset = mem - DEFAULT_SIZE_PREFIX;
*size_offset = size;
return mem;
}
/**
* @require !alignment || math::is_power_of_2(alignment)
* @require data `unexpectedly missing the allocator`
*/
private fn void*! dynamic_arena_allocator_function(Allocator* data, usize size, usize alignment, void* old_pointer, AllocationKind kind)
{
DynamicArenaAllocator* allocator = (DynamicArenaAllocator*)data;
switch (kind)
{
case CALLOC:
assert(!old_pointer, "Unexpected no old pointer for calloc.");
if (!size) return null;
void* mem = allocator.alloc(size, alignment)?;
mem::set(mem, 0, size);
return mem;
case ALLOC:
assert(!old_pointer, "Unexpected no old pointer for alloc.");
if (!size) return null;
return allocator.alloc(size, alignment);
case REALLOC:
if (!size)
{
if (!old_pointer) return null;
allocator.free(old_pointer);
return null;
}
if (!old_pointer) return allocator.alloc(size, alignment);
void* mem = allocator.realloc(old_pointer, size, alignment)?;
return mem;
case FREE:
if (!old_pointer) return null;
allocator.free(old_pointer);
return null;
case RESET:
allocator.reset();
return null;
}
unreachable();
}

View File

@@ -0,0 +1,68 @@
module std::core::mem::allocator;
import libc;
private const Allocator _NULL_ALLOCATOR = { &null_allocator_fn };
private const Allocator _SYSTEM_ALLOCATOR = { &libc_allocator_fn };
private fn void*! null_allocator_fn(Allocator* this, usize bytes, usize alignment, void* old_pointer, AllocationKind kind)
{
switch (kind)
{
case ALLOC:
case CALLOC:
case REALLOC:
return AllocationFailure.OUT_OF_MEMORY!;
default:
return null;
}
}
fn void*! libc_allocator_fn(Allocator* unused, usize bytes, usize alignment, void* old_pointer, AllocationKind kind) @inline
{
if (!alignment) alignment = DEFAULT_MEM_ALIGNMENT;
assert(math::is_power_of_2(alignment), "Alignment was not a power of 2");
void* data;
switch (kind)
{
case ALLOC:
if (alignment > DEFAULT_MEM_ALIGNMENT)
{
data = (void*)mem::aligned_offset((iptr)libc::malloc(bytes + alignment), alignment);
}
else
{
data = libc::malloc(bytes);
}
if (!data) return AllocationFailure.OUT_OF_MEMORY!;
return data;
case CALLOC:
if (alignment > DEFAULT_MEM_ALIGNMENT)
{
data = (void*)mem::aligned_offset((iptr)libc::calloc(bytes + alignment, 1), alignment);
}
else
{
data = libc::malloc(bytes);
}
if (!data) return AllocationFailure.OUT_OF_MEMORY!;
return data;
case REALLOC:
if (alignment > DEFAULT_MEM_ALIGNMENT)
{
data = (void*)mem::aligned_offset((iptr)libc::realloc(old_pointer, bytes + alignment), alignment);
}
else
{
data = libc::realloc(old_pointer, bytes);
}
if (!data) return AllocationFailure.OUT_OF_MEMORY!;
return data;
case RESET:
return AllocationFailure.UNSUPPORTED_OPERATION!;
case FREE:
libc::free(old_pointer);
return null;
}
unreachable();
}

View File

@@ -0,0 +1,82 @@
module std::core::mem::allocator;
/**
* @require !alignment || math::is_power_of_2(alignment)
* @require data `unexpectedly missing the allocator`
*/
private fn void*! arena_allocator_function(Allocator* data, usize size, usize alignment, void* old_pointer, AllocationKind kind)
{
MemoryArena* arena = (MemoryArena*)data;
switch (kind)
{
case CALLOC:
case ALLOC:
assert(!old_pointer, "Unexpected old pointer for alloc.");
if (!size) return null;
alignment = alignment_for_allocation(alignment);
void* mem = arena.alloc(size, alignment, DEFAULT_SIZE_PREFIX)?;
*(usize*)(mem - DEFAULT_SIZE_PREFIX) = size;
if (kind == AllocationKind.CALLOC) mem::set(mem, 0, size);
return mem;
case REALLOC:
if (!size) nextcase FREE;
if (!old_pointer) nextcase ALLOC;
assert((uptr)old_pointer >= (uptr)arena.memory, "Pointer originates from a different allocator.");
if (size > arena.total) return AllocationFailure.OUT_OF_MEMORY!;
alignment = alignment_for_allocation(alignment);
usize* old_size_ptr = (usize*)(old_pointer - DEFAULT_SIZE_PREFIX);
usize old_size = *old_size_ptr;
// Do last allocation and alignment match?
if (arena.memory + arena.used == old_pointer + old_size && mem::ptr_is_aligned(old_pointer, alignment))
{
if (old_size >= size)
{
*old_size_ptr = size;
arena.used -= old_size - size;
return old_pointer;
}
usize new_used = arena.used + size - old_size;
if (new_used > arena.total) return AllocationFailure.OUT_OF_MEMORY!;
arena.used = new_used;
*old_size_ptr = size;
return old_pointer;
}
// Otherwise just allocate new memory.
void* mem = arena.alloc(size, alignment, DEFAULT_SIZE_PREFIX)?;
*(usize*)(mem - DEFAULT_SIZE_PREFIX) = size;
mem::copy(mem, old_pointer, old_size);
return mem;
case FREE:
if (!old_pointer) return null;
assert((uptr)old_pointer >= (uptr)arena.memory, "Pointer originates from a different allocator.");
usize old_size = *(usize*)(old_pointer - DEFAULT_SIZE_PREFIX);
if (old_pointer + old_size == arena.memory + arena.used)
{
arena.used -= old_size;
}
return null;
case RESET:
arena.used = 0;
return null;
}
unreachable();
}
/**
* @require alignment > 0 `alignment must be non zero`
* @require math::is_power_of_2(alignment)
* @require size > 0
* @require alignment <= MAX_MEMORY_ALIGNMENT `alignment too big`
* @require this != null
**/
private fn void*! MemoryArena.alloc(MemoryArena* this, usize size, usize alignment, usize prefixed_bytes = 0)
{
void* start_mem = this.memory;
void* unaligned_pointer = start_mem + this.used + prefixed_bytes;
if ((uptr)unaligned_pointer < (uptr)start_mem) return AllocationFailure.OUT_OF_MEMORY!;
usize offset_start = mem::aligned_offset((usize)(uptr)unaligned_pointer, alignment) - (usize)(uptr)start_mem;
usize end = offset_start + size;
if (end > this.total || end < offset_start) return AllocationFailure.OUT_OF_MEMORY!;
this.used = end;
return start_mem + offset_start;
}

115
lib/std/core/builtin.c3 Normal file
View File

@@ -0,0 +1,115 @@
// Copyright (c) 2021-2022 Christoffer Lerno and contributors. All rights reserved.
// Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::core::builtin;
import libc;
fault IteratorResult
{
NO_MORE_ELEMENT
}
fault SearchResult
{
MISSING
}
fault VarCastResult
{
TYPE_MISMATCH
}
/**
* Stores a variable on the stack, then restores it at the end of the
* macro scope.
*
* @param variable `the variable to store and restore`
**/
macro void @scope(&variable; @body) @builtin
{
$typeof(variable) temp = variable;
defer variable = temp;
@body();
}
macro void @swap(&a, &b) @builtin
{
$typeof(a) temp = a;
a = b;
b = temp;
}
/**
* Convert a variant type to a type, returning an failure if there is a type mismatch.
*
* @param v `the variant to convert to the given type.`
* @param $Type `the type to convert to`
* @return `The variant.ptr converted to its type.`
**/
macro varcast(variant v, $Type) @builtin
{
if (v.type != $Type.typeid) return VarCastResult.TYPE_MISMATCH!;
return ($Type*)v.ptr;
}
struct CallstackElement
{
CallstackElement* prev;
char* function;
char* file;
uint line;
}
fn void panic(char* message, char *file, char *function, uint line) @builtin
{
CallstackElement* stack = $$stacktrace();
$if ($defined(libc::stderr) && $defined(libc::fprintf)):
if (stack) stack = stack.prev;
if (stack)
{
libc::fprintf(libc::stderr(), "\nERROR: '%s'\n", message);
}
else
{
libc::fprintf(libc::stderr(), "\nERROR: '%s', function %s (%s:%d)\n", message, function, file, line);
}
while (stack)
{
libc::fprintf(libc::stderr(), " at function %s (%s:%u)\n", stack.function, stack.file, stack.line);
if (stack == stack.prev) break;
stack = stack.prev;
}
$endif;
$$trap();
}
macro void unreachable($string = "Unreachable statement reached.") @builtin @noreturn
{
panic($string, $$FILE, $$FUNC, $$LINE);
$$unreachable();
}
macro bitcast(expr, $Type) @builtin
{
var $size = (usize)($sizeof(expr));
$assert($size == $Type.sizeof, "Cannot bitcast between types of different size.");
$Type x = void;
mem::memcpy(&x, &expr, $size, false, $alignof($Type), $alignof(expr));
return x;
}
/**
* @require $Type.kind == TypeKind.ENUM `Only enums may be used`
**/
macro enum_by_name($Type, char[] enum_name) @builtin
{
typeid x = $Type.typeid;
foreach (i, name : x.names)
{
if (str::compare(name, enum_name)) return ($Type)i;
}
return SearchResult.MISSING!;
}

View File

@@ -0,0 +1,76 @@
// Copyright (c) 2021-2022 Christoffer Lerno and contributors. All rights reserved.
// Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::core::builtin;
/**
* @require is_comparable_value(a) && is_comparable_value(b)
**/
macro less(a, b) @builtin
{
$if ($defined(a.less)):
return a.less(b);
$elif ($defined(a.compare_to)):
return a.compare_to(b) < 0;
$else:
return a < b;
$endif;
}
/**
* @require is_comparable_value(a) && is_comparable_value(b)
**/
macro less_eq(a, b) @builtin
{
$if ($defined(a.less)):
return !b.less(a);
$elif ($defined(a.compare_to)):
return a.compare_to(b) <= 0;
$else:
return a <= b;
$endif;
}
/**
* @require is_comparable_value(a) && is_comparable_value(b)
**/
macro greater(a, b) @builtin
{
$if ($defined(a.less)):
return b.less(a);
$elif ($defined(a.compare_to)):
return a.compare_to(b) > 0;
$else:
return a > b;
$endif;
}
/**
* @require is_comparable_value(a) && is_comparable_value(b)
**/
macro greater_eq(a, b) @builtin
{
$if ($defined(a.less)):
return !a.less(b);
$elif ($defined(a.compare_to)):
return a.compare_to(b) >= 0;
$else:
return a >= b;
$endif;
}
/**
* @require is_equatable_value(a) && is_equatable_value(b) `values must be equatable`
**/
macro bool equals(a, b) @builtin
{
$if ($defined(a.equals)):
return a.equals(b);
$elif ($defined(a.compare_to)):
return a.compare_to(b) == 0;
$elif ($defined(a.less)):
return !a.less(b) && !b.less(a);
$else:
return a == b;
$endif;
}

View File

@@ -1,9 +1,12 @@
module std::cinterop;
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::core::cinterop;
const C_INT_SIZE = ${C_INT_SIZE};
const C_LONG_SIZE = ${C_LONG_SIZE};
const C_SHORT_SIZE = ${C_SHORT_SIZE};
const C_LONG_LONG_SIZE = ${C_LONG_LONG_SIZE};
const C_INT_SIZE = $$C_INT_SIZE;
const C_LONG_SIZE = $$C_LONG_SIZE;
const C_SHORT_SIZE = $$C_SHORT_SIZE;
const C_LONG_LONG_SIZE = $$C_LONG_LONG_SIZE;
$assert (C_SHORT_SIZE < 32);
$assert (C_INT_SIZE < 128);
@@ -13,65 +16,71 @@ $assert (C_SHORT_SIZE <= C_INT_SIZE);
$assert (C_INT_SIZE <= C_LONG_SIZE);
$assert (C_LONG_SIZE <= C_LONG_LONG_SIZE);
$if (C_INT_SIZE == 64):
$switch ($$C_INT_SIZE):
$case 64:
define CInt = long;
define CUInt = ulong;
$elif (C_INT_SIZE == 32):
$case 32:
define CInt = int;
define CUInt = uint;
$elif (C_INT_SIZE == 16):
$case 16:
define CInt = short;
define CUInt = ushort;
$else:
$default:
$assert(false, "Invalid C int size");
$endif;
$endswitch;
$if (C_LONG_SIZE == 64):
$switch ($$C_LONG_SIZE):
$case 64:
define CLong = long;
define CULong = ulong;
$elif (C_LONG_SIZE == 32):
$case 32:
define CLong = int;
define CULong = uint;
$elif (C_LONG_SIZE == 16):
$case 16:
define CLong = short;
define CULong = ushort;
$else:
$default:
$assert(false, "Invalid C long size");
$endif;
$endswitch;
$if (C_SHORT_SIZE == 32):
$switch ($$C_SHORT_SIZE):
$case 32:
define CShort = int;
define CUShort = uint;
$elif (C_SHORT_SIZE == 16):
$case 16:
define CShort = short;
define CUShort = ushort;
$elif (C_SHORT_SIZE == 8):
$case 8:
define CShort = ichar;
define CUShort = char;
$else:
$default:
$assert(false, "Invalid C short size");
$endif;
$endswitch;
$if (C_LONG_LONG_SIZE == 128):
$switch ($$C_LONG_LONG_SIZE):
$case 128:
define CLongLong = int128;
define CULongLong = uint128;
$elif (C_LONG_LONG_SIZE == 64):
$case 64:
define CLongLong = long;
define CULongLong = ulong;
$elif (C_LONG_LONG_SIZE == 32):
$case 32:
define CLongLong = int;
define CULongLong = uint;
$elif (C_LONG_LONG_SIZE == 16):
$case 16:
define CLongLong = short;
define CULongLong = ushort;
$else:
$default:
$assert(false, "Invalid C long long size");
$endif;
$endswitch;
define CSChar = ichar;
define CUChar = char;
$if (${C_CHAR_IS_SIGNED}):
$if ($$C_CHAR_IS_SIGNED):
define CChar = ichar;
$else:
define CChar = char;

404
lib/std/core/conv.c3 Normal file
View File

@@ -0,0 +1,404 @@
module std::core::string::conv;
private const uint UTF16_SURROGATE_OFFSET = 0x10000;
private const uint UTF16_SURROGATE_GENERIC_MASK = 0xF800;
private const uint UTF16_SURROGATE_GENERIC_VALUE = 0xD800;
private const uint UTF16_SURROGATE_MASK = 0xFC00;
private const uint UTF16_SURROGATE_CODEPOINT_MASK = 0x03FF;
private const uint UTF16_SURROGATE_BITS = 10;
private const uint UTF16_SURROGATE_LOW_VALUE = 0xDC00;
private const uint UTF16_SURROGATE_HIGH_VALUE = 0xD800;
/**
* @param c `The utf32 codepoint to convert`
* @param [out] output `the resulting buffer`
* @param available `the size available`
**/
fn usize! char32_to_utf8(Char32 c, char* output, usize available)
{
if (!available) return UnicodeResult.CONVERSION_FAILED!;
switch (true)
{
case c < 0x7f:
output[0] = (char)c;
return 1;
case c < 0x7ff:
if (available < 2) return UnicodeResult.CONVERSION_FAILED!;
output[0] = (char)(0xC0 | c >> 6);
output[1] = (char)(0x80 | (c & 0x3F));
return 2;
case c < 0xffff:
if (available < 3) return UnicodeResult.CONVERSION_FAILED!;
output[0] = (char)(0xE0 | c >> 12);
output[1] = (char)(0x80 | (c >> 6 & 0x3F));
output[2] = (char)(0x80 | (c & 0x3F));
return 3;
default:
if (available < 4) return UnicodeResult.CONVERSION_FAILED!;
output[0] = (char)(0xF0 | c >> 18);
output[1] = (char)(0x80 | (c >> 12 & 0x3F));
output[2] = (char)(0x80 | (c >> 6 & 0x3F));
output[3] = (char)(0x80 | (c & 0x3F));
return 4;
}
}
/**
* Convert a code pointer into 1-2 UTF16 characters.
*
* @param c `The character to convert.`
* @param [inout] output `the resulting UTF16 buffer to write to.`
**/
fn void char32_to_utf16_unsafe(Char32 c, Char16** output)
{
if (c < UTF16_SURROGATE_OFFSET)
{
(*output)++[0] = (Char16)c;
return;
}
c -= UTF16_SURROGATE_OFFSET;
Char16 low = (Char16)(UTF16_SURROGATE_LOW_VALUE | (c & UTF16_SURROGATE_CODEPOINT_MASK));
c >>= UTF16_SURROGATE_BITS;
Char16 high = (Char16)(UTF16_SURROGATE_HIGH_VALUE | (c & UTF16_SURROGATE_CODEPOINT_MASK));
(*output)++[0] = (Char16)high;
(*output)++[0] = (Char16)low;
}
/**
* Convert 1-2 UTF16 data points into UTF8.
*
* @param [in] ptr `The UTF16 data to convert.`
* @param [inout] available `amount of UTF16 data available.`
* @param [inout] output `the resulting utf8 buffer to write to.`
**/
fn void! char16_to_utf8_unsafe(Char16 *ptr, usize *available, char** output)
{
Char16 high = *ptr;
if (high & UTF16_SURROGATE_GENERIC_MASK != UTF16_SURROGATE_GENERIC_VALUE)
{
char32_to_utf8_unsafe(high, output);
*available = 1;
return;
}
// Low surrogate first is an error
if (high & UTF16_SURROGATE_MASK != UTF16_SURROGATE_HIGH_VALUE) return UnicodeResult.INVALID_UTF16!;
// Unmatched high surrogate is an error
if (*available == 1) return UnicodeResult.INVALID_UTF16!;
Char16 low = ptr[1];
// Unmatched high surrogate, invalid
if (low & UTF16_SURROGATE_MASK != UTF16_SURROGATE_LOW_VALUE) return UnicodeResult.INVALID_UTF16!;
// The high bits of the codepoint are the value bits of the high surrogate
// The low bits of the codepoint are the value bits of the low surrogate
Char32 uc = (high & UTF16_SURROGATE_CODEPOINT_MASK) << UTF16_SURROGATE_BITS
| (low & UTF16_SURROGATE_CODEPOINT_MASK) + UTF16_SURROGATE_OFFSET;
char32_to_utf8_unsafe(uc, output);
*available = 2;
}
/**
* @param c `The utf32 codepoint to convert`
* @param [inout] output `the resulting buffer`
**/
fn void char32_to_utf8_unsafe(Char32 c, char** output)
{
switch (true)
{
case c < 0x7f:
(*output)++[0] = (char)c;
case c < 0x7ff:
(*output)++[0] = (char)(0xC0 | c >> 6);
(*output)++[0] = (char)(0x80 | (c & 0x3F));
case c < 0xffff:
(*output)++[0] = (char)(0xE0 | c >> 12);
(*output)++[0] = (char)(0x80 | (c >> 6 & 0x3F));
(*output)++[0] = (char)(0x80 | (c & 0x3F));
default:
(*output)++[0] = (char)(0xF0 | c >> 18);
(*output)++[0] = (char)(0x80 | (c >> 12 & 0x3F));
(*output)++[0] = (char)(0x80 | (c >> 6 & 0x3F));
(*output)++[0] = (char)(0x80 | (c & 0x3F));
}
}
/**
* @param [in] ptr `pointer to the first character to parse`
* @param [inout] size `Set to max characters to read, set to characters read`
* @return `the parsed 32 bit codepoint`
**/
fn Char32! utf8_to_char32(char* ptr, usize* size)
{
usize max_size = *size;
if (max_size < 1) return UnicodeResult.INVALID_UTF8!;
char c = (ptr++)[0];
if ((c & 0x80) == 0)
{
*size = 1;
return c;
}
if ((c & 0xE0) == 0xC0)
{
if (max_size < 2) return UnicodeResult.INVALID_UTF8!;
*size = 2;
Char32 uc = (c & 0x1F) << 6;
c = *ptr;
if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8!;
return uc + c & 0x3F;
}
if ((c & 0xF0) == 0xE0)
{
if (max_size < 3) return UnicodeResult.INVALID_UTF8!;
*size = 3;
Char32 uc = (c & 0x0F) << 12;
c = ptr++[0];
if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8!;
uc += (c & 0x3F) << 6;
c = ptr++[0];
if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8!;
return uc + c & 0x3F;
}
if (max_size < 4) return UnicodeResult.INVALID_UTF8!;
*size = 4;
Char32 uc = (c & 0x07) << 18;
c = ptr++[0];
if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8!;
uc += (c & 0x3F) << 12;
c = ptr++[0];
if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8!;
uc += (c & 0x3F) << 6;
c = ptr++[0];
if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8!;
return uc + c & 0x3F;
}
/**
* @param utf8 `An UTF-8 encoded slice of bytes`
* @return `the number of encoded code points`
**/
fn usize utf8_codepoints(char[] utf8)
{
usize len = 0;
foreach (char c : utf8)
{
if (c & 0xC0 != 0x80) len++;
}
return len;
}
/**
* Calculate the UTF8 length required to encode an UTF32 array.
* @param [in] utf32 `the utf32 data to calculate from`
* @return `the length of the resulting UTF8 array`
**/
fn usize utf8len_for_utf32(Char32[] utf32)
{
usize len = 0;
foreach (Char32 uc : utf32)
{
switch (true)
{
case uc < 0x7f:
len++;
case uc < 0x7ff:
len += 2;
case uc < 0xffff:
len += 3;
default:
len += 4;
}
}
return len;
}
/**
* Calculate the UTF8 length required to encode an UTF16 array.
* @param [in] utf16 `the utf16 data to calculate from`
* @return `the length of the resulting UTF8 array`
**/
fn usize utf8len_for_utf16(Char16[] utf16)
{
usize len = 0;
usize len16 = utf16.len;
for (usize i = 0; i < len16; i++)
{
Char16 c = utf16[i];
if (c & UTF16_SURROGATE_GENERIC_MASK != UTF16_SURROGATE_GENERIC_VALUE)
{
if (c < 0x7f)
{
len++;
continue;
}
if (c < 0x7ff)
{
len += 2;
continue;
}
len += 3;
continue;
}
len += 4;
}
return len;
}
/**
* Calculate the UTF16 length required to encode a UTF8 array.
* @param utf8 `the utf8 data to calculate from`
* @return `the length of the resulting UTF16 array`
**/
fn usize utf16len_for_utf8(char[] utf8)
{
usize len = utf8.len;
usize len16 = 0;
for (usize i = 0; i < len; i++)
{
len16++;
char c = utf8[i];
if (c & 0x80 == 0) continue;
i++;
if (c & 0xE0 == 0xC0) continue;
i++;
if (c & 0xF0 == 0xE0) continue;
i++;
len16++;
}
return len16;
}
/**
* @param [in] utf32 `the UTF32 array to check the length for`
* @return `the required length of an UTF16 array to hold the UTF32 data.`
**/
fn usize utf16len_for_utf32(Char32[] utf32)
{
usize len = utf32.len;
foreach (Char32 uc : utf32)
{
if (uc >= UTF16_SURROGATE_OFFSET) len++;
}
return len;
}
/**
* Convert an UTF32 array to an UTF8 array.
*
* @param [in] utf32
* @param [out] utf8_buffer
* @return `the number of bytes written.`
**/
fn usize! utf32to8(Char32[] utf32, char[] utf8_buffer)
{
usize len = utf8_buffer.len;
char* ptr = utf8_buffer.ptr;
foreach (Char32 uc : utf32)
{
usize used = char32_to_utf8(uc, ptr, len) @inline?;
len -= used;
ptr += used;
}
return utf8_buffer.len - len;
}
/**
* Convert an UTF8 array to an UTF32 array.
*
* @param [in] utf8
* @param [out] utf32_buffer
* @return `the number of Char32s written.`
**/
fn usize! utf8to32(char[] utf8, Char32[] utf32_buffer)
{
usize len = utf8.len;
Char32* ptr = utf32_buffer.ptr;
usize len32 = 0;
usize buf_len = utf32_buffer.len;
for (usize i = 0; i < len;)
{
if (len32 == buf_len) return UnicodeResult.CONVERSION_FAILED!;
usize width = len - i;
Char32 uc = utf8_to_char32(&utf8[i], &width) @inline?;
i += width;
ptr[len32++] = uc;
}
return len32;
}
/**
* Copy an array of UTF16 data into an UTF8 buffer without bounds
* checking. This will assume the buffer is sufficiently large to hold
* the converted data.
*
* @param [in] utf16 `The UTF16 array containing the data to convert.`
* @param [out] utf8_buffer `the (sufficiently large) buffer to hold the UTF16 data.`
**/
fn void! utf16to8_unsafe(Char16[] utf16, char* utf8_buffer)
{
usize len16 = utf16.len;
for (usize i = 0; i < len16;)
{
usize available = len16 - i;
char16_to_utf8_unsafe(&utf16[i], &available, &utf8_buffer) @inline?;
i += available;
}
}
/**
* Copy an array of UTF8 data into an UTF32 buffer without bounds
* checking. This will assume the buffer is sufficiently large to hold
* the converted data.
*
* @param [in] utf8 `The UTF8 buffer containing the data to convert.`
* @param [out] utf32_buffer `the (sufficiently large) buffer to hold the UTF8 data.`
**/
fn void! utf8to32_unsafe(char[] utf8, Char32* utf32_buffer)
{
usize len = utf8.len;
for (usize i = 0; i < len;)
{
usize width = len - i;
Char32 uc = utf8_to_char32(&utf8[i], &width) @inline?;
i += width;
(utf32_buffer++)[0] = uc;
}
}
/**
* Copy an array of UTF8 data into an UTF16 buffer without bounds
* checking. This will assume the buffer is sufficiently large to hold
* the converted data.
*
* @param [in] utf8 `The UTF8 buffer containing the data to convert.`
* @param [out] utf16_buffer `the (sufficiently large) buffer to hold the UTF8 data.`
**/
fn void! utf8to16_unsafe(char[] utf8, Char16* utf16_buffer)
{
usize len = utf8.len;
for (usize i = 0; i < len;)
{
usize width = len - i;
Char32 uc = utf8_to_char32(&utf8[i], &width) @inline?;
char32_to_utf16_unsafe(uc, &utf16_buffer) @inline;
i += width;
}
}
/**
* Copy an array of UTF32 code points into an UTF8 buffer without bounds
* checking. This will assume the buffer is sufficiently large to hold
* the converted data.
*
* @param [in] utf32 `The UTF32 buffer containing the data to convert.`
* @param [out] utf8_buffer `the (sufficiently large) buffer to hold the UTF8 data.`
**/
fn void utf32to8_unsafe(Char32[] utf32, char* utf8_buffer)
{
char* start = utf8_buffer;
foreach (Char32 uc : utf32)
{
char32_to_utf8_unsafe(uc, &utf8_buffer) @inline;
}
}

58
lib/std/core/env.c3 Normal file
View File

@@ -0,0 +1,58 @@
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::core::env;
enum CompilerOptLevel
{
O0,
O1,
O2,
O3
}
enum OsType
{
UNKNOWN,
NONE,
ANANAS,
CLOUD_ABI,
DRAGON_FLY,
FREEBSD,
FUCHSIA,
IOS,
KFREEBSD,
LINUX,
PS3,
MACOSX,
NETBSD,
OPENBSD,
SOLARIS,
WIN32,
HAIKU,
MINIX,
RTEMS,
NACL, // Native Client
CNK, // BG/P Compute-Node Kernel
AIX,
CUDA,
NVOPENCL,
AMDHSA,
PS4,
ELFIAMCU,
TVOS,
WATCHOS,
MESA3D,
CONTIKI,
AMDPAL,
HERMITCORE,
HURD,
WASI,
EMSCRIPTEN,
}
const OsType OS_TYPE = (OsType)($$OS_TYPE);
const CompilerOptLevel COMPILER_OPT_LEVEL = (CompilerOptLevel)($$COMPILER_OPT_LEVEL);
const bool BIG_ENDIAN = $$PLATFORM_BIG_ENDIAN;
const bool I128_SUPPORT = $$PLATFORM_I128_SUPPORTED;
const bool COMPILER_SAFE_MODE = $$COMPILER_SAFE_MODE;

150
lib/std/core/mem.c3 Normal file
View File

@@ -0,0 +1,150 @@
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::core::mem;
macro @volatile_load(&x)
{
return $$volatile_load(&x);
}
macro @volatile_store(&x, y)
{
return $$volatile_store(&x, y);
}
/**
* @require math::is_power_of_2(alignment)
**/
fn usize aligned_offset(usize offset, usize alignment)
{
return alignment * ((offset + alignment - 1) / alignment);
}
/**
* @require math::is_power_of_2(alignment)
**/
fn bool ptr_is_aligned(void* ptr, usize alignment) @inline
{
return (uptr)ptr & ((uptr)alignment - 1) == 0;
}
fn void copy(char* dst, char* src, usize size) @inline
{
memcpy(dst, src, size);
}
macro void memcpy(void* dst, void* src, usize size, bool $is_volatile = false, usize $dst_align = 0, usize $src_align = 0)
{
$$memcpy(dst, src, size, $is_volatile, $dst_align, $src_align);
}
fn void set(void* dst, char val, usize bytes) @inline
{
memset(dst, val, bytes);
}
macro void memset(void* dst, char val, usize bytes, bool $is_volatile = false, usize $dst_align = 0)
{
$$memset(dst, val, bytes, $is_volatile, $dst_align);
}
macro @clone(&value) @builtin
{
$typeof(value)* x = malloc($typeof(value));
*x = value;
return x;
}
macro malloc($Type) @builtin
{
return ($Type*)(mem::alloc($Type.sizeof));
}
fn char[] alloc_bytes(usize bytes) @inline
{
return ((char*)thread_allocator.alloc(bytes, 1))[0..bytes - 1]!!;
}
/**
* @require !alignment || math::is_power_of_2(alignment)
*/
fn void* alloc(usize size, usize alignment = 0)
{
return thread_allocator.alloc(size, alignment)!!;
}
/**
* @require !alignment || math::is_power_of_2(alignment)
*/
fn void*! alloc_checked(usize size, usize alignment = 0)
{
return thread_allocator.alloc(size, alignment);
}
/**
* @require !alignment || math::is_power_of_2(alignment)
*/
fn void* calloc(usize size, usize alignment = 0)
{
return thread_allocator.calloc(size, alignment)!!;
}
/**
* @require !alignment || math::is_power_of_2(alignment)
*/
fn void*! calloc_checked(usize size, usize alignment = 0)
{
return thread_allocator.calloc(size, alignment);
}
/**
* @require !alignment || math::is_power_of_2(alignment)
*/
fn void* realloc(void *ptr, usize new_size, usize alignment = 0)
{
return thread_allocator.realloc(ptr, new_size, alignment)!!;
}
/**
* @require !alignment || math::is_power_of_2(alignment)
*/
fn void*! realloc_checked(void *ptr, usize new_size, usize alignment = 0)
{
return thread_allocator.realloc(ptr, new_size, alignment);
}
fn void free(void* ptr) @builtin
{
return thread_allocator.free(ptr)!!;
}
/**
* Run with a specific allocator inside of the macro body.
**/
macro void @with_allocator(Allocator* allocator; @body())
{
Allocator* old_allocator = thread_allocator;
thread_allocator = allocator;
defer thread_allocator = old_allocator;
@body();
}
fn void*! talloc(usize size)
{
return temp_allocator.alloc(size);
}
private tlocal Allocator* thread_allocator = allocator::LIBC_ALLOCATOR;
macro Allocator* current_allocator()
{
return thread_allocator;
}

View File

@@ -0,0 +1,151 @@
module std::core::mem::allocator;
const MAX_MEMORY_ALIGNMENT = 0x1000_0000;
const DEFAULT_MEM_ALIGNMENT = $alignof(void*) * 2;
const DEFAULT_SIZE_PREFIX = usize.sizeof;
const DEFAULT_SIZE_PREFIX_ALIGNMENT = $alignof(usize);
const Allocator* NULL_ALLOCATOR = &_NULL_ALLOCATOR;
const Allocator* LIBC_ALLOCATOR = &_SYSTEM_ALLOCATOR;
define AllocatorFunction = fn void*!(Allocator* allocator, usize new_size, usize alignment, void* old_pointer, AllocationKind kind);
struct Allocator
{
AllocatorFunction function;
}
enum AllocationKind
{
ALLOC,
CALLOC,
REALLOC,
FREE,
RESET,
}
fault AllocationFailure
{
OUT_OF_MEMORY,
UNSUPPORTED_OPERATION,
}
/**
* @require !alignment || math::is_power_of_2(alignment)
*/
fn void*! Allocator.alloc(Allocator* allocator, usize size, usize alignment = 0) @inline
{
return allocator.function(allocator, size, alignment, null, ALLOC);
}
/**
* @require !alignment || math::is_power_of_2(alignment)
*/
fn void*! Allocator.realloc(Allocator* allocator, void* old_pointer, usize size, usize alignment = 0) @inline
{
return allocator.function(allocator, size, alignment, old_pointer, REALLOC);
}
/**
* @require !alignment || math::is_power_of_2(alignment)
*/
fn void*! Allocator.calloc(Allocator* allocator, usize size, usize alignment = 0) @inline
{
return allocator.function(allocator, size, alignment, null, CALLOC);
}
fn void! Allocator.free(Allocator* allocator, void* old_pointer) @inline
{
allocator.function(allocator, 0, 0, old_pointer, FREE)?;
}
fn void Allocator.reset(Allocator* allocator)
{
allocator.function(allocator, 0, 0, null, RESET)!!;
}
private fn usize alignment_for_allocation(usize alignment) @inline
{
if (alignment < DEFAULT_MEM_ALIGNMENT)
{
alignment = DEFAULT_SIZE_PREFIX_ALIGNMENT;
}
return alignment;
}
struct DynamicArenaAllocator
{
inline Allocator allocator;
Allocator* backing_allocator;
DynamicArenaPage* page;
DynamicArenaPage* unused_page;
usize page_size;
}
/**
* @require page_size >= 128
* @require this != null
**/
fn void DynamicArenaAllocator.init(DynamicArenaAllocator* this, usize page_size, Allocator* backing_allocator = mem::allocator())
{
this.function = &dynamic_arena_allocator_function;
this.page = null;
this.unused_page = null;
this.page_size = page_size;
this.backing_allocator = backing_allocator;
}
/**
* @require this != null
**/
fn void DynamicArenaAllocator.destroy(DynamicArenaAllocator* this)
{
DynamicArenaPage* page = this.page;
while (page)
{
DynamicArenaPage* next_page = page.prev_arena;
this.backing_allocator.free(page)!!;
page = next_page;
}
page = this.unused_page;
while (page)
{
DynamicArenaPage* next_page = page.prev_arena;
this.backing_allocator.free(page)!!;
page = next_page;
}
this.page = null;
this.unused_page = null;
}
struct MemoryArena
{
inline Allocator allocator;
void* memory;
usize total;
usize used;
}
/**
* Initialize a memory arena for use using the provided bytes.
*
* @require this != null
**/
fn void MemoryArena.init(MemoryArena* this, char[] data)
{
this.function = &arena_allocator_function;
this.memory = data.ptr;
this.total = data.len;
this.used = 0;
}
/**
* @require this != null
**/
fn void MemoryArena.reset(MemoryArena* this)
{
this.used = 0;
}

22
lib/std/core/mem_array.c3 Normal file
View File

@@ -0,0 +1,22 @@
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::core::mem::array;
/**
* @require usize.max / elements > $Type.sizeof
**/
macro alloc($Type, usize elements)
{
$Type* ptr = mem::alloc($Type.sizeof * elements, $alignof($Type));
return ptr[:elements];
}
/**
* @require (usize.max / elements > $Type.sizeof)
**/
macro make($Type, usize elements)
{
$Type* ptr = mem::calloc($sizeof($Type) * elements, $alignof($Type));
return ptr[:elements];
}

View File

@@ -1,52 +1,50 @@
module std::mem;
module std::core::mem;
extern func void* _malloc(usize bytes) @extname("malloc");
extern func void* _realloc(void* ptr, usize bytes) @extname("realloc");
extern func void* _calloc(usize bytes, usize elements) @extname("calloc");
extern func void _free(void* ptr) @extname("free");
const TEMP_BLOCK_SIZE = 1024;
const TEMP_PAGES = 64;
enum AllocationKind
private char[TEMP_BLOCK_SIZE * TEMP_PAGES] allocator_static_storage;
private void*[TEMP_PAGES] allocator_static_page_storage;
SlotAllocator temp_allocator = {
.pages = &allocator_static_storage,
.page_size = TEMP_BLOCK_SIZE,
.page_count = TEMP_PAGES,
.bitmask = TEMP_PAGES - 1,
.current_page = 0,
};
struct SlotAllocator
{
ALLOC,
REALLOC,
FREE,
void* pages;
usize page_size;
usize page_count;
usize bitmask;
usize current_page;
}
errtype AllocationFailure
fn void*! SlotAllocator.alloc(SlotAllocator *allocator, usize size)
{
OUT_OF_MEMORY
}
define AllocatorFunction = func void!(void *data, void** pointer, usize bytes, usize alignment, AllocationKind kind);
struct Allocator
{
AllocatorFunction allocation_function;
void *data;
}
func void! system_malloc_function(void *unused, void** pointer, usize bytes, usize alignment, AllocationKind kind) @inline
{
switch (kind)
void* active_page = (char*)(allocator.pages) + allocator.current_page * allocator.page_size;
void** page_pointer = (void**)(active_page);
if (*page_pointer)
{
case ALLOC:
void* data = _malloc(bytes);
if (!data) return AllocationFailure.OUT_OF_MEMORY!;
*pointer = data;
return;
case REALLOC:
void* data = _realloc(*pointer, bytes);
if (!data) return AllocationFailure.OUT_OF_MEMORY!;
*pointer = data;
return;
case FREE:
_free(*pointer);
*pointer = null;
return;
// TODO fix
thread_allocator.free(*page_pointer)?;
*page_pointer = null;
}
$unreachable;
if (size > allocator.page_size - $sizeof(page_pointer))
{
void* mem = thread_allocator.alloc(size)?;
*page_pointer = mem;
allocator.current_page = (allocator.current_page + 1) & (allocator.bitmask);
return mem;
}
allocator.current_page = (allocator.current_page + 1) & (allocator.bitmask);
return &page_pointer[1];
}
struct RingAllocator
{
char *data;
@@ -55,7 +53,7 @@ struct RingAllocator
}
func void* RingAllocator.alloc(RingAllocator *allocator, usize size)
fn void* RingAllocator.alloc(RingAllocator *allocator, usize size)
{
if (size > allocator.size) return null;
// Wraparound? If so, start at the beginning.
@@ -69,7 +67,7 @@ func void* RingAllocator.alloc(RingAllocator *allocator, usize size)
return data;
}
func void* RingAllocator.realloc(RingAllocator *allocator, void* ptr, usize size)
fn void* RingAllocator.realloc(RingAllocator *allocator, void* ptr, usize size)
{
if (size > allocator.size) return null;
assert(allocator.data >= ptr && ptr < allocator.data + size, "Realloc on other allocator.");
@@ -106,29 +104,3 @@ func void* RingAllocator.realloc(RingAllocator *allocator, void* ptr, usize size
return allocator.data;
}
Allocator main_allocator = { &system_malloc_function, null };
macro malloc($Type)
{
return ($Type*)(mem::alloc($sizeof($Type)));
}
func void* alloc(usize size, usize elements = 1) @inline
{
return _malloc(size * elements);
}
func void* calloc(usize size, usize elements = 1) @inline
{
return _calloc(size, elements);
}
func void* realloc(void *ptr, usize size) @inline
{
return _realloc(ptr, size);
}
func void free(void* ptr) @inline
{
_free(ptr);
}

17
lib/std/core/os/linux.c3 Normal file
View File

@@ -0,0 +1,17 @@
module std::core::os::linux;
$if (env::OS_TYPE == OsType.LINUX):
extern fn int* __errno_location();
fn int errno() @inline
{
return *__errno_location();
}
fn void errno_set(int err)
{
*(__errno_location()) = err;
}
$endif;

14
lib/std/core/os/macos.c3 Normal file
View File

@@ -0,0 +1,14 @@
module std::core::os::macos;
$if (env::OS_TYPE == OsType.MACOSX):
extern fn int* __error();
fn int errno() @inline
{
return *__error();
}
fn void errno_set(int err)
{
*(__error()) = err;
}
$endif;

View File

@@ -0,0 +1,10 @@
module std::core::os::windows;
$if (env::OS_TYPE == OsType.WIN32):
extern fn int getLastError() @stdcall @extname("GetLastError");
fn int errno() @inline
{
return getLastError();
}
$endif;

160
lib/std/core/str.c3 Normal file
View File

@@ -0,0 +1,160 @@
module std::core::str;
define ZString = distinct char*;
define Char32 = uint;
define Char16 = ushort;
private const uint SURROGATE_OFFSET = 0x10000;
private const uint SURROGATE_GENERIC_MASK = 0xF800;
private const uint SURROGATE_MASK = 0xFC00;
private const uint SURROGATE_CODEPOINT_MASK = 0x03FF;
private const uint SURROGATE_BITS = 10;
private const uint SURROGATE_LOW_VALUE = 0xDC00;
private const uint SURROGATE_HIGH_VALUE = 0xD800;
fn String join(char[][] s, char[] joiner)
{
if (!s.len) return (String)null;
usize total_size = joiner.len * s.len;
foreach (char[]* &str : s)
{
total_size += str.len;
}
String res = string::new_with_capacity(total_size);
res.append(s[0]);
foreach (char[]* &str : s[1..])
{
res.append(joiner);
res.append(*str);
}
return res;
}
fn ZString copy_zstring(char[] s)
{
usize len = s.len;
char* str = mem::alloc(len + 1);
mem::copy(str, s.ptr, len);
str[len] = 0;
return (ZString)str;
}
fn ZString tcopy_zstring(char[] s)
{
usize len = s.len;
char* str = mem::talloc(len + 1)!!;
mem::copy(str, s.ptr, len);
str[len] = 0;
return (ZString)str;
}
fn bool compare(char[] a, char[] b)
{
if (a.len != b.len) return false;
foreach (i, c : a)
{
if (c != b[i]) return false;
}
return true;
}
fault UnicodeResult
{
INVALID_UTF8,
INVALID_UTF16,
CONVERSION_FAILED,
}
fn usize utf8_codepoints(char[] utf8)
{
usize len = 0;
foreach (char c : utf8)
{
if (c & 0xC0 != 0x80) len++;
}
return len;
}
fn Char32[]! utf8to32(char[] utf8, Allocator* allocator = mem::current_allocator)
{
usize codepoints = conv::utf8_codepoints(utf8);
Char32* data = allocator.alloc(Char32.sizeof * (codepoints + 1))?;
conv::utf8to32_unsafe(utf8, data)?;
data[codepoints] = 0;
return data[0..codepoints - 1];
}
fn char[] utf32to8(Char32[] utf32, Allocator* allocator = mem::current_allocator)
{
usize len = conv::utf8len_for_utf32(utf32);
char* data = allocator.alloc(len + 1)!!;
conv::utf32to8_unsafe(utf32, data);
data[len] = 0;
return data[0..len - 1];
}
fn Char16[]! utf8to16(char[] utf8, Allocator* allocator = mem::current_allocator)
{
usize len16 = conv::utf16len_for_utf8(utf8);
Char16* data = allocator.alloc((len16 + 1) * Char16.sizeof)?;
conv::utf8to16_unsafe(utf8, data)?;
data[len16] = 0;
return data[0..len16 - 1];
}
fn char[]! utf16to8(Char16[] utf16, Allocator* allocator = mem::current_allocator())
{
usize len = conv::utf8len_for_utf16(utf16);
char* data = allocator.alloc(len + 1)?;
conv::utf16to8_unsafe(utf16, data)?;
return data[0 .. len - 1];
}
fn char[] copy(char[] s)
{
usize len = s.len;
ZString str_copy = copy_zstring(s) @inline;
return str_copy[..len];
}
fn char[] tcopy(char[] s)
{
usize len = s.len;
ZString str_copy = tcopy_zstring(s) @inline;
return str_copy[..len];
}
fn char[] tconcat(char[] s1, char[] s2)
{
usize full_len = s1.len + s2.len;
char* str = mem::talloc(full_len + 1)!!;
usize s1_len = s1.len;
mem::copy(str, s1.ptr, s1_len);
mem::copy(str + s1_len, s2.ptr, s2.len);
str[full_len] = 0;
return str[..full_len];
}
fn char[] concat(char[] s1, char[] s2)
{
usize full_len = s1.len + s2.len;
char* str = mem::alloc(full_len + 1);
usize s1_len = s1.len;
mem::copy(str, s1.ptr, s1_len);
mem::copy(str + s1_len, s2.ptr, s2.len);
str[full_len] = 0;
return str[..full_len];
}
fn usize ZString.len(ZString *str)
{
usize len = 0;
char* ptr = (char*)*str;
while (char c = ptr++[0])
{
if (c & 0xC0 != 0x80) len++;
}
return len;
}

299
lib/std/core/string.c3 Normal file
View File

@@ -0,0 +1,299 @@
module std::core::string;
import libc;
define String = distinct void*;
private struct StringData
{
Allocator* allocator;
usize len;
usize capacity;
char[*] chars;
}
const usize MIN_CAPACITY = 16;
fn String new_with_capacity(usize capacity, Allocator* allocator = mem::current_allocator())
{
if (capacity < MIN_CAPACITY) capacity = MIN_CAPACITY;
StringData* data = allocator.alloc(StringData.sizeof + capacity)!!;
data.allocator = allocator;
data.len = 0;
data.capacity = capacity;
return (String)data;
}
fn String new(char[] c)
{
usize len = c.len;
String str = new_with_capacity(len);
StringData* data = str.data();
if (len)
{
data.len = len;
mem::copy(&data.chars, c.ptr, len);
}
return (String)data;
}
fn ZString String.zstr(String str)
{
StringData* data = str.data();
if (!data) return (ZString)"";
if (data.capacity == data.len)
{
str.reserve(1);
data.chars[data.len] = 0;
}
else if (data.chars[data.len] != 0)
{
data.chars[data.len] = 0;
}
return (ZString)&data.chars[0];
}
fn usize String.len(String this)
{
if (!this) return 0;
return this.data().len;
}
/**
* @require new_size <= this.len()
*/
fn void String.chop(String this, usize new_size)
{
if (!this) return;
this.data().len = new_size;
}
fn char[] String.str(String str)
{
StringData* data = (StringData*)str;
if (!data) return char[] {};
return data.chars[:data.len];
}
fn void String.append_utf32(String* str, Char32[] chars)
{
str.reserve(chars.len);
foreach (Char32 c : chars)
{
str.append_char32(c);
}
}
/**
* @require index < str.len()
**/
fn void String.set(String str, usize index, char c)
{
str.data().chars[index] = c;
}
fn void String.append_repeat(String* str, char c, usize times)
{
if (times == 0) return;
str.reserve(times);
StringData* data = str.data();
for (usize i = 0; i < times; i++)
{
data.chars[data.len++] = c;
}
}
/**
* @require c < 0x10ffff
*/
fn void String.append_char32(String* str, Char32 c)
{
if (c < 0x7f)
{
str.reserve(1);
StringData* data = str.data();
data.chars[data.len++] = (char)c;
return;
}
if (c < 0x7ff)
{
str.reserve(2);
StringData* data = str.data();
data.chars[data.len++] = (char)(0xC0 | c >> 6);
data.chars[data.len++] = (char)(0x80 | (c & 0x3F));
return;
}
if (c < 0xffff)
{
str.reserve(3);
StringData* data = str.data();
data.chars[data.len++] = (char)(0xE0 | c >> 12);
data.chars[data.len++] = (char)(0x80 | (c >> 6 & 0x3F));
data.chars[data.len++] = (char)(0x80 | (c & 0x3F));
return;
}
str.reserve(4);
StringData* data = str.data();
data.chars[data.len++] = (char)(0xF0 | c >> 18);
data.chars[data.len++] = (char)(0x80 | (c >> 12 & 0x3F));
data.chars[data.len++] = (char)(0x80 | (c >> 6 & 0x3F));
data.chars[data.len++] = (char)(0x80 | (c & 0x3F));
}
fn String String.copy(String* str, Allocator* allocator = null)
{
if (!str)
{
if (allocator) return new_with_capacity(0, allocator);
return (String)null;
}
if (!allocator) allocator = mem::current_allocator();
StringData* data = str.data();
String new_string = new_with_capacity(data.capacity, allocator);
mem::copy((char*)new_string.data(), (char*)data, StringData.sizeof + data.len);
return new_string;
}
fn ZString String.copy_zstr(String* str, Allocator* allocator = mem::current_allocator())
{
usize str_len = str.len();
if (!str_len)
{
return (ZString)allocator.calloc(1, 1)!!;
}
char* zstr = allocator.alloc(str_len + 1)!!;
StringData* data = str.data();
mem::copy(zstr, &data.chars, str_len);
zstr[str_len] = 0;
return (ZString)zstr;
}
fn char[] String.copy_str(String* str, Allocator* allocator = mem::current_allocator())
{
return str.copy_zstr(allocator)[:str.len()];
}
fn bool String.equals(String str, String other_string)
{
StringData *str1 = str.data();
StringData *str2 = other_string.data();
if (str1 == str2) return true;
if (!str1) return str2.len == 0;
if (!str2) return str1.len == 0;
usize str1_len = str1.len;
if (str1_len != str2.len) return false;
for (int i = 0; i < str1_len; i++)
{
if (str1.chars[i] != str2.chars[i]) return false;
}
return true;
}
fn void String.destroy(String* str)
{
if (!*str) return;
StringData* data = str.data();
if (!data) return;
data.allocator.free(data)!!;
*str = (String)null;
}
fn bool String.less(String str, String other_string)
{
StringData* str1 = str.data();
StringData* str2 = other_string.data();
if (str1 == str2) return false;
if (!str1) return str2.len != 0;
if (!str2) return str1.len == 0;
usize str1_len = str1.len;
usize str2_len = str2.len;
if (str1_len != str2_len) return str1_len < str2_len;
for (int i = 0; i < str1_len; i++)
{
if (str1.chars[i] >= str2.chars[i]) return false;
}
return true;
}
fn void String.append_chars(String* this, char[] str)
{
usize other_len = str.len;
if (!other_len) return;
if (!*this)
{
*this = new(str);
return;
}
this.reserve(other_len);
StringData* data = (StringData*)*this;
mem::copy(&data.chars[data.len], str.ptr, other_len);
data.len += other_len;
}
fn Char32[] String.copy_utf32(String* this, Allocator* allocator = mem::current_allocator())
{
return str::utf8to32(this.str(), allocator) @inline!!;
}
fn void String.append_string(String* this, String str)
{
StringData* other = (StringData*)str;
if (!other) return;
this.append(str.str());
}
fn void String.append_char(String* str, char c)
{
if (!*str)
{
*str = new_with_capacity(MIN_CAPACITY);
}
str.reserve(1);
StringData* data = (StringData*)*str;
data.chars[data.len++] = c;
}
macro void String.append(String* str, value)
{
var $Type = $typeof(value);
$switch ($Type):
$case char:
$case ichar:
str.append_char(value);
$case String:
str.append_string(value);
$case char[]:
str.append_chars(value);
$case Char32:
str.append_char32(value);
$default:
$if ($convertible($Type, Char32)):
str.append_char32(value);
$elif ($convertible($Type, char[])):
str.append_chars(value);
$else:
$assert("Unsupported type for appending");
$endif;
$endswitch;
}
private fn StringData* String.data(String str) @inline
{
return (StringData*)str;
}
private fn void String.reserve(String* str, usize addition)
{
StringData* data = str.data();
if (!data)
{
*str = string::new_with_capacity(addition);
return;
}
usize len = data.len + addition;
if (data.capacity >= len) return;
usize new_capacity = data.capacity * 2;
if (new_capacity < MIN_CAPACITY) new_capacity = MIN_CAPACITY;
*str = (String)data.allocator.realloc(data, StringData.sizeof + new_capacity)!!;
}

View File

@@ -0,0 +1,25 @@
module std::core::string::iterator;
struct StringIterator
{
char[] utf8;
usize current;
}
fn void StringIterator.reset(StringIterator* this)
{
this.current = 0;
}
fn Char32! StringIterator.next(StringIterator* this)
{
usize len = this.utf8.len;
usize current = this.current;
if (current >= len) return IteratorResult.NO_MORE_ELEMENT!;
usize read = (len - current < 4 ? len - current : 4);
Char32 res = conv::utf8_to_char32(&this.utf8[current], &read)?;
this.current += read;
return res;
}

159
lib/std/core/types.c3 Normal file
View File

@@ -0,0 +1,159 @@
module std::core::types;
import libc;
fault ConversionResult
{
VALUE_OUT_OF_RANGE,
VALUE_OUT_OF_UNSIGNED_RANGE,
}
/**
* @require type.kind == SIGNED_INT || type.kind == UNSIGNED_INT || type.kind == ENUM, "Argument was not an integer"
**/
macro variant_to_int(variant v, $Type)
{
typeid variant_type = v.type;
TypeKind kind = variant_type.kind;
if (kind == TypeKind.ENUM)
{
variant_type = variant_type.inner;
kind = variant_type.kind;
}
bool is_mixed_signed = $Type.kind != variant_type.kind;
$Type max = $Type.max;
$Type min = $Type.min;
switch (variant_type)
{
case ichar:
ichar c = *(char*)v.ptr;
if (is_mixed_signed && c < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE!;
return ($Type)c;
case short:
short s = *(short*)v.ptr;
if (is_mixed_signed && s < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE!;
if (s > max || s < min) return ConversionResult.VALUE_OUT_OF_RANGE!;
return ($Type)s;
case int:
int i = *(int*)v.ptr;
if (is_mixed_signed && i < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE!;
if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE!;
return ($Type)i;
case long:
long l = *(long*)v.ptr;;
if (is_mixed_signed && l < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE!;
if (l > max || l < min) return ConversionResult.VALUE_OUT_OF_RANGE!;
return ($Type)l;
case int128:
$if (env::I128_SUPPORT):
int128 i = *(int128*)v.ptr;
if (is_mixed_signed && i < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE!;
if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE!;
return ($Type)i;
$else:
unreachable();
$endif;
case char:
char c = *(char*)v.ptr;
if (c > max) return ConversionResult.VALUE_OUT_OF_RANGE!;
return ($Type)c;
case ushort:
ushort s = *(ushort*)v.ptr;;
if (s > max || s < min) return ConversionResult.VALUE_OUT_OF_RANGE!;
return ($Type)s;
case uint:
uint i = *(uint*)v.ptr;;
if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE!;
return ($Type)i;
case ulong:
ulong l = *(ulong*)v.ptr;;
if (l > max || l < min) return ConversionResult.VALUE_OUT_OF_RANGE!;
return ($Type)l;
case uint128:
$if (env::I128_SUPPORT):
uint128 i = *(uint128*)v.ptr;
if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE!;
return ($Type)i;
$else:
unreachable();
$endif;
default:
unreachable();
}
}
macro bool is_numerical($Type)
{
var $kind = $Type.kind;
$if ($kind == TypeKind.DISTINCT):
return is_numerical($Type.inner);
$else:
return $kind == TypeKind.SIGNED_INT || $kind == TypeKind.UNSIGNED_INT || $kind == TypeKind.FLOAT
|| $kind == TypeKind.VECTOR;
$endif;
}
fn bool TypeKind.is_int(TypeKind kind) @inline
{
return kind == TypeKind.SIGNED_INT || kind == TypeKind.UNSIGNED_INT;
}
macro bool is_comparable($Type)
{
var $kind = $Type.kind;
$if ($kind == TypeKind.DISTINCT):
return is_comparable($Type.inner);
$else:
return $kind == TypeKind.SIGNED_INT || $kind == TypeKind.UNSIGNED_INT || $kind == TypeKind.FLOAT
|| $kind == TypeKind.VECTOR || $kind == TypeKind.BOOL || $kind == TypeKind.POINTER
|| $kind == TypeKind.ENUM;
$endif;
}
macro bool is_equatable_value(value)
{
$if ($defined(value.less) || $defined(value.compare_to) || $defined(value.equals)):
return true;
$else:
return is_comparable($typeof(value));
$endif;
}
macro bool is_comparable_value(value)
{
$if ($defined(value.less) || $defined(value.compare_to)):
return true;
$else:
return is_comparable($typeof(value));
$endif;
}
enum TypeKind : char
{
VOID,
BOOL,
SIGNED_INT,
UNSIGNED_INT,
FLOAT,
TYPEID,
ANYERR,
ANY,
ENUM,
FAULT,
STRUCT,
UNION,
BITSTRUCT,
FUNC,
FAILABLE,
ARRAY,
SUBARRAY,
VECTOR,
DISTINCT,
POINTER,
VARIANT
}
struct TypeEnum
{
TypeKind type;
usize elements;
}

83
lib/std/enumset.c3 Normal file
View File

@@ -0,0 +1,83 @@
// TODO: ensure the type is an enum first.
module std::enumset<Enum>;
$assert(Enum.elements < 64, "Maximum number of elements for an enum used as enum set is 63");
$switch ($$C_INT_SIZE):
$case 64:
private define EnumSetType = ulong;
$case 32:
$if (Enum.elements < 32):
private define EnumSetType = uint;
$else:
private define EnumSetType = ulong;
$endif;
$default:
$if (Enum.elements < 16):
private define EnumSetType = ushort;
$elif (Enum.elements < 31):
private define EnumSetType = uint;
$else:
private define EnumSetType = ulong;
$endif;
$endswitch;
define EnumSet = distinct EnumSetType;
fn void EnumSet.add(EnumSet* this, Enum v)
{
*this = (EnumSet)((EnumSetType)*this | 1u << (EnumSetType)v);
}
fn void EnumSet.clear(EnumSet* this)
{
*this = 0;
}
fn bool EnumSet.remove(EnumSet* this, Enum v)
{
EnumSetType old = (EnumSetType)*this;
EnumSetType new = old & ~(1u << (EnumSetType)v);
*this = (EnumSet)new;
return old != new;
}
fn bool EnumSet.has(EnumSet* this, Enum v)
{
return ((EnumSetType)*this & (1u << (EnumSetType)v)) != 0;
}
fn void EnumSet.add_all(EnumSet* this, EnumSet s)
{
*this = (EnumSet)((EnumSetType)*this | (EnumSetType)s);
}
fn void EnumSet.retain_all(EnumSet* this, EnumSet s)
{
*this = (EnumSet)((EnumSetType)*this & (EnumSetType)s);
}
fn void EnumSet.remove_all(EnumSet* this, EnumSet s)
{
*this = (EnumSet)((EnumSetType)*this & ~(EnumSetType)s);
}
fn EnumSet EnumSet.and_of(EnumSet* this, EnumSet s)
{
return (EnumSet)((EnumSetType)*this & (EnumSetType)s);
}
fn EnumSet EnumSet.or_of(EnumSet* this, EnumSet s)
{
return (EnumSet)((EnumSetType)*this | (EnumSetType)s);
}
fn EnumSet EnumSet.diff_of(EnumSet* this, EnumSet s)
{
return (EnumSet)((EnumSetType)*this & ~(EnumSetType)s);
}
fn EnumSet EnumSet.xor_of(EnumSet* this, EnumSet s)
{
return (EnumSet)((EnumSetType)*this ^ (EnumSetType)s);
}

53
lib/std/hash/adler32.c3 Normal file
View File

@@ -0,0 +1,53 @@
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::hash::adler32;
private const uint ADLER_CONST = 65521;
struct Adler32
{
uint a;
uint b;
}
fn void Adler32.init(Adler32 *this)
{
*this = { 1, 0 };
}
fn void Adler32.updatec(Adler32* this, char c)
{
this.a = (this.a + c) % ADLER_CONST;
this.b = (this.b + this.a) % ADLER_CONST;
}
fn void Adler32.update(Adler32* this, char[] data)
{
uint a = this.a;
uint b = this.b;
foreach (char x : data)
{
a = (a + x) % ADLER_CONST;
b = (b + a) % ADLER_CONST;
}
*this = { a, b };
}
fn uint Adler32.final(Adler32* this)
{
return (this.b << 16) | this.a;
}
fn uint encode(char[] data)
{
uint a = 1;
uint b = 0;
foreach (char x : data)
{
a = (a + x) % ADLER_CONST;
b = (b + a) % ADLER_CONST;
}
return (b << 16) | a;
}

111
lib/std/hash/crc32.c3 Normal file
View File

@@ -0,0 +1,111 @@
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::hash::crc32;
struct Crc32
{
uint result;
}
fn void Crc32.init(Crc32* this, uint seed = 0)
{
this.result = ~seed;
}
fn void Crc32.updatec(Crc32* this, char c)
{
this.result = (this.result >> 8) ^ CRC32_TABLE[(this.result ^ c) & 0xFF];
}
fn void Crc32.update(Crc32* this, char[] data)
{
uint result = this.result;
foreach (char x : data)
{
result = (result >> 8) ^ CRC32_TABLE[(result ^ x) & 0xFF];
}
this.result = result;
}
fn uint Crc32.final(Crc32* this)
{
return ~this.result;
}
fn uint encode(char[] data)
{
uint result = ~(uint)(0);
foreach (char x : data)
{
result = (result >> 8) ^ CRC32_TABLE[(result ^ x) & 0xFF];
}
return ~result;
}
private const uint[256] CRC32_TABLE = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
};

111
lib/std/hash/crc64.c3 Normal file
View File

@@ -0,0 +1,111 @@
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::hash::crc64;
struct Crc64
{
ulong result;
}
fn void Crc64.init(Crc64* this, uint seed = 0)
{
this.result = seed;
}
fn void Crc64.updatec(Crc64* this, char c)
{
this.result = (this.result << 8) ^ CRC64_TABLE[(char)((this.result >> 56) ^ c)];
}
fn void Crc64.update(Crc64* this, char[] data)
{
ulong result = this.result;
foreach (char x : data)
{
result = (result << 8) ^ CRC64_TABLE[(char)((result >> 56) ^ x)];
}
this.result = result;
}
fn ulong Crc64.final(Crc64* this)
{
return this.result;
}
fn ulong encode(char[] data)
{
ulong result = (ulong)(0);
foreach (char x : data)
{
result = (result << 8) ^ CRC64_TABLE[(char)((result >> 56) ^ x)];
}
return result;
}
private const ulong[256] CRC64_TABLE = {
0x0000000000000000, 0x42f0e1eba9ea3693, 0x85e1c3d753d46d26, 0xc711223cfa3e5bb5,
0x493366450e42ecdf, 0x0bc387aea7a8da4c, 0xccd2a5925d9681f9, 0x8e224479f47cb76a,
0x9266cc8a1c85d9be, 0xd0962d61b56fef2d, 0x17870f5d4f51b498, 0x5577eeb6e6bb820b,
0xdb55aacf12c73561, 0x99a54b24bb2d03f2, 0x5eb4691841135847, 0x1c4488f3e8f96ed4,
0x663d78ff90e185ef, 0x24cd9914390bb37c, 0xe3dcbb28c335e8c9, 0xa12c5ac36adfde5a,
0x2f0e1eba9ea36930, 0x6dfeff5137495fa3, 0xaaefdd6dcd770416, 0xe81f3c86649d3285,
0xf45bb4758c645c51, 0xb6ab559e258e6ac2, 0x71ba77a2dfb03177, 0x334a9649765a07e4,
0xbd68d2308226b08e, 0xff9833db2bcc861d, 0x388911e7d1f2dda8, 0x7a79f00c7818eb3b,
0xcc7af1ff21c30bde, 0x8e8a101488293d4d, 0x499b3228721766f8, 0x0b6bd3c3dbfd506b,
0x854997ba2f81e701, 0xc7b97651866bd192, 0x00a8546d7c558a27, 0x4258b586d5bfbcb4,
0x5e1c3d753d46d260, 0x1cecdc9e94ace4f3, 0xdbfdfea26e92bf46, 0x990d1f49c77889d5,
0x172f5b3033043ebf, 0x55dfbadb9aee082c, 0x92ce98e760d05399, 0xd03e790cc93a650a,
0xaa478900b1228e31, 0xe8b768eb18c8b8a2, 0x2fa64ad7e2f6e317, 0x6d56ab3c4b1cd584,
0xe374ef45bf6062ee, 0xa1840eae168a547d, 0x66952c92ecb40fc8, 0x2465cd79455e395b,
0x3821458aada7578f, 0x7ad1a461044d611c, 0xbdc0865dfe733aa9, 0xff3067b657990c3a,
0x711223cfa3e5bb50, 0x33e2c2240a0f8dc3, 0xf4f3e018f031d676, 0xb60301f359dbe0e5,
0xda050215ea6c212f, 0x98f5e3fe438617bc, 0x5fe4c1c2b9b84c09, 0x1d14202910527a9a,
0x93366450e42ecdf0, 0xd1c685bb4dc4fb63, 0x16d7a787b7faa0d6, 0x5427466c1e109645,
0x4863ce9ff6e9f891, 0x0a932f745f03ce02, 0xcd820d48a53d95b7, 0x8f72eca30cd7a324,
0x0150a8daf8ab144e, 0x43a04931514122dd, 0x84b16b0dab7f7968, 0xc6418ae602954ffb,
0xbc387aea7a8da4c0, 0xfec89b01d3679253, 0x39d9b93d2959c9e6, 0x7b2958d680b3ff75,
0xf50b1caf74cf481f, 0xb7fbfd44dd257e8c, 0x70eadf78271b2539, 0x321a3e938ef113aa,
0x2e5eb66066087d7e, 0x6cae578bcfe24bed, 0xabbf75b735dc1058, 0xe94f945c9c3626cb,
0x676dd025684a91a1, 0x259d31cec1a0a732, 0xe28c13f23b9efc87, 0xa07cf2199274ca14,
0x167ff3eacbaf2af1, 0x548f120162451c62, 0x939e303d987b47d7, 0xd16ed1d631917144,
0x5f4c95afc5edc62e, 0x1dbc74446c07f0bd, 0xdaad56789639ab08, 0x985db7933fd39d9b,
0x84193f60d72af34f, 0xc6e9de8b7ec0c5dc, 0x01f8fcb784fe9e69, 0x43081d5c2d14a8fa,
0xcd2a5925d9681f90, 0x8fdab8ce70822903, 0x48cb9af28abc72b6, 0x0a3b7b1923564425,
0x70428b155b4eaf1e, 0x32b26afef2a4998d, 0xf5a348c2089ac238, 0xb753a929a170f4ab,
0x3971ed50550c43c1, 0x7b810cbbfce67552, 0xbc902e8706d82ee7, 0xfe60cf6caf321874,
0xe224479f47cb76a0, 0xa0d4a674ee214033, 0x67c58448141f1b86, 0x253565a3bdf52d15,
0xab1721da49899a7f, 0xe9e7c031e063acec, 0x2ef6e20d1a5df759, 0x6c0603e6b3b7c1ca,
0xf6fae5c07d3274cd, 0xb40a042bd4d8425e, 0x731b26172ee619eb, 0x31ebc7fc870c2f78,
0xbfc9838573709812, 0xfd39626eda9aae81, 0x3a28405220a4f534, 0x78d8a1b9894ec3a7,
0x649c294a61b7ad73, 0x266cc8a1c85d9be0, 0xe17dea9d3263c055, 0xa38d0b769b89f6c6,
0x2daf4f0f6ff541ac, 0x6f5faee4c61f773f, 0xa84e8cd83c212c8a, 0xeabe6d3395cb1a19,
0x90c79d3fedd3f122, 0xd2377cd44439c7b1, 0x15265ee8be079c04, 0x57d6bf0317edaa97,
0xd9f4fb7ae3911dfd, 0x9b041a914a7b2b6e, 0x5c1538adb04570db, 0x1ee5d94619af4648,
0x02a151b5f156289c, 0x4051b05e58bc1e0f, 0x87409262a28245ba, 0xc5b073890b687329,
0x4b9237f0ff14c443, 0x0962d61b56fef2d0, 0xce73f427acc0a965, 0x8c8315cc052a9ff6,
0x3a80143f5cf17f13, 0x7870f5d4f51b4980, 0xbf61d7e80f251235, 0xfd913603a6cf24a6,
0x73b3727a52b393cc, 0x31439391fb59a55f, 0xf652b1ad0167feea, 0xb4a25046a88dc879,
0xa8e6d8b54074a6ad, 0xea16395ee99e903e, 0x2d071b6213a0cb8b, 0x6ff7fa89ba4afd18,
0xe1d5bef04e364a72, 0xa3255f1be7dc7ce1, 0x64347d271de22754, 0x26c49cccb40811c7,
0x5cbd6cc0cc10fafc, 0x1e4d8d2b65facc6f, 0xd95caf179fc497da, 0x9bac4efc362ea149,
0x158e0a85c2521623, 0x577eeb6e6bb820b0, 0x906fc95291867b05, 0xd29f28b9386c4d96,
0xcedba04ad0952342, 0x8c2b41a1797f15d1, 0x4b3a639d83414e64, 0x09ca82762aab78f7,
0x87e8c60fded7cf9d, 0xc51827e4773df90e, 0x020905d88d03a2bb, 0x40f9e43324e99428,
0x2cffe7d5975e55e2, 0x6e0f063e3eb46371, 0xa91e2402c48a38c4, 0xebeec5e96d600e57,
0x65cc8190991cb93d, 0x273c607b30f68fae, 0xe02d4247cac8d41b, 0xa2dda3ac6322e288,
0xbe992b5f8bdb8c5c, 0xfc69cab42231bacf, 0x3b78e888d80fe17a, 0x7988096371e5d7e9,
0xf7aa4d1a85996083, 0xb55aacf12c735610, 0x724b8ecdd64d0da5, 0x30bb6f267fa73b36,
0x4ac29f2a07bfd00d, 0x08327ec1ae55e69e, 0xcf235cfd546bbd2b, 0x8dd3bd16fd818bb8,
0x03f1f96f09fd3cd2, 0x41011884a0170a41, 0x86103ab85a2951f4, 0xc4e0db53f3c36767,
0xd8a453a01b3a09b3, 0x9a54b24bb2d03f20, 0x5d45907748ee6495, 0x1fb5719ce1045206,
0x919735e51578e56c, 0xd367d40ebc92d3ff, 0x1476f63246ac884a, 0x568617d9ef46bed9,
0xe085162ab69d5e3c, 0xa275f7c11f7768af, 0x6564d5fde549331a, 0x279434164ca30589,
0xa9b6706fb8dfb2e3, 0xeb46918411358470, 0x2c57b3b8eb0bdfc5, 0x6ea7525342e1e956,
0x72e3daa0aa188782, 0x30133b4b03f2b111, 0xf7021977f9cceaa4, 0xb5f2f89c5026dc37,
0x3bd0bce5a45a6b5d, 0x79205d0e0db05dce, 0xbe317f32f78e067b, 0xfcc19ed95e6430e8,
0x86b86ed5267cdbd3, 0xc4488f3e8f96ed40, 0x0359ad0275a8b6f5, 0x41a94ce9dc428066,
0xcf8b0890283e370c, 0x8d7be97b81d4019f, 0x4a6acb477bea5a2a, 0x089a2aacd2006cb9,
0x14dea25f3af9026d, 0x562e43b4931334fe, 0x913f6188692d6f4b, 0xd3cf8063c0c759d8,
0x5dedc41a34bbeeb2, 0x1f1d25f19d51d821, 0xd80c07cd676f8394, 0x9afce626ce85b507,
};

211
lib/std/io.c3 Normal file
View File

@@ -0,0 +1,211 @@
// Copyright (c) 2021-2022 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::io;
import libc;
struct File
{
CFile file;
}
fn int putchar(char c) @inline
{
return libc::putchar(c);
}
/**
* @param [&in] message
* @return `number of bytes printed.`
*/
fn int print(char* message)
{
char* pointer = message;
while (*pointer != '\0')
{
if (!putchar(*pointer)) return 0;
pointer++;
}
return 1;
}
/**
* @param [&in] message
* @return `number of bytes printed.`
*/
fn int println(char *message = "") @inline
{
return libc::puts(message);
}
fn void! File.open(File* file, char[] filename, char[] mode)
{
char* filename_copy = mem::talloc(filename.len + 1)!!;
char* mode_copy = mem::talloc(mode.len + 1)!!;
mem::copy(filename_copy, (char*)(filename), filename.len);
mem::copy(mode_copy, (char*)(mode), mode.len);
filename_copy[filename.len] = 0;
mode_copy[filename.len] = 0;
file.file = libc::fopen(filename_copy, mode_copy);
if (!file.file) return IoError.FILE_NOT_FOUND!;
}
enum Seek
{
SET,
CURSOR,
END
}
fault IoError
{
FILE_NOT_FOUND,
FILE_NOT_SEEKABLE,
FILE_NOT_VALID,
FILE_INVALID_POSITION,
FILE_OVERFLOW,
FILE_IS_PIPE,
FILE_EOF,
FILE_INCOMPLETE_WRITE,
INTERRUPTED,
UNKNOWN_ERROR,
}
/**
* @require file.file != null
**/
fn void! File.seek(File *file, long offset, Seek seekMode = Seek.SET)
{
if (libc::fseek(file.file, (SeekIndex)(offset), (int)(seekMode)))
{
switch (libc::errno())
{
case errno::EBADF: return IoError.FILE_NOT_SEEKABLE!;
case errno::EINVAL: return IoError.FILE_INVALID_POSITION!;
case errno::EOVERFLOW: return IoError.FILE_OVERFLOW!;
case errno::ESPIPE: return IoError.FILE_IS_PIPE!;
default: return IoError.UNKNOWN_ERROR!;
}
}
}
/**
* @require file && file.file != null
*/
fn void! File.putc(File *file, char c)
{
if (!libc::fputc(c, file.file)) return IoError.FILE_EOF!;
}
/**
* @require file != null
*/
fn void! File.close(File *file) @inline
{
if (file.file && libc::fclose(file.file))
{
switch (libc::errno())
{
case errno::ECONNRESET:
case errno::EBADF: return IoError.FILE_NOT_VALID!;
case errno::EINTR: return IoError.INTERRUPTED!;
case errno::EDQUOT:
case errno::EFAULT:
case errno::EAGAIN:
case errno::EFBIG:
case errno::ENETDOWN:
case errno::ENETUNREACH:
case errno::ENOSPC:
case errno::EIO: return IoError.FILE_INCOMPLETE_WRITE!;
default: return IoError.UNKNOWN_ERROR!;
}
}
file.file = null;
}
/**
* @require file && file.file
*/
fn bool File.eof(File* file) @inline
{
return libc::feof(file.file) != 0;
}
/**
* @require file && file.file
*/
fn usize File.read(File* file, void* buffer, usize items, usize element_size = 1)
{
return libc::fread(buffer, element_size, items, file.file);
}
/**
* @param [&in] file
* @param [&out] buffer
* @param items
* @param element_size
* @require file.file `File must be initialized`
* @require element_size > 1
*/
fn usize File.write(File* file, void* buffer, usize items, usize element_size = 1)
{
return libc::fwrite(buffer, element_size, items, file.file);
}
/**
* @param [&in] file
* @require file.file `File must be initialized`
*/
fn usize! File.println(File* file, char[] string)
{
usize len = string.len;
if (len != libc::fwrite(string.ptr, 1, len, file.file)) return IoError.UNKNOWN_ERROR!;
if (!libc::putc('\n', file.file)) return IoError.UNKNOWN_ERROR!;
return len + 1;
}
fn File stdout()
{
return { libc::stdout() };
}
fn File stderr()
{
return { libc::stderr() };
}
fn File stdin()
{
return { libc::stdin() };
}
/*
error FileError
{
ulong errno;
}
fn FileError errorFromErrno()
{
return FileError { };
}
pubic fn void! File.clearerr(File *file) @inline
{
clearerr(file->file);
}
fn void File.error(File *file) @inline
{
int err = ferror
}
*/

902
lib/std/io_printf.c3 Normal file
View File

@@ -0,0 +1,902 @@
module std::io;
import libc;
const int PRINTF_NTOA_BUFFER_SIZE = 256;
const int PRINTF_FTOA_BUFFER_SIZE = 256;
const float PRINTF_MAX_FLOAT = 1e9;
const uint PRINTF_DEFAULT_FLOAT_PRECISION = 6;
fault PrintFault
{
BUFFER_EXCEEDED,
INTERNAL_BUFFER_EXCEEDED,
INVALID_FORMAT_STRING,
MISSING_ARG,
}
bitstruct PrintFlags : uint
{
bool zeropad : 0;
bool left : 1;
bool plus : 2;
bool space : 3;
bool hash : 4;
bool uppercase : 5;
bool precision : 6;
bool adapt_exp : 7;
}
struct PrintParam
{
OutputFn outfn;
void* buffer;
PrintFlags flags;
uint width;
uint prec;
usize idx;
}
define OutputFn = fn void!(char c, void* buffer, usize buffer_idx);
fn void! PrintParam.out(PrintParam* param, char c)
{
param.outfn(c, param.buffer, param.idx++)?;
}
private fn void! out_str(PrintParam* param, variant arg)
{
switch (arg.type.kind)
{
case TYPEID:
return out_substr(param, "<typeid>");
case VOID:
return out_substr(param, "void");
case ANYERR:
case FAULT:
return out_substr(param, (*(anyerr*)arg.ptr).nameof);
case VARIANT:
return out_substr(param, "<variant>");
case ENUM:
return out_substr(param, arg.type.names[types::variant_to_int(arg, usize)!!]);
case STRUCT:
return out_substr(param, "<struct>");
case UNION:
return out_substr(param, "<union>");
case BITSTRUCT:
return out_substr(param, "<bitstruct>");
case FUNC:
return out_substr(param, "<func>");
case FAILABLE:
unreachable();
case DISTINCT:
if (arg.type == String.typeid)
{
return out_substr(param, ((String*)arg).str());
}
return out_str(param, variant { arg.ptr, arg.type.inner });
case POINTER:
typeid inner = arg.type.inner;
if (inner.kind == TypeKind.ARRAY && inner.inner == char.typeid)
{
char *ptr = *(char**)arg.ptr;
return out_substr(param, ptr[:inner.len]);
}
return ntoa_variant(param, arg, 16);
case SIGNED_INT:
case UNSIGNED_INT:
return ntoa_variant(param, arg, 10);
case FLOAT:
return ftoa(param, float_from_variant(arg));
case ARRAY:
// this is SomeType[*] so grab the "SomeType"
typeid inner = arg.type.inner;
usize size = inner.sizeof;
usize len = arg.type.len;
// Pretend this is a char[]
void* ptr = (void*)arg.ptr;
param.out('[')?;
for (usize i = 0; i < len; i++)
{
if (i != 0) out_substr(param, ", ")?;
out_str(param, variant { ptr, inner })?;
ptr += size;
}
return param.out(']');
case VECTOR:
// this is SomeType[*] so grab the "SomeType"
typeid inner = arg.type.inner;
usize size = inner.sizeof;
usize len = arg.type.len;
// Pretend this is a char[]
void* ptr = (void*)arg.ptr;
out_substr(param, "[<")?;
for (usize i = 0; i < len; i++)
{
if (i != 0) out_substr(param, ", ")?;
out_str(param, variant { ptr, inner })?;
ptr += size;
}
return out_substr(param, ">]");
case SUBARRAY:
// this is SomeType[] so grab the "SomeType"
typeid inner = arg.type.inner;
if (inner == char.typeid)
{
return out_substr(param, *(char[]*)arg);
}
usize size = inner.sizeof;
// Pretend this is a char[]
char[]* temp = (void*)arg.ptr;
void* ptr = (void*)temp.ptr;
usize len = temp.len;
param.out('[')?;
for (usize i = 0; i < len; i++)
{
if (i != 0) out_substr(param, ", ")?;
out_str(param, variant { ptr, inner })?;
ptr += size;
}
param.out(']')?;
case BOOL:
if (*(bool*)arg.ptr)
{
return out_substr(param, "true");
}
else
{
return out_substr(param, "false");
}
default:
return out_substr(param, "Invalid type");
}
}
private fn uint simple_atoi(char* buf, usize maxlen, usize* len_ptr) @inline
{
uint i = 0;
usize len = *len_ptr;
while (len < maxlen)
{
char c = buf[len];
if (c < '0' || c > '9') break;
i = i * 10 + c - '0';
len++;
}
*len_ptr = len;
return i;
}
fault FormattingFault
{
UNTERMINATED_FORMAT,
MISSING_ARG,
INVALID_WIDTH_ARG,
INVALID_FORMAT_TYPE,
}
private fn void! printf_advance_format(usize format_len, usize *index_ptr) @inline
{
usize val = ++(*index_ptr);
if (val >= format_len) return FormattingFault.UNTERMINATED_FORMAT!;
}
private fn variant! next_variant(variant* args_ptr, usize args_len, usize* arg_index_ptr) @inline
{
if (*arg_index_ptr >= args_len) return FormattingFault.MISSING_ARG!;
return args_ptr[(*arg_index_ptr)++];
}
private fn int! printf_parse_format_field(variant* args_ptr, usize args_len, usize* args_index_ptr, char* format_ptr, usize format_len, usize* index_ptr) @inline
{
char c = format_ptr[*index_ptr];
if (c >= '0' && c <= '9') return simple_atoi(format_ptr, format_len, index_ptr);
if (c != '*') return 0;
printf_advance_format(format_len, index_ptr)?;
variant val = next_variant(args_ptr, args_len, args_index_ptr)?;
if (!val.type.kind.is_int()) return FormattingFault.INVALID_WIDTH_ARG!;
uint! intval = types::variant_to_int(val, int);
if (catch intval) return FormattingFault.INVALID_WIDTH_ARG!;
return intval;
}
private fn void! out_buffer_fn(char c, char[] buffer, usize buffer_idx)
{
if (buffer_idx >= buffer.len) return PrintFault.BUFFER_EXCEEDED!;
buffer[buffer_idx] = c;
}
private fn void! out_null_fn(char c @unused, void* data @unused, usize idx @unused)
{
}
private fn void! out_putchar_fn(char c, void* data @unused, usize idx @unused)
{
libc::putchar(c);
}
private fn void! out_fputchar_fn(char c, void* data, usize idx @unused)
{
File* f = data;
f.putc(c)?;
}
private fn void! out_string_append_fn(char c, void* data, usize idx @unused)
{
String* s = data;
s.append_char(c);
}
private fn void! PrintParam.out_reverse(PrintParam* param, char[] buf)
{
usize buffer_start_idx = param.idx;
usize len = buf.len;
// pad spaces up to given width
if (!param.flags.left && !param.flags.zeropad)
{
for (usize i = len; i < param.width; i++)
{
param.out(' ')?;
}
}
// reverse string
while (len) param.out(buf[--len])?;
// append pad spaces up to given width
return param.left_adjust(param.idx - buffer_start_idx);
}
private fn void! out_char(PrintParam* param, variant arg)
{
uint l = 1;
// pre padding
param.right_adjust(l)?;
// char output
Char32 c = types::variant_to_int(arg, uint) ?? 0xFFFD;
switch (true)
{
case c < 0x7f:
param.out((char)c)?;
case c < 0x7ff:
param.out((char)(0xC0 | c >> 6))?;
param.out((char)(0x80 | (c & 0x3F)))?;
case c < 0xffff:
param.out((char)(0xE0 | c >> 12))?;
param.out((char)(0x80 | (c >> 6 & 0x3F)))?;
param.out((char)(0x80 | (c & 0x3F)))?;
default:
param.out((char)(0xF0 | c >> 18))?;
param.out((char)(0x80 | (c >> 12 & 0x3F)))?;
param.out((char)(0x80 | (c >> 6 & 0x3F)))?;
param.out((char)(0x80 | (c & 0x3F)))?;
}
return param.left_adjust(l);
}
private fn void! ntoa_format(PrintParam* param, char[] buf, usize len, bool negative, uint base)
{
// pad leading zeros
if (!param.flags.left)
{
if (param.width && param.flags.zeropad && (negative || param.flags.plus || param.flags.space)) param.width--;
while (len < param.prec)
{
if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
buf[len++] = '0';
}
while (param.flags.zeropad && len < param.width)
{
if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
buf[len++] = '0';
}
}
// handle hash
if (param.flags.hash && base != 10)
{
if (!param.flags.precision && len && len == param.prec && len == param.width)
{
len--;
if (len) len--;
}
if (base != 10)
{
if (len + 1 >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
switch (base)
{
case 16:
buf[len++] = param.flags.uppercase ? 'X' : 'x';
case 8:
buf[len++] = param.flags.uppercase ? 'O' : 'o';
case 2:
buf[len++] = param.flags.uppercase ? 'B' : 'b';
default:
unreachable();
}
buf[len++] = '0';
}
}
switch (true)
{
case negative:
if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
buf[len++] = '-';
case param.flags.plus:
if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
buf[len++] = '+';
case param.flags.space:
if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
buf[len++] = ' ';
}
if (!len) return;
return param.out_reverse(buf[:len]);
}
$if (env::I128_SUPPORT):
define NtoaType = uint128;
$else:
define NtoaType = ulong;
$endif;
private fn void! ntoa_variant(PrintParam* param, variant arg, uint base)
{
bool is_neg;
NtoaType val = int_from_variant(arg, &is_neg);
return ntoa(param, val, is_neg, base) @inline;
}
private fn void! ntoa(PrintParam* param, NtoaType value, bool negative, uint base)
{
char[PRINTF_NTOA_BUFFER_SIZE] buf = void;
usize len = 0;
// no hash for 0 values
if (!value) param.flags.hash = false;
// write if precision != 0 or value is != 0
if (!param.flags.precision || value)
{
char past_10 = (param.flags.uppercase ? 'A' : 'a') - 10;
do
{
if (len >= PRINTF_NTOA_BUFFER_SIZE) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
char digit = (char)(value % base);
buf[len++] = digit + (digit < 10 ? '0' : past_10);
value /= base;
}
while (value);
}
return ntoa_format(param, buf[:PRINTF_NTOA_BUFFER_SIZE], len, negative, base);
}
define FloatType = double;
// internal ftoa for fixed decimal floating point
private fn void! ftoa(PrintParam* param, FloatType value)
{
char[PRINTF_FTOA_BUFFER_SIZE] buf = void;
usize len = 0;
const FloatType[] POW10 = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
FloatType diff = 0.0;
// powers of 10
// test for special values
if (value != value)
{
return param.out_reverse("nan");
}
if (value < -FloatType.max)
{
return param.out_reverse("fni-");
}
if (value > FloatType.max)
{
if (param.flags.plus)
{
return param.out_reverse("fni+");
}
return param.out_reverse("fni");
}
// test for very large values
// standard printf behavior is to print EVERY whole number digit -- which could be 100s of characters overflowing your buffers == bad
if (value > PRINTF_MAX_FLOAT || value < -PRINTF_MAX_FLOAT)
{
return etoa(param, value);
}
// test for negative
bool negative = value < 0;
if (negative) value = 0 - value;
// set default precision, if not set explicitly
if (!param.flags.precision) param.prec = PRINTF_DEFAULT_FLOAT_PRECISION;
// limit precision to 9, cause a prec >= 10 can lead to overflow errors
while (param.prec > 9)
{
if (len >= PRINTF_FTOA_BUFFER_SIZE) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
buf[len++] = '0';
param.prec--;
}
// Safe due to 1e9 limit.
int whole = (int)value;
FloatType tmp = (value - whole) * POW10[param.prec];
ulong frac = (ulong)tmp;
diff = tmp - frac;
switch (true)
{
case diff > 0.5:
++frac;
// handle rollover, e.g. case 0.99 with prec 1 is 1.0
if (frac >= POW10[param.prec])
{
frac = 0;
++whole;
}
case diff < 0.5:
break;
case !frac && (frac & 1):
// if halfway, round up if odd OR if last digit is 0
++frac;
}
if (!param.prec)
{
diff = value - (FloatType)whole;
if ((!(diff < 0.5) || diff > 0.5) && (whole & 1))
{
// exactly 0.5 and ODD, then round up
// 1.5 -> 2, but 2.5 -> 2
++whole;
}
}
else
{
uint count = param.prec;
// now do fractional part, as an unsigned number
do
{
if (len >= PRINTF_FTOA_BUFFER_SIZE) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
--count;
buf[len++] = (char)(48 + (frac % 10));
}
while (frac /= 10);
// add extra 0s
while (count-- > 0)
{
if (len >= PRINTF_FTOA_BUFFER_SIZE) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
buf[len++] = '0';
}
if (len >= PRINTF_FTOA_BUFFER_SIZE) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
// add decimal
buf[len++] = '.';
}
// do whole part, number is reversed
do
{
if (len >= PRINTF_FTOA_BUFFER_SIZE) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
buf[len++] = (char)(48 + (whole % 10));
}
while (whole /= 10);
// pad leading zeros
if (!param.flags.left && param.flags.zeropad)
{
if (param.width && (negative || param.flags.plus || param.flags.space)) param.width--;
while (len < param.width)
{
if (len >= PRINTF_FTOA_BUFFER_SIZE) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
buf[len++] = '0';
}
}
char next = {|
if (negative) return '-';
if (param.flags.plus) return '+';
if (param.flags.space) return ' ';
return 0;
|};
if (next)
{
if (len >= PRINTF_FTOA_BUFFER_SIZE) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
buf[len++] = next;
}
return param.out_reverse(buf[:len]);
}
union ConvUnion
{
ulong u;
double f;
}
private fn void! etoa(PrintParam* param, FloatType value)
{
// check for NaN and special values
if (value != value || value < FloatType.min || value > FloatType.max)
{
return ftoa(param, value);
}
// determine the sign
bool negative = value < 0;
if (negative) value = -value;
// default precision
if (!param.flags.precision)
{
param.prec = PRINTF_DEFAULT_FLOAT_PRECISION;
}
// determine the decimal exponent
// based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c)
ConvUnion conv;
conv.f = (double)value;
int exp2 = (int)(conv.u >> 52 & 0x7FF) - 1023; // effectively log2
conv.u = (conv.u & (1u64 << 52 - 1)) | (1023u64 << 52); // drop the exponent so conv.F is now in [1,2)
// now approximate log10 from the log2 integer part and an expansion of ln around 1.5
int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.f - 1.5) * 0.289529654602168);
// now we want to compute 10^expval but we want to be sure it won't overflow
exp2 = (int)(expval * 3.321928094887362 + 0.5);
double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453;
double z2 = z * z;
conv.u = (ulong)(exp2 + 1023) << 52;
// compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex
conv.f *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14)))));
// correct for rounding errors
if (value < conv.f)
{
expval--;
conv.f /= 10;
}
// the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters
uint minwidth = ((expval < 100) && (expval > -100)) ? 4 : 5;
// in "%g" mode, "prec" is the number of *significant figures* not decimals
if (param.flags.adapt_exp)
{
// do we want to fall-back to "%f" mode?
if (value >= 1e-4 && value < 1e6)
{
param.prec = param.prec > expval ? param.prec - expval - 1 : 0;
param.flags.precision = true; // make sure ftoa respects precision
// no characters in exponent
minwidth = 0;
expval = 0;
}
else
{
// we use one sigfig for the whole part
if (param.prec > 0 && param.flags.precision) param.prec--;
}
}
// Adjust width
uint fwidth = param.width > minwidth ? param.width - minwidth : 0;
// if we're padding on the right, DON'T pad the floating part
if (param.flags.left && minwidth) fwidth = 0;
// rescale the float value
if (expval) value /= conv.f;
// output the floating part
usize start_idx = param.idx;
PrintFlags old = param.flags;
param.flags.adapt_exp = false;
param.width = fwidth;
ftoa(param, negative ? -value : value)?;
param.flags = old;
// output the exponent part
if (minwidth)
{
// output the exponential symbol
param.out(param.flags.uppercase ? 'E' : 'e')?;
// output the exponent value
param.flags = { .zeropad = true, .plus = true };
param.width = minwidth - 1;
param.prec = 0;
ntoa(param, (NtoaType)(expval < 0 ? -expval : expval), expval < 0, 10)?;
param.flags = old;
// might need to right-pad spaces
param.left_adjust(param.idx - start_idx)?;
}
}
private fn FloatType float_from_variant(variant arg)
{
$if (env::I128_SUPPORT):
switch (arg)
{
case int128:
return *arg;
case uint128:
return *arg;
}
$endif;
if (arg.type.kind == TypeKind.POINTER)
{
return (FloatType)(uptr)(void*)arg.ptr;
}
switch (arg)
{
case bool:
return (FloatType)*arg;
case ichar:
return *arg;
case short:
return *arg;
case int:
return *arg;
case long:
return *arg;
case char:
return *arg;
case ushort:
return *arg;
case uint:
return *arg;
case ulong:
return *arg;
case float:
return (FloatType)*arg;
case double:
return (FloatType)*arg;
default:
return 0;
}
}
private fn NtoaType int_from_variant(variant arg, bool *is_neg)
{
*is_neg = false;
$if (NtoaType.typeid == uint128.typeid):
switch (arg)
{
case int128:
int128 val = *arg;
return (*is_neg = val < 0) ? -val : val;
case uint128:
return *arg;
}
$endif;
if (arg.type.kind == TypeKind.POINTER)
{
return (NtoaType)(uptr)(void*)arg.ptr;
}
switch (arg)
{
case bool:
return (NtoaType)*arg;
case ichar:
int val = *arg;
return (NtoaType)((*is_neg = val < 0) ? -val : val);
case short:
int val = *arg;
return (NtoaType)((*is_neg = val < 0) ? -val : val);
case int:
int val = *arg;
return (NtoaType)((*is_neg = val < 0) ? -val : val);
case long:
long val = *arg;
return (NtoaType)((*is_neg = val < 0) ? -val : val);
case char:
return *arg;
case ushort:
return *arg;
case uint:
return *arg;
case ulong:
return *arg;
case float:
float f = *arg;
return (NtoaType)((*is_neg = f < 0) ? -f : f);
case double:
double d = *arg;
return (NtoaType)((*is_neg = d < 0) ? -d : d);
default:
return 0;
}
}
fn usize! printf(char[] format, args...) @maydiscard
{
return vsnprintf(&out_putchar_fn, null, format, args);
}
fn usize! String.printf(String* str, char[] format, args...) @maydiscard
{
return vsnprintf(&out_string_append_fn, str, format, args);
}
fn usize! File.printf(File file, char[] format, args...) @maydiscard
{
return vsnprintf(&out_putchar_fn, &file, format, args);
}
private fn void! PrintParam.left_adjust(PrintParam* param, usize len)
{
if (!param.flags.left) return;
for (usize l = len; l < param.width; l++) param.out(' ')?;
}
private fn void! PrintParam.right_adjust(PrintParam* param, usize len)
{
if (param.flags.left) return;
for (usize l = len; l < param.width; l++) param.out(' ')?;
}
private fn void! out_substr(PrintParam* param, char[] str)
{
usize l = conv::utf8_codepoints(str);
uint prec = param.prec;
if (param.flags.precision && l < prec) l = prec;
param.right_adjust(' ')?;
usize index = 0;
usize chars = str.len;
char* ptr = str.ptr;
while (index < chars)
{
char c = ptr[index];
// Break if we have precision set and we ran out...
if (c & 0xC0 != 0x80 && param.flags.precision && !prec--) break;
param.out(c)?;
index++;
}
return param.left_adjust(l);
}
private fn usize! vsnprintf(OutputFn out, void* data, char[] format, variant[] variants)
{
if (!out)
{
// use null output function
out = &out_null_fn;
}
PrintParam param = { .outfn = out, .buffer = data };
usize format_len = format.len;
usize variant_index = 0;
for (usize i = 0; i < format_len; i++)
{
// format specifier? %[flags][width][.precision][length]
char c = format[i];
if (c != '%')
{
// no
param.out(c)?;
continue;
}
i++;
if (i >= format_len) return PrintFault.INVALID_FORMAT_STRING!;
c = format[i];
if (c == '%')
{
param.out(c)?;
continue;
}
// evaluate flags
param.flags = {};
while FLAG_EVAL: (true)
{
switch (c)
{
case '0': param.flags.zeropad = true;
case '-': param.flags.left = true;
case '+': param.flags.plus = true;
case ' ': param.flags.space = true;
case '#': param.flags.hash = true;
default: break FLAG_EVAL;
}
if (++i >= format_len) return PrintFault.INVALID_FORMAT_STRING!;
c = format[i];
}
// evaluate width field
int w = printf_parse_format_field(variants.ptr, variants.len, &variant_index, format.ptr, format.len, &i)?;
c = format[i];
if (w < 0)
{
param.flags.left = true;
w = -w;
}
param.width = w;
// evaluate precision field
param.prec = 0;
if (c == '.')
{
param.flags.precision = true;
if (++i >= format_len) return PrintFault.INVALID_FORMAT_STRING!;
int prec = printf_parse_format_field(variants.ptr, variants.len, &variant_index, format.ptr, format.len, &i)?;
param.prec = prec < 0 ? 0 : prec;
c = format[i];
}
// evaluate specifier
uint base = 0;
if (variant_index >= variants.len) return PrintFault.MISSING_ARG!;
variant current = variants[variant_index++];
switch (c)
{
case 'd':
base = 10;
param.flags.hash = false;
case 'X' :
param.flags.uppercase = true;
nextcase;
case 'x' :
base = 16;
case 'O':
param.flags.uppercase = true;
nextcase;
case 'o' :
base = 8;
case 'B':
param.flags.uppercase = true;
nextcase;
case 'b' :
base = 2;
case 'F' :
param.flags.uppercase = true;
nextcase;
case 'f':
ftoa(&param, float_from_variant(current))?;
continue;
case 'E':
param.flags.uppercase = true;
nextcase;
case 'e':
etoa(&param, float_from_variant(current))?;
continue;
case 'G':
param.flags.uppercase = true;
nextcase;
case 'g':
param.flags.adapt_exp = true;
etoa(&param, float_from_variant(current))?;
continue;
case 'c':
out_char(&param, current)?;
continue;
case 's':
out_str(&param, current)?;
continue;
case 'p':
param.width = (uint)(void*.sizeof * 2);
param.flags.zeropad = true;
param.flags.hash = true;
base = 16;
default:
return PrintFault.INVALID_FORMAT_STRING!;
}
if (base != 10)
{
param.flags.plus = false;
param.flags.space = false;
}
// ignore '0' flag when precision is given
if (param.flags.precision) param.flags.zeropad = false;
bool is_neg;
NtoaType v = int_from_variant(current, &is_neg);
ntoa(&param, v, is_neg, base)?;
}
// termination
// out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen);
// return written chars without terminating \0
return param.idx;
}

354
lib/std/libc.c3 Normal file
View File

@@ -0,0 +1,354 @@
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module libc;
// stdlib
// Constants need to be per os/arch
const int EXIT_FAILURE = 1;
const int EXIT_SUCCESS = 0;
const int RAND_MAX = 0x7fffffff;
struct DivResult
{
int quot;
int rem;
}
struct LongDivResult
{
long quot;
long rem;
}
fn Errno errno()
{
$if (env::OS_TYPE == OsType.WIN32):
return (Errno)windows::errno();
$elif (env::OS_TYPE == OsType.MACOSX):
return (Errno)macos::errno();
$elif (env::OS_TYPE == OsType.LINUX):
return (Errno)linux::errno();
$else:
return errno::ENOTRECOVERABLE;
$endif;
}
define TerminateFunction = fn void();
define CompareFunction = fn int(void*, void*);
extern fn double atof(char* str);
extern fn int atoi(char* str);
extern fn CLongLong atoll(char* str);
extern fn double strtod(char* str, char** endptr);
extern fn CLong strtol(char* str, char** endptr, int base);
extern fn CULong stroul(char* str, char** endptr, int base);
extern fn void abort();
extern fn void atexit(TerminateFunction f);
extern fn void exit(int status);
extern fn char* getenv(char* name);
extern fn int system(char* str);
extern fn void bsearch(void* key, void *base, usize items, usize size, CompareFunction compare);
extern fn void qsort(void* base, usize items, usize size, CompareFunction compare);
extern fn int abs(int x);
extern fn DivResult div(int numer, int denom);
extern fn long labs(long x);
extern fn LongDivResult ldiv(long number, long denom);
extern fn int rand();
extern fn void srand(uint seed);
// MB functions omitted
// string
extern fn void* memchr(void* str, int c, usize n);
extern fn int memcmp(void* str1, void* str2, usize n);
extern fn void* memcpy(void* dest, void* src, usize n);
extern fn void* memmove(void* dest, void* src, usize n);
extern fn void* memset(void* dest, usize n);
extern fn char* strcat(char* dest, char* src);
extern fn char* strncat(char* dest, char* src, usize n);
extern fn char* strchr(char* str, int c);
extern fn int strcmp(char* str1, char* str2);
extern fn int strncmp(char* str1, char* str2, usize n);
extern fn int strcoll(char* str1, char* str2);
extern fn char* strcpy(char* dst, char* src);
extern fn char* strncpy(char* dst, char* src, usize n);
extern fn usize strcspn(char* str1, char* str2);
extern fn char* strerror(int errn);
extern fn usize strlen(char* str);
extern fn char* strpbrk(char* str1, char* str2);
extern fn usize strspn(char* str1, char* str2);
extern fn char* strstr(char* haystack, char* needle);
extern fn char* strtok(char* str, char* delim);
extern fn usize strxfrm(char* dest, char* src, usize n);
// malloc
extern fn void* malloc(usize size);
extern fn void* calloc(usize count, usize size);
extern fn void* free(void*);
extern fn void* realloc(void* ptr, usize size);
// stdio
define Fpos = long;
define CFile = void*;
$switch (env::OS_TYPE):
$case OsType.LINUX:
extern CFile __stdin @extname("stdin");
extern CFile __stdout @extname("stdout");
extern CFile __stderr @extname("stderr");
macro CFile stdin() { return __stdin; }
macro CFile stdout() { return __stdout; }
macro CFile stderr() { return __stderr; }
$case OsType.MACOSX:
extern CFile __stdinp;
extern CFile __stdoutp;
extern CFile __stderrp;
macro CFile stdin() { return __stdinp; }
macro CFile stdout() { return __stdoutp; }
macro CFile stderr() { return __stderrp; }
$case OsType.WIN32:
extern fn CFile __acrt_iob_func(CInt c);
macro CFile stdin() { return __acrt_iob_func(0); }
macro CFile stdout() { return __acrt_iob_func(1); }
macro CFile stderr() { return __acrt_iob_func(2); }
$default:
macro CFile stdin() { return (CFile*)(uptr)0; }
macro CFile stdout() { return (CFile*)(uptr)1; }
macro CFile stderr() { return (CFile*)(uptr)2; }
$endswitch;
// The following needs to be set per arch+os
// For now I have simply pulled the defaults from MacOS
const int SEEK_SET = 0;
const int SEEK_CUR = 1;
const int SEEK_END = 2;
const int _IOFBF = 0; // Fully buffered
const int _IOLBF = 1; // Line buffered
const int _IONBF = 2; // Unbuffered
const int BUFSIZ = 1024;
const int EOF = -1;
const int FOPEN_MAX = 20;
const int FILENAME_MAX = 1024;
define Errno = distinct CInt;
define SeekIndex = CLong;
extern fn int fclose(CFile stream);
extern fn void clearerr(CFile stream);
extern fn int feof(CFile stream);
extern fn int ferror(CFile stream);
extern fn int fflush(CFile stream);
extern fn int fgetpos(CFile stream, Fpos* pos);
extern fn CFile fopen(char* filename, char* mode);
extern fn usize fread(void* ptr, usize size, usize nmemb, CFile stream);
extern fn CFile freopen(char* filename, char* mode, CFile stream);
extern fn int fseek(CFile stream, SeekIndex offset, int whence);
extern fn int fsetpos(CFile stream, Fpos* pos);
extern fn SeekIndex ftell(CFile stream);
extern fn usize fwrite(void* ptr, usize size, usize nmemb, CFile stream);
extern fn int remove(char* filename);
extern fn int rename(char* old_name, char* new_name);
extern fn void rewind(CFile stream);
extern fn void setbuf(CFile stream, char* buffer);
extern fn void setvbuf(CFile stream, char* buffer, int mode, usize size);
extern fn CFile tmpnam(char* str);
extern fn int fprintf(CFile stream, char* format, ...);
extern fn int printf(char* format, ...);
extern fn int sprintf(char* str, char* format, ...);
extern fn int snprintf(char* str, usize size, char* format, ...);
extern fn int fscanf(CFile stream, char* format, ...);
extern fn int scanf(char* format, ...);
extern fn int sscanf(char* str, char* format, ...);
extern fn int fgetc(CFile stream);
extern fn char* fgets(char* str, int n, CFile stream);
extern fn int fputc(int c, CFile stream);
extern fn int getc(CFile stream);
extern fn int getchar();
extern fn int putc(char c, CFile stream);
extern fn int putchar(int c);
extern fn int puts(char* str);
extern fn int ungetc(int c, CFile stream);
extern fn void perror(char* str);
// vsprintf vprintf not supported
// time.h
define TimeOffset = CLong;
struct Tm
{
int tm_sec; /* seconds after the minute [0-60] */
int tm_min; /* minutes after the hour [0-59] */
int tm_hour; /* hours since midnight [0-23] */
int tm_mday; /* day of the month [1-31] */
int tm_mon; /* months since January [0-11] */
int tm_year; /* years since 1900 */
int tm_wday; /* days since Sunday [0-6] */
int tm_yday; /* days since January 1 [0-365] */
int tm_isdst; /* Daylight Savings Time flag */
TimeOffset tm_gmtoff; /* offset from UTC in seconds */
char *tm_zone; /* timezone abbreviation */
}
// Likely wrong, must be per platform.
const CLOCKS_PER_SEC = 1000000;
// Time also needs to be per platform
define Time = long;
define Clock = ulong;
extern fn char* asctime(Tm *timeptr);
extern fn Clock clock();
extern fn char* ctime(Time *timer);
extern fn double difftime(Time time1, Time time2);
extern fn Tm* gmtime(Time *timer);
extern fn Tm* localtime(Time *timer);
extern fn Time mktime(Tm *timeptr);
extern fn usize strftime(char* str, usize maxsize, char* format, Tm *timeptr);
extern fn Time time(Time *timer);
// signal
define SignalFunction = fn void(int);
extern fn SignalFunction signal(int sig, SignalFunction function);
// Incomplete
module libc::errno;
const Errno EPERM = 1; /* Operation not permitted */
const Errno ENOENT = 2; /* No such file or directory */
const Errno ESRCH = 3; /* No such process */
const Errno EINTR = 4; /* Interrupted system call */
const Errno EIO = 5; /* I/O error */
const Errno ENXIO = 6; /* No such device or address */
const Errno E2BIG = 7; /* Argument list too long */
const Errno ENOEXEC = 8; /* Exec format error */
const Errno EBADF = 9; /* Bad file number */
const Errno ECHILD = 10; /* No child processes */
const Errno EAGAIN = 11; /* Try again */
const Errno ENOMEM = 12; /* Out of memory */
const Errno EACCES = 13; /* Permission denied */
const Errno EFAULT = 14; /* Bad address */
const Errno ENOTBLK = 15; /* Block device required */
const Errno EBUSY = 16; /* Device or resource busy */
const Errno EEXIST = 17; /* File exists */
const Errno EXDEV = 18; /* Cross-device link */
const Errno ENODEV = 19; /* No such device */
const Errno ENOTDIR = 20; /* Not a directory */
const Errno EISDIR = 21; /* Is a directory */
const Errno EINVAL = 22; /* Invalid argument */
const Errno ENFILE = 23; /* File table overflow */
const Errno EMFILE = 24; /* Too many open files */
const Errno ENOTTY = 25; /* Not a typewriter */
const Errno ETXTBSY = 26; /* Text file busy */
const Errno EFBIG = 27; /* File too large */
const Errno ENOSPC = 28; /* No space left on device */
const Errno ESPIPE = 29; /* Illegal seek */
const Errno EROFS = 30; /* Read-only file system */
const Errno EMLINK = 31; /* Too many links */
const Errno EPIPE = 32; /* Broken pipe */
const Errno EDOM = 33; /* Math argument out of domain of func */
const Errno ERANGE = 34; /* Math result not representable */
const Errno EDEADLK = 35; /* Resource deadlock would occur */
const Errno ENAMETOOLONG = 36; /* File name too long */
const Errno ENOLCK = 37; /* No record locks available */
const Errno ENOSYS = 38; /* Function not implemented */
const Errno ENOTEMPTY = 39; /* Directory not empty */
const Errno ELOOP = 40; /* Too many symbolic links encountered */
const Errno ENOMSG = 42; /* No message of desired type */
const Errno EIDRM = 43; /* Identifier removed */
const Errno ECHRNG = 44; /* Channel number out of range */
const Errno EL2NSYNC = 45; /* Level 2 not synchronized */
const Errno EL3HLT = 46; /* Level 3 halted */
const Errno EL3RST = 47; /* Level 3 reset */
const Errno ELNRNG = 48; /* Link number out of range */
const Errno EUNATCH = 49; /* Protocol driver not attached */
const Errno ENOCSI = 50; /* No CSI structure available */
const Errno EL2HLT = 51; /* Level 2 halted */
const Errno EBADE = 52; /* Invalid exchange */
const Errno EBADR = 53; /* Invalid request descriptor */
const Errno EXFULL = 54; /* Exchange full */
const Errno ENOANO = 55; /* No anode */
const Errno EBADRQC = 56; /* Invalid request code */
const Errno EBADSLT = 57; /* Invalid slot */
const Errno EBFONT = 59; /* Bad font file format */
const Errno ENOSTR = 60; /* Device not a stream */
const Errno ENODATA = 61; /* No data available */
const Errno ETIME = 62; /* Timer expired */
const Errno ENOSR = 63; /* Out of streams resources */
const Errno ENONET = 64; /* Machine is not on the network */
const Errno ENOPKG = 65; /* Package not installed */
const Errno EREMOTE = 66; /* Object is remote */
const Errno ENOLINK = 67; /* Link has been severed */
const Errno EADV = 68; /* Advertise error */
const Errno ESRMNT = 69; /* Srmount error */
const Errno ECOMM = 70; /* Communication error on send */
const Errno EPROTO = 71; /* Protocol error */
const Errno EMULTIHOP = 72; /* Multihop attempted */
const Errno EDOTDOT = 73; /* RFS specific error */
const Errno EBADMSG = 74; /* Not a data message */
const Errno EOVERFLOW = 75; /* Value too large for defined data type */
const Errno ENOTUNIQ = 76; /* Name not unique on network */
const Errno EBADFD = 77; /* File descriptor in bad state */
const Errno EREMCHG = 78; /* Remote address changed */
const Errno ELIBACC = 79; /* Can not access a needed shared library */
const Errno ELIBBAD = 80; /* Accessing a corrupted shared library */
const Errno ELIBSCN = 81; /* .lib section in a.out corrupted */
const Errno ELIBMAX = 82; /* Attempting to link in too many shared libraries */
const Errno ELIBEXEC = 83; /* Cannot exec a shared library directly */
const Errno EILSEQ = 84; /* Illegal byte sequence */
const Errno ERESTART = 85; /* Interrupted system call should be restarted */
const Errno ESTRPIPE = 86; /* Streams pipe error */
const Errno EUSERS = 87; /* Too many users */
const Errno ENOTSOCK = 88; /* Socket operation on non-socket */
const Errno EDESTADDRREQ = 89; /* Destination address required */
const Errno EMSGSIZE = 90; /* Message too long */
const Errno EPROTOTYPE = 91; /* Protocol wrong type for socket */
const Errno ENOPROTOOPT = 92; /* Protocol not available */
const Errno EPROTONOSUPPORT = 93; /* Protocol not supported */
const Errno ESOCKTNOSUPPORT = 94; /* Socket type not supported */
const Errno EOPNOTSUPP = 95; /* Operation not supported on transport endpoint */
const Errno EPFNOSUPPORT = 96; /* Protocol family not supported */
const Errno EAFNOSUPPORT = 97; /* Address family not supported by protocol */
const Errno EADDRINUSE = 98; /* Address already in use */
const Errno EADDRNOTAVAIL = 99; /* Cannot assign requested address */
const Errno ENETDOWN = 100; /* Network is down */
const Errno ENETUNREACH = 101; /* Network is unreachable */
const Errno ENETRESET = 102; /* Network dropped connection because of reset */
const Errno ECONNABORTED = 103; /* Software caused connection abort */
const Errno ECONNRESET = 104; /* Connection reset by peer */
const Errno ENOBUFS = 105; /* No buffer space available */
const Errno EISCONN = 106; /* Transport endpoint is already connected */
const Errno ENOTCONN = 107; /* Transport endpoint is not connected */
const Errno ESHUTDOWN = 108; /* Cannot send after transport endpoint shutdown */
const Errno ETOOMANYREFS = 109; /* Too many references: cannot splice */
const Errno ETIMEDOUT = 110; /* Connection timed out */
const Errno ECONNREFUSED = 111; /* Connection refused */
const Errno EHOSTDOWN = 112; /* Host is down */
const Errno EHOSTUNREACH = 113; /* No route to host */
const Errno EALREADY = 114; /* Operation already in progress */
const Errno EINPROGRESS = 115; /* Operation now in progress */
const Errno ESTALE = 116; /* Stale NFS file handle */
const Errno EUCLEAN = 117; /* Structure needs cleaning */
const Errno ENOTNAM = 118; /* Not a XENIX named type file */
const Errno ENAVAIL = 119; /* No XENIX semaphores available */
const Errno EISNAM = 120; /* Is a named type file */
const Errno EREMOTEIO = 121; /* Remote I/O error */
const Errno EDQUOT = 122; /* Quota exceeded */
const Errno ENOMEDIUM = 123; /* No medium found */
const Errno EMEDIUMTYPE = 124; /* Wrong medium type */
const Errno ECANCELED = 125; /* Operation Canceled */
const Errno ENOKEY = 126; /* Required key not available */
const Errno EKEYEXPIRED = 127; /* Key has expired */
const Errno EKEYREVOKED = 128; /* Key has been revoked */
const Errno EKEYREJECTED = 129; /* Key was rejected by service */
const Errno EOWNERDEAD = 130; /* Owner died */
const Errno ENOTRECOVERABLE = 131; /* State not recoverable */

View File

@@ -1,5 +1,7 @@
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::array::linkedlist<Type>;
import std::mem;
private struct Node
{
@@ -15,15 +17,15 @@ struct LinkedList
Node *last;
}
func void LinkedList.push(LinkedList *list, Type value)
fn void LinkedList.push(LinkedList *list, Type value)
{
list.linkLast(value);
}
private func void LinkedList.linkFirst(LinkedList *list, Type value)
private fn void LinkedList.linkFirst(LinkedList *list, Type value)
{
Node *first = list.first;
Node *new_node = @mem::malloc(Node);
Node *new_node = mem::malloc(Node);
*new_node = { .next = first, .value = value };
list.first = new_node;
if (!first)
@@ -37,10 +39,10 @@ private func void LinkedList.linkFirst(LinkedList *list, Type value)
list.size++;
}
private func void LinkedList.linkLast(LinkedList *list, Type value)
private fn void LinkedList.linkLast(LinkedList *list, Type value)
{
Node *last = list.last;
Node *new_node = mem::alloc($sizeof(Node));
Node *new_node = mem::alloc(Node.sizeof);
*new_node = { .prev = last, .value = value };
list.last = new_node;
if (!last)
@@ -54,7 +56,7 @@ private func void LinkedList.linkLast(LinkedList *list, Type value)
list.size++;
}
func void LinkedList.free(LinkedList *list)
fn void LinkedList.free(LinkedList *list)
{
for (Node* node = list.first; node != null;)
{
@@ -67,12 +69,12 @@ func void LinkedList.free(LinkedList *list)
list.size = 0;
}
func usize LinkedList.len(LinkedList* list) @inline
fn usize LinkedList.len(LinkedList* list) @inline
{
return list.size;
}
func Type LinkedList.get(LinkedList* list, usize index)
fn Type LinkedList.get(LinkedList* list, usize index)
{
Node* node = list.first;
while (index--)
@@ -84,10 +86,10 @@ func Type LinkedList.get(LinkedList* list, usize index)
/**
* @require succ != null
**/
private func void LinkedList.linkBefore(LinkedList *list, Node *succ, Type value)
private fn void LinkedList.linkBefore(LinkedList *list, Node *succ, Type value)
{
Node* pred = succ.prev;
Node* new_node = @mem::malloc(Node);
Node* new_node = mem::malloc(Node);
*new_node = { .prev = pred, .next = succ, .value = value };
succ.prev = new_node;
if (!pred)
@@ -104,7 +106,7 @@ private func void LinkedList.linkBefore(LinkedList *list, Node *succ, Type value
/**
* @require f == list.first && f != null
**/
private func void unlinkFirst(LinkedList* list, Node* f)
private fn void unlinkFirst(LinkedList* list, Node* f)
{
Node* next = f.next;
mem::free(f);
@@ -123,7 +125,7 @@ private func void unlinkFirst(LinkedList* list, Node* f)
/**
* @require l == list.last && l != null
**/
private func void LinkedList.unlinkLast(LinkedList *list, Node* l)
private fn void LinkedList.unlinkLast(LinkedList *list, Node* l)
{
Node* prev = l.prev;
list.last = prev;
@@ -142,7 +144,7 @@ private func void LinkedList.unlinkLast(LinkedList *list, Node* l)
/**
* @require x != null
**/
private func void LinkedList.unlink(LinkedList* list, Node* x)
private fn void LinkedList.unlink(LinkedList* list, Node* x)
{
Node* next = x.next;
Node* prev = x.prev;

133
lib/std/list.c3 Normal file
View File

@@ -0,0 +1,133 @@
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::array::list<Type>;
struct List
{
usize size;
usize capacity;
Type *entries;
}
private fn void List.ensure_capacity(List *list) @inline
{
if (list.capacity == list.size)
{
list.capacity = list.capacity ? 2 * list.capacity : 16;
list.entries = mem::realloc(list.entries, Type.sizeof * list.capacity);
}
}
fn void List.push(List *list, Type element) @inline
{
list.append(element);
}
fn void List.append(List* list, Type element)
{
list.ensure_capacity();
list.entries[list.size++] = element;
}
/**
* @require list.size > 0
*/
fn Type List.pop(List* list)
{
return list.entries[--list.size];
}
/**
* @require list.size > 0
*/
fn Type List.pop_first(List *list)
{
Type value = list.entries[0];
list.remove_at(0);
return value;
}
fn void List.remove_at(List *list, usize index)
{
for (usize i = index + 1; i < list.size; i++)
{
list.entries[i - 1] = list.entries[i];
}
list.size--;
}
fn void List.push_front(List *list, Type type) @inline
{
list.insert_at(0, type);
}
fn void List.insert_at(List* list, usize index, Type type)
{
list.ensure_capacity();
for (usize i = list.size; i > index; i--)
{
list.entries[i] = list.entries[i - 1];
}
list.size++;
list.entries[index] = type;
}
fn void List.remove_last(List* list)
{
list.size--;
}
fn void List.remove_first(List *list)
{
list.remove_at(0);
}
fn Type* List.first(List *list)
{
return list.size ? &list.entries[0] : null;
}
fn Type* List.last(List *list)
{
return list.size ? &list.entries[list.size - 1] : null;
}
fn bool List.is_empty(List *list)
{
return !list.size;
}
fn usize List.len(List *list) @operator(len)
{
return list.size;
}
fn Type List.get(List *list, usize index)
{
return list.entries[index];
}
fn void List.free(List *list)
{
mem::free(list.entries);
list.capacity = 0;
list.size = 0;
list.entries = null;
}
fn void List.swap(List *list, usize i, usize j)
{
@swap(list.entries[i], list.entries[j]);
}
macro Type List.@item_at(List &list, usize index) @operator(elementat)
{
return list.entries[index];
}
macro Type* List.@item_ref(List &list, usize index) @operator(elementref)
{
return &list.entries[index];
}

139
lib/std/math.c3 Normal file
View File

@@ -0,0 +1,139 @@
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::math;
// TODO Define these using quad precision.
const E = 2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427427466;
const LOG2E = 1.44269504088896340735992468100189214; // log2(e)
const LOG10E = 0.434294481903251827651128918916605082; // log10(e)
const LN2 = 0.693147180559945309417232121458176568; // ln(2)
const LN10 = 2.30258509299404568401799145468436421; // ln(10)
const PI = 3.14159265358979323846264338327950288419716939937510; // pi
const PI_2 = 1.57079632679489661923132169163975144; // pi / 2
const PI_4 = 0.785398163397448309615660845819875721; // pi / 4
const DIV_PI = 0.318309886183790671537767526745028724; // 1 / pi
const DIV_2_PI = 0.636619772367581343075535053490057448; // 2 / pi
const DIV_2_SQRTPI = 1.12837916709551257389615890312154517; // 2/sqrt(pi)
const SQRT2 = 1.41421356237309504880168872420969808; // sqrt(2)
const double DIV_1_SQRT2 = 0.707106781186547524400844362104849039; // 1 / sqrt(2)
const HALF_MAX = 6.5504e+4;
const HALF_MIN = 6.103515625e-5;
const HALF_DENORM_MIN = 5.9604644775390625e-8;
const HALF_DIG = 3;
const HALF_DEC_DIGITS = 5;
const HALF_MANT_DIG = 11;
const HALF_MAX_10_EXP = 4;
const HALF_MIN_10_EXP = -4;
const HALF_MAX_EXP = 16;
const HALF_MIN_EXP = -13;
const HALF_EPSILON = 9.765625e-4;
const FLOAT_MAX = 0x1.fffffep+127;
const FLOAT_MIN = 1.17549435e-38;
const FLOAT_DENORM_MIN = 1.40129846432481707092e-45;
const FLOAT_DIG = 6;
const FLOAT_DEC_DIGITS = 9;
const FLOAT_MANT_DIG = 24;
const FLOAT_MAX_10_EXP = 38;
const FLOAT_MIN_10_EXP = -37;
const FLOAT_MAX_EXP = 128;
const FLOAT_MIN_EXP = -125;
const FLOAT_EPSILON = 1.1920928955078125e-07;
const DOUBLE_MAX = 1.79769313486231570815e+308;
const DOUBLE_MIN = 2.2250738585072014e-308;
const DOUBLE_DENORM_MIN = 4.94065645841246544177e-324;
const DOUBLE_DIG = 15;
const DOUBLE_DEC_DIGITS = 17;
const DOUBLE_MANT_DIG = 53;
const DOUBLE_MAX_10_EXP = 308;
const DOUBLE_MIN_10_EXP = -307;
const DOUBLE_MAX_EXP = 1024;
const DOUBLE_MIN_EXP = -1021;
const DOUBLE_EPSILON = 2.22044604925031308085e-16;
/*
const QUAD_MAX = 1.18973149535723176508575932662800702e+4932;
const QUAD_MIN = 3.36210314311209350626267781732175260e-4932;
const QUAD_DENORM_MIN = 6.47517511943802511092443895822764655e-4966;
const QUAD_DIG = 33;
const QUAD_DEC_DIGITS = 36;
const QUAD_MANT_DIG = 113;
const QUAD_MAX_10_EXP = 4932;
const QUAD_MIN_10_EXP = -4931;
const QUAD_MAX_EXP = 16384;
const QUAD_MIN_EXP = -16481;
const QUAD_EPSILON = 1.92592994438723585305597794258492732e-34;
*/
macro max(x, y) @builtin
{
return x > y ? x : y;
}
macro min(x, y) @builtin
{
return x < y ? x : y;
}
fn double log10(double x) @inline
{
return $$log10(x);
}
fn double log2(double x) @inline
{
return $$log2(x);
}
fn double log(double x) @inline
{
return $$log(x);
}
fn double cos(double x) @inline
{
return $$cos(x);
}
fn double sin(double x) @inline
{
return $$sin(x);
}
fn double exp(double x) @inline
{
return $$exp(x);
}
fn double pow(double x, double y) @inline
{
return $$pow(x, y);
}
fn double fabs(double x) @inline
{
return $$fabs(x);
}
fn double trunc(double x) @inline
{
return $$trunc(x);
}
fn double ceil(double x) @inline
{
return $$ceil(x);
}
/**
* @checked x & 1
*/
macro bool is_power_of_2(x)
{
return x != 0 && (x & (x - 1)) == 0;
}

391
lib/std/math.matrix.c3 Normal file
View File

@@ -0,0 +1,391 @@
module std::math::matrix;
fault MatrixError {
MATRIX_INVERSE_DOESNT_EXIST,
}
struct Matrix2x2 {
union {
struct {
float m00, m01;
float m10, m11;
}
float[4] m;
}
}
struct Matrix3x3 {
union {
struct {
float m00; float m01; float m02;
float m10; float m11; float m12;
float m20; float m21; float m22;
}
float[9] m;
}
}
struct Matrix4x4 {
union {
float[16] m;
struct {
float m00, m01, m02, m03;
float m10, m11, m12, m13;
float m20, m21, m22, m23;
float m30, m31, m32, m33;
}
}
}
fn float[<2>] Matrix2x2.apply(Matrix2x2* mat, float[<2>] vec) {
return float[<2>] {
mat.m00 * vec[0] + mat.m01 * vec[1],
mat.m10 * vec[0] + mat.m11 * vec[1],
};
}
fn float[<3>] Matrix3x3.apply(Matrix3x3* mat, float[<3>] vec) {
return float[<3>] {
mat.m00 * vec[0] + mat.m01 * vec[1] + mat.m02 * vec[2],
mat.m10 * vec[0] + mat.m11 * vec[1] + mat.m12 * vec[2],
mat.m20 * vec[0] + mat.m21 * vec[1] + mat.m22 * vec[2],
};
}
fn float[<4>] Matrix4x4.apply(Matrix4x4* mat, float[<4>] vec) {
return float[<4>] {
mat.m00 * vec[0] + mat.m01 * vec[1] + mat.m02 * vec[2] + mat.m03 * vec[3],
mat.m10 * vec[0] + mat.m11 * vec[1] + mat.m12 * vec[2] + mat.m13 * vec[3],
mat.m20 * vec[0] + mat.m21 * vec[1] + mat.m22 * vec[2] + mat.m23 * vec[3],
mat.m30 * vec[0] + mat.m31 * vec[1] + mat.m32 * vec[2] + mat.m33 * vec[3],
};
}
fn Matrix2x2 Matrix2x2.mul(Matrix2x2* a, Matrix2x2 b) {
return Matrix2x2 { .m = {
a.m00 * b.m00 + a.m01 * b.m10, a.m00 * b.m01 + a.m01 * b.m11,
a.m10 * b.m01 + a.m11 * b.m11, a.m10 * b.m01 + a.m11 * b.m11,
} };
}
fn Matrix3x3 Matrix3x3.mul(Matrix3x3* a, Matrix3x3 b) {
return Matrix3x3 { .m = {
a.m00 * b.m00 + a.m01 * b.m10 + a.m02 * b.m20,
a.m00 * b.m01 + a.m01 * b.m11 + a.m02 * b.m21,
a.m00 * b.m02 + a.m01 * b.m12 + a.m02 * b.m22,
a.m10 * b.m00 + a.m11 * b.m10 + a.m12 * b.m20,
a.m10 * b.m01 + a.m11 * b.m11 + a.m12 * b.m21,
a.m10 * b.m02 + a.m11 * b.m12 + a.m12 * b.m22,
a.m20 * b.m00 + a.m21 * b.m10 + a.m22 * b.m20,
a.m20 * b.m01 + a.m21 * b.m11 + a.m22 * b.m21,
a.m20 * b.m02 + a.m21 * b.m12 + a.m22 * b.m22,
} };
}
fn Matrix4x4 Matrix4x4.mul(Matrix4x4* a, Matrix4x4 b) {
return Matrix4x4 { .m = {
a.m00 * b.m00 + a.m01 * b.m10 + a.m02 * b.m20 + a.m03 * b.m30,
a.m00 * b.m01 + a.m01 * b.m11 + a.m02 * b.m21 + a.m03 * b.m31,
a.m00 * b.m02 + a.m01 * b.m12 + a.m02 * b.m22 + a.m03 * b.m32,
a.m00 * b.m03 + a.m01 * b.m13 + a.m02 * b.m23 + a.m03 * b.m33,
a.m10 * b.m00 + a.m11 * b.m10 + a.m12 * b.m20 + a.m13 * b.m30,
a.m10 * b.m01 + a.m11 * b.m11 + a.m12 * b.m21 + a.m13 * b.m31,
a.m10 * b.m02 + a.m11 * b.m12 + a.m12 * b.m22 + a.m13 * b.m32,
a.m10 * b.m03 + a.m11 * b.m13 + a.m12 * b.m23 + a.m13 * b.m33,
a.m20 * b.m00 + a.m21 * b.m10 + a.m22 * b.m20 + a.m23 * b.m30,
a.m20 * b.m01 + a.m21 * b.m11 + a.m22 * b.m21 + a.m23 * b.m31,
a.m20 * b.m02 + a.m21 * b.m12 + a.m22 * b.m22 + a.m23 * b.m32,
a.m20 * b.m03 + a.m21 * b.m13 + a.m22 * b.m23 + a.m23 * b.m33,
a.m30 * b.m00 + a.m31 * b.m10 + a.m32 * b.m20 + a.m33 * b.m30,
a.m30 * b.m01 + a.m31 * b.m11 + a.m32 * b.m21 + a.m33 * b.m31,
a.m30 * b.m02 + a.m31 * b.m12 + a.m32 * b.m22 + a.m33 * b.m32,
a.m30 * b.m03 + a.m31 * b.m13 + a.m32 * b.m23 + a.m33 * b.m33,
} };
}
fn Matrix2x2 Matrix2x2.component_mul(Matrix2x2* mat, float s) {
return Matrix2x2 { .m = {
mat.m00 * s, mat.m01 * s,
mat.m10 * s, mat.m11 * s,
} };
}
fn Matrix3x3 Matrix3x3.component_mul(Matrix3x3* mat, float s) {
return Matrix3x3 { .m = {
mat.m00 * s, mat.m01 * s, mat.m02 * s,
mat.m10 * s, mat.m11 * s, mat.m12 * s,
mat.m20 * s, mat.m21 * s, mat.m22 * s,
} };
}
fn Matrix4x4 Matrix4x4.component_mul(Matrix4x4* mat, float s) {
return Matrix4x4 { .m = {
mat.m00 * s, mat.m01 * s, mat.m02 * s, mat.m03 * s,
mat.m10 * s, mat.m11 * s, mat.m12 * s, mat.m13 * s,
mat.m20 * s, mat.m21 * s, mat.m22 * s, mat.m23 * s,
mat.m30 * s, mat.m31 * s, mat.m32 * s, mat.m33 * s,
} };
}
fn Matrix2x2 Matrix2x2.transpose(Matrix2x2* mat) {
return Matrix2x2 { .m = { mat.m00, mat.m10, mat.m01, mat.m11 } };
}
fn Matrix3x3 Matrix3x3.transpose(Matrix3x3* mat) {
return Matrix3x3 { .m = {
mat.m00, mat.m10, mat.m20,
mat.m01, mat.m11, mat.m21,
mat.m02, mat.m12, mat.m22,
} };
}
fn Matrix4x4 Matrix4x4.transpose(Matrix4x4* mat) {
return Matrix4x4 { .m = {
mat.m00, mat.m10, mat.m20, mat.m30,
mat.m01, mat.m11, mat.m21, mat.m31,
mat.m02, mat.m12, mat.m22, mat.m32,
mat.m03, mat.m13, mat.m23, mat.m33,
} };
}
fn float Matrix2x2.determinant(Matrix2x2* mat) {
return mat.m00 * mat.m11 - mat.m01 * mat.m10;
}
fn float Matrix3x3.determinant(Matrix3x3* mat) {
return
mat.m00 * (mat.m11 * mat.m22 - mat.m21 * mat.m12) -
mat.m01 * (mat.m10 * mat.m22 - mat.m20 * mat.m12) +
mat.m02 * (mat.m10 * mat.m21 - mat.m20 * mat.m11);
}
fn float Matrix4x4.determinant(Matrix4x4* mat) {
return
mat.m00 * (mat.m11 * (mat.m22 * mat.m33 - mat.m32 * mat.m23) -
mat.m12 * (mat.m21 * mat.m33 - mat.m31 * mat.m23) +
mat.m13 * (mat.m21 * mat.m32 - mat.m31 * mat.m22) ) -
mat.m01 * (mat.m10 * (mat.m22 * mat.m33 - mat.m32 * mat.m23) -
mat.m12 * (mat.m20 * mat.m33 - mat.m30 * mat.m23) +
mat.m13 * (mat.m20 * mat.m32 - mat.m30 * mat.m22) ) +
mat.m02 * (mat.m10 * (mat.m21 * mat.m33 - mat.m31 * mat.m23) -
mat.m11 * (mat.m20 * mat.m33 - mat.m30 * mat.m23) +
mat.m13 * (mat.m20 * mat.m31 - mat.m30 * mat.m21) ) -
mat.m03 * (mat.m10 * (mat.m21 * mat.m32 - mat.m31 * mat.m22) -
mat.m11 * (mat.m20 * mat.m32 - mat.m30 * mat.m22) +
mat.m12 * (mat.m20 * mat.m31 - mat.m30 * mat.m21) )
;
}
fn Matrix2x2 Matrix2x2.adjoint(Matrix2x2* mat) {
return Matrix2x2 { .m = { mat.m00, -mat.m01, -mat.m10, mat.m11 } };
}
fn Matrix3x3 Matrix3x3.adjoint(Matrix3x3* mat) {
return Matrix3x3 { .m = {
(mat.m11 * mat.m22 - mat.m21 * mat.m12),
-(mat.m10 * mat.m22 - mat.m20 * mat.m12),
(mat.m10 * mat.m21 - mat.m20 * mat.m11),
-(mat.m01 * mat.m22 - mat.m21 * mat.m02),
(mat.m00 * mat.m22 - mat.m20 * mat.m02),
-(mat.m00 * mat.m21 - mat.m20 * mat.m01),
(mat.m01 * mat.m12 - mat.m11 * mat.m02),
-(mat.m00 * mat.m12 - mat.m10 * mat.m02),
(mat.m00 * mat.m11 - mat.m10 * mat.m01),
} };
}
fn Matrix4x4 Matrix4x4.adjoint(Matrix4x4* mat) {
return Matrix4x4 { .m = {
(mat.m11 * (mat.m22 * mat.m33 - mat.m32 * mat.m23) -
mat.m12 * (mat.m21 * mat.m33 - mat.m31 * mat.m23) +
mat.m13 * (mat.m21 * mat.m32 - mat.m31 * mat.m22)),
-(mat.m10 * (mat.m22 * mat.m33 - mat.m32 * mat.m23) -
mat.m12 * (mat.m20 * mat.m33 - mat.m30 * mat.m23) +
mat.m13 * (mat.m20 * mat.m32 - mat.m30 * mat.m22)),
(mat.m10 * (mat.m21 * mat.m33 - mat.m31 * mat.m23) -
mat.m11 * (mat.m20 * mat.m33 - mat.m30 * mat.m23) +
mat.m13 * (mat.m20 * mat.m31 - mat.m30 * mat.m21)),
-(mat.m10 * (mat.m21 * mat.m32 - mat.m31 * mat.m22) -
mat.m11 * (mat.m20 * mat.m32 - mat.m30 * mat.m22) +
mat.m12 * (mat.m20 * mat.m31 - mat.m30 * mat.m21)),
-(mat.m01 * (mat.m22 * mat.m33 - mat.m32 * mat.m23) -
mat.m02 * (mat.m21 * mat.m33 - mat.m31 * mat.m23) +
mat.m03 * (mat.m21 * mat.m32 - mat.m31 * mat.m22)),
(mat.m00 * (mat.m22 * mat.m33 - mat.m32 * mat.m23) -
mat.m02 * (mat.m20 * mat.m33 - mat.m30 * mat.m23) +
mat.m03 * (mat.m20 * mat.m32 - mat.m30 * mat.m22)),
-(mat.m00 * (mat.m21 * mat.m33 - mat.m31 * mat.m23) -
mat.m01 * (mat.m20 * mat.m33 - mat.m30 * mat.m23) +
mat.m03 * (mat.m20 * mat.m31 - mat.m30 * mat.m21)),
(mat.m00 * (mat.m21 * mat.m32 - mat.m31 * mat.m22) -
mat.m01 * (mat.m20 * mat.m32 - mat.m30 * mat.m22) +
mat.m02 * (mat.m20 * mat.m31 - mat.m30 * mat.m21)),
(mat.m01 * (mat.m12 * mat.m33 - mat.m32 * mat.m13) -
mat.m02 * (mat.m11 * mat.m33 - mat.m31 * mat.m13) +
mat.m03 * (mat.m11 * mat.m32 - mat.m31 * mat.m12)),
-(mat.m00 * (mat.m12 * mat.m33 - mat.m32 * mat.m13) -
mat.m02 * (mat.m10 * mat.m33 - mat.m30 * mat.m13) +
mat.m03 * (mat.m10 * mat.m32 - mat.m30 * mat.m12)),
(mat.m00 * (mat.m11 * mat.m33 - mat.m31 * mat.m13) -
mat.m01 * (mat.m10 * mat.m33 - mat.m30 * mat.m13) +
mat.m03 * (mat.m10 * mat.m31 - mat.m30 * mat.m11)),
-(mat.m00 * (mat.m11 * mat.m32 - mat.m31 * mat.m12) -
mat.m01 * (mat.m10 * mat.m32 - mat.m30 * mat.m12) +
mat.m02 * (mat.m10 * mat.m31 - mat.m30 * mat.m11)),
-(mat.m01 * (mat.m12 * mat.m23 - mat.m22 * mat.m13) -
mat.m02 * (mat.m11 * mat.m23 - mat.m21 * mat.m13) +
mat.m03 * (mat.m11 * mat.m22 - mat.m21 * mat.m12)),
(mat.m00 * (mat.m12 * mat.m23 - mat.m22 * mat.m13) -
mat.m02 * (mat.m10 * mat.m23 - mat.m20 * mat.m13) +
mat.m03 * (mat.m10 * mat.m22 - mat.m20 * mat.m12)),
-(mat.m00 * (mat.m11 * mat.m23 - mat.m21 * mat.m13) -
mat.m01 * (mat.m10 * mat.m23 - mat.m20 * mat.m13) +
mat.m03 * (mat.m10 * mat.m21 - mat.m20 * mat.m11)),
(mat.m00 * (mat.m11 * mat.m22 - mat.m21 * mat.m12) -
mat.m01 * (mat.m10 * mat.m22 - mat.m20 * mat.m12) +
mat.m02 * (mat.m10 * mat.m21 - mat.m20 * mat.m11)),
} };
}
fn Matrix2x2! Matrix2x2.inverse(Matrix2x2* m) {
float det = m.determinant();
if (det == 0) return MatrixError.MATRIX_INVERSE_DOESNT_EXIST!;
Matrix2x2 adj = m.adjoint();
return adj.component_mul(1 / det).transpose();
}
fn Matrix3x3! Matrix3x3.inverse(Matrix3x3* m) {
float det = m.determinant();
if (det == 0) return MatrixError.MATRIX_INVERSE_DOESNT_EXIST!;
Matrix3x3 adj = m.adjoint();
return adj.component_mul(1 / det).transpose();
}
fn Matrix4x4! Matrix4x4.inverse(Matrix4x4* m) {
float det = m.determinant();
if (det == 0) return MatrixError.MATRIX_INVERSE_DOESNT_EXIST!;
Matrix4x4 adj = m.adjoint();
return adj.component_mul(1 / det).transpose();
}
fn Matrix3x3 Matrix3x3.translate(Matrix3x3* m, float[<2>] v) {
return m.mul(Matrix3x3 { .m = {
1.f, 0.f, v[0],
0.f, 1.f, v[1],
0.f, 0.f, 1.f,
} });
}
fn Matrix4x4 Matrix4x4.translate(Matrix4x4* m, float[<3>] v) {
return m.mul(Matrix4x4 { .m = {
1.f, 0.f, 0.f, v[0],
0.f, 1.f, 0.f, v[1],
0.f, 0.f, 1.f, v[2],
0.f, 0.f, 0.f, 1.f,
} });
}
// r in radians
fn Matrix3x3 Matrix3x3.rotate(Matrix3x3* m, float r) {
return m.mul(Matrix3x3 { .m = {
(float)math::cos(r), (float)-math::sin(r), 0.f,
(float)math::sin(r), (float) math::cos(r), 0.f,
0.f, 0.f, 1.f,
} });
}
// r in radians
fn Matrix4x4 Matrix4x4.rotateZ(Matrix4x4* m, float r) {
return m.mul(Matrix4x4 { .m = {
(float)math::cos(r), (float)-math::sin(r), 0.f, 0.f,
(float)math::sin(r), (float) math::cos(r), 0.f, 0.f,
0.f, 0.f, 1.f, 0.f,
0.f, 0.f, 0.f, 1.f,
} });
}
// r in radians
fn Matrix4x4 Matrix4x4.rotateY(Matrix4x4* m, float r) {
return m.mul(Matrix4x4 { .m = {
(float)math::cos(r), 0.f, (float)-math::sin(r), 0.f,
0.f, 1.f, 0.f, 0.f,
(float)math::sin(r), 0.f, (float) math::cos(r), 0.f,
0.f, 0.f, 0.f, 1.f,
} });
}
// r in radians
fn Matrix4x4 Matrix4x4.rotateX(Matrix4x4* m, float r) {
return m.mul(Matrix4x4 { .m = {
1.f, 0.f, 0.f, 0.f,
0.f, (float)math::cos(r), (float)-math::sin(r), 0.f,
0.f, (float)math::sin(r), (float) math::cos(r), 0.f,
0.f, 0.f, 0.f, 1.f,
} });
}
fn Matrix3x3 Matrix3x3.scale(Matrix3x3* m, float[<2>] v) {
return m.mul(Matrix3x3 { .m = {
v[0], 0.f, 0.f,
0.f, v[1], 0.f,
0.f, 0.f, 1.f,
} });
}
fn Matrix4x4 Matrix4x4.scale(Matrix4x4* m, float[<3>] v) {
return m.mul(Matrix4x4 { .m = {
v[0], 0.f, 0.f, 0.f,
0.f, v[1], 0.f, 0.f,
0.f, 0.f, v[2], 0.f,
0.f, 0.f, 0.f, 1.f,
} });
}
fn Matrix4x4 ortho(float left, float right, float top, float bottom, float near, float far) {
float width = right - left;
float height = top - bottom;
float depth = far - near;
return Matrix4x4 {
.m = {
2.f / width, 0.f, 0.f, 0.f,
0.f, 2.f / height, 0.f, 0.f,
0.f, 0.f, -2.f / depth, 0.f,
-(right + left) / width, -(top + bottom) / height, -(far + near) / depth, 1.f,
}
};
}
// fov in radians
fn Matrix4x4 perspective(float fov, float aspect_ratio, float near, float far) {
float top = ((float)math::sin(fov / 2) / (float)math::cos(fov / 2)) * near;
float right = top * aspect_ratio;
float depth = far - near;
return Matrix4x4 {
.m = {
1.f / right, 0.f, 0.f, 0.f,
0.f, 1.f / top, 0.f, 0.f,
0.f, 0.f, -2.f / depth, 0.f,
0.f, 0.f, -(far + near) / depth, 1.f,
}
};
}

View File

@@ -0,0 +1,47 @@
module math;
struct SimpleRandom
{
long seed;
}
private const long SIMPLE_RANDOM_MULTIPLIER = 0x5DEECE66Di64;
private const long SIMPLE_RANDOM_ADDEND = 0xB;
private const long SIMPLE_RANDOM_MASK = (1i64 << 48) - 1;
private fn long simple_random_initial_scramble(long seed)
{
return (seed ^ SIMPLE_RANDOM_MULTIPLIER) & SIMPLE_RANDOM_MASK;
}
private fn int SimpleRandom.next(SimpleRandom* r, int bits)
{
long nextseed = (r.seed * SIMPLE_RANDOM_MULTIPLIER + SIMPLE_RANDOM_ADDEND) & SIMPLE_RANDOM_MASK;
r.seed = nextseed;
return (int)nextseed >> (48 - bits);
}
fn void SimpleRandom.set_seed(SimpleRandom* r, long seed)
{
r.seed = simple_random_initial_scramble(seed);
}
fn int SimpleRandom.next_int(SimpleRandom* r)
{
return r.next(32) @inline;
}
fn bool SimpleRandom.next_bool(SimpleRandom* r)
{
return r.next(1) != 0;
}
fn float SimpleRandom.next_float(SimpleRandom* r)
{
return r.next(24) / (float)(1 << 24);
}
fn double SimpleRandom.next_double(SimpleRandom* r)
{
return (((long)(r.next(26)) << 27) + r.next(27)) * 0x1.0p-53;
}

105
lib/std/priorityqueue.c3 Normal file
View File

@@ -0,0 +1,105 @@
// priorityqueue.c3
// A priority queue using a classic binary heap for C3.
//
// Copyright (c) 2022 David Kopec
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
module std::priorityqueue<Type>;
import std::array::list;
define Heap = List<Type>;
struct PriorityQueue
{
Heap heap;
bool max; // true if max-heap, false if min-heap
}
fn void PriorityQueue.push(PriorityQueue* pq, Type element)
{
pq.heap.push(element);
usize i = pq.heap.len() - 1;
while (i > 0)
{
usize parent = (i - 1) / 2;
if ((pq.max && greater(pq.heap.get(i), pq.heap.get(parent))) || (!pq.max && less(pq.heap.get(i), pq.heap.get(parent))))
{
pq.heap.swap(i, parent);
i = parent;
continue;
}
break;
}
}
/**
* @require pq != null
*/
fn Type! PriorityQueue.pop(PriorityQueue* pq)
{
usize i = 0;
usize len = pq.heap.len() @inline;
if (!len) return IteratorResult.NO_MORE_ELEMENT!;
usize newCount = len - 1;
pq.heap.swap(0, newCount);
while ((2 * i + 1) < newCount)
{
usize j = 2 * i + 1;
if (((j + 1) < newCount) &&
((pq.max && greater(pq.heap.get(j + 1), pq.heap[j]))
|| (!pq.max && less(pq.heap.get(j + 1), pq.heap.get(j)))))
{
j++;
}
if ((pq.max && less(pq.heap.get(i), pq.heap.get(j))) || (!pq.max && greater(pq.heap.get(i), pq.heap.get(j))))
{
pq.heap.swap(i, j);
i = j;
continue;
}
break;
}
return pq.heap.pop();
}
/**
* @require pq != null
*/
fn Type! PriorityQueue.peek(PriorityQueue* pq)
{
if (!pq.len()) return IteratorResult.NO_MORE_ELEMENT!;
return pq.heap.get(0);
}
/**
* @require pq != null
*/
fn void PriorityQueue.free(PriorityQueue* pq)
{
pq.heap.free();
}
/**
* @require pq != null
*/
fn usize PriorityQueue.len(PriorityQueue* pq) @operator(len)
{
return pq.heap.len();
}

View File

@@ -1,3 +1,6 @@
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::runtime;
struct VirtualAny
@@ -23,10 +26,5 @@ struct VarArrayHeader
usize size;
usize capacity;
void *allocator;
}
struct VarArrayContainer
{
}

View File

@@ -1,377 +0,0 @@
name = C3
file_extensions [] = c3;
################################################################
## Constants
################################################################
__CONSTANT \= (_*[A-Z][A-Za-z0-9_]*)
__IDENT \= _*[a-z][A-Za-z0-9_]*
__TYPE \= _*[A-Z][A-Za-z0-9_]*[a-z][A-Za-z0-9_]*
__SCOPE \= ([a-z]+::)*
__USERTYPE \= _*[A-Z][A-Za-z0-9_]*[a-z][A-Za-z0-9_]*
__BUILTIN_TYPE \= void|float|half|double|quad|long|ulong|int|short|char|uint|ushort|ichar|usize|isize|iptr|uptr|iptrdiff|uptrdiff
################################################################
## Styles
################################################################
styles [] {
.comment : style {
color = #5F5A60
italic = true
ace_scope = comment
textmate_scope = comment
pygments_scope = Comment
}
.type : style {
color = #AE81FF
pygments_scope = Name.Class
textmate_scope = entity.name.type
}
.string : style {
color = #E6DB74
pygments_scope = String.Double
textmate_scope = string.quoted.double
}
.escaped_text : style {
color = #AE81FF
pygments_scope = String.Escape
}
.function_decl : style {
color = #A6E22E
pygments_scope = Name.Entity
}
.declare : style {
color = #66D9EF
pygments_scope = Keyword.Declaration
}
.function_call : style {
color = #66D9EF
pygments_scope = Name.Function
}
.type_builtin : style {
color = #f92672
ace_scope = keyword
textmate_scope = keyword
pygments_scope = Keyword.Type
}
.keyword_constant : style
{
color = #f92672
ace_scope = keyword
textmate_scope = keyword
pygments_scope = Keyword.Constant
}
.keyword : style {
color = #f92672
ace_scope = keyword
textmate_scope = keyword
pygments_scope = Keyword
}
.constant : style {
color = #AE81FF
textmate_scope = constant
pygments_scope = Name.Constant
}
.numeric : style {
color = #AE81FF
ace_scope = constant.numeric
textmate_scope = constant.numeric
pygments_scope = Number
}
.punctuation : style {
color = #FD971F
ace_scope = punctuation
textmate_scope = punctuation
pygments_scope = Punctuation
}
.compile_time : style {
color = #908B25
pygments_scope = Keyword.Pseudo
}
.variable : style {
color = #f8f8f2
background_color = #272822
pygments_scope = Name
}
.text : style {
color = #f8f8f2
background_color = #272822
ace_scope = text
textmate_scope = text
pygments_scope = String
}
.illegal : style {
color = white
background_color = red
ace_scope = invalid
textmate_scope = invalid
pygments_scope = Generic.Error
}
}
#################################################
## Parse contexts
#################################################
contexts [] {
top_level : context {
: include "parens";
: include "comment";
: include "constants";
: include "ct_keywords";
: include "decls";
: include "path";
: include "type";
: include "keywords";
: include "storage";
: include "call";
: include "identifier";
: include "kw_operators";
: include "operators";
: pattern {
regex \= ([\.\;])
styles [] = .punctuation;
}
: pattern {
regex \= ([\@])
styles [] = .keyword;
}
}
builtin_constants : context {
: pattern {
regex \= (true|false|null)
styles [] = .keyword_constant;
}
}
constants : context {
: pattern {
regex \= ($${__CONSTANT})
styles [] = .constant;
}
}
type : context {
: pattern {
regex \= ($${__SCOPE})?($${__USERTYPE})
styles [] = .type;
}
: pattern {
regex \= ($${__BUILTIN_TYPE})
styles [] = .type_builtin;
}
}
path : context {
: pattern {
regex \= ([a-z][a-z_0-9]*)(\s*)(::)
styles [] = .text, .text, .keyword;
}
}
call : context {
: pattern {
regex \= ($${__IDENT}\s*)(\()
styles [] = .function_call, .text;
}
}
keywords : context {
: pattern {
regex \= (import|for|foreach|return|else|if|default|switch|while|do|module|assert|distinct|break|nextcase|case|continue|defer)
styles [] = .keyword;
}
}
ct_keywords : context {
: pattern {
regex \= (\$[a-zA-Z][a-z_A-Z0-9]*)
styles [] = .compile_time;
}
}
storage : context {
: pattern {
regex \= (const|extern|static|private)
styles [] = .keyword;
}
}
identifier : context {
: pattern {
regex \= ($${__IDENT})
styles [] = .variable;
}
}
operators : context {
: pattern {
regex \= ([\*\=\/\%\<\>\,\:\^\&\!\|\~])
styles [] = .text;
}
}
kw_operators : context {
: pattern {
regex \= ([\+\-])
styles [] = .text;
}
}
parens : context {
: pattern {
regex \= ([\[\]\(\)\{\}])
styles [] = .text;
}
}
decls : context
{
: pattern {
regex \= (func\s+)($${__SCOPE})?($${__USERTYPE})?($${__BUILTIN_TYPE})?(\s+$${__IDENT})
styles [] = .declare, .text, .text, .type, .type_builtin, .function_decl;
}
: pattern {
regex \= (func\s+)($${__SCOPE})?($${__USERTYPE})?($${__BUILTIN_TYPE})?(\s+$${__IDENT})
styles [] = .declare, .text, .text, .type, .type_builtin, .function_decl;
}
: pattern {
regex \= (enum|struct|errtype|union)(\s+)($${__USERTYPE})
styles[] = .declare, .text, .function_decl;
}
: pattern {
regex \= (struct|union|define)
styles[] = .declare;
}
}
nested_comment : context {
: inline_push {
regex \= (/\*)
styles [] = .comment;
: pop {
regex \= (.*\*/)
styles [] = .comment;
}
: include "nested_comment";
}
}
comment : context {
: pattern {
regex \= (//.*)
styles [] = .comment;
}
: include "nested_comment";
}
main : context {
: include "top_level";
: pattern {
regex \= (define|extern|if|module|import|func|struct|while|do|return|union|errtype)
styles [] = .keyword;
}
: include "numeric" ;
: inline_push {
regex \= (\{)
styles [] = .punctuation;
: pop {
regex \= (\})
styles [] = .punctuation;
}
: include "main" ;
}
: pattern {
regex \= (;)
styles [] = .punctuation;
}
: inline_push {
regex \= (\")
styles [] = .punctuation;
: pop {
regex \= (\")
styles [] = .punctuation;
}
: pattern {
regex \= (\\(?:\\|"))
styles [] = .escaped_text;
}
: pattern {
regex \= ([^"\\]+)
styles [] = .string;
}
}
: include "multi_line_comment" ;
: pattern {
regex \= (//.*)
styles [] = .comment;
}
: pattern {
regex \= ([^\s])
styles [] = .illegal;
}
}
#################################################
## End of Contexts
#################################################
###########################################
## Numeric Context
###########################################
numeric : context {
: pattern {
regex \= (\b\d+)
styles [] = .numeric;
}
}
###########################################
## Multi Line Comment Context
###########################################
multi_line_comment : context {
description = multiline
: inline_push {
regex \= (/\*)
styles [] = .comment;
default_style = .comment
: pop {
regex \= (\*/)
styles [] = .comment;
}
}
}
}

View File

@@ -1,4 +0,0 @@
This .nanorc file adds syntax highlighting support for C3 to nano.
It can either be installed under `/usr/share/nano` or included into `~/.nanorc`.

View File

@@ -1,43 +0,0 @@
## C3 syntax highlighting support for nano
## https://github.com/c3lang/c3c
syntax c3 "\.(c3|c3t)$"
comment "//"
# Default color
color white ".*"
# Constants
#color brightred "\<[A-Z_][0-9A-Z_]+\>"
# Function names
color magenta "\<[A-Za-z_]+\>\("
color normal "\(|\)"
# Types
color green "\<(virtual|anyerr|void|bool|quad|double|float|long|ulong|int|uint|short|ushort|ichar|char|isize|usize|iptr|uptr|iptrdiff|uptrdiff|half)\>"
# Keywords
color yellow "\<(alias|as|asm|assert|attribute|break|case|catch|const|continue|default|defer|define|do|else|enum|extern|errtype|false|for|foreach|func|generic|if|import|interface|macro|module|nextcase|null|private|return|static|struct|switch|true|try|typeid|typeof|union|while|var|volatile|yield)\>"
# $ Statements
color brightyellow "\$\<(assert|case|default|elif|else|endif|endswitch|for|if|switch|unreachable)\>"
# @ Attributes
color brightred "@\<[A-Za-z_]+\>"
# Strings
color brightblack "\"[^"]*\""
# Everything down from here should stay in the current order
# Comments
color cyan "//.*"
color cyan start="/\+" end="\+/"
color cyan start="/\*" end="\*/"
# Reminders
color brightwhite,red "\<(FIXME|TODO|XXX)\>"
# Trailing whitespace
color ,green "[[:space:]]+$"

View File

@@ -1,41 +1,40 @@
module base64;
// Based on the C2 version.
error InvalidCharacter
{
int index;
char c;
}
fault DecodingError
{
INVALID_CHARACTER
}
const char[64] LUT_ENC = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/',
};
const char ERR = 0xFF;
const char[256] LUT_DEC =
{
[0..255] = ERR,
['A'] = 0, ['B'] = 1, ['C'] = 2, ['D'] = 3, ['E'] = 4,
['F'] = 5, ['G'] = 6, ['H'] = 7, ['I'] = 8, ['J'] = 9,
['K'] = 10, ['L'] = 11, ['M'] = 12, ['N'] = 13, ['O'] = 14,
['P'] = 15, ['Q'] = 16, ['R'] = 17, ['S'] = 18, ['T'] = 19,
['U'] = 20, ['V'] = 21, ['W'] = 22, ['X'] = 23, ['Y'] = 24,
['Z'] = 25, ['a'] = 26, ['b'] = 27, ['c'] = 28, ['d'] = 29,
['e'] = 30, ['f'] = 31, ['g'] = 32, ['h'] = 33, ['i'] = 34,
['j'] = 35, ['k'] = 36, ['l'] = 37, ['m'] = 38, ['n'] = 39,
['o'] = 40, ['p'] = 41, ['q'] = 42, ['r'] = 43, ['s'] = 44,
['t'] = 45, ['u'] = 46, ['v'] = 47, ['w'] = 48, ['x'] = 49,
['y'] = 50, ['z'] = 51, ['0'] = 52, ['1'] = 53, ['2'] = 54,
['3'] = 55, ['4'] = 56, ['5'] = 57, ['6'] = 58, ['7'] = 59,
['8'] = 60, ['9'] = 61, ['+'] = 62, ['/'] = 63
[0..255] = ERR,
['A'] = 0, ['B'] = 1, ['C'] = 2, ['D'] = 3, ['E'] = 4,
['F'] = 5, ['G'] = 6, ['H'] = 7, ['I'] = 8, ['J'] = 9,
['K'] = 10, ['L'] = 11, ['M'] = 12, ['N'] = 13, ['O'] = 14,
['P'] = 15, ['Q'] = 16, ['R'] = 17, ['S'] = 18, ['T'] = 19,
['U'] = 20, ['V'] = 21, ['W'] = 22, ['X'] = 23, ['Y'] = 24,
['Z'] = 25, ['a'] = 26, ['b'] = 27, ['c'] = 28, ['d'] = 29,
['e'] = 30, ['f'] = 31, ['g'] = 32, ['h'] = 33, ['i'] = 34,
['j'] = 35, ['k'] = 36, ['l'] = 37, ['m'] = 38, ['n'] = 39,
['o'] = 40, ['p'] = 41, ['q'] = 42, ['r'] = 43, ['s'] = 44,
['t'] = 45, ['u'] = 46, ['v'] = 47, ['w'] = 48, ['x'] = 49,
['y'] = 50, ['z'] = 51, ['0'] = 52, ['1'] = 53, ['2'] = 54,
['3'] = 55, ['4'] = 56, ['5'] = 57, ['6'] = 58, ['7'] = 59,
['8'] = 60, ['9'] = 61, ['+'] = 62, ['/'] = 63
};
@@ -43,86 +42,93 @@ const char PAD = '=';
const char FIRST = '+';
const char LAST = 'z';
public func void encode(char[] in, char *out)
fn void encode(char[] in, char *out)
{
int j = 0;
char c = LUT_ENC[1];
for (int i = 0; i < in.len(); i++)
char c = LUT_ENC[1];
for (int i = 0; i < in.len; i++)
{
switch (i % 3)
{
case 0:
out[j++] = LUT_ENC[(in[i] >> 2) & 0x3F];
case 1:
out[j++] = LUT_ENC[(in[i - 1] & 0x3) << 4 + ((in[i] >> 4) & 0xF)];
case 2:
out[j++] = LUT_ENC[(in[i - 1] & 0xF) << 2 + ((in[i] >> 6) & 0x3)];
out[j++] = LUT_ENC[in[i] & 0x3F];
}
switch (i % 3)
{
case 0:
out[j++] = LUT_ENC[(in[i] >> 2) & 0x3F];
case 1:
out[j++] = LUT_ENC[(in[i - 1] & 0x3) << 4 + ((in[i] >> 4) & 0xF)];
case 2:
out[j++] = LUT_ENC[(in[i - 1] & 0xF) << 2 + ((in[i] >> 6) & 0x3)];
out[j++] = LUT_ENC[in[i] & 0x3F];
}
}
// move back
usize last = in.len() - 1;
// check the last and add padding
switch (last % 3)
{
case 0:
out[j++] = LUT_ENC[(in[last] & 0x3) << 4];
out[j++] = PAD;
out[j++] = PAD;
case 1:
out[j++] = LUT_ENC[(in[last] & 0xF) << 2];
out[j++] = PAD;
}
// move back
usize last = in.len - 1;
// check the last and add padding
switch (last % 3)
{
case 0:
out[j++] = LUT_ENC[(in[last] & 0x3) << 4];
out[j++] = PAD;
out[j++] = PAD;
case 1:
out[j++] = LUT_ENC[(in[last] & 0xF) << 2];
out[j++] = PAD;
}
}
public func int! decode(char[] in, char* out)
fn int! decode(char[] in, char* out, int* invalid_char_index = null)
{
int j = 0;
int j = 0;
for (int i = 0; i < in.len(); i++)
{
char value = in[i];
if (value == PAD) return j;
for (int i = 0; i < in.len; i++)
{
char value = in[i];
if (value == PAD) return j;
char c = LUT_DEC[in[i]];
if (c == ERR) return InvalidCharacter({i, value})!;
char c = LUT_DEC[in[i]];
if (c == ERR)
{
if (invalid_char_index) *invalid_char_index = i;
return DecodingError.INVALID_CHARACTER!;
}
switch (i % 4)
{
case 0:
out[j] = c << 2;
case 1:
out[j++] += c >> 4 & 0x3;
// if not last char with padding
if (i < (in.len() - 3) || in[(long)(in.len()) - 2] != PAD)
{
out[j] = (c & 0xF) << 4;
}
case 2:
out[j++] += c >> 2 & 0xF;
if (i < (in.len() - 2) || in[(long)(in.len()) - 1] != PAD)
{
out[j] = (c & 0x3) << 6;
}
case 3:
out[j++] += c;
}
}
return j;
switch (i % 4)
{
case 0:
out[j] = c << 2;
case 1:
out[j++] += c >> 4 & 0x3;
// if not last char with padding
if (i < (in.len - 3) || in[(long)(in.len) - 2] != PAD)
{
out[j] = (c & 0xF) << 4;
}
case 2:
out[j++] += c >> 2 & 0xF;
if (i < (in.len - 2) || in[(long)(in.len) - 1] != PAD)
{
out[j] = (c & 0x3) << 6;
}
case 3:
out[j++] += c;
}
}
return j;
}
extern func void printf(char *fmt, ...);
extern fn void printf(char *fmt, ...);
public func void main()
fn void main()
{
char *helloworld = "Hello World\n";
char[1000] buffer;
encode(helloworld[0..12], &buffer);
printf("Result: %s\n", &buffer);
char *to_decode = "aGVsbG8gd29ybGRcMA==";
decode(to_decode[0..19], &buffer);
printf("Result: %s\n", &buffer);
char *helloworld = "Hello World\n";
char[1000] buffer;
encode(helloworld[0..12], &buffer);
printf("Result: %s\n", &buffer);
char *to_decode = "aGVsbG8gd29ybGRcMA==";
char[*] result = b64"aGVsbG8gd29ybGRcMA==";
decode(to_decode[0..19], &buffer);
printf("Result: %s\n", &buffer);
printf("Result direct: %.*s\n", 13, &result);
}

View File

@@ -0,0 +1,25 @@
module binarydigits;
import std::math;
import std::io;
fn void main()
{
for (int i = 0; i < 20; i++)
{
String s = bin(i);
defer s.destroy();
io::printf("%s\n", s);
}
}
fn String bin(int x)
{
int bits = 1 + (int)(x == 0 ? 0 : math::log10((double)(x)) / math::log10(2));
String str;
str.append_repeat('0', bits);
for (int i = 0; i < bits; i++)
{
str.set((usize)(bits - i - 1), x & 1 ? '1' : '0');
x >>= 1;
}
return str;
}

View File

@@ -0,0 +1,141 @@
module test;
import libc;
import std::io;
struct Doc { Head *head; }
struct Head { String* title; }
struct Summary
{
String* title;
bool ok;
}
private struct StringData
{
Allocator allocator;
usize len;
usize capacity;
char[*] chars;
}
fn void Summary.print(Summary *s, File out)
{
char[] title = s.title ? s.title.str() : "missing";
out.printf("Summary({ .title = %s, .ok = %s})", title, s.ok);
}
fn bool contains(char[] haystack, char[] needle)
{
usize len = haystack.len;
usize needle_len = needle.len;
if (len < needle_len) return false;
if (!needle_len) return true;
len -= needle_len - 1;
for (usize i = 0; i < len; i++)
{
if (libc::memcmp(&haystack[i], needle.ptr, needle_len) == 0)
{
return true;
}
}
return false;
}
macro @dupe(value)
{
$typeof(&value) temp = mem::alloc_checked($sizeof(value))?;
*temp = value;
return temp;
}
fault ReadError
{
BAD_READ,
}
fn Doc! readDoc(char[] url)
{
if (contains(url, "fail")) return ReadError.BAD_READ!;
if (contains(url, "head-missing")) return { .head = null };
if (contains(url, "title-missing")) return { @dupe(Head { .title = null }) };
if (contains(url, "title-empty")) return { @dupe(Head { .title = @dupe((String)null) }) };
String str;
str.printf("Title of %s", url);
return { @dupe(Head { .title = @dupe(str) }) };
}
fn Summary buildSummary(Doc doc)
{
return Summary {
.title = doc.head ? doc.head.title : null,
.ok = true,
};
}
fn Summary readAndBuildSummary(char[] url)
{
return buildSummary(readDoc(url)) ?? Summary { .title = null, .ok = false };
/*
// or
Summary summary = buildSummary(readDoc(url));
if (catch summary) return Summary { .title = null, .ok = false };
return summary;
// or
Summary summary = buildSummary(readDoc(url));
if (try summary) return summary;
return Summary { .title = null, .ok = false };
*/
}
fault TitleResult
{
TITLE_MISSING
}
fn bool! isTitleNonEmpty(Doc doc)
{
if (!doc.head) return TitleResult.TITLE_MISSING!;
String* head = doc.head.title;
if (!head) return TitleResult.TITLE_MISSING!;
return head.len() > 0;
}
fn bool! readWhetherTitleNonEmpty(char[] url)
{
return isTitleNonEmpty(readDoc(url));
}
fn char[] bool_to_string(bool b)
{
return b ? "true" : "false";
}
fn void main()
{
const char[][] URLS = { "good", "title-empty", "title-missing", "head-missing", "fail" };
DynamicArenaAllocator dynamic_arena;
dynamic_arena.init(1024);
foreach (char[] url : URLS)
{
mem::@with_allocator(&dynamic_arena)
{
io::printf(`Checking "https://%s/":` "\n", url);
Summary summary = readAndBuildSummary(url);
io::printf(" Summary: ");
summary.print(io::stdout());
io::println("");
char[] title_sure = summary.title ? summary.title.str() : "";
io::printf(" Title: %s\n", title_sure);
bool! has_title = readWhetherTitleNonEmpty(url);
// This looks a bit less than elegant, but as you see it's mostly due to having to
// use printf here.
io::printf(" Has title: %s vs %s\n", bool_to_string(has_title) ?? catch(has_title).nameof, has_title ?? false);
};
dynamic_arena.reset();
}
dynamic_arena.destroy();
}

View File

@@ -0,0 +1,28 @@
module foo;
import std::io;
tlocal char[] context_user = "safe";
macro long perform(task)
{
io::printf("%s: %s\n", context_user, task);
return task.len;
}
macro @with_mode(char[] user, #action, arg)
{
@scope(context_user)
{
context_user = user;
return #action(arg);
};
}
fn void main()
{
long result = perform("something!");
result += @with_mode("faster", perform, "reliable");
result += perform(char[][] {"again", "more"});
result += perform(int[<2>] { 56, 99 });
io::printf("Result: %d\n", result);
}

View File

@@ -0,0 +1,93 @@
module guess_number;
import std::io;
import libc;
extern fn isize getline(char** linep, usize* linecapp, CFile stream);
struct Game
{
int answer;
bool done;
int guesses;
int high;
}
fault InputResult
{
NOT_AN_INT,
FAILED_TO_READ,
}
int err_count = 0;
fn int! askGuess(int high)
{
libc::printf("Guess a number between 1 and %d: ", high);
char[] text = readLine()?;
char* end = null;
int value = (int)libc::strtol(text.ptr, &end, 10);
if (end && end[0] >= ' ') return InputResult.NOT_AN_INT!;
return value;
}
fn char[]! readLine()
{
char* chars = mem::talloc(1024)?;
isize loaded = getline(&chars, &&(usize)1023, libc::stdin());
if (loaded < 0) return InputResult.FAILED_TO_READ!;
chars[loaded] = 0;
return chars[0..(loaded - 1)];
}
fn int! askGuessMulti(int high)
{
while (true)
{
int! result = askGuess(high);
if (catch(result) == InputResult.NOT_AN_INT)
{
libc::printf("I didn't understand that.\n");
err_count++;
continue;
}
return result;
}
unreachable();
}
fn void! Game.play(Game *game)
{
while (!game.done)
{
int guess = askGuessMulti(game.high)?;
game.report(guess);
game.update(guess);
}
}
fn void Game.report(Game *game, int guess)
{
char[] desc = {|
if (guess < game.answer) return "too low";
if (guess > game.answer) return "too high";
return "the answer";
|};
libc::printf("%d is %.*s.\n", guess, (int)desc.len, desc.ptr);
}
fn void Game.update(Game *game, int guess)
{
if (guess == game.answer) game.done = true;
game.guesses++;
}
fn void! main()
{
libc::srand((int)libc::clock());
int high = 100;
int answer = libc::rand() % high + 1;
Game game = { .answer = answer, .high = high };
game.play();
libc::printf("Finished in %d guesses.\n", game.guesses);
libc::printf("Total input errors: %d.\n", err_count);
}

View File

@@ -0,0 +1,27 @@
module test;
import std::io;
fn void main()
{
/*
Here's a comment.
/*
And a nested comment.
*/
*/
char[] text = `
function hello() {
console.log("name`"\t"`age");
}
hello();
`;
io::println(text);
// Binary
const DATA = x"4749463839610100010080"
x"0100ffffff00000021f904"
x"010a0001002c0000000001"
x"0001000002024c01003b";
io::printf("%d\n", DATA.len);
}

View File

@@ -0,0 +1,16 @@
macro int factorial($n)
{
$if ($n == 0):
return 1;
$else:
return $n * factorial($n - 1);
$endif;
}
extern fn void printf(char *fmt, ...);
fn void main()
{
int x = factorial(12);
printf("12! = %d\n", x);
}

View File

@@ -0,0 +1,76 @@
module fannkuch;
import std::array;
import std::io;
import std::math;
import libc;
fn int fannkuchredux(int n)
{
int* perm = array::alloc(int, n);
int* perm1 = array::alloc(int, n);
int* count = array::alloc(int, n);
int max_flips_count;
int perm_count;
int checksum;
for (int i = 0; i < n; i++) perm1[i] = i;
int r = n;
while (1)
{
for (; r != 1; r--) count[r - 1] = r;
for (int i = 0; i < n; i++) perm[i] = perm1[i];
int flips_count = 0;
int k;
while (!((k = perm[0]) == 0))
{
int k2 = (k + 1) >> 1;
for (int i = 0; i < k2; i++)
{
int temp = perm[i];
perm[i] = perm[k - i];
perm[k - i] = temp;
}
flips_count++;
}
max_flips_count = max(max_flips_count, flips_count);
checksum += perm_count % 2 == 0 ? flips_count : -flips_count;
/* Use incremental change to generate another permutation */
while (1)
{
if (r == n)
{
io::printf("%d\n", checksum);
return max_flips_count;
}
int perm0 = perm1[0];
int i = 0;
while (i < r)
{
int j = i + 1;
perm1[i] = perm1[j];
i = j;
}
perm1[r] = perm0;
count[r] = count[r] - 1;
if (count[r] > 0) break;
r++;
}
perm_count++;
}
return 0;
}
fn int main(int argc, char** argv)
{
int n = argc > 1 ? libc::atoi(argv[1]) : 7;
io::printf("Pfannkuchen(%d) = %d\n", n, fannkuchredux(n));
return 0;
}

104
resources/examples/fasta.c3 Normal file
View File

@@ -0,0 +1,104 @@
module fasta;
import std::io;
import libc;
const IM = 139968;
const IA = 3877;
const IC = 29573;
const SEED = 42;
uint seed = SEED;
fn float fasta_rand(float max_val)
{
seed = (seed * IA + IC) % IM;
return max_val * seed / IM;
}
private char[] alu =
"GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG"
"GAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA"
"CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT"
"ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA"
"GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG"
"AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC"
"AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA";
char[] iub = "acgtBDHKMNRSVWY";
double[] iub_p = {
0.27,
0.12,
0.12,
0.27,
0.02,
0.02,
0.02,
0.02,
0.02,
0.02,
0.02,
0.02,
0.02,
0.02,
0.02 };
char[] homosapiens = "acgt";
double[] homosapiens_p = {
0.3029549426680,
0.1979883004921,
0.1975473066391,
0.3015094502008
};
const LINELEN = 60;
// slowest character-at-a-time output
fn void repeat_fasta(char[] seq, int n)
{
usize len = seq.len;
int i = void;
for (i = 0; i < n; i++)
{
io::putchar(seq[i % len]);
if (i % LINELEN == LINELEN - 1) io::putchar('\n');
}
if (i % LINELEN != 0) io::putchar('\n');
}
fn void random_fasta(char[] symb, double[] probability, int n)
{
assert(symb.len == probability.len);
int len = probability.len;
int i = void;
for (i = 0; i < n; i++)
{
double v = fasta_rand(1.0);
/* slowest idiomatic linear lookup. Fast if len is short though. */
int j = void;
for (j = 0; j < len - 1; j++)
{
v -= probability[j];
if (v < 0) break;
}
io::putchar(symb[j]);
if (i % LINELEN == LINELEN - 1) io::putchar('\n');
}
if (i % LINELEN != 0) io::putchar('\n');
}
fn void main(int argc, char **argv)
{
int n = 1000;
if (argc > 1) n = libc::atoi(argv[1]);
io::printf(">ONE Homo sapiens alu\n");
repeat_fasta(alu, n * 2);
io::printf(">TWO IUB ambiguity codes\n");
random_fasta(iub, iub_p, n * 3);
io::printf(">THREE Homo sapiens frequency\n");
random_fasta(homosapiens, homosapiens_p, n * 5);
}

View File

@@ -1,86 +1,82 @@
module game_of_life;
import std::io;
import libc;
extern func void printf(char *fmt, ...);
extern func int atoi(char *val);
extern void *__stdoutp;
extern func void fflush(void *std);
extern func int rand();
extern func void* malloc(usize size);
extern func void usleep(int time);
extern fn void usleep(int time);
struct GameBoard
{
int h;
int w;
char* world;
char* temp;
int h;
int w;
char* world;
char* temp;
}
func void GameBoard.show(GameBoard *board)
fn void GameBoard.show(GameBoard *board)
{
printf("\e[H");
io::printf("\e[H");
char* current = board.world;
for (int y = 0; y < board.h; y++)
{
for (int x = 0; x < board.w; x++)
{
printf(*current ? "\e[07m \e[m" : " ");
current++;
}
printf("\e[E");
for (int x = 0; x < board.w; x++)
{
io::printf(*current ? "\e[07m \e[m" : " ");
current++;
}
io::printf("\e[E");
}
fflush(__stdoutp);
libc::fflush(libc::stdout());
}
func void GameBoard.evolve(GameBoard *board)
fn void GameBoard.evolve(GameBoard *board)
{
for (int y = 0; y < board.h; y++)
{
for (int x = 0; x < board.w; x++)
{
int n = 0;
for (int y1 = y - 1; y1 <= y + 1; y1++)
{
for (int x1 = x - 1; x1 <= x + 1; x1++)
{
int actualX = (x1 + board.w) % board.w;
int actualY = (y1 + board.h) % board.h;
if (board.world[actualX + actualY * board.w]) n++;
}
}
if (board.world[x + y * board.w]) n--;
board.temp[x + y * board.w] = (char)(n == 3 || (n == 2 && board.world[x + y * board.w]));
}
for (int x = 0; x < board.w; x++)
{
int n = 0;
for (int y1 = y - 1; y1 <= y + 1; y1++)
{
for (int x1 = x - 1; x1 <= x + 1; x1++)
{
int actualX = (x1 + board.w) % board.w;
int actualY = (y1 + board.h) % board.h;
if (board.world[actualX + actualY * board.w]) n++;
}
}
if (board.world[x + y * board.w]) n--;
board.temp[x + y * board.w] = (char)(n == 3 || (n == 2 && board.world[x + y * board.w]));
}
}
for (int i = 0; i < board.w * board.h; i++)
{
board.world[i] = board.temp[i];
board.world[i] = board.temp[i];
}
}
func int main(int c, char** v)
fn int main(int c, char** v)
{
int w = 0;
int h = 0;
if (c > 1) w = atoi(v[1]);
if (c > 2) h = atoi(v[2]);
if (c > 1) w = libc::atoi(v[1]);
if (c > 2) h = libc::atoi(v[2]);
if (w <= 0) w = 30;
if (h <= 0) h = 30;
GameBoard board;
board.w = w;
board.h = h;
board.world = malloc((ulong)(h * w));
board.temp = malloc((ulong)(h * w));
GameBoard board;
board.w = w;
board.h = h;
board.world = mem::alloc((ulong)(h * w));
board.temp = mem::alloc((ulong)(h * w));
for (int i = h * w - 1; i >= 0; i--)
{
board.world[i] = rand() % 10 == 0 ? 1 : 0;
}
for (int j = 0; j < 1000; j++)
for (int i = h * w - 1; i >= 0; i--)
{
board.world[i] = libc::rand() % 10 == 0 ? 1 : 0;
}
for (int j = 0; j < 1000; j++)
{
board.show();
board.evolve();

View File

@@ -1,24 +1,23 @@
module hash;
import libc;
// Code adapted from Odin's hash.odin
// The code below should not be considered *correct*
// They are merely done to illustrate the language syntax.
extern func void printf(char*, ...);
public func void main()
fn void main()
{
char* y = "Hello World!";
printf("Adler32 of %s is %x\n", y, adler32(y[0..11]));
printf("CRC32 of %s is %x\n", y, crc32(y[0..11]));
printf("CRC64 of %s is %llx\n", y, crc64(y[0..11]));
printf("FNV32 of %s is %x\n", y, fnv32(y[0..11]));
printf("FNV32a of %s is %x\n", y, fnv32a(y[0..11]));
printf("FNV64 of %s is %llx\n", y, fnv64(y[0..11]));
printf("FNV64a of %s is %llx\n", y, fnv64a(y[0..11]));
char[] y = "Hello World!";
libc::printf("Adler32 of %s is %x, expected 1c49043e\n", (char*)(y), adler32(y));
libc::printf("CRC32B of %s is %x, expected 1c291ca3\n", (char*)(y), crc32(y));
libc::printf("CRC64 of %s is %llx, expected fad9a77c67077205\n", (char*)(y), crc64(y));
libc::printf("FNV32 of %s is %x, expected 12a9a41c\n", (char*)(y), fnv32(y));
libc::printf("FNV32a of %s is %x, expected b1ea4872\n", (char*)(y), fnv32a(y));
libc::printf("FNV64 of %s is %llx, expected 8e59dd02f68c387c\n", (char*)(y), fnv64(y));
libc::printf("FNV64a of %s is %llx, expected 8c0ec8d1fb9e6e32\n", (char*)(y), fnv64a(y));
}
public func uint adler32(char[] data)
fn uint adler32(char[] data)
{
const uint ADLER_CONST = 65521;
uint a = 1;
@@ -31,7 +30,7 @@ public func uint adler32(char[] data)
return (b << 16) | a;
}
public func uint crc32(char[] data)
fn uint crc32(char[] data)
{
uint result = ~(uint)(0);
foreach (char x : data)
@@ -41,18 +40,18 @@ public func uint crc32(char[] data)
return ~result;
}
public func ulong crc64(char[] data)
fn ulong crc64(char[] data)
{
ulong result = 0;
ulong result = (ulong)(0);
foreach (char x : data)
{
result = (result >> 8) ^ CRC64_TABLE[(char)(result ^ x)];
result = (result << 8) ^ CRC64_TABLE[(char)((result >> 56) ^ x)];
}
return result;
}
public func uint fnv32(char[] data)
fn uint fnv32(char[] data)
{
uint h = 0x811c9dc5;
foreach (char x : data)
@@ -62,7 +61,7 @@ public func uint fnv32(char[] data)
return h;
}
public func ulong fnv64(char[] data)
fn ulong fnv64(char[] data)
{
ulong h = 0xcbf29ce484222325;
foreach (char x : data)
@@ -72,7 +71,7 @@ public func ulong fnv64(char[] data)
return h;
}
public func uint fnv32a(char[] data)
fn uint fnv32a(char[] data)
{
uint h = 0x811c9dc5;
foreach (char x : data)
@@ -82,7 +81,7 @@ public func uint fnv32a(char[] data)
return h;
}
public func ulong fnv64a(char[] data)
fn ulong fnv64a(char[] data)
{
ulong h = 0xcbf29ce484222325;
foreach (char x : data)
@@ -92,7 +91,7 @@ public func ulong fnv64a(char[] data)
return h;
}
const uint[256] CRC32_TABLE = {
private const uint[256] CRC32_TABLE = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
@@ -159,133 +158,69 @@ const uint[256] CRC32_TABLE = {
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
};
const ulong[256] CRC64_TABLE = {
0x0000000000000000, 0x7ad870c830358979,
0xf5b0e190606b12f2, 0x8f689158505e9b8b,
0xc038e5739841b68f, 0xbae095bba8743ff6,
0x358804e3f82aa47d, 0x4f50742bc81f2d04,
0xab28ecb46814fe75, 0xd1f09c7c5821770c,
0x5e980d24087fec87, 0x24407dec384a65fe,
0x6b1009c7f05548fa, 0x11c8790fc060c183,
0x9ea0e857903e5a08, 0xe478989fa00bd371,
0x7d08ff3b88be6f81, 0x07d08ff3b88be6f8,
0x88b81eabe8d57d73, 0xf2606e63d8e0f40a,
0xbd301a4810ffd90e, 0xc7e86a8020ca5077,
0x4880fbd87094cbfc, 0x32588b1040a14285,
0xd620138fe0aa91f4, 0xacf86347d09f188d,
0x2390f21f80c18306, 0x594882d7b0f40a7f,
0x1618f6fc78eb277b, 0x6cc0863448deae02,
0xe3a8176c18803589, 0x997067a428b5bcf0,
0xfa11fe77117cdf02, 0x80c98ebf2149567b,
0x0fa11fe77117cdf0, 0x75796f2f41224489,
0x3a291b04893d698d, 0x40f16bccb908e0f4,
0xcf99fa94e9567b7f, 0xb5418a5cd963f206,
0x513912c379682177, 0x2be1620b495da80e,
0xa489f35319033385, 0xde51839b2936bafc,
0x9101f7b0e12997f8, 0xebd98778d11c1e81,
0x64b116208142850a, 0x1e6966e8b1770c73,
0x8719014c99c2b083, 0xfdc17184a9f739fa,
0x72a9e0dcf9a9a271, 0x08719014c99c2b08,
0x4721e43f0183060c, 0x3df994f731b68f75,
0xb29105af61e814fe, 0xc849756751dd9d87,
0x2c31edf8f1d64ef6, 0x56e99d30c1e3c78f,
0xd9810c6891bd5c04, 0xa3597ca0a188d57d,
0xec09088b6997f879, 0x96d1784359a27100,
0x19b9e91b09fcea8b, 0x636199d339c963f2,
0xdf7adabd7a6e2d6f, 0xa5a2aa754a5ba416,
0x2aca3b2d1a053f9d, 0x50124be52a30b6e4,
0x1f423fcee22f9be0, 0x659a4f06d21a1299,
0xeaf2de5e82448912, 0x902aae96b271006b,
0x74523609127ad31a, 0x0e8a46c1224f5a63,
0x81e2d7997211c1e8, 0xfb3aa75142244891,
0xb46ad37a8a3b6595, 0xceb2a3b2ba0eecec,
0x41da32eaea507767, 0x3b024222da65fe1e,
0xa2722586f2d042ee, 0xd8aa554ec2e5cb97,
0x57c2c41692bb501c, 0x2d1ab4dea28ed965,
0x624ac0f56a91f461, 0x1892b03d5aa47d18,
0x97fa21650afae693, 0xed2251ad3acf6fea,
0x095ac9329ac4bc9b, 0x7382b9faaaf135e2,
0xfcea28a2faafae69, 0x8632586aca9a2710,
0xc9622c4102850a14, 0xb3ba5c8932b0836d,
0x3cd2cdd162ee18e6, 0x460abd1952db919f,
0x256b24ca6b12f26d, 0x5fb354025b277b14,
0xd0dbc55a0b79e09f, 0xaa03b5923b4c69e6,
0xe553c1b9f35344e2, 0x9f8bb171c366cd9b,
0x10e3202993385610, 0x6a3b50e1a30ddf69,
0x8e43c87e03060c18, 0xf49bb8b633338561,
0x7bf329ee636d1eea, 0x012b592653589793,
0x4e7b2d0d9b47ba97, 0x34a35dc5ab7233ee,
0xbbcbcc9dfb2ca865, 0xc113bc55cb19211c,
0x5863dbf1e3ac9dec, 0x22bbab39d3991495,
0xadd33a6183c78f1e, 0xd70b4aa9b3f20667,
0x985b3e827bed2b63, 0xe2834e4a4bd8a21a,
0x6debdf121b863991, 0x1733afda2bb3b0e8,
0xf34b37458bb86399, 0x8993478dbb8deae0,
0x06fbd6d5ebd3716b, 0x7c23a61ddbe6f812,
0x3373d23613f9d516, 0x49aba2fe23cc5c6f,
0xc6c333a67392c7e4, 0xbc1b436e43a74e9d,
0x95ac9329ac4bc9b5, 0xef74e3e19c7e40cc,
0x601c72b9cc20db47, 0x1ac40271fc15523e,
0x5594765a340a7f3a, 0x2f4c0692043ff643,
0xa02497ca54616dc8, 0xdafce7026454e4b1,
0x3e847f9dc45f37c0, 0x445c0f55f46abeb9,
0xcb349e0da4342532, 0xb1eceec59401ac4b,
0xfebc9aee5c1e814f, 0x8464ea266c2b0836,
0x0b0c7b7e3c7593bd, 0x71d40bb60c401ac4,
0xe8a46c1224f5a634, 0x927c1cda14c02f4d,
0x1d148d82449eb4c6, 0x67ccfd4a74ab3dbf,
0x289c8961bcb410bb, 0x5244f9a98c8199c2,
0xdd2c68f1dcdf0249, 0xa7f41839ecea8b30,
0x438c80a64ce15841, 0x3954f06e7cd4d138,
0xb63c61362c8a4ab3, 0xcce411fe1cbfc3ca,
0x83b465d5d4a0eece, 0xf96c151de49567b7,
0x76048445b4cbfc3c, 0x0cdcf48d84fe7545,
0x6fbd6d5ebd3716b7, 0x15651d968d029fce,
0x9a0d8ccedd5c0445, 0xe0d5fc06ed698d3c,
0xaf85882d2576a038, 0xd55df8e515432941,
0x5a3569bd451db2ca, 0x20ed197575283bb3,
0xc49581ead523e8c2, 0xbe4df122e51661bb,
0x3125607ab548fa30, 0x4bfd10b2857d7349,
0x04ad64994d625e4d, 0x7e7514517d57d734,
0xf11d85092d094cbf, 0x8bc5f5c11d3cc5c6,
0x12b5926535897936, 0x686de2ad05bcf04f,
0xe70573f555e26bc4, 0x9ddd033d65d7e2bd,
0xd28d7716adc8cfb9, 0xa85507de9dfd46c0,
0x273d9686cda3dd4b, 0x5de5e64efd965432,
0xb99d7ed15d9d8743, 0xc3450e196da80e3a,
0x4c2d9f413df695b1, 0x36f5ef890dc31cc8,
0x79a59ba2c5dc31cc, 0x037deb6af5e9b8b5,
0x8c157a32a5b7233e, 0xf6cd0afa9582aa47,
0x4ad64994d625e4da, 0x300e395ce6106da3,
0xbf66a804b64ef628, 0xc5bed8cc867b7f51,
0x8aeeace74e645255, 0xf036dc2f7e51db2c,
0x7f5e4d772e0f40a7, 0x05863dbf1e3ac9de,
0xe1fea520be311aaf, 0x9b26d5e88e0493d6,
0x144e44b0de5a085d, 0x6e963478ee6f8124,
0x21c640532670ac20, 0x5b1e309b16452559,
0xd476a1c3461bbed2, 0xaeaed10b762e37ab,
0x37deb6af5e9b8b5b, 0x4d06c6676eae0222,
0xc26e573f3ef099a9, 0xb8b627f70ec510d0,
0xf7e653dcc6da3dd4, 0x8d3e2314f6efb4ad,
0x0256b24ca6b12f26, 0x788ec2849684a65f,
0x9cf65a1b368f752e, 0xe62e2ad306bafc57,
0x6946bb8b56e467dc, 0x139ecb4366d1eea5,
0x5ccebf68aecec3a1, 0x2616cfa09efb4ad8,
0xa97e5ef8cea5d153, 0xd3a62e30fe90582a,
0xb0c7b7e3c7593bd8, 0xca1fc72bf76cb2a1,
0x45775673a732292a, 0x3faf26bb9707a053,
0x70ff52905f188d57, 0x0a2722586f2d042e,
0x854fb3003f739fa5, 0xff97c3c80f4616dc,
0x1bef5b57af4dc5ad, 0x61372b9f9f784cd4,
0xee5fbac7cf26d75f, 0x9487ca0fff135e26,
0xdbd7be24370c7322, 0xa10fceec0739fa5b,
0x2e675fb4576761d0, 0x54bf2f7c6752e8a9,
0xcdcf48d84fe75459, 0xb71738107fd2dd20,
0x387fa9482f8c46ab, 0x42a7d9801fb9cfd2,
0x0df7adabd7a6e2d6, 0x772fdd63e7936baf,
0xf8474c3bb7cdf024, 0x829f3cf387f8795d,
0x66e7a46c27f3aa2c, 0x1c3fd4a417c62355,
0x935745fc4798b8de, 0xe98f353477ad31a7,
0xa6df411fbfb21ca3, 0xdc0731d78f8795da,
0x536fa08fdfd90e51, 0x29b7d047efec8728,
private const ulong[256] CRC64_TABLE = {
0x0000000000000000, 0x42f0e1eba9ea3693, 0x85e1c3d753d46d26, 0xc711223cfa3e5bb5,
0x493366450e42ecdf, 0x0bc387aea7a8da4c, 0xccd2a5925d9681f9, 0x8e224479f47cb76a,
0x9266cc8a1c85d9be, 0xd0962d61b56fef2d, 0x17870f5d4f51b498, 0x5577eeb6e6bb820b,
0xdb55aacf12c73561, 0x99a54b24bb2d03f2, 0x5eb4691841135847, 0x1c4488f3e8f96ed4,
0x663d78ff90e185ef, 0x24cd9914390bb37c, 0xe3dcbb28c335e8c9, 0xa12c5ac36adfde5a,
0x2f0e1eba9ea36930, 0x6dfeff5137495fa3, 0xaaefdd6dcd770416, 0xe81f3c86649d3285,
0xf45bb4758c645c51, 0xb6ab559e258e6ac2, 0x71ba77a2dfb03177, 0x334a9649765a07e4,
0xbd68d2308226b08e, 0xff9833db2bcc861d, 0x388911e7d1f2dda8, 0x7a79f00c7818eb3b,
0xcc7af1ff21c30bde, 0x8e8a101488293d4d, 0x499b3228721766f8, 0x0b6bd3c3dbfd506b,
0x854997ba2f81e701, 0xc7b97651866bd192, 0x00a8546d7c558a27, 0x4258b586d5bfbcb4,
0x5e1c3d753d46d260, 0x1cecdc9e94ace4f3, 0xdbfdfea26e92bf46, 0x990d1f49c77889d5,
0x172f5b3033043ebf, 0x55dfbadb9aee082c, 0x92ce98e760d05399, 0xd03e790cc93a650a,
0xaa478900b1228e31, 0xe8b768eb18c8b8a2, 0x2fa64ad7e2f6e317, 0x6d56ab3c4b1cd584,
0xe374ef45bf6062ee, 0xa1840eae168a547d, 0x66952c92ecb40fc8, 0x2465cd79455e395b,
0x3821458aada7578f, 0x7ad1a461044d611c, 0xbdc0865dfe733aa9, 0xff3067b657990c3a,
0x711223cfa3e5bb50, 0x33e2c2240a0f8dc3, 0xf4f3e018f031d676, 0xb60301f359dbe0e5,
0xda050215ea6c212f, 0x98f5e3fe438617bc, 0x5fe4c1c2b9b84c09, 0x1d14202910527a9a,
0x93366450e42ecdf0, 0xd1c685bb4dc4fb63, 0x16d7a787b7faa0d6, 0x5427466c1e109645,
0x4863ce9ff6e9f891, 0x0a932f745f03ce02, 0xcd820d48a53d95b7, 0x8f72eca30cd7a324,
0x0150a8daf8ab144e, 0x43a04931514122dd, 0x84b16b0dab7f7968, 0xc6418ae602954ffb,
0xbc387aea7a8da4c0, 0xfec89b01d3679253, 0x39d9b93d2959c9e6, 0x7b2958d680b3ff75,
0xf50b1caf74cf481f, 0xb7fbfd44dd257e8c, 0x70eadf78271b2539, 0x321a3e938ef113aa,
0x2e5eb66066087d7e, 0x6cae578bcfe24bed, 0xabbf75b735dc1058, 0xe94f945c9c3626cb,
0x676dd025684a91a1, 0x259d31cec1a0a732, 0xe28c13f23b9efc87, 0xa07cf2199274ca14,
0x167ff3eacbaf2af1, 0x548f120162451c62, 0x939e303d987b47d7, 0xd16ed1d631917144,
0x5f4c95afc5edc62e, 0x1dbc74446c07f0bd, 0xdaad56789639ab08, 0x985db7933fd39d9b,
0x84193f60d72af34f, 0xc6e9de8b7ec0c5dc, 0x01f8fcb784fe9e69, 0x43081d5c2d14a8fa,
0xcd2a5925d9681f90, 0x8fdab8ce70822903, 0x48cb9af28abc72b6, 0x0a3b7b1923564425,
0x70428b155b4eaf1e, 0x32b26afef2a4998d, 0xf5a348c2089ac238, 0xb753a929a170f4ab,
0x3971ed50550c43c1, 0x7b810cbbfce67552, 0xbc902e8706d82ee7, 0xfe60cf6caf321874,
0xe224479f47cb76a0, 0xa0d4a674ee214033, 0x67c58448141f1b86, 0x253565a3bdf52d15,
0xab1721da49899a7f, 0xe9e7c031e063acec, 0x2ef6e20d1a5df759, 0x6c0603e6b3b7c1ca,
0xf6fae5c07d3274cd, 0xb40a042bd4d8425e, 0x731b26172ee619eb, 0x31ebc7fc870c2f78,
0xbfc9838573709812, 0xfd39626eda9aae81, 0x3a28405220a4f534, 0x78d8a1b9894ec3a7,
0x649c294a61b7ad73, 0x266cc8a1c85d9be0, 0xe17dea9d3263c055, 0xa38d0b769b89f6c6,
0x2daf4f0f6ff541ac, 0x6f5faee4c61f773f, 0xa84e8cd83c212c8a, 0xeabe6d3395cb1a19,
0x90c79d3fedd3f122, 0xd2377cd44439c7b1, 0x15265ee8be079c04, 0x57d6bf0317edaa97,
0xd9f4fb7ae3911dfd, 0x9b041a914a7b2b6e, 0x5c1538adb04570db, 0x1ee5d94619af4648,
0x02a151b5f156289c, 0x4051b05e58bc1e0f, 0x87409262a28245ba, 0xc5b073890b687329,
0x4b9237f0ff14c443, 0x0962d61b56fef2d0, 0xce73f427acc0a965, 0x8c8315cc052a9ff6,
0x3a80143f5cf17f13, 0x7870f5d4f51b4980, 0xbf61d7e80f251235, 0xfd913603a6cf24a6,
0x73b3727a52b393cc, 0x31439391fb59a55f, 0xf652b1ad0167feea, 0xb4a25046a88dc879,
0xa8e6d8b54074a6ad, 0xea16395ee99e903e, 0x2d071b6213a0cb8b, 0x6ff7fa89ba4afd18,
0xe1d5bef04e364a72, 0xa3255f1be7dc7ce1, 0x64347d271de22754, 0x26c49cccb40811c7,
0x5cbd6cc0cc10fafc, 0x1e4d8d2b65facc6f, 0xd95caf179fc497da, 0x9bac4efc362ea149,
0x158e0a85c2521623, 0x577eeb6e6bb820b0, 0x906fc95291867b05, 0xd29f28b9386c4d96,
0xcedba04ad0952342, 0x8c2b41a1797f15d1, 0x4b3a639d83414e64, 0x09ca82762aab78f7,
0x87e8c60fded7cf9d, 0xc51827e4773df90e, 0x020905d88d03a2bb, 0x40f9e43324e99428,
0x2cffe7d5975e55e2, 0x6e0f063e3eb46371, 0xa91e2402c48a38c4, 0xebeec5e96d600e57,
0x65cc8190991cb93d, 0x273c607b30f68fae, 0xe02d4247cac8d41b, 0xa2dda3ac6322e288,
0xbe992b5f8bdb8c5c, 0xfc69cab42231bacf, 0x3b78e888d80fe17a, 0x7988096371e5d7e9,
0xf7aa4d1a85996083, 0xb55aacf12c735610, 0x724b8ecdd64d0da5, 0x30bb6f267fa73b36,
0x4ac29f2a07bfd00d, 0x08327ec1ae55e69e, 0xcf235cfd546bbd2b, 0x8dd3bd16fd818bb8,
0x03f1f96f09fd3cd2, 0x41011884a0170a41, 0x86103ab85a2951f4, 0xc4e0db53f3c36767,
0xd8a453a01b3a09b3, 0x9a54b24bb2d03f20, 0x5d45907748ee6495, 0x1fb5719ce1045206,
0x919735e51578e56c, 0xd367d40ebc92d3ff, 0x1476f63246ac884a, 0x568617d9ef46bed9,
0xe085162ab69d5e3c, 0xa275f7c11f7768af, 0x6564d5fde549331a, 0x279434164ca30589,
0xa9b6706fb8dfb2e3, 0xeb46918411358470, 0x2c57b3b8eb0bdfc5, 0x6ea7525342e1e956,
0x72e3daa0aa188782, 0x30133b4b03f2b111, 0xf7021977f9cceaa4, 0xb5f2f89c5026dc37,
0x3bd0bce5a45a6b5d, 0x79205d0e0db05dce, 0xbe317f32f78e067b, 0xfcc19ed95e6430e8,
0x86b86ed5267cdbd3, 0xc4488f3e8f96ed40, 0x0359ad0275a8b6f5, 0x41a94ce9dc428066,
0xcf8b0890283e370c, 0x8d7be97b81d4019f, 0x4a6acb477bea5a2a, 0x089a2aacd2006cb9,
0x14dea25f3af9026d, 0x562e43b4931334fe, 0x913f6188692d6f4b, 0xd3cf8063c0c759d8,
0x5dedc41a34bbeeb2, 0x1f1d25f19d51d821, 0xd80c07cd676f8394, 0x9afce626ce85b507,
};

View File

@@ -0,0 +1,26 @@
module levenshtein;
import std::math;
// This levenshtein exercises C3 subarrays.
fn int levenshtein(char[] s, char[] t)
{
// if either string is empty, difference is inserting all chars
// from the other
if (!s.len) return t.len;
if (!t.len) return s.len;
// if last letters are the same, the difference is whatever is
// required to edit the rest of the strings
if (s[^1] == t[^1]) return levenshtein(s[0..^2], t[0..^2]);
// else try:
// changing last letter of s to that of t; or
// remove last letter of s; or
// remove last letter of t,
// any of which is 1 edit plus editing the rest of the strings
int a = levenshtein(s[0..^2], t[0..^2]);
int b = levenshtein(s, t[0..^2]);
int c = levenshtein(s[0..^2], t);
return min(min(a, b), c) + 1;
}

View File

@@ -0,0 +1,58 @@
module mandelbrot;
extern fn int atoi(char *s);
extern fn int printf(char *s, ...);
extern fn void putchar(int c);
fn void main(int argc, char **argv)
{
int w = atoi(argv[1]);
int h = w;
const LIMIT = 2.0;
const SQUARE_LIMIT = LIMIT * LIMIT;
printf("P4\n%d %d\n", w, h);
int iter = 50;
int bit_num = 0;
char byte_acc = 0;
for (double y = 0; y < h; y++)
{
for (double x = 0; x < w; x++)
{
double zr;
double zi;
double ti;
double tr;
double cr = (2.0 * x / w - 1.5);
double ci = (2.0 * y / h - 1.0);
for (int i = 0; i < iter && (tr + ti <= SQUARE_LIMIT); i++)
{
zi = 2.0 * zr * zi + ci;
zr = tr - ti + cr;
tr = zr * zr;
ti = zi * zi;
}
byte_acc <<= 1;
if (tr + ti <= SQUARE_LIMIT) byte_acc |= 0x01;
++bit_num;
if (bit_num == 8)
{
putchar(byte_acc);
byte_acc = 0;
bit_num = 0;
}
else if (x == w - 1)
{
byte_acc <<= (8 - w % 8);
putchar(byte_acc);
byte_acc = 0;
bit_num = 0;
}
}
}
}

View File

@@ -0,0 +1,161 @@
module nbodies;
const PI = 3.141592653589793;
const SOLAR_MASS = 4 * PI * PI;
const DAYS_PER_YEAR = 365.24;
const DT = 1e-2;
const RECIP_DT = (1.0/DT);
struct Planet
{
double x, y, z;
double vx, vy, vz;
double mass;
}
fn void advance(Planet[] bodies) @noinline
{
usize nbodies = bodies.len;
foreach (i, Planet* &b : bodies)
{
for (usize j = i + 1; j < nbodies; j++)
{
Planet* b2 = &bodies[j];
double dx = b.x - b2.x;
double dy = b.y - b2.y;
double dz = b.z - b2.z;
double inv_distance = 1.0/sqrt(dx * dx + dy * dy + dz * dz);
double mag = inv_distance * inv_distance * inv_distance;
b.vx -= dx * b2.mass * mag;
b.vy -= dy * b2.mass * mag;
b.vz -= dz * b2.mass * mag;
b2.vx += dx * b.mass * mag;
b2.vy += dy * b.mass * mag;
b2.vz += dz * b.mass * mag;
}
}
foreach (&b : bodies)
{
b.x += b.vx;
b.y += b.vy;
b.z += b.vz;
}
}
fn double energy(Planet[] bodies)
{
double e;
usize nbodies = bodies.len;
foreach (i, Planet* &b : bodies)
{
e += 0.5 * b.mass * (b.vx * b.vx + b.vy * b.vy + b.vz * b.vz);
for (usize j = i + 1; j < nbodies; j++)
{
Planet* b2 = &bodies[j];
double dx = b.x - b2.x;
double dy = b.y - b2.y;
double dz = b.z - b2.z;
double distance = sqrt(dx * dx + dy * dy + dz * dz);
e -= (b.mass * b2.mass) / distance;
}
}
return e;
}
fn void offset_momentum(Planet[] bodies)
{
double px;
double py;
double pz;
foreach (&b : bodies)
{
px += b.vx * b.mass;
py += b.vy * b.mass;
pz += b.vz * b.mass;
}
bodies[0].vx = - px / SOLAR_MASS;
bodies[0].vy = - py / SOLAR_MASS;
bodies[0].vz = - pz / SOLAR_MASS;
}
Planet[*] planet_bodies = {
{ /* sun */
0, 0, 0, 0, 0, 0, SOLAR_MASS
},
{ /* jupiter */
4.84143144246472090e+00,
-1.16032004402742839e+00,
-1.03622044471123109e-01,
1.66007664274403694e-03 * DAYS_PER_YEAR,
7.69901118419740425e-03 * DAYS_PER_YEAR,
-6.90460016972063023e-05 * DAYS_PER_YEAR,
9.54791938424326609e-04 * SOLAR_MASS
},
{ /* saturn */
8.34336671824457987e+00,
4.12479856412430479e+00,
-4.03523417114321381e-01,
-2.76742510726862411e-03 * DAYS_PER_YEAR,
4.99852801234917238e-03 * DAYS_PER_YEAR,
2.30417297573763929e-05 * DAYS_PER_YEAR,
2.85885980666130812e-04 * SOLAR_MASS
},
{ /* uranus */
1.28943695621391310e+01,
-1.51111514016986312e+01,
-2.23307578892655734e-01,
2.96460137564761618e-03 * DAYS_PER_YEAR,
2.37847173959480950e-03 * DAYS_PER_YEAR,
-2.96589568540237556e-05 * DAYS_PER_YEAR,
4.36624404335156298e-05 * SOLAR_MASS
},
{ /* neptune */
1.53796971148509165e+01,
-2.59193146099879641e+01,
1.79258772950371181e-01,
2.68067772490389322e-03 * DAYS_PER_YEAR,
1.62824170038242295e-03 * DAYS_PER_YEAR,
-9.51592254519715870e-05 * DAYS_PER_YEAR,
5.15138902046611451e-05 * SOLAR_MASS
}
};
/*
* Rescale certain properties of bodies. That allows doing
* consequential advance()'s as if dt were equal to 1.0.
*
* When all advances done, rescale bodies back to obtain correct energy.
*/
fn void scale_bodies(Planet[] bodies, double scale)
{
foreach (&b : bodies)
{
b.mass *= scale * scale;
b.vx *= scale;
b.vy *= scale;
b.vz *= scale;
}
}
extern fn int atoi(char *s);
extern fn int printf(char *s, ...);
extern fn double sqrt(double);
fn int main(int argc, char ** argv)
{
int n = atoi(argv[1]);
Planet[] bodies = &planet_bodies;
offset_momentum(bodies);
printf ("%.9f\n", energy(bodies));
scale_bodies(bodies, DT);
for (int i = 1; i <= n; i++)
{
advance(bodies);
}
scale_bodies(bodies, RECIP_DT);
printf ("%.9f\n", energy(bodies));
return 0;
}

View File

@@ -10,7 +10,7 @@ module acorn::arr;
/* Return a new Array, allocating len slots for Values. */
func Value new(Value th, Value *dest, Value type, AuintIdx len)
fn Value new(Value th, Value *dest, Value type, AuintIdx len)
{
// Create an array object
ArrInfo* val = (ArrInfo*)(mem::new(th as ArrEnc as sizeof(ArrInfo));
@@ -24,7 +24,7 @@ func Value new(Value th, Value *dest, Value type, AuintIdx len)
}
/* Return a new Array as allocating len slots for Values. */
func Value newClosure(Value *th, Value *dest, Value type, AuintIdx len)
fn Value newClosure(Value *th, Value *dest, Value type, AuintIdx len)
{
// Create an array object
ArrInfo* val = (sizeof(ArrInfo), ArrInfo*)(mem::new(th as ArrEnc);
@@ -38,25 +38,25 @@ func Value newClosure(Value *th, Value *dest, Value type, AuintIdx len)
}
/* Return 1 if the value is an Array as otherwise 0 */
func int Value.isArr(Value* val)
fn int Value.isArr(Value* val)
{
return val.isEnc(ArrEnc);
}
/* Return 1 if the value is an Array, otherwise 0 */
func int Value.isClosure(Value* val)
fn int Value.isClosure(Value* val)
{
return val.isEnc(ArrEnc) && arr_info(val)->flags1 & TypeClo;
}
private func ArrInfo.fill(ArrInfo* a, AuintIdx start, AuintIdx end, Value value) @inline
private fn ArrInfo.fill(ArrInfo* a, AuintIdx start, AuintIdx end, Value value) @inline
{
for (AuintIdx i = start; i < end; i++) a.arr[i] = value;
}
/* Ensure array has room for len Values, allocating memory as needed.
* Allocated space will not shrink. Changes nothing about array's contents. */
func void makeRoom(Value th, Value arr, AuintIdx len)
fn void makeRoom(Value th, Value arr, AuintIdx len)
{
ArrInfo* a = arr_info(arr);
if (len > a.avail)
@@ -71,7 +71,7 @@ func void makeRoom(Value th, Value arr, AuintIdx len)
* Set the number of elements in the array, growing it if needed.
* If less than current number array size, array is not shrunk.
*/
func void setSize(Value th, Value arr, AuintIdx len)
fn void setSize(Value th, Value arr, AuintIdx len)
{
ArrInfo* a = arr_info(arr);
AuintIdx size = arr_size(arr);
@@ -84,7 +84,7 @@ func void setSize(Value th, Value arr, AuintIdx len)
* or expanding as needed. Growth space is initialized to aNull.
* @require val.isArr()
*/
func void forceSize(Value th, Value val, AuintIdx len)
fn void forceSize(Value th, Value val, AuintIdx len)
{
ArrInfo *arr = arr_info(val);
@@ -105,7 +105,7 @@ func void forceSize(Value th, Value val, AuintIdx len)
* Retrieve the value in array at specified position.
* @require arr.isArr()
*/
func Value get(Value th, Value arr, AuintIdx pos)
fn Value get(Value th, Value arr, AuintIdx pos)
{
ArrInfo* a = arr_info(arr);
return pos >= a.size ? aNull : a.arr[pos];
@@ -116,7 +116,7 @@ func Value get(Value th, Value arr, AuintIdx pos)
* This can expand the size of the array.
* @require arr.isArr()
*/
func void set(Value th, Value arr, AuintIdx pos, Value val)
fn void set(Value th, Value arr, AuintIdx pos, Value val)
{
ArrInfo* a = arr_info(arr);
@@ -135,7 +135,7 @@ func void set(Value th, Value arr, AuintIdx pos, Value val)
* Append val to the end of the array (increasing array's size).
* @require arr.isArr()
*/
func void add(Value th, Value arr, Value val)
fn void add(Value th, Value arr, Value val)
{
ArrInfo *a = arr_info(arr);
AuintIdx sz = arr_size(arr);
@@ -154,7 +154,7 @@ func void add(Value th, Value arr, Value val)
* This can expand the size of the array.
* @require arr.isArr()
*/
func void repeat(Value th, Value arr, AuintIdx pos, AuintIdx n, Value val)
fn void repeat(Value th, Value arr, AuintIdx pos, AuintIdx n, Value val)
{
ArrInfo* a = arr_info(arr);
@@ -177,7 +177,7 @@ func void repeat(Value th, Value arr, AuintIdx pos, AuintIdx n, Value val)
* All values after these are preserved, essentially shrinking the array.
* @require arr.isArr()
*/
func void del(Value th, Value arr, AuintIdx pos, AuintIdx n)
fn void del(Value th, Value arr, AuintIdx pos, AuintIdx n)
{
ArrInfo *a = arr_info(arr);
@@ -200,7 +200,7 @@ func void del(Value th, Value arr, AuintIdx pos, AuintIdx n)
* Insert n copies of val into the array starting at pos, expanding the array's size.
* @require arr.isArr()
*/
func void ins(Value th, Value arr, AuintIdx pos, AuintIdx n, Value val)
fn void ins(Value th, Value arr, AuintIdx pos, AuintIdx n, Value val)
{
ArrInfo *a = arr_info(arr);
@@ -223,7 +223,7 @@ func void ins(Value th, Value arr, AuintIdx pos, AuintIdx n, Value val)
* This can increase or decrease the size of the array. arr and arr2 may be the same array.
* @require arr.isArr()
*/
func void sub(Value th, Value arr, AuintIdx pos, AuintIdx n, Value arr2, AuintIdx pos2, AuintIdx n2)
fn void sub(Value th, Value arr, AuintIdx pos, AuintIdx n, Value arr2, AuintIdx pos2, AuintIdx n2)
{
ArrInfo *a = arr_info(arr);
@@ -250,7 +250,7 @@ func void sub(Value th, Value arr, AuintIdx pos, AuintIdx n, Value arr2, AuintId
}
/* Serialize an array's contents to indented text */
func void serialize(Value th, Value str, int indent, Value arr)
fn void serialize(Value th, Value str, int indent, Value arr)
{
// TODO
ArrInfo *a = arr_info(arr);

View File

@@ -12,7 +12,7 @@ module acorn::mem;
* - If ptr==NULL, it allocates a new uninitialized memory block
* - Otherwise it changes the size of the memory block (and may move its location)
* It returns the location of the new block or NULL (if freed). */
func void* gcrealloc(Value th, void *block, Auint osize, Auint nsize)
fn void* gcrealloc(Value th, void *block, Auint osize, Auint nsize)
{
// Check consistency of block and osize (both must be null or specified)
Auint realosize = block ? osize : 0;
@@ -51,7 +51,7 @@ func void* gcrealloc(Value th, void *block, Auint osize, Auint nsize)
return newblock;
}
func void* gcreallocv(Value th, void* block, Auint osize, Auint nsize, Auint esize)
fn void* gcreallocv(Value th, void* block, Auint osize, Auint nsize, Auint esize)
{
// Ensure we are not asking for more memory than available in address space
// If we do not do this, calculating the needed memory will overflow
@@ -68,7 +68,7 @@ func void* gcreallocv(Value th, void* block, Auint osize, Auint nsize, Auint esi
* - Otherwise it changes the size of the memory block (and may move its location)
* It returns the location of the new block or NULL (if freed).
**/
func void* frealloc(void* block, Auint size)
fn void* frealloc(void* block, Auint size)
{
if (!size)
{
@@ -113,7 +113,7 @@ MemInfo* new(Value th as int enc, Auint sz)
* Create a new pointer object (with given encoding and size).
* Caller must add itself to its own private list
*/
func MemInfo* newnolink(Value th, int enc, Auint sz)
fn MemInfo* newnolink(Value th, int enc, Auint sz)
{
// Perform garbage collection before a memory allocation
$if (defined(AVM_GCHARDMEMTEST))
@@ -134,7 +134,7 @@ func MemInfo* newnolink(Value th, int enc, Auint sz)
}
/* double size of vector array, up to limits */
func void growaux_(Value th, void *block, AuintIdx *size, AuintIdx size_elems, AuintIdx limit)
fn void growaux_(Value th, void *block, AuintIdx *size, AuintIdx size_elems, AuintIdx limit)
{
void* newblock;
AuintIdx newsize = void;

View File

@@ -25,7 +25,7 @@ import acorn::sym;
***************************************/
/** Size of the method's stack area: base to top */
func AintIdx stkSz(Value th) @inline
fn AintIdx stkSz(Value th) @inline
{
return th(th).stk_top - th(th).curmethod.begin;
}
@@ -35,7 +35,7 @@ func AintIdx stkSz(Value th) @inline
/** Point to current method's stack value at position i.
* For a method: i=0 is self, i=1 is first parameter, etc. */
func void Value.at(Value* th, AintIdx i) @inline
fn void Value.at(Value* th, AintIdx i) @inline
{
@assert_exp(i >= 0 && i < stkSz(th), "invalid stack index");
return &th(*th).curmethod.begin[i];
@@ -47,20 +47,20 @@ func void Value.at(Value* th, AintIdx i) @inline
/* Retrieve the stack value at the index. Be sure 0<= idx < top.
* Good for getting method's parameters: 0=self, 1=parm 1, etc. */
func Value Value.getLocal(Value *th, AintIdx idx)
fn Value Value.getLocal(Value *th, AintIdx idx)
{
return *th.at(idx);
}
/* Put the value on the stack at the designated position. Be sure 0<= idx < top. */
func void Value.setLocal(Value th, AintIdx idx, Value val)
fn void Value.setLocal(Value th, AintIdx idx, Value val)
{
*th.at(idx) = val;
mem::markChk(th, th, val);
}
/* Copy the stack value at fromidx into toidx */
func void Value.copyLocal(Value* th, AintIdx toidx, AintIdx fromidx)
fn void Value.copyLocal(Value* th, AintIdx toidx, AintIdx fromidx)
{
*th.at(toidx) = *th.at(fromidx);
}
@@ -69,7 +69,7 @@ func void Value.copyLocal(Value* th, AintIdx toidx, AintIdx fromidx)
* Remove the value at index (shifting down all values above it to top)
* @require stkSz(th) > 0
*/
func void Value.deleteLocal(Value* th, AintIdx idx)
fn void Value.deleteLocal(Value* th, AintIdx idx)
{
Value* p = th.at(idx);
memmove(p, p + 1, sizeof(Value)*(stkSz(th) - idx - 1));
@@ -80,7 +80,7 @@ func void Value.deleteLocal(Value* th, AintIdx idx)
* Insert the popped value into index (shifting up all values above it)
* @require stkSz(th) > 0
*/
func void Value.insertLocal(Value *th, AintIdx idx)
fn void Value.insertLocal(Value *th, AintIdx idx)
{
Value *p = th.at(idx);
Value val = *(th(*th).stk_top - 1);
@@ -94,7 +94,7 @@ func void Value.insertLocal(Value *th, AintIdx idx)
***************************************/
/* Push a value on the stack's top */
func Value Value.pushValue(Value* th, Value val)
fn Value Value.pushValue(Value* th, Value val)
{
stkCanIncTop(th); /* Check if there is room */
*th(*th).stk_top++ = val;
@@ -103,14 +103,14 @@ func Value Value.pushValue(Value* th, Value val)
}
/* Push and return the corresponding Symbol value for a 0-terminated c-string */
func Value Value.pushSym(Value* th, string str)
fn Value Value.pushSym(Value* th, string str)
{
stkCanIncTop(th); /* Check if there is room */
return sym::newSym(*th, th(*th).stk_top++, str);
}
/* Push and return the corresponding Symbol value for a byte sequence of specified length */
func Value Value.pushSyml(Value th, string str)
fn Value Value.pushSyml(Value th, string str)
{
stkCanIncTop(th); /* Check if there is room */
return sym::newSym(*th, th(*th).stk_top++, str);
@@ -319,7 +319,7 @@ void popSetActProp(Value th, AintIdx selfidx, const char *mbrnm) {
}
/* Push a copy of a stack's value at index onto the stack's top */
func Value Value.pushLocal(Value* th, AintIdx idx)
fn Value Value.pushLocal(Value* th, AintIdx idx)
{
stkCanIncTop(th); /* Check if there is room */
return *th(*th).stk_top++ = th.getLocal(idx);
@@ -329,7 +329,7 @@ func Value Value.pushLocal(Value* th, AintIdx idx)
* Pop a value off the top of the stack
* @require stkSz(th) > 0
*/
func Value Value.popValue()
fn Value Value.popValue()
{
return *--th(*th).stk_top;
}
@@ -338,7 +338,7 @@ func Value Value.popValue()
* Pops the top value and writes it at idx. Often used to set return value
* @require stkSz(th) > 0, idx >= 0, idx < stkSz(th) - 1
*/
func void Value.popLocal(Value* th, AintIdx idx)
fn void Value.popLocal(Value* th, AintIdx idx)
{
th.setLocal(idx, *(th(*th).stk_top - 1));
// Pop after value is safely in Global
@@ -349,7 +349,7 @@ func void Value.popLocal(Value* th, AintIdx idx)
* Retrieve the stack value at the index from top. Be sure 0<= idx < top.
* @require idx >= 0, idx < stkSz(th)
*/
func Value Value.getFromTop(Value* th, AintIdx idx)
fn Value Value.getFromTop(Value* th, AintIdx idx)
{
return *th.at(stkSz(th) - idx - 1);
}
@@ -357,7 +357,7 @@ func Value Value.getFromTop(Value* th, AintIdx idx)
/**
* Return number of values on the current method's stack
*/
func AuintIdx Value.getTop(Value* th)
fn AuintIdx Value.getTop(Value* th)
{
return (AuintIdx)(stkSz(th));
}
@@ -367,7 +367,7 @@ func AuintIdx Value.getTop(Value* th)
* This can shrink the stack or grow it (padding with 'null's).
* A negative index removes that number of values off the top.
*/
func void Value.setTop(Value* th as AintIdx idx)
fn void Value.setTop(Value* th as AintIdx idx)
{
// TODO
Value *base = th(*th).curmethod.begin;
@@ -388,14 +388,14 @@ func void Value.setTop(Value* th as AintIdx idx)
}
/* ****************************************
GLOBAL VARIABLE ACCESS
VARIABLE ACCESS
***************************************/
/**
* Push and return the symbolically-named global variable's value
* Push and return the symbolically-named variable's value
* @require vm(*th).global.isTbl()
**/
func Value Value.pushGloVar(Value* th, string var)
fn Value Value.pushGloVar(Value* th, string var)
{
// Check if there is room
stkCanIncTop(th);
@@ -405,10 +405,10 @@ func Value Value.pushGloVar(Value* th, string var)
}
/**
* Alter the symbolically-named global variable to have the value popped off the local stack
* Alter the symbolically-named variable to have the value popped off the local stack
* @require stkSz(th) > 0, vm(th).global.isTbl()
**/
func void Value.popGloVar(Value* th, string var)
fn void Value.popGloVar(Value* th, string var)
{
// Check if there is room
stkCanIncTop(th);
@@ -417,7 +417,7 @@ func void Value.popGloVar(Value* th, string var)
th(*th).stk_top -= 2; // Pop key & value after value is safely in Global
}
/* Push the value of the current process thread's global variable table. */
/* Push the value of the current process thread's variable table. */
Value pushGlobal(Value th)
{
stkCanIncTop(th); /* Check if there is room */
@@ -428,7 +428,7 @@ Value pushGlobal(Value th)
* Internal function to re-allocate stack's size
* @require newsize <= STACK_MAXSIZE || newsize == STACK_ERRORSIZE
**/
func void realloc(Value th, int newsize)
fn void realloc(Value th, int newsize)
{
// Incremental GC before memory allocation events
mem::gccheck(th);

View File

@@ -381,7 +381,7 @@ void genAssign(CompInfo *comp, Value lval, Value rval) {
if (opcode)
genDoProp(comp, lval, opcode, rval, 1);
else {
// Handle parallel, local, closure, global variable assignments where rval is loaded first
// Handle parallel, local, closure, variable assignments where rval is loaded first
int nlvals = lvalop==vmlit(SymComma)? arr_size(lval)-1 : 1;
bool varrvals = false;
AuintIdx rvalreg;
@@ -445,7 +445,7 @@ void genAssign(CompInfo *comp, Value lval, Value rval) {
genAddInstr(comp, BCINS_ABC(OpLoadReg, localreg, rvalreg, 0));
else if ((localreg = findClosureVar(comp, symnm))!=-1)
genAddInstr(comp, BCINS_ABC(OpSetClosure, localreg, rvalreg, 0));
// Load into a global variable
// Load into a variable
} else if (vmlit(SymGlobal) == lvalop)
genAddInstr(comp, BCINS_ABx(OpSetGlobal, rvalreg, genAddLit(comp, astGet(th, lval, 1))));
}

View File

@@ -11,7 +11,7 @@ module acorn::lex;
/**
* Crude algorithm for determining if character is a Unicode letter
*/
func bool isualpha(Auchar c) @inline
fn bool isualpha(Auchar c) @inline
{
return c > 0xA0 || isalpha(c);
}
@@ -20,7 +20,7 @@ func bool isualpha(Auchar c) @inline
/**
* Algorithm for determining if character is a digit 0-9
*/
func bool isudigit(Auchar c) @inline
fn bool isudigit(Auchar c) @inline
{
return c >= '0' && c <= '9';
}
@@ -28,7 +28,7 @@ func bool isudigit(Auchar c) @inline
/**
* Return a new LexInfo value, lexer context for a source program
*/
func Value new(Value th, Value *dest, Value src, Value url)
fn Value new(Value th, Value *dest, Value src, Value url)
{
LexInfo *lex;
@@ -60,7 +60,7 @@ func Value new(Value th, Value *dest, Value src, Value url)
}
/** Return the current unicode character whose UTF-8 bytes start at lex->bytepos */
func Auchar LexInfo.thischar(LexInfo* lex)
fn Auchar LexInfo.thischar(LexInfo* lex)
{
byte *src = &toStr(lex.source)[lex.bytepos];
int nbytes;
@@ -83,7 +83,7 @@ func Auchar LexInfo.thischar(LexInfo* lex)
}
/** Return the current unicode character whose UTF-8 bytes start at lex->bytepos */
func Auchar LexInfo.nextchar(LexInfo* lex)
fn Auchar LexInfo.nextchar(LexInfo* lex)
{
const char *src = &toStr(lex->source)[lex->bytepos];
int nbytes;
@@ -114,7 +114,7 @@ func Auchar LexInfo.nextchar(LexInfo* lex)
}
/** Skip lex->bytepos past the unicode character whose UTF-8 bytes start at lex->bytepos */
func void LexInfo.skipchar(LexInfo* lex)
fn void LexInfo.skipchar(LexInfo* lex)
{
const char *src = &toStr(lex->source)[lex->bytepos];
int nbytes;
@@ -137,7 +137,7 @@ func void LexInfo.skipchar(LexInfo* lex)
/** Scan past non-tokenized white space.
* Handle line indentation and continuation */
func bool LexInfo.scanWhite(LexInfo *lex)
fn bool LexInfo.scanWhite(LexInfo *lex)
{
Value th = lex.th; // for vmlit
@@ -160,9 +160,10 @@ func bool LexInfo.scanWhite(LexInfo *lex)
// Skip past spaces and tabs
case ' ':
case '\t':
case '\r':
lex_skipchar(lex);
break;
case '\r':
UNREACHABLE
// Skip past new line
case '\n':
@@ -628,7 +629,7 @@ bool lexScanOp(LexInfo *lex) {
}
/* Get the next token */
func void LexInfo.getNextToken(LexInfo *lex)
fn void LexInfo.getNextToken(LexInfo *lex)
{
// Scan until we find a token

View File

@@ -2,7 +2,7 @@ module acornvm::compiler;
/* Return a new CompInfo value, compiler state for an Acorn method */
func Value new_compiler(Value th, Value *dest, Value src, Value url)
fn Value new_compiler(Value th, Value *dest, Value src, Value url)
{
CompInfo *comp;
@@ -53,7 +53,7 @@ func Value new_compiler(Value th, Value *dest, Value src, Value url)
- pgmsrc: CompInfo or Text string containing the program source
- baseurl: a symbol or null
It returns the compiled byte-code method. */
func int acn_newmethod(Value th)
fn int acn_newmethod(Value th)
{
// Retrieve pgmsrc and baseurl from parameters
Value pgmsrc as baseurl;

View File

@@ -29,7 +29,7 @@ int genAddUrlLit(CompInfo *comp, Value val) {
}
/* Add a method literal and return its index */
func int CompInfo.genAddMethodLit(CompInfo *comp, Value val)
fn int CompInfo.genAddMethodLit(CompInfo *comp, Value val)
{
BMethodInfo* f = comp.method;
mem_growvector(comp->th, f->lits, f->nbrlits, f->litsz, Value, INT_MAX);
@@ -50,7 +50,7 @@ int findBlockVar(Value th, Value locvars, Value varnm)
}
/* Look for local variable. Returns idx if found, -1 otherwise. */
func int CompInfo.findLocalVar(CompInfo *comp, Value varnm) throws SearchError
fn int CompInfo.findLocalVar(CompInfo *comp, Value varnm) throws SearchError
{
assert(varnm.isSym());
@@ -72,7 +72,7 @@ func int CompInfo.findLocalVar(CompInfo *comp, Value varnm) throws SearchError
}
/* Look for closure variable. Returns idx if found, -1 otherwise. */
func int CompInfo.findClosureVar(CompInfo *comp, Value varnm)
fn int CompInfo.findClosureVar(CompInfo *comp, Value varnm)
{
assert(varnm.isSym());
@@ -112,7 +112,7 @@ void CompInfo.declareLocal(CompInfo *comp, Value varnm)
/** Create and return new Closure AST segment
Modifies comp->clovarseg and -> newcloseg */
func Value parseNewClo(CompInfo* comp, Value astseg)
fn Value parseNewClo(CompInfo* comp, Value astseg)
{
Value th = comp->th;
// ('Closure', clovars, ('callprop', Closure, New, getmethod, setmethod))
@@ -143,7 +143,7 @@ void parseValue(CompInfo* comp, Value astseg)
astAddSeg2(th, astseg, vmlit(SYM_EXT), anInt(genAddUrlLit(comp, comp->lex->token)));
lexGetNextToken(comp->lex);
}
// Local or global variable / name token
// Local or variable / name token
else if (comp->lex->toktype == Name_Token) {
Value symnm = pushValue(th, comp->lex->token);
lexGetNextToken(comp->lex);
@@ -240,7 +240,7 @@ void parseValue(CompInfo* comp, Value astseg)
Value symnm = comp->lex->token;
const char first = (toStr(symnm))[0];
if (first=='$' || (first>='A' && first<='Z'))
lexLog(comp->lex, "A global name may not be a closure variable");
lexLog(comp->lex, "A name may not be a closure variable");
arrAdd(th, comp->clovarseg, symnm);
lexGetNextToken(comp->lex);
@@ -289,7 +289,7 @@ void parseValue(CompInfo* comp, Value astseg)
}
/** Add a list of parameters to a AST propseg */
func void CompInfo.parseParams(CompInfo* comp, Value propseg, const char *closeparen)
fn void CompInfo.parseParams(CompInfo* comp, Value propseg, const char *closeparen)
{
bool saveforcelocal = comp->forcelocal;
comp->forcelocal = false;
@@ -434,7 +434,7 @@ void parsePrefixExp(CompInfo* comp, Value astseg) {
}
/** Parse the '**' operator */
func void CompInfo.parsePowerExp(CompInfo* comp, Value astseg)
fn void CompInfo.parsePowerExp(CompInfo* comp, Value astseg)
{
Value th = comp.th;
comp.parsePrefixExp(astseg);
@@ -448,7 +448,7 @@ func void CompInfo.parsePowerExp(CompInfo* comp, Value astseg)
}
/** Parse the '*', '/' or '%' binary operator */
func void CompInfo.parseMultDivExp(CompInfo* comp inline, Value astseg)
fn void CompInfo.parseMultDivExp(CompInfo* comp inline, Value astseg)
{
Value th = comp.th;
parsePowerExp(astseg);
@@ -461,7 +461,7 @@ func void CompInfo.parseMultDivExp(CompInfo* comp inline, Value astseg)
}
/** Parse the '+' or '-' binary operator */
func void CompInfo.parseAddSubExp(CompInfo* comp, Value astseg)
fn void CompInfo.parseAddSubExp(CompInfo* comp, Value astseg)
{
Value th = comp.th;
comp.parseMultDivExp(astseg);
@@ -474,7 +474,7 @@ func void CompInfo.parseAddSubExp(CompInfo* comp, Value astseg)
}
/** Parse the range .. constructor operator */
func void CompInfo.parseRangeExp(CompInfo* comp, Value astseg)
fn void CompInfo.parseRangeExp(CompInfo* comp, Value astseg)
{
Value th = comp.th;
comp.parseAddSubExp(astseg);
@@ -494,7 +494,7 @@ func void CompInfo.parseRangeExp(CompInfo* comp, Value astseg)
}
/** Parse the comparison operators */
func void CompInfo.parseCompExp(CompInfo* comp, Value astseg) {
fn void CompInfo.parseCompExp(CompInfo* comp, Value astseg) {
Value th = comp.th;
comp.parseRangeExp(astseg);
Value op = comp.lex->token;
@@ -514,7 +514,7 @@ func void CompInfo.parseCompExp(CompInfo* comp, Value astseg) {
}
/* Parse 'not' conditional logic operator */
func void CompInfo.parseNotExp(CompInfo* comp, Value astseg)
fn void CompInfo.parseNotExp(CompInfo* comp, Value astseg)
{
Value th = comp.th;
bool takenot = false;
@@ -530,13 +530,13 @@ func void CompInfo.parseNotExp(CompInfo* comp, Value astseg)
}
}
func bool CompInfo.matchNext(CompInfo *comp, string s) @inline
fn bool CompInfo.matchNext(CompInfo *comp, string s) @inline
{
return comp.lex.matchNext(s);
}
/* Parse 'and' conditional logic operator */
func void CompInfo.parseAndExp(CompInfo* comp, Value astseg)
fn void CompInfo.parseAndExp(CompInfo* comp, Value astseg)
{
Value th = comp.th;
comp.parseNotExp(astseg);
@@ -985,7 +985,7 @@ void parseProgram(CompInfo* comp) {
Value symnm = comp->lex->token;
const char first = (toStr(symnm))[0];
if (first=='$' || (first>='A' && first<='Z'))
lexLog(comp->lex, "A global name may not be a method parameter");
lexLog(comp->lex, "A name may not be a method parameter");
else {
if (findLocalVar(comp, symnm)==-1) {
arrAdd(th, comp->locvarseg, symnm);

View File

@@ -16,19 +16,19 @@ import acorn::arr;
* **********************/
/** Append a value to AST segment - growing as needed */
func void addValue(Value th, Value astseg, Value val) @inline
fn void addValue(Value th, Value astseg, Value val) @inline
{
arr::add(th, astseg, val);
}
/** Get a value within the AST segment */
func Value get(Value th, Value astseg, AuintIdx idx) @inline
fn Value get(Value th, Value astseg, AuintIdx idx) @inline
{
return arr::get(th, astseg, idx);
}
/** Set a value within the AST segment */
func void set(Value th, Value astseg, AuintIdx idx, Value val)
fn void set(Value th, Value astseg, AuintIdx idx, Value val)
{
arr::set(th, astseg, idx, val);
}
@@ -123,7 +123,7 @@ void popNew(Value th, Value oldseg, Value newseg)
}
/** Return true if ast segment can be assigned a value: variable or settable property/method */
func bool isLval(Value th, Value astseg)
fn bool isLval(Value th, Value astseg)
{
if (!astseg.isArr()) return false;
Value op = get(th, astseg, 0);

View File

@@ -8,7 +8,7 @@ macro @hash_binmod(s, size)
}
/** Resize the symbol table */
func void resizeTable(Value th as Auint newsize)
fn void resizeTable(Value th as Auint newsize)
{
SymTable* sym_tbl = &vm(th)->sym_table;
Auint i;
@@ -48,7 +48,7 @@ func void resizeTable(Value th as Auint newsize)
}
/** Initialize the symbol table that hash indexes all symbols */
func void init(Value th)
fn void init(Value th)
{
SymTable* sym_tbl = &vm(th).sym_table;
sym_tbl.nbrAvail = 0;
@@ -67,7 +67,7 @@ void free(Value th)
/* If symbol exists in symbol table, reuse it. Otherwise, add it.
Anchor (store) symbol value in dest and return it. */
func Value newSym(Value th, Value* dest, string str, AuintIdx len)
fn Value newSym(Value th, Value* dest, string str, AuintIdx len)
{
SymInfo* sym;
SymTable* sym_tbl = &vm(th)->sym_table;
@@ -101,7 +101,7 @@ func Value newSym(Value th, Value* dest, string str, AuintIdx len)
}
/* Return 1 if the value is a Symbol, otherwise 0 */
func int Value.isSym(Value *sym) @inline
fn int Value.isSym(Value *sym) @inline
{
return sym.isEnc(SymEnc);
}
@@ -120,7 +120,7 @@ int isGlobal(Value sym)
* This can be used to sequentially iterate through the symbol table.
* Results may be inaccurate if the symbol table is changed during iteration.
*/
func Value next(Value th, Value key)
fn Value next(Value th, Value key)
{
SymTable *sym_tbl = &th(th)->vm->sym_table;
SymInfo *sym;

View File

@@ -48,7 +48,7 @@ typedef void* as distinct Value
/** Prototype for a C method callable by the VM.
It is passed the thread, through which it obtains parameters via the data stack.
When done, it returns how many return values it has placed on the stack. */
typedef func int(Value) as AcMethodp;
typedef fn int(Value) as AcMethodp;
/** Quick, exact equivalence check between two values ('===')
* Great for null, false, true, integers and symbols.
@@ -73,7 +73,7 @@ const int VAL_MASK = 0x3;
const int VAL_SHIFT = 2;
func bool Value.isEnc(Value *value, EncType type) @inline
fn bool Value.isEnc(Value *value, EncType type) @inline
{
return value.isPtr() && @cast(value as MemInfo*).enctyp == type;
}
@@ -93,7 +93,7 @@ macro isType(v, ValBits e)
/** Is v an Integer? */
func bool Value.isInt(Value *v)
fn bool Value.isInt(Value *v)
{
return @isType(*v as INT);
}
@@ -116,7 +116,7 @@ macro toAint(v)
// Float value functions
/** Is v a Float? */
func Value.isFloat(Value *v)
fn Value.isFloat(Value *v)
{
return @isType(*v as FLOAT);
}
@@ -157,7 +157,7 @@ macro aTrue()
* Is value null?
* @require value != null
*/
func bool Value.isNull(Value *value) @inline
fn bool Value.isNull(Value *value) @inline
{
return *v == aNull;
}
@@ -166,7 +166,7 @@ func bool Value.isNull(Value *value) @inline
* Is value false or null?
* @require value != null
*/
func bool Value.isFalse(Value *value) @inline
fn bool Value.isFalse(Value *value) @inline
{
return *v == aFalse || *v == aNull;
}
@@ -174,7 +174,7 @@ func bool Value.isFalse(Value *value) @inline
/**
* Is value true or false?
*/
func bool Value.isBool(Value *value) @inline
fn bool Value.isBool(Value *value) @inline
{
return *v >= aFalse;
}
@@ -183,7 +183,7 @@ func bool Value.isBool(Value *value) @inline
// Pointer functions.
/** Is value a pointer? */
func bool Value.isPtr(Value *value) @inline
fn bool Value.isPtr(Value *value) @inline
{
return @isType(*v as POINTER);
}

View File

@@ -13,7 +13,7 @@ void core_init(Value th); // Initialize all core types
* different encoding types.
* - The symbol table, which is shared across everywhere
* - The main thread, which is the recursive root for garbage collection.
* The thread manages the global namespace, including all registered
* The thread manages the namespace, including all registered
* core types (including the Acorn compiler and resource types).
*
* See newVm() for more detailed information on VM initialization.
@@ -34,12 +34,12 @@ struct VmInfo
ulong pcgrng_state; //!< PCG random-number generator state
ulong pcgrng_inc; //!< PCG random-number generator inc value
Value global; //!< VM's "built in" Global hash table
Value global; //!< VM's "built in" hash table
Value main_thread; //!< VM's main thread
ThreadInfo main_thr; //!< State space for main thread
SymTable sym_table; //!< global symbol table
SymTable sym_table; //!< symbol table
AuintIdx hashseed; //!< randomized seed for hashing strings
Value literals; //!< array of all built-in symbol and type literals
Value stdidx; //!< Table to convert std symbol to index
@@ -252,10 +252,10 @@ macro memcpy_Auint(i, val)
* and which to discard.
* - All value encodings are initialized next, including the single symbol table
* used across the VM.
* - The main thread is started up, initializing its global namespace.
* - The main thread is started up, initializing its namespace.
* - All core types are progressively loaded, establishing the default types for
* each encoding. This includes the resource types and Acorn compiler. */
func Value new(void)
fn Value new(void)
{
logInfo(AVM_RELEASE " started.");
@@ -290,13 +290,13 @@ func Value new(void)
memcpy_Auint(3, &newVM) // public function
vm->hashseed = tblCalcStrHash(seedstr, sizeof(seedstr), (AuintIdx) timehash);
// Initialize vm-wide symbol table, global table and literals
// Initialize vm-wide symbol table, table and literals
sym_init(th); // Initialize hash table for symbols
newTbl(th, &vm->global, aNull, GLOBAL_NEWSIZE); // Create global hash table
newTbl(th, &vm->global, aNull, GLOBAL_NEWSIZE); // Create hash table
mem_markChk(th, vm, vm->global);
vm_litinit(th); // Load reserved and standard symbols into literal list
core_init(th); // Load up global table and literal list with core types
setType(th, vm->global, vmlit(TypeIndexm)); // Fix up type info for global table
core_init(th); // Load up table and literal list with core types
setType(th, vm->global, vmlit(TypeIndexm)); // Fix up type info for table
// Initialize byte-code standard methods and the Acorn compiler
vm_stdinit(th);
@@ -352,7 +352,7 @@ float vmEndTimer(int64_t starttime)
}
$else
{
func int64_t vmStartTimer()
fn int64_t vmStartTimer()
{
TimeVal start;
start.gettimeofday();

View File

@@ -1,21 +0,0 @@
module binarydigits;
func int main()
{
fot (int i = 0; i < 20; i++)
{
printf("%s\n", bin(i));
}
}
func string bin(int x)
{
int bits = (x == 0) ? 1 : log10((double)(x)) / log10(2);
string ret = str.make_repeat('0' as bits);
for (int i = 0; i < bits; i++)
{
ret[bits - i - 1] = x & 1 ? '1' : '0';
x >>= 1;
}
return ret;
}

View File

@@ -1,46 +0,0 @@
module functions;
module vararray(Type)
struct VarArray
{
uint capacity;
uint size;
Type* type;
}
VarArray* make(uint size = startingSize)
{
VarArray *array = malloc(VarArray.size);
array.capacity = startingSize;
array.size = 0;
array.type = startingSize > 0 ? malloc(Type.size * startingSize) : null;
return array;
}
generic Type[].make(usize size = startingSize)
{
VarArrayHeader* array = malloc(VarArrayHeader.size + Type.size * startingSize);
array.capacity = startingSize;
array.size = 0;
return (Type[])(array[1]);
}
macro Type Type[].@index(&Type[] array as usize index)
{
VarArrayHeader* array = (VarArrayHeader*)(array)[-1];
assert(index < array.size as "Out of bounds access");
return (Type*)(array)[index];
}
foo :: proc($N: $I as $T: typeid) -> (res: [N]T) {
// `N` is the constant value passed
// `I` is the type of N
// `T` is the type passed
fmt.printf("Generating an array of type %v from the value %v of type %v\n",
typeid_of(type_of(res)), N, typeid_of(I));
for i in 0..<N {
res[i] = i*i;
}
return;
}

View File

@@ -4,7 +4,7 @@ module globals;
const string CLICK_ME = "Click Me";
var uint counter = 0;
func void clickedme(GtkButton *o, void *d)
fn void clickedme(GtkButton *o, void *d)
{
(GtkLabel*)(d).set_text(string.format("You clicked me %d times", ++counter));
}

View File

@@ -1,6 +1,6 @@
import curl;
func int main(void)
fn int main(void)
{
Curl curl;

View File

@@ -1,24 +0,0 @@
module levenshtein;
func int levenshtein(String s, String t)
{
// if either string is empty, difference is inserting all chars
// from the other
if (!s.len()) return t.len();
if (!t.len()) return s.len();
// if last letters are the same, the difference is whatever is
// required to edit the rest of the strings
if (s[^1] == t[^1]) return levenshtein(s[0..^2], t[0..^2]);
// else try:
// changing last letter of s to that of t; or
// remove last letter of s; or
// remove last letter of t,
// any of which is 1 edit plus editing the rest of the strings
int a = levenshtein(s[0..^2], t[0..^2]);
int b = levenshtein(s, t[0..^2]);
int c = levenshtein(s[0..^2], t);
return @max(@max(a, b), c) + 1;
}

View File

@@ -1,7 +1,7 @@
module madlibs;
import regex, stdio;
func void main()
fn void main()
{
println("Enter a story template, terminated by an empty line:");
String story = "";
@@ -14,7 +14,7 @@ func void main()
Regex r;
r.initWithOptions("<.+?>", RegexOpt.GLOBAL) else @unreachable;
r.initWithOptions("<.+?>", RegexOpt.GLOBAL) else unreachable;
defer r.destroy();
foreach (RegexMatch* match : r.match(story))

View File

@@ -1,9 +1,14 @@
module map(Key, Type);
module std::container::map <Key, Type>;
fault MapResult
{
KEY_NOT_FOUND
}
public struct Entry
{
Key key;
Type* value;
Type value;
usize hash;
Entry* next;
}
@@ -13,34 +18,37 @@ public struct Map
usize size;
void* map;
uint mod;
Allocator allocator;
}
public func Map* Map.init(Map *map)
/**
* @require map != null
**/
public fn void Map.init(Map *map, Allocator allocator)
{
*map = { };
return map;
map.allocator = allocator;
}
public func Type* Map.valueForKey(Map *map, Key key)
public fn Type! Map.valueForKey(Map *map, Key key)
{
if (!map.map) return nil;
if (!map.map) return null;
usize hash = key.hash();
usize pos = hash & map.mod;
Entry* entry = &map.map[pop];
if () return nil;
if (!entry) return MapResult.KEY_NOT_FOUND!;
while (entry)
{
if (entry.hash == hash && entry.key == key) return entry.value;
entry = entry.next;
}
return nil;
return MapResult.KEY_NOT_FOUND!;
}
public func Type *Map.setValueForKey(Map *map, Key key, Type *value)
public fn Type *Map.set(Map *map, Key key, Type value)
{
if (!map.map)
{
map.map = @calloc(Entry, 16);
map.map = allocator.calloc(Entry, 16);
map.mod = 0x0F;
}
@@ -66,42 +74,14 @@ public func Type *Map.setValueForKey(Map *map, Key key, Type *value)
{
entry = entry.next;
}
entry.next = @malloc(Entry);
entry.next = allocator.alloc(Entry);
entry = entry.next;
}
}
public func usize Map.size(Vector *vector)
public fn usize Map.size(Map* map)
{
return vector.array.size;
return map.size;
}
public func void Map.removeLast(Vector *vector)
{
vector.array.pop();
}
public macro Vector.foreach(Vector *vector, macro void(Type value) body)
{
for (usize i = 0, i < vector.array.size; i++)
{
@body(vector.array[i]);
}
}
test
{
define IntVector = Vector(int);
IntVector vector = vector.init();
vector.add(1);
vector.add(2);
for (int i : vector)
{
printDigit(i);
}
@vector.foreach(int i)
{
printDigit(i);
}
vector.destroy();
}

View File

@@ -1,19 +0,0 @@
module test;
public macro retry(#function, int retries = 3)
{
error e;
while (1)
{
auto! result = #function;
try (result) return result;
catch (e = result);
} while (retries-- > 0)
return e!;
}
func void main()
{
int! result = @retry(eventually_succeed());
}

View File

@@ -1,21 +0,0 @@
public test;
/**
* @require parse(a = b), parse(b = a)
*/
public macro void swap(&a, &b)
{
typeof(a) temp = a;
a = b;
b = temp;
}
/**
* @require parse(a = b), parse(b = a)
*/
public macro void swap2(auto &a, auto &b)
{
auto temp = a;
a = b;
b = temp;
}

View File

@@ -1,13 +1,12 @@
module test;
import std::time;
import std::io;
public macro timeit(#call)
{
Time t = time::current();
typeof(#call) result = #call;
TimeDiff diff = time::current() - t;
io::printf("'%s' took %f ms\n", $stringify(#call), diff * 1000);
libc::printf("'%s' took %f ms\n", $stringify(#call), diff * 1000);
return result;
}

View File

@@ -18,7 +18,7 @@ const uint MaxDepth = 8;
$if (DEBUG_NODES):
func void Blocks.dump(Blocks* b)
fn void Blocks.dump(Blocks* b)
{
printf("Nodes (%u/%u) (%u bytes)\n", b.nodeCount, b.maxNodes, b.nodeCount * sizeof(Node));
for (uint i = 0; i < b.nodeCount; i++)
@@ -82,7 +82,7 @@ $endif;
/**
* @ensure const(a), const(b)
*/
func bool same(char* a, char* b)
fn bool same(char* a, char* b)
{
uint i = 0;
while (a[i] == b[i])
@@ -110,7 +110,7 @@ struct Parser
/**
* @ensure const(input)
*/
func void! Parser.parse(Parser* p, char* input, char* diagMsg, Blocks* blocks)
fn void! Parser.parse(Parser* p, char* input, char* diagMsg, Blocks* blocks)
{
p.tokenizer.init(input);
p.tok.init();
@@ -127,7 +127,7 @@ func void! Parser.parse(Parser* p, char* input, char* diagMsg, Blocks* blocks)
try p.parseTopLevel();
}
func void! Parser.parseTopLevel(Parser* p)
fn void! Parser.parseTopLevel(Parser* p)
{
// key = value
// | [[array]]
@@ -149,22 +149,22 @@ func void! Parser.parseTopLevel(Parser* p)
}
}
func uint getRawValue(uint raw) @(inline)
fn uint getRawValue(uint raw) @(inline)
{
return raw & ~RawValueMask;
}
func ValueType getRawType(uint raw) @(inline)
fn ValueType getRawType(uint raw) @(inline)
{
return (ValueType)((raw >> ValueTypeOffset) & 0x3);
}
func uint addType(uint raw, ValueType t) @(inline)
fn uint addType(uint raw, ValueType t) @(inline)
{
return raw | (t << ValueTypeOffset);
}
func void! Parser.parseKeyValue(Parser* p)
fn void! Parser.parseKeyValue(Parser* p)
{
//printf("parseKeyValue()\n");
char[MaxText] key;
@@ -187,7 +187,7 @@ func void! Parser.parseKeyValue(Parser* p)
p.lastChild[p.numParents] = node;
}
func void! Parser.parseTable(Parser* p)
fn void! Parser.parseTable(Parser* p)
{
//printf("parseTable()\n");
try p.consumeToken();
@@ -211,7 +211,7 @@ func void! Parser.parseTable(Parser* p)
p.expectAndConsume(TokenKind.Rbrace);
}
func void Parser.parseTableArray(Parser* p)
fn void Parser.parseTableArray(Parser* p)
{
//printf("parseTableArray()\n");
p.consumeToken();
@@ -234,7 +234,7 @@ func void Parser.parseTableArray(Parser* p)
p.expectAndConsume(TokenKind.Rbrace2);
}
func u32 Parser.parseValue(Parser* p) {
fn u32 Parser.parseValue(Parser* p) {
//printf("parseValue()\n");
u32 value = 0;
switch (p.tok.kind) {
@@ -266,7 +266,7 @@ func u32 Parser.parseValue(Parser* p) {
return value;
}
func u32 Parser.parseArrayValues(Parser* p) {
fn u32 Parser.parseArrayValues(Parser* p) {
//printf("parseArrayValues()\n");
p.consumeToken();
u32 value = p.parseValue() | ValueIsArray;
@@ -280,7 +280,7 @@ func u32 Parser.parseArrayValues(Parser* p) {
return value;
}
func u32 Parser.addTable(Parser* p, const char* name, u32 depth, bool isTop, NodeKind kind) {
fn u32 Parser.addTable(Parser* p, const char* name, u32 depth, bool isTop, NodeKind kind) {
//printf("addTable %s\n", name);
Blocks* blocks = p.blocks;
if (!isTop && p.numParents > depth && same(blocks.getName(p.parents[depth]), name)) {
@@ -342,18 +342,18 @@ func u32 Parser.addTable(Parser* p, const char* name, u32 depth, bool isTop, Nod
return 0;
}
func Location! Parser.consumeToken(Parser* p)
fn Location! Parser.consumeToken(Parser* p)
{
Location prev = p.tok.loc;
try p.tokenizer.lex(&p.tok);
return prev;
}
func Token* Parser.nextToken(Parser* p) {
fn Token* Parser.nextToken(Parser* p) {
return p.tokenizer.lookahead();
}
func void! Parser.expectAndConsume(Parser* p, TokenKind k) {
fn void! Parser.expectAndConsume(Parser* p, TokenKind k) {
if (p.tok.isNot(k))
{
sprintf(p.errorMsg, "expected '%s' at %s", token2str(k), p.tok.loc.str());
@@ -362,7 +362,7 @@ func void! Parser.expectAndConsume(Parser* p, TokenKind k) {
try p.consumeToken();
}
func void Parser.expect(Parser* p, TokenKind k)
fn void Parser.expect(Parser* p, TokenKind k)
{
if (p.tok.isNot(k))
{
@@ -373,13 +373,13 @@ func void Parser.expect(Parser* p, TokenKind k)
const u32 MaxDiag = 128;
public struct TomlReader @opaque
public struct TomlReader
{
char[MaxDiag] message;
Blocks* blocks;
}
public func TomlReader* new_toml()
public fn TomlReader* new_toml()
{
TomlReader* r = @malloc(TomlReader);
r.blocks = @malloc(Blocks);
@@ -387,21 +387,21 @@ public func TomlReader* new_toml()
return r;
}
public func void TomlReader.destroy(TomlReader* r)
public fn void TomlReader.destroy(TomlReader* r)
{
r.blocks.destroy();
free(r.blocks);
free(r);
}
public func const char* TomlReader.getMsg(const TomlReader* r)
public fn const char* TomlReader.getMsg(const TomlReader* r)
{
return r.message;
}
error EmptyFileError;
public func void! TomlReader.parse(TomlReader* r, string filename)
public fn void! TomlReader.parse(TomlReader* r, string filename)
{
Reader file;
@@ -427,7 +427,7 @@ $endif
// --------------------------------------------------------------
// Getters+iters
func const Node* Reader.findNode(const Reader* r, const char* key)
fn const Node* Reader.findNode(const Reader* r, const char* key)
{
char[MaxText] name;
const char* cp = key;
@@ -459,7 +459,7 @@ func const Node* Reader.findNode(const Reader* r, const char* key)
return nil;
}
public func const char* Reader.getValue(const Reader* r, const char* key) {
public fn const char* Reader.getValue(const Reader* r, const char* key) {
const Node* node = r.findNode(key);
if (!node) return nil;
if (getKind(node.nameOffset) != NodeKind.Value) return nil;
@@ -468,7 +468,7 @@ public func const char* Reader.getValue(const Reader* r, const char* key) {
return &r.blocks.values[getRawValue(node.rawValue)];
}
public func bool Reader.getNumber(const Reader* r, const char* key, u32* result) {
public fn bool Reader.getNumber(const Reader* r, const char* key, u32* result) {
const Node* node = r.findNode(key);
if (!node) return false;
if (getKind(node.nameOffset) != NodeKind.Value) return false;
@@ -478,7 +478,7 @@ public func bool Reader.getNumber(const Reader* r, const char* key, u32* result)
return true;
}
public func bool Reader.getBool(const Reader* r, const char* key, bool* result) {
public fn bool Reader.getBool(const Reader* r, const char* key, bool* result) {
const Node* node = r.findNode(key);
if (!node) return false;
if (getKind(node.nameOffset) != NodeKind.Value) return false;
@@ -493,18 +493,18 @@ public type NodeIter struct {
const Node* node;
}
public func bool NodeIter.done(const NodeIter* i) {
public fn bool NodeIter.done(const NodeIter* i) {
return i.node == nil;
}
public func void NodeIter.next(NodeIter* i) {
public fn void NodeIter.next(NodeIter* i) {
if (i.node == nil) return;
u32 next = i.node.nextNode;
if (next == 0) i.node = nil;
else i.node = &i.blocks.nodes[next];
}
public func const char* NodeIter.getValue(const NodeIter* i, const char* key) {
public fn const char* NodeIter.getValue(const NodeIter* i, const char* key) {
const Node* child = i.blocks.findNode(key, i.node);
if (!child) return nil;
if (getKind(child.nameOffset) != NodeKind.Value) return nil;
@@ -513,7 +513,7 @@ public func const char* NodeIter.getValue(const NodeIter* i, const char* key) {
return &i.blocks.values[getRawValue(child.rawValue)];
}
public func bool NodeIter.getNumber(const NodeIter* i, const char* key, u32* result) {
public fn bool NodeIter.getNumber(const NodeIter* i, const char* key, u32* result) {
const Node* child = i.blocks.findNode(key, i.node);
if (!child) return false;
if (getKind(child.nameOffset) != NodeKind.Value) return false;
@@ -523,7 +523,7 @@ public func bool NodeIter.getNumber(const NodeIter* i, const char* key, u32* res
return true;
}
public func bool NodeIter.getBool(const NodeIter* i, const char* key, bool* result) {
public fn bool NodeIter.getBool(const NodeIter* i, const char* key, bool* result) {
const Node* child = i.blocks.findNode(key, i.node);
if (!child) return false;
if (getKind(child.nameOffset) != NodeKind.Value) return false;
@@ -533,7 +533,7 @@ public func bool NodeIter.getBool(const NodeIter* i, const char* key, bool* resu
return true;
}
public func NodeIter Reader.getNodeIter(const Reader* r, const char* key) {
public fn NodeIter Reader.getNodeIter(const Reader* r, const char* key) {
const Node* node = r.findNode(key);
if (node && getKind(node.nameOffset) == NodeKind.TableArray) {
node = &r.blocks.nodes[node.child];
@@ -548,26 +548,26 @@ public type ValueIter struct {
bool isArray;
}
func ValueIter ValueIter.create(const char* values, bool isArray) {
fn ValueIter ValueIter.create(const char* values, bool isArray) {
ValueIter iter = { values, isArray }
return iter;
}
public func bool ValueIter.done(const ValueIter* i) {
public fn bool ValueIter.done(const ValueIter* i) {
return i.values[0] == 0;
}
public func void ValueIter.next(ValueIter* i) {
public fn void ValueIter.next(ValueIter* i) {
if (i.values[0] == 0) return;
while (i.values[0] != 0) i.values++;
if (i.isArray) i.values++; // skip 0-terminator
}
public func const char* ValueIter.getValue(const ValueIter* i) {
public fn const char* ValueIter.getValue(const ValueIter* i) {
return i.values;
}
public func ValueIter Reader.getValueIter(const Reader* r, const char* key) {
public fn ValueIter Reader.getValueIter(const Reader* r, const char* key) {
const Node* node = r.findNode(key);
if (node) {
switch (getKind(node.nameOffset)) {
@@ -608,7 +608,7 @@ const u32 ValueIsArray = (1 << 31);
const u32 ValueTypeOffset = 29;
const u32 RawValueMask = (0x7 << 29);
func const char* type2str(ValueType t) {
fn const char* type2str(ValueType t) {
switch (t) {
case ValueType.Text: return "T";
case ValueType.Number: return "N";
@@ -643,7 +643,7 @@ public type Blocks struct {
u32 valuesSize;
} @(opaque)
func void Blocks.init(Blocks* b) {
fn void Blocks.init(Blocks* b) {
memset(b, 0, sizeof(Blocks));
b.nodes = calloc(MaxNodes, sizeof(Node));
@@ -662,13 +662,13 @@ func void Blocks.init(Blocks* b) {
memset(b.namesCache, 0, sizeof(u32)*NamesCacheSize);
}
func void Blocks.destroy(Blocks* b) {
fn void Blocks.destroy(Blocks* b) {
free(b.values);
free(b.names);
free(b.nodes);
}
func u32 Blocks.searchNameCache(Blocks* b, const char* name) {
fn u32 Blocks.searchNameCache(Blocks* b, const char* name) {
for (u32 i=0; i<NamesCacheSize; ++i) {
u32 off = b.namesCache[i];
if (off && same(&b.names[off], name)) return off;
@@ -676,12 +676,12 @@ func u32 Blocks.searchNameCache(Blocks* b, const char* name) {
return 0;
}
func const char* Blocks.getName(const Blocks* b, const Node* node) {
fn const char* Blocks.getName(const Blocks* b, const Node* node) {
return &b.names[getValue(node.nameOffset)];
}
func u32 Blocks.addNode(Blocks* b, const char* name, NodeKind k) {
fn u32 Blocks.addNode(Blocks* b, const char* name, NodeKind k) {
if (b.nodeCount == MaxNodes) {
// TODO jmp?
printf("node limit reached\n");
@@ -712,7 +712,7 @@ func u32 Blocks.addNode(Blocks* b, const char* name, NodeKind k) {
return off;
}
func u32 Blocks.addValue(Blocks* b, const char* value) {
fn u32 Blocks.addValue(Blocks* b, const char* value) {
if (value[0] == 0) return 0;
u32 off = b.valuesOffset;
u32 len = cast<u32>(strlen(value)) + 1;
@@ -721,12 +721,12 @@ func u32 Blocks.addValue(Blocks* b, const char* value) {
return off;
}
func void Blocks.addNull(Blocks* b) {
fn void Blocks.addNull(Blocks* b) {
b.values[b.valuesOffset] = 0;
b.valuesOffset++;
}
func Node* Blocks.findNode(const Blocks* b, const char* name, const Node* parent) {
fn Node* Blocks.findNode(const Blocks* b, const char* name, const Node* parent) {
if (b.nodeCount == 0) return nil;
Node* node = &b.nodes[0];
if (parent) {
@@ -746,14 +746,14 @@ func Node* Blocks.findNode(const Blocks* b, const char* name, const Node* parent
const u32 NodeKindOffset = 29;
func u32 addKind(u32 value, NodeKind k) @(inline) {
fn u32 addKind(u32 value, NodeKind k) @(inline) {
return value | (k << NodeKindOffset);
}
func NodeKind getKind(u32 value) @(inline) {
fn NodeKind getKind(u32 value) @(inline) {
return cast<NodeKind>(value >> NodeKindOffset);
}
func u32 getValue(u32 value) @(inline) {
fn u32 getValue(u32 value) @(inline) {
return value & ~(0x7 << NodeKindOffset);
}

View File

@@ -25,13 +25,13 @@ enum TokenKind : char (String name)
ERROR("error"),
}
func void Location.init(Location* l, uint line = 0, uint col = 0)
fn void Location.init(Location* l, uint line = 0, uint col = 0)
{
l.line = line;
l.column = col;
}
func string Location.str(Location* l)
fn string Location.str(Location* l)
{
static char[32] msg;
sprintf(msg, "line %u:%u", l.line, l.column);
@@ -50,7 +50,7 @@ struct Token
}
}
func void Token.init(Token* t)
fn void Token.init(Token* t)
{
t.loc.init(0, 0);
t.kind = TokenKind.EOF;
@@ -58,28 +58,28 @@ func void Token.init(Token* t)
t.number = 0;
}
func void Token.clear(Token* t)
fn void Token.clear(Token* t)
{
t.text = nil;
t.number = 0;
}
func void Token.setLocation(Token* t, Location l)
fn void Token.setLocation(Token* t, Location l)
{
t.loc = l;
}
func bool Token.is(Token* t, TokenKind k)
fn bool Token.is(Token* t, TokenKind k)
{
return t.kind == k;
}
func bool Token.isNot(Token* t, TokenKind k)
fn bool Token.isNot(Token* t, TokenKind k)
{
return t.kind != k;
}
func string Token.getName(Token* t)
fn string Token.getName(Token* t)
{
return t.kind.name;
}
@@ -94,7 +94,7 @@ struct Tokenizer
bool haveNext;
}
func void Tokenizer.init(Tokenizer* t, char* input)
fn void Tokenizer.init(Tokenizer* t, char* input)
{
t.dataStart = input;
t.current = input;
@@ -109,7 +109,7 @@ error LexError
string error_message;
}
func void! Tokenizer.lex(Tokenizer* t, Token* result)
fn void! Tokenizer.lex(Tokenizer* t, Token* result)
{
if (t.haveNext)
{
@@ -221,7 +221,7 @@ func void! Tokenizer.lex(Tokenizer* t, Token* result)
}
}
func Token*! Tokenizer.lookahead(Tokenizer* t)
fn Token*! Tokenizer.lookahead(Tokenizer* t)
{
if (!t.haveNext)
{
@@ -231,13 +231,13 @@ func Token*! Tokenizer.lookahead(Tokenizer* t)
return &t.nextToken;
}
func void Tokenizer.advance(Tokenizer* t, uint amount)
fn void Tokenizer.advance(Tokenizer* t, uint amount)
{
t.loc.column += amount;
t.current += amount;
}
func void Tokenizer.parseComment(Tokenizer* t)
fn void Tokenizer.parseComment(Tokenizer* t)
{
while (1)
{
@@ -258,7 +258,7 @@ func void Tokenizer.parseComment(Tokenizer* t)
}
}
func void Tokenizer.parseText(Tokenizer* t, Token* result)
fn void Tokenizer.parseText(Tokenizer* t, Token* result)
{
// TODO handle literal strings ' .. ' -> no escaping
// TODO handle escape chars for normal strings " .. \" \r \n "
@@ -277,7 +277,7 @@ func void Tokenizer.parseText(Tokenizer* t, Token* result)
t.advance(1);
}
func void! Tokenizer.parseMultiText(Tokenizer* t, Token* result)
fn void! Tokenizer.parseMultiText(Tokenizer* t, Token* result)
{
t.advance(3);
if (t.current[0] == '\n')
@@ -317,7 +317,7 @@ func void! Tokenizer.parseMultiText(Tokenizer* t, Token* result)
t.advance(3);
}
func void Tokenizer.parseNumber(Tokenizer* t, Token* result)
fn void Tokenizer.parseNumber(Tokenizer* t, Token* result)
{
// TODO handle prefix +/-
// handle hexadecimal/ocal/binary number
@@ -333,7 +333,7 @@ func void Tokenizer.parseNumber(Tokenizer* t, Token* result)
}
}
func bool isKeyChar(u8 c)
fn bool isKeyChar(u8 c)
{
if (c >= 128) return true;
if (isalpha(c)) return true;
@@ -342,7 +342,7 @@ func bool isKeyChar(u8 c)
return false;
}
func void Tokenizer.parseKey(Tokenizer* t, Token* result)
fn void Tokenizer.parseKey(Tokenizer* t, Token* result)
{
char* start = t.current;
while (t.current[0] && isKeyChar((char)(t.current[0]))) t.current++;

View File

@@ -1,70 +0,0 @@
module vector(Type);
public struct Vector
{
Type[] array;
}
public func void Vector.init()
{
array = nil;
}
public func void Vector.add(Vector *vector, Type type)
{
vector.array += type;
}
public func usize Vector.size(Vector *vector)
{
return vector.array.size;
}
public func void Vector.removeLast(Vector *vector)
{
vector.array.pop();
}
public func void Vector.removefirst(Vector *vector)
{
vector.array.removeAt(0);
}
public func void Type *Vector.first(Vector *vector)
{
return &vector.array.first;
}
public func void Type *Vector.last(Vector *vector)
{
return &vector.array.last();
}
public func bool Vector.empty(Vector *vector)
{
return !vector.array.size;
}
public macro Vector.foreach(Vector *vector, macro void(Type value) body)
{
for (usize i = 0, i < vector.array.size; i++)
{
@body(vector.array[i]);
}
}
test
{
define IntVector = Vector(int);
IntVector *vector = @calloc(IntVector);
vector.add(1);
vector.add(2);
for (int i : vector)
{
printDigit(i);
}
@vector.foreach(int i)
{
printDigit(i);
}
}

View File

@@ -1,51 +0,0 @@
module comparable;
import std::math;
interface Geometry
{
func double area();
func double perim();
}
struct Rect
{
double width, height;
}
struct Circle
{
double radius;
}
func double Rect.area(Rect *r)
{
return r.width * r.height;
}
func double Rect.perim(Rect *r)
{
return 2 * r.width + 2 * r.height;
}
func double Circle.area(Circle *c)
{
return math::PI * c.radius * c.radius
}
func double Circle.perim(Circle *c)
{
return math::PI * c.radius * 2;
}
func void measure(virtual Geometry g)
{
printf("area: %f, perimeter: %f\n", g.area(), g.perim());
}
func void main()
{
Rect r = { 3, 4 };
Circle c = { 5 };
measure(&r);
measure(&c);
}

View File

@@ -1,17 +0,0 @@
module std::io;
interface File : Closable, Readable, Seekable
{
FileInfo[]! readdir(int count);
FileInfo! stat();
}
interface File
{
inline Closable;
inline Readable;
inline Seekable;
FileInfo[]! readdir(int count);
FileInfo! stat();
}

View File

@@ -3,7 +3,7 @@ import gtk;
const string CLICK_ME = "Click Me";
uint counter = 0;
func void clickedme(GtkButton *o, void *d)
fn void clickedme(GtkButton *o, void *d)
{
(GtkLabel*)(d).set_text(string.format("You clicked me %d times", ++counter));
}

View File

@@ -0,0 +1,313 @@
module arkanoid;
/**
*
* raylib - classic game: arkanoid
*
* Sample game developed by Marc Palau and Ramon Santamaria
* converted to C3 by Christoffer Lerno
*
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
*/
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 450;
//----------------------------------------------------------------------------------
// Some Defines
//----------------------------------------------------------------------------------
const PLAYER_MAX_LIFE = 5;
const LINES_OF_BRICKS = 5;
const BRICKS_PER_LINE = 20;
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
enum GameScreen
{
LOGO,
TITLE,
GAMEPLAY,
ENDING
}
struct Player
{
Vector2 position;
Vector2 size;
int life;
}
struct Ball
{
Vector2 position;
Vector2 speed;
int radius;
bool active;
}
struct Brick
{
Vector2 position;
bool active;
}
//------------------------------------------------------------------------------------
// Global Variables Declaration
//------------------------------------------------------------------------------------
bool game_over = false;
bool pause = false;
Player player;
Ball ball;
Brick[BRICKS_PER_LINE][LINES_OF_BRICKS] brick;
Vector2 brick_size;
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
fn void main()
{
// Initialization (Note windowTitle is unused on Android)
//---------------------------------------------------------
raylib::init_window(SCREEN_WIDTH, SCREEN_HEIGHT, "classic game: arkanoid");
init_game();
raylib::set_target_fps(60);
//--------------------------------------------------------------------------------------
// Main game loop
while (!raylib::window_should_close()) // Detect window close button or ESC key
{
// Update and Draw
//----------------------------------------------------------------------------------
update_draw_frame();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
unload_game(); // Unload loaded data (textures, sounds, models...)
raylib::close_window(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
}
//------------------------------------------------------------------------------------
// Module Functions Definitions (local)
//------------------------------------------------------------------------------------
// Initialize game variables
fn void init_game()
{
brick_size = { raylib::get_screen_width() / BRICKS_PER_LINE, 40 };
// Initialize player
player.position = { SCREEN_WIDTH/2, SCREEN_HEIGHT * 7 / 8 };
player.size = { SCREEN_WIDTH / 10, 20 };
player.life = PLAYER_MAX_LIFE;
// Initialize ball
ball.position = { SCREEN_WIDTH / 2, SCREEN_HEIGHT * 7 / 8 - 30 };
ball.speed = { 0, 0 };
ball.radius = 7;
ball.active = false;
// Initialize bricks
int initial_down_position = 50;
for (int i = 0; i < LINES_OF_BRICKS; i++)
{
for (int j = 0; j < BRICKS_PER_LINE; j++)
{
brick[i][j].position = { j * brick_size.x + brick_size.x / 2, i * brick_size.y + initial_down_position };
brick[i][j].active = true;
}
}
}
// Update game (one frame)
fn void update_game()
{
if (game_over)
{
if (raylib::is_key_pressed(keyboard::ENTER))
{
init_game();
game_over = false;
}
}
if (raylib::is_key_pressed((KeyboardKey)'P')) pause = !pause;
if (pause) return;
// Player movement logic
if (raylib::is_key_down(keyboard::LEFT)) player.position.x -= 5;
if ((player.position.x - player.size.x/2) <= 0) player.position.x = player.size.x/2;
if (raylib::is_key_down(keyboard::RIGHT)) player.position.x += 5;
if ((player.position.x + player.size.x/2) >= SCREEN_WIDTH) player.position.x = SCREEN_WIDTH - player.size.x/2;
// Ball launching logic
if (!ball.active)
{
if (raylib::is_key_pressed(keyboard::SPACE))
{
ball.active = true;
ball.speed = { 0, -5 };
}
}
// Ball movement logic
if (ball.active)
{
ball.position.x += ball.speed.x;
ball.position.y += ball.speed.y;
}
else
{
ball.position = { player.position.x, SCREEN_HEIGHT * 7 / 8 - 30 };
}
// Collision logic: ball vs walls
if (((ball.position.x + ball.radius) >= SCREEN_WIDTH) || ((ball.position.x - ball.radius) <= 0)) ball.speed.x *= -1;
if ((ball.position.y - ball.radius) <= 0) ball.speed.y *= -1;
if ((ball.position.y + ball.radius) >= SCREEN_HEIGHT)
{
ball.speed = { 0, 0 };
ball.active = false;
player.life--;
}
// Collision logic: ball vs player
if (raylib::check_collision_circle_rec(ball.position, ball.radius,
Rectangle{ player.position.x - player.size.x / 2, player.position.y - player.size.y / 2, player.size.x, player.size.y}))
{
if (ball.speed.y > 0)
{
ball.speed.y *= -1;
ball.speed.x = (ball.position.x - player.position.x) / (player.size.x / 2) * 5;
}
}
// Collision logic: ball vs bricks
for (int i = 0; i < LINES_OF_BRICKS; i++)
{
for (int j = 0; j < BRICKS_PER_LINE; j++)
{
if (brick[i][j].active)
{
// Hit below
if (((ball.position.y - ball.radius) <= (brick[i][j].position.y + brick_size.y / 2)) &&
((ball.position.y - ball.radius) > (brick[i][j].position.y + brick_size.y / 2 + ball.speed.y)) &&
((math::fabs((double)ball.position.x - brick[i][j].position.x)) < (double)(brick_size.x / 2 + ball.radius * 2 / 3)) && (ball.speed.y < 0))
{
brick[i][j].active = false;
ball.speed.y *= -1;
}
// Hit above
else if (((ball.position.y + ball.radius) >= (brick[i][j].position.y - brick_size.y/2)) &&
((ball.position.y + ball.radius) < (brick[i][j].position.y - brick_size.y/2 + ball.speed.y)) &&
((math::fabs((double)ball.position.x - brick[i][j].position.x)) < (double)(brick_size.x/2 + ball.radius*2/3)) && (ball.speed.y > 0))
{
brick[i][j].active = false;
ball.speed.y *= -1;
}
// Hit left
else if (((ball.position.x + ball.radius) >= (brick[i][j].position.x - brick_size.x/2)) &&
((ball.position.x + ball.radius) < (brick[i][j].position.x - brick_size.x/2 + ball.speed.x)) &&
((math::fabs((double)ball.position.y - brick[i][j].position.y)) < (double)(brick_size.y/2 + ball.radius*2/3)) && (ball.speed.x > 0))
{
brick[i][j].active = false;
ball.speed.x *= -1;
}
// Hit right
else if (((ball.position.x - ball.radius) <= (brick[i][j].position.x + brick_size.x/2)) &&
((ball.position.x - ball.radius) > (brick[i][j].position.x + brick_size.x/2 + ball.speed.x)) &&
((math::fabs((double)ball.position.y - brick[i][j].position.y)) < (double)(brick_size.y/2 + ball.radius*2/3)) && (ball.speed.x < 0))
{
brick[i][j].active = false;
ball.speed.x *= -1;
}
}
}
}
// Game over logic
if (player.life <= 0)
{
game_over = true;
}
else
{
game_over = true;
for (int i = 0; i < LINES_OF_BRICKS; i++)
{
for (int j = 0; j < BRICKS_PER_LINE; j++)
{
if (brick[i][j].active) game_over = false;
}
}
}
}
// Draw game (one frame)
fn void draw_game()
{
raylib::begin_drawing();
raylib::clear_background(raylib::RAYWHITE);
if (!game_over)
{
// Draw player bar
raylib::draw_rectangle((int)(player.position.x - player.size.x/2), (int)(player.position.y - player.size.y/2), (int)player.size.x, (int)player.size.y, raylib::BLACK);
// Draw player lives
for (int i = 0; i < player.life; i++) raylib::draw_rectangle(20 + 40*i, SCREEN_HEIGHT - 30, 35, 10, raylib::LIGHTGRAY);
// Draw ball
raylib::draw_circle_v(ball.position, ball.radius, raylib::MAROON);
// Draw bricks
for (int i = 0; i < LINES_OF_BRICKS; i++)
{
for (int j = 0; j < BRICKS_PER_LINE; j++)
{
if (brick[i][j].active)
{
if ((i + j) % 2 == 0)
{
raylib::draw_rectangle((int)(brick[i][j].position.x - brick_size.x/2), (int)(brick[i][j].position.y - brick_size.y/2), (int)brick_size.x, (int)brick_size.y, raylib::GRAY);
}
else
{
raylib::draw_rectangle((int)(brick[i][j].position.x - brick_size.x/2), (int)(brick[i][j].position.y - brick_size.y/2), (int)brick_size.x, (int)brick_size.y, raylib::DARKGRAY);
}
}
}
}
if (pause) raylib::draw_text("GAME PAUSED", SCREEN_WIDTH/2 - raylib::measure_text("GAME PAUSED", 40)/2, SCREEN_HEIGHT/2 - 40, 40, raylib::GRAY);
}
else
{
raylib::draw_text("PRESS [ENTER] TO PLAY AGAIN", raylib::get_screen_width()/2 - raylib::measure_text("PRESS [ENTER] TO PLAY AGAIN", 20)/2, raylib::get_screen_height()/2 - 50, 20, raylib::GRAY);
}
raylib::end_drawing();
}
// Unload game variables
fn void unload_game()
{
// TODO: Unload all dynamic loaded data (textures, sounds, models...)
}
// Update and Draw (one frame)
fn void update_draw_frame()
{
update_game();
draw_game();
}

View File

@@ -0,0 +1,251 @@
module snake;
/**
*
* raylib - classic game: snake
*
* Sample game developed by Ian Eito, Albert Martos and Ramon Santamaria,
* converted to C3 and modified by Christoffer Lerno
*
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
*
*/
const SNAKE_LENGTH = 256;
const SQUARE_SIZE = 32;
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 450;
enum SnakeDirection
{
RIGHT,
DOWN,
LEFT,
UP
}
struct Snake
{
Vector2 position;
Vector2 size;
Color color;
}
struct Food
{
Vector2 position;
Vector2 size;
bool active;
Color color;
}
int frames_counter = 0;
bool game_over = false;
bool pause = false;
Food fruit;
SnakeDirection snake_direction;
Snake[SNAKE_LENGTH] snake;
Vector2[SNAKE_LENGTH] snake_position;
bool allow_move = false;
Vector2 offset;
int counter_tail = 0;
fn void main()
{
raylib::init_window(SCREEN_WIDTH, SCREEN_HEIGHT, "classic game: snake");
init_game();
raylib::set_target_fps(60);
while (!raylib::window_should_close()) // Detect window close button or ESC key
{
update_draw_frame();
}
unload_game();
raylib::close_window();
}
// Initialize game variables
fn void init_game()
{
frames_counter = 0;
game_over = false;
pause = false;
counter_tail = 1;
allow_move = false;
snake_direction = SnakeDirection.RIGHT;
offset.x = SCREEN_WIDTH % SQUARE_SIZE;
offset.y = SCREEN_HEIGHT % SQUARE_SIZE;
for (int i = 0; i < SNAKE_LENGTH; i++)
{
snake[i].position = { offset.x / 2, offset.y / 2 };
snake[i].size = { SQUARE_SIZE, SQUARE_SIZE };
if (i == 0)
{
snake[i].color = raylib::DARKBLUE;
}
else
{
snake[i].color = raylib::BLUE;
}
}
for (int i = 0; i < SNAKE_LENGTH; i++)
{
snake_position[i] = { 0.0f, 0.0f };
}
fruit.size = { SQUARE_SIZE, SQUARE_SIZE };
fruit.color = raylib::SKYBLUE;
fruit.active = false;
}
fn void update_game()
{
if (game_over)
{
if (raylib::is_key_pressed(keyboard::ENTER))
{
init_game();
game_over = false;
}
return;
}
if (raylib::is_key_pressed((KeyboardKey)'P')) pause = !pause;
if (pause) return;
if (raylib::is_key_pressed(keyboard::RIGHT) && allow_move)
{
snake_direction = (SnakeDirection)((snake_direction + 1) % 4);
allow_move = false;
}
if (raylib::is_key_pressed(keyboard::LEFT) && allow_move)
{
snake_direction = (SnakeDirection)((snake_direction + 3) % 4);
allow_move = false;
}
// Snake movement
for (int i = 0; i < counter_tail; i++) snake_position[i] = snake[i].position;
if (frames_counter++ % 5 != 0) return;
allow_move = true;
switch (snake_direction)
{
case RIGHT:
snake[0].position.x += SQUARE_SIZE;
snake[0].position.y += 0;
case UP:
snake[0].position.x += 0;
snake[0].position.y += -SQUARE_SIZE;
case DOWN:
snake[0].position.x += 0;
snake[0].position.y += SQUARE_SIZE;
case LEFT:
snake[0].position.x += -SQUARE_SIZE;
snake[0].position.y += 0;
default:
unreachable();
}
for (int i = 1; i < counter_tail; i++)
{
snake[i].position = snake_position[i - 1];
}
// Wall behaviour
if (((snake[0].position.x) > (SCREEN_WIDTH - offset.x)) ||
((snake[0].position.y) > (SCREEN_HEIGHT - offset.y)) ||
(snake[0].position.x < 0) || (snake[0].position.y < 0))
{
game_over = true;
}
// Collision with yourself
for (int i = 1; i < counter_tail; i++)
{
if ((snake[0].position.x == snake[i].position.x) && (snake[0].position.y == snake[i].position.y)) game_over = true;
}
// Fruit position calculation
if (!fruit.active)
{
fruit.active = true;
fruit.position = { raylib::get_random_value(0, (SCREEN_WIDTH / SQUARE_SIZE) - 1) * SQUARE_SIZE + offset.x/2, raylib::get_random_value(0, (SCREEN_HEIGHT / SQUARE_SIZE) - 1) * SQUARE_SIZE + offset.y / 2 };
for (int i = 0; i < counter_tail; i++)
{
while ((fruit.position.x == snake[i].position.x) && (fruit.position.y == snake[i].position.y))
{
fruit.position = { raylib::get_random_value(0, (SCREEN_WIDTH / SQUARE_SIZE) - 1) * SQUARE_SIZE + offset.x/2, raylib::get_random_value(0, (SCREEN_HEIGHT / SQUARE_SIZE) - 1) * SQUARE_SIZE + offset.y / 2 };
i = 0;
}
}
}
// Collision
if ((snake[0].position.x < (fruit.position.x + fruit.size.x) && (snake[0].position.x + snake[0].size.x) > fruit.position.x) &&
(snake[0].position.y < (fruit.position.y + fruit.size.y) && (snake[0].position.y + snake[0].size.y) > fruit.position.y))
{
snake[counter_tail].position = snake_position[counter_tail - 1];
counter_tail += 1;
fruit.active = false;
}
}
// Draw game (one frame)
fn void draw_game()
{
raylib::begin_drawing();
raylib::clear_background(raylib::RAYWHITE);
if (!game_over)
{
// Draw grid lines
for (int i = 0; i < SCREEN_WIDTH / SQUARE_SIZE + 1; i++)
{
raylib::draw_line_v({SQUARE_SIZE * i + offset.x/2, offset.y/2}, {SQUARE_SIZE * i + offset.x/2, SCREEN_HEIGHT - offset.y/2}, raylib::LIGHTGRAY);
}
for (int i = 0; i < SCREEN_HEIGHT/SQUARE_SIZE + 1; i++)
{
raylib::draw_line_v({offset.x/2, SQUARE_SIZE * i + offset.y / 2 }, { SCREEN_WIDTH - offset.x/2, SQUARE_SIZE * i + offset.y / 2 }, raylib::LIGHTGRAY);
}
// Draw snake
for (int i = 0; i < counter_tail; i++) raylib::draw_rectangle_v(snake[i].position, snake[i].size, snake[i].color);
// Draw fruit to pick
raylib::draw_rectangle_v(fruit.position, fruit.size, fruit.color);
if (pause) raylib::draw_text("GAME PAUSED", SCREEN_WIDTH/2 - raylib::measure_text("GAME PAUSED", 40)/2, SCREEN_HEIGHT / 2 - 40, 40, raylib::GRAY);
}
else
{
raylib::draw_text("PRESS [ENTER] TO PLAY AGAIN", raylib::get_screen_width()/2 - raylib::measure_text("PRESS [ENTER] TO PLAY AGAIN", 20)/2, raylib::get_screen_height()/2 - 50, 20, raylib::GRAY);
}
raylib::end_drawing();
}
// Unload game variables
fn void unload_game()
{
// TODO: Unload all dynamic loaded data (textures, sounds, models...)
}
// Update and Draw (one frame)
fn void update_draw_frame()
{
update_game();
draw_game();
}

View File

@@ -0,0 +1,793 @@
module tetris;
/**
* raylib - classic game: tetris
*
* Sample game developed by Marc Palau and Ramon Santamaria,
* converted to C3 by Christoffer Lerno.
*
* This game has been created using raylib v1.3 (www.raylib.com)
*
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
*/
//----------------------------------------------------------------------------------
// Some Defines
//----------------------------------------------------------------------------------
const SQUARE_SIZE = 20;
const GRID_HORIZONTAL_SIZE = 12;
const GRID_VERTICAL_SIZE = 20;
const LATERAL_SPEED = 10;
const TURNING_SPEED = 12;
const FAST_FALL_AWAIT_COUNTER = 30;
const FADING_TIME = 33;
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
enum GridSquare { EMPTY, MOVING, FULL, BLOCK, FADING }
//------------------------------------------------------------------------------------
// Global Variables Declaration
//------------------------------------------------------------------------------------
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 450;
bool game_over = false;
bool pause = false;
// Matrices
GridSquare[GRID_VERTICAL_SIZE][GRID_HORIZONTAL_SIZE] grid;
GridSquare[4][4] piece;
GridSquare[4][4] incoming_piece;
struct IntVec
{
int x;
int y;
}
// These variables keep track of the active piece position
int piece_position_x = 0;
int piece_position_y = 0;
// Game parameters
Color fading_color;
//int fallingSpeed; // In frames
bool begin_play = true; // This var is only true at the begining of the game, used for the first matrix creations
bool piece_active = false;
bool detection = false;
bool line_to_delete = false;
// Statistics
int level = 1;
int lines = 0;
// Counters
int gravity_movement_counter = 0;
int lateral_movement_counter = 0;
int turn_movement_counter = 0;
int fast_fall_movement_counter = 0;
int fade_line_counter = 0;
// Based on level
int gravity_speed = 30;
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
fn void main()
{
// Initialization (Note windowTitle is unused on Android)
//---------------------------------------------------------
raylib::init_window(SCREEN_WIDTH, SCREEN_HEIGHT, "classic game: tetris");
init_game();
raylib::set_target_fps(60);
//--------------------------------------------------------------------------------------
// Main game loop
while (!raylib::window_should_close()) // Detect window close button or ESC key
{
// Update and Draw
//----------------------------------------------------------------------------------
update_draw_frame();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
unload_game(); // Unload loaded data (textures, sounds, models...)
raylib::close_window(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
}
//--------------------------------------------------------------------------------------
// Game Module Functions Definition
//--------------------------------------------------------------------------------------
// Initialize game variables
fn void init_game()
{
// Initialize game statistics
level = 1;
lines = 0;
fading_color = raylib::GRAY;
piece_position_x = 0;
piece_position_y = 0;
pause = false;
begin_play = true;
piece_active = false;
detection = false;
line_to_delete = false;
// Counters
gravity_movement_counter = 0;
lateral_movement_counter = 0;
turn_movement_counter = 0;
fast_fall_movement_counter = 0;
fade_line_counter = 0;
gravity_speed = 30;
// Initialize grid matrices
for (int i = 0; i < GRID_HORIZONTAL_SIZE; i++)
{
for (int j = 0; j < GRID_VERTICAL_SIZE; j++)
{
if ((j == GRID_VERTICAL_SIZE - 1) || (i == 0) || (i == GRID_HORIZONTAL_SIZE - 1))
{
grid[i][j] = BLOCK;
}
else
{
grid[i][j] = EMPTY;
}
}
}
// Initialize incoming piece matrices
for (int i = 0; i < 4; i++)
{
for (int j = 0; j< 4; j++)
{
incoming_piece[i][j] = EMPTY;
}
}
}
// Update game (one frame)
fn void update_game()
{
if (game_over)
{
if (raylib::is_key_pressed(keyboard::ENTER))
{
init_game();
game_over = false;
}
return;
}
if (raylib::is_key_pressed((KeyboardKey)'P')) pause = !pause;
if (pause) return;
if (line_to_delete)
{
// Animation when deleting lines
fade_line_counter++;
fading_color = fade_line_counter % 8 < 4 ? raylib::MAROON : raylib::GRAY;
if (fade_line_counter >= FADING_TIME)
{
lines += delete_complete_lines();
fade_line_counter = 0;
line_to_delete = false;
}
return;
}
if (!piece_active)
{
// Get another piece
piece_active = create_piece();
// We leave a little time before starting the fast falling down
fast_fall_movement_counter = 0;
}
else // Piece falling
{
// Counters update
fast_fall_movement_counter++;
gravity_movement_counter++;
lateral_movement_counter++;
turn_movement_counter++;
// We make sure to move if we've pressed the key this frame
if (raylib::is_key_pressed(keyboard::LEFT) || raylib::is_key_pressed(keyboard::RIGHT)) lateral_movement_counter = LATERAL_SPEED;
if (raylib::is_key_pressed(keyboard::UP)) turn_movement_counter = TURNING_SPEED;
// Fall down
if (raylib::is_key_down(keyboard::DOWN) && (fast_fall_movement_counter >= FAST_FALL_AWAIT_COUNTER))
{
// We make sure the piece is going to fall this frame
gravity_movement_counter += gravity_speed;
}
if (gravity_movement_counter >= gravity_speed)
{
// Basic falling movement
if (check_detection()) detection = true;
// Check if the piece has collided with another piece or with the boundings
resolve_falling_movement(&detection, &piece_active);
// Check if we fullfilled a line and if so, erase the line and pull down the the lines above
check_completion(&line_to_delete);
gravity_movement_counter = 0;
}
// Move laterally at player's will
if (lateral_movement_counter >= LATERAL_SPEED)
{
// Update the lateral movement and if success, reset the lateral counter
if (!resolve_lateral_movement()) lateral_movement_counter = 0;
}
// Turn the piece at player's will
if (turn_movement_counter >= TURNING_SPEED)
{
// Update the turning movement and reset the turning counter
if (resolve_turn_movement()) turn_movement_counter = 0;
}
}
// Game over logic
for (int j = 0; j < 2; j++)
{
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
{
if (grid[i][j] == GridSquare.FULL)
{
game_over = true;
}
}
}
}
// Draw game (one frame)
fn void draw_game()
{
raylib::begin_drawing();
raylib::clear_background(raylib::RAYWHITE);
if (game_over)
{
raylib::draw_text("PRESS [ENTER] TO PLAY AGAIN", raylib::get_screen_width() / 2 - raylib::measure_text("PRESS [ENTER] TO PLAY AGAIN", 20) / 2, raylib::get_screen_height() / 2 - 50, 20, raylib::GRAY);
raylib::end_drawing();
return;
}
// Draw gameplay area
IntVec offset = {
SCREEN_WIDTH / 2 - (GRID_HORIZONTAL_SIZE * SQUARE_SIZE / 2) - 50,
SCREEN_HEIGHT / 2 - ((GRID_VERTICAL_SIZE - 1) * SQUARE_SIZE / 2) + SQUARE_SIZE * 2
};
offset.y -= 50; // NOTE: Harcoded position!
int controller = offset.x;
for (int j = 0; j < GRID_VERTICAL_SIZE; j++)
{
for (int i = 0; i < GRID_HORIZONTAL_SIZE; i++)
{
// Draw each square of the grid
switch (grid[i][j])
{
case EMPTY:
raylib::draw_line(offset.x, offset.y, offset.x + SQUARE_SIZE, offset.y, raylib::LIGHTGRAY );
raylib::draw_line(offset.x, offset.y, offset.x, offset.y + SQUARE_SIZE, raylib::LIGHTGRAY );
raylib::draw_line(offset.x + SQUARE_SIZE, offset.y, offset.x + SQUARE_SIZE, offset.y + SQUARE_SIZE, raylib::LIGHTGRAY );
raylib::draw_line(offset.x, offset.y + SQUARE_SIZE, offset.x + SQUARE_SIZE, offset.y + SQUARE_SIZE, raylib::LIGHTGRAY );
offset.x += SQUARE_SIZE;
case FULL:
raylib::draw_rectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, raylib::GRAY);
offset.x += SQUARE_SIZE;
case MOVING:
raylib::draw_rectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, raylib::DARKGRAY);
offset.x += SQUARE_SIZE;
case BLOCK:
raylib::draw_rectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, raylib::LIGHTGRAY);
offset.x += SQUARE_SIZE;
case FADING:
raylib::draw_rectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, fading_color);
offset.x += SQUARE_SIZE;
default:
}
}
offset.x = controller;
offset.y += SQUARE_SIZE;
}
// Draw incoming piece (hardcoded)
offset.x = 500;
offset.y = 45;
controller = offset.x;
for (int j = 0; j < 4; j++)
{
for (int i = 0; i < 4; i++)
{
switch (incoming_piece[i][j])
{
case EMPTY:
raylib::draw_line(offset.x, offset.y, offset.x + SQUARE_SIZE, offset.y, raylib::LIGHTGRAY);
raylib::draw_line(offset.x, offset.y, offset.x, offset.y + SQUARE_SIZE, raylib::LIGHTGRAY);
raylib::draw_line(offset.x + SQUARE_SIZE, offset.y, offset.x + SQUARE_SIZE, offset.y + SQUARE_SIZE, raylib::LIGHTGRAY);
raylib::draw_line(offset.x, offset.y + SQUARE_SIZE, offset.x + SQUARE_SIZE, offset.y + SQUARE_SIZE, raylib::LIGHTGRAY);
offset.x += SQUARE_SIZE;
case MOVING:
raylib::draw_rectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, raylib::GRAY);
offset.x += SQUARE_SIZE;
default:
break;
}
}
offset.x = controller;
offset.y += SQUARE_SIZE;
}
raylib::draw_text("INCOMING:", offset.x, offset.y - 100, 10, raylib::GRAY);
raylib::draw_text(raylib::text_format("LINES: %04i", lines), offset.x, offset.y + 20, 10, raylib::GRAY);
if (pause)
{
raylib::draw_text("GAME PAUSED", SCREEN_WIDTH / 2 - raylib::measure_text("GAME PAUSED", 40)/2, SCREEN_HEIGHT/2 - 40, 40, raylib::GRAY);
}
raylib::end_drawing();
}
// Unload game variables
fn void unload_game()
{
// TODO: Unload all dynamic loaded data (textures, sounds, models...)
}
// Update and Draw (one frame)
fn void update_draw_frame()
{
update_game();
draw_game();
}
//--------------------------------------------------------------------------------------
// Additional module functions
//--------------------------------------------------------------------------------------
fn bool create_piece()
{
piece_position_x = (int)((GRID_HORIZONTAL_SIZE - 4)/2);
piece_position_y = 0;
// If the game is starting and you are going to create the first piece, we create an extra one
if (begin_play)
{
get_random_piece();
begin_play = false;
}
// We assign the incoming piece to the actual piece
for (int i = 0; i < 4; i++)
{
for (int j = 0; j< 4; j++)
{
piece[i][j] = incoming_piece[i][j];
}
}
// We assign a random piece to the incoming one
get_random_piece();
// Assign the piece to the grid
for (int i = piece_position_x; i < piece_position_x + 4; i++)
{
for (int j = 0; j < 4; j++)
{
if (piece[i - (int)piece_position_x][j] == GridSquare.MOVING) grid[i][j] = MOVING;
}
}
return true;
}
fn void get_random_piece()
{
int random = raylib::get_random_value(0, 6);
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
incoming_piece[i][j] = EMPTY;
}
}
switch (random)
{
case 0:
incoming_piece[1][1] = MOVING;
incoming_piece[2][1] = MOVING;
incoming_piece[1][2] = MOVING;
incoming_piece[2][2] = MOVING; //Cube
case 1:
incoming_piece[1][0] = MOVING;
incoming_piece[1][1] = MOVING;
incoming_piece[1][2] = MOVING;
incoming_piece[2][2] = MOVING; //L
case 2:
incoming_piece[1][2] = MOVING;
incoming_piece[2][0] = MOVING;
incoming_piece[2][1] = MOVING;
incoming_piece[2][2] = MOVING; //L inversa
case 3:
incoming_piece[0][1] = MOVING;
incoming_piece[1][1] = MOVING;
incoming_piece[2][1] = MOVING;
incoming_piece[3][1] = MOVING; //Recta
case 4:
incoming_piece[1][0] = MOVING;
incoming_piece[1][1] = MOVING;
incoming_piece[1][2] = MOVING;
incoming_piece[2][1] = MOVING; //Creu tallada
case 5:
incoming_piece[1][1] = MOVING;
incoming_piece[2][1] = MOVING;
incoming_piece[2][2] = MOVING;
incoming_piece[3][2] = MOVING; //S
case 6:
incoming_piece[1][2] = MOVING;
incoming_piece[2][2] = MOVING;
incoming_piece[2][1] = MOVING;
incoming_piece[3][1] = MOVING; //S inversa
default:
unreachable();
}
}
fn void resolve_falling_movement(bool* detection_ref, bool* piece_active_ref)
{
// If we finished moving this piece, we stop it
if (*detection_ref)
{
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
{
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
{
if (grid[i][j] == GridSquare.MOVING)
{
grid[i][j] = FULL;
*detection_ref = false;
*piece_active_ref = false;
}
}
}
}
else // We move down the piece
{
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
{
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
{
if (grid[i][j] == GridSquare.MOVING)
{
grid[i][j+1] = MOVING;
grid[i][j] = EMPTY;
}
}
}
piece_position_y++;
}
}
fn bool resolve_lateral_movement()
{
bool collision = false;
// Piece movement
if (raylib::is_key_down(keyboard::LEFT)) // Move left
{
// Check if is possible to move to left
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
{
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
{
if (grid[i][j] == GridSquare.MOVING)
{
// Check if we are touching the left wall or we have a full square at the left
if ((i-1 == 0) || (grid[i-1][j] == GridSquare.FULL)) collision = true;
}
}
}
// If able, move left
if (!collision)
{
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
{
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++) // We check the matrix from left to right
{
// Move everything to the left
if (grid[i][j] == GridSquare.MOVING)
{
grid[i-1][j] = MOVING;
grid[i][j] = EMPTY;
}
}
}
piece_position_x--;
}
}
else if (raylib::is_key_down(keyboard::RIGHT)) // Move right
{
// Check if is possible to move to right
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
{
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
{
if (grid[i][j] == GridSquare.MOVING)
{
// Check if we are touching the right wall or we have a full square at the right
if ((i+1 == GRID_HORIZONTAL_SIZE - 1) || (grid[i+1][j] == GridSquare.FULL))
{
collision = true;
}
}
}
}
// If able move right
if (!collision)
{
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
{
for (int i = GRID_HORIZONTAL_SIZE - 1; i >= 1; i--) // We check the matrix from right to left
{
// Move everything to the right
if (grid[i][j] == GridSquare.MOVING)
{
grid[i+1][j] = MOVING;
grid[i][j] = EMPTY;
}
}
}
piece_position_x++;
}
}
return collision;
}
fn bool resolve_turn_movement()
{
// Input for turning the piece
if (raylib::is_key_down(keyboard::UP))
{
GridSquare aux;
bool checker = false;
// Check all turning possibilities
if ((grid[piece_position_x + 3][piece_position_y] == GridSquare.MOVING) &&
(grid[piece_position_x][piece_position_y] != GridSquare.EMPTY) &&
(grid[piece_position_x][piece_position_y] != GridSquare.MOVING)) checker = true;
if ((grid[piece_position_x + 3][piece_position_y + 3] == GridSquare.MOVING) &&
(grid[piece_position_x + 3][piece_position_y] != GridSquare.EMPTY) &&
(grid[piece_position_x + 3][piece_position_y] != GridSquare.MOVING)) checker = true;
if ((grid[piece_position_x][piece_position_y + 3] == GridSquare.MOVING) &&
(grid[piece_position_x + 3][piece_position_y + 3] != GridSquare.EMPTY) &&
(grid[piece_position_x + 3][piece_position_y + 3] != GridSquare.MOVING)) checker = true;
if ((grid[piece_position_x][piece_position_y] == GridSquare.MOVING) &&
(grid[piece_position_x][piece_position_y + 3] != GridSquare.EMPTY) &&
(grid[piece_position_x][piece_position_y + 3] != GridSquare.MOVING)) checker = true;
if ((grid[piece_position_x + 1][piece_position_y] == GridSquare.MOVING) &&
(grid[piece_position_x][piece_position_y + 2] != GridSquare.EMPTY) &&
(grid[piece_position_x][piece_position_y + 2] != GridSquare.MOVING)) checker = true;
if ((grid[piece_position_x + 3][piece_position_y + 1] == GridSquare.MOVING) &&
(grid[piece_position_x + 1][piece_position_y] != GridSquare.EMPTY) &&
(grid[piece_position_x + 1][piece_position_y] != GridSquare.MOVING)) checker = true;
if ((grid[piece_position_x + 2][piece_position_y + 3] == GridSquare.MOVING) &&
(grid[piece_position_x + 3][piece_position_y + 1] != GridSquare.EMPTY) &&
(grid[piece_position_x + 3][piece_position_y + 1] != GridSquare.MOVING)) checker = true;
if ((grid[piece_position_x][piece_position_y + 2] == GridSquare.MOVING) &&
(grid[piece_position_x + 2][piece_position_y + 3] != GridSquare.EMPTY) &&
(grid[piece_position_x + 2][piece_position_y + 3] != GridSquare.MOVING)) checker = true;
if ((grid[piece_position_x + 2][piece_position_y] == GridSquare.MOVING) &&
(grid[piece_position_x][piece_position_y + 1] != GridSquare.EMPTY) &&
(grid[piece_position_x][piece_position_y + 1] != GridSquare.MOVING)) checker = true;
if ((grid[piece_position_x + 3][piece_position_y + 2] == GridSquare.MOVING) &&
(grid[piece_position_x + 2][piece_position_y] != GridSquare.EMPTY) &&
(grid[piece_position_x + 2][piece_position_y] != GridSquare.MOVING)) checker = true;
if ((grid[piece_position_x + 1][piece_position_y + 3] == GridSquare.MOVING) &&
(grid[piece_position_x + 3][piece_position_y + 2] != GridSquare.EMPTY) &&
(grid[piece_position_x + 3][piece_position_y + 2] != GridSquare.MOVING)) checker = true;
if ((grid[piece_position_x][piece_position_y + 1] == GridSquare.MOVING) &&
(grid[piece_position_x + 1][piece_position_y + 3] != GridSquare.EMPTY) &&
(grid[piece_position_x + 1][piece_position_y + 3] != GridSquare.MOVING)) checker = true;
if ((grid[piece_position_x + 1][piece_position_y + 1] == GridSquare.MOVING) &&
(grid[piece_position_x + 1][piece_position_y + 2] != GridSquare.EMPTY) &&
(grid[piece_position_x + 1][piece_position_y + 2] != GridSquare.MOVING)) checker = true;
if ((grid[piece_position_x + 2][piece_position_y + 1] == GridSquare.MOVING) &&
(grid[piece_position_x + 1][piece_position_y + 1] != GridSquare.EMPTY) &&
(grid[piece_position_x + 1][piece_position_y + 1] != GridSquare.MOVING)) checker = true;
if ((grid[piece_position_x + 2][piece_position_y + 2] == GridSquare.MOVING) &&
(grid[piece_position_x + 2][piece_position_y + 1] != GridSquare.EMPTY) &&
(grid[piece_position_x + 2][piece_position_y + 1] != GridSquare.MOVING)) checker = true;
if ((grid[piece_position_x + 1][piece_position_y + 2] == GridSquare.MOVING) &&
(grid[piece_position_x + 2][piece_position_y + 2] != GridSquare.EMPTY) &&
(grid[piece_position_x + 2][piece_position_y + 2] != GridSquare.MOVING)) checker = true;
if (!checker)
{
aux = piece[0][0];
piece[0][0] = piece[3][0];
piece[3][0] = piece[3][3];
piece[3][3] = piece[0][3];
piece[0][3] = aux;
aux = piece[1][0];
piece[1][0] = piece[3][1];
piece[3][1] = piece[2][3];
piece[2][3] = piece[0][2];
piece[0][2] = aux;
aux = piece[2][0];
piece[2][0] = piece[3][2];
piece[3][2] = piece[1][3];
piece[1][3] = piece[0][1];
piece[0][1] = aux;
aux = piece[1][1];
piece[1][1] = piece[2][1];
piece[2][1] = piece[2][2];
piece[2][2] = piece[1][2];
piece[1][2] = aux;
}
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
{
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
{
if (grid[i][j] == GridSquare.MOVING)
{
grid[i][j] = EMPTY;
}
}
}
for (int i = piece_position_x; i < piece_position_x + 4; i++)
{
for (int j = piece_position_y; j < piece_position_y + 4; j++)
{
if (piece[i - piece_position_x][j - piece_position_y] == GridSquare.MOVING)
{
grid[i][j] = MOVING;
}
}
}
return true;
}
return false;
}
fn bool check_detection()
{
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
{
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
{
if ((grid[i][j] == GridSquare.MOVING) && ((grid[i][j+1] == GridSquare.FULL)
|| (grid[i][j+1] == GridSquare.BLOCK))) return true;
}
}
return false;
}
fn void check_completion(bool *line_to_delete_ref)
{
int calculator = 0;
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
{
calculator = 0;
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
{
// Count each square of the line
if (grid[i][j] == GridSquare.FULL)
{
calculator++;
}
// Check if we completed the whole line
if (calculator == GRID_HORIZONTAL_SIZE - 2)
{
*line_to_delete_ref = true;
calculator = 0;
// points++;
// Mark the completed line
for (int z = 1; z < GRID_HORIZONTAL_SIZE - 1; z++)
{
grid[z][j] = FADING;
}
}
}
}
}
fn int delete_complete_lines()
{
int lines_to_erase = 0;
// Erase the completed line
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
{
while (grid[1][j] == GridSquare.FADING)
{
lines_to_erase++;
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
{
grid[i][j] = GridSquare.EMPTY;
}
for (int j2 = j-1; j2 >= 0; j2--)
{
for (int i2 = 1; i2 < GRID_HORIZONTAL_SIZE - 1; i2++)
{
switch (grid[i2][j2])
{
case FULL:
grid[i2][j2+1] = GridSquare.FULL;
grid[i2][j2] = GridSquare.EMPTY;
case FADING:
grid[i2][j2+1] = GridSquare.FADING;
grid[i2][j2] = GridSquare.EMPTY;
default:
}
}
}
}
}
return lines_to_erase;
}

View File

@@ -0,0 +1,44 @@
module test;
import libc;
fault TestErr
{
NOPE
}
fn int! eventually_succeed()
{
static int i = 0;
if (i++ < 3) return TestErr.NOPE!;
return i * 3;
}
macro @retry(#function, int retries = 3)
{
var $Type = $typeof(#function);
anyerr e;
do
{
$Type! result = #function;
if (catch err = result)
{
e = err;
continue;
}
return result;
} while (retries-- > 0);
return e!;
}
fn void main()
{
int! result = @retry(eventually_succeed());
if (try result)
{
libc::printf("Got result: %d\n", result);
}
else
{
libc::printf("Failed :(\n");
}
}

View File

@@ -0,0 +1,67 @@
module spectralnorm;
import std::mem;
import std::array;
extern fn int atoi(char *s);
extern fn int printf(char *s, ...);
extern fn double sqrt(double);
double[] temparr;
fn double eval_A(int i, int j)
{
return 1.0 / ((i + j) * (i + j + 1) / 2 + i + 1);
}
fn void eval_A_times_u(double[] u, double[] au)
{
foreach (i, &val : au)
{
*val = 0;
foreach (j, uval : u)
{
*val += eval_A((int)(i), (int)(j)) * uval;
}
}
}
fn void eval_At_times_u(double[] u, double[] au)
{
foreach (i, &val : au)
{
*val = 0;
foreach (j, uval : u)
{
*val += eval_A((int)(j), (int)(i)) * uval;
}
}
}
fn void eval_AtA_times_u(double[] u, double[] atau) @noinline
{
eval_A_times_u(u, temparr);
eval_At_times_u(temparr, atau);
}
fn int main(int argc, char **argv)
{
int n = (argc == 2) ? atoi(argv[1]) : 2000;
temparr = array::alloc(double, n);
double[] u = array::alloc(double, n);
double[] v = array::alloc(double, n);
foreach(&uval : u) *uval = 1;
for (int i = 0; i < 10; i++)
{
eval_AtA_times_u(u, v);
eval_AtA_times_u(v, u);
}
double vBv;
double vv;
foreach (i, vval : v)
{
vBv += u[i] * vval;
vv += vval * vval;
}
printf("%0.9f\n", sqrt(vBv / vv));
return 0;
}

View File

@@ -0,0 +1,20 @@
module test;
import libc;
/**
* @checked a = b, b = a
*/
macro void @swap(&a, &b)
{
$typeof(a) temp = a;
a = b;
b = temp;
}
fn void main()
{
int x = 123;
int y = 456;
@swap(x, y);
libc::printf("x: %d y: %d\n", x, y);
}

View File

@@ -56,7 +56,7 @@ void comment(void);
"void" { count(); return(VOID); }
"volatile" { count(); return(VOLATILE); }
"while" { count(); return(WHILE); }
"func" { count(); return(FUNC); }
"fn" { count(); return(FUNC); }
"nil" { count(); return(NIL); }
"next" { count(); return(NEXT); }
"in" { count(); return(IN); }

View File

@@ -1,16 +0,0 @@
module std::array;
import std::mem;
macro make($Type, usize elements)
{
assert(elements > 0);
$Type* ptr = mem::alloc($Type.sizeof, elements);
return ptr[0..(elements - 1)];
}
macro make_zero($Type, usize elements)
{
assert(elements > 0);
$Type* ptr = mem::calloc($Type.sizeof, elements);
return ptr[0..(elements - 1)];
}

View File

@@ -1,100 +0,0 @@
module std::builtin;
/*
enum TypeKind
{
VOID,
BOOL,
FLOAT,
INTEGER,
STRUCT,
UNION,
ERROR,
ENUM,
ARRAY,
POINTER,
VAR_ARRAY,
SUBARRAY,
OPAQUE
// ALIAS,
}
struct TypeData
{
typeid typeId;
TypeKind kind;
int size;
int alignment;
char* name;
char* fullName;
}
struct TypeAlias
{
TypeData data;
typeid aliasType;
}
struct TypeError
{
TypeData data;
TypeErrorValue[] errors;
}
struct TypeArray
{
TypeData data;
typeid elementType;
ulong elements;
}
struct TypeVarArray
{
TypeData data;
typeid elementType;
}
struct TypeSubarray
{
TypeData data;
typeid elementType;
}
struct TypePointer
{
TypeData data;
typeid baseType;
}
struct TypeStruct
{
TypeData data;
TypeData*[] fields;
}
struct TypeUnion
{
TypeData data;
TypeData*[] variants;
}
struct TypeEnum
{
TypeData data;
typeid valueType;
TypeData*[] associated_value_types;
}
struct TypeEnumValue
{
char* name;
ulong value;
void*[] associated_values;
}
struct TypeErrorValue
{
char* name;
ulong value;
}
*/

View File

@@ -1,14 +0,0 @@
module std::env;
enum CompilerOptLevel
{
O0,
O1,
O2,
O3
}
const CompilerOptLevel COMPILER_OPT_LEVEL = (CompilerOptLevel)(${COMPILER_OPT_LEVEL});
const bool BIG_ENDIAN = ${PLATFORM_BIG_ENDIAN};
const bool I128_SUPPORT = ${PLATFORM_I128_SUPPORTED};
const bool COMPILER_SAFE_MODE = ${COMPILER_SAFE_MODE};

View File

@@ -1,427 +0,0 @@
module std::io;
errtype IoError
{
FILE_NOT_FOUND
}
/*
extern File *stdin @cname(__stdinp);
extern File *stdout @cname(__stdoutp);
extern File *stderr @cname(__stderrp);
*/
/*
extern func int fputc(int, aliased void*);
extern func void clearerr(aliased void*);
extern func int fclose(aliased void*);
extern func int feof(aliased void*);
extern func int ferror(aliased void*);
extern func int fflush(aliased FILE *);
extern func int fgetc(aliased FILE *);
extern func int fgetpos(FILE *, fpos_t *);
extern func int fseek(void*, long, int);
extern func void* fopen(char *, char *);
*/
struct File
{
void *file;
}
extern func int _puts(char* message) @extname("puts");
extern func int printf(char* message, ...);
extern func int _putchar(char c) @extname("putchar");
extern File *__stdinp;
func int putchar(char c) @inline
{
return _putchar(c);
}
func int print(char *message)
{
char* pointer = message;
while (*pointer != '\0')
{
if (!putchar(*pointer)) return 0;
pointer++;
}
return 1;
}
func int println(char *message = "") @inline
{
return _puts(message);
}
/*
enum Seek
{
SET = 0,
CURSOR = 1,
END = 2
}
error FileError
{
ulong errno;
}
func FileError errorFromErrno()
{
return FileError { };
}
public func void! File.open(File *file, char *filename, char *mode)
{
file.file = fopen(filename, mode);
if (!file.file) return errorFromErrno()!;
}
public func void! File.seek(File *file, long offset, Seek seekMode = Seek.SET)
{
if (fseek(file->file, offset, (int)(seekMode))) return errorFromErrno()!;
}
public func void! File.putChar(File *file as char c)
{
if (fputc(c, file->file)) return errorFromErrno()!;
}
pubic func void! File.clearerr(File *file) @inline
{
clearerr(file->file);
}
func void File.close(File *file) @inline
{
if (fclose(file->file)) return errorFromErrno()!;
}
func void File.eof(File *file) @inline
{
int err = feof(file->file);
}
func void File.error(File *file) @inline
{
int err = ferror
}
*/
/*
#define __SLBF 0x0001 /* line buffered */
#define __SNBF 0x0002 /* unbuffered */
#define __SRD 0x0004 /* OK to read */
#define __SWR 0x0008 /* OK to write */
/* RD and WR are never simultaneously asserted */
#define __SRW 0x0010 /* open for reading & writing */
#define __SEOF 0x0020 /* found EOF */
#define __SERR 0x0040 /* found error */
#define __SMBF 0x0080 /* _buf is from malloc */
#define __SAPP 0x0100 /* fdopen()ed in append mode */
#define __SSTR 0x0200 /* this is an sprintf/snprintf string */
#define __SOPT 0x0400 /* do fseek() optimisation */
#define __SNPT 0x0800 /* do not do fseek() optimisation */
#define __SOFF 0x1000 /* set iff _offset is in fact correct */
#define __SMOD 0x2000 /* true => fgetln modified _p text */
#define __SALC 0x4000 /* allocate string space dynamically */
#define __SIGN 0x8000 /* ignore this file in _fwalk */
/*
* The following three definitions are for ANSI C, which took them
* from System V, which brilliantly took internal interface macros and
* made them official arguments to setvbuf(), without renaming them.
* Hence, these ugly _IOxxx names are *supposed* to appear in user code.
*
* Although numbered as their counterparts above, the implementation
* does not rely on this.
*/
#define _IOFBF 0 /* setvbuf should set fully buffered */
#define _IOLBF 1 /* setvbuf should set line buffered */
#define _IONBF 2 /* setvbuf should set unbuffered */
#define BUFSIZ 1024 /* size of buffer used by setbuf */
#define EOF (-1)
/* must be == _POSIX_STREAM_MAX <limits.h> */
#define FOPEN_MAX 20 /* must be <= OPEN_MAX <sys/syslimits.h> */
#define FILENAME_MAX 1024 /* must be <= PATH_MAX <sys/syslimits.h> */
/* System V/ANSI C; this is the wrong way to do this, do *not* use these. */
#ifndef _ANSI_SOURCE
#define P_tmpdir "/var/tmp/"
#endif
#define L_tmpnam 1024 /* XXX must be == PATH_MAX */
#define TMP_MAX 308915776
#define stdin __stdinp
#define stdout __stdoutp
#define stderr __stderrp
/* ANSI-C */
__BEGIN_DECLS
char *fgets(char * __restrict, int, FILE *);
#if defined(_DARWIN_UNLIMITED_STREAMS) || defined(_DARWIN_C_SOURCE)
#else /* !_DARWIN_UNLIMITED_STREAMS && !_DARWIN_C_SOURCE */
FILE *fopen(const char * __restrict __filename, const char * __restrict __mode) __DARWIN_ALIAS_STARTING(__MAC_10_6, __IPHONE_2_0, __DARWIN_ALIAS(fopen));
#endif /* (DARWIN_UNLIMITED_STREAMS || _DARWIN_C_SOURCE) */
int fprintf(FILE * __restrict, const char * __restrict, ...) __printflike(2, 3);
int fputs(const char * __restrict, FILE * __restrict) __DARWIN_ALIAS(fputs);
size_t fread(void * __restrict __ptr, size_t __size, size_t __nitems, FILE * __restrict __stream);
FILE *freopen(const char * __restrict, const char * __restrict,
FILE * __restrict) __DARWIN_ALIAS(freopen);
int fscanf(FILE * __restrict, const char * __restrict, ...) __scanflike(2, 3);
int fsetpos(FILE *, const fpos_t *);
long ftell(FILE *);
size_t fwrite(const void * __restrict __ptr, size_t __size, size_t __nitems, FILE * __restrict __stream) __DARWIN_ALIAS(fwrite);
int getc(FILE *);
int getchar(void);
char *gets(char *);
void perror(const char *) __cold;
int printf(const char * __restrict, ...) __printflike(1, 2);
int putc(int, FILE *);
int putchar(int);
int puts(const char *);
int remove(const char *);
int rename (const char *__old, const char *__new);
void rewind(FILE *);
int scanf(const char * __restrict, ...) __scanflike(1, 2);
void setbuf(FILE * __restrict, char * __restrict);
int setvbuf(FILE * __restrict, char * __restrict, int, size_t);
int sprintf(char * __restrict, const char * __restrict, ...) __printflike(2, 3) __swift_unavailable("Use snprintf instead.");
int sscanf(const char * __restrict, const char * __restrict, ...) __scanflike(2, 3);
FILE *tmpfile(void);
__swift_unavailable("Use mkstemp(3) instead.")
#if !defined(_POSIX_C_SOURCE)
__deprecated_msg("This function is provided for compatibility reasons only. Due to security concerns inherent in the design of tmpnam(3), it is highly recommended that you use mkstemp(3) instead.")
#endif
char *tmpnam(char *);
int ungetc(int, FILE *);
int vfprintf(FILE * __restrict, const char * __restrict, va_list) __printflike(2, 0);
int vprintf(const char * __restrict, va_list) __printflike(1, 0);
int vsprintf(char * __restrict, const char * __restrict, va_list) __printflike(2, 0) __swift_unavailable("Use vsnprintf instead.");
__END_DECLS
/* Additional functionality provided by:
* POSIX.1-1988
*/
#if __DARWIN_C_LEVEL >= 198808L
#define L_ctermid 1024 /* size for ctermid(); PATH_MAX */
__BEGIN_DECLS
#include <_ctermid.h>
#if defined(_DARWIN_UNLIMITED_STREAMS) || defined(_DARWIN_C_SOURCE)
FILE *fdopen(int, const char *) __DARWIN_ALIAS_STARTING(__MAC_10_6, __IPHONE_3_2, __DARWIN_EXTSN(fdopen));
#else /* !_DARWIN_UNLIMITED_STREAMS && !_DARWIN_C_SOURCE */
FILE *fdopen(int, const char *) __DARWIN_ALIAS_STARTING(__MAC_10_6, __IPHONE_2_0, __DARWIN_ALIAS(fdopen));
#endif /* (DARWIN_UNLIMITED_STREAMS || _DARWIN_C_SOURCE) */
int fileno(FILE *);
__END_DECLS
#endif /* __DARWIN_C_LEVEL >= 198808L */
/* Additional functionality provided by:
* POSIX.2-1992 C Language Binding Option
*/
#if TARGET_OS_EMBEDDED
#define __swift_unavailable_on(osx_msg, ios_msg) __swift_unavailable(ios_msg)
#else
#define __swift_unavailable_on(osx_msg, ios_msg) __swift_unavailable(osx_msg)
#endif
#if __DARWIN_C_LEVEL >= 199209L
__BEGIN_DECLS
int pclose(FILE *) __swift_unavailable_on("Use posix_spawn APIs or NSTask instead.", "Process spawning is unavailable.");
#if defined(_DARWIN_UNLIMITED_STREAMS) || defined(_DARWIN_C_SOURCE)
FILE *popen(const char *, const char *) __DARWIN_ALIAS_STARTING(__MAC_10_6, __IPHONE_3_2, __DARWIN_EXTSN(popen)) __swift_unavailable_on("Use posix_spawn APIs or NSTask instead.", "Process spawning is unavailable.");
#else /* !_DARWIN_UNLIMITED_STREAMS && !_DARWIN_C_SOURCE */
FILE *popen(const char *, const char *) __DARWIN_ALIAS_STARTING(__MAC_10_6, __IPHONE_2_0, __DARWIN_ALIAS(popen)) __swift_unavailable_on("Use posix_spawn APIs or NSTask instead.", "Process spawning is unavailable.");
#endif /* (DARWIN_UNLIMITED_STREAMS || _DARWIN_C_SOURCE) */
__END_DECLS
#endif /* __DARWIN_C_LEVEL >= 199209L */
#undef __swift_unavailable_on
/* Additional functionality provided by:
* POSIX.1c-1995,
* POSIX.1i-1995,
* and the omnibus ISO/IEC 9945-1: 1996
*/
#if __DARWIN_C_LEVEL >= 199506L
/* Functions internal to the implementation. */
__BEGIN_DECLS
int __srget(FILE *);
int __svfscanf(FILE *, const char *, va_list) __scanflike(2, 0);
int __swbuf(int, FILE *);
__END_DECLS
/*
* The __sfoo macros are here so that we can
* define function versions in the C library.
*/
#define __sgetc(p) (--(p)->_r < 0 ? __srget(p) : (int)(*(p)->_p++))
#if defined(__GNUC__) && defined(__STDC__)
__header_always_inline int __sputc(int _c, FILE *_p) {
if (--_p->_w >= 0 || (_p->_w >= _p->_lbfsize && (char)_c != '\n'))
return (*_p->_p++ = _c);
else
return (__swbuf(_c, _p));
}
#else
/*
* This has been tuned to generate reasonable code on the vax using pcc.
*/
#define __sputc(c, p) \
(--(p)->_w < 0 ? \
(p)->_w >= (p)->_lbfsize ? \
(*(p)->_p = (c)), *(p)->_p != '\n' ? \
(int)*(p)->_p++ : \
__swbuf('\n', p) : \
__swbuf((int)(c), p) : \
(*(p)->_p = (c), (int)*(p)->_p++))
#endif
#define __sfeof(p) (((p)->_flags & __SEOF) != 0)
#define __sferror(p) (((p)->_flags & __SERR) != 0)
#define __sclearerr(p) ((void)((p)->_flags &= ~(__SERR|__SEOF)))
#define __sfileno(p) ((p)->_file)
__BEGIN_DECLS
void flockfile(FILE *);
int ftrylockfile(FILE *);
void funlockfile(FILE *);
int getc_unlocked(FILE *);
int getchar_unlocked(void);
int putc_unlocked(int, FILE *);
int putchar_unlocked(int);
/* Removed in Issue 6 */
#if !defined(_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 200112L
int getw(FILE *);
int putw(int, FILE *);
#endif
__swift_unavailable("Use mkstemp(3) instead.")
#if !defined(_POSIX_C_SOURCE)
__deprecated_msg("This function is provided for compatibility reasons only. Due to security concerns inherent in the design of tempnam(3), it is highly recommended that you use mkstemp(3) instead.")
#endif
char *tempnam(const char *__dir, const char *__prefix) __DARWIN_ALIAS(tempnam);
__END_DECLS
#ifndef lint
#define getc_unlocked(fp) __sgetc(fp)
#define putc_unlocked(x, fp) __sputc(x, fp)
#endif /* lint */
#define getchar_unlocked() getc_unlocked(stdin)
#define putchar_unlocked(x) putc_unlocked(x, stdout)
#endif /* __DARWIN_C_LEVEL >= 199506L */
/* Additional functionality provided by:
* POSIX.1-2001
* ISO C99
*/
#if __DARWIN_C_LEVEL >= 200112L
#include <sys/_types/_off_t.h>
__BEGIN_DECLS
int fseeko(FILE * __stream, off_t __offset, int __whence);
off_t ftello(FILE * __stream);
__END_DECLS
#endif /* __DARWIN_C_LEVEL >= 200112L */
#if __DARWIN_C_LEVEL >= 200112L || defined(_C99_SOURCE) || defined(__cplusplus)
__BEGIN_DECLS
int snprintf(char * __restrict __str, size_t __size, const char * __restrict __format, ...) __printflike(3, 4);
int vfscanf(FILE * __restrict __stream, const char * __restrict __format, va_list) __scanflike(2, 0);
int vscanf(const char * __restrict __format, va_list) __scanflike(1, 0);
int vsnprintf(char * __restrict __str, size_t __size, const char * __restrict __format, va_list) __printflike(3, 0);
int vsscanf(const char * __restrict __str, const char * __restrict __format, va_list) __scanflike(2, 0);
__END_DECLS
#endif /* __DARWIN_C_LEVEL >= 200112L || defined(_C99_SOURCE) || defined(__cplusplus) */
/* Additional functionality provided by:
* POSIX.1-2008
*/
#if __DARWIN_C_LEVEL >= 200809L
#include <sys/_types/_ssize_t.h>
__BEGIN_DECLS
int dprintf(int, const char * __restrict, ...) __printflike(2, 3) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
int vdprintf(int, const char * __restrict, va_list) __printflike(2, 0) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
ssize_t getdelim(char ** __restrict __linep, size_t * __restrict __linecapp, int __delimiter, FILE * __restrict __stream) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
ssize_t getline(char ** __restrict __linep, size_t * __restrict __linecapp, FILE * __restrict __stream) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
FILE *fmemopen(void * __restrict __buf, size_t __size, const char * __restrict __mode) __API_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0));
FILE *open_memstream(char **__bufp, size_t *__sizep) __API_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0));
__END_DECLS
#endif /* __DARWIN_C_LEVEL >= 200809L */
/* Darwin extensions */
#if __DARWIN_C_LEVEL >= __DARWIN_C_FULL
__BEGIN_DECLS
extern __const int sys_nerr; /* perror(3) external variables */
extern __const char *__const sys_errlist[];
int asprintf(char ** __restrict, const char * __restrict, ...) __printflike(2, 3);
char *ctermid_r(char *);
char *fgetln(FILE *, size_t *);
__const char *fmtcheck(const char *, const char *);
int fpurge(FILE *);
void setbuffer(FILE *, char *, int);
int setlinebuf(FILE *);
int vasprintf(char ** __restrict, const char * __restrict, va_list) __printflike(2, 0);
FILE *zopen(const char *, const char *, int);
/*
* Stdio function-access interface.
*/
FILE *funopen(const void *,
int (* _Nullable)(void *, char *, int),
int (* _Nullable)(void *, const char *, int),
fpos_t (* _Nullable)(void *, fpos_t, int),
int (* _Nullable)(void *));
__END_DECLS
#define fropen(cookie, fn) funopen(cookie, fn, 0, 0, 0)
#define fwopen(cookie, fn) funopen(cookie, 0, fn, 0, 0)
#define feof_unlocked(p) __sfeof(p)
#define ferror_unlocked(p) __sferror(p)
#define clearerr_unlocked(p) __sclearerr(p)
#define fileno_unlocked(p) __sfileno(p)
#endif /* __DARWIN_C_LEVEL >= __DARWIN_C_FULL */
#ifdef _USE_EXTENDED_LOCALES_
#include <xlocale/_stdio.h>
#endif /* _USE_EXTENDED_LOCALES_ */
#if defined (__GNUC__) && _FORTIFY_SOURCE > 0 && !defined (__cplusplus)
/* Security checking functions. */
#include <secure/_stdio.h>
#endif
#endif /* _STDIO_H_ */
*/

View File

@@ -1,155 +0,0 @@
module std::array::list<Type>;
import std::mem;
struct List
{
usize size;
usize capacity;
Type *entries;
}
private func void List.ensureCapacity(List *list) @inline
{
if (list.capacity == list.size)
{
list.capacity = list.capacity ? 2 * list.capacity : 16;
list.entries = mem::realloc(list.entries, $sizeof(Type) * list.capacity);
}
}
func void List.push(List *list, Type element) @inline
{
list.append(element);
}
func void List.append(List *list, Type element)
{
list.ensureCapacity();
list.entries[list.size++] = element;
}
/**
* @require list.size > 0
*/
func Type List.pop(List *list)
{
return list.entries[--list.size];
}
/**
* @require list.size > 0
*/
func Type List.popFirst(List *list)
{
Type value = list.entries[0];
list.removeAt(0);
return value;
}
func void List.removeAt(List *list, usize index)
{
for (usize i = index + 1; i < list.size; i++)
{
list.entries[i - 1] = list.entries[i];
}
list.size--;
}
func void List.pushFront(List *list, Type type) @inline
{
list.insertAt(0, type);
}
func void List.insertAt(List *list, usize index, Type type)
{
list.ensureCapacity();
for (usize i = list.size; i > index; i--)
{
list.entries[i] = list.entries[i - 1];
}
list.size++;
list.entries[index] = type;
}
func void List.removeLast(List *list)
{
list.size--;
}
func void List.removeFirst(List *list)
{
list.removeAt(0);
}
func Type* List.first(List *list)
{
return list.size ? &list.entries[0] : null;
}
func Type* List.last(List *list)
{
return list.size ? &list.entries[list.size - 1] : null;
}
func bool List.isEmpty(List *list)
{
return list.size;
}
func usize List.len(List *list)
{
return list.size;
}
func Type List.get(List *list, usize index)
{
return list.entries[index];
}
func void List.free(List *list)
{
mem::free(list.entries);
list.capacity = 0;
list.size = 0;
}
/*
operator for(List *list; index, Type type)
{
$IndexType = typeof(index);
$IndexType last_index = ($IndexType)(list.size);
for ($IndexType i = 0; i < last_index; i++)
{
yield(i, list.entries[index]);
}
}
operator for(List *list; index, Type *type)
{
$IndexType = typeof(index);
$IndexType last_index = ($IndexType)(list.size);
for ($IndexType i = 0; i < last_index; i++)
{
yield(i, &list.entries[index]);
}
}
operator for(List *list; Type *type)
{
usize size = list.size;
for (usize i = 0; i < last_index; i++)
{
yield(i, &list.entries[index]);
}
}
*/
/*
operator for(List *list; Type type)
{
usize size = list.size;
for (usize i = 0; i < last_index; i++)
{
yield(i, list.entries[index]);
}
}*/

View File

@@ -1,233 +0,0 @@
module std::math;
// TODO Define these using quad precision.
const E = 2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427427466;
const LOG2E = 1.44269504088896340735992468100189214; // log2(e)
const LOG10E = 0.434294481903251827651128918916605082; // log10(e)
const LN2 = 0.693147180559945309417232121458176568; // ln(2)
const LN10 = 2.30258509299404568401799145468436421; // ln(10)
const PI = 3.14159265358979323846264338327950288419716939937510; // pi
const PI_2 = 1.57079632679489661923132169163975144; // pi / 2
const PI_4 = 0.785398163397448309615660845819875721; // pi / 4
const DIV_PI = 0.318309886183790671537767526745028724; // 1 / pi
const DIV_2_PI = 0.636619772367581343075535053490057448; // 2 / pi
const DIV_2_SQRTPI = 1.12837916709551257389615890312154517; // 2/sqrt(pi)
const SQRT2 = 1.41421356237309504880168872420969808; // sqrt(2)
const DIV_1_SQRT2 = 0.707106781186547524400844362104849039; // 1 / sqrt(2)
const HALF_MAX = 6.5504e+4;
const HALF_MIN = 6.103515625e-5;
const HALF_DENORM_MIN = 5.9604644775390625e-8;
const HALF_DIG = 3;
const HALF_DEC_DIGITS = 5;
const HALF_MANT_DIG = 11;
const HALF_MAX_10_EXP = 4;
const HALF_MIN_10_EXP = -4;
const HALF_MAX_EXP = 16;
const HALF_MIN_EXP = -13;
const HALF_EPSILON = 9.765625e-4;
const FLOAT_MAX = 0x1.fffffep+127;
const FLOAT_MIN = 1.17549435e-38;
const FLOAT_DENORM_MIN = 1.40129846432481707092e-45;
const FLOAT_DIG = 6;
const FLOAT_DEC_DIGITS = 9;
const FLOAT_MANT_DIG = 24;
const FLOAT_MAX_10_EXP = 38;
const FLOAT_MIN_10_EXP = -37;
const FLOAT_MAX_EXP = 128;
const FLOAT_MIN_EXP = -125;
const FLOAT_EPSILON = 1.1920928955078125e-07;
const DOUBLE_MAX = 1.79769313486231570815e+308;
const DOUBLE_MIN = 2.2250738585072014e-308;
const DOUBLE_DENORM_MIN = 4.94065645841246544177e-324;
const DOUBLE_DIG = 15;
const DOUBLE_DEC_DIGITS = 17;
const DOUBLE_MANT_DIG = 53;
const DOUBLE_MAX_10_EXP = 308;
const DOUBLE_MIN_10_EXP = -307;
const DOUBLE_MAX_EXP = 1024;
const DOUBLE_MIN_EXP = -1021;
const DOUBLE_EPSILON = 2.22044604925031308085e-16;
const QUAD_MAX = 1.18973149535723176508575932662800702e+4932;
const QUAD_MIN = 3.36210314311209350626267781732175260e-4932;
const QUAD_DENORM_MIN = 6.47517511943802511092443895822764655e-4966;
const QUAD_DIG = 33;
const QUAD_DEC_DIGITS = 36;
const QUAD_MANT_DIG = 113;
const QUAD_MAX_10_EXP = 4932;
const QUAD_MIN_10_EXP = -4931;
const QUAD_MAX_EXP = 16384;
const QUAD_MIN_EXP = -16481;
const QUAD_EPSILON = 1.92592994438723585305597794258492732e-34;
private union DoubleLong
{
double f;
ulong i;
}
func double log10(double x)
{
const double IVLN10HI = 4.34294481878168880939e-01; /* 0x3fdbcb7b, 0x15200000 */
const double IVLN10LO = 2.50829467116452752298e-11; /* 0x3dbb9438, 0xca9aadd5 */
const double LOG10_2HI = 3.01029995663611771306e-01; /* 0x3FD34413, 0x509F6000 */
const double LOG10_2LO = 3.69423907715893078616e-13; /* 0x3D59FEF3, 0x11F12B36 */
const double LG1 = 6.666666666666735130e-01; /* 3FE55555 55555593 */
const double LG2 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */
const double LG3 = 2.857142874366239149e-01; /* 3FD24924 94229359 */
const double LG4 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */
const double LG5 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */
const double LG6 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */
const double LG7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */
DoubleLong u = { .f = x };
ulong hx = (uint)(u.i >> 32);
int k = 0;
if (hx < 0x00100000 || hx >> 31)
{
if (u.i << 1 == 0) return -1 / (x * x); /* log(+-0)=-inf */
if (hx >> 31) return (x - x) / 0.0; /* log(-#) = NaN */
/* subnormal number, scale x up */
k -= 54;
x *= 0x1p54;
u.f = x;
hx = (uint)(u.i >> 32);
}
else if (hx >= 0x7ff00000)
{
return x;
}
else if (hx == 0x3ff00000 && u.i << 32 == 0)
{
return 0;
}
/* reduce x into [sqrt(2)/2, sqrt(2)] */
hx += 0x3ff00000 - 0x3fe6a09e;
k += (int)(hx >> 20) - 0x3ff;
hx = (hx & 0x000fffff) + 0x3fe6a09e;
u.i = (ulong)(hx << 32) | (u.i & 0xffffffff);
x = u.f;
hx += 0x3ff00000 - 0x3fe6a09e;
k += (int)(hx >> 20) - 0x3ff;
hx = (hx & 0x000fffff) + 0x3fe6a09e;
u.i = (ulong)(hx << 32) | (u.i & 0xffffffff);
x = u.f;
double f = x - 1.0;
double hfsq = 0.5 * f * f;
double s = f / (2.0+f);
double z = s * s;
double w = z * z;
double t1 = w * (LG2 + w * (LG4 + w * LG6));
double t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7)));
double r = t2 + t1;
/* See log2.c for details. */
/* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */
double hi = f - hfsq;
u.f = hi;
// u.i &= (ulong)(-1) << 32;
u.i &= 0xFFFFFFFF00000000;
hi = u.f;
double lo = f - hi - hfsq + s * (hfsq + r);
/* val_hi+val_lo ~ log10(1+f) + k*log10(2) */
double val_hi = hi * IVLN10HI;
double dk = k;
double y = dk * LOG10_2HI;
double val_lo = dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo*IVLN10HI;
/*
* Extra precision in for adding y is not strictly needed
* since there is no very large cancellation near x = sqrt(2) or
* x = 1/sqrt(2), but we do it anyway since it costs little on CPUs
* with some parallelism and it reduces the error for many args.
*/
w = y + val_hi;
val_lo += (y - w) + val_hi;
val_hi = w;
return val_lo + val_hi;
}
func double cos_limited(double x, double y)
{
const double C1 = 4.16666666666666019037e-02; /* 0x3FA55555, 0x5555554C */
const double C2 = -1.38888888888741095749e-03; /* 0xBF56C16C, 0x16C15177 */
const double C3 = 2.48015872894767294178e-05; /* 0x3EFA01A0, 0x19CB1590 */
const double C4 = -2.75573143513906633035e-07; /* 0xBE927E4F, 0x809C52AD */
const double C5 = 2.08757232129817482790e-09; /* 0x3E21EE9E, 0xBDB4B1C4 */
const double C6 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */
double z = x * x;
double w = z * z;
double r = z * (C1+ z * (C2 + z * C3)) + w * w * (C4 + z * (C5 + z * C6));
double hz = 0.5 * z;
w = 1.0 - hz;
return w + (((1.0 - w) - hz) + (z*r - x*y));
}
private func double sin_limited(double x, double y, bool iy)
{
const double S1 = -1.66666666666666324348e-01; // 0xBFC55555, 0x55555549
const double S2 = 8.33333333332248946124e-03; // 0x3F811111, 0x1110F8A6
const double S3 = -1.98412698298579493134e-04; // 0xBF2A01A0, 0x19C161D5
const double S4 = 2.75573137070700676789e-06; // 0x3EC71DE3, 0x57B1FE7D
const double S5 = -2.50507602534068634195e-08; // 0xBE5AE5E6, 0x8A2B9CEB
const double S6 = 1.58969099521155010221e-10; // 0x3DE5D93A, 0x5ACFD57C
double z = x * x;
double w = z * z;
double r = S2 + z * (S3 + z * S4) + z * w * (S5 + z * S6);
double v = z * x;
if (!iy)
{
return x + v * (S1 + z * r);
}
else
{
return x - ((z * (0.5 * y - v * r) - y) - v * S1);
}
}
/*
public func double cos(double x)
{
double[2] y;
uint32_t ix;
unsigned n;
GET_HIGH_WORD(ix, x);
ix &= 0x7fffffff;
/* |x| ~< pi/4 */
if (ix <= 0x3fe921fb)
{
if (ix < 0x3e46a09e)
{
// |x| < 2**-27 * sqrt(2)
/* raise inexact if x!=0 */
FORCE_EVAL(x + 0x1p120f);
return 1.0;
}
return cos_limited(x, 0);
}
/* cos(Inf or NaN) is NaN */
if (ix >= 0x7ff00000) return x - x;
/* argument reduction */
n = __rem_pio2(x, y);
switch (n&3)
{
case 0: return cos_limited(y[0], y[1]);
case 1: return -sin_limited(y[0], y[1], true);
case 2: return -cos_limited(y[0], y[1]);
default:
return sin_limited(y[0], y[1], true);
}
}
*/

View File

@@ -1,9 +1,7 @@
module antiprime;
import std::io;
extern func int printf(char* message, ...);
func int countDivisors(int n)
fn int countDivisors(int n)
{
if (n < 2) return 1;
int count = 2;
@@ -14,7 +12,7 @@ func int countDivisors(int n)
return count;
}
func int main()
fn int main()
{
int maxDiv;
int count;
@@ -25,7 +23,7 @@ func int main()
int d = countDivisors(n);
if (d > maxDiv)
{
printf("%d ", n);
io::printf("%d ", n);
maxDiv = d;
count++;
}

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