mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-11 22:01:25 -07:00
Compare commits
156 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6e1864d21c | |||
| fb2d611dcd | |||
| 9e8c9be1ea | |||
| 9bc37f4400 | |||
| f29e303ce7 | |||
| 3c9143957c | |||
| 18b3c0b2fc | |||
| c59f6b7d0b | |||
| 67ed8a9a4a | |||
| 4cc4d604bc | |||
| eec709c545 | |||
| 9b2f5c359a | |||
| a982c51c30 | |||
| 047c0e4bcc | |||
| a94dfdf21d | |||
| c0d5237b75 | |||
| 6fdcbefe5d | |||
| 3cec2550d9 | |||
| 758dd9ba16 | |||
| 0c37aa9ea0 | |||
| 9ff474f387 | |||
| d2f9d20833 | |||
| 71100ed427 | |||
| 3ecf3505fd | |||
| daa1cd55a1 | |||
| 2722de65b7 | |||
| 8b5e3428a1 | |||
| d1f65097c4 | |||
| 74d15ab84b | |||
| 763cd2649d | |||
| bd27c24fab | |||
| 282f8bb06f | |||
| b9ed546ce0 | |||
| e1fdd675ce | |||
| 4306345ff1 | |||
| 346aa5f71c | |||
| 73d6a55f5c | |||
| f18ae89931 | |||
| 454d0b5cf5 | |||
| 219ca0ac46 | |||
| 5796c41357 | |||
| 8cfae17535 | |||
| df78b8ad3e | |||
| f11d73ffaa | |||
| c126339090 | |||
| 9f2d9b596d | |||
| 00c7489157 | |||
| b1562edccf | |||
| 2a5b674d33 | |||
| 7944b7714f | |||
| 205f4664f8 | |||
| c6133587d1 | |||
| 5516e80ab7 | |||
| 864310e3da | |||
| 4e7082a68d | |||
| 502e63b9c5 | |||
| 34150385d8 | |||
| 0ca1b4612c | |||
| 9e143a38ce | |||
| 43be91bca3 | |||
| 984e36a151 | |||
| ec9c8fb8a4 | |||
| 3e79ec4aef | |||
| 3e257ef8d0 | |||
| 626f91f307 | |||
| e86c990b75 | |||
| 31aacd5bf4 | |||
| 92453369c5 | |||
| 832009f33a | |||
| d3d3bfd455 | |||
| ce3582fd89 | |||
| e3e16f5d05 | |||
| f47f25f942 | |||
| e85458919c | |||
| b59a052e32 | |||
| 12498b2d39 | |||
| 6d93aa429f | |||
| 3f023509a7 | |||
| 563b1e2b28 | |||
| 4603d2525e | |||
| 2af9fb79dc | |||
| 367d307dc4 | |||
| cb59c1cf08 | |||
| 383f5b55ad | |||
| 6dc6b6f8aa | |||
| ac736aa4ec | |||
| 6fe25badf0 | |||
| c29d433e38 | |||
| ff473e8342 | |||
| 659e5359b2 | |||
| d9ce0b9da0 | |||
| 703e1aa2bc | |||
| b1e35b6da3 | |||
| fc1af0a04b | |||
| 4afb3f8fa4 | |||
| 207b252f23 | |||
| 1356dfeec2 | |||
| d025791462 | |||
| b07ee9ec23 | |||
| 915b5cdab7 | |||
| c8f99b360f | |||
| b76f6a8c27 | |||
| cff1b3dff6 | |||
| 883dd0642c | |||
| 40f5dd56f7 | |||
| 70d4ca00df | |||
| a86896e4d3 | |||
| a3883a178c | |||
| ce89a1428e | |||
| 9202bd1b06 | |||
| a48e0c7179 | |||
| 3f1195cd03 | |||
| 311b5cb6e2 | |||
| 6fef74317c | |||
| 0c6775ca14 | |||
| 6748f305db | |||
| 2ecafda1d3 | |||
| 23d32f34e5 | |||
| d714bece47 | |||
| 923b039cf6 | |||
| d0e1efe622 | |||
| 478d63424f | |||
| ac1566762b | |||
| f5eeecaca5 | |||
| 77e219d442 | |||
| 4c10fbdcd4 | |||
| e370337f97 | |||
| 5217eb55b4 | |||
| 062a2c63e1 | |||
| b957365b0d | |||
| 625b98eac4 | |||
| 0f809989e3 | |||
| d4457e9fa4 | |||
| 9634b28b07 | |||
| f567983260 | |||
| ad84314143 | |||
| a6f8c9d6e0 | |||
| de9016b7d0 | |||
| e8b4228833 | |||
| 0d69dfcde6 | |||
| fa89d2775a | |||
| 60b6538a7a | |||
| d9bd770992 | |||
| 517b34f798 | |||
| a16bdb215a | |||
| 88aa74bbb9 | |||
| 8ec9811d7a | |||
| c71b547cde | |||
| 76e724718c | |||
| 0b87313f08 | |||
| 4bb45700a5 | |||
| be8b9bda2f | |||
| ab2ca7cf59 | |||
| b76c8abe73 | |||
| d9c686b53d | |||
| b232b9d5ea |
@@ -255,3 +255,4 @@ paket-files/
|
|||||||
!misc/llvm-bim/lli.exe
|
!misc/llvm-bim/lli.exe
|
||||||
!misc/llvm-bim/opt.exe
|
!misc/llvm-bim/opt.exe
|
||||||
builds
|
builds
|
||||||
|
bin
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
# The Odin Programming Language
|
# The Odin Programming Language
|
||||||
|
|
||||||
Odin is fast, concise, readable, pragmatic and open sourced. It is designed with the intent of replacing C with the following goals:
|
The Odin programming language is fast, concise, readable, pragmatic and open sourced. It is designed with the intent of replacing C with the following goals:
|
||||||
* simplicity
|
* simplicity
|
||||||
* high performance
|
* high performance
|
||||||
* built for modern systems
|
* built for modern systems
|
||||||
@@ -18,6 +18,7 @@ Odin is fast, concise, readable, pragmatic and open sourced. It is designed with
|
|||||||
* [Composition & Refactorability](https://www.youtube.com/watch?v=n1wemZfcbXM)
|
* [Composition & Refactorability](https://www.youtube.com/watch?v=n1wemZfcbXM)
|
||||||
* [Introspection, Modules, and Record Layout](https://www.youtube.com/watch?v=UFq8rhWhx4s)
|
* [Introspection, Modules, and Record Layout](https://www.youtube.com/watch?v=UFq8rhWhx4s)
|
||||||
* [push_allocator & Minimal Dependency Building](https://www.youtube.com/watch?v=f_LGVOAMb78)
|
* [push_allocator & Minimal Dependency Building](https://www.youtube.com/watch?v=f_LGVOAMb78)
|
||||||
|
* [when, for, & procedure overloading](https://www.youtube.com/watch?v=OzeOekzyZK8)
|
||||||
|
|
||||||
## Requirements to build and run
|
## Requirements to build and run
|
||||||
|
|
||||||
@@ -34,7 +35,7 @@ Odin is fast, concise, readable, pragmatic and open sourced. It is designed with
|
|||||||
|
|
||||||
## Roadmap
|
## Roadmap
|
||||||
|
|
||||||
Not in any particular order
|
Not in any particular order and not be implemented
|
||||||
|
|
||||||
* Compile Time Execution (CTE)
|
* Compile Time Execution (CTE)
|
||||||
- More metaprogramming madness
|
- More metaprogramming madness
|
||||||
@@ -44,17 +45,11 @@ Not in any particular order
|
|||||||
* Replace LLVM backend with my own custom backend
|
* Replace LLVM backend with my own custom backend
|
||||||
* Improve SSA design to accommodate for lowering to a "bytecode"
|
* Improve SSA design to accommodate for lowering to a "bytecode"
|
||||||
* SSA optimizations
|
* SSA optimizations
|
||||||
* Parametric Polymorphism ("Generics")
|
|
||||||
* Documentation Generator for "Entities"
|
* Documentation Generator for "Entities"
|
||||||
* Multiple Architecture support
|
* Multiple Architecture support
|
||||||
* Language level atomics and concurrency support
|
|
||||||
* Linking Options
|
|
||||||
- Executable
|
|
||||||
- Static/Dynamic Library
|
|
||||||
* Debug Information
|
* Debug Information
|
||||||
- pdb format too
|
- pdb format too
|
||||||
* Command Line Tooling
|
* Command Line Tooling
|
||||||
* Compiler Internals:
|
* Compiler Internals:
|
||||||
- Big numbers library
|
- Big numbers library
|
||||||
- Cyclic Type Checking (at the moment will cause compiler to go into an infinite loop)
|
|
||||||
- Multithreading for performance increase
|
- Multithreading for performance increase
|
||||||
|
|||||||
@@ -1,200 +0,0 @@
|
|||||||
This file is a list of the people responsible for ensuring that patches for a
|
|
||||||
particular part of LLVM are reviewed, either by themself or by someone else.
|
|
||||||
They are also the gatekeepers for their part of LLVM, with the final word on
|
|
||||||
what goes in or not.
|
|
||||||
|
|
||||||
The list is sorted by surname and formatted to allow easy grepping and
|
|
||||||
beautification by scripts. The fields are: name (N), email (E), web-address
|
|
||||||
(W), PGP key ID and fingerprint (P), description (D), and snail-mail address
|
|
||||||
(S). Each entry should contain at least the (N), (E) and (D) fields.
|
|
||||||
|
|
||||||
N: Joe Abbey
|
|
||||||
E: jabbey@arxan.com
|
|
||||||
D: LLVM Bitcode (lib/Bitcode/* include/llvm/Bitcode/*)
|
|
||||||
|
|
||||||
N: Owen Anderson
|
|
||||||
E: resistor@mac.com
|
|
||||||
D: SelectionDAG (lib/CodeGen/SelectionDAG/*)
|
|
||||||
|
|
||||||
N: Rafael Avila de Espindola
|
|
||||||
E: rafael.espindola@gmail.com
|
|
||||||
D: Gold plugin (tools/gold/*)
|
|
||||||
|
|
||||||
N: Justin Bogner
|
|
||||||
E: mail@justinbogner.com
|
|
||||||
D: InstrProfiling and related parts of ProfileData
|
|
||||||
|
|
||||||
N: Chandler Carruth
|
|
||||||
E: chandlerc@gmail.com
|
|
||||||
E: chandlerc@google.com
|
|
||||||
D: Config, ADT, Support, inlining & related passes, SROA/mem2reg & related passes, CMake, library layering
|
|
||||||
|
|
||||||
N: Evan Cheng
|
|
||||||
E: evan.cheng@apple.com
|
|
||||||
D: parts of code generator not covered by someone else
|
|
||||||
|
|
||||||
N: Eric Christopher
|
|
||||||
E: echristo@gmail.com
|
|
||||||
D: Debug Information, autotools/configure/make build, inline assembly
|
|
||||||
|
|
||||||
N: Greg Clayton
|
|
||||||
E: gclayton@apple.com
|
|
||||||
D: LLDB
|
|
||||||
|
|
||||||
N: Marshall Clow
|
|
||||||
E: mclow.lists@gmail.com
|
|
||||||
D: libc++
|
|
||||||
|
|
||||||
N: Peter Collingbourne
|
|
||||||
E: peter@pcc.me.uk
|
|
||||||
D: llgo
|
|
||||||
|
|
||||||
N: Quentin Colombet
|
|
||||||
E: qcolombet@apple.com
|
|
||||||
D: Register allocators
|
|
||||||
|
|
||||||
N: Duncan P. N. Exon Smith
|
|
||||||
E: dexonsmith@apple.com
|
|
||||||
D: Branch weights and BlockFrequencyInfo
|
|
||||||
|
|
||||||
N: Hal Finkel
|
|
||||||
E: hfinkel@anl.gov
|
|
||||||
D: BBVectorize, the loop reroller, alias analysis and the PowerPC target
|
|
||||||
|
|
||||||
N: Dan Gohman
|
|
||||||
E: sunfish@mozilla.com
|
|
||||||
D: WebAssembly Backend (lib/Target/WebAssembly/*)
|
|
||||||
|
|
||||||
N: Renato Golin
|
|
||||||
E: renato.golin@linaro.org
|
|
||||||
D: ARM Linux support
|
|
||||||
|
|
||||||
N: Venkatraman Govindaraju
|
|
||||||
E: venkatra@cs.wisc.edu
|
|
||||||
D: Sparc Backend (lib/Target/Sparc/*)
|
|
||||||
|
|
||||||
N: Tobias Grosser
|
|
||||||
E: tobias@grosser.es
|
|
||||||
D: Polly
|
|
||||||
|
|
||||||
N: James Grosbach
|
|
||||||
E: grosbach@apple.com
|
|
||||||
D: MC layer
|
|
||||||
|
|
||||||
N: Justin Holewinski
|
|
||||||
E: jholewinski@nvidia.com
|
|
||||||
D: NVPTX Target (lib/Target/NVPTX/*)
|
|
||||||
|
|
||||||
N: Lang Hames
|
|
||||||
E: lhames@gmail.com
|
|
||||||
D: MCJIT, RuntimeDyld and JIT event listeners
|
|
||||||
|
|
||||||
N: Galina Kistanova
|
|
||||||
E: gkistanova@gmail.com
|
|
||||||
D: LLVM Buildbot
|
|
||||||
|
|
||||||
N: Anton Korobeynikov
|
|
||||||
E: anton@korobeynikov.info
|
|
||||||
D: Exception handling, Windows codegen, ARM EABI
|
|
||||||
|
|
||||||
N: Benjamin Kramer
|
|
||||||
E: benny.kra@gmail.com
|
|
||||||
D: DWARF Parser
|
|
||||||
|
|
||||||
N: Sergei Larin
|
|
||||||
E: slarin@codeaurora.org
|
|
||||||
D: VLIW Instruction Scheduling, Packetization
|
|
||||||
|
|
||||||
N: Chris Lattner
|
|
||||||
E: sabre@nondot.org
|
|
||||||
W: http://nondot.org/~sabre/
|
|
||||||
D: Everything not covered by someone else
|
|
||||||
|
|
||||||
N: David Majnemer
|
|
||||||
E: david.majnemer@gmail.com
|
|
||||||
D: IR Constant Folder, InstCombine
|
|
||||||
|
|
||||||
N: Dylan McKay
|
|
||||||
E: dylanmckay34@gmail.com
|
|
||||||
D: AVR Backend
|
|
||||||
|
|
||||||
N: Tim Northover
|
|
||||||
E: t.p.northover@gmail.com
|
|
||||||
D: AArch64 backend, misc ARM backend
|
|
||||||
|
|
||||||
N: Diego Novillo
|
|
||||||
E: dnovillo@google.com
|
|
||||||
D: SampleProfile and related parts of ProfileData
|
|
||||||
|
|
||||||
N: Jakob Olesen
|
|
||||||
E: stoklund@2pi.dk
|
|
||||||
D: TableGen
|
|
||||||
|
|
||||||
N: Richard Osborne
|
|
||||||
E: richard@xmos.com
|
|
||||||
D: XCore Backend
|
|
||||||
|
|
||||||
N: Krzysztof Parzyszek
|
|
||||||
E: kparzysz@codeaurora.org
|
|
||||||
D: Hexagon Backend
|
|
||||||
|
|
||||||
N: Paul Robinson
|
|
||||||
E: paul_robinson@playstation.sony.com
|
|
||||||
D: Sony PlayStation®4 support
|
|
||||||
|
|
||||||
N: Chad Rosier
|
|
||||||
E: mcrosier@codeaurora.org
|
|
||||||
D: Fast-Isel
|
|
||||||
|
|
||||||
N: Nadav Rotem
|
|
||||||
E: nrotem@apple.com
|
|
||||||
D: X86 Backend, Loop Vectorizer
|
|
||||||
|
|
||||||
N: Daniel Sanders
|
|
||||||
E: daniel.sanders@imgtec.com
|
|
||||||
D: MIPS Backend (lib/Target/Mips/*)
|
|
||||||
|
|
||||||
N: Duncan Sands
|
|
||||||
E: baldrick@free.fr
|
|
||||||
D: DragonEgg
|
|
||||||
|
|
||||||
N: Kostya Serebryany
|
|
||||||
E: kcc@google.com
|
|
||||||
D: AddressSanitizer, ThreadSanitizer (LLVM parts)
|
|
||||||
|
|
||||||
N: Michael Spencer
|
|
||||||
E: bigcheesegs@gmail.com
|
|
||||||
D: Windows parts of Support, Object, ar, nm, objdump, ranlib, size
|
|
||||||
|
|
||||||
N: Alexei Starovoitov
|
|
||||||
E: alexei.starovoitov@gmail.com
|
|
||||||
D: BPF backend
|
|
||||||
|
|
||||||
N: Tom Stellard
|
|
||||||
E: thomas.stellard@amd.com
|
|
||||||
E: mesa-dev@lists.freedesktop.org
|
|
||||||
D: Release manager for the 3.5 and 3.6 branches, R600 Backend, libclc
|
|
||||||
|
|
||||||
N: Evgeniy Stepanov
|
|
||||||
E: eugenis@google.com
|
|
||||||
D: MemorySanitizer (LLVM part)
|
|
||||||
|
|
||||||
N: Andrew Trick
|
|
||||||
E: atrick@apple.com
|
|
||||||
D: IndVar Simplify, Loop Strength Reduction, Instruction Scheduling
|
|
||||||
|
|
||||||
N: Ulrich Weigand
|
|
||||||
E: uweigand@de.ibm.com
|
|
||||||
D: SystemZ Backend
|
|
||||||
|
|
||||||
N: Bill Wendling
|
|
||||||
E: isanbard@gmail.com
|
|
||||||
D: libLTO, IR Linker
|
|
||||||
|
|
||||||
N: Peter Zotov
|
|
||||||
E: whitequark@whitequark.org
|
|
||||||
D: OCaml bindings
|
|
||||||
|
|
||||||
N: Andrey Churbanov
|
|
||||||
E: andrey.churbanov@intel.com
|
|
||||||
D: OpenMP runtime library
|
|
||||||
-467
@@ -1,467 +0,0 @@
|
|||||||
This file is a partial list of people who have contributed to the LLVM
|
|
||||||
project. If you have contributed a patch or made some other contribution to
|
|
||||||
LLVM, please submit a patch to this file to add yourself, and it will be
|
|
||||||
done!
|
|
||||||
|
|
||||||
The list is sorted by surname and formatted to allow easy grepping and
|
|
||||||
beautification by scripts. The fields are: name (N), email (E), web-address
|
|
||||||
(W), PGP key ID and fingerprint (P), description (D), snail-mail address
|
|
||||||
(S), and (I) IRC handle.
|
|
||||||
|
|
||||||
|
|
||||||
N: Vikram Adve
|
|
||||||
E: vadve@cs.uiuc.edu
|
|
||||||
W: http://www.cs.uiuc.edu/~vadve/
|
|
||||||
D: The Sparc64 backend, provider of much wisdom, and motivator for LLVM
|
|
||||||
|
|
||||||
N: Owen Anderson
|
|
||||||
E: resistor@mac.com
|
|
||||||
D: LCSSA pass and related LoopUnswitch work
|
|
||||||
D: GVNPRE pass, DataLayout refactoring, random improvements
|
|
||||||
|
|
||||||
N: Henrik Bach
|
|
||||||
D: MingW Win32 API portability layer
|
|
||||||
|
|
||||||
N: Aaron Ballman
|
|
||||||
E: aaron@aaronballman.com
|
|
||||||
D: __declspec attributes, Windows support, general bug fixing
|
|
||||||
|
|
||||||
N: Nate Begeman
|
|
||||||
E: natebegeman@mac.com
|
|
||||||
D: PowerPC backend developer
|
|
||||||
D: Target-independent code generator and analysis improvements
|
|
||||||
|
|
||||||
N: Daniel Berlin
|
|
||||||
E: dberlin@dberlin.org
|
|
||||||
D: ET-Forest implementation.
|
|
||||||
D: Sparse bitmap
|
|
||||||
|
|
||||||
N: David Blaikie
|
|
||||||
E: dblaikie@gmail.com
|
|
||||||
D: General bug fixing/fit & finish, mostly in Clang
|
|
||||||
|
|
||||||
N: Neil Booth
|
|
||||||
E: neil@daikokuya.co.uk
|
|
||||||
D: APFloat implementation.
|
|
||||||
|
|
||||||
N: Misha Brukman
|
|
||||||
E: brukman+llvm@uiuc.edu
|
|
||||||
W: http://misha.brukman.net
|
|
||||||
D: Portions of X86 and Sparc JIT compilers, PowerPC backend
|
|
||||||
D: Incremental bitcode loader
|
|
||||||
|
|
||||||
N: Cameron Buschardt
|
|
||||||
E: buschard@uiuc.edu
|
|
||||||
D: The `mem2reg' pass - promotes values stored in memory to registers
|
|
||||||
|
|
||||||
N: Brendon Cahoon
|
|
||||||
E: bcahoon@codeaurora.org
|
|
||||||
D: Loop unrolling with run-time trip counts.
|
|
||||||
|
|
||||||
N: Chandler Carruth
|
|
||||||
E: chandlerc@gmail.com
|
|
||||||
E: chandlerc@google.com
|
|
||||||
D: Hashing algorithms and interfaces
|
|
||||||
D: Inline cost analysis
|
|
||||||
D: Machine block placement pass
|
|
||||||
D: SROA
|
|
||||||
|
|
||||||
N: Casey Carter
|
|
||||||
E: ccarter@uiuc.edu
|
|
||||||
D: Fixes to the Reassociation pass, various improvement patches
|
|
||||||
|
|
||||||
N: Evan Cheng
|
|
||||||
E: evan.cheng@apple.com
|
|
||||||
D: ARM and X86 backends
|
|
||||||
D: Instruction scheduler improvements
|
|
||||||
D: Register allocator improvements
|
|
||||||
D: Loop optimizer improvements
|
|
||||||
D: Target-independent code generator improvements
|
|
||||||
|
|
||||||
N: Dan Villiom Podlaski Christiansen
|
|
||||||
E: danchr@gmail.com
|
|
||||||
E: danchr@cs.au.dk
|
|
||||||
W: http://villiom.dk
|
|
||||||
D: LLVM Makefile improvements
|
|
||||||
D: Clang diagnostic & driver tweaks
|
|
||||||
S: Aarhus, Denmark
|
|
||||||
|
|
||||||
N: Jeff Cohen
|
|
||||||
E: jeffc@jolt-lang.org
|
|
||||||
W: http://jolt-lang.org
|
|
||||||
D: Native Win32 API portability layer
|
|
||||||
|
|
||||||
N: John T. Criswell
|
|
||||||
E: criswell@uiuc.edu
|
|
||||||
D: Original Autoconf support, documentation improvements, bug fixes
|
|
||||||
|
|
||||||
N: Anshuman Dasgupta
|
|
||||||
E: adasgupt@codeaurora.org
|
|
||||||
D: Deterministic finite automaton based infrastructure for VLIW packetization
|
|
||||||
|
|
||||||
N: Stefanus Du Toit
|
|
||||||
E: stefanus.du.toit@intel.com
|
|
||||||
D: Bug fixes and minor improvements
|
|
||||||
|
|
||||||
N: Rafael Avila de Espindola
|
|
||||||
E: rafael.espindola@gmail.com
|
|
||||||
D: The ARM backend
|
|
||||||
|
|
||||||
N: Dave Estes
|
|
||||||
E: cestes@codeaurora.org
|
|
||||||
D: AArch64 machine description for Cortex-A53
|
|
||||||
|
|
||||||
N: Alkis Evlogimenos
|
|
||||||
E: alkis@evlogimenos.com
|
|
||||||
D: Linear scan register allocator, many codegen improvements, Java frontend
|
|
||||||
|
|
||||||
N: Hal Finkel
|
|
||||||
E: hfinkel@anl.gov
|
|
||||||
D: Basic-block autovectorization, PowerPC backend improvements
|
|
||||||
|
|
||||||
N: Eric Fiselier
|
|
||||||
E: eric@efcs.ca
|
|
||||||
D: LIT patches and documentation.
|
|
||||||
|
|
||||||
N: Ryan Flynn
|
|
||||||
E: pizza@parseerror.com
|
|
||||||
D: Miscellaneous bug fixes
|
|
||||||
|
|
||||||
N: Brian Gaeke
|
|
||||||
E: gaeke@uiuc.edu
|
|
||||||
W: http://www.students.uiuc.edu/~gaeke/
|
|
||||||
D: Portions of X86 static and JIT compilers; initial SparcV8 backend
|
|
||||||
D: Dynamic trace optimizer
|
|
||||||
D: FreeBSD/X86 compatibility fixes, the llvm-nm tool
|
|
||||||
|
|
||||||
N: Nicolas Geoffray
|
|
||||||
E: nicolas.geoffray@lip6.fr
|
|
||||||
W: http://www-src.lip6.fr/homepages/Nicolas.Geoffray/
|
|
||||||
D: PPC backend fixes for Linux
|
|
||||||
|
|
||||||
N: Louis Gerbarg
|
|
||||||
E: lgg@apple.com
|
|
||||||
D: Portions of the PowerPC backend
|
|
||||||
|
|
||||||
N: Saem Ghani
|
|
||||||
E: saemghani@gmail.com
|
|
||||||
D: Callgraph class cleanups
|
|
||||||
|
|
||||||
N: Mikhail Glushenkov
|
|
||||||
E: foldr@codedgers.com
|
|
||||||
D: Author of llvmc2
|
|
||||||
|
|
||||||
N: Dan Gohman
|
|
||||||
E: sunfish@mozilla.com
|
|
||||||
D: Miscellaneous bug fixes
|
|
||||||
D: WebAssembly Backend
|
|
||||||
|
|
||||||
N: David Goodwin
|
|
||||||
E: david@goodwinz.net
|
|
||||||
D: Thumb-2 code generator
|
|
||||||
|
|
||||||
N: David Greene
|
|
||||||
E: greened@obbligato.org
|
|
||||||
D: Miscellaneous bug fixes
|
|
||||||
D: Register allocation refactoring
|
|
||||||
|
|
||||||
N: Gabor Greif
|
|
||||||
E: ggreif@gmail.com
|
|
||||||
D: Improvements for space efficiency
|
|
||||||
|
|
||||||
N: James Grosbach
|
|
||||||
E: grosbach@apple.com
|
|
||||||
I: grosbach
|
|
||||||
D: SjLj exception handling support
|
|
||||||
D: General fixes and improvements for the ARM back-end
|
|
||||||
D: MCJIT
|
|
||||||
D: ARM integrated assembler and assembly parser
|
|
||||||
D: Led effort for the backend formerly known as ARM64
|
|
||||||
|
|
||||||
N: Lang Hames
|
|
||||||
E: lhames@gmail.com
|
|
||||||
D: PBQP-based register allocator
|
|
||||||
|
|
||||||
N: Gordon Henriksen
|
|
||||||
E: gordonhenriksen@mac.com
|
|
||||||
D: Pluggable GC support
|
|
||||||
D: C interface
|
|
||||||
D: Ocaml bindings
|
|
||||||
|
|
||||||
N: Raul Fernandes Herbster
|
|
||||||
E: raul@dsc.ufcg.edu.br
|
|
||||||
D: JIT support for ARM
|
|
||||||
|
|
||||||
N: Paolo Invernizzi
|
|
||||||
E: arathorn@fastwebnet.it
|
|
||||||
D: Visual C++ compatibility fixes
|
|
||||||
|
|
||||||
N: Patrick Jenkins
|
|
||||||
E: patjenk@wam.umd.edu
|
|
||||||
D: Nightly Tester
|
|
||||||
|
|
||||||
N: Dale Johannesen
|
|
||||||
E: dalej@apple.com
|
|
||||||
D: ARM constant islands improvements
|
|
||||||
D: Tail merging improvements
|
|
||||||
D: Rewrite X87 back end
|
|
||||||
D: Use APFloat for floating point constants widely throughout compiler
|
|
||||||
D: Implement X87 long double
|
|
||||||
|
|
||||||
N: Brad Jones
|
|
||||||
E: kungfoomaster@nondot.org
|
|
||||||
D: Support for packed types
|
|
||||||
|
|
||||||
N: Rod Kay
|
|
||||||
E: rkay@auroraux.org
|
|
||||||
D: Author of LLVM Ada bindings
|
|
||||||
|
|
||||||
N: Eric Kidd
|
|
||||||
W: http://randomhacks.net/
|
|
||||||
D: llvm-config script
|
|
||||||
|
|
||||||
N: Anton Korobeynikov
|
|
||||||
E: asl@math.spbu.ru
|
|
||||||
D: Mingw32 fixes, cross-compiling support, stdcall/fastcall calling conv.
|
|
||||||
D: x86/linux PIC codegen, aliases, regparm/visibility attributes
|
|
||||||
D: Switch lowering refactoring
|
|
||||||
|
|
||||||
N: Sumant Kowshik
|
|
||||||
E: kowshik@uiuc.edu
|
|
||||||
D: Author of the original C backend
|
|
||||||
|
|
||||||
N: Benjamin Kramer
|
|
||||||
E: benny.kra@gmail.com
|
|
||||||
D: Miscellaneous bug fixes
|
|
||||||
|
|
||||||
N: Sundeep Kushwaha
|
|
||||||
E: sundeepk@codeaurora.org
|
|
||||||
D: Implemented DFA-based target independent VLIW packetizer
|
|
||||||
|
|
||||||
N: Christopher Lamb
|
|
||||||
E: christopher.lamb@gmail.com
|
|
||||||
D: aligned load/store support, parts of noalias and restrict support
|
|
||||||
D: vreg subreg infrastructure, X86 codegen improvements based on subregs
|
|
||||||
D: address spaces
|
|
||||||
|
|
||||||
N: Jim Laskey
|
|
||||||
E: jlaskey@apple.com
|
|
||||||
D: Improvements to the PPC backend, instruction scheduling
|
|
||||||
D: Debug and Dwarf implementation
|
|
||||||
D: Auto upgrade mangler
|
|
||||||
D: llvm-gcc4 svn wrangler
|
|
||||||
|
|
||||||
N: Chris Lattner
|
|
||||||
E: sabre@nondot.org
|
|
||||||
W: http://nondot.org/~sabre/
|
|
||||||
D: Primary architect of LLVM
|
|
||||||
|
|
||||||
N: Tanya Lattner (Tanya Brethour)
|
|
||||||
E: tonic@nondot.org
|
|
||||||
W: http://nondot.org/~tonic/
|
|
||||||
D: The initial llvm-ar tool, converted regression testsuite to dejagnu
|
|
||||||
D: Modulo scheduling in the SparcV9 backend
|
|
||||||
D: Release manager (1.7+)
|
|
||||||
|
|
||||||
N: Sylvestre Ledru
|
|
||||||
E: sylvestre@debian.org
|
|
||||||
W: http://sylvestre.ledru.info/
|
|
||||||
W: http://llvm.org/apt/
|
|
||||||
D: Debian and Ubuntu packaging
|
|
||||||
D: Continuous integration with jenkins
|
|
||||||
|
|
||||||
N: Andrew Lenharth
|
|
||||||
E: alenhar2@cs.uiuc.edu
|
|
||||||
W: http://www.lenharth.org/~andrewl/
|
|
||||||
D: Alpha backend
|
|
||||||
D: Sampling based profiling
|
|
||||||
|
|
||||||
N: Nick Lewycky
|
|
||||||
E: nicholas@mxc.ca
|
|
||||||
D: PredicateSimplifier pass
|
|
||||||
|
|
||||||
N: Tony Linthicum, et. al.
|
|
||||||
E: tlinth@codeaurora.org
|
|
||||||
D: Backend for Qualcomm's Hexagon VLIW processor.
|
|
||||||
|
|
||||||
N: Bruno Cardoso Lopes
|
|
||||||
E: bruno.cardoso@gmail.com
|
|
||||||
I: bruno
|
|
||||||
W: http://brunocardoso.cc
|
|
||||||
D: Mips backend
|
|
||||||
D: Random ARM integrated assembler and assembly parser improvements
|
|
||||||
D: General X86 AVX1 support
|
|
||||||
|
|
||||||
N: Duraid Madina
|
|
||||||
E: duraid@octopus.com.au
|
|
||||||
W: http://kinoko.c.u-tokyo.ac.jp/~duraid/
|
|
||||||
D: IA64 backend, BigBlock register allocator
|
|
||||||
|
|
||||||
N: John McCall
|
|
||||||
E: rjmccall@apple.com
|
|
||||||
D: Clang semantic analysis and IR generation
|
|
||||||
|
|
||||||
N: Michael McCracken
|
|
||||||
E: michael.mccracken@gmail.com
|
|
||||||
D: Line number support for llvmgcc
|
|
||||||
|
|
||||||
N: Vladimir Merzliakov
|
|
||||||
E: wanderer@rsu.ru
|
|
||||||
D: Test suite fixes for FreeBSD
|
|
||||||
|
|
||||||
N: Scott Michel
|
|
||||||
E: scottm@aero.org
|
|
||||||
D: Added STI Cell SPU backend.
|
|
||||||
|
|
||||||
N: Kai Nacke
|
|
||||||
E: kai@redstar.de
|
|
||||||
D: Support for implicit TLS model used with MS VC runtime
|
|
||||||
D: Dumping of Win64 EH structures
|
|
||||||
|
|
||||||
N: Takumi Nakamura
|
|
||||||
E: geek4civic@gmail.com
|
|
||||||
E: chapuni@hf.rim.or.jp
|
|
||||||
D: Cygwin and MinGW support.
|
|
||||||
D: Win32 tweaks.
|
|
||||||
S: Yokohama, Japan
|
|
||||||
|
|
||||||
N: Edward O'Callaghan
|
|
||||||
E: eocallaghan@auroraux.org
|
|
||||||
W: http://www.auroraux.org
|
|
||||||
D: Add Clang support with various other improvements to utils/NewNightlyTest.pl
|
|
||||||
D: Fix and maintain Solaris & AuroraUX support for llvm, various build warnings
|
|
||||||
D: and error clean ups.
|
|
||||||
|
|
||||||
N: Morten Ofstad
|
|
||||||
E: morten@hue.no
|
|
||||||
D: Visual C++ compatibility fixes
|
|
||||||
|
|
||||||
N: Jakob Stoklund Olesen
|
|
||||||
E: stoklund@2pi.dk
|
|
||||||
D: Machine code verifier
|
|
||||||
D: Blackfin backend
|
|
||||||
D: Fast register allocator
|
|
||||||
D: Greedy register allocator
|
|
||||||
|
|
||||||
N: Richard Osborne
|
|
||||||
E: richard@xmos.com
|
|
||||||
D: XCore backend
|
|
||||||
|
|
||||||
N: Devang Patel
|
|
||||||
E: dpatel@apple.com
|
|
||||||
D: LTO tool, PassManager rewrite, Loop Pass Manager, Loop Rotate
|
|
||||||
D: GCC PCH Integration (llvm-gcc), llvm-gcc improvements
|
|
||||||
D: Optimizer improvements, Loop Index Split
|
|
||||||
|
|
||||||
N: Ana Pazos
|
|
||||||
E: apazos@codeaurora.org
|
|
||||||
D: Fixes and improvements to the AArch64 backend
|
|
||||||
|
|
||||||
N: Wesley Peck
|
|
||||||
E: peckw@wesleypeck.com
|
|
||||||
W: http://wesleypeck.com/
|
|
||||||
D: MicroBlaze backend
|
|
||||||
|
|
||||||
N: Francois Pichet
|
|
||||||
E: pichet2000@gmail.com
|
|
||||||
D: MSVC support
|
|
||||||
|
|
||||||
N: Vladimir Prus
|
|
||||||
W: http://vladimir_prus.blogspot.com
|
|
||||||
E: ghost@cs.msu.su
|
|
||||||
D: Made inst_iterator behave like a proper iterator, LowerConstantExprs pass
|
|
||||||
|
|
||||||
N: Kalle Raiskila
|
|
||||||
E: kalle.rasikila@nokia.com
|
|
||||||
D: Some bugfixes to CellSPU
|
|
||||||
|
|
||||||
N: Xerxes Ranby
|
|
||||||
E: xerxes@zafena.se
|
|
||||||
D: Cmake dependency chain and various bug fixes
|
|
||||||
|
|
||||||
N: Alex Rosenberg
|
|
||||||
E: alexr@leftfield.org
|
|
||||||
I: arosenberg
|
|
||||||
D: ARM calling conventions rewrite, hard float support
|
|
||||||
|
|
||||||
N: Chad Rosier
|
|
||||||
E: mcrosier@codeaurora.org
|
|
||||||
I: mcrosier
|
|
||||||
D: AArch64 fast instruction selection pass
|
|
||||||
D: Fixes and improvements to the ARM fast-isel pass
|
|
||||||
D: Fixes and improvements to the AArch64 backend
|
|
||||||
|
|
||||||
N: Nadav Rotem
|
|
||||||
E: nrotem@apple.com
|
|
||||||
D: X86 code generation improvements, Loop Vectorizer.
|
|
||||||
|
|
||||||
N: Roman Samoilov
|
|
||||||
E: roman@codedgers.com
|
|
||||||
D: MSIL backend
|
|
||||||
|
|
||||||
N: Duncan Sands
|
|
||||||
E: baldrick@free.fr
|
|
||||||
I: baldrick
|
|
||||||
D: Ada support in llvm-gcc
|
|
||||||
D: Dragonegg plugin
|
|
||||||
D: Exception handling improvements
|
|
||||||
D: Type legalizer rewrite
|
|
||||||
|
|
||||||
N: Ruchira Sasanka
|
|
||||||
E: sasanka@uiuc.edu
|
|
||||||
D: Graph coloring register allocator for the Sparc64 backend
|
|
||||||
|
|
||||||
N: Arnold Schwaighofer
|
|
||||||
E: arnold.schwaighofer@gmail.com
|
|
||||||
D: Tail call optimization for the x86 backend
|
|
||||||
|
|
||||||
N: Shantonu Sen
|
|
||||||
E: ssen@apple.com
|
|
||||||
D: Miscellaneous bug fixes
|
|
||||||
|
|
||||||
N: Anand Shukla
|
|
||||||
E: ashukla@cs.uiuc.edu
|
|
||||||
D: The `paths' pass
|
|
||||||
|
|
||||||
N: Michael J. Spencer
|
|
||||||
E: bigcheesegs@gmail.com
|
|
||||||
D: Shepherding Windows COFF support into MC.
|
|
||||||
D: Lots of Windows stuff.
|
|
||||||
|
|
||||||
N: Reid Spencer
|
|
||||||
E: rspencer@reidspencer.com
|
|
||||||
W: http://reidspencer.com/
|
|
||||||
D: Lots of stuff, see: http://wiki.llvm.org/index.php/User:Reid
|
|
||||||
|
|
||||||
N: Alp Toker
|
|
||||||
E: alp@nuanti.com
|
|
||||||
W: http://atoker.com/
|
|
||||||
D: C++ frontend next generation standards implementation
|
|
||||||
|
|
||||||
N: Craig Topper
|
|
||||||
E: craig.topper@gmail.com
|
|
||||||
D: X86 codegen and disassembler improvements. AVX2 support.
|
|
||||||
|
|
||||||
N: Edwin Torok
|
|
||||||
E: edwintorok@gmail.com
|
|
||||||
D: Miscellaneous bug fixes
|
|
||||||
|
|
||||||
N: Adam Treat
|
|
||||||
E: manyoso@yahoo.com
|
|
||||||
D: C++ bugs filed, and C++ front-end bug fixes.
|
|
||||||
|
|
||||||
N: Lauro Ramos Venancio
|
|
||||||
E: lauro.venancio@indt.org.br
|
|
||||||
D: ARM backend improvements
|
|
||||||
D: Thread Local Storage implementation
|
|
||||||
|
|
||||||
N: Bill Wendling
|
|
||||||
I: wendling
|
|
||||||
E: isanbard@gmail.com
|
|
||||||
D: Release manager, IR Linker, LTO
|
|
||||||
D: Bunches of stuff
|
|
||||||
|
|
||||||
N: Bob Wilson
|
|
||||||
E: bob.wilson@acm.org
|
|
||||||
D: Advanced SIMD (NEON) support in the ARM backend.
|
|
||||||
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
==============================================================================
|
|
||||||
LLVM Release License
|
|
||||||
==============================================================================
|
|
||||||
University of Illinois/NCSA
|
|
||||||
Open Source License
|
|
||||||
|
|
||||||
Copyright (c) 2003-2015 University of Illinois at Urbana-Champaign.
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Developed by:
|
|
||||||
|
|
||||||
LLVM Team
|
|
||||||
|
|
||||||
University of Illinois at Urbana-Champaign
|
|
||||||
|
|
||||||
http://llvm.org
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
||||||
this software and associated documentation files (the "Software"), to deal with
|
|
||||||
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:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimers.
|
|
||||||
|
|
||||||
* Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimers in the
|
|
||||||
documentation and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
* Neither the names of the LLVM Team, University of Illinois at
|
|
||||||
Urbana-Champaign, nor the names of its contributors may be used to
|
|
||||||
endorse or promote products derived from this Software without specific
|
|
||||||
prior written permission.
|
|
||||||
|
|
||||||
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
|
|
||||||
CONTRIBUTORS 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 WITH THE
|
|
||||||
SOFTWARE.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
Copyrights and Licenses for Third Party Software Distributed with LLVM:
|
|
||||||
==============================================================================
|
|
||||||
The LLVM software contains code written by third parties. Such software will
|
|
||||||
have its own individual LICENSE.TXT file in the directory in which it appears.
|
|
||||||
This file will describe the copyrights, license, and restrictions which apply
|
|
||||||
to that code.
|
|
||||||
|
|
||||||
The disclaimer of warranty in the University of Illinois Open Source License
|
|
||||||
applies to all code in the LLVM Distribution, and nothing in any of the
|
|
||||||
other licenses gives permission to use the names of the LLVM Team or the
|
|
||||||
University of Illinois to endorse or promote products derived from this
|
|
||||||
Software.
|
|
||||||
|
|
||||||
The following pieces of software have additional or alternate copyrights,
|
|
||||||
licenses, and/or restrictions:
|
|
||||||
|
|
||||||
Program Directory
|
|
||||||
------- ---------
|
|
||||||
Autoconf llvm/autoconf
|
|
||||||
llvm/projects/ModuleMaker/autoconf
|
|
||||||
Google Test llvm/utils/unittest/googletest
|
|
||||||
OpenBSD regex llvm/lib/Support/{reg*, COPYRIGHT.regex}
|
|
||||||
pyyaml tests llvm/test/YAMLParser/{*.data, LICENSE.TXT}
|
|
||||||
ARM contributions llvm/lib/Target/ARM/LICENSE.TXT
|
|
||||||
md5 contributions llvm/lib/Support/MD5.cpp llvm/include/llvm/Support/MD5.h
|
|
||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -4,9 +4,8 @@
|
|||||||
set exe_name=odin.exe
|
set exe_name=odin.exe
|
||||||
|
|
||||||
:: Debug = 0, Release = 1
|
:: Debug = 0, Release = 1
|
||||||
set release_mode=1
|
set release_mode=0
|
||||||
|
set compiler_flags= -nologo -Oi -TC -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR-
|
||||||
set compiler_flags= -nologo -Oi -TC -W4 -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR-
|
|
||||||
|
|
||||||
if %release_mode% EQU 0 ( rem Debug
|
if %release_mode% EQU 0 ( rem Debug
|
||||||
set compiler_flags=%compiler_flags% -Od -MDd -Z7
|
set compiler_flags=%compiler_flags% -Od -MDd -Z7
|
||||||
@@ -16,7 +15,7 @@ if %release_mode% EQU 0 ( rem Debug
|
|||||||
)
|
)
|
||||||
|
|
||||||
set compiler_warnings= ^
|
set compiler_warnings= ^
|
||||||
-we4013 -we4706 -we4002 -we4133 ^
|
-W4 -WX ^
|
||||||
-wd4100 -wd4101 -wd4127 -wd4189 ^
|
-wd4100 -wd4101 -wd4127 -wd4189 ^
|
||||||
-wd4201 -wd4204 -wd4244 ^
|
-wd4201 -wd4204 -wd4244 ^
|
||||||
-wd4306 ^
|
-wd4306 ^
|
||||||
@@ -40,19 +39,21 @@ set compiler_settings=%compiler_includes% %compiler_flags% %compiler_warnings%
|
|||||||
set linker_settings=%libs% %linker_flags%
|
set linker_settings=%libs% %linker_flags%
|
||||||
|
|
||||||
|
|
||||||
rem set build_dir= "\"
|
del *.pdb > NUL 2> NUL
|
||||||
rem if not exist %build_dir% mkdir %build_dir%
|
del *.ilk > NUL 2> NUL
|
||||||
rem pushd %build_dir%
|
|
||||||
del *.pdb > NUL 2> NUL
|
|
||||||
del *.ilk > NUL 2> NUL
|
|
||||||
|
|
||||||
cl %compiler_settings% "src\main.c" ^
|
cl %compiler_settings% "src\main.c" ^
|
||||||
/link %linker_settings% -OUT:%exe_name% ^
|
/link %linker_settings% -OUT:%exe_name% ^
|
||||||
&& odin run code/demo.odin
|
&& odin run code/demo.odin
|
||||||
|
rem && odin build code/Jaze/src/main.odin
|
||||||
|
rem && odin build_dll code/example.odin ^
|
||||||
rem odin run code/demo.odin
|
rem odin run code/demo.odin
|
||||||
|
|
||||||
|
rem pushd src\asm
|
||||||
:do_not_compile_exe
|
rem nasm hellope.asm -fwin64 -o hellope.obj ^
|
||||||
|
rem && cl /nologo hellope.obj /link kernel32.lib /entry:main ^
|
||||||
|
rem && hellope.exe
|
||||||
rem popd
|
rem popd
|
||||||
|
|
||||||
:end_of_build
|
:end_of_build
|
||||||
|
|
||||||
|
|||||||
+158
-23
@@ -1,32 +1,167 @@
|
|||||||
#import "fmt.odin"
|
#import "fmt.odin";
|
||||||
#import "utf8.odin"
|
#import "atomic.odin";
|
||||||
|
#import "hash.odin";
|
||||||
|
#import "math.odin";
|
||||||
|
#import "mem.odin";
|
||||||
|
#import "opengl.odin";
|
||||||
|
#import "os.odin";
|
||||||
|
#import "strconv.odin";
|
||||||
|
#import "sync.odin";
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
MAX :: 64
|
// buf: [64]byte;
|
||||||
buf: [MAX]rune
|
// // len := strconv.generic_ftoa(buf[..], 123.5431, 'f', 4, 64);
|
||||||
backing: [MAX]byte
|
// x := 624.123;
|
||||||
offset: int
|
// s := strconv.format_float(buf[..], x, 'f', 6, 64);
|
||||||
|
// fmt.println(s);
|
||||||
|
// fmt.printf("%3d\n", 102);
|
||||||
|
|
||||||
msg := "Hello"
|
s := new_slice(int, 0, 10);
|
||||||
count := utf8.rune_count(msg)
|
append(s, 1, 2, 6, 3, 6, 5, 5, 5, 5, 1, 2);
|
||||||
assert(count <= MAX)
|
fmt.println(s);
|
||||||
runes := buf[:count]
|
|
||||||
|
|
||||||
|
when false {
|
||||||
|
/*
|
||||||
|
Version 0.1.1
|
||||||
|
|
||||||
|
Added:
|
||||||
|
* Dynamic Arrays `[dynamic]Type`
|
||||||
|
* Dynamic Maps `map[Key]Value`
|
||||||
|
* Dynamic array and map literals
|
||||||
|
* Custom struct alignemnt `struct #align 8 { bar: i8 }`
|
||||||
|
* Allow `_` in numbers
|
||||||
|
* Variadic `append`
|
||||||
|
* fmt.sprint*
|
||||||
|
* Entities prefixes with an underscore do not get exported on imports
|
||||||
|
* Overloaded `free` for pointers, slices, strings, dynamic arrays, and dynamic maps
|
||||||
|
* enum types have an implict `names` field, a []string of all the names in that enum
|
||||||
|
* immutable variables are "completely immutable" - rules need a full explanation
|
||||||
|
* `slice_to_bytes` - convert any slice to a slice of bytes
|
||||||
|
* `union_cast` allows for optional ok check
|
||||||
|
* Record type field `names` (struct/raw_union/enum)
|
||||||
|
* ?: ternary operator
|
||||||
|
* Unions with variants and common fields
|
||||||
|
* New built-in procedures
|
||||||
|
- `delete` to delete map entries `delete(m, key)`
|
||||||
|
- `clear` to clear dynamic maps and arrays `clear(map_or_array)`
|
||||||
|
- `reserve` to reserve space for the dynamic maps and arrays `reserve(map_or_array)`
|
||||||
|
* Unexported entities and fields using an underscore prefix
|
||||||
|
|
||||||
|
Removed:
|
||||||
|
* Maybe/option types
|
||||||
|
* Remove `type` keyword and other "reserved" keywords
|
||||||
|
* `compile_assert` and `assert`return the value of the condition for semantic reasons
|
||||||
|
|
||||||
|
Changed:
|
||||||
|
* thread_local -> #thread_local
|
||||||
|
* #include -> #load
|
||||||
|
* Files only get checked if they are actually used
|
||||||
|
* match x in y {} // For type match statements
|
||||||
|
* Version numbering now starts from 0.1.0 and uses the convention:
|
||||||
|
- major.minor.patch
|
||||||
|
* Core library additions to Windows specific stuff
|
||||||
|
|
||||||
|
Fixes:
|
||||||
|
* Many fmt.* fixes
|
||||||
|
* Overloading bug due to comparison of named types
|
||||||
|
* Overloading bug due to `#import .` collision
|
||||||
|
* disallow a `cast` from pointers of unions
|
||||||
|
* Minor bugs in generated IR code for slices
|
||||||
|
|
||||||
|
To come very Soon™:
|
||||||
|
* Linux and OS X builds (unofficial ones do exist already)
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
|
||||||
offset = 0
|
|
||||||
for i := 0; i < count; i++ {
|
|
||||||
s := msg[offset:]
|
|
||||||
r, len := utf8.decode_rune(s)
|
|
||||||
runes[count-i-1] = r
|
|
||||||
offset += len
|
|
||||||
}
|
}
|
||||||
|
|
||||||
offset = 0
|
{
|
||||||
for i := 0; i < count; i++ {
|
Fruit :: enum {
|
||||||
data, len := utf8.encode_rune(runes[i])
|
APPLE,
|
||||||
copy(backing[offset:], data[:len])
|
BANANA,
|
||||||
offset += len
|
COCONUT,
|
||||||
|
}
|
||||||
|
fmt.println(Fruit.names);
|
||||||
}
|
}
|
||||||
|
|
||||||
reverse := backing[:offset] as string
|
{
|
||||||
fmt.println(reverse) // olleH
|
m: map[f32]int;
|
||||||
|
reserve(m, 16);
|
||||||
|
defer free(m);
|
||||||
|
|
||||||
|
m[1.0] = 1278;
|
||||||
|
m[2.0] = 7643;
|
||||||
|
m[3.0] = 564;
|
||||||
|
_, ok := m[3.0];
|
||||||
|
c := m[3.0];
|
||||||
|
assert(ok && c == 564);
|
||||||
|
|
||||||
|
fmt.print("map[");
|
||||||
|
i := 0;
|
||||||
|
for val, key in m {
|
||||||
|
if i > 0 {
|
||||||
|
fmt.print(", ");
|
||||||
|
}
|
||||||
|
fmt.printf("%v=%v", key, val);
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
fmt.println("]");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
m := map[string]u32{
|
||||||
|
"a" = 56,
|
||||||
|
"b" = 13453,
|
||||||
|
"c" = 7654,
|
||||||
|
};
|
||||||
|
defer free(m);
|
||||||
|
|
||||||
|
c := m["c"];
|
||||||
|
_, ok := m["c"];
|
||||||
|
assert(ok && c == 7654);
|
||||||
|
|
||||||
|
fmt.println(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
x: [dynamic]f64;
|
||||||
|
reserve(x, 16);
|
||||||
|
defer free(x);
|
||||||
|
append(x, 2_000_000.500_000, 3, 5, 7);
|
||||||
|
|
||||||
|
for p, i in x {
|
||||||
|
if i > 0 { fmt.print(", "); }
|
||||||
|
fmt.print(p);
|
||||||
|
}
|
||||||
|
fmt.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
x := [dynamic]f64{2_000_000.500_000, 3, 5, 7};
|
||||||
|
defer free(x);
|
||||||
|
fmt.println(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
Vec3 :: [vector 3]f32;
|
||||||
|
|
||||||
|
x := Vec3{1, 2, 3};
|
||||||
|
y := Vec3{4, 5, 6};
|
||||||
|
fmt.println(x < y);
|
||||||
|
fmt.println(x + y);
|
||||||
|
fmt.println(x - y);
|
||||||
|
fmt.println(x * y);
|
||||||
|
fmt.println(x / y);
|
||||||
|
|
||||||
|
for i in x {
|
||||||
|
fmt.println(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
compile_assert(size_of([vector 7]bool) == size_of([7]bool));
|
||||||
|
compile_assert(size_of([vector 7]i32) == size_of([7]i32));
|
||||||
|
// align_of([vector 7]i32) != align_of([7]i32) // this may be the case
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
+94
-94
@@ -1,60 +1,60 @@
|
|||||||
#import "win32.odin"
|
#import "win32.odin" when ODIN_OS == "windows";
|
||||||
#import "fmt.odin"
|
#import "fmt.odin";
|
||||||
#import "math.odin"
|
#import "math.odin";
|
||||||
#import "os.odin"
|
#import "os.odin";
|
||||||
#import "opengl.odin" as gl
|
#import gl "opengl.odin";
|
||||||
|
|
||||||
TWO_HEARTS :: '💕'
|
TWO_HEARTS :: '💕';
|
||||||
|
|
||||||
win32_perf_count_freq := win32.GetQueryPerformanceFrequency()
|
win32_perf_count_freq := win32.GetQueryPerformanceFrequency();
|
||||||
time_now :: proc() -> f64 {
|
time_now :: proc() -> f64 {
|
||||||
assert(win32_perf_count_freq != 0)
|
assert(win32_perf_count_freq != 0);
|
||||||
|
|
||||||
counter: i64
|
counter: i64;
|
||||||
win32.QueryPerformanceCounter(^counter)
|
win32.QueryPerformanceCounter(^counter);
|
||||||
result := counter as f64 / win32_perf_count_freq as f64
|
result := counter as f64 / win32_perf_count_freq as f64;
|
||||||
return result
|
return result;
|
||||||
}
|
}
|
||||||
win32_print_last_error :: proc() {
|
win32_print_last_error :: proc() {
|
||||||
err_code := win32.GetLastError() as int
|
err_code := win32.GetLastError() as int;
|
||||||
if err_code != 0 {
|
if err_code != 0 {
|
||||||
fmt.println("GetLastError: %", err_code)
|
fmt.println("GetLastError: %", err_code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Yuk!
|
// Yuk!
|
||||||
to_c_string :: proc(s: string) -> []u8 {
|
to_c_string :: proc(s: string) -> []u8 {
|
||||||
c_str := new_slice(u8, s.count+1)
|
c_str := new_slice(u8, s.count+1);
|
||||||
copy(c_str, s as []byte)
|
copy(c_str, s as []byte);
|
||||||
c_str[s.count] = 0
|
c_str[s.count] = 0;
|
||||||
return c_str
|
return c_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Window :: struct {
|
Window :: struct {
|
||||||
width, height: int
|
width, height: int;
|
||||||
wc: win32.WNDCLASSEXA
|
wc: win32.WNDCLASSEXA;
|
||||||
dc: win32.HDC
|
dc: win32.HDC;
|
||||||
hwnd: win32.HWND
|
hwnd: win32.HWND;
|
||||||
opengl_context, rc: win32.HGLRC
|
opengl_context, rc: win32.HGLRC;
|
||||||
c_title: []u8
|
c_title: []u8;
|
||||||
}
|
}
|
||||||
|
|
||||||
make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC) -> (Window, bool) {
|
make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC) -> (Window, bool) {
|
||||||
using win32
|
using win32;
|
||||||
|
|
||||||
w: Window
|
w: Window;
|
||||||
w.width, w.height = msg, height
|
w.width, w.height = msg, height;
|
||||||
|
|
||||||
class_name := "Win32-Odin-Window\x00"
|
class_name := "Win32-Odin-Window\x00";
|
||||||
c_class_name := class_name.data
|
c_class_name := class_name.data;
|
||||||
if title[title.count-1] != 0 {
|
if title[title.count-1] != 0 {
|
||||||
w.c_title = to_c_string(title)
|
w.c_title = to_c_string(title);
|
||||||
} else {
|
} else {
|
||||||
w.c_title = title as []u8
|
w.c_title = title as []u8;
|
||||||
}
|
}
|
||||||
|
|
||||||
instance := GetModuleHandleA(nil)
|
instance := GetModuleHandleA(nil);
|
||||||
|
|
||||||
w.wc = WNDCLASSEXA{
|
w.wc = WNDCLASSEXA{
|
||||||
size = size_of(WNDCLASSEXA) as u32,
|
size = size_of(WNDCLASSEXA) as u32,
|
||||||
@@ -65,8 +65,8 @@ make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC)
|
|||||||
};
|
};
|
||||||
|
|
||||||
if RegisterClassExA(^w.wc) == 0 {
|
if RegisterClassExA(^w.wc) == 0 {
|
||||||
win32_print_last_error()
|
win32_print_last_error();
|
||||||
return w, false
|
return w, false;
|
||||||
}
|
}
|
||||||
|
|
||||||
w.hwnd = CreateWindowExA(0,
|
w.hwnd = CreateWindowExA(0,
|
||||||
@@ -74,14 +74,14 @@ make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC)
|
|||||||
WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
|
WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
|
||||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||||
w.width as i32, w.height as i32,
|
w.width as i32, w.height as i32,
|
||||||
nil, nil, instance, nil)
|
nil, nil, instance, nil);
|
||||||
|
|
||||||
if w.hwnd == nil {
|
if w.hwnd == nil {
|
||||||
win32_print_last_error()
|
win32_print_last_error();
|
||||||
return w, false
|
return w, false;
|
||||||
}
|
}
|
||||||
|
|
||||||
w.dc = GetDC(w.hwnd)
|
w.dc = GetDC(w.hwnd);
|
||||||
|
|
||||||
{
|
{
|
||||||
pfd := PIXELFORMATDESCRIPTOR{
|
pfd := PIXELFORMATDESCRIPTOR{
|
||||||
@@ -94,122 +94,122 @@ make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC)
|
|||||||
depth_bits = 24,
|
depth_bits = 24,
|
||||||
stencil_bits = 8,
|
stencil_bits = 8,
|
||||||
layer_type = PFD_MAIN_PLANE,
|
layer_type = PFD_MAIN_PLANE,
|
||||||
}
|
};
|
||||||
|
|
||||||
SetPixelFormat(w.dc, ChoosePixelFormat(w.dc, ^pfd), nil)
|
SetPixelFormat(w.dc, ChoosePixelFormat(w.dc, ^pfd), nil);
|
||||||
w.opengl_context = wglCreateContext(w.dc)
|
w.opengl_context = wglCreateContext(w.dc);
|
||||||
wglMakeCurrent(w.dc, w.opengl_context)
|
wglMakeCurrent(w.dc, w.opengl_context);
|
||||||
|
|
||||||
attribs := [8]i32{
|
attribs := [8]i32{
|
||||||
WGL_CONTEXT_MAJOR_VERSION_ARB, 2,
|
WGL_CONTEXT_MAJOR_VERSION_ARB, 2,
|
||||||
WGL_CONTEXT_MINOR_VERSION_ARB, 1,
|
WGL_CONTEXT_MINOR_VERSION_ARB, 1,
|
||||||
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
|
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
|
||||||
0, // NOTE(bill): tells the proc that this is the end of attribs
|
0, // NOTE(bill): tells the proc that this is the end of attribs
|
||||||
}
|
};
|
||||||
|
|
||||||
wglCreateContextAttribsARB := wglGetProcAddress(("wglCreateContextAttribsARB\x00" as string).data) as wglCreateContextAttribsARBType
|
wglCreateContextAttribsARB := wglGetProcAddress(("wglCreateContextAttribsARB\x00" as string).data) as wglCreateContextAttribsARBType;
|
||||||
w.rc = wglCreateContextAttribsARB(w.dc, 0, ^attribs[0])
|
w.rc = wglCreateContextAttribsARB(w.dc, 0, ^attribs[0]);
|
||||||
wglMakeCurrent(w.dc, w.rc)
|
wglMakeCurrent(w.dc, w.rc);
|
||||||
SwapBuffers(w.dc)
|
SwapBuffers(w.dc);
|
||||||
}
|
}
|
||||||
|
|
||||||
return w, true
|
return w, true;
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy_window :: proc(w: ^Window) {
|
destroy_window :: proc(w: ^Window) {
|
||||||
free(w.c_title.data)
|
free(w.c_title.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
display_window :: proc(w: ^Window) {
|
display_window :: proc(w: ^Window) {
|
||||||
win32.SwapBuffers(w.dc)
|
win32.SwapBuffers(w.dc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
run :: proc() {
|
run :: proc() {
|
||||||
using win32
|
using win32;
|
||||||
using math
|
using math;
|
||||||
|
|
||||||
win32_proc :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #no_inline {
|
win32_proc :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #no_inline {
|
||||||
if msg == WM_DESTROY || msg == WM_CLOSE || msg == WM_QUIT {
|
if msg == WM_DESTROY || msg == WM_CLOSE || msg == WM_QUIT {
|
||||||
os.exit(0)
|
os.exit(0);
|
||||||
return 0
|
return 0;
|
||||||
}
|
}
|
||||||
return DefWindowProcA(hwnd, msg, wparam, lparam)
|
return DefWindowProcA(hwnd, msg, wparam, lparam);
|
||||||
}
|
}
|
||||||
|
|
||||||
window, window_success := make_window("Odin Language Demo", 854, 480, win32_proc)
|
window, window_success := make_window("Odin Language Demo", 854, 480, win32_proc);
|
||||||
if !window_success {
|
if !window_success {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
defer destroy_window(^window)
|
defer destroy_window(^window);
|
||||||
|
|
||||||
gl.init()
|
gl.init();
|
||||||
|
|
||||||
|
|
||||||
prev_time := time_now()
|
prev_time := time_now();
|
||||||
running := true
|
running := true;
|
||||||
|
|
||||||
pos := Vec2{100, 100}
|
pos := Vec2{100, 100};
|
||||||
|
|
||||||
for running {
|
for running {
|
||||||
curr_time := time_now()
|
curr_time := time_now();
|
||||||
dt := (curr_time - prev_time) as f32
|
dt := (curr_time - prev_time) as f32;
|
||||||
prev_time = curr_time
|
prev_time = curr_time;
|
||||||
|
|
||||||
msg: MSG
|
msg: MSG;
|
||||||
for PeekMessageA(^msg, nil, 0, 0, PM_REMOVE) > 0 {
|
for PeekMessageA(^msg, nil, 0, 0, PM_REMOVE) > 0 {
|
||||||
if msg.message == WM_QUIT {
|
if msg.message == WM_QUIT {
|
||||||
running = false
|
running = false;
|
||||||
}
|
}
|
||||||
TranslateMessage(^msg)
|
TranslateMessage(^msg);
|
||||||
DispatchMessageA(^msg)
|
DispatchMessageA(^msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_key_down(Key_Code.ESCAPE) {
|
if is_key_down(Key_Code.ESCAPE) {
|
||||||
running = false
|
running = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
SPEED :: 500
|
SPEED :: 500;
|
||||||
v: Vec2
|
v: Vec2;
|
||||||
|
|
||||||
if is_key_down(Key_Code.RIGHT) { v[0] += 1 }
|
if is_key_down(Key_Code.RIGHT) { v[0] += 1; }
|
||||||
if is_key_down(Key_Code.LEFT) { v[0] -= 1 }
|
if is_key_down(Key_Code.LEFT) { v[0] -= 1; }
|
||||||
if is_key_down(Key_Code.UP) { v[1] += 1 }
|
if is_key_down(Key_Code.UP) { v[1] += 1; }
|
||||||
if is_key_down(Key_Code.DOWN) { v[1] -= 1 }
|
if is_key_down(Key_Code.DOWN) { v[1] -= 1; }
|
||||||
|
|
||||||
v = vec2_norm0(v)
|
v = vec2_norm0(v);
|
||||||
|
|
||||||
pos += v * Vec2{SPEED * dt}
|
pos += v * Vec2{SPEED * dt};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
gl.ClearColor(0.5, 0.7, 1.0, 1.0)
|
gl.ClearColor(0.5, 0.7, 1.0, 1.0);
|
||||||
gl.Clear(gl.COLOR_BUFFER_BIT)
|
gl.Clear(gl.COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
gl.LoadIdentity()
|
gl.LoadIdentity();
|
||||||
gl.Ortho(0, window.width as f64,
|
gl.Ortho(0, window.width as f64,
|
||||||
0, window.height as f64, 0, 1)
|
0, window.height as f64, 0, 1);
|
||||||
|
|
||||||
draw_rect :: proc(x, y, w, h: f32) {
|
draw_rect :: proc(x, y, w, h: f32) {
|
||||||
gl.Begin(gl.TRIANGLES)
|
gl.Begin(gl.TRIANGLES);
|
||||||
defer gl.End()
|
defer gl.End();
|
||||||
|
|
||||||
gl.Color3f(1, 0, 0); gl.Vertex3f(x, y, 0)
|
gl.Color3f(1, 0, 0); gl.Vertex3f(x, y, 0);
|
||||||
gl.Color3f(0, 1, 0); gl.Vertex3f(x+w, y, 0)
|
gl.Color3f(0, 1, 0); gl.Vertex3f(x+w, y, 0);
|
||||||
gl.Color3f(0, 0, 1); gl.Vertex3f(x+w, y+h, 0)
|
gl.Color3f(0, 0, 1); gl.Vertex3f(x+w, y+h, 0);
|
||||||
|
|
||||||
gl.Color3f(0, 0, 1); gl.Vertex3f(x+w, y+h, 0)
|
gl.Color3f(0, 0, 1); gl.Vertex3f(x+w, y+h, 0);
|
||||||
gl.Color3f(1, 1, 0); gl.Vertex3f(x, y+h, 0)
|
gl.Color3f(1, 1, 0); gl.Vertex3f(x, y+h, 0);
|
||||||
gl.Color3f(1, 0, 0); gl.Vertex3f(x, y, 0)
|
gl.Color3f(1, 0, 0); gl.Vertex3f(x, y, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
draw_rect(pos.x, pos.y, 50, 50)
|
draw_rect(pos.x, pos.y, 50, 50);
|
||||||
|
|
||||||
display_window(^window)
|
display_window(^window);
|
||||||
ms_to_sleep := (16 - 1000*dt) as i32
|
ms_to_sleep := (16 - 1000*dt) as i32;
|
||||||
if ms_to_sleep > 0 {
|
if ms_to_sleep > 0 {
|
||||||
win32.Sleep(ms_to_sleep)
|
win32.Sleep(ms_to_sleep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+87
-87
@@ -1,10 +1,10 @@
|
|||||||
#import "fmt.odin" as fmt
|
#import "fmt.odin";
|
||||||
|
|
||||||
#foreign_system_library "Ws2_32"
|
#foreign_system_library ws2 "Ws2_32.lib" when ODIN_OS == "windows";
|
||||||
|
|
||||||
|
|
||||||
SOCKET :: type uint
|
SOCKET :: #type uint;
|
||||||
INVALID_SOCKET :: ~(0 as SOCKET)
|
INVALID_SOCKET :: ~(cast(SOCKET)0);
|
||||||
|
|
||||||
AF :: enum i32 {
|
AF :: enum i32 {
|
||||||
UNSPEC = 0, // unspecified
|
UNSPEC = 0, // unspecified
|
||||||
@@ -35,111 +35,111 @@ AF :: enum i32 {
|
|||||||
SIP = 24, // Simple Internet Protocol
|
SIP = 24, // Simple Internet Protocol
|
||||||
PIP = 25, // Help Identify PIP packets
|
PIP = 25, // Help Identify PIP packets
|
||||||
MAX = 26,
|
MAX = 26,
|
||||||
}
|
};
|
||||||
|
|
||||||
SOCK_STREAM :: 1
|
SOCK_STREAM :: 1;
|
||||||
SOCKET_ERROR :: -1
|
SOCKET_ERROR :: -1;
|
||||||
IPPROTO_TCP :: 6
|
IPPROTO_TCP :: 6;
|
||||||
AI_PASSIVE :: 0x0020
|
AI_PASSIVE :: 0x0020;
|
||||||
SOMAXCONN :: 128
|
SOMAXCONN :: 128;
|
||||||
|
|
||||||
SD_RECEIVE :: 0
|
SD_RECEIVE :: 0;
|
||||||
SD_SEND :: 1
|
SD_SEND :: 1;
|
||||||
SD_BOTH :: 2
|
SD_BOTH :: 2;
|
||||||
|
|
||||||
WSADESCRIPTION_LEN :: 256
|
WSADESCRIPTION_LEN :: 256;
|
||||||
WSASYS_STATUS_LEN :: 128
|
WSASYS_STATUS_LEN :: 128;
|
||||||
WSADATA :: struct #ordered {
|
WSADATA :: struct #ordered {
|
||||||
version: i16
|
version: i16,
|
||||||
high_version: i16
|
high_version: i16,
|
||||||
|
|
||||||
|
|
||||||
// NOTE(bill): This is x64 ordering
|
// NOTE(bill): This is x64 ordering
|
||||||
max_sockets: u16
|
max_sockets: u16,
|
||||||
max_udp_dg: u16
|
max_udp_dg: u16,
|
||||||
vendor_info: ^byte
|
vendor_info: ^byte,
|
||||||
description: [WSADESCRIPTION_LEN+1]byte
|
description: [WSADESCRIPTION_LEN+1]byte,
|
||||||
system_status: [WSASYS_STATUS_LEN+1]byte
|
system_status: [WSASYS_STATUS_LEN+1]byte,
|
||||||
}
|
}
|
||||||
|
|
||||||
addrinfo :: struct #ordered {
|
addrinfo :: struct #ordered {
|
||||||
flags: i32
|
flags: i32,
|
||||||
family: i32
|
family: i32,
|
||||||
socktype: i32
|
socktype: i32,
|
||||||
protocol: i32
|
protocol: i32,
|
||||||
addrlen: uint
|
addrlen: uint,
|
||||||
canonname: ^u8
|
canonname: ^u8,
|
||||||
addr: ^sockaddr
|
addr: ^sockaddr,
|
||||||
next: ^addrinfo
|
next: ^addrinfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
sockaddr :: struct #ordered {
|
sockaddr :: struct #ordered {
|
||||||
family: u16
|
family: u16,
|
||||||
data: [14]byte
|
data: [14]byte,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
WSAStartup :: proc(version_requested: i16, data: ^WSADATA) -> i32 #foreign #dll_import
|
WSAStartup :: proc(version_requested: i16, data: ^WSADATA) -> i32 #foreign ws2;
|
||||||
WSACleanup :: proc() -> i32 #foreign #dll_import
|
WSACleanup :: proc() -> i32 #foreign ws2;
|
||||||
getaddrinfo :: proc(node_name, service_name: ^u8, hints: ^addrinfo, result: ^^addrinfo) -> i32 #foreign #dll_import
|
getaddrinfo :: proc(node_name, service_name: ^u8, hints: ^addrinfo, result: ^^addrinfo) -> i32 #foreign ws2;
|
||||||
freeaddrinfo :: proc(ai: ^addrinfo) #foreign #dll_import
|
freeaddrinfo :: proc(ai: ^addrinfo) #foreign ws2;
|
||||||
socket :: proc(af, type_, protocol: i32) -> SOCKET #foreign #dll_import
|
socket :: proc(af, type_, protocol: i32) -> SOCKET #foreign ws2;
|
||||||
closesocket :: proc(s: SOCKET) -> i32 #foreign #dll_import
|
closesocket :: proc(s: SOCKET) -> i32 #foreign ws2;
|
||||||
bind :: proc(s: SOCKET, name: ^sockaddr, name_len: i32) -> i32 #foreign #dll_import
|
bind :: proc(s: SOCKET, name: ^sockaddr, name_len: i32) -> i32 #foreign ws2;
|
||||||
listen :: proc(s: SOCKET, back_log: i32) -> i32 #foreign #dll_import
|
listen :: proc(s: SOCKET, back_log: i32) -> i32 #foreign ws2;
|
||||||
accept :: proc(s: SOCKET, addr: ^sockaddr, addr_len: i32) -> SOCKET #foreign #dll_import
|
accept :: proc(s: SOCKET, addr: ^sockaddr, addr_len: i32) -> SOCKET #foreign ws2;
|
||||||
recv :: proc(s: SOCKET, buf: ^byte, len: i32, flags: i32) -> i32 #foreign #dll_import
|
recv :: proc(s: SOCKET, buf: ^byte, len: i32, flags: i32) -> i32 #foreign ws2;
|
||||||
send :: proc(s: SOCKET, buf: ^byte, len: i32, flags: i32) -> i32 #foreign #dll_import
|
send :: proc(s: SOCKET, buf: ^byte, len: i32, flags: i32) -> i32 #foreign ws2;
|
||||||
shutdown :: proc(s: SOCKET, how: i32) -> i32 #foreign #dll_import
|
shutdown :: proc(s: SOCKET, how: i32) -> i32 #foreign ws2;
|
||||||
WSAGetLastError :: proc() -> i32 #foreign #dll_import
|
WSAGetLastError :: proc() -> i32 #foreign ws2;
|
||||||
|
|
||||||
to_c_string :: proc(s: string) -> ^byte {
|
to_c_string :: proc(s: string) -> ^byte {
|
||||||
c_str := new_slice(byte, s.count+1)
|
c_str := new_slice(byte, s.count+1);
|
||||||
assert(c_str.data != null)
|
assert(c_str.data != nil);
|
||||||
copy(c_str, s as []byte)
|
copy(c_str, cast([]byte)s);
|
||||||
c_str[s.count] = 0
|
c_str[s.count] = 0;
|
||||||
return c_str.data
|
return c_str.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
run :: proc() {
|
run :: proc() {
|
||||||
wsa: WSADATA
|
wsa: WSADATA;
|
||||||
res: ^addrinfo = null
|
res: ^addrinfo = nil;
|
||||||
hints: addrinfo
|
hints: addrinfo;
|
||||||
s, client: SOCKET
|
s, client: SOCKET;
|
||||||
|
|
||||||
if WSAStartup(2 | (2 << 8), ^wsa) != 0 {
|
if WSAStartup(2 | (2 << 8), ^wsa) != 0 {
|
||||||
fmt.println("WSAStartup failed: ", WSAGetLastError())
|
fmt.println("WSAStartup failed: ", WSAGetLastError());
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
defer WSACleanup()
|
defer WSACleanup();
|
||||||
|
|
||||||
hints.family = AF.INET as i32
|
hints.family = cast(i32)AF.INET;
|
||||||
hints.socktype = SOCK_STREAM
|
hints.socktype = SOCK_STREAM;
|
||||||
hints.protocol = IPPROTO_TCP
|
hints.protocol = IPPROTO_TCP;
|
||||||
hints.flags = AI_PASSIVE
|
hints.flags = AI_PASSIVE;
|
||||||
|
|
||||||
if getaddrinfo(null, to_c_string("8080"), ^hints, ^res) != 0 {
|
if getaddrinfo(nil, to_c_string("8080"), ^hints, ^res) != 0 {
|
||||||
fmt.println("getaddrinfo failed: ", WSAGetLastError())
|
fmt.println("getaddrinfo failed: ", WSAGetLastError());
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
defer freeaddrinfo(res)
|
defer freeaddrinfo(res);
|
||||||
|
|
||||||
s = socket(res.family, res.socktype, res.protocol)
|
s = socket(res.family, res.socktype, res.protocol);
|
||||||
if s == INVALID_SOCKET {
|
if s == INVALID_SOCKET {
|
||||||
fmt.println("socket failed: ", WSAGetLastError())
|
fmt.println("socket failed: ", WSAGetLastError());
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
defer closesocket(s)
|
defer closesocket(s);
|
||||||
|
|
||||||
bind(s, res.addr, res.addrlen as i32)
|
bind(s, res.addr, cast(i32)res.addrlen);
|
||||||
listen(s, SOMAXCONN)
|
listen(s, SOMAXCONN);
|
||||||
|
|
||||||
client = accept(s, null, null)
|
client = accept(s, nil, 0);
|
||||||
if client == INVALID_SOCKET {
|
if client == INVALID_SOCKET {
|
||||||
fmt.println("socket failed: ", WSAGetLastError())
|
fmt.println("socket failed: ", WSAGetLastError());
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
defer closesocket(client)
|
defer closesocket(client);
|
||||||
|
|
||||||
html :=
|
html :=
|
||||||
`HTTP/1.1 200 OK
|
`HTTP/1.1 200 OK
|
||||||
@@ -154,27 +154,27 @@ Content-type: text/html
|
|||||||
<h1 style="color: orange;">Odin Server Demo</h1>
|
<h1 style="color: orange;">Odin Server Demo</h1>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
`
|
`;
|
||||||
|
|
||||||
buf: [1024]byte
|
buf: [1024]byte;
|
||||||
for {
|
for {
|
||||||
bytes := recv(client, ^buf[0], buf.count as i32, 0)
|
bytes := recv(client, ^buf[0], cast(i32)buf.count, 0);
|
||||||
if bytes > 0 {
|
if bytes > 0 {
|
||||||
// fmt.println(buf[:bytes] as string)
|
// fmt.println(buf[:bytes] as string)
|
||||||
bytes_sent := send(client, html.data, (html.count-1) as i32, 0)
|
bytes_sent := send(client, html.data, cast(i32)(html.count-1), 0);
|
||||||
if bytes_sent == SOCKET_ERROR {
|
if bytes_sent == SOCKET_ERROR {
|
||||||
fmt.println("send failed: ", WSAGetLastError())
|
fmt.println("send failed: ", WSAGetLastError());
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
break
|
break;
|
||||||
} else if bytes == 0 {
|
} else if bytes == 0 {
|
||||||
fmt.println("Connection closing...")
|
fmt.println("Connection closing...");
|
||||||
break
|
break;
|
||||||
} else {
|
} else {
|
||||||
fmt.println("recv failed: ", WSAGetLastError())
|
fmt.println("recv failed: ", WSAGetLastError());
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
shutdown(client, SD_SEND)
|
shutdown(client, SD_SEND);
|
||||||
}
|
}
|
||||||
|
|||||||
+104
-101
@@ -1,83 +1,86 @@
|
|||||||
#import "fmt.odin"
|
#import "fmt.odin";
|
||||||
#import "os.odin"
|
#import "os.odin";
|
||||||
#import "mem.odin"
|
#import "mem.odin";
|
||||||
// #import "http_test.odin" as ht
|
// #import "http_test.odin" as ht;
|
||||||
// #import "game.odin" as game
|
// #import "game.odin" as game;
|
||||||
// #import "punity.odin" as pn
|
// #import "punity.odin" as pn;
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
// struct_padding()
|
struct_padding();
|
||||||
// bounds_checking()
|
bounds_checking();
|
||||||
// type_introspection()
|
type_introspection();
|
||||||
// any_type()
|
any_type();
|
||||||
// crazy_introspection()
|
crazy_introspection();
|
||||||
// namespaces_and_files()
|
namespaces_and_files();
|
||||||
// miscellany()
|
miscellany();
|
||||||
// ht.run()
|
|
||||||
// game.run()
|
|
||||||
// {
|
|
||||||
// init :: proc(c: ^pn.Core) {}
|
|
||||||
// step :: proc(c: ^pn.Core) {}
|
|
||||||
|
|
||||||
// pn.run(init, step)
|
/*
|
||||||
// }
|
ht.run();
|
||||||
|
game.run();
|
||||||
|
{
|
||||||
|
init :: proc(c: ^pn.Core) {}
|
||||||
|
step :: proc(c: ^pn.Core) {}
|
||||||
|
|
||||||
|
pn.run(init, step);
|
||||||
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
struct_padding :: proc() {
|
struct_padding :: proc() {
|
||||||
{
|
{
|
||||||
A :: struct {
|
A :: struct {
|
||||||
a: u8
|
a: u8,
|
||||||
b: u32
|
b: u32,
|
||||||
c: u16
|
c: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
B :: struct {
|
B :: struct {
|
||||||
a: [7]u8
|
a: [7]u8,
|
||||||
b: [3]u16
|
b: [3]u16,
|
||||||
c: u8
|
c: u8,
|
||||||
d: u16
|
d: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.println("size_of(A):", size_of(A))
|
fmt.println("size_of(A):", size_of(A));
|
||||||
fmt.println("size_of(B):", size_of(B))
|
fmt.println("size_of(B):", size_of(B));
|
||||||
|
|
||||||
// n.b. http://cbloomrants.blogspot.co.uk/2012/07/07-23-12-structs-are-not-what-you-want.html
|
// n.b. http://cbloomrants.blogspot.co.uk/2012/07/07-23-12-structs-are-not-what-you-want.html
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
A :: struct #ordered {
|
A :: struct #ordered {
|
||||||
a: u8
|
a: u8,
|
||||||
b: u32
|
b: u32,
|
||||||
c: u16
|
c: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
B :: struct #ordered {
|
B :: struct #ordered {
|
||||||
a: [7]u8
|
a: [7]u8,
|
||||||
b: [3]u16
|
b: [3]u16,
|
||||||
c: u8
|
c: u8,
|
||||||
d: u16
|
d: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.println("size_of(A):", size_of(A))
|
fmt.println("size_of(A):", size_of(A));
|
||||||
fmt.println("size_of(B):", size_of(B))
|
fmt.println("size_of(B):", size_of(B));
|
||||||
|
|
||||||
// C-style structure layout
|
// C-style structure layout
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
A :: struct #packed {
|
A :: struct #packed {
|
||||||
a: u8
|
a: u8,
|
||||||
b: u32
|
b: u32,
|
||||||
c: u16
|
c: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
B :: struct #packed {
|
B :: struct #packed {
|
||||||
a: [7]u8
|
a: [7]u8,
|
||||||
b: [3]u16
|
b: [3]u16,
|
||||||
c: u8
|
c: u8,
|
||||||
d: u16
|
d: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.println("size_of(A):", size_of(A))
|
fmt.println("size_of(A):", size_of(A));
|
||||||
fmt.println("size_of(B):", size_of(B))
|
fmt.println("size_of(B):", size_of(B));
|
||||||
|
|
||||||
// Useful for explicit layout
|
// Useful for explicit layout
|
||||||
}
|
}
|
||||||
@@ -119,7 +122,7 @@ struct_padding :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bounds_checking :: proc() {
|
bounds_checking :: proc() {
|
||||||
x: [4]int
|
x: [4]int;
|
||||||
// x[-1] = 0; // Compile Time
|
// x[-1] = 0; // Compile Time
|
||||||
// x[4] = 0; // Compile Time
|
// x[4] = 0; // Compile Time
|
||||||
|
|
||||||
@@ -132,9 +135,9 @@ bounds_checking :: proc() {
|
|||||||
// Works for arrays, strings, slices, and related procedures & operations
|
// Works for arrays, strings, slices, and related procedures & operations
|
||||||
|
|
||||||
{
|
{
|
||||||
base: [10]int
|
base: [10]int;
|
||||||
s := base[2:6]
|
s := base[2:6];
|
||||||
a, b := -1, 6
|
a, b := -1, 6;
|
||||||
|
|
||||||
#no_bounds_check {
|
#no_bounds_check {
|
||||||
s[a] = 0;
|
s[a] = 0;
|
||||||
@@ -154,69 +157,69 @@ bounds_checking :: proc() {
|
|||||||
|
|
||||||
type_introspection :: proc() {
|
type_introspection :: proc() {
|
||||||
{
|
{
|
||||||
info: ^Type_Info
|
info: ^Type_Info;
|
||||||
x: int
|
x: int;
|
||||||
|
|
||||||
info = type_info(int) // by type
|
info = type_info(int); // by type
|
||||||
info = type_info_of_val(x) // by value
|
info = type_info_of_val(x); // by value
|
||||||
// See: runtime.odin
|
// See: runtime.odin
|
||||||
|
|
||||||
match type i : info {
|
match type i in info {
|
||||||
case Type_Info.Integer:
|
case Type_Info.Integer:
|
||||||
fmt.println("integer!")
|
fmt.println("integer!");
|
||||||
case Type_Info.Float:
|
case Type_Info.Float:
|
||||||
fmt.println("float!")
|
fmt.println("float!");
|
||||||
default:
|
default:
|
||||||
fmt.println("potato!")
|
fmt.println("potato!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unsafe cast
|
// Unsafe cast
|
||||||
integer_info := info as ^Type_Info.Integer
|
integer_info := cast(^Type_Info.Integer)info;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
Vector2 :: struct { x, y: f32 }
|
Vector2 :: struct { x, y: f32 }
|
||||||
Vector3 :: struct { x, y, z: f32 }
|
Vector3 :: struct { x, y, z: f32 }
|
||||||
|
|
||||||
v1: Vector2
|
v1: Vector2;
|
||||||
v2: Vector3
|
v2: Vector3;
|
||||||
v3: Vector3
|
v3: Vector3;
|
||||||
|
|
||||||
t1 := type_info_of_val(v1)
|
t1 := type_info_of_val(v1);
|
||||||
t2 := type_info_of_val(v2)
|
t2 := type_info_of_val(v2);
|
||||||
t3 := type_info_of_val(v3)
|
t3 := type_info_of_val(v3);
|
||||||
|
|
||||||
fmt.println()
|
fmt.println();
|
||||||
fmt.print("Type of v1 is:\n\t", t1)
|
fmt.print("Type of v1 is:\n\t", t1);
|
||||||
|
|
||||||
fmt.println()
|
fmt.println();
|
||||||
fmt.print("Type of v2 is:\n\t", t2)
|
fmt.print("Type of v2 is:\n\t", t2);
|
||||||
|
|
||||||
fmt.println("\n")
|
fmt.println("\n");
|
||||||
fmt.println("t1 == t2:", t1 == t2)
|
fmt.println("t1 == t2:", t1 == t2);
|
||||||
fmt.println("t2 == t3:", t2 == t3)
|
fmt.println("t2 == t3:", t2 == t3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
any_type :: proc() {
|
any_type :: proc() {
|
||||||
a: any
|
a: any;
|
||||||
|
|
||||||
x: int = 123
|
x: int = 123;
|
||||||
y: f64 = 6.28
|
y: f64 = 6.28;
|
||||||
z: string = "Yo-Yo Ma"
|
z: string = "Yo-Yo Ma";
|
||||||
// All types can be implicit cast to `any`
|
// All types can be implicit cast to `any`
|
||||||
a = x
|
a = x;
|
||||||
a = y
|
a = y;
|
||||||
a = z
|
a = z;
|
||||||
a = a // This the "identity" type, it doesn't get converted
|
a = a; // This the "identity" type, it doesn't get converted
|
||||||
|
|
||||||
a = 123 // Literals are copied onto the stack first
|
a = 123; // Literals are copied onto the stack first
|
||||||
|
|
||||||
// any has two members
|
// any has two members
|
||||||
// data - rawptr to the data
|
// data - rawptr to the data
|
||||||
// type_info - pointer to the type info
|
// type_info - pointer to the type info
|
||||||
|
|
||||||
fmt.println(x, y, z)
|
fmt.println(x, y, z);
|
||||||
// See: fmt.odin
|
// See: fmt.odin
|
||||||
// For variadic any procedures in action
|
// For variadic any procedures in action
|
||||||
}
|
}
|
||||||
@@ -232,15 +235,15 @@ crazy_introspection :: proc() {
|
|||||||
TOMATO,
|
TOMATO,
|
||||||
}
|
}
|
||||||
|
|
||||||
s: string
|
s: string;
|
||||||
s = enum_to_string(Fruit.PEACH)
|
// s = enum_to_string(Fruit.PEACH);
|
||||||
fmt.println(s)
|
fmt.println(s);
|
||||||
|
|
||||||
f := Fruit.GRAPE
|
f := Fruit.GRAPE;
|
||||||
s = enum_to_string(f)
|
// s = enum_to_string(f);
|
||||||
fmt.println(s)
|
fmt.println(s);
|
||||||
|
|
||||||
fmt.println(f)
|
fmt.println(f);
|
||||||
// See: runtime.odin
|
// See: runtime.odin
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,15 +262,15 @@ crazy_introspection :: proc() {
|
|||||||
TOMATO,
|
TOMATO,
|
||||||
}
|
}
|
||||||
|
|
||||||
fruit_ti := type_info(Fruit)
|
fruit_ti := type_info(Fruit);
|
||||||
name := (fruit_ti as ^Type_Info.Named).name // Unsafe casts
|
name := (cast(^Type_Info.Named)fruit_ti).name; // Unsafe casts
|
||||||
info := type_info_base(fruit_ti) as ^Type_Info.Enum // Unsafe casts
|
info := cast(^Type_Info.Enum)type_info_base(fruit_ti); // Unsafe casts
|
||||||
|
|
||||||
fmt.printf("% :: enum % {\n", name, info.base);
|
fmt.printf("% :: enum % {\n", name, info.base);
|
||||||
for i := 0; i < info.values.count; i++ {
|
for i := 0; i < info.values.count; i += 1 {
|
||||||
fmt.printf("\t%\t= %,\n", info.names[i], info.values[i])
|
fmt.printf("\t%\t= %,\n", info.names[i], info.values[i]);
|
||||||
}
|
}
|
||||||
fmt.printf("}\n")
|
fmt.printf("}\n");
|
||||||
|
|
||||||
// NOTE(bill): look at that type-safe printf!
|
// NOTE(bill): look at that type-safe printf!
|
||||||
}
|
}
|
||||||
@@ -275,10 +278,10 @@ crazy_introspection :: proc() {
|
|||||||
{
|
{
|
||||||
Vector3 :: struct {x, y, z: f32}
|
Vector3 :: struct {x, y, z: f32}
|
||||||
|
|
||||||
a := Vector3{x = 1, y = 4, z = 9}
|
a := Vector3{x = 1, y = 4, z = 9};
|
||||||
fmt.println(a)
|
fmt.println(a);
|
||||||
b := Vector3{x = 9, y = 3, z = 1}
|
b := Vector3{x = 9, y = 3, z = 1};
|
||||||
fmt.println(b)
|
fmt.println(b);
|
||||||
|
|
||||||
// NOTE(bill): See fmt.odin
|
// NOTE(bill): See fmt.odin
|
||||||
}
|
}
|
||||||
@@ -301,7 +304,7 @@ namespaces_and_files :: proc() {
|
|||||||
#import "file.odin" as _
|
#import "file.odin" as _
|
||||||
|
|
||||||
// Exporting import
|
// Exporting import
|
||||||
#load "file.odin"
|
#include "file.odin"
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Talk about scope rules and diagram
|
// Talk about scope rules and diagram
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Demo 002
|
// Demo 002
|
||||||
#load "basic.odin"
|
#include "basic.odin"
|
||||||
#load "math.odin"
|
#include "math.odin"
|
||||||
// #load "game.odin"
|
// #include "game.odin"
|
||||||
|
|
||||||
#thread_local tls_int: int
|
#thread_local tls_int: int
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,282 @@
|
|||||||
|
#import "fmt.odin";
|
||||||
|
#import "utf8.odin";
|
||||||
|
// #import "atomic.odin";
|
||||||
|
// #import "hash.odin";
|
||||||
|
// #import "math.odin";
|
||||||
|
// #import "mem.odin";
|
||||||
|
// #import "opengl.odin";
|
||||||
|
// #import "os.odin";
|
||||||
|
// #import "sync.odin";
|
||||||
|
// #import win32 "sys/windows.odin";
|
||||||
|
|
||||||
|
main :: proc() {
|
||||||
|
// syntax();
|
||||||
|
procedure_overloading();
|
||||||
|
}
|
||||||
|
|
||||||
|
syntax :: proc() {
|
||||||
|
// Cyclic type checking
|
||||||
|
// Uncomment to see the error
|
||||||
|
// A :: struct {b: B};
|
||||||
|
// B :: struct {a: A};
|
||||||
|
|
||||||
|
x: int;
|
||||||
|
y := cast(f32)x;
|
||||||
|
z := transmute(u32)y;
|
||||||
|
// down_cast, union_cast are similar too
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Basic directives
|
||||||
|
fmt.printf("Basic directives = %s(%d): %s\n", #file, #line, #procedure);
|
||||||
|
// NOTE: new and improved `printf`
|
||||||
|
// TODO: It does need accurate float printing
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// record fields use the same syntax a procedure signatures
|
||||||
|
Thing1 :: struct {
|
||||||
|
x: f32,
|
||||||
|
y: int,
|
||||||
|
z: ^[]int,
|
||||||
|
};
|
||||||
|
Thing2 :: struct {x: f32, y: int, z: ^[]int};
|
||||||
|
|
||||||
|
// Slice interals are now just a `ptr+count`
|
||||||
|
slice: []int; compile_assert(size_of_val(slice) == 2*size_of(int));
|
||||||
|
|
||||||
|
// Helper type - Help the reader understand what it is quicker
|
||||||
|
My_Int :: type int;
|
||||||
|
My_Proc :: type proc(int) -> f32;
|
||||||
|
|
||||||
|
|
||||||
|
// All declarations with : are either variable or constant
|
||||||
|
// To make these declarations syntactically consistent
|
||||||
|
v_variable := 123;
|
||||||
|
c_constant :: 123;
|
||||||
|
c_type1 :: int;
|
||||||
|
c_type2 :: []int;
|
||||||
|
c_proc :: proc() { /* code here */ };
|
||||||
|
|
||||||
|
|
||||||
|
x += 1;
|
||||||
|
x -= 1;
|
||||||
|
// ++ and -- have been removed
|
||||||
|
// x++;
|
||||||
|
// x--;
|
||||||
|
// Question: Should they be added again?
|
||||||
|
// They were removed as they are redundant and statements, not expressions
|
||||||
|
// like in C/C++
|
||||||
|
|
||||||
|
|
||||||
|
// You can now build files as a `.dll`
|
||||||
|
// `odin build_dll demo.odin`
|
||||||
|
|
||||||
|
|
||||||
|
// New vector syntax
|
||||||
|
u, v: [vector 3]f32;
|
||||||
|
v[0] = 123;
|
||||||
|
v.x = 123; // valid for all vectors with count 1 to 4
|
||||||
|
|
||||||
|
// Next part
|
||||||
|
prefixes();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Prefix_Type :: struct {x: int, y: f32, z: rawptr};
|
||||||
|
|
||||||
|
thread_local my_tls: Prefix_Type;
|
||||||
|
|
||||||
|
prefixes :: proc() {
|
||||||
|
using var: Prefix_Type;
|
||||||
|
immutable const := Prefix_Type{1, 2, nil};
|
||||||
|
var.x = 123;
|
||||||
|
x = 123;
|
||||||
|
// const.x = 123; // const is immutable
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
foo :: proc(using immutable pt: Prefix_Type, immutable int_ptr: ^int) {
|
||||||
|
// int_ptr = nil; // Not valid
|
||||||
|
int_ptr^ = 123; // Is valid
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Same as C99's `restrict`
|
||||||
|
bar :: proc(no_alias a, b: ^int) {
|
||||||
|
// Assumes a never equals b so it can perform optimizations with that fact
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
when_statements();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
when_statements :: proc() {
|
||||||
|
X :: 123 + 12;
|
||||||
|
Y :: X/5;
|
||||||
|
COND :: Y > 0;
|
||||||
|
|
||||||
|
when COND {
|
||||||
|
fmt.println("Y > 0");
|
||||||
|
} else {
|
||||||
|
fmt.println("Y <= 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
when false {
|
||||||
|
this_code_does_not_exist(123, 321);
|
||||||
|
but_its_syntax_is_valid();
|
||||||
|
x :: ^^^^int;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreign_procedures();
|
||||||
|
}
|
||||||
|
|
||||||
|
#foreign_system_library win32_user "user32.lib" when ODIN_OS == "windows";
|
||||||
|
// NOTE: This is done on purpose for two reasons:
|
||||||
|
// * Makes it clear where the platform specific stuff is
|
||||||
|
// * Removes the need to solve the travelling salesman problem when importing files :P
|
||||||
|
|
||||||
|
foreign_procedures :: proc() {
|
||||||
|
ShowWindow :: proc(hwnd: rawptr, cmd_show: i32) -> i32 #foreign win32_user;
|
||||||
|
show_window :: proc(hwnd: rawptr, cmd_show: i32) -> i32 #foreign win32_user "ShowWindow";
|
||||||
|
// NOTE: If that library doesn't get used, it doesn't get linked with
|
||||||
|
// NOTE: There is not link checking yet to see if that procedure does come from that library
|
||||||
|
|
||||||
|
// See sys/windows.odin for more examples
|
||||||
|
|
||||||
|
special_expressions();
|
||||||
|
}
|
||||||
|
|
||||||
|
special_expressions :: proc() {
|
||||||
|
// Block expression
|
||||||
|
x := {
|
||||||
|
a: f32 = 123;
|
||||||
|
b := a-123;
|
||||||
|
c := b/a;
|
||||||
|
give c;
|
||||||
|
}; // semicolon is required as it's an expression
|
||||||
|
|
||||||
|
y := if x < 50 {
|
||||||
|
give x;
|
||||||
|
} else {
|
||||||
|
// TODO: Type cohesion is not yet finished
|
||||||
|
give 123;
|
||||||
|
}; // semicolon is required as it's an expression
|
||||||
|
|
||||||
|
|
||||||
|
// This is allows for inline blocks of code and will be a useful feature to have when
|
||||||
|
// macros will be implemented into the language
|
||||||
|
|
||||||
|
loops();
|
||||||
|
}
|
||||||
|
|
||||||
|
loops :: proc() {
|
||||||
|
// The C-style for loop
|
||||||
|
for i := 0; i < 123; i += 1 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for i := 0; i < 123; {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for false {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..<123 { // 123 exclusive
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0...122 { // 122 inclusive
|
||||||
|
}
|
||||||
|
|
||||||
|
for val, idx in 12..<16 {
|
||||||
|
fmt.println(val, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
primes := [...]int{2, 3, 5, 7, 11, 13, 17, 19};
|
||||||
|
|
||||||
|
for p in primes {
|
||||||
|
fmt.println(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pointers to arrays, slices, or strings are allowed
|
||||||
|
for _ in ^primes {
|
||||||
|
// ignore the value and just iterate across it
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
name := "你好,世界";
|
||||||
|
fmt.println(name);
|
||||||
|
for r in name {
|
||||||
|
compile_assert(type_of_val(r) == rune);
|
||||||
|
fmt.printf("%r\n", r);
|
||||||
|
}
|
||||||
|
|
||||||
|
when false {
|
||||||
|
for i, size := 0; i < name.count; i += size {
|
||||||
|
r: rune;
|
||||||
|
r, size = utf8.decode_rune(name[i:]);
|
||||||
|
fmt.printf("%r\n", r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
procedure_overloading();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
procedure_overloading :: proc() {
|
||||||
|
THINGF :: 14451.1;
|
||||||
|
THINGI :: 14451;
|
||||||
|
|
||||||
|
foo :: proc() {
|
||||||
|
fmt.printf("Zero args\n");
|
||||||
|
}
|
||||||
|
foo :: proc(i: int) {
|
||||||
|
fmt.printf("int arg, i=%d\n", i);
|
||||||
|
}
|
||||||
|
foo :: proc(f: f64) {
|
||||||
|
i := cast(int)f;
|
||||||
|
fmt.printf("f64 arg, f=%d\n", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
foo();
|
||||||
|
foo(THINGF);
|
||||||
|
// foo(THINGI); // 14451 is just a number so it could go to either procedures
|
||||||
|
foo(cast(int)THINGI);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
foo :: proc(x: ^i32) -> (int, int) {
|
||||||
|
fmt.println("^int");
|
||||||
|
return 123, cast(int)(x^);
|
||||||
|
}
|
||||||
|
foo :: proc(x: rawptr) {
|
||||||
|
fmt.println("rawptr");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
a: i32 = 123;
|
||||||
|
b: f32;
|
||||||
|
c: rawptr;
|
||||||
|
fmt.println(foo(^a));
|
||||||
|
foo(^b);
|
||||||
|
foo(c);
|
||||||
|
// foo(nil); // nil could go to numerous types thus the ambiguity
|
||||||
|
|
||||||
|
f: proc();
|
||||||
|
f = foo; // The correct `foo` to chosen
|
||||||
|
f();
|
||||||
|
|
||||||
|
|
||||||
|
// See math.odin and atomic.odin for more examples
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#load "win32.odin"
|
#include "win32.odin"
|
||||||
|
|
||||||
assume :: proc(cond: bool) #foreign "llvm.assume"
|
assume :: proc(cond: bool) #foreign "llvm.assume"
|
||||||
|
|
||||||
|
|||||||
+164
-159
@@ -1,34 +1,35 @@
|
|||||||
#import "win32.odin"
|
#import win32 "sys/windows.odin";
|
||||||
#import "fmt.odin"
|
#import "fmt.odin";
|
||||||
#import "os.odin"
|
#import "os.odin";
|
||||||
|
#import "mem.odin";
|
||||||
|
|
||||||
CANVAS_WIDTH :: 128
|
CANVAS_WIDTH :: 128;
|
||||||
CANVAS_HEIGHT :: 128
|
CANVAS_HEIGHT :: 128;
|
||||||
CANVAS_SCALE :: 3
|
CANVAS_SCALE :: 3;
|
||||||
FRAME_TIME :: 1.0/30.0
|
FRAME_TIME :: 1.0/30.0;
|
||||||
WINDOW_TITLE : string : "Punity\x00"
|
WINDOW_TITLE :: "Punity\x00";
|
||||||
|
|
||||||
_ := compile_assert(CANVAS_WIDTH % 16 == 0)
|
_ := compile_assert(CANVAS_WIDTH % 16 == 0);
|
||||||
|
|
||||||
WINDOW_WIDTH :: CANVAS_WIDTH * CANVAS_SCALE
|
WINDOW_WIDTH :: CANVAS_WIDTH * CANVAS_SCALE;
|
||||||
WINDOW_HEIGHT :: CANVAS_HEIGHT * CANVAS_SCALE
|
WINDOW_HEIGHT :: CANVAS_HEIGHT * CANVAS_SCALE;
|
||||||
|
|
||||||
|
|
||||||
STACK_CAPACITY :: 1<<20
|
STACK_CAPACITY :: 1<<20;
|
||||||
STORAGE_CAPACITY :: 1<<20
|
STORAGE_CAPACITY :: 1<<20;
|
||||||
|
|
||||||
DRAW_LIST_RESERVE :: 128
|
DRAW_LIST_RESERVE :: 128;
|
||||||
|
|
||||||
MAX_KEYS :: 256
|
MAX_KEYS :: 256;
|
||||||
|
|
||||||
Core :: struct {
|
Core :: struct {
|
||||||
stack: ^Bank
|
stack: ^Bank,
|
||||||
storage: ^Bank
|
storage: ^Bank,
|
||||||
|
|
||||||
running: bool
|
running: bool,
|
||||||
key_modifiers: u32
|
key_modifiers: u32,
|
||||||
key_states: [MAX_KEYS]byte
|
key_states: [MAX_KEYS]byte,
|
||||||
key_deltas: [MAX_KEYS]byte
|
key_deltas: [MAX_KEYS]byte,
|
||||||
|
|
||||||
perf_frame,
|
perf_frame,
|
||||||
perf_frame_inner,
|
perf_frame_inner,
|
||||||
@@ -36,70 +37,66 @@ Core :: struct {
|
|||||||
perf_audio,
|
perf_audio,
|
||||||
perf_blit,
|
perf_blit,
|
||||||
perf_blit_cvt,
|
perf_blit_cvt,
|
||||||
perf_blit_gdi: Perf_Span
|
perf_blit_gdi: Perf_Span,
|
||||||
|
|
||||||
frame: i64
|
frame: i64,
|
||||||
|
|
||||||
canvas: Canvas
|
canvas: Canvas,
|
||||||
draw_list: ^Draw_List
|
draw_list: ^Draw_List,
|
||||||
}
|
}
|
||||||
|
|
||||||
Perf_Span :: struct {
|
Perf_Span :: struct {
|
||||||
stamp: f64
|
stamp: f64,
|
||||||
delta: f32
|
delta: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
Bank :: struct {
|
Bank :: struct {
|
||||||
memory: []byte
|
memory: []byte,
|
||||||
cursor: int
|
cursor: int,
|
||||||
}
|
}
|
||||||
|
|
||||||
Bank_State :: struct {
|
Bank_State :: struct {
|
||||||
state: Bank
|
state: Bank,
|
||||||
bank: ^Bank
|
bank: ^Bank,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Color :: raw_union {
|
Color :: raw_union {
|
||||||
using channels: struct{ a, b, g, r: byte }
|
using channels: struct{a, b, g, r: byte},
|
||||||
rgba: u32
|
rgba: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
Palette :: struct {
|
Palette :: struct {
|
||||||
colors: [256]Color
|
colors: [256]Color,
|
||||||
colors_count: byte
|
colors_count: byte,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Rect :: raw_union {
|
Rect :: raw_union {
|
||||||
using minmax: struct {
|
using minmax: struct {min_x, min_y, max_x, max_y: int},
|
||||||
min_x, min_y, max_x, max_y: int
|
using pos: struct {left, top, right, bottom: int},
|
||||||
}
|
e: [4]int,
|
||||||
using pos: struct {
|
|
||||||
left, top, right, bottom: int
|
|
||||||
}
|
|
||||||
e: [4]int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Bitmap :: struct {
|
Bitmap :: struct {
|
||||||
pixels: []byte
|
pixels: []byte,
|
||||||
width: int
|
width: int,
|
||||||
height: int
|
height: int,
|
||||||
}
|
}
|
||||||
|
|
||||||
Font :: struct {
|
Font :: struct {
|
||||||
using bitmap: Bitmap
|
using bitmap: Bitmap,
|
||||||
char_width: int
|
char_width: int,
|
||||||
char_height: int
|
char_height: int,
|
||||||
}
|
}
|
||||||
|
|
||||||
Canvas :: struct {
|
Canvas :: struct {
|
||||||
using bitmap: ^Bitmap
|
using bitmap: ^Bitmap,
|
||||||
palette: Palette
|
palette: Palette,
|
||||||
translate_x: int
|
translate_x: int,
|
||||||
translate_y: int
|
translate_y: int,
|
||||||
clip: Rect
|
clip: Rect,
|
||||||
font: ^Font
|
font: ^Font,
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawFlag :: enum {
|
DrawFlag :: enum {
|
||||||
@@ -109,12 +106,9 @@ DrawFlag :: enum {
|
|||||||
MASK = 1<<2,
|
MASK = 1<<2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Draw_Item :: struct {}
|
||||||
Draw_List :: struct {
|
Draw_List :: struct {
|
||||||
Item :: struct {
|
items: []Draw_Item,
|
||||||
|
|
||||||
}
|
|
||||||
items: []Item
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Key :: enum {
|
Key :: enum {
|
||||||
@@ -268,113 +262,112 @@ Key :: enum {
|
|||||||
BACKSLASH = 92, /* \ */
|
BACKSLASH = 92, /* \ */
|
||||||
RIGHT_BRACKET = 93, /* ] */
|
RIGHT_BRACKET = 93, /* ] */
|
||||||
GRAVE_ACCENT = 96, /* ` */
|
GRAVE_ACCENT = 96, /* ` */
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
key_down :: proc(k: Key) -> bool {
|
key_down :: proc(k: Key) -> bool {
|
||||||
return _core.key_states[k] != 0
|
return _core.key_states[k] != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
key_pressed :: proc(k: Key) -> bool {
|
key_pressed :: proc(k: Key) -> bool {
|
||||||
return (_core.key_deltas[k] != 0) && key_down(k)
|
return (_core.key_deltas[k] != 0) && key_down(k);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
win32_perf_count_freq := win32.GetQueryPerformanceFrequency()
|
win32_perf_count_freq := win32.GetQueryPerformanceFrequency();
|
||||||
time_now :: proc() -> f64 {
|
time_now :: proc() -> f64 {
|
||||||
assert(win32_perf_count_freq != 0)
|
assert(win32_perf_count_freq != 0);
|
||||||
|
|
||||||
counter: i64
|
counter: i64;
|
||||||
win32.QueryPerformanceCounter(^counter)
|
win32.QueryPerformanceCounter(^counter);
|
||||||
result := counter as f64 / win32_perf_count_freq as f64
|
result := cast(f64)counter / cast(f64)win32_perf_count_freq;
|
||||||
return result
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
_core: Core
|
_core: Core;
|
||||||
|
|
||||||
run :: proc(user_init, user_step: proc(c: ^Core)) {
|
run :: proc(user_init, user_step: proc(c: ^Core)) {
|
||||||
using win32
|
using win32;
|
||||||
|
|
||||||
|
_core.running = true;
|
||||||
|
|
||||||
_core.running = true
|
win32_proc :: proc(hwnd: win32.HWND, msg: u32, wparam: win32.WPARAM, lparam: win32.LPARAM) -> win32.LRESULT #no_inline #cc_c {
|
||||||
|
|
||||||
win32_proc :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #no_inline #stdcall {
|
|
||||||
win32_app_key_mods :: proc() -> u32 {
|
win32_app_key_mods :: proc() -> u32 {
|
||||||
mods: u32 = 0
|
mods: u32 = 0;
|
||||||
|
|
||||||
if is_key_down(Key_Code.SHIFT) {
|
if is_key_down(Key_Code.SHIFT) {
|
||||||
mods |= Key.MOD_SHIFT as u32;
|
mods |= cast(u32)Key.MOD_SHIFT;
|
||||||
}
|
}
|
||||||
if is_key_down(Key_Code.CONTROL) {
|
if is_key_down(Key_Code.CONTROL) {
|
||||||
mods |= Key.MOD_CONTROL as u32;
|
mods |= cast(u32)Key.MOD_CONTROL;
|
||||||
}
|
}
|
||||||
if is_key_down(Key_Code.MENU) {
|
if is_key_down(Key_Code.MENU) {
|
||||||
mods |= Key.MOD_ALT as u32;
|
mods |= cast(u32)Key.MOD_ALT;
|
||||||
}
|
}
|
||||||
if is_key_down(Key_Code.LWIN) || is_key_down(Key_Code.RWIN) {
|
if is_key_down(Key_Code.LWIN) || is_key_down(Key_Code.RWIN) {
|
||||||
mods |= Key.MOD_SUPER as u32;
|
mods |= cast(u32)Key.MOD_SUPER;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mods
|
return mods;
|
||||||
}
|
}
|
||||||
|
|
||||||
match msg {
|
match msg {
|
||||||
case WM_KEYDOWN:
|
case WM_KEYDOWN:
|
||||||
_core.key_modifiers = win32_app_key_mods()
|
_core.key_modifiers = win32_app_key_mods();
|
||||||
if wparam < MAX_KEYS {
|
if wparam < MAX_KEYS {
|
||||||
_core.key_states[wparam] = 1
|
_core.key_states[wparam] = 1;
|
||||||
_core.key_deltas[wparam] = 1
|
_core.key_deltas[wparam] = 1;
|
||||||
}
|
}
|
||||||
return 0
|
return 0;
|
||||||
|
|
||||||
case WM_KEYUP:
|
case WM_KEYUP:
|
||||||
_core.key_modifiers = win32_app_key_mods()
|
_core.key_modifiers = win32_app_key_mods();
|
||||||
if wparam < MAX_KEYS {
|
if wparam < MAX_KEYS {
|
||||||
_core.key_states[wparam] = 0
|
_core.key_states[wparam] = 0;
|
||||||
_core.key_deltas[wparam] = 1
|
_core.key_deltas[wparam] = 1;
|
||||||
}
|
}
|
||||||
return 0
|
return 0;
|
||||||
|
|
||||||
case WM_CLOSE:
|
case WM_CLOSE:
|
||||||
PostQuitMessage(0)
|
PostQuitMessage(0);
|
||||||
_core.running = false
|
_core.running = false;
|
||||||
return 0
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return DefWindowProcA(hwnd, msg, wparam, lparam)
|
return DefWindowProcA(hwnd, msg, wparam, lparam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
window_class := WNDCLASSEXA{
|
window_class := WNDCLASSEXA{
|
||||||
class_name = ("Punity\x00" as string).data, // C-style string
|
class_name = (cast(string)"Punity\x00").data, // C-style string
|
||||||
size = size_of(WNDCLASSEXA) as u32,
|
size = size_of(WNDCLASSEXA),
|
||||||
style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
|
style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
|
||||||
instance = GetModuleHandleA(null) as HINSTANCE,
|
instance = cast(HINSTANCE)GetModuleHandleA(nil),
|
||||||
wnd_proc = win32_proc,
|
wnd_proc = win32_proc,
|
||||||
// wnd_proc = DefWindowProcA,
|
// wnd_proc = DefWindowProcA,
|
||||||
background = GetStockObject(BLACK_BRUSH) as HBRUSH,
|
background = cast(HBRUSH)GetStockObject(BLACK_BRUSH),
|
||||||
}
|
};
|
||||||
|
|
||||||
if RegisterClassExA(^window_class) == 0 {
|
if RegisterClassExA(^window_class) == 0 {
|
||||||
fmt.fprintln(os.stderr, "RegisterClassExA failed")
|
fmt.fprintln(os.stderr, "RegisterClassExA failed");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
screen_width := GetSystemMetrics(SM_CXSCREEN)
|
screen_width := GetSystemMetrics(SM_CXSCREEN);
|
||||||
screen_height := GetSystemMetrics(SM_CYSCREEN)
|
screen_height := GetSystemMetrics(SM_CYSCREEN);
|
||||||
|
|
||||||
rc: RECT
|
rc: RECT;
|
||||||
rc.left = (screen_width - WINDOW_WIDTH) / 2
|
rc.left = (screen_width - WINDOW_WIDTH) / 2;
|
||||||
rc.top = (screen_height - WINDOW_HEIGHT) / 2
|
rc.top = (screen_height - WINDOW_HEIGHT) / 2;
|
||||||
rc.right = rc.left + WINDOW_WIDTH
|
rc.right = rc.left + WINDOW_WIDTH;
|
||||||
rc.bottom = rc.top + WINDOW_HEIGHT
|
rc.bottom = rc.top + WINDOW_HEIGHT;
|
||||||
|
|
||||||
style: u32 = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX
|
style: u32 = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
|
||||||
assert(AdjustWindowRect(^rc, style, 0) != 0)
|
assert(AdjustWindowRect(^rc, style, 0) != 0);
|
||||||
|
|
||||||
wt := WINDOW_TITLE
|
wt := WINDOW_TITLE;
|
||||||
|
|
||||||
win32_window := CreateWindowExA(0,
|
win32_window := CreateWindowExA(0,
|
||||||
window_class.class_name,
|
window_class.class_name,
|
||||||
@@ -382,83 +375,82 @@ run :: proc(user_init, user_step: proc(c: ^Core)) {
|
|||||||
style,
|
style,
|
||||||
rc.left, rc.top,
|
rc.left, rc.top,
|
||||||
rc.right-rc.left, rc.bottom-rc.top,
|
rc.right-rc.left, rc.bottom-rc.top,
|
||||||
null, null, window_class.instance,
|
nil, nil, window_class.instance,
|
||||||
null);
|
nil);
|
||||||
|
|
||||||
if win32_window == null {
|
if win32_window == nil {
|
||||||
fmt.fprintln(os.stderr, "CreateWindowExA failed")
|
fmt.fprintln(os.stderr, "CreateWindowExA failed");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
window_bmi: BITMAPINFO;
|
window_bmi: BITMAPINFO;
|
||||||
window_bmi.size = size_of(BITMAPINFO.HEADER) as u32
|
window_bmi.size = size_of(BITMAPINFOHEADER);
|
||||||
window_bmi.width = CANVAS_WIDTH
|
window_bmi.width = CANVAS_WIDTH;
|
||||||
window_bmi.height = CANVAS_HEIGHT
|
window_bmi.height = CANVAS_HEIGHT;
|
||||||
window_bmi.planes = 1
|
window_bmi.planes = 1;
|
||||||
window_bmi.bit_count = 32
|
window_bmi.bit_count = 32;
|
||||||
window_bmi.compression = BI_RGB
|
window_bmi.compression = BI_RGB;
|
||||||
|
|
||||||
|
|
||||||
user_init(^_core)
|
user_init(^_core);
|
||||||
|
|
||||||
|
ShowWindow(win32_window, SW_SHOW);
|
||||||
ShowWindow(win32_window, SW_SHOW)
|
|
||||||
|
|
||||||
window_buffer := new_slice(u32, CANVAS_WIDTH * CANVAS_HEIGHT);
|
window_buffer := new_slice(u32, CANVAS_WIDTH * CANVAS_HEIGHT);
|
||||||
assert(window_buffer.data != null)
|
defer free(window_buffer);
|
||||||
defer free(window_buffer.data)
|
|
||||||
|
|
||||||
for i := 0; i < window_buffer.count; i++ {
|
|
||||||
window_buffer[i] = 0xff00ff
|
for i := 0; i < window_buffer.count; i += 1 {
|
||||||
|
window_buffer[i] = 0xff00ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
prev_time, curr_time,dt: f64
|
dt: f64;
|
||||||
prev_time = time_now()
|
prev_time := time_now();
|
||||||
curr_time = time_now()
|
curr_time := time_now();
|
||||||
total_time : f64 = 0
|
total_time : f64 = 0;
|
||||||
offset_x := 0;
|
offset_x := 0;
|
||||||
offset_y := 0;
|
offset_y := 0;
|
||||||
|
|
||||||
message: MSG
|
message: MSG;
|
||||||
for _core.running {
|
for _core.running {
|
||||||
curr_time = time_now()
|
curr_time = time_now();
|
||||||
dt = curr_time - prev_time
|
dt = curr_time - prev_time;
|
||||||
prev_time = curr_time
|
prev_time = curr_time;
|
||||||
total_time += dt
|
total_time += dt;
|
||||||
|
|
||||||
offset_x += 1
|
offset_x += 1;
|
||||||
offset_y += 2
|
offset_y += 2;
|
||||||
|
|
||||||
{
|
{
|
||||||
data: [128]byte
|
data: [128]byte;
|
||||||
buf := data[:0]
|
buf: fmt.Buffer;
|
||||||
fmt.bprintf(^buf, "Punity: % ms\x00", dt*1000)
|
buf.data = data[:];
|
||||||
win32.SetWindowTextA(win32_window, buf.data)
|
fmt.bprintf(^buf, "Punity: %.4f ms\x00", dt*1000);
|
||||||
|
win32.SetWindowTextA(win32_window, ^buf[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for y := 0; y < CANVAS_HEIGHT; y++ {
|
for y := 0; y < CANVAS_HEIGHT; y += 1 {
|
||||||
for x := 0; x < CANVAS_WIDTH; x++ {
|
for x := 0; x < CANVAS_WIDTH; x += 1 {
|
||||||
g := (x % 32) * 8
|
g := (x % 32) * 8;
|
||||||
b := (y % 32) * 8
|
b := (y % 32) * 8;
|
||||||
window_buffer[x + y*CANVAS_WIDTH] = (g << 8 | b) as u32
|
window_buffer[x + y*CANVAS_WIDTH] = cast(u32)(g << 8 | b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
memory_zero(^_core.key_deltas[0], size_of_val(_core.key_deltas[0]))
|
mem.zero(^_core.key_deltas[0], size_of_val(_core.key_deltas));
|
||||||
|
|
||||||
|
for PeekMessageA(^message, nil, 0, 0, PM_REMOVE) != 0 {
|
||||||
for PeekMessageA(^message, null, 0, 0, PM_REMOVE) != 0 {
|
|
||||||
if message.message == WM_QUIT {
|
if message.message == WM_QUIT {
|
||||||
_core.running = false
|
_core.running = false;
|
||||||
}
|
}
|
||||||
TranslateMessage(^message)
|
TranslateMessage(^message);
|
||||||
DispatchMessageA(^message)
|
DispatchMessageA(^message);
|
||||||
}
|
}
|
||||||
|
|
||||||
user_step(^_core)
|
user_step(^_core);
|
||||||
|
|
||||||
dc := GetDC(win32_window);
|
dc := GetDC(win32_window);
|
||||||
StretchDIBits(dc,
|
StretchDIBits(dc,
|
||||||
@@ -467,18 +459,31 @@ run :: proc(user_init, user_step: proc(c: ^Core)) {
|
|||||||
window_buffer.data,
|
window_buffer.data,
|
||||||
^window_bmi,
|
^window_bmi,
|
||||||
DIB_RGB_COLORS,
|
DIB_RGB_COLORS,
|
||||||
SRCCOPY)
|
SRCCOPY);
|
||||||
ReleaseDC(win32_window, dc)
|
ReleaseDC(win32_window, dc);
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
delta := time_now() - prev_time
|
delta := time_now() - prev_time;
|
||||||
ms := ((FRAME_TIME - delta) * 1000) as i32
|
ms := cast(i32)((FRAME_TIME - delta) * 1000);
|
||||||
if ms > 0 {
|
if ms > 0 {
|
||||||
win32.Sleep(ms)
|
win32.Sleep(ms);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_core.frame++
|
_core.frame += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
main :: proc() {
|
||||||
|
user_init :: proc(c: ^Core) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
user_step :: proc(c: ^Core) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
run(user_init, user_step);
|
||||||
|
}
|
||||||
|
|||||||
+4
-4
@@ -5,10 +5,10 @@ thing :: proc() {
|
|||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
|
||||||
#import "fmt.odin" as format
|
#import "fmt.odin";
|
||||||
|
|
||||||
thing :: proc() {
|
main :: proc() {
|
||||||
format.println("Hello2!")
|
fmt.println("hello, world!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ thing :: proc() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#load "fmt.odin"
|
#include "fmt.odin"
|
||||||
|
|
||||||
thing :: proc() {
|
thing :: proc() {
|
||||||
println("Hello5!")
|
println("Hello5!")
|
||||||
|
|||||||
+541
-232
@@ -1,288 +1,274 @@
|
|||||||
#shared_global_scope
|
#shared_global_scope;
|
||||||
|
|
||||||
#import "os.odin"
|
#import "os.odin";
|
||||||
#import "fmt.odin"
|
#import "fmt.odin";
|
||||||
#import "mem.odin"
|
#import "mem.odin";
|
||||||
|
#import "utf8.odin";
|
||||||
|
#import "hash.odin";
|
||||||
|
|
||||||
/*
|
// IMPORTANT NOTE(bill): `type_info` & `type_info_val` cannot be used within a
|
||||||
Optimization_Level :: enum {
|
// #shared_global_scope due to the internals of the compiler.
|
||||||
DEBUG,
|
// This could change at a later date if the all these data structures are
|
||||||
RELEASE,
|
// implemented within the compiler rather than in this "preload" file
|
||||||
}
|
|
||||||
|
|
||||||
Bounds_Check_Mode :: enum {
|
|
||||||
ON,
|
|
||||||
OFF,
|
|
||||||
}
|
|
||||||
|
|
||||||
Build_Options :: struct {
|
|
||||||
optimization_level: Optimization_Level
|
|
||||||
|
|
||||||
bounds_check: Bounds_Check_Mode
|
|
||||||
|
|
||||||
output_name: string
|
|
||||||
output_path: string
|
|
||||||
}
|
|
||||||
|
|
||||||
build_options: Build_Options
|
|
||||||
*/
|
|
||||||
|
|
||||||
// IMPORTANT NOTE(bill): Do not change the order of any of this data
|
// IMPORTANT NOTE(bill): Do not change the order of any of this data
|
||||||
// The compiler relies upon this _exact_ order
|
// The compiler relies upon this _exact_ order
|
||||||
Type_Info :: union {
|
Type_Info_Enum_Value :: raw_union {
|
||||||
Member :: struct #ordered {
|
f: f64,
|
||||||
name: string // can be empty if tuple
|
i: i64,
|
||||||
type_info: ^Type_Info
|
|
||||||
offset: int // offsets are not used in tuples
|
|
||||||
}
|
|
||||||
Record :: struct #ordered {
|
|
||||||
fields: []Member
|
|
||||||
size: int // in bytes
|
|
||||||
align: int // in bytes
|
|
||||||
packed: bool
|
|
||||||
ordered: bool
|
|
||||||
}
|
|
||||||
|
|
||||||
Named: struct #ordered {
|
|
||||||
name: string
|
|
||||||
base: ^Type_Info // This will _not_ be a Type_Info.Named
|
|
||||||
}
|
|
||||||
Integer: struct #ordered {
|
|
||||||
size: int // in bytes
|
|
||||||
signed: bool
|
|
||||||
}
|
|
||||||
Float: struct #ordered {
|
|
||||||
size: int // in bytes
|
|
||||||
}
|
|
||||||
Any: struct #ordered {}
|
|
||||||
String: struct #ordered {}
|
|
||||||
Boolean: struct #ordered {}
|
|
||||||
Pointer: struct #ordered {
|
|
||||||
elem: ^Type_Info // nil -> rawptr
|
|
||||||
}
|
|
||||||
Maybe: struct #ordered {
|
|
||||||
elem: ^Type_Info
|
|
||||||
}
|
|
||||||
Procedure: struct #ordered {
|
|
||||||
params: ^Type_Info // Type_Info.Tuple
|
|
||||||
results: ^Type_Info // Type_Info.Tuple
|
|
||||||
variadic: bool
|
|
||||||
}
|
|
||||||
Array: struct #ordered {
|
|
||||||
elem: ^Type_Info
|
|
||||||
elem_size: int
|
|
||||||
count: int
|
|
||||||
}
|
|
||||||
Slice: struct #ordered {
|
|
||||||
elem: ^Type_Info
|
|
||||||
elem_size: int
|
|
||||||
}
|
|
||||||
Vector: struct #ordered {
|
|
||||||
elem: ^Type_Info
|
|
||||||
elem_size: int
|
|
||||||
count: int
|
|
||||||
align: int
|
|
||||||
}
|
|
||||||
Tuple: Record
|
|
||||||
Struct: Record
|
|
||||||
Union: Record
|
|
||||||
Raw_Union: Record
|
|
||||||
Enum: struct #ordered {
|
|
||||||
base: ^Type_Info
|
|
||||||
values: []i64
|
|
||||||
names: []string
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// NOTE(bill): This must match the compiler's
|
||||||
|
Calling_Convention :: enum {
|
||||||
|
ODIN = 0,
|
||||||
|
C = 1,
|
||||||
|
STD = 2,
|
||||||
|
FAST = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
Type_Info_Record :: struct #ordered {
|
||||||
|
types: []^Type_Info,
|
||||||
|
names: []string,
|
||||||
|
offsets: []int, // offsets may not be used in tuples
|
||||||
|
size: int, // in bytes
|
||||||
|
align: int, // in bytes
|
||||||
|
packed: bool,
|
||||||
|
ordered: bool,
|
||||||
|
custom_align: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
Type_Info :: union {
|
||||||
|
Named{name: string, base: ^Type_Info},
|
||||||
|
Integer{size: int, signed: bool},
|
||||||
|
Float{size: int},
|
||||||
|
String{},
|
||||||
|
Boolean{},
|
||||||
|
Any{},
|
||||||
|
Pointer{
|
||||||
|
elem: ^Type_Info, // nil -> rawptr
|
||||||
|
},
|
||||||
|
Procedure{
|
||||||
|
params: ^Type_Info, // Type_Info.Tuple
|
||||||
|
results: ^Type_Info, // Type_Info.Tuple
|
||||||
|
variadic: bool,
|
||||||
|
convention: Calling_Convention,
|
||||||
|
},
|
||||||
|
Array{
|
||||||
|
elem: ^Type_Info,
|
||||||
|
elem_size: int,
|
||||||
|
count: int,
|
||||||
|
},
|
||||||
|
Dynamic_Array{elem: ^Type_Info, elem_size: int},
|
||||||
|
Slice {elem: ^Type_Info, elem_size: int},
|
||||||
|
Vector {elem: ^Type_Info, elem_size, count, align: int},
|
||||||
|
Tuple {using record: Type_Info_Record}, // Only really used for procedures
|
||||||
|
Struct {using record: Type_Info_Record},
|
||||||
|
Raw_Union {using record: Type_Info_Record},
|
||||||
|
Union{
|
||||||
|
common_fields: struct {
|
||||||
|
types: []^Type_Info,
|
||||||
|
names: []string,
|
||||||
|
offsets: []int, // offsets may not be used in tuples
|
||||||
|
},
|
||||||
|
variant_names: []string,
|
||||||
|
variant_types: []^Type_Info,
|
||||||
|
size: int,
|
||||||
|
align: int,
|
||||||
|
},
|
||||||
|
Enum{
|
||||||
|
base: ^Type_Info,
|
||||||
|
names: []string,
|
||||||
|
values: []Type_Info_Enum_Value,
|
||||||
|
},
|
||||||
|
Map{
|
||||||
|
key: ^Type_Info,
|
||||||
|
value: ^Type_Info,
|
||||||
|
generated_struct: ^Type_Info,
|
||||||
|
count: int, // == 0 if dynamic
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// NOTE(bill): only the ones that are needed (not all types)
|
||||||
|
// This will be set by the compiler
|
||||||
|
__type_table: []Type_Info;
|
||||||
|
|
||||||
type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
|
type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
|
||||||
if info == nil {
|
if info == nil {
|
||||||
return nil
|
return nil;
|
||||||
}
|
}
|
||||||
base := info
|
base := info;
|
||||||
match type i : base {
|
match i in base {
|
||||||
case Type_Info.Named:
|
case Type_Info.Named:
|
||||||
base = i.base
|
base = i.base;
|
||||||
}
|
}
|
||||||
return base
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type_info_base_without_enum :: proc(info: ^Type_Info) -> ^Type_Info {
|
||||||
|
if info == nil {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
base := info;
|
||||||
|
match i in base {
|
||||||
|
case Type_Info.Named:
|
||||||
|
base = i.base;
|
||||||
|
case Type_Info.Enum:
|
||||||
|
base = i.base;
|
||||||
|
}
|
||||||
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
assume :: proc(cond: bool) #foreign "llvm.assume"
|
assume :: proc(cond: bool) #foreign __llvm_core "llvm.assume";
|
||||||
|
|
||||||
__debug_trap :: proc() #foreign "llvm.debugtrap"
|
|
||||||
__trap :: proc() #foreign "llvm.trap"
|
|
||||||
read_cycle_counter :: proc() -> u64 #foreign "llvm.readcyclecounter"
|
|
||||||
|
|
||||||
bit_reverse16 :: proc(b: u16) -> u16 #foreign "llvm.bitreverse.i16"
|
|
||||||
bit_reverse32 :: proc(b: u32) -> u32 #foreign "llvm.bitreverse.i32"
|
|
||||||
bit_reverse64 :: proc(b: u64) -> u64 #foreign "llvm.bitreverse.i64"
|
|
||||||
|
|
||||||
byte_swap16 :: proc(b: u16) -> u16 #foreign "llvm.bswap.i16"
|
|
||||||
byte_swap32 :: proc(b: u32) -> u32 #foreign "llvm.bswap.i32"
|
|
||||||
byte_swap64 :: proc(b: u64) -> u64 #foreign "llvm.bswap.i64"
|
|
||||||
|
|
||||||
fmuladd32 :: proc(a, b, c: f32) -> f32 #foreign "llvm.fmuladd.f32"
|
|
||||||
fmuladd64 :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64"
|
|
||||||
|
|
||||||
|
__debug_trap :: proc() #foreign __llvm_core "llvm.debugtrap";
|
||||||
|
__trap :: proc() #foreign __llvm_core "llvm.trap";
|
||||||
|
read_cycle_counter :: proc() -> u64 #foreign __llvm_core "llvm.readcyclecounter";
|
||||||
|
|
||||||
|
__cpuid :: proc(level: u32, sig: ^u32) -> i32 #foreign __llvm_core "__get_cpuid";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// IMPORTANT NOTE(bill): Must be in this order (as the compiler relies upon it)
|
||||||
|
Allocator_Mode :: enum u8 {
|
||||||
|
ALLOC,
|
||||||
|
FREE,
|
||||||
|
FREE_ALL,
|
||||||
|
RESIZE,
|
||||||
|
}
|
||||||
|
Allocator_Proc :: #type proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||||
|
size, alignment: int,
|
||||||
|
old_memory: rawptr, old_size: int, flags: u64) -> rawptr;
|
||||||
Allocator :: struct #ordered {
|
Allocator :: struct #ordered {
|
||||||
Mode :: enum {
|
procedure: Allocator_Proc,
|
||||||
ALLOC,
|
data: rawptr,
|
||||||
FREE,
|
|
||||||
FREE_ALL,
|
|
||||||
RESIZE,
|
|
||||||
}
|
|
||||||
Proc :: type proc(allocator_data: rawptr, mode: Mode,
|
|
||||||
size, alignment: int,
|
|
||||||
old_memory: rawptr, old_size: int, flags: u64) -> rawptr
|
|
||||||
|
|
||||||
|
|
||||||
procedure: Proc;
|
|
||||||
data: rawptr
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Context :: struct #ordered {
|
Context :: struct #ordered {
|
||||||
thread_id: int
|
thread_id: int,
|
||||||
|
|
||||||
allocator: Allocator
|
allocator: Allocator,
|
||||||
|
|
||||||
user_data: rawptr
|
user_data: rawptr,
|
||||||
user_index: int
|
user_index: int,
|
||||||
}
|
}
|
||||||
|
|
||||||
#thread_local __context: Context
|
#thread_local __context: Context;
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_ALIGNMENT :: align_of({4}f32)
|
DEFAULT_ALIGNMENT :: align_of([vector 4]f32);
|
||||||
|
|
||||||
|
|
||||||
__check_context :: proc() {
|
__check_context :: proc() {
|
||||||
c := ^__context
|
c := ^__context;
|
||||||
|
|
||||||
if c.allocator.procedure == nil {
|
if c.allocator.procedure == nil {
|
||||||
c.allocator = default_allocator()
|
c.allocator = default_allocator();
|
||||||
}
|
}
|
||||||
if c.thread_id == 0 {
|
if c.thread_id == 0 {
|
||||||
c.thread_id = os.current_thread_id()
|
c.thread_id = os.current_thread_id();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
alloc :: proc(size: int) -> rawptr #inline { return alloc_align(size, DEFAULT_ALIGNMENT) }
|
alloc :: proc(size: int) -> rawptr #inline { return alloc_align(size, DEFAULT_ALIGNMENT); }
|
||||||
|
|
||||||
alloc_align :: proc(size, alignment: int) -> rawptr #inline {
|
alloc_align :: proc(size, alignment: int) -> rawptr #inline {
|
||||||
__check_context()
|
__check_context();
|
||||||
a := context.allocator
|
a := context.allocator;
|
||||||
return a.procedure(a.data, Allocator.Mode.ALLOC, size, alignment, nil, 0, 0)
|
return a.procedure(a.data, Allocator_Mode.ALLOC, size, alignment, nil, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
free :: proc(ptr: rawptr) #inline {
|
free_ptr_with_allocator :: proc(a: Allocator, ptr: rawptr) #inline {
|
||||||
__check_context()
|
if ptr == nil {
|
||||||
a := context.allocator
|
return;
|
||||||
if ptr != nil {
|
|
||||||
a.procedure(a.data, Allocator.Mode.FREE, 0, 0, ptr, 0, 0)
|
|
||||||
}
|
}
|
||||||
|
if a.procedure == nil {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
a.procedure(a.data, Allocator_Mode.FREE, 0, 0, ptr, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free_ptr :: proc(ptr: rawptr) #inline {
|
||||||
|
__check_context();
|
||||||
|
free_ptr_with_allocator(context.allocator, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
free_all :: proc() #inline {
|
free_all :: proc() #inline {
|
||||||
__check_context()
|
__check_context();
|
||||||
a := context.allocator
|
a := context.allocator;
|
||||||
a.procedure(a.data, Allocator.Mode.FREE_ALL, 0, 0, nil, 0, 0)
|
a.procedure(a.data, Allocator_Mode.FREE_ALL, 0, 0, nil, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
resize :: proc(ptr: rawptr, old_size, new_size: int) -> rawptr #inline { return resize_align(ptr, old_size, new_size, DEFAULT_ALIGNMENT) }
|
resize :: proc(ptr: rawptr, old_size, new_size: int) -> rawptr #inline { return resize_align(ptr, old_size, new_size, DEFAULT_ALIGNMENT); }
|
||||||
resize_align :: proc(ptr: rawptr, old_size, new_size, alignment: int) -> rawptr #inline {
|
resize_align :: proc(ptr: rawptr, old_size, new_size, alignment: int) -> rawptr #inline {
|
||||||
__check_context()
|
__check_context();
|
||||||
a := context.allocator
|
a := context.allocator;
|
||||||
return a.procedure(a.data, Allocator.Mode.RESIZE, new_size, alignment, ptr, old_size, 0)
|
return a.procedure(a.data, Allocator_Mode.RESIZE, new_size, alignment, ptr, old_size, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int) -> rawptr {
|
default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int) -> rawptr {
|
||||||
if old_memory == nil {
|
if old_memory == nil {
|
||||||
return alloc_align(new_size, alignment)
|
return alloc_align(new_size, alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
if new_size == 0 {
|
if new_size == 0 {
|
||||||
free(old_memory)
|
free(old_memory);
|
||||||
return nil
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
if new_size == old_size {
|
if new_size == old_size {
|
||||||
return old_memory
|
return old_memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
new_memory := alloc_align(new_size, alignment)
|
new_memory := alloc_align(new_size, alignment);
|
||||||
if new_memory == nil {
|
if new_memory == nil {
|
||||||
return nil
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
mem.copy(new_memory, old_memory, min(old_size, new_size));
|
mem.copy(new_memory, old_memory, min(old_size, new_size));;
|
||||||
free(old_memory)
|
free(old_memory);
|
||||||
return new_memory
|
return new_memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator.Mode,
|
default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||||
size, alignment: int,
|
size, alignment: int,
|
||||||
old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
|
old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
|
||||||
using Allocator.Mode
|
using Allocator_Mode;
|
||||||
/*
|
|
||||||
match mode {
|
match mode {
|
||||||
case ALLOC:
|
case ALLOC:
|
||||||
total_size := size + alignment + size_of(mem.AllocationHeader)
|
return os.heap_alloc(size);
|
||||||
ptr := os.heap_alloc(total_size)
|
|
||||||
header := ptr as ^mem.AllocationHeader
|
|
||||||
ptr = mem.align_forward(header+1, alignment)
|
|
||||||
mem.allocation_header_fill(header, ptr, size)
|
|
||||||
return mem.zero(ptr, size)
|
|
||||||
|
|
||||||
case FREE:
|
case FREE:
|
||||||
os.heap_free(mem.allocation_header(old_memory))
|
os.heap_free(old_memory);
|
||||||
return nil
|
return nil;
|
||||||
|
|
||||||
case FREE_ALL:
|
case FREE_ALL:
|
||||||
// NOTE(bill): Does nothing
|
// NOTE(bill): Does nothing
|
||||||
|
|
||||||
case RESIZE:
|
case RESIZE:
|
||||||
total_size := size + alignment + size_of(mem.AllocationHeader)
|
ptr := os.heap_resize(old_memory, size);
|
||||||
ptr := os.heap_resize(mem.allocation_header(old_memory), total_size)
|
assert(ptr != nil);
|
||||||
header := ptr as ^mem.AllocationHeader
|
return ptr;
|
||||||
ptr = mem.align_forward(header+1, alignment)
|
|
||||||
mem.allocation_header_fill(header, ptr, size)
|
|
||||||
return mem.zero(ptr, size)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
match mode {
|
|
||||||
case ALLOC:
|
|
||||||
return os.heap_alloc(size)
|
|
||||||
|
|
||||||
case FREE:
|
|
||||||
os.heap_free(old_memory)
|
|
||||||
return nil
|
|
||||||
|
|
||||||
case FREE_ALL:
|
|
||||||
// NOTE(bill): Does nothing
|
|
||||||
|
|
||||||
case RESIZE:
|
|
||||||
return os.heap_resize(old_memory, size)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
default_allocator :: proc() -> Allocator {
|
default_allocator :: proc() -> Allocator {
|
||||||
return Allocator{
|
return Allocator{
|
||||||
procedure = default_allocator_proc,
|
procedure = default_allocator_proc,
|
||||||
data = nil,
|
data = nil,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -297,71 +283,394 @@ default_allocator :: proc() -> Allocator {
|
|||||||
|
|
||||||
__string_eq :: proc(a, b: string) -> bool {
|
__string_eq :: proc(a, b: string) -> bool {
|
||||||
if a.count != b.count {
|
if a.count != b.count {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
if a.data == b.data {
|
if a.data == b.data {
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
return mem.compare(a.data, b.data, a.count) == 0
|
return __string_cmp(a, b) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
__string_cmp :: proc(a, b : string) -> int {
|
__string_cmp :: proc(a, b: string) -> int {
|
||||||
return mem.compare(a.data, b.data, min(a.count, b.count))
|
return mem.compare(cast([]byte)a, cast([]byte)b);
|
||||||
}
|
}
|
||||||
|
|
||||||
__string_ne :: proc(a, b: string) -> bool #inline { return !__string_eq(a, b) }
|
__string_ne :: proc(a, b: string) -> bool #inline { return !__string_eq(a, b); }
|
||||||
__string_lt :: proc(a, b: string) -> bool #inline { return __string_cmp(a, b) < 0 }
|
__string_lt :: proc(a, b: string) -> bool #inline { return __string_cmp(a, b) < 0; }
|
||||||
__string_gt :: proc(a, b: string) -> bool #inline { return __string_cmp(a, b) > 0 }
|
__string_gt :: proc(a, b: string) -> bool #inline { return __string_cmp(a, b) > 0; }
|
||||||
__string_le :: proc(a, b: string) -> bool #inline { return __string_cmp(a, b) <= 0 }
|
__string_le :: proc(a, b: string) -> bool #inline { return __string_cmp(a, b) <= 0; }
|
||||||
__string_ge :: proc(a, b: string) -> bool #inline { return __string_cmp(a, b) >= 0 }
|
__string_ge :: proc(a, b: string) -> bool #inline { return __string_cmp(a, b) >= 0; }
|
||||||
|
|
||||||
|
|
||||||
__assert :: proc(file: string, line, column: int, msg: string) #inline {
|
__assert :: proc(file: string, line, column: int, msg: string) #inline {
|
||||||
fmt.fprintf(os.stderr, "%(%:%) Runtime assertion: %\n",
|
fmt.fprintf(os.stderr, "%s(%d:%d) Runtime assertion: %s\n",
|
||||||
file, line, column, msg)
|
file, line, column, msg);
|
||||||
__debug_trap()
|
__debug_trap();
|
||||||
}
|
}
|
||||||
|
__panic :: proc(file: string, line, column: int, msg: string) #inline {
|
||||||
__bounds_check_error :: proc(file: string, line, column: int,
|
fmt.fprintf(os.stderr, "%s(%d:%d) Panic: %s\n",
|
||||||
index, count: int) {
|
file, line, column, msg);
|
||||||
|
__debug_trap();
|
||||||
|
}
|
||||||
|
__bounds_check_error :: proc(file: string, line, column: int, index, count: int) {
|
||||||
if 0 <= index && index < count {
|
if 0 <= index && index < count {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
fmt.fprintf(os.stderr, "%(%:%) Index % is out of bounds range [0, %)\n",
|
fmt.fprintf(os.stderr, "%s(%d:%d) Index %d is out of bounds range 0..%d\n",
|
||||||
file, line, column, index, count)
|
file, line, column, index, count);
|
||||||
__debug_trap()
|
__debug_trap();
|
||||||
}
|
}
|
||||||
|
|
||||||
__slice_expr_error :: proc(file: string, line, column: int,
|
__slice_expr_error :: proc(file: string, line, column: int, low, high, max: int) {
|
||||||
low, high, max: int) {
|
|
||||||
if 0 <= low && low <= high && high <= max {
|
if 0 <= low && low <= high && high <= max {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
fmt.fprintf(os.stderr, "%(%:%) Invalid slice indices: [%:%:%]\n",
|
fmt.fprintf(os.stderr, "%s(%d:%d) Invalid slice indices: [%d..%d..%d]\n",
|
||||||
file, line, column, low, high, max)
|
file, line, column, low, high, max);
|
||||||
__debug_trap()
|
__debug_trap();
|
||||||
}
|
}
|
||||||
__substring_expr_error :: proc(file: string, line, column: int,
|
__substring_expr_error :: proc(file: string, line, column: int, low, high: int) {
|
||||||
low, high: int) {
|
|
||||||
if 0 <= low && low <= high {
|
if 0 <= low && low <= high {
|
||||||
return
|
return;
|
||||||
|
}
|
||||||
|
fmt.fprintf(os.stderr, "%s(%d:%d) Invalid substring indices: [%d..%d]\n",
|
||||||
|
file, line, column, low, high);
|
||||||
|
__debug_trap();
|
||||||
|
}
|
||||||
|
__union_cast_check :: proc(ok: bool, file: string, line, column: int, from, to: ^Type_Info) {
|
||||||
|
if !ok {
|
||||||
|
fmt.fprintf(os.stderr, "%s(%d:%d) Invalid `union_cast` from %T to %T\n",
|
||||||
|
file, line, column, from, to);
|
||||||
|
__debug_trap();
|
||||||
}
|
}
|
||||||
fmt.fprintf(os.stderr, "%(%:%) Invalid substring indices: [%:%:%]\n",
|
|
||||||
file, line, column, low, high)
|
|
||||||
__debug_trap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__enum_to_string :: proc(info: ^Type_Info, value: i64) -> string {
|
__string_decode_rune :: proc(s: string) -> (rune, int) #inline {
|
||||||
match type ti : type_info_base(info) {
|
return utf8.decode_rune(s);
|
||||||
case Type_Info.Enum:
|
}
|
||||||
// TODO(bill): Search faster than linearly
|
|
||||||
for i := 0; i < ti.values.count; i++ {
|
|
||||||
if ti.values[i] == value {
|
Raw_Any :: struct #ordered {
|
||||||
return ti.names[i]
|
type_info: ^Type_Info,
|
||||||
}
|
data: rawptr,
|
||||||
|
}
|
||||||
|
|
||||||
|
Raw_String :: struct #ordered {
|
||||||
|
data: ^byte,
|
||||||
|
count: int,
|
||||||
|
};
|
||||||
|
|
||||||
|
Raw_Slice :: struct #ordered {
|
||||||
|
data: rawptr,
|
||||||
|
count: int,
|
||||||
|
capacity: int,
|
||||||
|
};
|
||||||
|
|
||||||
|
Raw_Dynamic_Array :: struct #ordered {
|
||||||
|
data: rawptr,
|
||||||
|
count: int,
|
||||||
|
capacity: int,
|
||||||
|
allocator: Allocator,
|
||||||
|
};
|
||||||
|
|
||||||
|
Raw_Dynamic_Map :: struct #ordered {
|
||||||
|
hashes: [dynamic]int,
|
||||||
|
entries: Raw_Dynamic_Array,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
__dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, capacity: int) -> bool {
|
||||||
|
array := cast(^Raw_Dynamic_Array)array_;
|
||||||
|
|
||||||
|
if capacity <= array.capacity {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
__check_context();
|
||||||
|
if array.allocator.procedure == nil {
|
||||||
|
array.allocator = context.allocator;
|
||||||
|
}
|
||||||
|
assert(array.allocator.procedure != nil);
|
||||||
|
|
||||||
|
old_size := array.capacity * elem_size;
|
||||||
|
new_size := capacity * elem_size;
|
||||||
|
allocator := array.allocator;
|
||||||
|
|
||||||
|
new_data := allocator.procedure(allocator.data, Allocator_Mode.RESIZE, new_size, elem_align, array.data, old_size, 0);
|
||||||
|
if new_data == nil {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
array.data = new_data;
|
||||||
|
array.capacity = capacity;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
__dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
|
||||||
|
items: rawptr, item_count: int) -> int {
|
||||||
|
array := cast(^Raw_Dynamic_Array)array_;
|
||||||
|
|
||||||
|
if item_count <= 0 || items == nil {
|
||||||
|
return array.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ok := true;
|
||||||
|
if array.capacity <= array.count+item_count {
|
||||||
|
capacity := 2 * array.capacity + max(8, item_count);
|
||||||
|
ok = __dynamic_array_reserve(array, elem_size, elem_align, capacity);
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
// TODO(bill): Better error handling for failed reservation
|
||||||
|
return array.count;
|
||||||
|
}
|
||||||
|
data := cast(^byte)array.data;
|
||||||
|
assert(data != nil);
|
||||||
|
mem.copy(data + (elem_size*array.count), items, elem_size * item_count);
|
||||||
|
array.count += item_count;
|
||||||
|
return array.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
__dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: int) -> int {
|
||||||
|
array := cast(^Raw_Dynamic_Array)array_;
|
||||||
|
|
||||||
|
ok := true;
|
||||||
|
if array.capacity <= array.count+1 {
|
||||||
|
capacity := 2 * array.capacity + max(8, 1);
|
||||||
|
ok = __dynamic_array_reserve(array, elem_size, elem_align, capacity);
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
// TODO(bill): Better error handling for failed reservation
|
||||||
|
return array.count;
|
||||||
|
}
|
||||||
|
data := cast(^byte)array.data;
|
||||||
|
assert(data != nil);
|
||||||
|
mem.zero(data + (elem_size*array.count), elem_size);
|
||||||
|
array.count++;
|
||||||
|
return array.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
__slice_append :: proc(slice_: rawptr, elem_size, elem_align: int,
|
||||||
|
items: rawptr, item_count: int) -> int {
|
||||||
|
slice := cast(^Raw_Slice)slice_;
|
||||||
|
|
||||||
|
if item_count <= 0 || items == nil {
|
||||||
|
return slice.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
item_count = min(slice.capacity-slice.count, item_count);
|
||||||
|
if item_count > 0 {
|
||||||
|
data := cast(^byte)slice.data;
|
||||||
|
assert(data != nil);
|
||||||
|
mem.copy(data + (elem_size*slice.count), items, elem_size * item_count);
|
||||||
|
slice.count += item_count;
|
||||||
|
}
|
||||||
|
return slice.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Map stuff
|
||||||
|
|
||||||
|
__default_hash :: proc(data: []byte) -> u64 {
|
||||||
|
return hash.fnv64a(data);
|
||||||
|
}
|
||||||
|
__default_hash_string :: proc(s: string) -> u64 {
|
||||||
|
return __default_hash(cast([]byte)s);
|
||||||
|
}
|
||||||
|
|
||||||
|
__Map_Key :: struct #ordered {
|
||||||
|
hash: u64,
|
||||||
|
str: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
__Map_Find_Result :: struct #ordered {
|
||||||
|
hash_index: int,
|
||||||
|
entry_prev: int,
|
||||||
|
entry_index: int,
|
||||||
|
}
|
||||||
|
|
||||||
|
__Map_Entry_Header :: struct #ordered {
|
||||||
|
key: __Map_Key,
|
||||||
|
next: int,
|
||||||
|
/*
|
||||||
|
value: Value_Type,
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
__Map_Header :: struct #ordered {
|
||||||
|
m: ^Raw_Dynamic_Map,
|
||||||
|
is_key_string: bool,
|
||||||
|
entry_size: int,
|
||||||
|
entry_align: int,
|
||||||
|
value_offset: int,
|
||||||
|
}
|
||||||
|
|
||||||
|
__dynamic_map_reserve :: proc(using header: __Map_Header, capacity: int) -> bool {
|
||||||
|
h := __dynamic_array_reserve(^m.hashes, size_of(int), align_of(int), capacity);
|
||||||
|
e := __dynamic_array_reserve(^m.entries, entry_size, entry_align, capacity);
|
||||||
|
return h && e;
|
||||||
|
}
|
||||||
|
|
||||||
|
__dynamic_map_rehash :: proc(using header: __Map_Header, new_count: int) {
|
||||||
|
new_header := header;
|
||||||
|
nm: Raw_Dynamic_Map;
|
||||||
|
new_header.m = ^nm;
|
||||||
|
|
||||||
|
reserve(nm.hashes, new_count);
|
||||||
|
nm.hashes.count = nm.hashes.capacity;
|
||||||
|
__dynamic_array_reserve(^nm.entries, entry_size, entry_align, m.entries.count);
|
||||||
|
for _, i in nm.hashes {
|
||||||
|
nm.hashes[i] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < nm.entries.count; i++ {
|
||||||
|
entry_header := __dynamic_map_get_entry(new_header, i);
|
||||||
|
data := cast(^byte)entry_header;
|
||||||
|
|
||||||
|
if nm.hashes.count == 0 {
|
||||||
|
__dynamic_map_grow(new_header);
|
||||||
|
}
|
||||||
|
|
||||||
|
fr := __dynamic_map_find(new_header, entry_header.key);
|
||||||
|
j := __dynamic_map_add_entry(new_header, entry_header.key);
|
||||||
|
if fr.entry_prev < 0 {
|
||||||
|
nm.hashes[fr.hash_index] = j;
|
||||||
|
} else {
|
||||||
|
e := __dynamic_map_get_entry(new_header, fr.entry_prev);
|
||||||
|
e.next = j;
|
||||||
|
}
|
||||||
|
|
||||||
|
e := __dynamic_map_get_entry(new_header, j);
|
||||||
|
e.next = fr.entry_index;
|
||||||
|
ndata := cast(^byte)e;
|
||||||
|
mem.copy(ndata+value_offset, data+value_offset, entry_size-value_offset);
|
||||||
|
if __dynamic_map_full(new_header) {
|
||||||
|
__dynamic_map_grow(new_header);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ""
|
free_ptr_with_allocator(header.m.hashes.allocator, header.m.hashes.data);
|
||||||
|
free_ptr_with_allocator(header.m.entries.allocator, header.m.entries.data);
|
||||||
|
header.m^ = nm;
|
||||||
|
}
|
||||||
|
|
||||||
|
__dynamic_map_get :: proc(h: __Map_Header, key: __Map_Key) -> rawptr {
|
||||||
|
index := __dynamic_map_find(h, key).entry_index;
|
||||||
|
if index >= 0 {
|
||||||
|
data := cast(^byte)__dynamic_map_get_entry(h, index);
|
||||||
|
val := data + h.value_offset;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
__dynamic_map_set :: proc(using h: __Map_Header, key: __Map_Key, value: rawptr) {
|
||||||
|
index: int;
|
||||||
|
|
||||||
|
if m.hashes.count == 0 {
|
||||||
|
__dynamic_map_grow(h);
|
||||||
|
}
|
||||||
|
fr := __dynamic_map_find(h, key);
|
||||||
|
if fr.entry_index >= 0 {
|
||||||
|
index = fr.entry_index;
|
||||||
|
} else {
|
||||||
|
index = __dynamic_map_add_entry(h, key);
|
||||||
|
if fr.entry_prev >= 0 {
|
||||||
|
entry := __dynamic_map_get_entry(h, fr.entry_prev);
|
||||||
|
entry.next = index;
|
||||||
|
} else {
|
||||||
|
m.hashes[fr.hash_index] = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
data := cast(^byte)__dynamic_map_get_entry(h, index);
|
||||||
|
val := data+value_offset;
|
||||||
|
mem.copy(val, value, entry_size-value_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if __dynamic_map_full(h) {
|
||||||
|
__dynamic_map_grow(h);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
__dynamic_map_grow :: proc(using h: __Map_Header) {
|
||||||
|
new_count := 2*m.entries.count + 8;
|
||||||
|
__dynamic_map_rehash(h, new_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
__dynamic_map_full :: proc(using h: __Map_Header) -> bool {
|
||||||
|
return cast(int)(0.75 * cast(f64)m.hashes.count) <= m.entries.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
__dynamic_map_hash_equal :: proc(h: __Map_Header, a, b: __Map_Key) -> bool {
|
||||||
|
if a.hash == b.hash {
|
||||||
|
if h.is_key_string {
|
||||||
|
return a.str == b.str;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
__dynamic_map_find :: proc(using h: __Map_Header, key: __Map_Key) -> __Map_Find_Result {
|
||||||
|
fr := __Map_Find_Result{-1, -1, -1};
|
||||||
|
if m.hashes.count > 0 {
|
||||||
|
fr.hash_index = cast(int)(key.hash % cast(u64)m.hashes.count);
|
||||||
|
fr.entry_index = m.hashes[fr.hash_index];
|
||||||
|
for fr.entry_index >= 0 {
|
||||||
|
entry := __dynamic_map_get_entry(h, fr.entry_index);
|
||||||
|
if __dynamic_map_hash_equal(h, entry.key, key) {
|
||||||
|
return fr;
|
||||||
|
}
|
||||||
|
fr.entry_prev = fr.entry_index;
|
||||||
|
fr.entry_index = entry.next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
__dynamic_map_add_entry :: proc(using h: __Map_Header, key: __Map_Key) -> int {
|
||||||
|
prev := m.entries.count;
|
||||||
|
c := __dynamic_array_append_nothing(^m.entries, entry_size, entry_align);
|
||||||
|
if c != prev {
|
||||||
|
end := __dynamic_map_get_entry(h, c-1);
|
||||||
|
end.key = key;
|
||||||
|
end.next = -1;
|
||||||
|
}
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
__dynamic_map_delete :: proc(using h: __Map_Header, key: __Map_Key) {
|
||||||
|
fr := __dynamic_map_find(h, key);
|
||||||
|
if fr.entry_index >= 0 {
|
||||||
|
__dynamic_map_erase(h, fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__dynamic_map_get_entry :: proc(using h: __Map_Header, index: int) -> ^__Map_Entry_Header {
|
||||||
|
data := cast(^byte)m.entries.data + index*entry_size;
|
||||||
|
return cast(^__Map_Entry_Header)data;
|
||||||
|
}
|
||||||
|
|
||||||
|
__dynamic_map_erase :: proc(using h: __Map_Header, fr: __Map_Find_Result) {
|
||||||
|
if fr.entry_prev < 0 {
|
||||||
|
m.hashes[fr.hash_index] = __dynamic_map_get_entry(h, fr.entry_index).next;
|
||||||
|
} else {
|
||||||
|
__dynamic_map_get_entry(h, fr.entry_prev).next = __dynamic_map_get_entry(h, fr.entry_index).next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if fr.entry_index == m.entries.count-1 {
|
||||||
|
m.entries.count--;
|
||||||
|
}
|
||||||
|
mem.copy(__dynamic_map_get_entry(h, fr.entry_index), __dynamic_map_get_entry(h, m.entries.count-1), entry_size);
|
||||||
|
last := __dynamic_map_find(h, __dynamic_map_get_entry(h, fr.entry_index).key);
|
||||||
|
if last.entry_prev >= 0 {
|
||||||
|
__dynamic_map_get_entry(h, last.entry_prev).next = fr.entry_index;
|
||||||
|
} else {
|
||||||
|
m.hashes[last.hash_index] = fr.entry_index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+138
-137
@@ -1,157 +1,158 @@
|
|||||||
#shared_global_scope
|
#shared_global_scope;
|
||||||
|
|
||||||
#import "fmt.odin"
|
|
||||||
|
|
||||||
|
|
||||||
__u128_mod :: proc(a, b: u128) -> u128 #link_name "__umodti3" {
|
// import "fmt.odin";
|
||||||
_, r := __u128_quo_mod(a, b)
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
__u128_quo :: proc(a, b: u128) -> u128 #link_name "__udivti3" {
|
// proc __u128_mod(a, b: u128) -> u128 #link_name "__umodti3" {
|
||||||
n, _ := __u128_quo_mod(a, b)
|
// var _, r := __u128_quo_mod(a, b)
|
||||||
return n
|
// return r
|
||||||
}
|
// }
|
||||||
|
|
||||||
__i128_mod :: proc(a, b: i128) -> i128 #link_name "__modti3" {
|
// proc __u128_quo(a, b: u128) -> u128 #link_name "__udivti3" {
|
||||||
_, r := __i128_quo_mod(a, b)
|
// var n, _ := __u128_quo_mod(a, b)
|
||||||
return r
|
// return n
|
||||||
}
|
// }
|
||||||
|
|
||||||
__i128_quo :: proc(a, b: i128) -> i128 #link_name "__divti3" {
|
// proc __i128_mod(a, b: i128) -> i128 #link_name "__modti3" {
|
||||||
n, _ := __i128_quo_mod(a, b)
|
// var _, r := __i128_quo_mod(a, b)
|
||||||
return n
|
// return r
|
||||||
}
|
// }
|
||||||
|
|
||||||
__i128_quo_mod :: proc(a, b: i128) -> (i128, i128) #link_name "__divmodti4" {
|
// proc __i128_quo(a, b: i128) -> i128 #link_name "__divti3" {
|
||||||
s := b >> 127
|
// var n, _ := __i128_quo_mod(a, b)
|
||||||
b = (b ~ s) - s
|
// return n
|
||||||
s = a >> 127
|
// }
|
||||||
a = (a ~ s) - s
|
|
||||||
|
|
||||||
n, r := __u128_quo_mod(a as u128, b as u128)
|
// proc __i128_quo_mod(a, b: i128) -> (i128, i128) #link_name "__divmodti4" {
|
||||||
return (n as i128 ~ s) - s, (r as i128 ~ s) - s
|
// var s := b >> 127
|
||||||
}
|
// b = (b ~ s) - s
|
||||||
|
// s = a >> 127
|
||||||
|
// a = (a ~ s) - s
|
||||||
|
|
||||||
|
// var n, r := __u128_quo_mod(a as u128, b as u128)
|
||||||
|
// return (n as i128 ~ s) - s, (r as i128 ~ s) - s
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
__u128_quo_mod :: proc(a, b: u128) -> (u128, u128) #link_name "__udivmodti4" {
|
// proc __u128_quo_mod(a, b: u128) -> (u128, u128) #link_name "__udivmodti4" {
|
||||||
clz :: proc(x: u64) -> u64 {
|
// proc clz(x: u64) -> u64 {
|
||||||
clz_u64 :: proc(x: u64, is_zero_undef: bool) -> u64 #foreign "llvm.ctlz.i64"
|
// proc clz_u64(x: u64, is_zero_undef: bool) -> u64 #foreign "llvm.ctlz.i64"
|
||||||
return clz_u64(x, false)
|
// return clz_u64(x, false)
|
||||||
}
|
// }
|
||||||
ctz :: proc(x: u64) -> u64 {
|
// proc ctz(x: u64) -> u64 {
|
||||||
ctz_u64 :: proc(x: u64, is_zero_undef: bool) -> u64 #foreign "llvm.cttz.i64"
|
// proc ctz_u64(x: u64, is_zero_undef: bool) -> u64 #foreign "llvm.cttz.i64"
|
||||||
return ctz_u64(x, false)
|
// return ctz_u64(x, false)
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
u128_lo_hi :: raw_union {
|
// u128_lo_hi :: raw_union {
|
||||||
all: u128
|
// all: u128
|
||||||
using _lohi: struct {lo, hi: u64}
|
// using _lohi: struct {lo, hi: u64;}
|
||||||
}
|
// }
|
||||||
|
|
||||||
n, d, q, r: u128_lo_hi
|
// n, d, q, r: u128_lo_hi
|
||||||
sr: u64
|
// sr: u64
|
||||||
|
|
||||||
n.all = a
|
// n.all = a
|
||||||
d.all = b
|
// d.all = b
|
||||||
|
|
||||||
if n.hi == 0 {
|
// if n.hi == 0 {
|
||||||
if d.hi == 0 {
|
// if d.hi == 0 {
|
||||||
return (n.lo / d.lo) as u128, (n.lo % d.lo) as u128
|
// return (n.lo / d.lo) as u128, (n.lo % d.lo) as u128
|
||||||
}
|
// }
|
||||||
return 0, n.lo as u128
|
// return 0, n.lo as u128
|
||||||
}
|
// }
|
||||||
if d.lo == 0 {
|
// if d.lo == 0 {
|
||||||
if d.hi == 0 {
|
// if d.hi == 0 {
|
||||||
return (n.hi / d.lo) as u128, (n.hi % d.lo) as u128
|
// return (n.hi / d.lo) as u128, (n.hi % d.lo) as u128
|
||||||
}
|
// }
|
||||||
if n.lo == 0 {
|
// if n.lo == 0 {
|
||||||
r.hi = n.hi % d.hi
|
// r.hi = n.hi % d.hi
|
||||||
r.lo = 0
|
// r.lo = 0
|
||||||
return (n.hi / d.hi) as u128, r.all
|
// return (n.hi / d.hi) as u128, r.all
|
||||||
}
|
// }
|
||||||
if (d.hi & (d.hi-1)) == 0 {
|
// if (d.hi & (d.hi-1)) == 0 {
|
||||||
r.lo = n.lo
|
// r.lo = n.lo
|
||||||
r.hi = n.hi & (d.hi-1)
|
// r.hi = n.hi & (d.hi-1)
|
||||||
return (n.hi >> ctz(d.hi)) as u128, r.all
|
// return (n.hi >> ctz(d.hi)) as u128, r.all
|
||||||
}
|
// }
|
||||||
|
|
||||||
sr = clz(d.hi) - clz(n.hi)
|
// sr = clz(d.hi) - clz(n.hi)
|
||||||
if sr > 64 - 2 {
|
// if sr > 64 - 2 {
|
||||||
return 0, n.all
|
// return 0, n.all
|
||||||
}
|
// }
|
||||||
sr++
|
// sr++
|
||||||
q.lo = 0
|
// q.lo = 0
|
||||||
q.hi = n.lo << (64-sr)
|
// q.hi = n.lo << (64-sr)
|
||||||
r.hi = n.hi >> sr
|
// r.hi = n.hi >> sr
|
||||||
r.lo = (n.hi << (64-sr)) | (n.lo >> sr)
|
// r.lo = (n.hi << (64-sr)) | (n.lo >> sr)
|
||||||
} else {
|
// } else {
|
||||||
if d.hi == 0 {
|
// if d.hi == 0 {
|
||||||
if (d.lo & (d.lo - 1)) == 0 {
|
// if (d.lo & (d.lo - 1)) == 0 {
|
||||||
rem := (n.lo % (d.lo - 1)) as u128
|
// var rem := (n.lo % (d.lo - 1)) as u128
|
||||||
if d.lo == 1 {
|
// if d.lo == 1 {
|
||||||
return n.all, rem
|
// return n.all, rem
|
||||||
}
|
// }
|
||||||
sr = ctz(d.lo)
|
// sr = ctz(d.lo)
|
||||||
q.hi = n.hi >> sr
|
// q.hi = n.hi >> sr
|
||||||
q.lo = (n.hi << (64-sr)) | (n.lo >> sr);
|
// q.lo = (n.hi << (64-sr)) | (n.lo >> sr)
|
||||||
return q.all, rem
|
// return q.all, rem
|
||||||
}
|
// }
|
||||||
|
|
||||||
sr = 1 + 64 + clz(d.lo) - clz(n.hi)
|
// sr = 1 + 64 + clz(d.lo) - clz(n.hi)
|
||||||
|
|
||||||
q.all = n.all << (128-sr)
|
// q.all = n.all << (128-sr)
|
||||||
r.all = n.all >> sr
|
// r.all = n.all >> sr
|
||||||
if sr == 64 {
|
// if sr == 64 {
|
||||||
q.lo = 0
|
// q.lo = 0
|
||||||
q.hi = n.lo
|
// q.hi = n.lo
|
||||||
r.hi = 0
|
// r.hi = 0
|
||||||
r.lo = n.hi
|
// r.lo = n.hi
|
||||||
} else if sr < 64 {
|
// } else if sr < 64 {
|
||||||
q.lo = 0
|
// q.lo = 0
|
||||||
q.hi = n.lo << (64-sr)
|
// q.hi = n.lo << (64-sr)
|
||||||
r.hi = n.hi >> sr
|
// r.hi = n.hi >> sr
|
||||||
r.lo = (n.hi << (64-sr)) | (n.lo >> sr)
|
// r.lo = (n.hi << (64-sr)) | (n.lo >> sr)
|
||||||
} else {
|
// } else {
|
||||||
q.lo = n.lo << (128-sr)
|
// q.lo = n.lo << (128-sr)
|
||||||
q.hi = (n.hi << (128-sr)) | (n.lo >> (sr-64))
|
// q.hi = (n.hi << (128-sr)) | (n.lo >> (sr-64))
|
||||||
r.hi = 0
|
// r.hi = 0
|
||||||
r.lo = n.hi >> (sr-64)
|
// r.lo = n.hi >> (sr-64)
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
sr = clz(d.hi) - clz(n.hi)
|
// sr = clz(d.hi) - clz(n.hi)
|
||||||
if sr > 64-1 {
|
// if sr > 64-1 {
|
||||||
return 0, n.all
|
// return 0, n.all
|
||||||
}
|
// }
|
||||||
sr++
|
// sr++
|
||||||
q.lo = 0
|
// q.lo = 0
|
||||||
q.hi = n.lo << (64-sr)
|
// q.hi = n.lo << (64-sr)
|
||||||
r.all = n.all >> sr
|
// r.all = n.all >> sr
|
||||||
if sr < 64 {
|
// if sr < 64 {
|
||||||
r.hi = n.hi >> sr
|
// r.hi = n.hi >> sr
|
||||||
r.lo = (n.hi << (64-sr)) | (n.lo >> sr)
|
// r.lo = (n.hi << (64-sr)) | (n.lo >> sr)
|
||||||
} else {
|
// } else {
|
||||||
r.hi = 0
|
// r.hi = 0
|
||||||
r.lo = n.hi
|
// r.lo = n.hi
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
carry: u64
|
// carry: u64
|
||||||
for ; sr > 0; sr-- {
|
// for ; sr > 0; sr-- {
|
||||||
r.hi = (r.hi << 1) | (r.lo >> (64-1))
|
// r.hi = (r.hi << 1) | (r.lo >> (64-1))
|
||||||
r.lo = (r.lo << 1) | (r.hi >> (64-1))
|
// r.lo = (r.lo << 1) | (r.hi >> (64-1))
|
||||||
q.hi = (q.hi << 1) | (q.lo >> (64-1))
|
// q.hi = (q.hi << 1) | (q.lo >> (64-1))
|
||||||
q.lo = (q.lo << 1) | carry
|
// q.lo = (q.lo << 1) | carry
|
||||||
|
|
||||||
carry = 0
|
// carry = 0
|
||||||
if r.all >= d.all {
|
// if r.all >= d.all {
|
||||||
r.all -= d.all
|
// r.all -= d.all
|
||||||
carry = 1
|
// carry = 1
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
// q.all = (q.all << 1) | (carry as u128)
|
||||||
|
// return q.all, r.all
|
||||||
|
// }
|
||||||
|
|
||||||
q.all = (q.all << 1) | (carry as u128)
|
|
||||||
return q.all, r.all
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
// TODO(bill): Use assembly instead here to implement atomics
|
||||||
|
// Inline vs external file?
|
||||||
|
|
||||||
|
#import win32 "sys/windows.odin" when ODIN_OS == "windows";
|
||||||
|
_ := compile_assert(ODIN_ARCH == "amd64"); // TODO(bill): x86 version
|
||||||
|
|
||||||
|
|
||||||
|
yield_thread :: proc() { win32.mm_pause(); }
|
||||||
|
mfence :: proc() { win32.ReadWriteBarrier(); }
|
||||||
|
sfence :: proc() { win32.WriteBarrier(); }
|
||||||
|
lfence :: proc() { win32.ReadBarrier(); }
|
||||||
|
|
||||||
|
|
||||||
|
load :: proc(a: ^i32) -> i32 {
|
||||||
|
return a^;
|
||||||
|
}
|
||||||
|
store :: proc(a: ^i32, value: i32) {
|
||||||
|
a^ = value;
|
||||||
|
}
|
||||||
|
compare_exchange :: proc(a: ^i32, expected, desired: i32) -> i32 {
|
||||||
|
return win32.InterlockedCompareExchange(a, desired, expected);
|
||||||
|
}
|
||||||
|
exchanged :: proc(a: ^i32, desired: i32) -> i32 {
|
||||||
|
return win32.InterlockedExchange(a, desired);
|
||||||
|
}
|
||||||
|
fetch_add :: proc(a: ^i32, operand: i32) -> i32 {
|
||||||
|
return win32.InterlockedExchangeAdd(a, operand);
|
||||||
|
|
||||||
|
}
|
||||||
|
fetch_and :: proc(a: ^i32, operand: i32) -> i32 {
|
||||||
|
return win32.InterlockedAnd(a, operand);
|
||||||
|
}
|
||||||
|
fetch_or :: proc(a: ^i32, operand: i32) -> i32 {
|
||||||
|
return win32.InterlockedOr(a, operand);
|
||||||
|
}
|
||||||
|
spin_lock :: proc(a: ^i32, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
|
||||||
|
old_value := compare_exchange(a, 1, 0);
|
||||||
|
counter := 0;
|
||||||
|
for old_value != 0 && (time_out < 0 || counter < time_out) {
|
||||||
|
counter++;
|
||||||
|
yield_thread();
|
||||||
|
old_value = compare_exchange(a, 1, 0);
|
||||||
|
mfence();
|
||||||
|
}
|
||||||
|
return old_value == 0;
|
||||||
|
}
|
||||||
|
spin_unlock :: proc(a: ^i32) {
|
||||||
|
store(a, 0);
|
||||||
|
mfence();
|
||||||
|
}
|
||||||
|
try_acquire_lock :: proc(a: ^i32) -> bool {
|
||||||
|
yield_thread();
|
||||||
|
old_value := compare_exchange(a, 1, 0);
|
||||||
|
mfence();
|
||||||
|
return old_value == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
load :: proc(a: ^i64) -> i64 {
|
||||||
|
return a^;
|
||||||
|
}
|
||||||
|
store :: proc(a: ^i64, value: i64) {
|
||||||
|
a^ = value;
|
||||||
|
}
|
||||||
|
compare_exchange :: proc(a: ^i64, expected, desired: i64) -> i64 {
|
||||||
|
return win32.InterlockedCompareExchange64(a, desired, expected);
|
||||||
|
}
|
||||||
|
exchanged :: proc(a: ^i64, desired: i64) -> i64 {
|
||||||
|
return win32.InterlockedExchange64(a, desired);
|
||||||
|
}
|
||||||
|
fetch_add :: proc(a: ^i64, operand: i64) -> i64 {
|
||||||
|
return win32.InterlockedExchangeAdd64(a, operand);
|
||||||
|
}
|
||||||
|
fetch_and :: proc(a: ^i64, operand: i64) -> i64 {
|
||||||
|
return win32.InterlockedAnd64(a, operand);
|
||||||
|
}
|
||||||
|
fetch_or :: proc(a: ^i64, operand: i64) -> i64 {
|
||||||
|
return win32.InterlockedOr64(a, operand);
|
||||||
|
}
|
||||||
|
spin_lock :: proc(a: ^i64, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
|
||||||
|
old_value := compare_exchange(a, 1, 0);
|
||||||
|
counter := 0;
|
||||||
|
for old_value != 0 && (time_out < 0 || counter < time_out) {
|
||||||
|
counter++;
|
||||||
|
yield_thread();
|
||||||
|
old_value = compare_exchange(a, 1, 0);
|
||||||
|
mfence();
|
||||||
|
}
|
||||||
|
return old_value == 0;
|
||||||
|
}
|
||||||
|
spin_unlock :: proc(a: ^i64) {
|
||||||
|
store(a, 0);
|
||||||
|
mfence();
|
||||||
|
}
|
||||||
|
try_acquire_lock :: proc(a: ^i64) -> bool {
|
||||||
|
yield_thread();
|
||||||
|
old_value := compare_exchange(a, 1, 0);
|
||||||
|
mfence();
|
||||||
|
return old_value == 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,257 @@
|
|||||||
|
// #import "fmt.odin";
|
||||||
|
// Multiple precision decimal numbers
|
||||||
|
// NOTE: This is only for floating point printing and nothing else
|
||||||
|
|
||||||
|
Decimal :: struct {
|
||||||
|
digits: [384]byte, // big-endian digits
|
||||||
|
count: int,
|
||||||
|
decimal_point: int,
|
||||||
|
neg, trunc: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
decimal_to_string :: proc(buf: []byte, a: ^Decimal) -> string {
|
||||||
|
digit_zero :: proc(buf: []byte) -> int {
|
||||||
|
for _, i in buf {
|
||||||
|
buf[i] = '0';
|
||||||
|
}
|
||||||
|
return buf.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
n := 10 + a.count + abs(a.decimal_point);
|
||||||
|
|
||||||
|
// TODO(bill): make this work with a buffer that's not big enough
|
||||||
|
assert(buf.count >= n);
|
||||||
|
buf = buf[..n];
|
||||||
|
|
||||||
|
if a.count == 0 {
|
||||||
|
buf[0] = '0';
|
||||||
|
return cast(string)buf[0..1];
|
||||||
|
}
|
||||||
|
|
||||||
|
w := 0;
|
||||||
|
if a.decimal_point <= 0 {
|
||||||
|
buf[w] = '0'; w++;
|
||||||
|
buf[w] = '.'; w++;
|
||||||
|
w += digit_zero(buf[w .. w-a.decimal_point]);
|
||||||
|
w += copy(buf[w..], a.digits[0..a.count]);
|
||||||
|
} else if a.decimal_point < a.count {
|
||||||
|
w += copy(buf[w..], a.digits[0..a.decimal_point]);
|
||||||
|
buf[w] = '.'; w++;
|
||||||
|
w += copy(buf[w..], a.digits[a.decimal_point .. a.count]);
|
||||||
|
} else {
|
||||||
|
w += copy(buf[w..], a.digits[0..a.count]);
|
||||||
|
w += digit_zero(buf[w .. w+a.decimal_point-a.count]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cast(string)buf[0..w];
|
||||||
|
}
|
||||||
|
|
||||||
|
// trim trailing zeros
|
||||||
|
trim :: proc(a: ^Decimal) {
|
||||||
|
for a.count > 0 && a.digits[a.count-1] == '0' {
|
||||||
|
a.count--;
|
||||||
|
}
|
||||||
|
if a.count == 0 {
|
||||||
|
a.decimal_point = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
assign :: proc(a: ^Decimal, i: u64) {
|
||||||
|
buf: [32]byte;
|
||||||
|
n := 0;
|
||||||
|
for i > 0 {
|
||||||
|
j := i/10;
|
||||||
|
i -= 10*j;
|
||||||
|
buf[n] = cast(byte)('0'+i);
|
||||||
|
n++;
|
||||||
|
i = j;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.count = 0;
|
||||||
|
for n--; n >= 0; n-- {
|
||||||
|
a.digits[a.count] = buf[n];
|
||||||
|
a.count++;
|
||||||
|
}
|
||||||
|
a.decimal_point = a.count;
|
||||||
|
trim(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint_size :: 8*size_of(uint);
|
||||||
|
max_shift :: uint_size-4;
|
||||||
|
|
||||||
|
shift_right :: proc(a: ^Decimal, k: uint) {
|
||||||
|
r := 0; // read index
|
||||||
|
w := 0; // write index
|
||||||
|
|
||||||
|
n: uint;
|
||||||
|
for ; n>>k == 0; r++ {
|
||||||
|
if r >= a.count {
|
||||||
|
if n == 0 {
|
||||||
|
// Just in case
|
||||||
|
a.count = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for n>>k == 0 {
|
||||||
|
n = n * 10;
|
||||||
|
r++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
c := cast(uint)a.digits[r];
|
||||||
|
n = n*10 + c - '0';
|
||||||
|
}
|
||||||
|
a.decimal_point -= r-1;
|
||||||
|
|
||||||
|
mask: uint = (1<<k) - 1;
|
||||||
|
|
||||||
|
for ; r < a.count; r++ {
|
||||||
|
c := cast(uint)a.digits[r];
|
||||||
|
dig := n>>k;
|
||||||
|
n &= mask;
|
||||||
|
a.digits[w] = cast(byte)('0' + dig);
|
||||||
|
w++;
|
||||||
|
n = n*10 + c - '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
for n > 0 {
|
||||||
|
dig := n>>k;
|
||||||
|
n &= mask;
|
||||||
|
if w < a.digits.count {
|
||||||
|
a.digits[w] = cast(byte)('0' + dig);
|
||||||
|
w++;
|
||||||
|
} else if dig > 0 {
|
||||||
|
a.trunc = true;
|
||||||
|
}
|
||||||
|
n *= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
a.count = w;
|
||||||
|
trim(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
shift_left :: proc(a: ^Decimal, k: uint) {
|
||||||
|
delta := cast(int)(k/4);
|
||||||
|
|
||||||
|
r := a.count; // read index
|
||||||
|
w := a.count+delta; // write index
|
||||||
|
|
||||||
|
n: uint;
|
||||||
|
for r--; r >= 0; r-- {
|
||||||
|
n += (cast(uint)a.digits[r] - '0') << k;
|
||||||
|
quo := n/10;
|
||||||
|
rem := n - 10*quo;
|
||||||
|
w--;
|
||||||
|
if w < a.digits.count {
|
||||||
|
a.digits[w] = cast(byte)('0' + rem);
|
||||||
|
} else if rem != 0 {
|
||||||
|
a.trunc = true;
|
||||||
|
}
|
||||||
|
n = quo;
|
||||||
|
}
|
||||||
|
|
||||||
|
for n > 0 {
|
||||||
|
quo := n/10;
|
||||||
|
rem := n - 10*quo;
|
||||||
|
w--;
|
||||||
|
if w < a.digits.count {
|
||||||
|
a.digits[w] = cast(byte)('0' + rem);
|
||||||
|
} else if rem != 0 {
|
||||||
|
a.trunc = true;
|
||||||
|
}
|
||||||
|
n = quo;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.count += delta;
|
||||||
|
a.count = min(a.count, a.digits.count);
|
||||||
|
a.decimal_point += delta;
|
||||||
|
trim(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
shift :: proc(a: ^Decimal, k: int) {
|
||||||
|
match {
|
||||||
|
case a.count == 0:
|
||||||
|
// no need to update
|
||||||
|
case k > 0:
|
||||||
|
for k > max_shift {
|
||||||
|
shift_left(a, max_shift);
|
||||||
|
k -= max_shift;
|
||||||
|
}
|
||||||
|
shift_left(a, cast(uint)k);
|
||||||
|
|
||||||
|
|
||||||
|
case k < 0:
|
||||||
|
for k < -max_shift {
|
||||||
|
shift_right(a, max_shift);
|
||||||
|
k += max_shift;
|
||||||
|
}
|
||||||
|
shift_right(a, cast(uint)-k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
can_round_up :: proc(a: ^Decimal, nd: int) -> bool {
|
||||||
|
if nd < 0 || nd >= a.count { return false ; }
|
||||||
|
if a.digits[nd] == '5' && nd+1 == a.count {
|
||||||
|
if a.trunc {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return nd > 0 && (a.digits[nd-1]-'0')%2 != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.digits[nd] >= '5';
|
||||||
|
}
|
||||||
|
|
||||||
|
round :: proc(a: ^Decimal, nd: int) {
|
||||||
|
if nd < 0 || nd >= a.count { return; }
|
||||||
|
if can_round_up(a, nd) {
|
||||||
|
round_up(a, nd);
|
||||||
|
} else {
|
||||||
|
round_down(a, nd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
round_up :: proc(a: ^Decimal, nd: int) {
|
||||||
|
if nd < 0 || nd >= a.count { return; }
|
||||||
|
|
||||||
|
for i := nd-1; i >= 0; i-- {
|
||||||
|
if c := a.digits[i]; c < '9' {
|
||||||
|
a.digits[i]++;
|
||||||
|
a.count = i+1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Number is just 9s
|
||||||
|
a.digits[0] = '1';
|
||||||
|
a.count = 1;
|
||||||
|
a.decimal_point++;
|
||||||
|
}
|
||||||
|
|
||||||
|
round_down :: proc(a: ^Decimal, nd: int) {
|
||||||
|
if nd < 0 || nd >= a.count { return; }
|
||||||
|
a.count = nd;
|
||||||
|
trim(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Extract integer part, rounded appropriately. There are no guarantees about overflow.
|
||||||
|
rounded_integer :: proc(a: ^Decimal) -> u64 {
|
||||||
|
if a.decimal_point > 20 {
|
||||||
|
return 0xffff_ffff_ffff_ffff;
|
||||||
|
}
|
||||||
|
i: int;
|
||||||
|
n: u64 = 0;
|
||||||
|
m := min(a.decimal_point, a.count);
|
||||||
|
for i = 0; i < m; i++ {
|
||||||
|
n = n*10 + cast(u64)(a.digits[i]-'0');
|
||||||
|
}
|
||||||
|
for ; i < a.decimal_point; i++ {
|
||||||
|
n *= 10;
|
||||||
|
}
|
||||||
|
if can_round_up(a, a.decimal_point) {
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
+947
-505
File diff suppressed because it is too large
Load Diff
+159
-121
@@ -1,170 +1,208 @@
|
|||||||
crc32 :: proc(data: rawptr, len: int) -> u32 {
|
crc32 :: proc(data: []byte) -> u32 {
|
||||||
result := ~(0 as u32)
|
result := ~cast(u32)0;
|
||||||
s := slice_ptr(data as ^u8, len)
|
for b in data {
|
||||||
for i := 0; i < len; i++ {
|
result = result>>8 ~ _crc32_table[(result ~ cast(u32)b) & 0xff];
|
||||||
b := s[i] as u32
|
|
||||||
result = result>>8 ~ __CRC32_TABLE[(result ~ b) & 0xff]
|
|
||||||
}
|
}
|
||||||
return ~result
|
return ~result;
|
||||||
}
|
}
|
||||||
crc64 :: proc(data: rawptr, len: int) -> u64 {
|
crc64 :: proc(data: []byte) -> u64 {
|
||||||
result := ~(0 as u64)
|
result := ~cast(u64)0;
|
||||||
s := slice_ptr(data as ^u8, len)
|
for b in data {
|
||||||
for i := 0; i < len; i++ {
|
result = result>>8 ~ _crc64_table[(result ~ cast(u64)b) & 0xff];
|
||||||
b := s[i] as u64
|
|
||||||
result = result>>8 ~ __CRC64_TABLE[(result ~ b) & 0xff]
|
|
||||||
}
|
}
|
||||||
return ~result
|
return ~result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fnv32 :: proc(data: rawptr, len: int) -> u32 {
|
fnv32 :: proc(data: []byte) -> u32 {
|
||||||
s := slice_ptr(data as ^u8, len)
|
h: u32 = 0x811c9dc5;
|
||||||
|
for b in data {
|
||||||
h: u32 = 0x811c9dc5
|
h = (h * 0x01000193) ~ cast(u32)b;
|
||||||
for i := 0; i < len; i++ {
|
|
||||||
h = (h * 0x01000193) ~ s[i] as u32
|
|
||||||
}
|
}
|
||||||
return h
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
fnv64 :: proc(data: rawptr, len: int) -> u64 {
|
fnv64 :: proc(data: []byte) -> u64 {
|
||||||
s := slice_ptr(data as ^u8, len)
|
h: u64 = 0xcbf29ce484222325;
|
||||||
|
for b in data {
|
||||||
h: u64 = 0xcbf29ce484222325
|
h = (h * 0x100000001b3) ~ cast(u64)b;
|
||||||
for i := 0; i < len; i++ {
|
|
||||||
h = (h * 0x100000001b3) ~ s[i] as u64
|
|
||||||
}
|
}
|
||||||
return h
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
fnv32a :: proc(data: rawptr, len: int) -> u32 {
|
fnv32a :: proc(data: []byte) -> u32 {
|
||||||
s := slice_ptr(data as ^u8, len)
|
h: u32 = 0x811c9dc5;
|
||||||
|
for b in data {
|
||||||
h: u32 = 0x811c9dc5
|
h = (h ~ cast(u32)b) * 0x01000193;
|
||||||
for i := 0; i < len; i++ {
|
|
||||||
h = (h ~ s[i] as u32) * 0x01000193
|
|
||||||
}
|
}
|
||||||
return h
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
fnv64a :: proc(data: rawptr, len: int) -> u64 {
|
fnv64a :: proc(data: []byte) -> u64 {
|
||||||
s := slice_ptr(data as ^u8, len)
|
h: u64 = 0xcbf29ce484222325;
|
||||||
|
for b in data {
|
||||||
h: u64 = 0xcbf29ce484222325
|
h = (h ~ cast(u64)b) * 0x100000001b3;
|
||||||
for i := 0; i < len; i++ {
|
|
||||||
h = (h ~ s[i] as u64) * 0x100000001b3
|
|
||||||
}
|
}
|
||||||
return h
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
murmur32 :: proc(data: []byte) -> u32 {
|
||||||
|
c1_32: u32 : 0xcc9e2d51;
|
||||||
|
c2_32: u32 : 0x1b873593;
|
||||||
|
|
||||||
murmur64 :: proc(data_: rawptr, len: int) -> u64 {
|
h1: u32 = 0;
|
||||||
SEED :: 0x9747b28c
|
nblocks := data.count/4;
|
||||||
|
p := data.data;
|
||||||
|
p1 := p + 4*nblocks;
|
||||||
|
|
||||||
if size_of(int) == 8 {
|
for ; p < p1; p += 4 {
|
||||||
m :: 0xc6a4a7935bd1e995
|
k1 := (cast(^u32)p)^;
|
||||||
r :: 47
|
|
||||||
|
|
||||||
h: u64 = SEED ~ (len as u64 * m)
|
k1 *= c1_32;
|
||||||
|
k1 = (k1 << 15) | (k1 >> 17);
|
||||||
|
k1 *= c2_32;
|
||||||
|
|
||||||
data := slice_ptr(data_ as ^u64, len/size_of(u64))
|
h1 ~= k1;
|
||||||
data2 := slice_ptr(data_ as ^u8, len)
|
h1 = (h1 << 13) | (h1 >> 19);
|
||||||
|
h1 = h1*5 + 0xe6546b64;
|
||||||
|
}
|
||||||
|
|
||||||
for i := 0; i < data.count; i++ {
|
tail := data[nblocks*4 ..];
|
||||||
k := data[i]
|
|
||||||
|
|
||||||
k *= m
|
k1: u32;
|
||||||
k ~= k>>r
|
match tail.count&3 {
|
||||||
k *= m
|
case 3:
|
||||||
|
k1 ~= cast(u32)tail[2] << 16;
|
||||||
|
fallthrough;
|
||||||
|
case 2:
|
||||||
|
k1 ~= cast(u32)tail[2] << 8;
|
||||||
|
fallthrough;
|
||||||
|
case 1:
|
||||||
|
k1 ~= cast(u32)tail[0];
|
||||||
|
k1 *= c1_32;
|
||||||
|
k1 = (k1 << 15) | (k1 >> 17) ;
|
||||||
|
k1 *= c2_32;
|
||||||
|
h1 ~= k1;
|
||||||
|
}
|
||||||
|
|
||||||
h ~= k
|
h1 ~= cast(u32)data.count;
|
||||||
h *= m
|
|
||||||
|
h1 ~= h1 >> 16;
|
||||||
|
h1 *= 0x85ebca6b;
|
||||||
|
h1 ~= h1 >> 13;
|
||||||
|
h1 *= 0xc2b2ae35;
|
||||||
|
h1 ~= h1 >> 16;
|
||||||
|
|
||||||
|
return h1;
|
||||||
|
}
|
||||||
|
|
||||||
|
murmur64 :: proc(data: []byte) -> u64 {
|
||||||
|
SEED :: 0x9747b28c;
|
||||||
|
|
||||||
|
when false && size_of(int) == 8 {
|
||||||
|
m :: 0xc6a4a7935bd1e995;
|
||||||
|
r :: 47;
|
||||||
|
|
||||||
|
h: u64 = SEED ~ (cast(u64)data.count * m);
|
||||||
|
data64 := slice_ptr(cast(^u64)^data[0], data.count/size_of(u64));
|
||||||
|
|
||||||
|
for _, i in data64 {
|
||||||
|
k := data64[i];
|
||||||
|
|
||||||
|
k *= m;
|
||||||
|
k ~= k>>r;
|
||||||
|
k *= m;
|
||||||
|
|
||||||
|
h ~= k;
|
||||||
|
h *= m;
|
||||||
}
|
}
|
||||||
|
|
||||||
match len & 7 {
|
match data.count&7 {
|
||||||
case 7: h ~= data2[6] as u64 << 48; fallthrough
|
case 7: h ~= cast(u64)data[6] << 48; fallthrough;
|
||||||
case 6: h ~= data2[5] as u64 << 40; fallthrough
|
case 6: h ~= cast(u64)data[5] << 40; fallthrough;
|
||||||
case 5: h ~= data2[4] as u64 << 32; fallthrough
|
case 5: h ~= cast(u64)data[4] << 32; fallthrough;
|
||||||
case 4: h ~= data2[3] as u64 << 24; fallthrough
|
case 4: h ~= cast(u64)data[3] << 24; fallthrough;
|
||||||
case 3: h ~= data2[2] as u64 << 16; fallthrough
|
case 3: h ~= cast(u64)data[2] << 16; fallthrough;
|
||||||
case 2: h ~= data2[1] as u64 << 8; fallthrough
|
case 2: h ~= cast(u64)data[1] << 8; fallthrough;
|
||||||
case 1:
|
case 1:
|
||||||
h ~= data2[0] as u64
|
h ~= cast(u64)data[0];
|
||||||
h *= m
|
h *= m;
|
||||||
}
|
}
|
||||||
|
|
||||||
h ~= h>>r
|
h ~= h>>r;
|
||||||
h *= m
|
h *= m;
|
||||||
h ~= h>>r
|
h ~= h>>r;
|
||||||
|
|
||||||
return h
|
return h;
|
||||||
} else {
|
} else {
|
||||||
m :: 0x5bd1e995
|
m :: 0x5bd1e995;
|
||||||
r :: 24
|
r :: 24;
|
||||||
|
|
||||||
h1: u32 = SEED as u32 ~ len as u32
|
h1: u32 = cast(u32)SEED ~ cast(u32)data.count;
|
||||||
h2: u32 = SEED >> 32
|
h2: u32 = SEED >> 32;
|
||||||
|
|
||||||
data := slice_ptr(data_ as ^u32, len/size_of(u32))
|
data32 := slice_ptr(cast(^u32)^data[0], data.count/size_of(u32));
|
||||||
|
len := data.count;
|
||||||
|
|
||||||
i := 0
|
i := 0;
|
||||||
for len >= 8 {
|
for len >= 8 {
|
||||||
k1, k2: u32
|
k1, k2: u32;
|
||||||
k1 = data[i]; i++
|
k1 = data32[i]; i++;
|
||||||
k1 *= m
|
k1 *= m;
|
||||||
k1 ~= k1>>r
|
k1 ~= k1>>r;
|
||||||
k1 *= m
|
k1 *= m;
|
||||||
h1 *= m
|
h1 *= m;
|
||||||
h1 ~= k1
|
h1 ~= k1;
|
||||||
len -= 4
|
len -= 4;
|
||||||
|
|
||||||
k2 = data[i]; i++
|
k2 = data32[i]; i++;
|
||||||
k2 *= m
|
k2 *= m;
|
||||||
k2 ~= k2>>r
|
k2 ~= k2>>r;
|
||||||
k2 *= m
|
k2 *= m;
|
||||||
h2 *= m
|
h2 *= m;
|
||||||
h2 ~= k2
|
h2 ~= k2;
|
||||||
len -= 4
|
len -= 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len >= 4) {
|
if len >= 4 {
|
||||||
k1: u32
|
k1: u32;
|
||||||
k1 = data[i]; i++
|
k1 = data32[i]; i++;
|
||||||
k1 *= m
|
k1 *= m;
|
||||||
k1 ~= k1>>r
|
k1 ~= k1>>r;
|
||||||
k1 *= m
|
k1 *= m;
|
||||||
h1 *= m
|
h1 *= m;
|
||||||
h1 ~= k1
|
h1 ~= k1;
|
||||||
len -= 4
|
len -= 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
data8 := slice_ptr((data.data+i) as ^u8, 3) // NOTE(bill): This is unsafe
|
data8 := slice_to_bytes(data32[i..])[..3];
|
||||||
|
|
||||||
match len {
|
match len {
|
||||||
case 3: h2 ~= data8[2] as u32 << 16; fallthrough
|
case 3:
|
||||||
case 2: h2 ~= data8[1] as u32 << 8; fallthrough
|
h2 ~= cast(u32)data8[2] << 16;
|
||||||
|
fallthrough;
|
||||||
|
case 2:
|
||||||
|
h2 ~= cast(u32)data8[1] << 8;
|
||||||
|
fallthrough;
|
||||||
case 1:
|
case 1:
|
||||||
h2 ~= data8[0] as u32
|
h2 ~= cast(u32)data8[0];
|
||||||
h2 *= m
|
h2 *= m;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 ~= h2>>18
|
h1 ~= h2>>18;
|
||||||
h1 *= m
|
h1 *= m;
|
||||||
h2 ~= h1>>22
|
h2 ~= h1>>22;
|
||||||
h2 *= m
|
h2 *= m;
|
||||||
h1 ~= h2>>17
|
h1 ~= h2>>17;
|
||||||
h1 *= m
|
h1 *= m;
|
||||||
h2 ~= h1>>19
|
h2 ~= h1>>19;
|
||||||
h2 *= m
|
h2 *= m;
|
||||||
|
|
||||||
h := (h1 as u64)<<32 | h2 as u64
|
h := cast(u64)(h1)<<32 | cast(u64)(h2);
|
||||||
return h
|
return h;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
immutable _crc32_table := [256]u32{
|
||||||
__CRC32_TABLE := [256]u32{
|
|
||||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
|
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
|
||||||
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
||||||
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||||
@@ -229,8 +267,8 @@ __CRC32_TABLE := [256]u32{
|
|||||||
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
|
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
|
||||||
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
|
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
|
||||||
}
|
};
|
||||||
__CRC64_TABLE := [256]u64{
|
immutable _crc64_table := [256]u64{
|
||||||
0x0000000000000000, 0x42f0e1eba9ea3693, 0x85e1c3d753d46d26, 0xc711223cfa3e5bb5,
|
0x0000000000000000, 0x42f0e1eba9ea3693, 0x85e1c3d753d46d26, 0xc711223cfa3e5bb5,
|
||||||
0x493366450e42ecdf, 0x0bc387aea7a8da4c, 0xccd2a5925d9681f9, 0x8e224479f47cb76a,
|
0x493366450e42ecdf, 0x0bc387aea7a8da4c, 0xccd2a5925d9681f9, 0x8e224479f47cb76a,
|
||||||
0x9266cc8a1c85d9be, 0xd0962d61b56fef2d, 0x17870f5d4f51b498, 0x5577eeb6e6bb820b,
|
0x9266cc8a1c85d9be, 0xd0962d61b56fef2d, 0x17870f5d4f51b498, 0x5577eeb6e6bb820b,
|
||||||
@@ -295,4 +333,4 @@ __CRC64_TABLE := [256]u64{
|
|||||||
0xcf8b0890283e370c, 0x8d7be97b81d4019f, 0x4a6acb477bea5a2a, 0x089a2aacd2006cb9,
|
0xcf8b0890283e370c, 0x8d7be97b81d4019f, 0x4a6acb477bea5a2a, 0x089a2aacd2006cb9,
|
||||||
0x14dea25f3af9026d, 0x562e43b4931334fe, 0x913f6188692d6f4b, 0xd3cf8063c0c759d8,
|
0x14dea25f3af9026d, 0x562e43b4931334fe, 0x913f6188692d6f4b, 0xd3cf8063c0c759d8,
|
||||||
0x5dedc41a34bbeeb2, 0x1f1d25f19d51d821, 0xd80c07cd676f8394, 0x9afce626ce85b507,
|
0x5dedc41a34bbeeb2, 0x1f1d25f19d51d821, 0xd80c07cd676f8394, 0x9afce626ce85b507,
|
||||||
}
|
};
|
||||||
|
|||||||
+251
-252
@@ -1,141 +1,142 @@
|
|||||||
TAU :: 6.28318530717958647692528676655900576
|
TAU :: 6.28318530717958647692528676655900576;
|
||||||
PI :: 3.14159265358979323846264338327950288
|
PI :: 3.14159265358979323846264338327950288;
|
||||||
ONE_OVER_TAU :: 0.636619772367581343075535053490057448
|
ONE_OVER_TAU :: 0.636619772367581343075535053490057448;
|
||||||
ONE_OVER_PI :: 0.159154943091895335768883763372514362
|
ONE_OVER_PI :: 0.159154943091895335768883763372514362;
|
||||||
|
|
||||||
E :: 2.71828182845904523536
|
E :: 2.71828182845904523536;
|
||||||
SQRT_TWO :: 1.41421356237309504880168872420969808
|
SQRT_TWO :: 1.41421356237309504880168872420969808;
|
||||||
SQRT_THREE :: 1.73205080756887729352744634150587236
|
SQRT_THREE :: 1.73205080756887729352744634150587236;
|
||||||
SQRT_FIVE :: 2.23606797749978969640917366873127623
|
SQRT_FIVE :: 2.23606797749978969640917366873127623;
|
||||||
|
|
||||||
LOG_TWO :: 0.693147180559945309417232121458176568
|
LOG_TWO :: 0.693147180559945309417232121458176568;
|
||||||
LOG_TEN :: 2.30258509299404568401799145468436421
|
LOG_TEN :: 2.30258509299404568401799145468436421;
|
||||||
|
|
||||||
EPSILON :: 1.19209290e-7
|
EPSILON :: 1.19209290e-7;
|
||||||
|
|
||||||
τ :: TAU
|
τ :: TAU;
|
||||||
π :: PI
|
π :: PI;
|
||||||
|
|
||||||
|
Vec2 :: [vector 2]f32;
|
||||||
|
Vec3 :: [vector 3]f32;
|
||||||
|
Vec4 :: [vector 4]f32;
|
||||||
|
|
||||||
|
Mat2 :: [2]Vec2;
|
||||||
|
Mat3 :: [3]Vec3;
|
||||||
|
Mat4 :: [4]Vec4;
|
||||||
|
|
||||||
|
sqrt :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.sqrt.f32";
|
||||||
|
sqrt :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.sqrt.f64";
|
||||||
|
|
||||||
|
sin :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.sin.f32";
|
||||||
|
sin :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.sin.f64";
|
||||||
|
|
||||||
|
cos :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.cos.f32";
|
||||||
|
cos :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.cos.f64";
|
||||||
|
|
||||||
|
tan :: proc(x: f32) -> f32 #inline { return sin(x)/cos(x); }
|
||||||
|
tan :: proc(x: f64) -> f64 #inline { return sin(x)/cos(x); }
|
||||||
|
|
||||||
|
lerp :: proc(a, b, t: f32) -> f32 { return a*(1-t) + b*t; }
|
||||||
|
lerp :: proc(a, b, t: f64) -> f64 { return a*(1-t) + b*t; }
|
||||||
|
|
||||||
|
sign :: proc(x: f32) -> f32 { if x >= 0 { return +1; } return -1; }
|
||||||
|
sign :: proc(x: f64) -> f64 { if x >= 0 { return +1; } return -1; }
|
||||||
|
|
||||||
|
bit_reverse :: proc(b: u16) -> u16 #foreign __llvm_core "llvm.bitreverse.i16";
|
||||||
|
bit_reverse :: proc(b: u32) -> u32 #foreign __llvm_core "llvm.bitreverse.i32";
|
||||||
|
bit_reverse :: proc(b: u64) -> u64 #foreign __llvm_core "llvm.bitreverse.i64";
|
||||||
|
|
||||||
|
fmuladd :: proc(a, b, c: f32) -> f32 #foreign __llvm_core "llvm.fmuladd.f32";
|
||||||
|
fmuladd :: proc(a, b, c: f64) -> f64 #foreign __llvm_core "llvm.fmuladd.f64";
|
||||||
|
|
||||||
|
|
||||||
Vec2 :: type {2}f32
|
copy_sign :: proc(x, y: f32) -> f32 {
|
||||||
Vec3 :: type {3}f32
|
ix := transmute(u32)x;
|
||||||
Vec4 :: type {4}f32
|
iy := transmute(u32)y;
|
||||||
|
ix &= 0x7fffffff;
|
||||||
Mat2 :: type [2]Vec2
|
ix |= iy & 0x80000000;
|
||||||
Mat3 :: type [3]Vec3
|
return transmute(f32)ix;
|
||||||
Mat4 :: type [4]Vec4
|
|
||||||
|
|
||||||
|
|
||||||
sqrt32 :: proc(x: f32) -> f32 #foreign "llvm.sqrt.f32"
|
|
||||||
sqrt64 :: proc(x: f64) -> f64 #foreign "llvm.sqrt.f64"
|
|
||||||
|
|
||||||
sin32 :: proc(x: f32) -> f32 #foreign "llvm.sin.f32"
|
|
||||||
sin64 :: proc(x: f64) -> f64 #foreign "llvm.sin.f64"
|
|
||||||
|
|
||||||
cos32 :: proc(x: f32) -> f32 #foreign "llvm.cos.f32"
|
|
||||||
cos64 :: proc(x: f64) -> f64 #foreign "llvm.cos.f64"
|
|
||||||
|
|
||||||
tan32 :: proc(x: f32) -> f32 #inline { return sin32(x)/cos32(x) }
|
|
||||||
tan64 :: proc(x: f64) -> f64 #inline { return sin64(x)/cos64(x) }
|
|
||||||
|
|
||||||
lerp32 :: proc(a, b, t: f32) -> f32 { return a*(1-t) + b*t }
|
|
||||||
lerp64 :: proc(a, b, t: f64) -> f64 { return a*(1-t) + b*t }
|
|
||||||
|
|
||||||
clamp32 :: proc(x, lower, upper: f32) -> f32 { return min(max(x, lower), upper) }
|
|
||||||
clamp64 :: proc(x, lower, upper: f64) -> f64 { return min(max(x, lower), upper) }
|
|
||||||
|
|
||||||
sign32 :: proc(x: f32) -> f32 { if x >= 0 { return +1 } return -1 }
|
|
||||||
sign64 :: proc(x: f64) -> f64 { if x >= 0 { return +1 } return -1 }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
copy_sign32 :: proc(x, y: f32) -> f32 {
|
|
||||||
ix := x transmute u32
|
|
||||||
iy := y transmute u32
|
|
||||||
ix &= 0x7fffffff
|
|
||||||
ix |= iy & 0x80000000
|
|
||||||
return ix transmute f32
|
|
||||||
}
|
}
|
||||||
round32 :: proc(x: f32) -> f32 {
|
round :: proc(x: f32) -> f32 {
|
||||||
if x >= 0 {
|
if x >= 0 {
|
||||||
return floor32(x + 0.5)
|
return floor(x + 0.5);
|
||||||
}
|
}
|
||||||
return ceil32(x - 0.5)
|
return ceil(x - 0.5);
|
||||||
}
|
}
|
||||||
floor32 :: proc(x: f32) -> f32 {
|
floor :: proc(x: f32) -> f32 {
|
||||||
if x >= 0 {
|
if x >= 0 {
|
||||||
return x as int as f32
|
return cast(f32)cast(int)x;
|
||||||
}
|
}
|
||||||
return (x-0.5) as int as f32
|
return cast(f32)cast(int)(x-0.5);
|
||||||
}
|
}
|
||||||
ceil32 :: proc(x: f32) -> f32 {
|
ceil :: proc(x: f32) -> f32 {
|
||||||
if x < 0 {
|
if x < 0 {
|
||||||
return x as int as f32
|
return cast(f32)cast(int)x;
|
||||||
}
|
}
|
||||||
return ((x as int)+1) as f32
|
return cast(f32)cast(int)(x+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
remainder32 :: proc(x, y: f32) -> f32 {
|
remainder32 :: proc(x, y: f32) -> f32 {
|
||||||
return x - round32(x/y) * y
|
return x - round(x/y) * y;
|
||||||
}
|
}
|
||||||
|
|
||||||
fmod32 :: proc(x, y: f32) -> f32 {
|
fmod32 :: proc(x, y: f32) -> f32 {
|
||||||
y = abs(y)
|
y = abs(y);
|
||||||
result := remainder32(abs(x), y)
|
result := remainder32(abs(x), y);
|
||||||
if sign32(result) < 0 {
|
if sign(result) < 0 {
|
||||||
result += y
|
result += y;
|
||||||
}
|
}
|
||||||
return copy_sign32(result, x)
|
return copy_sign(result, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
to_radians :: proc(degrees: f32) -> f32 { return degrees * TAU / 360 }
|
to_radians :: proc(degrees: f32) -> f32 { return degrees * TAU / 360; }
|
||||||
to_degrees :: proc(radians: f32) -> f32 { return radians * 360 / TAU }
|
to_degrees :: proc(radians: f32) -> f32 { return radians * 360 / TAU; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
dot2 :: proc(a, b: Vec2) -> f32 { c := a*b; return c.x + c.y }
|
dot :: proc(a, b: Vec2) -> f32 { c := a*b; return c.x + c.y; }
|
||||||
dot3 :: proc(a, b: Vec3) -> f32 { c := a*b; return c.x + c.y + c.z }
|
dot :: proc(a, b: Vec3) -> f32 { c := a*b; return c.x + c.y + c.z; }
|
||||||
dot4 :: proc(a, b: Vec4) -> f32 { c := a*b; return c.x + c.y + c.z + c.w }
|
dot :: proc(a, b: Vec4) -> f32 { c := a*b; return c.x + c.y + c.z + c.w; }
|
||||||
|
|
||||||
cross3 :: proc(x, y: Vec3) -> Vec3 {
|
cross :: proc(x, y: Vec3) -> Vec3 {
|
||||||
a := swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1)
|
a := swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1);
|
||||||
b := swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0)
|
b := swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0);
|
||||||
return a - b
|
return a - b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
vec2_mag :: proc(v: Vec2) -> f32 { return sqrt32(dot2(v, v)) }
|
mag :: proc(v: Vec2) -> f32 { return sqrt(dot(v, v)); }
|
||||||
vec3_mag :: proc(v: Vec3) -> f32 { return sqrt32(dot3(v, v)) }
|
mag :: proc(v: Vec3) -> f32 { return sqrt(dot(v, v)); }
|
||||||
vec4_mag :: proc(v: Vec4) -> f32 { return sqrt32(dot4(v, v)) }
|
mag :: proc(v: Vec4) -> f32 { return sqrt(dot(v, v)); }
|
||||||
|
|
||||||
vec2_norm :: proc(v: Vec2) -> Vec2 { return v / Vec2{vec2_mag(v)} }
|
norm :: proc(v: Vec2) -> Vec2 { return v / Vec2{mag(v)}; }
|
||||||
vec3_norm :: proc(v: Vec3) -> Vec3 { return v / Vec3{vec3_mag(v)} }
|
norm :: proc(v: Vec3) -> Vec3 { return v / Vec3{mag(v)}; }
|
||||||
vec4_norm :: proc(v: Vec4) -> Vec4 { return v / Vec4{vec4_mag(v)} }
|
norm :: proc(v: Vec4) -> Vec4 { return v / Vec4{mag(v)}; }
|
||||||
|
|
||||||
vec2_norm0 :: proc(v: Vec2) -> Vec2 {
|
norm0 :: proc(v: Vec2) -> Vec2 {
|
||||||
m := vec2_mag(v)
|
m := mag(v);
|
||||||
if m == 0 {
|
if m == 0 {
|
||||||
return Vec2{0}
|
return Vec2{0};
|
||||||
}
|
}
|
||||||
return v / Vec2{m}
|
return v / Vec2{m};
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3_norm0 :: proc(v: Vec3) -> Vec3 {
|
norm0 :: proc(v: Vec3) -> Vec3 {
|
||||||
m := vec3_mag(v)
|
m := mag(v);
|
||||||
if m == 0 {
|
if m == 0 {
|
||||||
return Vec3{0}
|
return Vec3{0};
|
||||||
}
|
}
|
||||||
return v / Vec3{m}
|
return v / Vec3{m};
|
||||||
}
|
}
|
||||||
|
|
||||||
vec4_norm0 :: proc(v: Vec4) -> Vec4 {
|
norm0 :: proc(v: Vec4) -> Vec4 {
|
||||||
m := vec4_mag(v)
|
m := mag(v);
|
||||||
if m == 0 {
|
if m == 0 {
|
||||||
return Vec4{0}
|
return Vec4{0};
|
||||||
}
|
}
|
||||||
return v / Vec4{m}
|
return v / Vec4{m};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -146,228 +147,226 @@ mat4_identity :: proc() -> Mat4 {
|
|||||||
{0, 1, 0, 0},
|
{0, 1, 0, 0},
|
||||||
{0, 0, 1, 0},
|
{0, 0, 1, 0},
|
||||||
{0, 0, 0, 1},
|
{0, 0, 0, 1},
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
mat4_transpose :: proc(m: Mat4) -> Mat4 {
|
mat4_transpose :: proc(m: Mat4) -> Mat4 {
|
||||||
for j := 0; j < 4; j++ {
|
for j in 0..4 {
|
||||||
for i := 0; i < 4; i++ {
|
for i in 0..4 {
|
||||||
m[i][j], m[j][i] = m[j][i], m[i][j]
|
m[i][j], m[j][i] = m[j][i], m[i][j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return m
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
mat4_mul :: proc(a, b: Mat4) -> Mat4 {
|
mul :: proc(a, b: Mat4) -> Mat4 {
|
||||||
c: Mat4
|
c: Mat4;
|
||||||
for j := 0; j < 4; j++ {
|
for j in 0..4 {
|
||||||
for i := 0; i < 4; i++ {
|
for i in 0..4 {
|
||||||
c[j][i] = a[0][i]*b[j][0]
|
c[j][i] = a[0][i]*b[j][0] +
|
||||||
+ a[1][i]*b[j][1]
|
a[1][i]*b[j][1] +
|
||||||
+ a[2][i]*b[j][2]
|
a[2][i]*b[j][2] +
|
||||||
+ a[3][i]*b[j][3]
|
a[3][i]*b[j][3];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return c
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
mat4_mul_vec4 :: proc(m: Mat4, v: Vec4) -> Vec4 {
|
mul :: proc(m: Mat4, v: Vec4) -> Vec4 {
|
||||||
return Vec4{
|
return Vec4{
|
||||||
m[0][0]*v.x + m[1][0]*v.y + m[2][0]*v.z + m[3][0]*v.w,
|
m[0][0]*v.x + m[1][0]*v.y + m[2][0]*v.z + m[3][0]*v.w,
|
||||||
m[0][1]*v.x + m[1][1]*v.y + m[2][1]*v.z + m[3][1]*v.w,
|
m[0][1]*v.x + m[1][1]*v.y + m[2][1]*v.z + m[3][1]*v.w,
|
||||||
m[0][2]*v.x + m[1][2]*v.y + m[2][2]*v.z + m[3][2]*v.w,
|
m[0][2]*v.x + m[1][2]*v.y + m[2][2]*v.z + m[3][2]*v.w,
|
||||||
m[0][3]*v.x + m[1][3]*v.y + m[2][3]*v.z + m[3][3]*v.w,
|
m[0][3]*v.x + m[1][3]*v.y + m[2][3]*v.z + m[3][3]*v.w,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
mat4_inverse :: proc(m: Mat4) -> Mat4 {
|
inverse :: proc(m: Mat4) -> Mat4 {
|
||||||
o: Mat4
|
o: Mat4;
|
||||||
|
|
||||||
sf00 := m[2][2] * m[3][3] - m[3][2] * m[2][3]
|
sf00 := m[2][2] * m[3][3] - m[3][2] * m[2][3];
|
||||||
sf01 := m[2][1] * m[3][3] - m[3][1] * m[2][3]
|
sf01 := m[2][1] * m[3][3] - m[3][1] * m[2][3];
|
||||||
sf02 := m[2][1] * m[3][2] - m[3][1] * m[2][2]
|
sf02 := m[2][1] * m[3][2] - m[3][1] * m[2][2];
|
||||||
sf03 := m[2][0] * m[3][3] - m[3][0] * m[2][3]
|
sf03 := m[2][0] * m[3][3] - m[3][0] * m[2][3];
|
||||||
sf04 := m[2][0] * m[3][2] - m[3][0] * m[2][2]
|
sf04 := m[2][0] * m[3][2] - m[3][0] * m[2][2];
|
||||||
sf05 := m[2][0] * m[3][1] - m[3][0] * m[2][1]
|
sf05 := m[2][0] * m[3][1] - m[3][0] * m[2][1];
|
||||||
sf06 := m[1][2] * m[3][3] - m[3][2] * m[1][3]
|
sf06 := m[1][2] * m[3][3] - m[3][2] * m[1][3];
|
||||||
sf07 := m[1][1] * m[3][3] - m[3][1] * m[1][3]
|
sf07 := m[1][1] * m[3][3] - m[3][1] * m[1][3];
|
||||||
sf08 := m[1][1] * m[3][2] - m[3][1] * m[1][2]
|
sf08 := m[1][1] * m[3][2] - m[3][1] * m[1][2];
|
||||||
sf09 := m[1][0] * m[3][3] - m[3][0] * m[1][3]
|
sf09 := m[1][0] * m[3][3] - m[3][0] * m[1][3];
|
||||||
sf10 := m[1][0] * m[3][2] - m[3][0] * m[1][2]
|
sf10 := m[1][0] * m[3][2] - m[3][0] * m[1][2];
|
||||||
sf11 := m[1][1] * m[3][3] - m[3][1] * m[1][3]
|
sf11 := m[1][1] * m[3][3] - m[3][1] * m[1][3];
|
||||||
sf12 := m[1][0] * m[3][1] - m[3][0] * m[1][1]
|
sf12 := m[1][0] * m[3][1] - m[3][0] * m[1][1];
|
||||||
sf13 := m[1][2] * m[2][3] - m[2][2] * m[1][3]
|
sf13 := m[1][2] * m[2][3] - m[2][2] * m[1][3];
|
||||||
sf14 := m[1][1] * m[2][3] - m[2][1] * m[1][3]
|
sf14 := m[1][1] * m[2][3] - m[2][1] * m[1][3];
|
||||||
sf15 := m[1][1] * m[2][2] - m[2][1] * m[1][2]
|
sf15 := m[1][1] * m[2][2] - m[2][1] * m[1][2];
|
||||||
sf16 := m[1][0] * m[2][3] - m[2][0] * m[1][3]
|
sf16 := m[1][0] * m[2][3] - m[2][0] * m[1][3];
|
||||||
sf17 := m[1][0] * m[2][2] - m[2][0] * m[1][2]
|
sf17 := m[1][0] * m[2][2] - m[2][0] * m[1][2];
|
||||||
sf18 := m[1][0] * m[2][1] - m[2][0] * m[1][1]
|
sf18 := m[1][0] * m[2][1] - m[2][0] * m[1][1];
|
||||||
|
|
||||||
o[0][0] = +(m[1][1] * sf00 - m[1][2] * sf01 + m[1][3] * sf02)
|
o[0][0] = +(m[1][1] * sf00 - m[1][2] * sf01 + m[1][3] * sf02);
|
||||||
o[0][1] = -(m[1][0] * sf00 - m[1][2] * sf03 + m[1][3] * sf04)
|
o[0][1] = -(m[1][0] * sf00 - m[1][2] * sf03 + m[1][3] * sf04);
|
||||||
o[0][2] = +(m[1][0] * sf01 - m[1][1] * sf03 + m[1][3] * sf05)
|
o[0][2] = +(m[1][0] * sf01 - m[1][1] * sf03 + m[1][3] * sf05);
|
||||||
o[0][3] = -(m[1][0] * sf02 - m[1][1] * sf04 + m[1][2] * sf05)
|
o[0][3] = -(m[1][0] * sf02 - m[1][1] * sf04 + m[1][2] * sf05);
|
||||||
|
|
||||||
o[1][0] = -(m[0][1] * sf00 - m[0][2] * sf01 + m[0][3] * sf02)
|
o[1][0] = -(m[0][1] * sf00 - m[0][2] * sf01 + m[0][3] * sf02);
|
||||||
o[1][1] = +(m[0][0] * sf00 - m[0][2] * sf03 + m[0][3] * sf04)
|
o[1][1] = +(m[0][0] * sf00 - m[0][2] * sf03 + m[0][3] * sf04);
|
||||||
o[1][2] = -(m[0][0] * sf01 - m[0][1] * sf03 + m[0][3] * sf05)
|
o[1][2] = -(m[0][0] * sf01 - m[0][1] * sf03 + m[0][3] * sf05);
|
||||||
o[1][3] = +(m[0][0] * sf02 - m[0][1] * sf04 + m[0][2] * sf05)
|
o[1][3] = +(m[0][0] * sf02 - m[0][1] * sf04 + m[0][2] * sf05);
|
||||||
|
|
||||||
o[2][0] = +(m[0][1] * sf06 - m[0][2] * sf07 + m[0][3] * sf08)
|
o[2][0] = +(m[0][1] * sf06 - m[0][2] * sf07 + m[0][3] * sf08);
|
||||||
o[2][1] = -(m[0][0] * sf06 - m[0][2] * sf09 + m[0][3] * sf10)
|
o[2][1] = -(m[0][0] * sf06 - m[0][2] * sf09 + m[0][3] * sf10);
|
||||||
o[2][2] = +(m[0][0] * sf11 - m[0][1] * sf09 + m[0][3] * sf12)
|
o[2][2] = +(m[0][0] * sf11 - m[0][1] * sf09 + m[0][3] * sf12);
|
||||||
o[2][3] = -(m[0][0] * sf08 - m[0][1] * sf10 + m[0][2] * sf12)
|
o[2][3] = -(m[0][0] * sf08 - m[0][1] * sf10 + m[0][2] * sf12);
|
||||||
|
|
||||||
o[3][0] = -(m[0][1] * sf13 - m[0][2] * sf14 + m[0][3] * sf15)
|
o[3][0] = -(m[0][1] * sf13 - m[0][2] * sf14 + m[0][3] * sf15);
|
||||||
o[3][1] = +(m[0][0] * sf13 - m[0][2] * sf16 + m[0][3] * sf17)
|
o[3][1] = +(m[0][0] * sf13 - m[0][2] * sf16 + m[0][3] * sf17);
|
||||||
o[3][2] = -(m[0][0] * sf14 - m[0][1] * sf16 + m[0][3] * sf18)
|
o[3][2] = -(m[0][0] * sf14 - m[0][1] * sf16 + m[0][3] * sf18);
|
||||||
o[3][3] = +(m[0][0] * sf15 - m[0][1] * sf17 + m[0][2] * sf18)
|
o[3][3] = +(m[0][0] * sf15 - m[0][1] * sf17 + m[0][2] * sf18);
|
||||||
|
|
||||||
ood := 1.0 / (m[0][0] * o[0][0] +
|
ood := 1.0 / (m[0][0] * o[0][0] +
|
||||||
m[0][1] * o[0][1] +
|
m[0][1] * o[0][1] +
|
||||||
m[0][2] * o[0][2] +
|
m[0][2] * o[0][2] +
|
||||||
m[0][3] * o[0][3])
|
m[0][3] * o[0][3]);
|
||||||
|
|
||||||
o[0][0] *= ood
|
o[0][0] *= ood;
|
||||||
o[0][1] *= ood
|
o[0][1] *= ood;
|
||||||
o[0][2] *= ood
|
o[0][2] *= ood;
|
||||||
o[0][3] *= ood
|
o[0][3] *= ood;
|
||||||
o[1][0] *= ood
|
o[1][0] *= ood;
|
||||||
o[1][1] *= ood
|
o[1][1] *= ood;
|
||||||
o[1][2] *= ood
|
o[1][2] *= ood;
|
||||||
o[1][3] *= ood
|
o[1][3] *= ood;
|
||||||
o[2][0] *= ood
|
o[2][0] *= ood;
|
||||||
o[2][1] *= ood
|
o[2][1] *= ood;
|
||||||
o[2][2] *= ood
|
o[2][2] *= ood;
|
||||||
o[2][3] *= ood
|
o[2][3] *= ood;
|
||||||
o[3][0] *= ood
|
o[3][0] *= ood;
|
||||||
o[3][1] *= ood
|
o[3][1] *= ood;
|
||||||
o[3][2] *= ood
|
o[3][2] *= ood;
|
||||||
o[3][3] *= ood
|
o[3][3] *= ood;
|
||||||
|
|
||||||
return o
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
mat4_translate :: proc(v: Vec3) -> Mat4 {
|
mat4_translate :: proc(v: Vec3) -> Mat4 {
|
||||||
m := mat4_identity()
|
m := mat4_identity();
|
||||||
m[3][0] = v.x
|
m[3][0] = v.x;
|
||||||
m[3][1] = v.y
|
m[3][1] = v.y;
|
||||||
m[3][2] = v.z
|
m[3][2] = v.z;
|
||||||
m[3][3] = 1
|
m[3][3] = 1;
|
||||||
return m
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
mat4_rotate :: proc(v: Vec3, angle_radians: f32) -> Mat4 {
|
mat4_rotate :: proc(v: Vec3, angle_radians: f32) -> Mat4 {
|
||||||
c := cos32(angle_radians)
|
c := cos(angle_radians);
|
||||||
s := sin32(angle_radians)
|
s := sin(angle_radians);
|
||||||
|
|
||||||
a := vec3_norm(v)
|
a := norm(v);
|
||||||
t := a * Vec3{1-c}
|
t := a * Vec3{1-c};
|
||||||
|
|
||||||
rot := mat4_identity()
|
rot := mat4_identity();
|
||||||
|
|
||||||
rot[0][0] = c + t.x*a.x
|
rot[0][0] = c + t.x*a.x;
|
||||||
rot[0][1] = 0 + t.x*a.y + s*a.z
|
rot[0][1] = 0 + t.x*a.y + s*a.z;
|
||||||
rot[0][2] = 0 + t.x*a.z - s*a.y
|
rot[0][2] = 0 + t.x*a.z - s*a.y;
|
||||||
rot[0][3] = 0
|
rot[0][3] = 0;
|
||||||
|
|
||||||
rot[1][0] = 0 + t.y*a.x - s*a.z
|
rot[1][0] = 0 + t.y*a.x - s*a.z;
|
||||||
rot[1][1] = c + t.y*a.y
|
rot[1][1] = c + t.y*a.y;
|
||||||
rot[1][2] = 0 + t.y*a.z + s*a.x
|
rot[1][2] = 0 + t.y*a.z + s*a.x;
|
||||||
rot[1][3] = 0
|
rot[1][3] = 0;
|
||||||
|
|
||||||
rot[2][0] = 0 + t.z*a.x + s*a.y
|
rot[2][0] = 0 + t.z*a.x + s*a.y;
|
||||||
rot[2][1] = 0 + t.z*a.y - s*a.x
|
rot[2][1] = 0 + t.z*a.y - s*a.x;
|
||||||
rot[2][2] = c + t.z*a.z
|
rot[2][2] = c + t.z*a.z;
|
||||||
rot[2][3] = 0
|
rot[2][3] = 0;
|
||||||
|
|
||||||
return rot
|
return rot;
|
||||||
}
|
}
|
||||||
|
|
||||||
mat4_scale :: proc(m: Mat4, v: Vec3) -> Mat4 {
|
scale :: proc(m: Mat4, v: Vec3) -> Mat4 {
|
||||||
m[0][0] = v.x
|
m[0][0] *= v.x;
|
||||||
m[1][1] = v.y
|
m[1][1] *= v.y;
|
||||||
m[2][2] = v.z
|
m[2][2] *= v.z;
|
||||||
return m
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
mat4_scalef :: proc(m: Mat4, s: f32) -> Mat4 {
|
scale :: proc(m: Mat4, s: f32) -> Mat4 {
|
||||||
m[0][0] = s
|
m[0][0] *= s;
|
||||||
m[1][1] = s
|
m[1][1] *= s;
|
||||||
m[2][2] = s
|
m[2][2] *= s;
|
||||||
return m
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
mat4_look_at :: proc(eye, centre, up: Vec3) -> Mat4 {
|
look_at :: proc(eye, centre, up: Vec3) -> Mat4 {
|
||||||
f := vec3_norm(centre - eye)
|
f := norm(centre - eye);
|
||||||
s := vec3_norm(cross3(f, up))
|
s := norm(cross(f, up));
|
||||||
u := cross3(s, f)
|
u := cross(s, f);
|
||||||
|
|
||||||
m: Mat4
|
m: Mat4;
|
||||||
|
|
||||||
m[0] = Vec4{+s.x, +s.y, +s.z, 0}
|
m[0] = Vec4{+s.x, +s.y, +s.z, 0};
|
||||||
m[1] = Vec4{+u.x, +u.y, +u.z, 0}
|
m[1] = Vec4{+u.x, +u.y, +u.z, 0};
|
||||||
m[2] = Vec4{-f.x, -f.y, -f.z, 0}
|
m[2] = Vec4{-f.x, -f.y, -f.z, 0};
|
||||||
m[3] = Vec4{dot3(s, eye), dot3(u, eye), dot3(f, eye), 1}
|
m[3] = Vec4{dot(s, eye), dot(u, eye), dot(f, eye), 1};
|
||||||
|
|
||||||
return m
|
return m;
|
||||||
}
|
}
|
||||||
mat4_perspective :: proc(fovy, aspect, near, far: f32) -> Mat4 {
|
perspective :: proc(fovy, aspect, near, far: f32) -> Mat4 {
|
||||||
m: Mat4
|
m: Mat4;
|
||||||
tan_half_fovy := tan32(0.5 * fovy)
|
tan_half_fovy := tan(0.5 * fovy);
|
||||||
m[0][0] = 1.0 / (aspect*tan_half_fovy)
|
m[0][0] = 1.0 / (aspect*tan_half_fovy);
|
||||||
m[1][1] = 1.0 / (tan_half_fovy)
|
m[1][1] = 1.0 / (tan_half_fovy);
|
||||||
m[2][2] = -(far + near) / (far - near)
|
m[2][2] = -(far + near) / (far - near);
|
||||||
m[2][3] = -1.0
|
m[2][3] = -1.0;
|
||||||
m[3][2] = -2.0*far*near / (far - near)
|
m[3][2] = -2.0*far*near / (far - near);
|
||||||
return m
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
mat4_ortho3d :: proc(left, right, bottom, top, near, far: f32) -> Mat4 {
|
ortho3d :: proc(left, right, bottom, top, near, far: f32) -> Mat4 {
|
||||||
m := mat4_identity()
|
m := mat4_identity();
|
||||||
|
m[0][0] = +2.0 / (right - left);
|
||||||
m[0][0] = +2.0 / (right - left)
|
m[1][1] = +2.0 / (top - bottom);
|
||||||
m[1][1] = +2.0 / (top - bottom)
|
m[2][2] = -2.0 / (far - near);
|
||||||
m[2][2] = -2.0 / (far - near)
|
m[3][0] = -(right + left) / (right - left);
|
||||||
m[3][0] = -(right + left) / (right - left)
|
m[3][1] = -(top + bottom) / (top - bottom);
|
||||||
m[3][1] = -(top + bottom) / (top - bottom)
|
m[3][2] = -(far + near) / (far - near);
|
||||||
m[3][2] = -(far + near) / (far - near)
|
return m;
|
||||||
|
|
||||||
return m
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
F32_DIG :: 6
|
F32_DIG :: 6;
|
||||||
F32_EPSILON :: 1.192092896e-07
|
F32_EPSILON :: 1.192092896e-07;
|
||||||
F32_GUARD :: 0
|
F32_GUARD :: 0;
|
||||||
F32_MANT_DIG :: 24
|
F32_MANT_DIG :: 24;
|
||||||
F32_MAX :: 3.402823466e+38
|
F32_MAX :: 3.402823466e+38;
|
||||||
F32_MAX_10_EXP :: 38
|
F32_MAX_10_EXP :: 38;
|
||||||
F32_MAX_EXP :: 128
|
F32_MAX_EXP :: 128;
|
||||||
F32_MIN :: 1.175494351e-38
|
F32_MIN :: 1.175494351e-38;
|
||||||
F32_MIN_10_EXP :: -37
|
F32_MIN_10_EXP :: -37;
|
||||||
F32_MIN_EXP :: -125
|
F32_MIN_EXP :: -125;
|
||||||
F32_NORMALIZE :: 0
|
F32_NORMALIZE :: 0;
|
||||||
F32_RADIX :: 2
|
F32_RADIX :: 2;
|
||||||
F32_ROUNDS :: 1
|
F32_ROUNDS :: 1;
|
||||||
|
|
||||||
F64_DIG :: 15 // # of decimal digits of precision
|
F64_DIG :: 15; // # of decimal digits of precision
|
||||||
F64_EPSILON :: 2.2204460492503131e-016 // smallest such that 1.0+F64_EPSILON != 1.0
|
F64_EPSILON :: 2.2204460492503131e-016; // smallest such that 1.0+F64_EPSILON != 1.0
|
||||||
F64_MANT_DIG :: 53 // # of bits in mantissa
|
F64_MANT_DIG :: 53; // # of bits in mantissa
|
||||||
F64_MAX :: 1.7976931348623158e+308 // max value
|
F64_MAX :: 1.7976931348623158e+308; // max value
|
||||||
F64_MAX_10_EXP :: 308 // max decimal exponent
|
F64_MAX_10_EXP :: 308; // max decimal exponent
|
||||||
F64_MAX_EXP :: 1024 // max binary exponent
|
F64_MAX_EXP :: 1024; // max binary exponent
|
||||||
F64_MIN :: 2.2250738585072014e-308 // min positive value
|
F64_MIN :: 2.2250738585072014e-308; // min positive value
|
||||||
F64_MIN_10_EXP :: -307 // min decimal exponent
|
F64_MIN_10_EXP :: -307; // min decimal exponent
|
||||||
F64_MIN_EXP :: -1021 // min binary exponent
|
F64_MIN_EXP :: -1021; // min binary exponent
|
||||||
F64_RADIX :: 2 // exponent radix
|
F64_RADIX :: 2; // exponent radix
|
||||||
F64_ROUNDS :: 1 // addition rounding: near
|
F64_ROUNDS :: 1; // addition rounding: near
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+195
-201
@@ -1,111 +1,97 @@
|
|||||||
#import "fmt.odin"
|
#import "fmt.odin";
|
||||||
#import "os.odin"
|
#import "os.odin";
|
||||||
|
|
||||||
|
swap :: proc(b: u16) -> u16 #foreign __llvm_core "llvm.bswap.i16";
|
||||||
|
swap :: proc(b: u32) -> u32 #foreign __llvm_core "llvm.bswap.i32";
|
||||||
|
swap :: proc(b: u64) -> u64 #foreign __llvm_core "llvm.bswap.i64";
|
||||||
|
|
||||||
|
|
||||||
set :: proc(data: rawptr, value: i32, len: int) -> rawptr #link_name "__mem_set" {
|
set :: proc(data: rawptr, value: i32, len: int) -> rawptr #link_name "__mem_set" {
|
||||||
llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign "llvm.memset.p0i8.i64"
|
llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memset.p0i8.i64";
|
||||||
llvm_memset_64bit(data, value as byte, len, 1, false)
|
llvm_memset_64bit(data, cast(byte)value, len, 1, false);
|
||||||
return data
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
zero :: proc(data: rawptr, len: int) -> rawptr {
|
zero :: proc(data: rawptr, len: int) -> rawptr #link_name "__mem_zero" {
|
||||||
return set(data, 0, len)
|
return set(data, 0, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
copy :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy" {
|
copy :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy" {
|
||||||
// NOTE(bill): This _must_ implemented like C's memmove
|
// NOTE(bill): This _must_ be implemented like C's memmove
|
||||||
llvm_memmove_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign "llvm.memmove.p0i8.p0i8.i64"
|
llvm_memmove_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memmove.p0i8.p0i8.i64";
|
||||||
llvm_memmove_64bit(dst, src, len, 1, false)
|
llvm_memmove_64bit(dst, src, len, 1, false);
|
||||||
return dst
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy_non_overlapping" {
|
copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy_non_overlapping" {
|
||||||
// NOTE(bill): This _must_ implemented like C's memcpy
|
// NOTE(bill): This _must_ be implemented like C's memcpy
|
||||||
llvm_memcpy_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign "llvm.memcpy.p0i8.p0i8.i64"
|
llvm_memcpy_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memcpy.p0i8.p0i8.i64";
|
||||||
llvm_memcpy_64bit(dst, src, len, 1, false)
|
llvm_memcpy_64bit(dst, src, len, 1, false);
|
||||||
return dst
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
compare :: proc(a, b: []byte) -> int #link_name "__mem_compare" {
|
||||||
compare :: proc(dst, src: rawptr, n: int) -> int #link_name "__mem_compare" {
|
n := min(a.count, b.count);
|
||||||
// Translation of http://mgronhol.github.io/fast-strcmp/
|
for i in 0..n {
|
||||||
a := slice_ptr(dst as ^byte, n)
|
match {
|
||||||
b := slice_ptr(src as ^byte, n)
|
case a[i] < b[i]:
|
||||||
|
return -1;
|
||||||
fast := n/size_of(int) + 1
|
case a[i] > b[i]:
|
||||||
offset := (fast-1)*size_of(int)
|
return +1;
|
||||||
curr_block := 0
|
|
||||||
if n <= size_of(int) {
|
|
||||||
fast = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
la := slice_ptr(^a[0] as ^int, fast)
|
|
||||||
lb := slice_ptr(^b[0] as ^int, fast)
|
|
||||||
|
|
||||||
for ; curr_block < fast; curr_block++ {
|
|
||||||
if (la[curr_block] ~ lb[curr_block]) != 0 {
|
|
||||||
for pos := curr_block*size_of(int); pos < n; pos++ {
|
|
||||||
if (a[pos] ~ b[pos]) != 0 {
|
|
||||||
return a[pos] as int - b[pos] as int
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
for ; offset < n; offset++ {
|
|
||||||
if (a[offset] ~ b[offset]) != 0 {
|
|
||||||
return a[offset] as int - b[offset] as int
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
return 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
kilobytes :: proc(x: int) -> int #inline { return (x) * 1024 }
|
kilobytes :: proc(x: int) -> int #inline { return (x) * 1024; }
|
||||||
megabytes :: proc(x: int) -> int #inline { return kilobytes(x) * 1024 }
|
megabytes :: proc(x: int) -> int #inline { return kilobytes(x) * 1024; }
|
||||||
gigabytes :: proc(x: int) -> int #inline { return gigabytes(x) * 1024 }
|
gigabytes :: proc(x: int) -> int #inline { return megabytes(x) * 1024; }
|
||||||
terabytes :: proc(x: int) -> int #inline { return terabytes(x) * 1024 }
|
terabytes :: proc(x: int) -> int #inline { return gigabytes(x) * 1024; }
|
||||||
|
|
||||||
is_power_of_two :: proc(x: int) -> bool {
|
is_power_of_two :: proc(x: int) -> bool {
|
||||||
if x <= 0 {
|
if x <= 0 {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
return (x & (x-1)) == 0
|
return (x & (x-1)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
align_forward :: proc(ptr: rawptr, align: int) -> rawptr {
|
align_forward :: proc(ptr: rawptr, align: int) -> rawptr {
|
||||||
assert(is_power_of_two(align))
|
assert(is_power_of_two(align));
|
||||||
|
|
||||||
a := align as uint
|
a := cast(uint)align;
|
||||||
p := ptr as uint
|
p := cast(uint)ptr;
|
||||||
modulo := p & (a-1)
|
modulo := p & (a-1);
|
||||||
if modulo != 0 {
|
if modulo != 0 {
|
||||||
p += a - modulo
|
p += a - modulo;
|
||||||
}
|
}
|
||||||
return p as rawptr
|
return cast(rawptr)p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AllocationHeader :: struct {
|
Allocation_Header :: struct {
|
||||||
size: int
|
size: int,
|
||||||
}
|
}
|
||||||
allocation_header_fill :: proc(header: ^AllocationHeader, data: rawptr, size: int) {
|
|
||||||
header.size = size
|
|
||||||
ptr := (header+1) as ^int
|
|
||||||
|
|
||||||
for i := 0; ptr as rawptr < data; i++ {
|
allocation_header_fill :: proc(header: ^Allocation_Header, data: rawptr, size: int) {
|
||||||
(ptr+i)^ = -1
|
header.size = size;
|
||||||
|
ptr := cast(^int)(header+1);
|
||||||
|
|
||||||
|
for i := 0; cast(rawptr)ptr < data; i++ {
|
||||||
|
(ptr+i)^ = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
allocation_header :: proc(data: rawptr) -> ^AllocationHeader {
|
allocation_header :: proc(data: rawptr) -> ^Allocation_Header {
|
||||||
p := data as ^int
|
if data == nil {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
p := cast(^int)data;
|
||||||
for (p-1)^ == -1 {
|
for (p-1)^ == -1 {
|
||||||
p = (p-1)
|
p = (p-1);
|
||||||
}
|
}
|
||||||
return (p as ^AllocationHeader)-1
|
return cast(^Allocation_Header)p-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -113,16 +99,16 @@ allocation_header :: proc(data: rawptr) -> ^AllocationHeader {
|
|||||||
|
|
||||||
|
|
||||||
// Custom allocators
|
// Custom allocators
|
||||||
|
|
||||||
Arena :: struct {
|
Arena :: struct {
|
||||||
backing: Allocator
|
backing: Allocator,
|
||||||
memory: []byte
|
offset: int,
|
||||||
temp_count: int
|
memory: []byte,
|
||||||
|
temp_count: int,
|
||||||
|
}
|
||||||
|
|
||||||
Temp_Memory :: struct {
|
Arena_Temp_Memory :: struct {
|
||||||
arena: ^Arena
|
arena: ^Arena,
|
||||||
original_count: int
|
original_count: int,
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -130,22 +116,23 @@ Arena :: struct {
|
|||||||
|
|
||||||
|
|
||||||
init_arena_from_memory :: proc(using a: ^Arena, data: []byte) {
|
init_arena_from_memory :: proc(using a: ^Arena, data: []byte) {
|
||||||
backing = Allocator{}
|
backing = Allocator{};
|
||||||
memory = data[:0]
|
memory = data[..0];
|
||||||
temp_count = 0
|
temp_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
init_arena_from_context :: proc(using a: ^Arena, size: int) {
|
init_arena_from_context :: proc(using a: ^Arena, size: int) {
|
||||||
backing = context.allocator
|
backing = context.allocator;
|
||||||
memory = new_slice(byte, 0, size)
|
memory = new_slice(byte, size);
|
||||||
temp_count = 0
|
temp_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
free_arena :: proc(using a: ^Arena) {
|
free_arena :: proc(using a: ^Arena) {
|
||||||
if backing.procedure != nil {
|
if backing.procedure != nil {
|
||||||
push_allocator backing {
|
push_allocator backing {
|
||||||
free(memory.data)
|
free(memory);
|
||||||
memory = memory[0:0:0]
|
memory = nil;
|
||||||
|
offset = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -154,57 +141,57 @@ arena_allocator :: proc(arena: ^Arena) -> Allocator {
|
|||||||
return Allocator{
|
return Allocator{
|
||||||
procedure = arena_allocator_proc,
|
procedure = arena_allocator_proc,
|
||||||
data = arena,
|
data = arena,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator.Mode,
|
arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||||
size, alignment: int,
|
size, alignment: int,
|
||||||
old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
|
old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
|
||||||
arena := allocator_data as ^Arena
|
using Allocator_Mode;
|
||||||
|
arena := cast(^Arena)allocator_data;
|
||||||
|
|
||||||
using Allocator.Mode
|
|
||||||
match mode {
|
match mode {
|
||||||
case ALLOC:
|
case ALLOC:
|
||||||
total_size := size + alignment
|
total_size := size + alignment;
|
||||||
|
|
||||||
if arena.memory.count + total_size > arena.memory.capacity {
|
if arena.offset + total_size > arena.memory.count {
|
||||||
fmt.fprintln(os.stderr, "Arena out of memory")
|
fmt.fprintln(os.stderr, "Arena out of memory");
|
||||||
return nil
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
#no_bounds_check end := ^arena.memory[arena.memory.count]
|
#no_bounds_check end := ^arena.memory[arena.offset];
|
||||||
|
|
||||||
ptr := align_forward(end, alignment)
|
ptr := align_forward(end, alignment);
|
||||||
arena.memory.count += total_size
|
arena.offset += total_size;
|
||||||
return zero(ptr, size)
|
return zero(ptr, size);
|
||||||
|
|
||||||
case FREE:
|
case FREE:
|
||||||
// NOTE(bill): Free all at once
|
// NOTE(bill): Free all at once
|
||||||
// Use Arena.Temp_Memory if you want to free a block
|
// Use Arena_Temp_Memory if you want to free a block
|
||||||
|
|
||||||
case FREE_ALL:
|
case FREE_ALL:
|
||||||
arena.memory.count = 0
|
arena.offset = 0;
|
||||||
|
|
||||||
case RESIZE:
|
case RESIZE:
|
||||||
return default_resize_align(old_memory, old_size, size, alignment)
|
return default_resize_align(old_memory, old_size, size, alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
begin_arena_temp_memory :: proc(a: ^Arena) -> Arena.Temp_Memory {
|
begin_arena_temp_memory :: proc(a: ^Arena) -> Arena_Temp_Memory {
|
||||||
tmp: Arena.Temp_Memory
|
tmp: Arena_Temp_Memory;
|
||||||
tmp.arena = a
|
tmp.arena = a;
|
||||||
tmp.original_count = a.memory.count
|
tmp.original_count = a.memory.count;
|
||||||
a.temp_count++
|
a.temp_count++;
|
||||||
return tmp
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
end_arena_temp_memory :: proc(using tmp: Arena.Temp_Memory) {
|
end_arena_temp_memory :: proc(using tmp: Arena_Temp_Memory) {
|
||||||
assert(arena.memory.count >= original_count)
|
assert(arena.memory.count >= original_count);
|
||||||
assert(arena.temp_count > 0)
|
assert(arena.temp_count > 0);
|
||||||
arena.memory.count = original_count
|
arena.memory.count = original_count;
|
||||||
arena.temp_count--
|
arena.temp_count--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -214,119 +201,126 @@ end_arena_temp_memory :: proc(using tmp: Arena.Temp_Memory) {
|
|||||||
|
|
||||||
|
|
||||||
align_of_type_info :: proc(type_info: ^Type_Info) -> int {
|
align_of_type_info :: proc(type_info: ^Type_Info) -> int {
|
||||||
WORD_SIZE :: size_of(int)
|
prev_pow2 :: proc(n: i64) -> i64 {
|
||||||
using Type_Info
|
if n <= 0 {
|
||||||
|
return 0;
|
||||||
match type info : type_info {
|
}
|
||||||
case Named:
|
n |= n >> 1;
|
||||||
return align_of_type_info(info.base)
|
n |= n >> 2;
|
||||||
case Integer:
|
n |= n >> 4;
|
||||||
return info.size
|
n |= n >> 8;
|
||||||
case Float:
|
n |= n >> 16;
|
||||||
return info.size
|
n |= n >> 32;
|
||||||
case String:
|
return n - (n >> 1);
|
||||||
return WORD_SIZE
|
|
||||||
case Boolean:
|
|
||||||
return 1
|
|
||||||
case Pointer:
|
|
||||||
return WORD_SIZE
|
|
||||||
case Maybe:
|
|
||||||
return max(align_of_type_info(info.elem), 1)
|
|
||||||
case Procedure:
|
|
||||||
return WORD_SIZE
|
|
||||||
case Array:
|
|
||||||
return align_of_type_info(info.elem)
|
|
||||||
case Slice:
|
|
||||||
return WORD_SIZE
|
|
||||||
case Vector:
|
|
||||||
return align_of_type_info(info.elem)
|
|
||||||
case Struct:
|
|
||||||
return info.align
|
|
||||||
case Union:
|
|
||||||
return info.align
|
|
||||||
case Raw_Union:
|
|
||||||
return info.align
|
|
||||||
case Enum:
|
|
||||||
return align_of_type_info(info.base)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
WORD_SIZE :: size_of(int);
|
||||||
|
MAX_ALIGN :: size_of([vector 64]f64); // TODO(bill): Should these constants be builtin constants?
|
||||||
|
using Type_Info;
|
||||||
|
match info in type_info {
|
||||||
|
case Named:
|
||||||
|
return align_of_type_info(info.base);
|
||||||
|
case Integer:
|
||||||
|
return info.size;
|
||||||
|
case Float:
|
||||||
|
return info.size;
|
||||||
|
case String:
|
||||||
|
return WORD_SIZE;
|
||||||
|
case Boolean:
|
||||||
|
return 1;
|
||||||
|
case Any:
|
||||||
|
return WORD_SIZE;
|
||||||
|
case Pointer:
|
||||||
|
return WORD_SIZE;
|
||||||
|
case Procedure:
|
||||||
|
return WORD_SIZE;
|
||||||
|
case Array:
|
||||||
|
return align_of_type_info(info.elem);
|
||||||
|
case Dynamic_Array:
|
||||||
|
return WORD_SIZE;
|
||||||
|
case Slice:
|
||||||
|
return WORD_SIZE;
|
||||||
|
case Vector:
|
||||||
|
size := size_of_type_info(info.elem);
|
||||||
|
count := cast(int)max(prev_pow2(cast(i64)info.count), 1);
|
||||||
|
total := size * count;
|
||||||
|
return clamp(total, 1, MAX_ALIGN);
|
||||||
|
case Tuple:
|
||||||
|
return info.align;
|
||||||
|
case Struct:
|
||||||
|
return info.align;
|
||||||
|
case Union:
|
||||||
|
return info.align;
|
||||||
|
case Raw_Union:
|
||||||
|
return info.align;
|
||||||
|
case Enum:
|
||||||
|
return align_of_type_info(info.base);
|
||||||
|
case Map:
|
||||||
|
return align_of_type_info(info.generated_struct);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
align_formula :: proc(size, align: int) -> int {
|
align_formula :: proc(size, align: int) -> int {
|
||||||
result := size + align-1
|
result := size + align-1;
|
||||||
return result - result%align
|
return result - result%align;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_of_type_info :: proc(type_info: ^Type_Info) -> int {
|
size_of_type_info :: proc(type_info: ^Type_Info) -> int {
|
||||||
WORD_SIZE :: size_of(int)
|
WORD_SIZE :: size_of(int);
|
||||||
using Type_Info
|
using Type_Info;
|
||||||
|
match info in type_info {
|
||||||
match type info : type_info {
|
|
||||||
case Named:
|
case Named:
|
||||||
return size_of_type_info(info.base)
|
return size_of_type_info(info.base);
|
||||||
case Integer:
|
case Integer:
|
||||||
return info.size
|
return info.size;
|
||||||
case Float:
|
case Float:
|
||||||
return info.size
|
return info.size;
|
||||||
case Any:
|
|
||||||
return 2*WORD_SIZE
|
|
||||||
case String:
|
case String:
|
||||||
return 2*WORD_SIZE
|
return 2*WORD_SIZE;
|
||||||
case Boolean:
|
case Boolean:
|
||||||
return 1
|
return 1;
|
||||||
|
case Any:
|
||||||
|
return 2*WORD_SIZE;
|
||||||
case Pointer:
|
case Pointer:
|
||||||
return WORD_SIZE
|
return WORD_SIZE;
|
||||||
case Maybe:
|
|
||||||
return size_of_type_info(info.elem) + 1
|
|
||||||
case Procedure:
|
case Procedure:
|
||||||
return WORD_SIZE
|
return WORD_SIZE;
|
||||||
case Array:
|
case Array:
|
||||||
count := info.count
|
count := info.count;
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
return 0
|
return 0;
|
||||||
}
|
}
|
||||||
size := size_of_type_info(info.elem)
|
size := size_of_type_info(info.elem);
|
||||||
align := align_of_type_info(info.elem)
|
align := align_of_type_info(info.elem);
|
||||||
alignment := align_formula(size, align)
|
alignment := align_formula(size, align);
|
||||||
return alignment*(count-1) + size
|
return alignment*(count-1) + size;
|
||||||
|
case Dynamic_Array:
|
||||||
|
return size_of(rawptr) + 2*size_of(int) + size_of(Allocator);
|
||||||
case Slice:
|
case Slice:
|
||||||
return 3*WORD_SIZE
|
return 2*WORD_SIZE;
|
||||||
case Vector:
|
case Vector:
|
||||||
is_bool :: proc(type_info: ^Type_Info) -> bool {
|
count := info.count;
|
||||||
match type info : type_info {
|
|
||||||
case Named:
|
|
||||||
return is_bool(info.base)
|
|
||||||
case Boolean:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
count := info.count
|
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
return 0
|
return 0;
|
||||||
}
|
}
|
||||||
bit_size := 8*size_of_type_info(info.elem)
|
size := size_of_type_info(info.elem);
|
||||||
if is_bool(info.elem) {
|
align := align_of_type_info(info.elem);
|
||||||
// NOTE(bill): LLVM can store booleans as 1 bit because a boolean _is_ an `i1`
|
alignment := align_formula(size, align);
|
||||||
// Silly LLVM spec
|
return alignment*(count-1) + size;
|
||||||
bit_size = 1
|
|
||||||
}
|
|
||||||
total_size_in_bits := bit_size * count
|
|
||||||
total_size := (total_size_in_bits+7)/8
|
|
||||||
return total_size
|
|
||||||
|
|
||||||
case Struct:
|
case Struct:
|
||||||
return info.size
|
return info.size;
|
||||||
case Union:
|
case Union:
|
||||||
return info.size
|
return info.size;
|
||||||
case Raw_Union:
|
case Raw_Union:
|
||||||
return info.size
|
return info.size;
|
||||||
case Enum:
|
case Enum:
|
||||||
return size_of_type_info(info.base)
|
return size_of_type_info(info.base);
|
||||||
|
case Map:
|
||||||
|
return size_of_type_info(info.generated_struct);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+121
-120
@@ -1,155 +1,156 @@
|
|||||||
#foreign_system_library "opengl32"
|
#foreign_system_library lib "opengl32.lib" when ODIN_OS == "windows";
|
||||||
#import "win32.odin"
|
#import win32 "sys/windows.odin" when ODIN_OS == "windows";
|
||||||
#load "opengl_constants.odin"
|
#import "sys/wgl.odin" when ODIN_OS == "windows";
|
||||||
|
#load "opengl_constants.odin";
|
||||||
|
|
||||||
Clear :: proc(mask: u32) #foreign "glClear"
|
Clear :: proc(mask: u32) #foreign lib "glClear";
|
||||||
ClearColor :: proc(r, g, b, a: f32) #foreign "glClearColor"
|
ClearColor :: proc(r, g, b, a: f32) #foreign lib "glClearColor";
|
||||||
Begin :: proc(mode: i32) #foreign "glBegin"
|
Begin :: proc(mode: i32) #foreign lib "glBegin";
|
||||||
End :: proc() #foreign "glEnd"
|
End :: proc() #foreign lib "glEnd";
|
||||||
Finish :: proc() #foreign "glFinish"
|
Finish :: proc() #foreign lib "glFinish";
|
||||||
BlendFunc :: proc(sfactor, dfactor: i32) #foreign "glBlendFunc"
|
BlendFunc :: proc(sfactor, dfactor: i32) #foreign lib "glBlendFunc";
|
||||||
Enable :: proc(cap: i32) #foreign "glEnable"
|
Enable :: proc(cap: i32) #foreign lib "glEnable";
|
||||||
Disable :: proc(cap: i32) #foreign "glDisable"
|
Disable :: proc(cap: i32) #foreign lib "glDisable";
|
||||||
GenTextures :: proc(count: i32, result: ^u32) #foreign "glGenTextures"
|
GenTextures :: proc(count: i32, result: ^u32) #foreign lib "glGenTextures";
|
||||||
DeleteTextures :: proc(count: i32, result: ^u32) #foreign "glDeleteTextures"
|
DeleteTextures:: proc(count: i32, result: ^u32) #foreign lib "glDeleteTextures";
|
||||||
TexParameteri :: proc(target, pname, param: i32) #foreign "glTexParameteri"
|
TexParameteri :: proc(target, pname, param: i32) #foreign lib "glTexParameteri";
|
||||||
TexParameterf :: proc(target: i32, pname: i32, param: f32) #foreign "glTexParameterf"
|
TexParameterf :: proc(target: i32, pname: i32, param: f32) #foreign lib "glTexParameterf";
|
||||||
BindTexture :: proc(target: i32, texture: u32) #foreign "glBindTexture"
|
BindTexture :: proc(target: i32, texture: u32) #foreign lib "glBindTexture";
|
||||||
LoadIdentity :: proc() #foreign "glLoadIdentity"
|
LoadIdentity :: proc() #foreign lib "glLoadIdentity";
|
||||||
Viewport :: proc(x, y, width, height: i32) #foreign "glViewport"
|
Viewport :: proc(x, y, width, height: i32) #foreign lib "glViewport";
|
||||||
Ortho :: proc(left, right, bottom, top, near, far: f64) #foreign "glOrtho"
|
Ortho :: proc(left, right, bottom, top, near, far: f64) #foreign lib "glOrtho";
|
||||||
Color3f :: proc(r, g, b: f32) #foreign "glColor3f"
|
Color3f :: proc(r, g, b: f32) #foreign lib "glColor3f";
|
||||||
Vertex3f :: proc(x, y, z: f32) #foreign "glVertex3f"
|
Vertex3f :: proc(x, y, z: f32) #foreign lib "glVertex3f";
|
||||||
TexImage2D :: proc(target, level, internal_format,
|
GetError :: proc() -> i32 #foreign lib "glGetError";
|
||||||
width, height, border,
|
GetString :: proc(name: i32) -> ^byte #foreign lib "glGetString";
|
||||||
format, _type: i32, pixels: rawptr) #foreign "glTexImage2D"
|
GetIntegerv :: proc(name: i32, v: ^i32) #foreign lib "glGetIntegerv";
|
||||||
|
TexCoord2f :: proc(x, y: f32) #foreign lib "glTexCoord2f";
|
||||||
GetError :: proc() -> i32 #foreign "glGetError"
|
TexImage2D :: proc(target, level, internal_format,
|
||||||
GetString :: proc(name: i32) -> ^byte #foreign "glGetString"
|
width, height, border,
|
||||||
GetIntegerv :: proc(name: i32, v: ^i32) #foreign "glGetIntegerv"
|
format, type: i32, pixels: rawptr) #foreign lib "glTexImage2D";
|
||||||
|
|
||||||
|
|
||||||
|
string_data :: proc(s: string) -> ^u8 #inline { return ^s[0]; }
|
||||||
|
|
||||||
_libgl := win32.LoadLibraryA(("opengl32.dll\x00" as string).data)
|
_libgl := win32.LoadLibraryA(string_data("opengl32.dll\x00"));
|
||||||
|
|
||||||
GetProcAddress :: proc(name: string) -> proc() {
|
GetProcAddress :: proc(name: string) -> proc() #cc_c {
|
||||||
assert(name[name.count-1] == 0)
|
assert(name[name.count-1] == 0);
|
||||||
res := win32.wglGetProcAddress(name.data)
|
res := wgl.GetProcAddress(name.data);
|
||||||
if res == nil {
|
if res == nil {
|
||||||
res = win32.GetProcAddress(_libgl, name.data);
|
res = win32.GetProcAddress(_libgl, name.data);
|
||||||
}
|
}
|
||||||
return res
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GenBuffers: proc(count: i32, buffers: ^u32) #cc_c;
|
||||||
|
GenVertexArrays: proc(count: i32, buffers: ^u32) #cc_c;
|
||||||
|
GenSamplers: proc(count: i32, buffers: ^u32) #cc_c;
|
||||||
|
BindBuffer: proc(target: i32, buffer: u32) #cc_c;
|
||||||
|
BindVertexArray: proc(buffer: u32) #cc_c;
|
||||||
|
BindSampler: proc(position: i32, sampler: u32) #cc_c;
|
||||||
|
BufferData: proc(target: i32, size: int, data: rawptr, usage: i32) #cc_c;
|
||||||
|
BufferSubData: proc(target: i32, offset, size: int, data: rawptr) #cc_c;
|
||||||
|
|
||||||
GenBuffers: proc(count: i32, buffers: ^u32)
|
DrawArrays: proc(mode, first: i32, count: u32) #cc_c;
|
||||||
GenVertexArrays: proc(count: i32, buffers: ^u32)
|
DrawElements: proc(mode: i32, count: u32, type_: i32, indices: rawptr) #cc_c;
|
||||||
GenSamplers: proc(count: i32, buffers: ^u32)
|
|
||||||
BindBuffer: proc(target: i32, buffer: u32)
|
|
||||||
BindVertexArray: proc(buffer: u32)
|
|
||||||
BindSampler: proc(position: i32, sampler: u32)
|
|
||||||
BufferData: proc(target: i32, size: int, data: rawptr, usage: i32)
|
|
||||||
BufferSubData: proc(target: i32, offset, size: int, data: rawptr)
|
|
||||||
|
|
||||||
DrawArrays: proc(mode, first: i32, count: u32)
|
MapBuffer: proc(target, access: i32) -> rawptr #cc_c;
|
||||||
DrawElements: proc(mode: i32, count: u32, type_: i32, indices: rawptr)
|
UnmapBuffer: proc(target: i32) #cc_c;
|
||||||
|
|
||||||
MapBuffer: proc(target, access: i32) -> rawptr
|
VertexAttribPointer: proc(index: u32, size, type_: i32, normalized: i32, stride: u32, pointer: rawptr) #cc_c;
|
||||||
UnmapBuffer: proc(target: i32)
|
EnableVertexAttribArray: proc(index: u32) #cc_c;
|
||||||
|
|
||||||
VertexAttribPointer: proc(index: u32, size, type_: i32, normalized: i32, stride: u32, pointer: rawptr)
|
CreateShader: proc(shader_type: i32) -> u32 #cc_c;
|
||||||
EnableVertexAttribArray: proc(index: u32)
|
ShaderSource: proc(shader: u32, count: u32, str: ^^byte, length: ^i32) #cc_c;
|
||||||
|
CompileShader: proc(shader: u32) #cc_c;
|
||||||
CreateShader: proc(shader_type: i32) -> u32
|
CreateProgram: proc() -> u32 #cc_c;
|
||||||
ShaderSource: proc(shader: u32, count: u32, string: ^^byte, length: ^i32)
|
AttachShader: proc(program, shader: u32) #cc_c;
|
||||||
CompileShader: proc(shader: u32)
|
DetachShader: proc(program, shader: u32) #cc_c;
|
||||||
CreateProgram: proc() -> u32
|
DeleteShader: proc(shader: u32) #cc_c;
|
||||||
AttachShader: proc(program, shader: u32)
|
LinkProgram: proc(program: u32) #cc_c;
|
||||||
DetachShader: proc(program, shader: u32)
|
UseProgram: proc(program: u32) #cc_c;
|
||||||
DeleteShader: proc(shader: u32)
|
DeleteProgram: proc(program: u32) #cc_c;
|
||||||
LinkProgram: proc(program: u32)
|
|
||||||
UseProgram: proc(program: u32)
|
|
||||||
DeleteProgram: proc(program: u32)
|
|
||||||
|
|
||||||
|
|
||||||
GetShaderiv: proc(shader: u32, pname: i32, params: ^i32)
|
GetShaderiv: proc(shader: u32, pname: i32, params: ^i32) #cc_c;
|
||||||
GetProgramiv: proc(program: u32, pname: i32, params: ^i32)
|
GetProgramiv: proc(program: u32, pname: i32, params: ^i32) #cc_c;
|
||||||
GetShaderInfoLog: proc(shader: u32, max_length: u32, length: ^u32, info_long: ^byte)
|
GetShaderInfoLog: proc(shader: u32, max_length: u32, length: ^u32, info_long: ^byte) #cc_c;
|
||||||
GetProgramInfoLog: proc(program: u32, max_length: u32, length: ^u32, info_long: ^byte)
|
GetProgramInfoLog: proc(program: u32, max_length: u32, length: ^u32, info_long: ^byte) #cc_c;
|
||||||
|
|
||||||
ActiveTexture: proc(texture: i32)
|
ActiveTexture: proc(texture: i32) #cc_c;
|
||||||
GenerateMipmap: proc(target: i32)
|
GenerateMipmap: proc(target: i32) #cc_c;
|
||||||
|
|
||||||
SamplerParameteri: proc(sampler: u32, pname: i32, param: i32)
|
SamplerParameteri: proc(sampler: u32, pname: i32, param: i32) #cc_c;
|
||||||
SamplerParameterf: proc(sampler: u32, pname: i32, param: f32)
|
SamplerParameterf: proc(sampler: u32, pname: i32, param: f32) #cc_c;
|
||||||
SamplerParameteriv: proc(sampler: u32, pname: i32, params: ^i32)
|
SamplerParameteriv: proc(sampler: u32, pname: i32, params: ^i32) #cc_c;
|
||||||
SamplerParameterfv: proc(sampler: u32, pname: i32, params: ^f32)
|
SamplerParameterfv: proc(sampler: u32, pname: i32, params: ^f32) #cc_c;
|
||||||
SamplerParameterIiv: proc(sampler: u32, pname: i32, params: ^i32)
|
SamplerParameterIiv: proc(sampler: u32, pname: i32, params: ^i32) #cc_c;
|
||||||
SamplerParameterIuiv: proc(sampler: u32, pname: i32, params: ^u32)
|
SamplerParameterIuiv: proc(sampler: u32, pname: i32, params: ^u32) #cc_c;
|
||||||
|
|
||||||
|
|
||||||
Uniform1i: proc(loc: i32, v0: i32)
|
Uniform1i: proc(loc: i32, v0: i32) #cc_c;
|
||||||
Uniform2i: proc(loc: i32, v0, v1: i32)
|
Uniform2i: proc(loc: i32, v0, v1: i32) #cc_c;
|
||||||
Uniform3i: proc(loc: i32, v0, v1, v2: i32)
|
Uniform3i: proc(loc: i32, v0, v1, v2: i32) #cc_c;
|
||||||
Uniform4i: proc(loc: i32, v0, v1, v2, v3: i32)
|
Uniform4i: proc(loc: i32, v0, v1, v2, v3: i32) #cc_c;
|
||||||
Uniform1f: proc(loc: i32, v0: f32)
|
Uniform1f: proc(loc: i32, v0: f32) #cc_c;
|
||||||
Uniform2f: proc(loc: i32, v0, v1: f32)
|
Uniform2f: proc(loc: i32, v0, v1: f32) #cc_c;
|
||||||
Uniform3f: proc(loc: i32, v0, v1, v2: f32)
|
Uniform3f: proc(loc: i32, v0, v1, v2: f32) #cc_c;
|
||||||
Uniform4f: proc(loc: i32, v0, v1, v2, v3: f32)
|
Uniform4f: proc(loc: i32, v0, v1, v2, v3: f32) #cc_c;
|
||||||
UniformMatrix4fv: proc(loc: i32, count: u32, transpose: i32, value: ^f32)
|
UniformMatrix4fv: proc(loc: i32, count: u32, transpose: i32, value: ^f32) #cc_c;
|
||||||
|
|
||||||
GetUniformLocation: proc(program: u32, name: ^byte) -> i32
|
GetUniformLocation: proc(program: u32, name: ^byte) -> i32 #cc_c;
|
||||||
|
|
||||||
init :: proc() {
|
init :: proc() {
|
||||||
set_proc_address :: proc(p: rawptr, name: string) #inline { (p as ^proc())^ = GetProcAddress(name) }
|
set_proc_address :: proc(p: rawptr, name: string) #inline { (cast(^(proc() #cc_c))p)^ = GetProcAddress(name); }
|
||||||
|
|
||||||
set_proc_address(^GenBuffers, "glGenBuffers\x00")
|
set_proc_address(^GenBuffers, "glGenBuffers\x00");
|
||||||
set_proc_address(^GenVertexArrays, "glGenVertexArrays\x00")
|
set_proc_address(^GenVertexArrays, "glGenVertexArrays\x00");
|
||||||
set_proc_address(^GenSamplers, "glGenSamplers\x00")
|
set_proc_address(^GenSamplers, "glGenSamplers\x00");
|
||||||
set_proc_address(^BindBuffer, "glBindBuffer\x00")
|
set_proc_address(^BindBuffer, "glBindBuffer\x00");
|
||||||
set_proc_address(^BindSampler, "glBindSampler\x00")
|
set_proc_address(^BindSampler, "glBindSampler\x00");
|
||||||
set_proc_address(^BindVertexArray, "glBindVertexArray\x00")
|
set_proc_address(^BindVertexArray, "glBindVertexArray\x00");
|
||||||
set_proc_address(^BufferData, "glBufferData\x00")
|
set_proc_address(^BufferData, "glBufferData\x00");
|
||||||
set_proc_address(^BufferSubData, "glBufferSubData\x00")
|
set_proc_address(^BufferSubData, "glBufferSubData\x00");
|
||||||
|
|
||||||
set_proc_address(^DrawArrays, "glDrawArrays\x00")
|
set_proc_address(^DrawArrays, "glDrawArrays\x00");
|
||||||
set_proc_address(^DrawElements, "glDrawElements\x00")
|
set_proc_address(^DrawElements, "glDrawElements\x00");
|
||||||
|
|
||||||
set_proc_address(^MapBuffer, "glMapBuffer\x00")
|
set_proc_address(^MapBuffer, "glMapBuffer\x00");
|
||||||
set_proc_address(^UnmapBuffer, "glUnmapBuffer\x00")
|
set_proc_address(^UnmapBuffer, "glUnmapBuffer\x00");
|
||||||
|
|
||||||
set_proc_address(^VertexAttribPointer, "glVertexAttribPointer\x00")
|
set_proc_address(^VertexAttribPointer, "glVertexAttribPointer\x00");
|
||||||
set_proc_address(^EnableVertexAttribArray, "glEnableVertexAttribArray\x00")
|
set_proc_address(^EnableVertexAttribArray, "glEnableVertexAttribArray\x00");
|
||||||
|
|
||||||
set_proc_address(^CreateShader, "glCreateShader\x00")
|
set_proc_address(^CreateShader, "glCreateShader\x00");
|
||||||
set_proc_address(^ShaderSource, "glShaderSource\x00")
|
set_proc_address(^ShaderSource, "glShaderSource\x00");
|
||||||
set_proc_address(^CompileShader, "glCompileShader\x00")
|
set_proc_address(^CompileShader, "glCompileShader\x00");
|
||||||
set_proc_address(^CreateProgram, "glCreateProgram\x00")
|
set_proc_address(^CreateProgram, "glCreateProgram\x00");
|
||||||
set_proc_address(^AttachShader, "glAttachShader\x00")
|
set_proc_address(^AttachShader, "glAttachShader\x00");
|
||||||
set_proc_address(^DetachShader, "glDetachShader\x00")
|
set_proc_address(^DetachShader, "glDetachShader\x00");
|
||||||
set_proc_address(^DeleteShader, "glDeleteShader\x00")
|
set_proc_address(^DeleteShader, "glDeleteShader\x00");
|
||||||
set_proc_address(^LinkProgram, "glLinkProgram\x00")
|
set_proc_address(^LinkProgram, "glLinkProgram\x00");
|
||||||
set_proc_address(^UseProgram, "glUseProgram\x00")
|
set_proc_address(^UseProgram, "glUseProgram\x00");
|
||||||
set_proc_address(^DeleteProgram, "glDeleteProgram\x00")
|
set_proc_address(^DeleteProgram, "glDeleteProgram\x00");
|
||||||
|
|
||||||
set_proc_address(^GetShaderiv, "glGetShaderiv\x00")
|
set_proc_address(^GetShaderiv, "glGetShaderiv\x00");
|
||||||
set_proc_address(^GetProgramiv, "glGetProgramiv\x00")
|
set_proc_address(^GetProgramiv, "glGetProgramiv\x00");
|
||||||
set_proc_address(^GetShaderInfoLog, "glGetShaderInfoLog\x00")
|
set_proc_address(^GetShaderInfoLog, "glGetShaderInfoLog\x00");
|
||||||
set_proc_address(^GetProgramInfoLog, "glGetProgramInfoLog\x00")
|
set_proc_address(^GetProgramInfoLog, "glGetProgramInfoLog\x00");
|
||||||
|
|
||||||
set_proc_address(^ActiveTexture, "glActiveTexture\x00")
|
set_proc_address(^ActiveTexture, "glActiveTexture\x00");
|
||||||
set_proc_address(^GenerateMipmap, "glGenerateMipmap\x00")
|
set_proc_address(^GenerateMipmap, "glGenerateMipmap\x00");
|
||||||
|
|
||||||
set_proc_address(^Uniform1i, "glUniform1i\x00")
|
set_proc_address(^Uniform1i, "glUniform1i\x00");
|
||||||
set_proc_address(^UniformMatrix4fv, "glUniformMatrix4fv\x00")
|
set_proc_address(^UniformMatrix4fv, "glUniformMatrix4fv\x00");
|
||||||
|
|
||||||
set_proc_address(^GetUniformLocation, "glGetUniformLocation\x00")
|
set_proc_address(^GetUniformLocation, "glGetUniformLocation\x00");
|
||||||
|
|
||||||
set_proc_address(^SamplerParameteri, "glSamplerParameteri\x00")
|
set_proc_address(^SamplerParameteri, "glSamplerParameteri\x00");
|
||||||
set_proc_address(^SamplerParameterf, "glSamplerParameterf\x00")
|
set_proc_address(^SamplerParameterf, "glSamplerParameterf\x00");
|
||||||
set_proc_address(^SamplerParameteriv, "glSamplerParameteriv\x00")
|
set_proc_address(^SamplerParameteriv, "glSamplerParameteriv\x00");
|
||||||
set_proc_address(^SamplerParameterfv, "glSamplerParameterfv\x00")
|
set_proc_address(^SamplerParameterfv, "glSamplerParameterfv\x00");
|
||||||
set_proc_address(^SamplerParameterIiv, "glSamplerParameterIiv\x00")
|
set_proc_address(^SamplerParameterIiv, "glSamplerParameterIiv\x00");
|
||||||
set_proc_address(^SamplerParameterIuiv, "glSamplerParameterIuiv\x00")
|
set_proc_address(^SamplerParameterIuiv, "glSamplerParameterIuiv\x00");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1366
-1365
File diff suppressed because it is too large
Load Diff
+2
-171
@@ -1,172 +1,3 @@
|
|||||||
#import "win32.odin"
|
#load "os_windows.odin" when ODIN_OS == "windows";
|
||||||
#import "fmt.odin"
|
#load "os_x.odin" when ODIN_OS == "osx";
|
||||||
|
|
||||||
File_Time :: type u64
|
|
||||||
|
|
||||||
File :: struct {
|
|
||||||
Handle :: type win32.HANDLE
|
|
||||||
handle: Handle
|
|
||||||
last_write_time: File_Time
|
|
||||||
}
|
|
||||||
|
|
||||||
open :: proc(name: string) -> (File, bool) {
|
|
||||||
using win32
|
|
||||||
buf: [300]byte
|
|
||||||
copy(buf[:], name as []byte)
|
|
||||||
f := File{
|
|
||||||
handle = CreateFileA(^buf[0], FILE_GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, nil),
|
|
||||||
}
|
|
||||||
success := f.handle != INVALID_HANDLE_VALUE as File.Handle
|
|
||||||
f.last_write_time = last_write_time(^f)
|
|
||||||
return f, success
|
|
||||||
}
|
|
||||||
|
|
||||||
create :: proc(name: string) -> (File, bool) {
|
|
||||||
using win32
|
|
||||||
buf: [300]byte
|
|
||||||
copy(buf[:], name as []byte)
|
|
||||||
f := File{
|
|
||||||
handle = CreateFileA(^buf[0], FILE_GENERIC_WRITE, FILE_SHARE_READ, nil, CREATE_ALWAYS, 0, nil),
|
|
||||||
}
|
|
||||||
success := f.handle != INVALID_HANDLE_VALUE as File.Handle
|
|
||||||
f.last_write_time = last_write_time(^f)
|
|
||||||
return f, success
|
|
||||||
}
|
|
||||||
|
|
||||||
close :: proc(using f: ^File) {
|
|
||||||
win32.CloseHandle(handle)
|
|
||||||
}
|
|
||||||
|
|
||||||
write :: proc(using f: ^File, buf: []byte) -> bool {
|
|
||||||
bytes_written: i32
|
|
||||||
return win32.WriteFile(handle, buf.data, buf.count as i32, ^bytes_written, nil) != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
file_has_changed :: proc(f: ^File) -> bool {
|
|
||||||
last_write_time := last_write_time(f)
|
|
||||||
if f.last_write_time != last_write_time {
|
|
||||||
f.last_write_time = last_write_time
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
last_write_time :: proc(f: ^File) -> File_Time {
|
|
||||||
file_info: win32.BY_HANDLE_FILE_INFORMATION
|
|
||||||
win32.GetFileInformationByHandle(f.handle, ^file_info)
|
|
||||||
l := file_info.last_write_time.low_date_time as File_Time
|
|
||||||
h := file_info.last_write_time.high_date_time as File_Time
|
|
||||||
return l | h << 32
|
|
||||||
}
|
|
||||||
|
|
||||||
last_write_time_by_name :: proc(name: string) -> File_Time {
|
|
||||||
last_write_time: win32.FILETIME
|
|
||||||
data: win32.WIN32_FILE_ATTRIBUTE_DATA
|
|
||||||
|
|
||||||
buf: [1024]byte
|
|
||||||
path := buf[:0]
|
|
||||||
fmt.bprint(^path, name, "\x00")
|
|
||||||
|
|
||||||
if win32.GetFileAttributesExA(path.data, win32.GetFileExInfoStandard, ^data) != 0 {
|
|
||||||
last_write_time = data.last_write_time
|
|
||||||
}
|
|
||||||
|
|
||||||
l := last_write_time.low_date_time as File_Time
|
|
||||||
h := last_write_time.high_date_time as File_Time
|
|
||||||
return l | h << 32
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
File_Standard :: type enum {
|
|
||||||
INPUT,
|
|
||||||
OUTPUT,
|
|
||||||
ERROR,
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE(bill): Uses startup to initialize it
|
|
||||||
__std_files := [File_Standard.count]File{
|
|
||||||
{handle = win32.GetStdHandle(win32.STD_INPUT_HANDLE)},
|
|
||||||
{handle = win32.GetStdHandle(win32.STD_OUTPUT_HANDLE)},
|
|
||||||
{handle = win32.GetStdHandle(win32.STD_ERROR_HANDLE)},
|
|
||||||
}
|
|
||||||
|
|
||||||
stdin := ^__std_files[File_Standard.INPUT]
|
|
||||||
stdout := ^__std_files[File_Standard.OUTPUT]
|
|
||||||
stderr := ^__std_files[File_Standard.ERROR]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
read_entire_file :: proc(name: string) -> ([]byte, bool) {
|
|
||||||
buf: [300]byte
|
|
||||||
copy(buf[:], name as []byte)
|
|
||||||
|
|
||||||
f, file_ok := open(name)
|
|
||||||
if !file_ok {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
defer close(^f)
|
|
||||||
|
|
||||||
length: i64
|
|
||||||
file_size_ok := win32.GetFileSizeEx(f.handle as win32.HANDLE, ^length) != 0
|
|
||||||
if !file_size_ok {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
data := new_slice(u8, length)
|
|
||||||
if data.data == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
single_read_length: i32
|
|
||||||
total_read: i64
|
|
||||||
|
|
||||||
for total_read < length {
|
|
||||||
remaining := length - total_read
|
|
||||||
to_read: u32
|
|
||||||
MAX :: 1<<32-1
|
|
||||||
if remaining <= MAX {
|
|
||||||
to_read = remaining as u32
|
|
||||||
} else {
|
|
||||||
to_read = MAX
|
|
||||||
}
|
|
||||||
|
|
||||||
win32.ReadFile(f.handle as win32.HANDLE, ^data[total_read], to_read, ^single_read_length, nil)
|
|
||||||
if single_read_length <= 0 {
|
|
||||||
free(data.data)
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
total_read += single_read_length as i64
|
|
||||||
}
|
|
||||||
|
|
||||||
return data, true
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
heap_alloc :: proc(size: int) -> rawptr {
|
|
||||||
return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, size)
|
|
||||||
}
|
|
||||||
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
|
||||||
return win32.HeapReAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, ptr, new_size)
|
|
||||||
}
|
|
||||||
heap_free :: proc(ptr: rawptr) {
|
|
||||||
win32.HeapFree(win32.GetProcessHeap(), 0, ptr)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
exit :: proc(code: int) {
|
|
||||||
win32.ExitProcess(code as u32)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
current_thread_id :: proc() -> int {
|
|
||||||
GetCurrentThreadId :: proc() -> u32 #foreign #dll_import
|
|
||||||
return GetCurrentThreadId() as int
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,283 @@
|
|||||||
|
#import win32 "sys/windows.odin";
|
||||||
|
#import "fmt.odin";
|
||||||
|
|
||||||
|
|
||||||
|
Handle :: int;
|
||||||
|
File_Time :: u64;
|
||||||
|
Errno :: int;
|
||||||
|
|
||||||
|
INVALID_HANDLE: Handle : -1;
|
||||||
|
|
||||||
|
|
||||||
|
O_RDONLY :: 0x00000;
|
||||||
|
O_WRONLY :: 0x00001;
|
||||||
|
O_RDWR :: 0x00002;
|
||||||
|
O_CREAT :: 0x00040;
|
||||||
|
O_EXCL :: 0x00080;
|
||||||
|
O_NOCTTY :: 0x00100;
|
||||||
|
O_TRUNC :: 0x00200;
|
||||||
|
O_NONBLOCK :: 0x00800;
|
||||||
|
O_APPEND :: 0x00400;
|
||||||
|
O_SYNC :: 0x01000;
|
||||||
|
O_ASYNC :: 0x02000;
|
||||||
|
O_CLOEXEC :: 0x80000;
|
||||||
|
|
||||||
|
ERROR_NONE: Errno : 0;
|
||||||
|
ERROR_FILE_NOT_FOUND: Errno : 2;
|
||||||
|
ERROR_PATH_NOT_FOUND: Errno : 3;
|
||||||
|
ERROR_ACCESS_DENIED: Errno : 5;
|
||||||
|
ERROR_NO_MORE_FILES: Errno : 18;
|
||||||
|
ERROR_HANDLE_EOF: Errno : 38;
|
||||||
|
ERROR_NETNAME_DELETED: Errno : 64;
|
||||||
|
ERROR_FILE_EXISTS: Errno : 80;
|
||||||
|
ERROR_BROKEN_PIPE: Errno : 109;
|
||||||
|
ERROR_BUFFER_OVERFLOW: Errno : 111;
|
||||||
|
ERROR_INSUFFICIENT_BUFFER: Errno : 122;
|
||||||
|
ERROR_MOD_NOT_FOUND: Errno : 126;
|
||||||
|
ERROR_PROC_NOT_FOUND: Errno : 127;
|
||||||
|
ERROR_DIR_NOT_EMPTY: Errno : 145;
|
||||||
|
ERROR_ALREADY_EXISTS: Errno : 183;
|
||||||
|
ERROR_ENVVAR_NOT_FOUND: Errno : 203;
|
||||||
|
ERROR_MORE_DATA: Errno : 234;
|
||||||
|
ERROR_OPERATION_ABORTED: Errno : 995;
|
||||||
|
ERROR_IO_PENDING: Errno : 997;
|
||||||
|
ERROR_NOT_FOUND: Errno : 1168;
|
||||||
|
ERROR_PRIVILEGE_NOT_HELD: Errno : 1314;
|
||||||
|
WSAEACCES: Errno : 10013;
|
||||||
|
WSAECONNRESET: Errno : 10054;
|
||||||
|
|
||||||
|
// Windows reserves errors >= 1<<29 for application use
|
||||||
|
ERROR_FILE_IS_PIPE: Errno : 1<<29 + 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
open :: proc(path: string, mode: int, perm: u32) -> (Handle, Errno) {
|
||||||
|
using win32;
|
||||||
|
if path.count == 0 {
|
||||||
|
return INVALID_HANDLE, ERROR_FILE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
access: u32;
|
||||||
|
match mode & (O_RDONLY|O_WRONLY|O_RDWR) {
|
||||||
|
case O_RDONLY: access = FILE_GENERIC_READ;
|
||||||
|
case O_WRONLY: access = FILE_GENERIC_WRITE;
|
||||||
|
case O_RDWR: access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if mode&O_CREAT != 0 {
|
||||||
|
access |= FILE_GENERIC_WRITE;
|
||||||
|
}
|
||||||
|
if mode&O_APPEND != 0 {
|
||||||
|
access &~= FILE_GENERIC_WRITE;
|
||||||
|
access |= FILE_APPEND_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
share_mode := cast(u32)(FILE_SHARE_READ|FILE_SHARE_WRITE);
|
||||||
|
sa: ^SECURITY_ATTRIBUTES = nil;
|
||||||
|
sa_inherit := SECURITY_ATTRIBUTES{length = size_of(SECURITY_ATTRIBUTES), inherit_handle = 1};
|
||||||
|
if mode&O_CLOEXEC == 0 {
|
||||||
|
sa = ^sa_inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
create_mode: u32;
|
||||||
|
match {
|
||||||
|
case mode&(O_CREAT|O_EXCL) == (O_CREAT | O_EXCL):
|
||||||
|
create_mode = CREATE_NEW;
|
||||||
|
case mode&(O_CREAT|O_TRUNC) == (O_CREAT | O_TRUNC):
|
||||||
|
create_mode = CREATE_ALWAYS;
|
||||||
|
case mode&O_CREAT == O_CREAT:
|
||||||
|
create_mode = OPEN_ALWAYS;
|
||||||
|
case mode&O_TRUNC == O_TRUNC:
|
||||||
|
create_mode = TRUNCATE_EXISTING;
|
||||||
|
default:
|
||||||
|
create_mode = OPEN_EXISTING;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf: [300]byte;
|
||||||
|
copy(buf[..], cast([]byte)path);
|
||||||
|
|
||||||
|
handle := cast(Handle)CreateFileA(^buf[0], access, share_mode, sa, create_mode, FILE_ATTRIBUTE_NORMAL, nil);
|
||||||
|
if handle != INVALID_HANDLE {
|
||||||
|
return handle, ERROR_NONE;
|
||||||
|
}
|
||||||
|
err := GetLastError();
|
||||||
|
return INVALID_HANDLE, cast(Errno)err;
|
||||||
|
}
|
||||||
|
|
||||||
|
close :: proc(fd: Handle) {
|
||||||
|
win32.CloseHandle(cast(win32.HANDLE)fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||||
|
bytes_written: i32;
|
||||||
|
e := win32.WriteFile(cast(win32.HANDLE)fd, data.data, cast(i32)data.count, ^bytes_written, nil);
|
||||||
|
if e == win32.FALSE {
|
||||||
|
err := win32.GetLastError();
|
||||||
|
return 0, cast(Errno)err;
|
||||||
|
}
|
||||||
|
return cast(int)bytes_written, ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||||
|
bytes_read: i32;
|
||||||
|
e := win32.ReadFile(cast(win32.HANDLE)fd, data.data, cast(u32)data.count, ^bytes_read, nil);
|
||||||
|
if e == win32.FALSE {
|
||||||
|
err := win32.GetLastError();
|
||||||
|
return 0, cast(Errno)err;
|
||||||
|
}
|
||||||
|
return cast(int)bytes_read, ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
||||||
|
using win32;
|
||||||
|
w: u32;
|
||||||
|
match whence {
|
||||||
|
case 0: w = FILE_BEGIN;
|
||||||
|
case 1: w = FILE_CURRENT;
|
||||||
|
case 2: w = FILE_END;
|
||||||
|
}
|
||||||
|
hi := cast(i32)(offset>>32);
|
||||||
|
lo := cast(i32)(offset);
|
||||||
|
ft := GetFileType(cast(HANDLE)fd);
|
||||||
|
if ft == FILE_TYPE_PIPE {
|
||||||
|
return 0, ERROR_FILE_IS_PIPE;
|
||||||
|
}
|
||||||
|
dw_ptr := SetFilePointer(cast(HANDLE)fd, lo, ^hi, w);
|
||||||
|
if dw_ptr == INVALID_SET_FILE_POINTER {
|
||||||
|
err := GetLastError();
|
||||||
|
return 0, cast(Errno)err;
|
||||||
|
}
|
||||||
|
return cast(i64)hi<<32 + cast(i64)dw_ptr, ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// NOTE(bill): Uses startup to initialize it
|
||||||
|
stdin := get_std_handle(win32.STD_INPUT_HANDLE);
|
||||||
|
stdout := get_std_handle(win32.STD_OUTPUT_HANDLE);
|
||||||
|
stderr := get_std_handle(win32.STD_ERROR_HANDLE);
|
||||||
|
|
||||||
|
|
||||||
|
get_std_handle :: proc(h: int) -> Handle {
|
||||||
|
fd := win32.GetStdHandle(cast(i32)h);
|
||||||
|
win32.SetHandleInformation(fd, win32.HANDLE_FLAG_INHERIT, 0);
|
||||||
|
return cast(Handle)fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
last_write_time :: proc(fd: Handle) -> File_Time {
|
||||||
|
file_info: win32.BY_HANDLE_FILE_INFORMATION;
|
||||||
|
win32.GetFileInformationByHandle(cast(win32.HANDLE)fd, ^file_info);
|
||||||
|
lo := cast(File_Time)file_info.last_write_time.lo;
|
||||||
|
hi := cast(File_Time)file_info.last_write_time.hi;
|
||||||
|
return lo | hi << 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_write_time_by_name :: proc(name: string) -> File_Time {
|
||||||
|
last_write_time: win32.FILETIME;
|
||||||
|
data: win32.FILE_ATTRIBUTE_DATA;
|
||||||
|
buf: [1024]byte;
|
||||||
|
|
||||||
|
assert(buf.count > name.count);
|
||||||
|
|
||||||
|
copy(buf[..], cast([]byte)name);
|
||||||
|
|
||||||
|
if win32.GetFileAttributesExA(^buf[0], win32.GetFileExInfoStandard, ^data) != 0 {
|
||||||
|
last_write_time = data.last_write_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
l := cast(File_Time)last_write_time.lo;
|
||||||
|
h := cast(File_Time)last_write_time.hi;
|
||||||
|
return l | h << 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
read_entire_file :: proc(name: string) -> ([]byte, bool) {
|
||||||
|
buf: [300]byte;
|
||||||
|
copy(buf[..], cast([]byte)name);
|
||||||
|
|
||||||
|
fd, err := open(name, O_RDONLY, 0);
|
||||||
|
if err != ERROR_NONE {
|
||||||
|
return nil, false;
|
||||||
|
}
|
||||||
|
defer close(fd);
|
||||||
|
|
||||||
|
length: i64;
|
||||||
|
file_size_ok := win32.GetFileSizeEx(cast(win32.HANDLE)fd, ^length) != 0;
|
||||||
|
if !file_size_ok {
|
||||||
|
return nil, false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data := new_slice(u8, length);
|
||||||
|
if data.data == nil {
|
||||||
|
return nil, false;
|
||||||
|
}
|
||||||
|
|
||||||
|
single_read_length: i32;
|
||||||
|
total_read: i64;
|
||||||
|
|
||||||
|
for total_read < length {
|
||||||
|
remaining := length - total_read;
|
||||||
|
to_read: u32;
|
||||||
|
MAX :: 1<<32-1;
|
||||||
|
if remaining <= MAX {
|
||||||
|
to_read = cast(u32)remaining;
|
||||||
|
} else {
|
||||||
|
to_read = MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
win32.ReadFile(cast(win32.HANDLE)fd, ^data[total_read], to_read, ^single_read_length, nil);
|
||||||
|
if single_read_length <= 0 {
|
||||||
|
free(data);
|
||||||
|
return nil, false;
|
||||||
|
}
|
||||||
|
|
||||||
|
total_read += cast(i64)single_read_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
heap_alloc :: proc(size: int) -> rawptr {
|
||||||
|
assert(size > 0);
|
||||||
|
return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, size);
|
||||||
|
}
|
||||||
|
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
||||||
|
if new_size == 0 {
|
||||||
|
heap_free(ptr);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
if ptr == nil {
|
||||||
|
return heap_alloc(new_size);
|
||||||
|
}
|
||||||
|
return win32.HeapReAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, ptr, new_size);
|
||||||
|
}
|
||||||
|
heap_free :: proc(ptr: rawptr) {
|
||||||
|
if ptr == nil {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
win32.HeapFree(win32.GetProcessHeap(), 0, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
exit :: proc(code: int) {
|
||||||
|
win32.ExitProcess(cast(u32)code);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
current_thread_id :: proc() -> int {
|
||||||
|
return cast(int)win32.GetCurrentThreadId();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
+230
@@ -0,0 +1,230 @@
|
|||||||
|
#import "fmt.odin";
|
||||||
|
|
||||||
|
Handle :: i32;
|
||||||
|
File_Time :: u64;
|
||||||
|
Errno :: int;
|
||||||
|
|
||||||
|
// INVALID_HANDLE: Handle : -1;
|
||||||
|
|
||||||
|
|
||||||
|
O_RDONLY :: 0x00000;
|
||||||
|
O_WRONLY :: 0x00001;
|
||||||
|
O_RDWR :: 0x00002;
|
||||||
|
O_CREAT :: 0x00040;
|
||||||
|
O_EXCL :: 0x00080;
|
||||||
|
O_NOCTTY :: 0x00100;
|
||||||
|
O_TRUNC :: 0x00200;
|
||||||
|
O_NONBLOCK :: 0x00800;
|
||||||
|
O_APPEND :: 0x00400;
|
||||||
|
O_SYNC :: 0x01000;
|
||||||
|
O_ASYNC :: 0x02000;
|
||||||
|
O_CLOEXEC :: 0x80000;
|
||||||
|
|
||||||
|
// ERROR_NONE: Errno : 0;
|
||||||
|
// ERROR_FILE_NOT_FOUND: Errno : 2;
|
||||||
|
// ERROR_PATH_NOT_FOUND: Errno : 3;
|
||||||
|
// ERROR_ACCESS_DENIED: Errno : 5;
|
||||||
|
// ERROR_NO_MORE_FILES: Errno : 18;
|
||||||
|
// ERROR_HANDLE_EOF: Errno : 38;
|
||||||
|
// ERROR_NETNAME_DELETED: Errno : 64;
|
||||||
|
// ERROR_FILE_EXISTS: Errno : 80;
|
||||||
|
// ERROR_BROKEN_PIPE: Errno : 109;
|
||||||
|
// ERROR_BUFFER_OVERFLOW: Errno : 111;
|
||||||
|
// ERROR_INSUFFICIENT_BUFFER: Errno : 122;
|
||||||
|
// ERROR_MOD_NOT_FOUND: Errno : 126;
|
||||||
|
// ERROR_PROC_NOT_FOUND: Errno : 127;
|
||||||
|
// ERROR_DIR_NOT_EMPTY: Errno : 145;
|
||||||
|
// ERROR_ALREADY_EXISTS: Errno : 183;
|
||||||
|
// ERROR_ENVVAR_NOT_FOUND: Errno : 203;
|
||||||
|
// ERROR_MORE_DATA: Errno : 234;
|
||||||
|
// ERROR_OPERATION_ABORTED: Errno : 995;
|
||||||
|
// ERROR_IO_PENDING: Errno : 997;
|
||||||
|
// ERROR_NOT_FOUND: Errno : 1168;
|
||||||
|
// ERROR_PRIVILEGE_NOT_HELD: Errno : 1314;
|
||||||
|
// WSAEACCES: Errno : 10013;
|
||||||
|
// WSAECONNRESET: Errno : 10054;
|
||||||
|
|
||||||
|
// Windows reserves errors >= 1<<29 for application use
|
||||||
|
// ERROR_FILE_IS_PIPE: Errno : 1<<29 + 0;
|
||||||
|
|
||||||
|
#foreign_system_library libc "c";
|
||||||
|
|
||||||
|
unix_open :: proc(path: ^u8, mode: int, perm: u32) -> Handle #foreign libc "open";
|
||||||
|
unix_close :: proc(handle: Handle) #foreign libc "close";
|
||||||
|
unix_read :: proc(handle: Handle, buffer: rawptr, count: int) -> int #foreign libc "read";
|
||||||
|
unix_write :: proc(handle: Handle, buffer: rawptr, count: int) -> int #foreign libc "write";
|
||||||
|
unix_gettid :: proc() -> u64 #foreign libc "gettid";
|
||||||
|
|
||||||
|
unix_malloc :: proc(size: int) -> rawptr #foreign libc "malloc";
|
||||||
|
unix_free :: proc(ptr: rawptr) #foreign libc "free";
|
||||||
|
unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr #foreign libc "realloc";
|
||||||
|
|
||||||
|
unix_exit :: proc(status: int) #foreign libc "exit";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
open :: proc(path: string, mode: int, perm: u32) -> (Handle, Errno) {
|
||||||
|
return unix_open(path.data, mode, perm), 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
close :: proc(fd: Handle) {
|
||||||
|
unix_close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||||
|
return unix_write(fd, data.data, data.count), 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||||
|
return unix_read(fd, data.data, data.count), 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
||||||
|
/*
|
||||||
|
using win32;
|
||||||
|
w: u32;
|
||||||
|
match whence {
|
||||||
|
case 0: w = FILE_BEGIN;
|
||||||
|
case 1: w = FILE_CURRENT;
|
||||||
|
case 2: w = FILE_END;
|
||||||
|
}
|
||||||
|
hi := cast(i32)(offset>>32);
|
||||||
|
lo := cast(i32)(offset);
|
||||||
|
ft := GetFileType(cast(HANDLE)fd);
|
||||||
|
if ft == FILE_TYPE_PIPE {
|
||||||
|
return 0, ERROR_FILE_IS_PIPE;
|
||||||
|
}
|
||||||
|
dw_ptr := SetFilePointer(cast(HANDLE)fd, lo, ^hi, w);
|
||||||
|
if dw_ptr == INVALID_SET_FILE_POINTER {
|
||||||
|
err := GetLastError();
|
||||||
|
return 0, cast(Errno)err;
|
||||||
|
}
|
||||||
|
return cast(i64)hi<<32 + cast(i64)dw_ptr, ERROR_NONE;
|
||||||
|
|
||||||
|
*/
|
||||||
|
return 0, 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// NOTE(bill): Uses startup to initialize it
|
||||||
|
stdin: Handle = 0; // get_std_handle(win32.STD_INPUT_HANDLE);
|
||||||
|
stdout: Handle = 1; // get_std_handle(win32.STD_OUTPUT_HANDLE);
|
||||||
|
stderr: Handle = 2; // get_std_handle(win32.STD_ERROR_HANDLE);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
get_std_handle :: proc(h: int) -> Handle {
|
||||||
|
fd := win32.GetStdHandle(cast(i32)h);
|
||||||
|
win32.SetHandleInformation(fd, win32.HANDLE_FLAG_INHERIT, 0);
|
||||||
|
return cast(Handle)fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
last_write_time :: proc(fd: Handle) -> File_Time {
|
||||||
|
file_info: win32.BY_HANDLE_FILE_INFORMATION;
|
||||||
|
win32.GetFileInformationByHandle(cast(win32.HANDLE)fd, ^file_info);
|
||||||
|
lo := cast(File_Time)file_info.last_write_time.lo;
|
||||||
|
hi := cast(File_Time)file_info.last_write_time.hi;
|
||||||
|
return lo | hi << 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_write_time_by_name :: proc(name: string) -> File_Time {
|
||||||
|
last_write_time: win32.FILETIME;
|
||||||
|
data: win32.FILE_ATTRIBUTE_DATA;
|
||||||
|
buf: [1024]byte;
|
||||||
|
|
||||||
|
assert(buf.count > name.count);
|
||||||
|
|
||||||
|
copy(buf[:], cast([]byte)name);
|
||||||
|
|
||||||
|
if win32.GetFileAttributesExA(^buf[0], win32.GetFileExInfoStandard, ^data) != 0 {
|
||||||
|
last_write_time = data.last_write_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
l := cast(File_Time)last_write_time.lo;
|
||||||
|
h := cast(File_Time)last_write_time.hi;
|
||||||
|
return l | h << 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
read_entire_file :: proc(name: string) -> ([]byte, bool) {
|
||||||
|
buf: [300]byte;
|
||||||
|
copy(buf[:], cast([]byte)name);
|
||||||
|
|
||||||
|
fd, err := open(name, O_RDONLY, 0);
|
||||||
|
if err != ERROR_NONE {
|
||||||
|
return nil, false;
|
||||||
|
}
|
||||||
|
defer close(fd);
|
||||||
|
|
||||||
|
length: i64;
|
||||||
|
file_size_ok := win32.GetFileSizeEx(cast(win32.HANDLE)fd, ^length) != 0;
|
||||||
|
if !file_size_ok {
|
||||||
|
return nil, false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data := new_slice(u8, length);
|
||||||
|
if data.data == nil {
|
||||||
|
return nil, false;
|
||||||
|
}
|
||||||
|
|
||||||
|
single_read_length: i32;
|
||||||
|
total_read: i64;
|
||||||
|
|
||||||
|
for total_read < length {
|
||||||
|
remaining := length - total_read;
|
||||||
|
to_read: u32;
|
||||||
|
MAX :: 1<<32-1;
|
||||||
|
if remaining <= MAX {
|
||||||
|
to_read = cast(u32)remaining;
|
||||||
|
} else {
|
||||||
|
to_read = MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
win32.ReadFile(cast(win32.HANDLE)fd, ^data[total_read], to_read, ^single_read_length, nil);
|
||||||
|
if single_read_length <= 0 {
|
||||||
|
free(data);
|
||||||
|
return nil, false;
|
||||||
|
}
|
||||||
|
|
||||||
|
total_read += cast(i64)single_read_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
heap_alloc :: proc(size: int) -> rawptr {
|
||||||
|
assert(size > 0);
|
||||||
|
return unix_malloc(size);
|
||||||
|
}
|
||||||
|
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
||||||
|
return unix_realloc(ptr, new_size);
|
||||||
|
}
|
||||||
|
heap_free :: proc(ptr: rawptr) {
|
||||||
|
unix_free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
exit :: proc(code: int) {
|
||||||
|
unix_exit(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
current_thread_id :: proc() -> int {
|
||||||
|
// return cast(int) unix_gettid();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,336 @@
|
|||||||
|
#import . "decimal.odin";
|
||||||
|
#import "math.odin";
|
||||||
|
|
||||||
|
Int_Flag :: enum {
|
||||||
|
PREFIX = 1<<0,
|
||||||
|
PLUS = 1<<1,
|
||||||
|
SPACE = 1<<2,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
parse_bool :: proc(s: string) -> (result: bool, ok: bool) {
|
||||||
|
match s {
|
||||||
|
case "1", "t", "T", "true", "TRUE", "True":
|
||||||
|
return true, true;
|
||||||
|
case "0", "f", "F", "false", "FALSE", "False":
|
||||||
|
return false, true;
|
||||||
|
}
|
||||||
|
return false, false;
|
||||||
|
}
|
||||||
|
|
||||||
|
append_bool :: proc(buf: []byte, b: bool) -> string {
|
||||||
|
s := b ? "true" : "false";
|
||||||
|
append(buf, ..cast([]byte)s);
|
||||||
|
return cast(string)buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
append_uint :: proc(buf: []byte, u: u64, base: int) -> string {
|
||||||
|
return append_bits(buf, u, base, false, digits, 0);
|
||||||
|
}
|
||||||
|
append_int :: proc(buf: []byte, i: i64, base: int) -> string {
|
||||||
|
return append_bits(buf, cast(u64)i, base, i < 0, digits, 0);
|
||||||
|
}
|
||||||
|
itoa :: proc(buf: []byte, i: int) -> string {
|
||||||
|
return append_int(buf, cast(i64)i, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string {
|
||||||
|
return cast(string)generic_ftoa(buf, f, fmt, prec, bit_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Decimal_Slice :: struct {
|
||||||
|
digits: []byte,
|
||||||
|
count: int,
|
||||||
|
decimal_point: int,
|
||||||
|
neg: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
Float_Info :: struct {
|
||||||
|
mantbits: uint,
|
||||||
|
expbits: uint,
|
||||||
|
bias: int,
|
||||||
|
}
|
||||||
|
|
||||||
|
f32_info := Float_Info{23, 8, -127};
|
||||||
|
f64_info := Float_Info{52, 11, -1023};
|
||||||
|
|
||||||
|
|
||||||
|
generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> []byte {
|
||||||
|
bits: u64;
|
||||||
|
flt: ^Float_Info;
|
||||||
|
match bit_size {
|
||||||
|
case 32:
|
||||||
|
bits = cast(u64)transmute(u32)cast(f32)val;
|
||||||
|
flt = ^f32_info;
|
||||||
|
case 64:
|
||||||
|
bits = transmute(u64)val;
|
||||||
|
flt = ^f64_info;
|
||||||
|
default:
|
||||||
|
panic("strconv: invalid bit_size");
|
||||||
|
}
|
||||||
|
|
||||||
|
neg := bits>>(flt.expbits+flt.mantbits) != 0;
|
||||||
|
exp := cast(int)(bits>>flt.mantbits) & (1<<flt.expbits - 1);
|
||||||
|
mant := bits & (cast(u64)1 << flt.mantbits - 1);
|
||||||
|
|
||||||
|
match exp {
|
||||||
|
case 1<<flt.expbits - 1:
|
||||||
|
s: string;
|
||||||
|
if mant != 0 {
|
||||||
|
s = "NaN";
|
||||||
|
} else if neg {
|
||||||
|
s = "-Inf";
|
||||||
|
} else {
|
||||||
|
s = "+Inf";
|
||||||
|
}
|
||||||
|
append(buf, ..cast([]byte)s);
|
||||||
|
return buf;
|
||||||
|
|
||||||
|
case 0: // denormalized
|
||||||
|
exp++;
|
||||||
|
|
||||||
|
default:
|
||||||
|
mant |= cast(u64)1 << flt.mantbits;
|
||||||
|
}
|
||||||
|
|
||||||
|
exp += flt.bias;
|
||||||
|
|
||||||
|
d_: Decimal;
|
||||||
|
d := ^d_;
|
||||||
|
assign(d, mant);
|
||||||
|
shift(d, exp - cast(int)flt.mantbits);
|
||||||
|
digs: Decimal_Slice;
|
||||||
|
shortest := prec < 0;
|
||||||
|
if shortest {
|
||||||
|
round_shortest(d, mant, exp, flt);
|
||||||
|
digs = Decimal_Slice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point};
|
||||||
|
match fmt {
|
||||||
|
case 'e', 'E': prec = digs.count-1;
|
||||||
|
case 'f', 'F': prec = max(digs.count-digs.decimal_point, 0);
|
||||||
|
case 'g', 'G': prec = digs.count;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match fmt {
|
||||||
|
case 'e', 'E': round(d, prec+1);
|
||||||
|
case 'f', 'F': round(d, d.decimal_point+prec);
|
||||||
|
case 'g', 'G':
|
||||||
|
if prec == 0 {
|
||||||
|
prec = 1;
|
||||||
|
}
|
||||||
|
round(d, prec);
|
||||||
|
}
|
||||||
|
|
||||||
|
digs = Decimal_Slice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point};
|
||||||
|
}
|
||||||
|
return format_digits(buf, shortest, neg, digs, prec, fmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slice, prec: int, fmt: byte) -> []byte {
|
||||||
|
match fmt {
|
||||||
|
case 'f', 'F':
|
||||||
|
add_bytes :: proc(dst: ^[]byte, w: ^int, bytes: ..byte) {
|
||||||
|
for b in bytes {
|
||||||
|
if dst.capacity <= w^ {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dst.count++;
|
||||||
|
dst[w^] = b;
|
||||||
|
w^++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dst := buf[..];
|
||||||
|
w := 0;
|
||||||
|
if neg {
|
||||||
|
add_bytes(^dst, ^w, '-');
|
||||||
|
} else {
|
||||||
|
add_bytes(^dst, ^w, '+');
|
||||||
|
}
|
||||||
|
|
||||||
|
// integer, padded with zeros when needed
|
||||||
|
if digs.decimal_point > 0 {
|
||||||
|
m := min(digs.count, digs.decimal_point);
|
||||||
|
add_bytes(^dst, ^w, ..digs.digits[..m]);
|
||||||
|
for ; m < digs.decimal_point; m++ {
|
||||||
|
add_bytes(^dst, ^w, '0');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
add_bytes(^dst, ^w, '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// fractional part
|
||||||
|
if prec > 0 {
|
||||||
|
add_bytes(^dst, ^w, '.');
|
||||||
|
for i in 0..prec {
|
||||||
|
c: byte = '0';
|
||||||
|
if j := digs.decimal_point + i; 0 <= j && j < digs.count {
|
||||||
|
c = digs.digits[j];
|
||||||
|
}
|
||||||
|
add_bytes(^dst, ^w, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf[..w];
|
||||||
|
|
||||||
|
case 'e', 'E':
|
||||||
|
panic("strconv: e/E float printing is not yet supported");
|
||||||
|
return buf; // TODO
|
||||||
|
|
||||||
|
case 'g', 'G':
|
||||||
|
panic("strconv: g/G float printing is not yet supported");
|
||||||
|
return buf; // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
c: [2]byte;
|
||||||
|
c[0] = '%';
|
||||||
|
c[1] = fmt;
|
||||||
|
append(buf, ..c[..]);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
round_shortest :: proc(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) {
|
||||||
|
if mant == 0 { // If mantissa is zero, the number is zero
|
||||||
|
d.count = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
10^(dp-nd) > 2^(exp-mantbits)
|
||||||
|
log2(10) * (dp-nd) > exp-mantbits
|
||||||
|
log(2) >~ 0.332
|
||||||
|
332*(dp-nd) >= 100*(exp-mantbits)
|
||||||
|
*/
|
||||||
|
minexp := flt.bias+1;
|
||||||
|
if exp > minexp && 332*(d.decimal_point-d.count) >= 100*(exp - cast(int)flt.mantbits) {
|
||||||
|
// Number is already its shortest
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
upper_: Decimal; upper: = ^upper_;
|
||||||
|
assign(upper, 2*mant - 1);
|
||||||
|
shift(upper, exp - cast(int)flt.mantbits - 1);
|
||||||
|
|
||||||
|
mantlo: u64;
|
||||||
|
explo: int;
|
||||||
|
if mant > 1<<flt.mantbits || exp == minexp {
|
||||||
|
mantlo = mant-1;
|
||||||
|
explo = exp;
|
||||||
|
} else {
|
||||||
|
mantlo = 2*mant - 1;
|
||||||
|
explo = exp-1;
|
||||||
|
}
|
||||||
|
lower_: Decimal; lower: = ^lower_;
|
||||||
|
assign(lower, 2*mantlo + 1);
|
||||||
|
shift(lower, explo - cast(int)flt.mantbits - 1);
|
||||||
|
|
||||||
|
inclusive := mant%2 == 0;
|
||||||
|
|
||||||
|
for i in 0..d.count {
|
||||||
|
l: byte = '0'; // lower digit
|
||||||
|
if i < lower.count {
|
||||||
|
l = lower.digits[i];
|
||||||
|
}
|
||||||
|
m := d.digits[i]; // middle digit
|
||||||
|
u: byte = '0'; // upper digit
|
||||||
|
if i < upper.count {
|
||||||
|
u = upper.digits[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
ok_round_down := l != m || inclusive && i+1 == lower.count;
|
||||||
|
ok_round_up := m != u && (inclusive || m+1 < u || i+1 < upper.count);
|
||||||
|
|
||||||
|
if (ok_round_down && ok_round_up) {
|
||||||
|
round(d, i+1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ok_round_down) {
|
||||||
|
round_down(d, i+1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ok_round_up) {
|
||||||
|
round_up(d, i+1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
MAX_BASE :: 32;
|
||||||
|
immutable digits := "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||||
|
|
||||||
|
|
||||||
|
append_bits :: proc(buf: []byte, u: u64, base: int, neg: bool, digits: string, flags: Int_Flag) -> string {
|
||||||
|
is_pow2 :: proc(x: i64) -> bool {
|
||||||
|
if (x <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return x&(x-1) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if base < 2 || base > MAX_BASE {
|
||||||
|
panic("strconv: illegal base passed to append_bits");
|
||||||
|
}
|
||||||
|
|
||||||
|
a: [65]byte;
|
||||||
|
i := a.count;
|
||||||
|
if neg {
|
||||||
|
u = -u;
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_pow2(cast(i64)base) {
|
||||||
|
b := cast(u64)base;
|
||||||
|
m := cast(uint)b - 1;
|
||||||
|
for u >= b {
|
||||||
|
i--;
|
||||||
|
a[i] = digits[cast(uint)u & m];
|
||||||
|
u >>= b;
|
||||||
|
}
|
||||||
|
i--;
|
||||||
|
a[i] = digits[cast(uint)u];
|
||||||
|
} else {
|
||||||
|
b := cast(u64)base;
|
||||||
|
for u >= b {
|
||||||
|
i--;
|
||||||
|
q := u / b;
|
||||||
|
a[i] = digits[cast(uint)(u-q*b)];
|
||||||
|
u = q;
|
||||||
|
}
|
||||||
|
|
||||||
|
i--;
|
||||||
|
a[i] = digits[cast(uint)u];
|
||||||
|
}
|
||||||
|
|
||||||
|
if flags&Int_Flag.PREFIX != 0 {
|
||||||
|
ok := true;
|
||||||
|
match base {
|
||||||
|
case 2: i--; a[i] = 'b';
|
||||||
|
case 8: i--; a[i] = 'o';
|
||||||
|
case 10: i--; a[i] = 'd';
|
||||||
|
case 16: i--; a[i] = 'x';
|
||||||
|
default: ok = false;
|
||||||
|
}
|
||||||
|
if ok {
|
||||||
|
i--;
|
||||||
|
a[i] = '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if neg {
|
||||||
|
i--; a[i] = '-';
|
||||||
|
} else if flags&Int_Flag.PLUS != 0 {
|
||||||
|
i--; a[i] = '+';
|
||||||
|
} else if flags&Int_Flag.SPACE != 0 {
|
||||||
|
i--; a[i] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
append(buf, ..a[i..]);
|
||||||
|
return cast(string)buf;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
new_c_string :: proc(s: string) -> ^byte {
|
||||||
|
c := new_slice(byte, s.count+1);
|
||||||
|
copy(c, cast([]byte)s);
|
||||||
|
c[s.count] = 0;
|
||||||
|
return c.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
to_odin_string :: proc(c: ^byte) -> string {
|
||||||
|
s: string;
|
||||||
|
s.data = c;
|
||||||
|
for (c+s.count)^ != 0 {
|
||||||
|
s.count++;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
#import win32 "sys/windows.odin" when ODIN_OS == "windows";
|
||||||
|
#import "atomic.odin";
|
||||||
|
|
||||||
|
Semaphore :: struct {
|
||||||
|
_handle: win32.HANDLE,
|
||||||
|
}
|
||||||
|
|
||||||
|
Mutex :: struct {
|
||||||
|
_semaphore: Semaphore,
|
||||||
|
_counter: i32,
|
||||||
|
_owner: i32,
|
||||||
|
_recursion: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
current_thread_id :: proc() -> i32 {
|
||||||
|
return cast(i32)win32.GetCurrentThreadId();
|
||||||
|
}
|
||||||
|
|
||||||
|
semaphore_init :: proc(s: ^Semaphore) {
|
||||||
|
s._handle = win32.CreateSemaphoreA(nil, 0, 1<<31-1, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
semaphore_destroy :: proc(s: ^Semaphore) {
|
||||||
|
win32.CloseHandle(s._handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
semaphore_post :: proc(s: ^Semaphore, count: int) {
|
||||||
|
win32.ReleaseSemaphore(s._handle, cast(i32)count, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
semaphore_release :: proc(s: ^Semaphore) #inline { semaphore_post(s, 1); }
|
||||||
|
|
||||||
|
semaphore_wait :: proc(s: ^Semaphore) {
|
||||||
|
win32.WaitForSingleObject(s._handle, win32.INFINITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
mutex_init :: proc(m: ^Mutex) {
|
||||||
|
atomic.store(^m._counter, 0);
|
||||||
|
atomic.store(^m._owner, current_thread_id());
|
||||||
|
semaphore_init(^m._semaphore);
|
||||||
|
m._recursion = 0;
|
||||||
|
}
|
||||||
|
mutex_destroy :: proc(m: ^Mutex) {
|
||||||
|
semaphore_destroy(^m._semaphore);
|
||||||
|
}
|
||||||
|
mutex_lock :: proc(m: ^Mutex) {
|
||||||
|
thread_id := current_thread_id();
|
||||||
|
if atomic.fetch_add(^m._counter, 1) > 0 {
|
||||||
|
if thread_id != atomic.load(^m._owner) {
|
||||||
|
semaphore_wait(^m._semaphore);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
atomic.store(^m._owner, thread_id);
|
||||||
|
m._recursion++;
|
||||||
|
}
|
||||||
|
mutex_try_lock :: proc(m: ^Mutex) -> bool {
|
||||||
|
thread_id := current_thread_id();
|
||||||
|
if atomic.load(^m._owner) == thread_id {
|
||||||
|
atomic.fetch_add(^m._counter, 1);
|
||||||
|
} else {
|
||||||
|
expected: i32 = 0;
|
||||||
|
if atomic.load(^m._counter) != 0 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if atomic.compare_exchange(^m._counter, expected, 1) == 0 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
atomic.store(^m._owner, thread_id);
|
||||||
|
}
|
||||||
|
m._recursion++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
mutex_unlock :: proc(m: ^Mutex) {
|
||||||
|
recursion: i32;
|
||||||
|
thread_id := current_thread_id();
|
||||||
|
assert(thread_id == atomic.load(^m._owner));
|
||||||
|
|
||||||
|
m._recursion--;
|
||||||
|
recursion = m._recursion;
|
||||||
|
if recursion == 0 {
|
||||||
|
atomic.store(^m._owner, thread_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if atomic.fetch_add(^m._counter, -1) > 1 {
|
||||||
|
if recursion == 0 {
|
||||||
|
semaphore_release(^m._semaphore);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
#foreign_system_library "opengl32.lib" when ODIN_OS == "windows";
|
||||||
|
#import . "windows.odin";
|
||||||
|
|
||||||
|
CONTEXT_MAJOR_VERSION_ARB :: 0x2091;
|
||||||
|
CONTEXT_MINOR_VERSION_ARB :: 0x2092;
|
||||||
|
CONTEXT_FLAGS_ARB :: 0x2094;
|
||||||
|
CONTEXT_PROFILE_MASK_ARB :: 0x9126;
|
||||||
|
CONTEXT_FORWARD_COMPATIBLE_BIT_ARB :: 0x0002;
|
||||||
|
CONTEXT_CORE_PROFILE_BIT_ARB :: 0x00000001;
|
||||||
|
|
||||||
|
HGLRC :: HANDLE;
|
||||||
|
COLORREF :: u32;
|
||||||
|
|
||||||
|
LAYERPLANEDESCRIPTOR :: struct #ordered {
|
||||||
|
size: u16,
|
||||||
|
version: u16,
|
||||||
|
flags: u32,
|
||||||
|
pixel_type: byte,
|
||||||
|
color_bits: byte,
|
||||||
|
red_bits: byte,
|
||||||
|
red_shift: byte,
|
||||||
|
green_bits: byte,
|
||||||
|
green_shift: byte,
|
||||||
|
blue_bits: byte,
|
||||||
|
blue_shift: byte,
|
||||||
|
alpha_bits: byte,
|
||||||
|
alpha_shift: byte,
|
||||||
|
accum_bits: byte,
|
||||||
|
accum_red_bits: byte,
|
||||||
|
accum_green_bits: byte,
|
||||||
|
accum_blue_bits: byte,
|
||||||
|
accum_alpha_bits: byte,
|
||||||
|
depth_bits: byte,
|
||||||
|
stencil_bits: byte,
|
||||||
|
aux_buffers: byte,
|
||||||
|
layer_type: byte,
|
||||||
|
reserved: byte,
|
||||||
|
transparent: COLORREF,
|
||||||
|
}
|
||||||
|
|
||||||
|
POINTFLOAT :: struct #ordered {
|
||||||
|
x, y: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
GLYPHMETRICSFLOAT :: struct #ordered {
|
||||||
|
black_box_x: f32,
|
||||||
|
black_box_y: f32,
|
||||||
|
glyph_origin: POINTFLOAT,
|
||||||
|
cell_inc_x: f32,
|
||||||
|
cell_inc_y: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateContextAttribsARBType :: #type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC;
|
||||||
|
ChoosePixelFormatARBType :: #type proc(hdc: HDC, attrib_i_list: ^i32, attrib_f_list: ^f32, max_formats: u32, formats: ^i32, num_formats : ^u32) -> BOOL #cc_c;
|
||||||
|
|
||||||
|
|
||||||
|
CreateContext :: proc(hdc: HDC) -> HGLRC #foreign opengl32 "wglCreateContext";
|
||||||
|
MakeCurrent :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign opengl32 "wglMakeCurrent";
|
||||||
|
GetProcAddress :: proc(c_str: ^u8) -> PROC #foreign opengl32 "wglGetProcAddress";
|
||||||
|
DeleteContext :: proc(hglrc: HGLRC) -> BOOL #foreign opengl32 "wglDeleteContext";
|
||||||
|
CopyContext :: proc(src, dst: HGLRC, mask: u32) -> BOOL #foreign opengl32 "wglCopyContext";
|
||||||
|
CreateLayerContext :: proc(hdc: HDC, layer_plane: i32) -> HGLRC #foreign opengl32 "wglCreateLayerContext";
|
||||||
|
DescribeLayerPlane :: proc(hdc: HDC, pixel_format, layer_plane: i32, bytes: u32, pd: ^LAYERPLANEDESCRIPTOR) -> BOOL #foreign opengl32 "wglDescribeLayerPlane";
|
||||||
|
GetCurrentContext :: proc() -> HGLRC #foreign opengl32 "wglGetCurrentContext";
|
||||||
|
GetCurrentDC :: proc() -> HDC #foreign opengl32 "wglGetCurrentDC";
|
||||||
|
GetLayerPaletteEntries :: proc(hdc: HDC, layer_plane, start, entries: i32, cr: ^COLORREF) -> i32 #foreign opengl32 "wglGetLayerPaletteEntries";
|
||||||
|
RealizeLayerPalette :: proc(hdc: HDC, layer_plane: i32, realize: BOOL) -> BOOL #foreign opengl32 "wglRealizeLayerPalette";
|
||||||
|
SetLayerPaletteEntries :: proc(hdc: HDC, layer_plane, start, entries: i32, cr: ^COLORREF) -> i32 #foreign opengl32 "wglSetLayerPaletteEntries";
|
||||||
|
ShareLists :: proc(hglrc1, hglrc2: HGLRC) -> BOOL #foreign opengl32 "wglShareLists";
|
||||||
|
SwapLayerBuffers :: proc(hdc: HDC, planes: u32) -> BOOL #foreign opengl32 "wglSwapLayerBuffers";
|
||||||
|
UseFontBitmaps :: proc(hdc: HDC, first, count, list_base: u32) -> BOOL #foreign opengl32 "wglUseFontBitmaps";
|
||||||
|
UseFontOutlines :: proc(hdc: HDC, first, count, list_base: u32, deviation, extrusion: f32, format: i32, gmf: ^GLYPHMETRICSFLOAT) -> BOOL #foreign opengl32 "wglUseFontOutlines";
|
||||||
@@ -0,0 +1,625 @@
|
|||||||
|
#foreign_system_library "kernel32.lib" when ODIN_OS == "windows";
|
||||||
|
#foreign_system_library "user32.lib" when ODIN_OS == "windows";
|
||||||
|
#foreign_system_library "gdi32.lib" when ODIN_OS == "windows";
|
||||||
|
#foreign_system_library "winmm.lib" when ODIN_OS == "windows";
|
||||||
|
|
||||||
|
HANDLE :: rawptr;
|
||||||
|
HWND :: HANDLE;
|
||||||
|
HDC :: HANDLE;
|
||||||
|
HINSTANCE :: HANDLE;
|
||||||
|
HICON :: HANDLE;
|
||||||
|
HCURSOR :: HANDLE;
|
||||||
|
HMENU :: HANDLE;
|
||||||
|
HBRUSH :: HANDLE;
|
||||||
|
HGDIOBJ :: HANDLE;
|
||||||
|
HMODULE :: HANDLE;
|
||||||
|
WPARAM :: uint;
|
||||||
|
LPARAM :: int;
|
||||||
|
LRESULT :: int;
|
||||||
|
ATOM :: i16;
|
||||||
|
BOOL :: i32;
|
||||||
|
WNDPROC :: #type proc(HWND, u32, WPARAM, LPARAM) -> LRESULT #cc_c;
|
||||||
|
|
||||||
|
|
||||||
|
INVALID_HANDLE_VALUE :: cast(HANDLE)~cast(int)0;
|
||||||
|
|
||||||
|
FALSE: BOOL : 0;
|
||||||
|
TRUE: BOOL : 1;
|
||||||
|
|
||||||
|
CS_VREDRAW :: 0x0001;
|
||||||
|
CS_HREDRAW :: 0x0002;
|
||||||
|
CS_OWNDC :: 0x0020;
|
||||||
|
CW_USEDEFAULT :: -0x80000000;
|
||||||
|
|
||||||
|
WS_OVERLAPPED :: 0;
|
||||||
|
WS_MAXIMIZEBOX :: 0x00010000;
|
||||||
|
WS_MINIMIZEBOX :: 0x00020000;
|
||||||
|
WS_THICKFRAME :: 0x00040000;
|
||||||
|
WS_SYSMENU :: 0x00080000;
|
||||||
|
WS_CAPTION :: 0x00C00000;
|
||||||
|
WS_VISIBLE :: 0x10000000;
|
||||||
|
WS_OVERLAPPEDWINDOW :: WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX;
|
||||||
|
|
||||||
|
WM_DESTROY :: 0x0002;
|
||||||
|
WM_SIZE :: 0x0005;
|
||||||
|
WM_CLOSE :: 0x0010;
|
||||||
|
WM_ACTIVATEAPP :: 0x001C;
|
||||||
|
WM_QUIT :: 0x0012;
|
||||||
|
WM_KEYDOWN :: 0x0100;
|
||||||
|
WM_KEYUP :: 0x0101;
|
||||||
|
WM_SIZING :: 0x0214;
|
||||||
|
WM_MOUSEWHEEL :: 0x020A;
|
||||||
|
WM_SYSKEYDOWN :: 0x0104;
|
||||||
|
WM_WINDOWPOSCHANGED :: 0x0047;
|
||||||
|
WM_SETCURSOR :: 0x0020;
|
||||||
|
WM_CHAR :: 0x0102;
|
||||||
|
|
||||||
|
PM_REMOVE :: 1;
|
||||||
|
|
||||||
|
COLOR_BACKGROUND :: cast(HBRUSH)(cast(int)1);
|
||||||
|
BLACK_BRUSH :: 4;
|
||||||
|
|
||||||
|
SM_CXSCREEN :: 0;
|
||||||
|
SM_CYSCREEN :: 1;
|
||||||
|
|
||||||
|
SW_SHOW :: 5;
|
||||||
|
|
||||||
|
|
||||||
|
POINT :: struct #ordered {
|
||||||
|
x, y: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
WNDCLASSEXA :: struct #ordered {
|
||||||
|
size, style: u32,
|
||||||
|
wnd_proc: WNDPROC,
|
||||||
|
cls_extra, wnd_extra: i32,
|
||||||
|
instance: HINSTANCE,
|
||||||
|
icon: HICON,
|
||||||
|
cursor: HCURSOR,
|
||||||
|
background: HBRUSH,
|
||||||
|
menu_name, class_name: ^u8,
|
||||||
|
sm: HICON,
|
||||||
|
}
|
||||||
|
|
||||||
|
MSG :: struct #ordered {
|
||||||
|
hwnd: HWND,
|
||||||
|
message: u32,
|
||||||
|
wparam: WPARAM,
|
||||||
|
lparam: LPARAM,
|
||||||
|
time: u32,
|
||||||
|
pt: POINT,
|
||||||
|
}
|
||||||
|
|
||||||
|
RECT :: struct #ordered {
|
||||||
|
left: i32,
|
||||||
|
top: i32,
|
||||||
|
right: i32,
|
||||||
|
bottom: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
FILETIME :: struct #ordered {
|
||||||
|
lo, hi: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
SYSTEMTIME :: struct #ordered {
|
||||||
|
year, month: u16,
|
||||||
|
day_of_week, day: u16,
|
||||||
|
hour, minute, second, millisecond: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
BY_HANDLE_FILE_INFORMATION :: struct #ordered {
|
||||||
|
file_attributes: u32,
|
||||||
|
creation_time,
|
||||||
|
last_access_time,
|
||||||
|
last_write_time: FILETIME,
|
||||||
|
volume_serial_number,
|
||||||
|
file_size_high,
|
||||||
|
file_size_low,
|
||||||
|
number_of_links,
|
||||||
|
file_index_high,
|
||||||
|
file_index_low: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE_ATTRIBUTE_DATA :: struct #ordered {
|
||||||
|
file_attributes: u32,
|
||||||
|
creation_time,
|
||||||
|
last_access_time,
|
||||||
|
last_write_time: FILETIME,
|
||||||
|
file_size_high,
|
||||||
|
file_size_low: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
GET_FILEEX_INFO_LEVELS :: i32;
|
||||||
|
|
||||||
|
GetFileExInfoStandard: GET_FILEEX_INFO_LEVELS : 0;
|
||||||
|
GetFileExMaxInfoLevel: GET_FILEEX_INFO_LEVELS : 1;
|
||||||
|
|
||||||
|
GetLastError :: proc() -> i32 #foreign kernel32;
|
||||||
|
ExitProcess :: proc(exit_code: u32) #foreign kernel32;
|
||||||
|
GetDesktopWindow :: proc() -> HWND #foreign user32;
|
||||||
|
GetCursorPos :: proc(p: ^POINT) -> i32 #foreign user32;
|
||||||
|
ScreenToClient :: proc(h: HWND, p: ^POINT) -> i32 #foreign user32;
|
||||||
|
GetModuleHandleA :: proc(module_name: ^u8) -> HINSTANCE #foreign kernel32;
|
||||||
|
GetStockObject :: proc(fn_object: i32) -> HGDIOBJ #foreign gdi32;
|
||||||
|
PostQuitMessage :: proc(exit_code: i32) #foreign user32;
|
||||||
|
SetWindowTextA :: proc(hwnd: HWND, c_string: ^u8) -> BOOL #foreign user32;
|
||||||
|
|
||||||
|
QueryPerformanceFrequency :: proc(result: ^i64) -> i32 #foreign kernel32;
|
||||||
|
QueryPerformanceCounter :: proc(result: ^i64) -> i32 #foreign kernel32;
|
||||||
|
|
||||||
|
Sleep :: proc(ms: i32) -> i32 #foreign kernel32;
|
||||||
|
|
||||||
|
OutputDebugStringA :: proc(c_str: ^u8) #foreign kernel32;
|
||||||
|
|
||||||
|
|
||||||
|
RegisterClassExA :: proc(wc: ^WNDCLASSEXA) -> ATOM #foreign user32;
|
||||||
|
CreateWindowExA :: proc(ex_style: u32,
|
||||||
|
class_name, title: ^u8,
|
||||||
|
style: u32,
|
||||||
|
x, y, w, h: i32,
|
||||||
|
parent: HWND, menu: HMENU, instance: HINSTANCE,
|
||||||
|
param: rawptr) -> HWND #foreign user32;
|
||||||
|
|
||||||
|
ShowWindow :: proc(hwnd: HWND, cmd_show: i32) -> BOOL #foreign user32;
|
||||||
|
TranslateMessage :: proc(msg: ^MSG) -> BOOL #foreign user32;
|
||||||
|
DispatchMessageA :: proc(msg: ^MSG) -> LRESULT #foreign user32;
|
||||||
|
UpdateWindow :: proc(hwnd: HWND) -> BOOL #foreign user32;
|
||||||
|
PeekMessageA :: proc(msg: ^MSG, hwnd: HWND,
|
||||||
|
msg_filter_min, msg_filter_max, remove_msg: u32) -> BOOL #foreign user32;
|
||||||
|
|
||||||
|
DefWindowProcA :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #foreign user32;
|
||||||
|
|
||||||
|
AdjustWindowRect :: proc(rect: ^RECT, style: u32, menu: BOOL) -> BOOL #foreign user32;
|
||||||
|
GetActiveWindow :: proc() -> HWND #foreign user32;
|
||||||
|
|
||||||
|
DestroyWindow :: proc(wnd: HWND) -> BOOL #foreign user32;
|
||||||
|
DescribePixelFormat :: proc(dc: HDC, pixel_format: i32, bytes : u32, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign user32;
|
||||||
|
|
||||||
|
|
||||||
|
GetQueryPerformanceFrequency :: proc() -> i64 {
|
||||||
|
r: i64;
|
||||||
|
QueryPerformanceFrequency(^r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetCommandLineA :: proc() -> ^u8 #foreign kernel32;
|
||||||
|
GetSystemMetrics :: proc(index: i32) -> i32 #foreign kernel32;
|
||||||
|
GetCurrentThreadId :: proc() -> u32 #foreign kernel32;
|
||||||
|
|
||||||
|
timeGetTime :: proc() -> u32 #foreign winmm;
|
||||||
|
GetSystemTimeAsFileTime :: proc(system_time_as_file_time: ^FILETIME) #foreign kernel32;
|
||||||
|
FileTimeToLocalFileTime :: proc(file_time: ^FILETIME, local_file_time: ^FILETIME) -> BOOL #foreign kernel32;
|
||||||
|
FileTimeToSystemTime :: proc(file_time: ^FILETIME, system_time: ^SYSTEMTIME) -> BOOL #foreign kernel32;
|
||||||
|
SystemTimeToFileTime :: proc(system_time: ^SYSTEMTIME, file_time: ^FILETIME) -> BOOL #foreign kernel32;
|
||||||
|
|
||||||
|
// File Stuff
|
||||||
|
|
||||||
|
CloseHandle :: proc(h: HANDLE) -> i32 #foreign kernel32;
|
||||||
|
GetStdHandle :: proc(h: i32) -> HANDLE #foreign kernel32;
|
||||||
|
CreateFileA :: proc(filename: ^u8, desired_access, share_mode: u32,
|
||||||
|
security: rawptr,
|
||||||
|
creation, flags_and_attribs: u32, template_file: HANDLE) -> HANDLE #foreign kernel32;
|
||||||
|
ReadFile :: proc(h: HANDLE, buf: rawptr, to_read: u32, bytes_read: ^i32, overlapped: rawptr) -> BOOL #foreign kernel32;
|
||||||
|
WriteFile :: proc(h: HANDLE, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> BOOL #foreign kernel32;
|
||||||
|
|
||||||
|
GetFileSizeEx :: proc(file_handle: HANDLE, file_size: ^i64) -> BOOL #foreign kernel32;
|
||||||
|
GetFileAttributesExA :: proc(filename: ^u8, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: rawptr) -> BOOL #foreign kernel32;
|
||||||
|
GetFileInformationByHandle :: proc(file_handle: HANDLE, file_info: ^BY_HANDLE_FILE_INFORMATION) -> BOOL #foreign kernel32;
|
||||||
|
|
||||||
|
GetFileType :: proc(file_handle: HANDLE) -> u32 #foreign kernel32;
|
||||||
|
SetFilePointer :: proc(file_handle: HANDLE, distance_to_move: i32, distance_to_move_high: ^i32, move_method: u32) -> u32 #foreign kernel32;
|
||||||
|
|
||||||
|
SetHandleInformation :: proc(obj: HANDLE, mask, flags: u32) -> BOOL #foreign kernel32;
|
||||||
|
|
||||||
|
HANDLE_FLAG_INHERIT :: 1;
|
||||||
|
HANDLE_FLAG_PROTECT_FROM_CLOSE :: 2;
|
||||||
|
|
||||||
|
|
||||||
|
FILE_BEGIN :: 0;
|
||||||
|
FILE_CURRENT :: 1;
|
||||||
|
FILE_END :: 2;
|
||||||
|
|
||||||
|
FILE_SHARE_READ :: 0x00000001;
|
||||||
|
FILE_SHARE_WRITE :: 0x00000002;
|
||||||
|
FILE_SHARE_DELETE :: 0x00000004;
|
||||||
|
FILE_GENERIC_ALL :: 0x10000000;
|
||||||
|
FILE_GENERIC_EXECUTE :: 0x20000000;
|
||||||
|
FILE_GENERIC_WRITE :: 0x40000000;
|
||||||
|
FILE_GENERIC_READ :: 0x80000000;
|
||||||
|
|
||||||
|
FILE_APPEND_DATA :: 0x0004;
|
||||||
|
|
||||||
|
STD_INPUT_HANDLE :: -10;
|
||||||
|
STD_OUTPUT_HANDLE :: -11;
|
||||||
|
STD_ERROR_HANDLE :: -12;
|
||||||
|
|
||||||
|
CREATE_NEW :: 1;
|
||||||
|
CREATE_ALWAYS :: 2;
|
||||||
|
OPEN_EXISTING :: 3;
|
||||||
|
OPEN_ALWAYS :: 4;
|
||||||
|
TRUNCATE_EXISTING :: 5;
|
||||||
|
|
||||||
|
FILE_ATTRIBUTE_READONLY :: 0x00000001;
|
||||||
|
FILE_ATTRIBUTE_HIDDEN :: 0x00000002;
|
||||||
|
FILE_ATTRIBUTE_SYSTEM :: 0x00000004;
|
||||||
|
FILE_ATTRIBUTE_DIRECTORY :: 0x00000010;
|
||||||
|
FILE_ATTRIBUTE_ARCHIVE :: 0x00000020;
|
||||||
|
FILE_ATTRIBUTE_DEVICE :: 0x00000040;
|
||||||
|
FILE_ATTRIBUTE_NORMAL :: 0x00000080;
|
||||||
|
FILE_ATTRIBUTE_TEMPORARY :: 0x00000100;
|
||||||
|
FILE_ATTRIBUTE_SPARSE_FILE :: 0x00000200;
|
||||||
|
FILE_ATTRIBUTE_REPARSE_POINT :: 0x00000400;
|
||||||
|
FILE_ATTRIBUTE_COMPRESSED :: 0x00000800;
|
||||||
|
FILE_ATTRIBUTE_OFFLINE :: 0x00001000;
|
||||||
|
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED :: 0x00002000;
|
||||||
|
FILE_ATTRIBUTE_ENCRYPTED :: 0x00004000;
|
||||||
|
|
||||||
|
FILE_TYPE_DISK :: 0x0001;
|
||||||
|
FILE_TYPE_CHAR :: 0x0002;
|
||||||
|
FILE_TYPE_PIPE :: 0x0003;
|
||||||
|
|
||||||
|
INVALID_SET_FILE_POINTER :: ~cast(u32)0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
HeapAlloc :: proc (h: HANDLE, flags: u32, bytes: int) -> rawptr #foreign kernel32;
|
||||||
|
HeapReAlloc :: proc (h: HANDLE, flags: u32, memory: rawptr, bytes: int) -> rawptr #foreign kernel32;
|
||||||
|
HeapFree :: proc (h: HANDLE, flags: u32, memory: rawptr) -> BOOL #foreign kernel32;
|
||||||
|
GetProcessHeap :: proc () -> HANDLE #foreign kernel32;
|
||||||
|
|
||||||
|
|
||||||
|
HEAP_ZERO_MEMORY :: 0x00000008;
|
||||||
|
|
||||||
|
// Synchronization
|
||||||
|
|
||||||
|
SECURITY_ATTRIBUTES :: struct #ordered {
|
||||||
|
length: u32,
|
||||||
|
security_descriptor: rawptr,
|
||||||
|
inherit_handle: BOOL,
|
||||||
|
}
|
||||||
|
|
||||||
|
INFINITE :: 0xffffffff;
|
||||||
|
|
||||||
|
CreateSemaphoreA :: proc(attributes: ^SECURITY_ATTRIBUTES, initial_count, maximum_count: i32, name: ^byte) -> HANDLE #foreign kernel32;
|
||||||
|
ReleaseSemaphore :: proc(semaphore: HANDLE, release_count: i32, previous_count: ^i32) -> BOOL #foreign kernel32;
|
||||||
|
WaitForSingleObject :: proc(handle: HANDLE, milliseconds: u32) -> u32 #foreign kernel32;
|
||||||
|
|
||||||
|
|
||||||
|
InterlockedCompareExchange :: proc(dst: ^i32, exchange, comparand: i32) -> i32 #foreign kernel32;
|
||||||
|
InterlockedExchange :: proc(dst: ^i32, desired: i32) -> i32 #foreign kernel32;
|
||||||
|
InterlockedExchangeAdd :: proc(dst: ^i32, desired: i32) -> i32 #foreign kernel32;
|
||||||
|
InterlockedAnd :: proc(dst: ^i32, desired: i32) -> i32 #foreign kernel32;
|
||||||
|
InterlockedOr :: proc(dst: ^i32, desired: i32) -> i32 #foreign kernel32;
|
||||||
|
|
||||||
|
InterlockedCompareExchange64 :: proc(dst: ^i64, exchange, comparand: i64) -> i64 #foreign kernel32;
|
||||||
|
InterlockedExchange64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign kernel32;
|
||||||
|
InterlockedExchangeAdd64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign kernel32;
|
||||||
|
InterlockedAnd64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign kernel32;
|
||||||
|
InterlockedOr64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign kernel32;
|
||||||
|
|
||||||
|
mm_pause :: proc() #foreign kernel32 "_mm_pause";
|
||||||
|
ReadWriteBarrier :: proc() #foreign kernel32;
|
||||||
|
WriteBarrier :: proc() #foreign kernel32;
|
||||||
|
ReadBarrier :: proc() #foreign kernel32;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
HMONITOR :: HANDLE;
|
||||||
|
|
||||||
|
GWL_STYLE :: -16;
|
||||||
|
|
||||||
|
HWND_TOP :: cast(HWND)cast(uint)0;
|
||||||
|
|
||||||
|
MONITOR_DEFAULTTONULL :: 0x00000000;
|
||||||
|
MONITOR_DEFAULTTOPRIMARY :: 0x00000001;
|
||||||
|
MONITOR_DEFAULTTONEAREST :: 0x00000002;
|
||||||
|
|
||||||
|
SWP_FRAMECHANGED :: 0x0020;
|
||||||
|
SWP_NOOWNERZORDER :: 0x0200;
|
||||||
|
SWP_NOZORDER :: 0x0004;
|
||||||
|
SWP_NOSIZE :: 0x0001;
|
||||||
|
SWP_NOMOVE :: 0x0002;
|
||||||
|
|
||||||
|
|
||||||
|
MONITORINFO :: struct #ordered {
|
||||||
|
size: u32,
|
||||||
|
monitor: RECT,
|
||||||
|
work: RECT,
|
||||||
|
flags: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
WINDOWPLACEMENT :: struct #ordered {
|
||||||
|
length: u32,
|
||||||
|
flags: u32,
|
||||||
|
show_cmd: u32,
|
||||||
|
min_pos: POINT,
|
||||||
|
max_pos: POINT,
|
||||||
|
normal_pos: RECT,
|
||||||
|
}
|
||||||
|
|
||||||
|
GetMonitorInfoA :: proc(monitor: HMONITOR, mi: ^MONITORINFO) -> BOOL #foreign user32;
|
||||||
|
MonitorFromWindow :: proc(wnd: HWND, flags : u32) -> HMONITOR #foreign user32;
|
||||||
|
|
||||||
|
SetWindowPos :: proc(wnd: HWND, wndInsertAfter: HWND, x, y, width, height: i32, flags: u32) #foreign user32 "SetWindowPos";
|
||||||
|
|
||||||
|
GetWindowPlacement :: proc(wnd: HWND, wndpl: ^WINDOWPLACEMENT) -> BOOL #foreign user32;
|
||||||
|
SetWindowPlacement :: proc(wnd: HWND, wndpl: ^WINDOWPLACEMENT) -> BOOL #foreign user32;
|
||||||
|
|
||||||
|
GetWindowLongPtrA :: proc(wnd: HWND, index: i32) -> i64 #foreign user32;
|
||||||
|
SetWindowLongPtrA :: proc(wnd: HWND, index: i32, new: i64) -> i64 #foreign user32;
|
||||||
|
|
||||||
|
GetWindowText :: proc(wnd: HWND, str: ^byte, maxCount: i32) -> i32 #foreign user32;
|
||||||
|
|
||||||
|
HIWORD :: proc(wParam: WPARAM) -> u16 { return cast(u16)((cast(u32)wParam >> 16) & 0xffff); }
|
||||||
|
HIWORD :: proc(lParam: LPARAM) -> u16 { return cast(u16)((cast(u32)lParam >> 16) & 0xffff); }
|
||||||
|
LOWORD :: proc(wParam: WPARAM) -> u16 { return cast(u16)wParam; }
|
||||||
|
LOWORD :: proc(lParam: LPARAM) -> u16 { return cast(u16)lParam; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
BITMAPINFOHEADER :: struct #ordered {
|
||||||
|
size: u32,
|
||||||
|
width, height: i32,
|
||||||
|
planes, bit_count: i16,
|
||||||
|
compression: u32,
|
||||||
|
size_image: u32,
|
||||||
|
x_pels_per_meter: i32,
|
||||||
|
y_pels_per_meter: i32,
|
||||||
|
clr_used: u32,
|
||||||
|
clr_important: u32,
|
||||||
|
}
|
||||||
|
BITMAPINFO :: struct #ordered {
|
||||||
|
using header: BITMAPINFOHEADER,
|
||||||
|
colors: [1]RGBQUAD,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RGBQUAD :: struct #ordered { blue, green, red, reserved: byte }
|
||||||
|
|
||||||
|
BI_RGB :: 0;
|
||||||
|
DIB_RGB_COLORS :: 0x00;
|
||||||
|
SRCCOPY: u32 : 0x00cc0020;
|
||||||
|
|
||||||
|
|
||||||
|
StretchDIBits :: proc (hdc: HDC,
|
||||||
|
x_dst, y_dst, width_dst, height_dst: i32,
|
||||||
|
x_src, y_src, width_src, header_src: i32,
|
||||||
|
bits: rawptr, bits_info: ^BITMAPINFO,
|
||||||
|
usage: u32,
|
||||||
|
rop: u32) -> i32 #foreign gdi32;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
LoadLibraryA :: proc (c_str: ^u8) -> HMODULE #foreign kernel32;
|
||||||
|
FreeLibrary :: proc (h: HMODULE) #foreign kernel32;
|
||||||
|
GetProcAddress :: proc (h: HMODULE, c_str: ^u8) -> PROC #foreign kernel32;
|
||||||
|
|
||||||
|
GetClientRect :: proc(hwnd: HWND, rect: ^RECT) -> BOOL #foreign user32;
|
||||||
|
|
||||||
|
// Windows OpenGL
|
||||||
|
PFD_TYPE_RGBA :: 0;
|
||||||
|
PFD_TYPE_COLORINDEX :: 1;
|
||||||
|
PFD_MAIN_PLANE :: 0;
|
||||||
|
PFD_OVERLAY_PLANE :: 1;
|
||||||
|
PFD_UNDERLAY_PLANE :: -1;
|
||||||
|
PFD_DOUBLEBUFFER :: 1;
|
||||||
|
PFD_STEREO :: 2;
|
||||||
|
PFD_DRAW_TO_WINDOW :: 4;
|
||||||
|
PFD_DRAW_TO_BITMAP :: 8;
|
||||||
|
PFD_SUPPORT_GDI :: 16;
|
||||||
|
PFD_SUPPORT_OPENGL :: 32;
|
||||||
|
PFD_GENERIC_FORMAT :: 64;
|
||||||
|
PFD_NEED_PALETTE :: 128;
|
||||||
|
PFD_NEED_SYSTEM_PALETTE :: 0x00000100;
|
||||||
|
PFD_SWAP_EXCHANGE :: 0x00000200;
|
||||||
|
PFD_SWAP_COPY :: 0x00000400;
|
||||||
|
PFD_SWAP_LAYER_BUFFERS :: 0x00000800;
|
||||||
|
PFD_GENERIC_ACCELERATED :: 0x00001000;
|
||||||
|
PFD_DEPTH_DONTCARE :: 0x20000000;
|
||||||
|
PFD_DOUBLEBUFFER_DONTCARE :: 0x40000000;
|
||||||
|
PFD_STEREO_DONTCARE :: 0x80000000;
|
||||||
|
|
||||||
|
|
||||||
|
PIXELFORMATDESCRIPTOR :: struct #ordered {
|
||||||
|
size,
|
||||||
|
version,
|
||||||
|
flags: u32,
|
||||||
|
|
||||||
|
pixel_type,
|
||||||
|
color_bits,
|
||||||
|
red_bits,
|
||||||
|
red_shift,
|
||||||
|
green_bits,
|
||||||
|
green_shift,
|
||||||
|
blue_bits,
|
||||||
|
blue_shift,
|
||||||
|
alpha_bits,
|
||||||
|
alpha_shift,
|
||||||
|
accum_bits,
|
||||||
|
accum_red_bits,
|
||||||
|
accum_green_bits,
|
||||||
|
accum_blue_bits,
|
||||||
|
accum_alpha_bits,
|
||||||
|
depth_bits,
|
||||||
|
stencil_bits,
|
||||||
|
aux_buffers,
|
||||||
|
layer_type,
|
||||||
|
reserved: byte,
|
||||||
|
|
||||||
|
layer_mask,
|
||||||
|
visible_mask,
|
||||||
|
damage_mask: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
GetDC :: proc(h: HWND) -> HDC #foreign user32;
|
||||||
|
SetPixelFormat :: proc(hdc: HDC, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR) -> BOOL #foreign gdi32;
|
||||||
|
ChoosePixelFormat :: proc(hdc: HDC, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign gdi32;
|
||||||
|
SwapBuffers :: proc(hdc: HDC) -> BOOL #foreign gdi32;
|
||||||
|
ReleaseDC :: proc(wnd: HWND, hdc: HDC) -> i32 #foreign user32;
|
||||||
|
|
||||||
|
|
||||||
|
PROC :: #type proc() #cc_c;
|
||||||
|
|
||||||
|
|
||||||
|
GetKeyState :: proc(v_key: i32) -> i16 #foreign user32;
|
||||||
|
GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign user32;
|
||||||
|
|
||||||
|
is_key_down :: proc(key: Key_Code) -> bool #inline { return GetAsyncKeyState(cast(i32)key) < 0; }
|
||||||
|
|
||||||
|
Key_Code :: enum i32 {
|
||||||
|
LBUTTON = 0x01,
|
||||||
|
RBUTTON = 0x02,
|
||||||
|
CANCEL = 0x03,
|
||||||
|
MBUTTON = 0x04,
|
||||||
|
BACK = 0x08,
|
||||||
|
TAB = 0x09,
|
||||||
|
CLEAR = 0x0C,
|
||||||
|
RETURN = 0x0D,
|
||||||
|
|
||||||
|
SHIFT = 0x10,
|
||||||
|
CONTROL = 0x11,
|
||||||
|
MENU = 0x12,
|
||||||
|
PAUSE = 0x13,
|
||||||
|
CAPITAL = 0x14,
|
||||||
|
KANA = 0x15,
|
||||||
|
HANGEUL = 0x15,
|
||||||
|
HANGUL = 0x15,
|
||||||
|
JUNJA = 0x17,
|
||||||
|
FINAL = 0x18,
|
||||||
|
HANJA = 0x19,
|
||||||
|
KANJI = 0x19,
|
||||||
|
ESCAPE = 0x1B,
|
||||||
|
CONVERT = 0x1C,
|
||||||
|
NONCONVERT = 0x1D,
|
||||||
|
ACCEPT = 0x1E,
|
||||||
|
MODECHANGE = 0x1F,
|
||||||
|
SPACE = 0x20,
|
||||||
|
PRIOR = 0x21,
|
||||||
|
NEXT = 0x22,
|
||||||
|
END = 0x23,
|
||||||
|
HOME = 0x24,
|
||||||
|
LEFT = 0x25,
|
||||||
|
UP = 0x26,
|
||||||
|
RIGHT = 0x27,
|
||||||
|
DOWN = 0x28,
|
||||||
|
SELECT = 0x29,
|
||||||
|
PRINT = 0x2A,
|
||||||
|
EXECUTE = 0x2B,
|
||||||
|
SNAPSHOT = 0x2C,
|
||||||
|
INSERT = 0x2D,
|
||||||
|
DELETE = 0x2E,
|
||||||
|
HELP = 0x2F,
|
||||||
|
|
||||||
|
NUM0 = '0',
|
||||||
|
NUM1 = '1',
|
||||||
|
NUM2 = '2',
|
||||||
|
NUM3 = '3',
|
||||||
|
NUM4 = '4',
|
||||||
|
NUM5 = '5',
|
||||||
|
NUM6 = '6',
|
||||||
|
NUM7 = '7',
|
||||||
|
NUM8 = '8',
|
||||||
|
NUM9 = '9',
|
||||||
|
A = 'A',
|
||||||
|
B = 'B',
|
||||||
|
C = 'C',
|
||||||
|
D = 'D',
|
||||||
|
E = 'E',
|
||||||
|
F = 'F',
|
||||||
|
G = 'G',
|
||||||
|
H = 'H',
|
||||||
|
I = 'I',
|
||||||
|
J = 'J',
|
||||||
|
K = 'K',
|
||||||
|
L = 'L',
|
||||||
|
M = 'M',
|
||||||
|
N = 'N',
|
||||||
|
O = 'O',
|
||||||
|
P = 'P',
|
||||||
|
Q = 'Q',
|
||||||
|
R = 'R',
|
||||||
|
S = 'S',
|
||||||
|
T = 'T',
|
||||||
|
U = 'U',
|
||||||
|
V = 'V',
|
||||||
|
W = 'W',
|
||||||
|
X = 'X',
|
||||||
|
Y = 'Y',
|
||||||
|
Z = 'Z',
|
||||||
|
|
||||||
|
LWIN = 0x5B,
|
||||||
|
RWIN = 0x5C,
|
||||||
|
APPS = 0x5D,
|
||||||
|
|
||||||
|
NUMPAD0 = 0x60,
|
||||||
|
NUMPAD1 = 0x61,
|
||||||
|
NUMPAD2 = 0x62,
|
||||||
|
NUMPAD3 = 0x63,
|
||||||
|
NUMPAD4 = 0x64,
|
||||||
|
NUMPAD5 = 0x65,
|
||||||
|
NUMPAD6 = 0x66,
|
||||||
|
NUMPAD7 = 0x67,
|
||||||
|
NUMPAD8 = 0x68,
|
||||||
|
NUMPAD9 = 0x69,
|
||||||
|
MULTIPLY = 0x6A,
|
||||||
|
ADD = 0x6B,
|
||||||
|
SEPARATOR = 0x6C,
|
||||||
|
SUBTRACT = 0x6D,
|
||||||
|
DECIMAL = 0x6E,
|
||||||
|
DIVIDE = 0x6F,
|
||||||
|
|
||||||
|
F1 = 0x70,
|
||||||
|
F2 = 0x71,
|
||||||
|
F3 = 0x72,
|
||||||
|
F4 = 0x73,
|
||||||
|
F5 = 0x74,
|
||||||
|
F6 = 0x75,
|
||||||
|
F7 = 0x76,
|
||||||
|
F8 = 0x77,
|
||||||
|
F9 = 0x78,
|
||||||
|
F10 = 0x79,
|
||||||
|
F11 = 0x7A,
|
||||||
|
F12 = 0x7B,
|
||||||
|
F13 = 0x7C,
|
||||||
|
F14 = 0x7D,
|
||||||
|
F15 = 0x7E,
|
||||||
|
F16 = 0x7F,
|
||||||
|
F17 = 0x80,
|
||||||
|
F18 = 0x81,
|
||||||
|
F19 = 0x82,
|
||||||
|
F20 = 0x83,
|
||||||
|
F21 = 0x84,
|
||||||
|
F22 = 0x85,
|
||||||
|
F23 = 0x86,
|
||||||
|
F24 = 0x87,
|
||||||
|
|
||||||
|
NUMLOCK = 0x90,
|
||||||
|
SCROLL = 0x91,
|
||||||
|
LSHIFT = 0xA0,
|
||||||
|
RSHIFT = 0xA1,
|
||||||
|
LCONTROL = 0xA2,
|
||||||
|
RCONTROL = 0xA3,
|
||||||
|
LMENU = 0xA4,
|
||||||
|
RMENU = 0xA5,
|
||||||
|
PROCESSKEY = 0xE5,
|
||||||
|
ATTN = 0xF6,
|
||||||
|
CRSEL = 0xF7,
|
||||||
|
EXSEL = 0xF8,
|
||||||
|
EREOF = 0xF9,
|
||||||
|
PLAY = 0xFA,
|
||||||
|
ZOOM = 0xFB,
|
||||||
|
NONAME = 0xFC,
|
||||||
|
PA1 = 0xFD,
|
||||||
|
OEM_CLEAR = 0xFE,
|
||||||
|
}
|
||||||
|
|
||||||
+146
@@ -0,0 +1,146 @@
|
|||||||
|
is_signed :: proc(info: ^Type_Info) -> bool {
|
||||||
|
if is_integer(info) {
|
||||||
|
i := union_cast(^Type_Info.Integer)info;
|
||||||
|
return i.signed;
|
||||||
|
}
|
||||||
|
if is_float(info) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
is_integer :: proc(info: ^Type_Info) -> bool {
|
||||||
|
if info == nil { return false; }
|
||||||
|
|
||||||
|
match i in type_info_base(info) {
|
||||||
|
case Type_Info.Integer: return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
is_float :: proc(info: ^Type_Info) -> bool {
|
||||||
|
if info == nil { return false; }
|
||||||
|
|
||||||
|
match i in type_info_base(info) {
|
||||||
|
case Type_Info.Float: return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
is_any :: proc(info: ^Type_Info) -> bool {
|
||||||
|
if info == nil { return false; }
|
||||||
|
|
||||||
|
match i in type_info_base(info) {
|
||||||
|
case Type_Info.Any: return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
is_string :: proc(info: ^Type_Info) -> bool {
|
||||||
|
if info == nil { return false; }
|
||||||
|
|
||||||
|
match i in type_info_base(info) {
|
||||||
|
case Type_Info.String: return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
is_boolean :: proc(info: ^Type_Info) -> bool {
|
||||||
|
if info == nil { return false; }
|
||||||
|
|
||||||
|
match i in type_info_base(info) {
|
||||||
|
case Type_Info.Boolean: return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
is_pointer :: proc(info: ^Type_Info) -> bool {
|
||||||
|
if info == nil { return false; }
|
||||||
|
|
||||||
|
match i in type_info_base(info) {
|
||||||
|
case Type_Info.Pointer: return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
is_procedure :: proc(info: ^Type_Info) -> bool {
|
||||||
|
if info == nil { return false; }
|
||||||
|
|
||||||
|
match i in type_info_base(info) {
|
||||||
|
case Type_Info.Procedure: return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
is_array :: proc(info: ^Type_Info) -> bool {
|
||||||
|
if info == nil { return false; }
|
||||||
|
|
||||||
|
match i in type_info_base(info) {
|
||||||
|
case Type_Info.Array: return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
is_dynamic_array :: proc(info: ^Type_Info) -> bool {
|
||||||
|
if info == nil { return false; }
|
||||||
|
|
||||||
|
match i in type_info_base(info) {
|
||||||
|
case Type_Info.Dynamic_Array: return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
is_dynamic_map :: proc(info: ^Type_Info) -> bool {
|
||||||
|
if info == nil { return false; }
|
||||||
|
|
||||||
|
match i in type_info_base(info) {
|
||||||
|
case Type_Info.Map: return i.count == 0;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
is_slice :: proc(info: ^Type_Info) -> bool {
|
||||||
|
if info == nil { return false; }
|
||||||
|
|
||||||
|
match i in type_info_base(info) {
|
||||||
|
case Type_Info.Slice: return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
is_vector :: proc(info: ^Type_Info) -> bool {
|
||||||
|
if info == nil { return false; }
|
||||||
|
|
||||||
|
match i in type_info_base(info) {
|
||||||
|
case Type_Info.Vector: return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
is_tuple :: proc(info: ^Type_Info) -> bool {
|
||||||
|
if info == nil { return false; }
|
||||||
|
|
||||||
|
match i in type_info_base(info) {
|
||||||
|
case Type_Info.Tuple: return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
is_struct :: proc(info: ^Type_Info) -> bool {
|
||||||
|
if info == nil { return false; }
|
||||||
|
|
||||||
|
match i in type_info_base(info) {
|
||||||
|
case Type_Info.Struct: return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
is_union :: proc(info: ^Type_Info) -> bool {
|
||||||
|
if info == nil { return false; }
|
||||||
|
|
||||||
|
match i in type_info_base(info) {
|
||||||
|
case Type_Info.Union: return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
is_raw_union :: proc(info: ^Type_Info) -> bool {
|
||||||
|
if info == nil { return false; }
|
||||||
|
|
||||||
|
match i in type_info_base(info) {
|
||||||
|
case Type_Info.Raw_Union: return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
is_enum :: proc(info: ^Type_Info) -> bool {
|
||||||
|
if info == nil { return false; }
|
||||||
|
|
||||||
|
match i in type_info_base(info) {
|
||||||
|
case Type_Info.Enum: return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
+166
-112
@@ -1,28 +1,44 @@
|
|||||||
RUNE_ERROR :: '\ufffd'
|
RUNE_ERROR :: '\ufffd';
|
||||||
RUNE_SELF :: 0x80
|
RUNE_SELF :: 0x80;
|
||||||
RUNE_BOM :: 0xfeff
|
RUNE_BOM :: 0xfeff;
|
||||||
RUNE_EOF :: ~(0 as rune)
|
RUNE_EOF :: ~cast(rune)0;
|
||||||
MAX_RUNE :: '\U0010ffff'
|
MAX_RUNE :: '\U0010ffff';
|
||||||
UTF_MAX :: 4
|
UTF_MAX :: 4;
|
||||||
|
|
||||||
|
SURROGATE_MIN :: 0xd800;
|
||||||
|
SURROGATE_MAX :: 0xdfff;
|
||||||
|
|
||||||
SURROGATE_MIN :: 0xd800
|
T1 :: 0b0000_0000;
|
||||||
SURROGATE_MAX :: 0xdfff
|
TX :: 0b1000_0000;
|
||||||
|
T2 :: 0b1100_0000;
|
||||||
|
T3 :: 0b1110_0000;
|
||||||
|
T4 :: 0b1111_0000;
|
||||||
|
T5 :: 0b1111_1000;
|
||||||
|
|
||||||
|
MASKX :: 0b0011_1111;
|
||||||
|
MASK2 :: 0b0001_1111;
|
||||||
|
MASK3 :: 0b0000_1111;
|
||||||
|
MASK4 :: 0b0000_0111;
|
||||||
|
|
||||||
Accept_Range :: struct {
|
RUNE1_MAX :: 1<<7 - 1;
|
||||||
lo, hi: u8
|
RUNE2_MAX :: 1<<11 - 1;
|
||||||
}
|
RUNE3_MAX :: 1<<16 - 1;
|
||||||
|
|
||||||
accept_ranges := [5]Accept_Range{
|
// The default lowest and highest continuation byte.
|
||||||
|
LOCB :: 0b1000_0000;
|
||||||
|
HICB :: 0b1011_1111;
|
||||||
|
|
||||||
|
Accept_Range :: struct { lo, hi: u8 }
|
||||||
|
|
||||||
|
immutable accept_ranges := [5]Accept_Range{
|
||||||
{0x80, 0xbf},
|
{0x80, 0xbf},
|
||||||
{0xa0, 0xbf},
|
{0xa0, 0xbf},
|
||||||
{0x80, 0x9f},
|
{0x80, 0x9f},
|
||||||
{0x90, 0xbf},
|
{0x90, 0xbf},
|
||||||
{0x80, 0x8f},
|
{0x80, 0x8f},
|
||||||
}
|
};
|
||||||
|
|
||||||
accept_sizes := [256]byte{
|
immutable accept_sizes := [256]byte{
|
||||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f
|
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f
|
||||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1f
|
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1f
|
||||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f
|
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f
|
||||||
@@ -40,177 +56,215 @@ accept_sizes := [256]byte{
|
|||||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xd0-0xdf
|
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xd0-0xdf
|
||||||
0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, // 0xe0-0xef
|
0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, // 0xe0-0xef
|
||||||
0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xf0-0xff
|
0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xf0-0xff
|
||||||
}
|
};
|
||||||
|
|
||||||
encode_rune :: proc(r_: rune) -> ([4]byte, int) {
|
encode_rune :: proc(r: rune) -> ([4]byte, int) {
|
||||||
r := r_
|
buf: [4]byte;
|
||||||
buf: [4]byte
|
i := cast(u32)r;
|
||||||
i := r as u32
|
mask: byte : 0x3f;
|
||||||
mask: byte : 0x3f
|
|
||||||
if i <= 1<<7-1 {
|
if i <= 1<<7-1 {
|
||||||
buf[0] = r as byte
|
buf[0] = cast(byte)r;
|
||||||
return buf, 1
|
return buf, 1;
|
||||||
}
|
}
|
||||||
if i <= 1<<11-1 {
|
if i <= 1<<11-1 {
|
||||||
buf[0] = 0xc0 | (r>>6) as byte
|
buf[0] = 0xc0 | cast(byte)(r>>6);
|
||||||
buf[1] = 0x80 | (r) as byte & mask
|
buf[1] = 0x80 | cast(byte)r & mask;
|
||||||
return buf, 2
|
return buf, 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invalid or Surrogate range
|
// Invalid or Surrogate range
|
||||||
if i > 0x0010ffff ||
|
if i > 0x0010ffff ||
|
||||||
(0xd800 <= i && i <= 0xdfff) {
|
(0xd800 <= i && i <= 0xdfff) {
|
||||||
r = 0xfffd
|
r = 0xfffd;
|
||||||
}
|
}
|
||||||
|
|
||||||
if i <= 1<<16-1 {
|
if i <= 1<<16-1 {
|
||||||
buf[0] = 0xe0 | (r>>12) as byte
|
buf[0] = 0xe0 | cast(byte)(r>>12);
|
||||||
buf[1] = 0x80 | (r>>6) as byte & mask
|
buf[1] = 0x80 | cast(byte)(r>>6) & mask;
|
||||||
buf[2] = 0x80 | (r) as byte & mask
|
buf[2] = 0x80 | cast(byte)r & mask;
|
||||||
return buf, 3
|
return buf, 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf[0] = 0xf0 | (r>>18) as byte
|
buf[0] = 0xf0 | cast(byte)(r>>18);
|
||||||
buf[1] = 0x80 | (r>>12) as byte & mask
|
buf[1] = 0x80 | cast(byte)(r>>12) & mask;
|
||||||
buf[2] = 0x80 | (r>>6) as byte & mask
|
buf[2] = 0x80 | cast(byte)(r>>6) & mask;
|
||||||
buf[3] = 0x80 | (r) as byte & mask
|
buf[3] = 0x80 | cast(byte)r & mask;
|
||||||
return buf, 4
|
return buf, 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
decode_rune :: proc(s: string) -> (rune, int) {
|
decode_rune :: proc(s: string) -> (rune, int) #inline { return decode_rune(cast([]byte)s); }
|
||||||
n := s.count
|
decode_rune :: proc(s: []byte) -> (rune, int) {
|
||||||
|
n := s.count;
|
||||||
if n < 1 {
|
if n < 1 {
|
||||||
return RUNE_ERROR, 0
|
return RUNE_ERROR, 0;
|
||||||
}
|
}
|
||||||
b0 := s[0]
|
s0 := s[0];
|
||||||
x := accept_sizes[b0]
|
x := accept_sizes[s0];
|
||||||
if x >= 0xf0 {
|
if x >= 0xF0 {
|
||||||
mask := (x as rune << 31) >> 31 // all zeros or all ones
|
mask := cast(rune)(x) << 31 >> 31; // NOTE(bill): Create 0x0000 or 0xffff.
|
||||||
return (b0 as rune) &~ mask | RUNE_ERROR&mask, 1
|
return cast(rune)(s[0])&~mask | RUNE_ERROR&mask, 1;
|
||||||
}
|
}
|
||||||
size := x & 7
|
sz := x & 7;
|
||||||
ar := accept_ranges[x>>4]
|
accept := accept_ranges[x>>4];
|
||||||
if n < size as int {
|
if n < cast(int)sz {
|
||||||
return RUNE_ERROR, 1
|
return RUNE_ERROR, 1;
|
||||||
}
|
}
|
||||||
b1 := s[1]
|
b1 := s[1];
|
||||||
if b1 < ar.lo || ar.hi < b1 {
|
if b1 < accept.lo || accept.hi < b1 {
|
||||||
return RUNE_ERROR, 1
|
return RUNE_ERROR, 1;
|
||||||
}
|
}
|
||||||
|
if sz == 2 {
|
||||||
MASK_X :: 0b00111111
|
return cast(rune)(s0&MASK2)<<6 | cast(rune)(b1&MASKX), 2;
|
||||||
MASK_2 :: 0b00011111
|
|
||||||
MASK_3 :: 0b00001111
|
|
||||||
MASK_4 :: 0b00000111
|
|
||||||
|
|
||||||
if size == 2 {
|
|
||||||
return (b0&MASK_2) as rune <<6 | (b1&MASK_X) as rune, 2
|
|
||||||
}
|
}
|
||||||
b2 := s[2]
|
b2 := s[2];
|
||||||
if b2 < 0x80 || 0xbf < b2 {
|
if b2 < LOCB || HICB < b2 {
|
||||||
return RUNE_ERROR, 1
|
return RUNE_ERROR, 1;
|
||||||
}
|
}
|
||||||
if size == 3 {
|
if sz == 3 {
|
||||||
return (b0&MASK_3) as rune <<12 | (b1&MASK_X) as rune <<6 | (b2&MASK_X) as rune, 3
|
return cast(rune)(s0&MASK3)<<12 | cast(rune)(b1&MASKX)<<6 | cast(rune)(b2&MASKX), 3;
|
||||||
}
|
}
|
||||||
b3 := s[3]
|
b3 := s[3];
|
||||||
if b3 < 0x80 || 0xbf < b3 {
|
if b3 < LOCB || HICB < b3 {
|
||||||
return RUNE_ERROR, 1
|
return RUNE_ERROR, 1;
|
||||||
}
|
}
|
||||||
return (b0&MASK_4) as rune <<18 | (b1&MASK_X) as rune <<12 | (b3&MASK_X) as rune <<6 | (b3&MASK_X) as rune, 4
|
return cast(rune)(s0&MASK4)<<18 | cast(rune)(b1&MASKX)<<12 | cast(rune)(b2&MASKX)<<6 | cast(rune)(b3&MASKX), 4;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
decode_last_rune :: proc(s: string) -> (rune, int) #inline { return decode_last_rune(cast([]byte)s); }
|
||||||
|
decode_last_rune :: proc(s: []byte) -> (rune, int) {
|
||||||
|
r: rune;
|
||||||
|
size: int;
|
||||||
|
start, end, limit: int;
|
||||||
|
|
||||||
|
end = s.count;
|
||||||
|
if end == 0 {
|
||||||
|
return RUNE_ERROR, 0;
|
||||||
|
}
|
||||||
|
start = end-1;
|
||||||
|
r = cast(rune)s[start];
|
||||||
|
if r < RUNE_SELF {
|
||||||
|
return r, 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
limit = max(end - UTF_MAX, 0);
|
||||||
|
|
||||||
|
start--;
|
||||||
|
for start >= limit {
|
||||||
|
if rune_start(s[start]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
start--;
|
||||||
|
}
|
||||||
|
|
||||||
|
start = max(start, 0);
|
||||||
|
r, size = decode_rune(s[start..end]);
|
||||||
|
if start+size != end {
|
||||||
|
return RUNE_ERROR, 1;
|
||||||
|
}
|
||||||
|
return r, size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
valid_rune :: proc(r: rune) -> bool {
|
valid_rune :: proc(r: rune) -> bool {
|
||||||
if r < 0 {
|
if r < 0 {
|
||||||
return false
|
return false;
|
||||||
} else if SURROGATE_MIN <= r && r <= SURROGATE_MAX {
|
} else if SURROGATE_MIN <= r && r <= SURROGATE_MAX {
|
||||||
return false
|
return false;
|
||||||
} else if r > MAX_RUNE {
|
} else if r > MAX_RUNE {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
valid_string :: proc(s: string) -> bool {
|
valid_string :: proc(s: string) -> bool {
|
||||||
n := s.count
|
n := s.count;
|
||||||
for i := 0; i < n; {
|
for i := 0; i < n; {
|
||||||
si := s[i]
|
si := s[i];
|
||||||
if si < RUNE_SELF { // ascii
|
if si < RUNE_SELF { // ascii
|
||||||
i++
|
i++;
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
x := accept_sizes[si]
|
x := accept_sizes[si];
|
||||||
if x == 0xf1 {
|
if x == 0xf1 {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
size := (x & 7) as int
|
size := cast(int)(x & 7);
|
||||||
if i+size > n {
|
if i+size > n {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
ar := accept_ranges[x>>4]
|
ar := accept_ranges[x>>4];
|
||||||
if b := s[i+1]; b < ar.lo || ar.hi < b {
|
if b := s[i+1]; b < ar.lo || ar.hi < b {
|
||||||
return false
|
return false;
|
||||||
} else if size == 2 {
|
} else if size == 2 {
|
||||||
// Okay
|
// Okay
|
||||||
} else if b := s[i+2]; b < 0x80 || 0xbf < b {
|
} else if b := s[i+2]; b < 0x80 || 0xbf < b {
|
||||||
return false
|
return false;
|
||||||
} else if size == 3 {
|
} else if size == 3 {
|
||||||
// Okay
|
// Okay
|
||||||
} else if b := s[i+3]; b < 0x80 || 0xbf < b {
|
} else if b := s[i+3]; b < 0x80 || 0xbf < b {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
i += size
|
i += size;
|
||||||
}
|
}
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
rune_count :: proc(s: string) -> int {
|
rune_start :: proc(b: byte) -> bool #inline { return b&0xc0 != 0x80; }
|
||||||
count := 0
|
|
||||||
n := s.count
|
rune_count :: proc(s: string) -> int #inline { return rune_count(cast([]byte)s); }
|
||||||
for i := 0; i < n; count++ {
|
rune_count :: proc(s: []byte) -> int {
|
||||||
si := s[i]
|
count := 0;
|
||||||
|
n := s.count;
|
||||||
|
|
||||||
|
for i := 0; i < n; {
|
||||||
|
defer count++;
|
||||||
|
si := s[i];
|
||||||
if si < RUNE_SELF { // ascii
|
if si < RUNE_SELF { // ascii
|
||||||
i++
|
i++;
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
x := accept_sizes[si]
|
x := accept_sizes[si];
|
||||||
if x == 0xf1 {
|
if x == 0xf1 {
|
||||||
i++
|
i++;
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
size := (x & 7) as int
|
size := cast(int)(x & 7);
|
||||||
if i+size > n {
|
if i+size > n {
|
||||||
i++
|
i++;
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
ar := accept_ranges[x>>4]
|
ar := accept_ranges[x>>4];
|
||||||
if b := s[i+1]; b < ar.lo || ar.hi < b {
|
if b := s[i+1]; b < ar.lo || ar.hi < b {
|
||||||
size = 1
|
size = 1;
|
||||||
} else if size == 2 {
|
} else if size == 2 {
|
||||||
// Okay
|
// Okay
|
||||||
} else if b := s[i+2]; b < 0x80 || 0xbf < b {
|
} else if b := s[i+2]; b < 0x80 || 0xbf < b {
|
||||||
size = 1
|
size = 1;
|
||||||
} else if size == 3 {
|
} else if size == 3 {
|
||||||
// Okay
|
// Okay
|
||||||
} else if b := s[i+3]; b < 0x80 || 0xbf < b {
|
} else if b := s[i+3]; b < 0x80 || 0xbf < b {
|
||||||
size = 1
|
size = 1;
|
||||||
}
|
}
|
||||||
i += size
|
i += size;
|
||||||
}
|
}
|
||||||
return count
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
rune_size :: proc(r: rune) -> int {
|
rune_size :: proc(r: rune) -> int {
|
||||||
match {
|
match {
|
||||||
case r < 0: return -1
|
case r < 0: return -1;
|
||||||
case r <= 1<<7 - 1: return 1
|
case r <= 1<<7 - 1: return 1;
|
||||||
case r <= 1<<11 - 1: return 2
|
case r <= 1<<11 - 1: return 2;
|
||||||
case SURROGATE_MIN <= r && r <= SURROGATE_MAX: return -1
|
case SURROGATE_MIN <= r && r <= SURROGATE_MAX: return -1;
|
||||||
case r <= 1<<16 - 1: return 3
|
case r <= 1<<16 - 1: return 3;
|
||||||
case r <= MAX_RUNE: return 4
|
case r <= MAX_RUNE: return 4;
|
||||||
}
|
}
|
||||||
return -1
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
-495
@@ -1,495 +0,0 @@
|
|||||||
#foreign_system_library "user32"
|
|
||||||
#foreign_system_library "gdi32"
|
|
||||||
|
|
||||||
_:= compile_assert(ODIN_OS == "windows")
|
|
||||||
|
|
||||||
HANDLE :: type rawptr
|
|
||||||
HWND :: type HANDLE
|
|
||||||
HDC :: type HANDLE
|
|
||||||
HINSTANCE :: type HANDLE
|
|
||||||
HICON :: type HANDLE
|
|
||||||
HCURSOR :: type HANDLE
|
|
||||||
HMENU :: type HANDLE
|
|
||||||
HBRUSH :: type HANDLE
|
|
||||||
HGDIOBJ :: type HANDLE
|
|
||||||
HMODULE :: type HANDLE
|
|
||||||
WPARAM :: type uint
|
|
||||||
LPARAM :: type int
|
|
||||||
LRESULT :: type int
|
|
||||||
ATOM :: type i16
|
|
||||||
BOOL :: type i32
|
|
||||||
WNDPROC :: type proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT
|
|
||||||
|
|
||||||
INVALID_HANDLE_VALUE :: (-1 as int) as HANDLE
|
|
||||||
|
|
||||||
CS_VREDRAW :: 0x0001
|
|
||||||
CS_HREDRAW :: 0x0002
|
|
||||||
CS_OWNDC :: 0x0020
|
|
||||||
CW_USEDEFAULT :: -0x80000000
|
|
||||||
|
|
||||||
WS_OVERLAPPED :: 0
|
|
||||||
WS_MAXIMIZEBOX :: 0x00010000
|
|
||||||
WS_MINIMIZEBOX :: 0x00020000
|
|
||||||
WS_THICKFRAME :: 0x00040000
|
|
||||||
WS_SYSMENU :: 0x00080000
|
|
||||||
WS_CAPTION :: 0x00C00000
|
|
||||||
WS_VISIBLE :: 0x10000000
|
|
||||||
WS_OVERLAPPEDWINDOW :: WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX
|
|
||||||
|
|
||||||
WM_DESTROY :: 0x0002
|
|
||||||
WM_CLOSE :: 0x0010
|
|
||||||
WM_QUIT :: 0x0012
|
|
||||||
WM_KEYDOWN :: 0x0100
|
|
||||||
WM_KEYUP :: 0x0101
|
|
||||||
|
|
||||||
PM_REMOVE :: 1
|
|
||||||
|
|
||||||
COLOR_BACKGROUND :: 1 as HBRUSH
|
|
||||||
BLACK_BRUSH :: 4
|
|
||||||
|
|
||||||
SM_CXSCREEN :: 0
|
|
||||||
SM_CYSCREEN :: 1
|
|
||||||
|
|
||||||
SW_SHOW :: 5
|
|
||||||
|
|
||||||
POINT :: struct #ordered {
|
|
||||||
x, y: i32
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
WNDCLASSEXA :: struct #ordered {
|
|
||||||
size, style: u32
|
|
||||||
wnd_proc: WNDPROC
|
|
||||||
cls_extra, wnd_extra: i32
|
|
||||||
instance: HINSTANCE
|
|
||||||
icon: HICON
|
|
||||||
cursor: HCURSOR
|
|
||||||
background: HBRUSH
|
|
||||||
menu_name, class_name: ^u8
|
|
||||||
sm: HICON
|
|
||||||
}
|
|
||||||
|
|
||||||
MSG :: struct #ordered {
|
|
||||||
hwnd: HWND
|
|
||||||
message: u32
|
|
||||||
wparam: WPARAM
|
|
||||||
lparam: LPARAM
|
|
||||||
time: u32
|
|
||||||
pt: POINT
|
|
||||||
}
|
|
||||||
|
|
||||||
RECT :: struct #ordered {
|
|
||||||
left: i32
|
|
||||||
top: i32
|
|
||||||
right: i32
|
|
||||||
bottom: i32
|
|
||||||
}
|
|
||||||
|
|
||||||
FILETIME :: struct #ordered {
|
|
||||||
low_date_time, high_date_time: u32
|
|
||||||
}
|
|
||||||
|
|
||||||
BY_HANDLE_FILE_INFORMATION :: struct #ordered {
|
|
||||||
file_attributes: u32
|
|
||||||
creation_time,
|
|
||||||
last_access_time,
|
|
||||||
last_write_time: FILETIME
|
|
||||||
volume_serial_number,
|
|
||||||
file_size_high,
|
|
||||||
file_size_low,
|
|
||||||
number_of_links,
|
|
||||||
file_index_high,
|
|
||||||
file_index_low: u32
|
|
||||||
}
|
|
||||||
|
|
||||||
WIN32_FILE_ATTRIBUTE_DATA :: struct #ordered {
|
|
||||||
file_attributes: u32
|
|
||||||
creation_time,
|
|
||||||
last_access_time,
|
|
||||||
last_write_time: FILETIME
|
|
||||||
file_size_high,
|
|
||||||
file_size_low: u32
|
|
||||||
}
|
|
||||||
|
|
||||||
GET_FILEEX_INFO_LEVELS :: type i32
|
|
||||||
GetFileExInfoStandard : GET_FILEEX_INFO_LEVELS : 0
|
|
||||||
GetFileExMaxInfoLevel : GET_FILEEX_INFO_LEVELS : 1
|
|
||||||
|
|
||||||
GetLastError :: proc() -> i32 #foreign #dll_import
|
|
||||||
ExitProcess :: proc(exit_code: u32) #foreign #dll_import
|
|
||||||
GetDesktopWindow :: proc() -> HWND #foreign #dll_import
|
|
||||||
GetCursorPos :: proc(p: ^POINT) -> i32 #foreign #dll_import
|
|
||||||
ScreenToClient :: proc(h: HWND, p: ^POINT) -> i32 #foreign #dll_import
|
|
||||||
GetModuleHandleA :: proc(module_name: ^u8) -> HINSTANCE #foreign #dll_import
|
|
||||||
GetStockObject :: proc(fn_object: i32) -> HGDIOBJ #foreign #dll_import
|
|
||||||
PostQuitMessage :: proc(exit_code: i32) #foreign #dll_import
|
|
||||||
SetWindowTextA :: proc(hwnd: HWND, c_string: ^u8) -> BOOL #foreign #dll_import
|
|
||||||
|
|
||||||
QueryPerformanceFrequency :: proc(result: ^i64) -> i32 #foreign #dll_import
|
|
||||||
QueryPerformanceCounter :: proc(result: ^i64) -> i32 #foreign #dll_import
|
|
||||||
|
|
||||||
Sleep :: proc(ms: i32) -> i32 #foreign #dll_import
|
|
||||||
|
|
||||||
OutputDebugStringA :: proc(c_str: ^u8) #foreign #dll_import
|
|
||||||
|
|
||||||
|
|
||||||
RegisterClassExA :: proc(wc: ^WNDCLASSEXA) -> ATOM #foreign #dll_import
|
|
||||||
CreateWindowExA :: proc(ex_style: u32,
|
|
||||||
class_name, title: ^u8,
|
|
||||||
style: u32,
|
|
||||||
x, y, w, h: i32,
|
|
||||||
parent: HWND, menu: HMENU, instance: HINSTANCE,
|
|
||||||
param: rawptr) -> HWND #foreign #dll_import
|
|
||||||
|
|
||||||
ShowWindow :: proc(hwnd: HWND, cmd_show: i32) -> BOOL #foreign #dll_import
|
|
||||||
TranslateMessage :: proc(msg: ^MSG) -> BOOL #foreign #dll_import
|
|
||||||
DispatchMessageA :: proc(msg: ^MSG) -> LRESULT #foreign #dll_import
|
|
||||||
UpdateWindow :: proc(hwnd: HWND) -> BOOL #foreign #dll_import
|
|
||||||
PeekMessageA :: proc(msg: ^MSG, hwnd: HWND,
|
|
||||||
msg_filter_min, msg_filter_max, remove_msg: u32) -> BOOL #foreign #dll_import
|
|
||||||
|
|
||||||
DefWindowProcA :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #foreign #dll_import
|
|
||||||
|
|
||||||
AdjustWindowRect :: proc(rect: ^RECT, style: u32, menu: BOOL) -> BOOL #foreign #dll_import
|
|
||||||
|
|
||||||
|
|
||||||
GetQueryPerformanceFrequency :: proc() -> i64 {
|
|
||||||
r: i64
|
|
||||||
QueryPerformanceFrequency(^r)
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
GetCommandLineA :: proc() -> ^u8 #foreign #dll_import
|
|
||||||
GetSystemMetrics :: proc(index: i32) -> i32 #foreign #dll_import
|
|
||||||
GetCurrentThreadId :: proc() -> u32 #foreign #dll_import
|
|
||||||
|
|
||||||
// File Stuff
|
|
||||||
|
|
||||||
CloseHandle :: proc(h: HANDLE) -> i32 #foreign #dll_import
|
|
||||||
GetStdHandle :: proc(h: i32) -> HANDLE #foreign #dll_import
|
|
||||||
CreateFileA :: proc(filename: ^u8, desired_access, share_mode: u32,
|
|
||||||
security: rawptr,
|
|
||||||
creation, flags_and_attribs: u32, template_file: HANDLE) -> HANDLE #foreign #dll_import
|
|
||||||
ReadFile :: proc(h: HANDLE, buf: rawptr, to_read: u32, bytes_read: ^i32, overlapped: rawptr) -> BOOL #foreign #dll_import
|
|
||||||
WriteFile :: proc(h: HANDLE, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> i32 #foreign #dll_import
|
|
||||||
|
|
||||||
GetFileSizeEx :: proc(file_handle: HANDLE, file_size: ^i64) -> BOOL #foreign #dll_import
|
|
||||||
GetFileAttributesExA :: proc(filename: ^u8, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: rawptr) -> BOOL #foreign #dll_import
|
|
||||||
GetFileInformationByHandle :: proc(file_handle: HANDLE, file_info: ^BY_HANDLE_FILE_INFORMATION) -> BOOL #foreign #dll_import
|
|
||||||
|
|
||||||
FILE_SHARE_READ :: 0x00000001
|
|
||||||
FILE_SHARE_WRITE :: 0x00000002
|
|
||||||
FILE_SHARE_DELETE :: 0x00000004
|
|
||||||
FILE_GENERIC_ALL :: 0x10000000
|
|
||||||
FILE_GENERIC_EXECUTE :: 0x20000000
|
|
||||||
FILE_GENERIC_WRITE :: 0x40000000
|
|
||||||
FILE_GENERIC_READ :: 0x80000000
|
|
||||||
|
|
||||||
STD_INPUT_HANDLE :: -10
|
|
||||||
STD_OUTPUT_HANDLE :: -11
|
|
||||||
STD_ERROR_HANDLE :: -12
|
|
||||||
|
|
||||||
CREATE_NEW :: 1
|
|
||||||
CREATE_ALWAYS :: 2
|
|
||||||
OPEN_EXISTING :: 3
|
|
||||||
OPEN_ALWAYS :: 4
|
|
||||||
TRUNCATE_EXISTING :: 5
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
HeapAlloc :: proc(h: HANDLE, flags: u32, bytes: int) -> rawptr #foreign #dll_import
|
|
||||||
HeapReAlloc :: proc(h: HANDLE, flags: u32, memory: rawptr, bytes: int) -> rawptr #foreign #dll_import
|
|
||||||
HeapFree :: proc(h: HANDLE, flags: u32, memory: rawptr) -> BOOL #foreign #dll_import
|
|
||||||
GetProcessHeap :: proc() -> HANDLE #foreign #dll_import
|
|
||||||
|
|
||||||
|
|
||||||
HEAP_ZERO_MEMORY :: 0x00000008
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// GDI
|
|
||||||
|
|
||||||
BITMAPINFO :: struct #ordered {
|
|
||||||
HEADER :: struct #ordered {
|
|
||||||
size: u32
|
|
||||||
width, height: i32
|
|
||||||
planes, bit_count: i16
|
|
||||||
compression: u32
|
|
||||||
size_image: u32
|
|
||||||
x_pels_per_meter: i32
|
|
||||||
y_pels_per_meter: i32
|
|
||||||
clr_used: u32
|
|
||||||
clr_important: u32
|
|
||||||
}
|
|
||||||
using header: HEADER
|
|
||||||
colors: [1]RGBQUAD
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
RGBQUAD :: struct #ordered {
|
|
||||||
blue, green, red, reserved: byte
|
|
||||||
}
|
|
||||||
|
|
||||||
BI_RGB :: 0
|
|
||||||
DIB_RGB_COLORS :: 0x00
|
|
||||||
SRCCOPY : u32 : 0x00cc0020
|
|
||||||
|
|
||||||
StretchDIBits :: proc(hdc: HDC,
|
|
||||||
x_dst, y_dst, width_dst, height_dst: i32,
|
|
||||||
x_src, y_src, width_src, header_src: i32,
|
|
||||||
bits: rawptr, bits_info: ^BITMAPINFO,
|
|
||||||
usage: u32,
|
|
||||||
rop: u32) -> i32 #foreign #dll_import
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
LoadLibraryA :: proc(c_str: ^u8) -> HMODULE #foreign
|
|
||||||
FreeLibrary :: proc(h: HMODULE) #foreign
|
|
||||||
GetProcAddress :: proc(h: HMODULE, c_str: ^u8) -> proc() #foreign
|
|
||||||
|
|
||||||
GetClientRect :: proc(hwnd: HWND, rect: ^RECT) -> BOOL #foreign
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Windows OpenGL
|
|
||||||
|
|
||||||
PFD_TYPE_RGBA :: 0
|
|
||||||
PFD_TYPE_COLORINDEX :: 1
|
|
||||||
PFD_MAIN_PLANE :: 0
|
|
||||||
PFD_OVERLAY_PLANE :: 1
|
|
||||||
PFD_UNDERLAY_PLANE :: -1
|
|
||||||
PFD_DOUBLEBUFFER :: 1
|
|
||||||
PFD_STEREO :: 2
|
|
||||||
PFD_DRAW_TO_WINDOW :: 4
|
|
||||||
PFD_DRAW_TO_BITMAP :: 8
|
|
||||||
PFD_SUPPORT_GDI :: 16
|
|
||||||
PFD_SUPPORT_OPENGL :: 32
|
|
||||||
PFD_GENERIC_FORMAT :: 64
|
|
||||||
PFD_NEED_PALETTE :: 128
|
|
||||||
PFD_NEED_SYSTEM_PALETTE :: 0x00000100
|
|
||||||
PFD_SWAP_EXCHANGE :: 0x00000200
|
|
||||||
PFD_SWAP_COPY :: 0x00000400
|
|
||||||
PFD_SWAP_LAYER_BUFFERS :: 0x00000800
|
|
||||||
PFD_GENERIC_ACCELERATED :: 0x00001000
|
|
||||||
PFD_DEPTH_DONTCARE :: 0x20000000
|
|
||||||
PFD_DOUBLEBUFFER_DONTCARE :: 0x40000000
|
|
||||||
PFD_STEREO_DONTCARE :: 0x80000000
|
|
||||||
|
|
||||||
HGLRC :: type HANDLE
|
|
||||||
PROC :: type proc()
|
|
||||||
wglCreateContextAttribsARBType :: type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC
|
|
||||||
|
|
||||||
|
|
||||||
PIXELFORMATDESCRIPTOR :: struct #ordered {
|
|
||||||
size,
|
|
||||||
version,
|
|
||||||
flags: u32
|
|
||||||
|
|
||||||
pixel_type,
|
|
||||||
color_bits,
|
|
||||||
red_bits,
|
|
||||||
red_shift,
|
|
||||||
green_bits,
|
|
||||||
green_shift,
|
|
||||||
blue_bits,
|
|
||||||
blue_shift,
|
|
||||||
alpha_bits,
|
|
||||||
alpha_shift,
|
|
||||||
accum_bits,
|
|
||||||
accum_red_bits,
|
|
||||||
accum_green_bits,
|
|
||||||
accum_blue_bits,
|
|
||||||
accum_alpha_bits,
|
|
||||||
depth_bits,
|
|
||||||
stencil_bits,
|
|
||||||
aux_buffers,
|
|
||||||
layer_type,
|
|
||||||
reserved: byte
|
|
||||||
|
|
||||||
layer_mask,
|
|
||||||
visible_mask,
|
|
||||||
damage_mask: u32
|
|
||||||
}
|
|
||||||
|
|
||||||
GetDC :: proc(h: HANDLE) -> HDC #foreign
|
|
||||||
SetPixelFormat :: proc(hdc: HDC, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR ) -> BOOL #foreign #dll_import
|
|
||||||
ChoosePixelFormat :: proc(hdc: HDC, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign #dll_import
|
|
||||||
SwapBuffers :: proc(hdc: HDC) -> BOOL #foreign #dll_import
|
|
||||||
ReleaseDC :: proc(wnd: HWND, hdc: HDC) -> i32 #foreign #dll_import
|
|
||||||
|
|
||||||
WGL_CONTEXT_MAJOR_VERSION_ARB :: 0x2091
|
|
||||||
WGL_CONTEXT_MINOR_VERSION_ARB :: 0x2092
|
|
||||||
WGL_CONTEXT_PROFILE_MASK_ARB :: 0x9126
|
|
||||||
WGL_CONTEXT_CORE_PROFILE_BIT_ARB :: 0x0001
|
|
||||||
WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x0002
|
|
||||||
|
|
||||||
wglCreateContext :: proc(hdc: HDC) -> HGLRC #foreign #dll_import
|
|
||||||
wglMakeCurrent :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign #dll_import
|
|
||||||
wglGetProcAddress :: proc(c_str: ^u8) -> PROC #foreign #dll_import
|
|
||||||
wglDeleteContext :: proc(hglrc: HGLRC) -> BOOL #foreign #dll_import
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GetKeyState :: proc(v_key: i32) -> i16 #foreign #dll_import
|
|
||||||
GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign #dll_import
|
|
||||||
|
|
||||||
is_key_down :: proc(key: Key_Code) -> bool {
|
|
||||||
return GetAsyncKeyState(key as i32) < 0
|
|
||||||
}
|
|
||||||
|
|
||||||
Key_Code :: enum i32 {
|
|
||||||
LBUTTON = 0x01,
|
|
||||||
RBUTTON = 0x02,
|
|
||||||
CANCEL = 0x03,
|
|
||||||
MBUTTON = 0x04,
|
|
||||||
|
|
||||||
BACK = 0x08,
|
|
||||||
TAB = 0x09,
|
|
||||||
|
|
||||||
CLEAR = 0x0C,
|
|
||||||
RETURN = 0x0D,
|
|
||||||
|
|
||||||
SHIFT = 0x10,
|
|
||||||
CONTROL = 0x11,
|
|
||||||
MENU = 0x12,
|
|
||||||
PAUSE = 0x13,
|
|
||||||
CAPITAL = 0x14,
|
|
||||||
|
|
||||||
KANA = 0x15,
|
|
||||||
HANGEUL = 0x15,
|
|
||||||
HANGUL = 0x15,
|
|
||||||
JUNJA = 0x17,
|
|
||||||
FINAL = 0x18,
|
|
||||||
HANJA = 0x19,
|
|
||||||
KANJI = 0x19,
|
|
||||||
|
|
||||||
ESCAPE = 0x1B,
|
|
||||||
|
|
||||||
CONVERT = 0x1C,
|
|
||||||
NONCONVERT = 0x1D,
|
|
||||||
ACCEPT = 0x1E,
|
|
||||||
MODECHANGE = 0x1F,
|
|
||||||
|
|
||||||
SPACE = 0x20,
|
|
||||||
PRIOR = 0x21,
|
|
||||||
NEXT = 0x22,
|
|
||||||
END = 0x23,
|
|
||||||
HOME = 0x24,
|
|
||||||
LEFT = 0x25,
|
|
||||||
UP = 0x26,
|
|
||||||
RIGHT = 0x27,
|
|
||||||
DOWN = 0x28,
|
|
||||||
SELECT = 0x29,
|
|
||||||
PRINT = 0x2A,
|
|
||||||
EXECUTE = 0x2B,
|
|
||||||
SNAPSHOT = 0x2C,
|
|
||||||
INSERT = 0x2D,
|
|
||||||
DELETE = 0x2E,
|
|
||||||
HELP = 0x2F,
|
|
||||||
|
|
||||||
NUM0 = '0',
|
|
||||||
NUM1 = '1',
|
|
||||||
NUM2 = '2',
|
|
||||||
NUM3 = '3',
|
|
||||||
NUM4 = '4',
|
|
||||||
NUM5 = '5',
|
|
||||||
NUM6 = '6',
|
|
||||||
NUM7 = '7',
|
|
||||||
NUM8 = '8',
|
|
||||||
NUM9 = '9',
|
|
||||||
|
|
||||||
A = 'A',
|
|
||||||
B = 'B',
|
|
||||||
C = 'C',
|
|
||||||
D = 'D',
|
|
||||||
E = 'E',
|
|
||||||
F = 'F',
|
|
||||||
G = 'G',
|
|
||||||
H = 'H',
|
|
||||||
I = 'I',
|
|
||||||
J = 'J',
|
|
||||||
K = 'K',
|
|
||||||
L = 'L',
|
|
||||||
M = 'M',
|
|
||||||
N = 'N',
|
|
||||||
O = 'O',
|
|
||||||
P = 'P',
|
|
||||||
Q = 'Q',
|
|
||||||
R = 'R',
|
|
||||||
S = 'S',
|
|
||||||
T = 'T',
|
|
||||||
U = 'U',
|
|
||||||
V = 'V',
|
|
||||||
W = 'W',
|
|
||||||
X = 'X',
|
|
||||||
Y = 'Y',
|
|
||||||
Z = 'Z',
|
|
||||||
|
|
||||||
LWIN = 0x5B,
|
|
||||||
RWIN = 0x5C,
|
|
||||||
APPS = 0x5D,
|
|
||||||
|
|
||||||
NUMPAD0 = 0x60,
|
|
||||||
NUMPAD1 = 0x61,
|
|
||||||
NUMPAD2 = 0x62,
|
|
||||||
NUMPAD3 = 0x63,
|
|
||||||
NUMPAD4 = 0x64,
|
|
||||||
NUMPAD5 = 0x65,
|
|
||||||
NUMPAD6 = 0x66,
|
|
||||||
NUMPAD7 = 0x67,
|
|
||||||
NUMPAD8 = 0x68,
|
|
||||||
NUMPAD9 = 0x69,
|
|
||||||
MULTIPLY = 0x6A,
|
|
||||||
ADD = 0x6B,
|
|
||||||
SEPARATOR = 0x6C,
|
|
||||||
SUBTRACT = 0x6D,
|
|
||||||
DECIMAL = 0x6E,
|
|
||||||
DIVIDE = 0x6F,
|
|
||||||
F1 = 0x70,
|
|
||||||
F2 = 0x71,
|
|
||||||
F3 = 0x72,
|
|
||||||
F4 = 0x73,
|
|
||||||
F5 = 0x74,
|
|
||||||
F6 = 0x75,
|
|
||||||
F7 = 0x76,
|
|
||||||
F8 = 0x77,
|
|
||||||
F9 = 0x78,
|
|
||||||
F10 = 0x79,
|
|
||||||
F11 = 0x7A,
|
|
||||||
F12 = 0x7B,
|
|
||||||
F13 = 0x7C,
|
|
||||||
F14 = 0x7D,
|
|
||||||
F15 = 0x7E,
|
|
||||||
F16 = 0x7F,
|
|
||||||
F17 = 0x80,
|
|
||||||
F18 = 0x81,
|
|
||||||
F19 = 0x82,
|
|
||||||
F20 = 0x83,
|
|
||||||
F21 = 0x84,
|
|
||||||
F22 = 0x85,
|
|
||||||
F23 = 0x86,
|
|
||||||
F24 = 0x87,
|
|
||||||
|
|
||||||
NUMLOCK = 0x90,
|
|
||||||
SCROLL = 0x91,
|
|
||||||
|
|
||||||
LSHIFT = 0xA0,
|
|
||||||
RSHIFT = 0xA1,
|
|
||||||
LCONTROL = 0xA2,
|
|
||||||
RCONTROL = 0xA3,
|
|
||||||
LMENU = 0xA4,
|
|
||||||
RMENU = 0xA5,
|
|
||||||
PROCESSKEY = 0xE5,
|
|
||||||
ATTN = 0xF6,
|
|
||||||
CRSEL = 0xF7,
|
|
||||||
EXSEL = 0xF8,
|
|
||||||
EREOF = 0xF9,
|
|
||||||
PLAY = 0xFA,
|
|
||||||
ZOOM = 0xFB,
|
|
||||||
NONAME = 0xFC,
|
|
||||||
PA1 = 0xFD,
|
|
||||||
OEM_CLEAR = 0xFE,
|
|
||||||
}
|
|
||||||
|
|
||||||
+13
-16
@@ -2,23 +2,20 @@
|
|||||||
|
|
||||||
Not in any particular order
|
Not in any particular order
|
||||||
|
|
||||||
* Compile Time Execution (CTE)
|
* Custom backend to replace LLVM
|
||||||
- More metaprogramming madness
|
- Improve SSA design to accommodate for lowering to a "bytecode"
|
||||||
- Compiler as a library
|
- SSA optimizations
|
||||||
- AST inspection and modification
|
- COFF generation
|
||||||
* CTE-based build system
|
- linker
|
||||||
* Replace LLVM backend with my own custom backend
|
* Type safe "macros"
|
||||||
* Improve SSA design to accommodate for lowering to a "bytecode"
|
* Documentation generator for "Entities"
|
||||||
* SSA optimizations
|
* Multiple architecture support
|
||||||
* Parametric Polymorphism
|
* Inline assembly
|
||||||
* Documentation Generator for "Entities"
|
* Linking options
|
||||||
* Multiple Architecture support
|
|
||||||
* Linking Options
|
|
||||||
- Executable
|
- Executable
|
||||||
- Static/Dynamic Library
|
- Static/Dynamic Library
|
||||||
* Debug Information
|
* Debug information
|
||||||
- pdb format too
|
- pdb format too
|
||||||
* Command Line Tooling
|
* Command line tooling
|
||||||
* Compiler Internals:
|
* Compiler internals:
|
||||||
- Big numbers library
|
- Big numbers library
|
||||||
- Cyclic Type Checking (at the moment will cause compiler to go into an infinite loop)
|
|
||||||
|
|||||||
@@ -0,0 +1,238 @@
|
|||||||
|
// This stores the information for the specify architecture of this build
|
||||||
|
typedef struct BuildContext {
|
||||||
|
// Constants
|
||||||
|
String ODIN_OS; // target operating system
|
||||||
|
String ODIN_ARCH; // target architecture
|
||||||
|
String ODIN_ENDIAN; // target endian
|
||||||
|
String ODIN_VENDOR; // compiler vendor
|
||||||
|
String ODIN_VERSION; // compiler version
|
||||||
|
String ODIN_ROOT; // Odin ROOT
|
||||||
|
|
||||||
|
// In bytes
|
||||||
|
i64 word_size; // Size of a pointer, must be >= 4
|
||||||
|
i64 max_align; // max alignment, must be >= 1 (and typically >= word_size)
|
||||||
|
|
||||||
|
String llc_flags;
|
||||||
|
String link_flags;
|
||||||
|
bool is_dll;
|
||||||
|
} BuildContext;
|
||||||
|
|
||||||
|
|
||||||
|
gb_global BuildContext build_context = {0};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// TODO(bill): OS dependent versions for the BuildContext
|
||||||
|
// join_path
|
||||||
|
// is_dir
|
||||||
|
// is_file
|
||||||
|
// is_abs_path
|
||||||
|
// has_subdir
|
||||||
|
|
||||||
|
String const WIN32_SEPARATOR_STRING = {cast(u8 *)"\\", 1};
|
||||||
|
String const NIX_SEPARATOR_STRING = {cast(u8 *)"/", 1};
|
||||||
|
|
||||||
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
|
String odin_root_dir(void) {
|
||||||
|
String path = global_module_path;
|
||||||
|
Array(wchar_t) path_buf;
|
||||||
|
isize len, i;
|
||||||
|
gbTempArenaMemory tmp;
|
||||||
|
wchar_t *text;
|
||||||
|
|
||||||
|
if (global_module_path_set) {
|
||||||
|
return global_module_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
array_init_count(&path_buf, heap_allocator(), 300);
|
||||||
|
|
||||||
|
len = 0;
|
||||||
|
for (;;) {
|
||||||
|
len = GetModuleFileNameW(NULL, &path_buf.e[0], path_buf.count);
|
||||||
|
if (len == 0) {
|
||||||
|
return make_string(NULL, 0);
|
||||||
|
}
|
||||||
|
if (len < path_buf.count) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
array_resize(&path_buf, 2*path_buf.count + 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
|
||||||
|
|
||||||
|
text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1);
|
||||||
|
|
||||||
|
GetModuleFileNameW(NULL, text, len);
|
||||||
|
path = string16_to_string(heap_allocator(), make_string16(text, len));
|
||||||
|
for (i = path.len-1; i >= 0; i--) {
|
||||||
|
u8 c = path.text[i];
|
||||||
|
if (c == '/' || c == '\\') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
path.len--;
|
||||||
|
}
|
||||||
|
|
||||||
|
global_module_path = path;
|
||||||
|
global_module_path_set = true;
|
||||||
|
|
||||||
|
gb_temp_arena_memory_end(tmp);
|
||||||
|
|
||||||
|
array_free(&path_buf);
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(GB_SYSTEM_OSX)
|
||||||
|
|
||||||
|
#include <mach-o/dyld.h>
|
||||||
|
|
||||||
|
String odin_root_dir(void) {
|
||||||
|
String path = global_module_path;
|
||||||
|
Array(char) path_buf;
|
||||||
|
isize len, i;
|
||||||
|
gbTempArenaMemory tmp;
|
||||||
|
wchar_t *text;
|
||||||
|
|
||||||
|
if (global_module_path_set) {
|
||||||
|
return global_module_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
array_init_count(&path_buf, heap_allocator(), 300);
|
||||||
|
|
||||||
|
len = 0;
|
||||||
|
for (;;) {
|
||||||
|
int sz = path_buf.count;
|
||||||
|
int res = _NSGetExecutablePath(&path_buf.e[0], &sz);
|
||||||
|
if(res == 0) {
|
||||||
|
len = sz;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
array_resize(&path_buf, sz + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
|
||||||
|
text = gb_alloc_array(string_buffer_allocator, u8, len + 1);
|
||||||
|
gb_memmove(text, &path_buf.e[0], len);
|
||||||
|
|
||||||
|
path = make_string(text, len);
|
||||||
|
for (i = path.len-1; i >= 0; i--) {
|
||||||
|
u8 c = path.text[i];
|
||||||
|
if (c == '/' || c == '\\') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
path.len--;
|
||||||
|
}
|
||||||
|
|
||||||
|
global_module_path = path;
|
||||||
|
global_module_path_set = true;
|
||||||
|
|
||||||
|
gb_temp_arena_memory_end(tmp);
|
||||||
|
|
||||||
|
// array_free(&path_buf);
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#error Implement system
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
|
String path_to_fullpath(gbAllocator a, String s) {
|
||||||
|
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
|
||||||
|
String16 string16 = string_to_string16(string_buffer_allocator, s);
|
||||||
|
String result = {0};
|
||||||
|
|
||||||
|
DWORD len = GetFullPathNameW(string16.text, 0, NULL, NULL);
|
||||||
|
if (len != 0) {
|
||||||
|
wchar_t *text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1);
|
||||||
|
GetFullPathNameW(string16.text, len, text, NULL);
|
||||||
|
text[len] = 0;
|
||||||
|
result = string16_to_string(a, make_string16(text, len));
|
||||||
|
}
|
||||||
|
gb_temp_arena_memory_end(tmp);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
|
||||||
|
String path_to_fullpath(gbAllocator a, String s) {
|
||||||
|
char* p = realpath(s.text, 0);
|
||||||
|
// GB_ASSERT(p && "file does not exist");
|
||||||
|
if(!p) return make_string_c("");
|
||||||
|
|
||||||
|
return make_string(p, strlen(p));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#error Implement system
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
String get_fullpath_relative(gbAllocator a, String base_dir, String path) {
|
||||||
|
String res = {0};
|
||||||
|
isize str_len = base_dir.len+path.len;
|
||||||
|
|
||||||
|
u8 *str = gb_alloc_array(heap_allocator(), u8, str_len+1);
|
||||||
|
|
||||||
|
isize i = 0;
|
||||||
|
gb_memmove(str+i, base_dir.text, base_dir.len); i += base_dir.len;
|
||||||
|
gb_memmove(str+i, path.text, path.len);
|
||||||
|
str[str_len] = '\0';
|
||||||
|
res = path_to_fullpath(a, make_string(str, str_len));
|
||||||
|
gb_free(heap_allocator(), str);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
String get_fullpath_core(gbAllocator a, String path) {
|
||||||
|
String module_dir = odin_root_dir();
|
||||||
|
String res = {0};
|
||||||
|
|
||||||
|
char core[] = "core/";
|
||||||
|
isize core_len = gb_size_of(core)-1;
|
||||||
|
|
||||||
|
isize str_len = module_dir.len + core_len + path.len;
|
||||||
|
u8 *str = gb_alloc_array(heap_allocator(), u8, str_len+1);
|
||||||
|
|
||||||
|
gb_memmove(str, module_dir.text, module_dir.len);
|
||||||
|
gb_memmove(str+module_dir.len, core, core_len);
|
||||||
|
gb_memmove(str+module_dir.len+core_len, path.text, path.len);
|
||||||
|
str[str_len] = '\0';
|
||||||
|
|
||||||
|
res = path_to_fullpath(a, make_string(str, str_len));
|
||||||
|
gb_free(heap_allocator(), str);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void init_build_context(void) {
|
||||||
|
BuildContext *bc = &build_context;
|
||||||
|
bc->ODIN_VENDOR = str_lit("odin");
|
||||||
|
bc->ODIN_VERSION = str_lit("0.1.1");
|
||||||
|
bc->ODIN_ROOT = odin_root_dir();
|
||||||
|
|
||||||
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
|
bc->ODIN_OS = str_lit("windows");
|
||||||
|
bc->ODIN_ARCH = str_lit("amd64");
|
||||||
|
bc->ODIN_ENDIAN = str_lit("little");
|
||||||
|
#elif defined(GB_SYSTEM_OSX)
|
||||||
|
bc->ODIN_OS = str_lit("osx");
|
||||||
|
bc->ODIN_ARCH = str_lit("amd64");
|
||||||
|
bc->ODIN_ENDIAN = str_lit("little");
|
||||||
|
#else
|
||||||
|
#error Implement system
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (str_eq(bc->ODIN_ARCH, str_lit("amd64"))) {
|
||||||
|
bc->word_size = 8;
|
||||||
|
bc->max_align = 16;
|
||||||
|
bc->llc_flags = str_lit("-march=x86-64 ");
|
||||||
|
bc->link_flags = str_lit("/machine:x64 ");
|
||||||
|
} else if (str_eq(bc->ODIN_ARCH, str_lit("x86"))) {
|
||||||
|
bc->word_size = 4;
|
||||||
|
bc->max_align = 8;
|
||||||
|
bc->llc_flags = str_lit("-march=x86 ");
|
||||||
|
bc->link_flags = str_lit("/machine:x86 ");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,6 @@
|
|||||||
bool check_is_terminating(AstNode *node);
|
bool check_is_terminating(AstNode *node);
|
||||||
void check_stmt (Checker *c, AstNode *node, u32 flags);
|
void check_stmt (Checker *c, AstNode *node, u32 flags);
|
||||||
void check_stmt_list (Checker *c, AstNodeArray stmts, u32 flags);
|
void check_stmt_list (Checker *c, AstNodeArray stmts, u32 flags);
|
||||||
void check_type_decl (Checker *c, Entity *e, AstNode *type_expr, Type *def, CycleChecker *cycle_checker);
|
|
||||||
void check_const_decl (Checker *c, Entity *e, AstNode *type_expr, AstNode *init_expr);
|
|
||||||
void check_proc_decl (Checker *c, Entity *e, DeclInfo *d);
|
|
||||||
void check_var_decl (Checker *c, Entity *e, Entity **entities, isize entity_count, AstNode *type_expr, AstNode *init_expr);
|
|
||||||
|
|
||||||
// NOTE(bill): `content_name` is for debugging and error messages
|
// NOTE(bill): `content_name` is for debugging and error messages
|
||||||
Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String context_name) {
|
Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String context_name) {
|
||||||
@@ -16,7 +12,7 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
|
|||||||
gbString expr_str = expr_to_string(operand->expr);
|
gbString expr_str = expr_to_string(operand->expr);
|
||||||
|
|
||||||
// TODO(bill): is this a good enough error message?
|
// TODO(bill): is this a good enough error message?
|
||||||
error(ast_node_token(operand->expr),
|
error_node(operand->expr,
|
||||||
"Cannot assign builtin procedure `%s` in %.*s",
|
"Cannot assign builtin procedure `%s` in %.*s",
|
||||||
expr_str,
|
expr_str,
|
||||||
LIT(context_name));
|
LIT(context_name));
|
||||||
@@ -44,6 +40,7 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
|
|||||||
}
|
}
|
||||||
t = default_type(t);
|
t = default_type(t);
|
||||||
}
|
}
|
||||||
|
GB_ASSERT(is_type_typed(t));
|
||||||
e->type = t;
|
e->type = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,23 +61,9 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArra
|
|||||||
|
|
||||||
// NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
|
// NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
|
||||||
// an extra allocation
|
// an extra allocation
|
||||||
Array(Operand) operands;
|
ArrayOperand operands = {0};
|
||||||
array_init_reserve(&operands, c->tmp_allocator, 2*lhs_count);
|
array_init_reserve(&operands, c->tmp_allocator, 2*lhs_count);
|
||||||
|
check_unpack_arguments(c, lhs_count, &operands, inits, true);
|
||||||
for_array(i, inits) {
|
|
||||||
AstNode *rhs = inits.e[i];
|
|
||||||
Operand o = {0};
|
|
||||||
check_multi_expr(c, &o, rhs);
|
|
||||||
if (o.type->kind != Type_Tuple) {
|
|
||||||
array_add(&operands, o);
|
|
||||||
} else {
|
|
||||||
TypeTuple *tuple = &o.type->Tuple;
|
|
||||||
for (isize j = 0; j < tuple->variable_count; j++) {
|
|
||||||
o.type = tuple->variables[j]->type;
|
|
||||||
array_add(&operands, o);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isize rhs_count = operands.count;
|
isize rhs_count = operands.count;
|
||||||
for_array(i, operands) {
|
for_array(i, operands) {
|
||||||
@@ -89,132 +72,17 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArra
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
isize max = gb_min(lhs_count, rhs_count);
|
isize max = gb_min(lhs_count, rhs_count);
|
||||||
for (isize i = 0; i < max; i++) {
|
for (isize i = 0; i < max; i++) {
|
||||||
check_init_variable(c, lhs[i], &operands.e[i], context_name);
|
check_init_variable(c, lhs[i], &operands.e[i], context_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rhs_count > 0 && lhs_count != rhs_count) {
|
if (rhs_count > 0 && lhs_count != rhs_count) {
|
||||||
error(lhs[0]->token, "Assignment count mismatch `%td` := `%td`", lhs_count, rhs_count);
|
error(lhs[0]->token, "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
gb_temp_arena_memory_end(tmp);
|
gb_temp_arena_memory_end(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type, CycleChecker *cycle_checker) {
|
|
||||||
if (e->type != NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (d == NULL) {
|
|
||||||
DeclInfo **found = map_decl_info_get(&c->info.entities, hash_pointer(e));
|
|
||||||
if (found) {
|
|
||||||
d = *found;
|
|
||||||
} else {
|
|
||||||
e->type = t_invalid;
|
|
||||||
set_base_type(named_type, t_invalid);
|
|
||||||
return;
|
|
||||||
// GB_PANIC("`%.*s` should been declared!", LIT(e->token.string));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e->kind == Entity_Procedure) {
|
|
||||||
check_proc_decl(c, e, d);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
CheckerContext prev = c->context;
|
|
||||||
c->context.scope = d->scope;
|
|
||||||
c->context.decl = d;
|
|
||||||
|
|
||||||
switch (e->kind) {
|
|
||||||
case Entity_Constant:
|
|
||||||
check_const_decl(c, e, d->type_expr, d->init_expr);
|
|
||||||
break;
|
|
||||||
case Entity_Variable:
|
|
||||||
check_var_decl(c, e, d->entities, d->entity_count, d->type_expr, d->init_expr);
|
|
||||||
break;
|
|
||||||
case Entity_TypeName:
|
|
||||||
check_type_decl(c, e, d->type_expr, named_type, cycle_checker);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
c->context = prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void check_var_decl_node(Checker *c, AstNode *node) {
|
|
||||||
ast_node(vd, VarDecl, node);
|
|
||||||
isize entity_count = vd->names.count;
|
|
||||||
isize entity_index = 0;
|
|
||||||
Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count);
|
|
||||||
|
|
||||||
for_array(i, vd->names) {
|
|
||||||
AstNode *name = vd->names.e[i];
|
|
||||||
Entity *entity = NULL;
|
|
||||||
if (name->kind == AstNode_Ident) {
|
|
||||||
Token token = name->Ident;
|
|
||||||
String str = token.string;
|
|
||||||
Entity *found = NULL;
|
|
||||||
// NOTE(bill): Ignore assignments to `_`
|
|
||||||
if (str_ne(str, str_lit("_"))) {
|
|
||||||
found = current_scope_lookup_entity(c->context.scope, str);
|
|
||||||
}
|
|
||||||
if (found == NULL) {
|
|
||||||
entity = make_entity_variable(c->allocator, c->context.scope, token, NULL);
|
|
||||||
add_entity_definition(&c->info, name, entity);
|
|
||||||
} else {
|
|
||||||
TokenPos pos = found->token.pos;
|
|
||||||
error(token,
|
|
||||||
"Redeclaration of `%.*s` in this scope\n"
|
|
||||||
"\tat %.*s(%td:%td)",
|
|
||||||
LIT(str), LIT(pos.file), pos.line, pos.column);
|
|
||||||
entity = found;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
error(ast_node_token(name), "A variable declaration must be an identifier");
|
|
||||||
}
|
|
||||||
if (entity == NULL) {
|
|
||||||
entity = make_entity_dummy_variable(c->allocator, c->global_scope, ast_node_token(name));
|
|
||||||
}
|
|
||||||
entities[entity_index++] = entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
Type *init_type = NULL;
|
|
||||||
if (vd->type) {
|
|
||||||
init_type = check_type_extra(c, vd->type, NULL, NULL);
|
|
||||||
if (init_type == NULL)
|
|
||||||
init_type = t_invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (isize i = 0; i < entity_count; i++) {
|
|
||||||
Entity *e = entities[i];
|
|
||||||
GB_ASSERT(e != NULL);
|
|
||||||
if (e->flags & EntityFlag_Visited) {
|
|
||||||
e->type = t_invalid;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
e->flags |= EntityFlag_Visited;
|
|
||||||
|
|
||||||
if (e->type == NULL)
|
|
||||||
e->type = init_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
check_init_variables(c, entities, entity_count, vd->values, str_lit("variable declaration"));
|
|
||||||
|
|
||||||
for_array(i, vd->names) {
|
|
||||||
if (entities[i] != NULL) {
|
|
||||||
add_entity(c, c->context.scope, vd->names.e[i], entities[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void check_init_constant(Checker *c, Entity *e, Operand *operand) {
|
void check_init_constant(Checker *c, Entity *e, Operand *operand) {
|
||||||
if (operand->mode == Addressing_Invalid ||
|
if (operand->mode == Addressing_Invalid ||
|
||||||
operand->type == t_invalid ||
|
operand->type == t_invalid ||
|
||||||
@@ -227,23 +95,23 @@ void check_init_constant(Checker *c, Entity *e, Operand *operand) {
|
|||||||
|
|
||||||
if (operand->mode != Addressing_Constant) {
|
if (operand->mode != Addressing_Constant) {
|
||||||
// TODO(bill): better error
|
// TODO(bill): better error
|
||||||
error(ast_node_token(operand->expr),
|
gbString str = expr_to_string(operand->expr);
|
||||||
"`%.*s` is not a constant", LIT(ast_node_token(operand->expr).string));
|
error_node(operand->expr, "`%s` is not a constant", str);
|
||||||
|
gb_string_free(str);
|
||||||
|
if (e->type == NULL) {
|
||||||
|
e->type = t_invalid;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!is_type_constant_type(operand->type)) {
|
||||||
|
gbString type_str = type_to_string(operand->type);
|
||||||
|
error_node(operand->expr, "Invalid constant type: `%s`", type_str);
|
||||||
|
gb_string_free(type_str);
|
||||||
if (e->type == NULL) {
|
if (e->type == NULL) {
|
||||||
e->type = t_invalid;
|
e->type = t_invalid;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// if (!is_type_constant_type(operand->type)) {
|
|
||||||
// gbString type_str = type_to_string(operand->type);
|
|
||||||
// defer (gb_string_free(type_str));
|
|
||||||
// error(ast_node_token(operand->expr),
|
|
||||||
// "Invalid constant type: `%s`", type_str);
|
|
||||||
// if (e->type == NULL) {
|
|
||||||
// e->type = t_invalid;
|
|
||||||
// }
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (e->type == NULL) { // NOTE(bill): type inference
|
if (e->type == NULL) { // NOTE(bill): type inference
|
||||||
e->type = operand->type;
|
e->type = operand->type;
|
||||||
@@ -257,9 +125,27 @@ void check_init_constant(Checker *c, Entity *e, Operand *operand) {
|
|||||||
e->Constant.value = operand->value;
|
e->Constant.value = operand->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def) {
|
||||||
void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init_expr) {
|
|
||||||
GB_ASSERT(e->type == NULL);
|
GB_ASSERT(e->type == NULL);
|
||||||
|
Type *named = make_type_named(c->allocator, e->token.string, NULL, e);
|
||||||
|
named->Named.type_name = e;
|
||||||
|
if (def != NULL && def->kind == Type_Named) {
|
||||||
|
def->Named.base = named;
|
||||||
|
}
|
||||||
|
e->type = named;
|
||||||
|
|
||||||
|
// gb_printf_err("%.*s %p\n", LIT(e->token.string), e);
|
||||||
|
|
||||||
|
Type *bt = check_type_extra(c, type_expr, named);
|
||||||
|
named->Named.base = base_type(bt);
|
||||||
|
if (named->Named.base == t_invalid) {
|
||||||
|
// gb_printf("check_type_decl: %s\n", type_to_string(named));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init, Type *named_type) {
|
||||||
|
GB_ASSERT(e->type == NULL);
|
||||||
|
GB_ASSERT(e->kind == Entity_Constant);
|
||||||
|
|
||||||
if (e->flags & EntityFlag_Visited) {
|
if (e->flags & EntityFlag_Visited) {
|
||||||
e->type = t_invalid;
|
e->type = t_invalid;
|
||||||
@@ -269,47 +155,37 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init_e
|
|||||||
|
|
||||||
if (type_expr) {
|
if (type_expr) {
|
||||||
Type *t = check_type(c, type_expr);
|
Type *t = check_type(c, type_expr);
|
||||||
// if (!is_type_constant_type(t)) {
|
if (!is_type_constant_type(t)) {
|
||||||
// gbString str = type_to_string(t);
|
gbString str = type_to_string(t);
|
||||||
// defer (gb_string_free(str));
|
error_node(type_expr, "Invalid constant type `%s`", str);
|
||||||
// error(ast_node_token(type_expr),
|
gb_string_free(str);
|
||||||
// "Invalid constant type `%s`", str);
|
e->type = t_invalid;
|
||||||
// e->type = t_invalid;
|
return;
|
||||||
// return;
|
}
|
||||||
// }
|
|
||||||
e->type = t;
|
e->type = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
Operand operand = {0};
|
Operand operand = {0};
|
||||||
if (init_expr) {
|
if (init != NULL) {
|
||||||
check_expr(c, &operand, init_expr);
|
check_expr_or_type(c, &operand, init);
|
||||||
}
|
}
|
||||||
|
if (operand.mode == Addressing_Type) {
|
||||||
|
e->kind = Entity_TypeName;
|
||||||
|
|
||||||
|
DeclInfo *d = c->context.decl;
|
||||||
|
d->type_expr = d->init_expr;
|
||||||
|
check_type_decl(c, e, d->type_expr, named_type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
check_init_constant(c, e, &operand);
|
check_init_constant(c, e, &operand);
|
||||||
|
|
||||||
|
if (operand.mode == Addressing_Invalid ||
|
||||||
|
base_type(operand.type) == t_invalid) {
|
||||||
|
error(e->token, "Invalid declaration type");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def, CycleChecker *cycle_checker) {
|
|
||||||
GB_ASSERT(e->type == NULL);
|
|
||||||
Type *named = make_type_named(c->allocator, e->token.string, NULL, e);
|
|
||||||
named->Named.type_name = e;
|
|
||||||
if (def != NULL && def->kind == Type_Named) {
|
|
||||||
def->Named.base = named;
|
|
||||||
}
|
|
||||||
e->type = named;
|
|
||||||
|
|
||||||
CycleChecker local_cycle_checker = {0};
|
|
||||||
if (cycle_checker == NULL) {
|
|
||||||
cycle_checker = &local_cycle_checker;
|
|
||||||
}
|
|
||||||
|
|
||||||
Type *bt = check_type_extra(c, type_expr, named, cycle_checker_add(cycle_checker, e));
|
|
||||||
named->Named.base = bt;
|
|
||||||
named->Named.base = base_type(named->Named.base);
|
|
||||||
if (named->Named.base == t_invalid) {
|
|
||||||
gb_printf("check_type_decl: %s\n", type_to_string(named));
|
|
||||||
}
|
|
||||||
|
|
||||||
cycle_checker_destroy(&local_cycle_checker);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool are_signatures_similar_enough(Type *a_, Type *b_) {
|
bool are_signatures_similar_enough(Type *a_, Type *b_) {
|
||||||
@@ -350,18 +226,24 @@ bool are_signatures_similar_enough(Type *a_, Type *b_) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
|
||||||
GB_ASSERT(e->type == NULL);
|
GB_ASSERT(e->type == NULL);
|
||||||
|
if (d->proc_lit->kind != AstNode_ProcLit) {
|
||||||
|
// TOOD(bill): Better error message
|
||||||
|
error_node(d->proc_lit, "Expected a procedure to check");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Type *proc_type = make_type_proc(c->allocator, e->scope, NULL, 0, NULL, 0, false);
|
Type *proc_type = make_type_proc(c->allocator, e->scope, NULL, 0, NULL, 0, false, ProcCC_Odin);
|
||||||
e->type = proc_type;
|
e->type = proc_type;
|
||||||
ast_node(pd, ProcDecl, d->proc_decl);
|
ast_node(pd, ProcLit, d->proc_lit);
|
||||||
|
|
||||||
check_open_scope(c, pd->type);
|
check_open_scope(c, pd->type);
|
||||||
check_procedure_type(c, proc_type, pd->type);
|
check_procedure_type(c, proc_type, pd->type);
|
||||||
|
|
||||||
bool is_foreign = (pd->tags & ProcTag_foreign) != 0;
|
bool is_foreign = (pd->tags & ProcTag_foreign) != 0;
|
||||||
bool is_link_name = (pd->tags & ProcTag_link_name) != 0;
|
bool is_link_name = (pd->tags & ProcTag_link_name) != 0;
|
||||||
|
bool is_export = (pd->tags & ProcTag_export) != 0;
|
||||||
bool is_inline = (pd->tags & ProcTag_inline) != 0;
|
bool is_inline = (pd->tags & ProcTag_inline) != 0;
|
||||||
bool is_no_inline = (pd->tags & ProcTag_no_inline) != 0;
|
bool is_no_inline = (pd->tags & ProcTag_no_inline) != 0;
|
||||||
|
|
||||||
@@ -370,31 +252,36 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
|||||||
if (proc_type != NULL) {
|
if (proc_type != NULL) {
|
||||||
TypeProc *pt = &proc_type->Proc;
|
TypeProc *pt = &proc_type->Proc;
|
||||||
if (pt->param_count != 0 ||
|
if (pt->param_count != 0 ||
|
||||||
pt->result_count) {
|
pt->result_count != 0) {
|
||||||
gbString str = type_to_string(proc_type);
|
gbString str = type_to_string(proc_type);
|
||||||
error(e->token,
|
error(e->token, "Procedure type of `main` was expected to be `proc()`, got %s", str);
|
||||||
"Procedure type of `main` was expected to be `proc()`, got %s", str);
|
|
||||||
gb_string_free(str);
|
gb_string_free(str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_inline && is_no_inline) {
|
if (is_inline && is_no_inline) {
|
||||||
error(ast_node_token(pd->type),
|
error_node(pd->type, "You cannot apply both `inline` and `no_inline` to a procedure");
|
||||||
"You cannot apply both `inline` and `no_inline` to a procedure");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_foreign && is_link_name) {
|
if (is_foreign && is_link_name) {
|
||||||
error(ast_node_token(pd->type),
|
error_node(pd->type, "You cannot apply both `foreign` and `link_name` to a procedure");
|
||||||
"You cannot apply both `foreign` and `link_name` to a procedure");
|
} else if (is_foreign && is_export) {
|
||||||
|
error_node(pd->type, "You cannot apply both `foreign` and `export` to a procedure");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (pd->body != NULL) {
|
if (pd->body != NULL) {
|
||||||
if (is_foreign) {
|
if (is_foreign) {
|
||||||
error(ast_node_token(pd->body),
|
error_node(pd->body, "A procedure tagged as `#foreign` cannot have a body");
|
||||||
"A procedure tagged as `#foreign` cannot have a body");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(bill): Is this the best option? What about passing to external shit?!
|
||||||
|
// if (proc_type->Proc.calling_convention != ProcCC_Odin) {
|
||||||
|
// error_node(d->proc_lit, "An internal procedure may only have the Odin calling convention");
|
||||||
|
// proc_type->Proc.calling_convention = ProcCC_Odin;
|
||||||
|
// }
|
||||||
|
|
||||||
d->scope = c->context.scope;
|
d->scope = c->context.scope;
|
||||||
|
|
||||||
GB_ASSERT(pd->body->kind == AstNode_BlockStmt);
|
GB_ASSERT(pd->body->kind == AstNode_BlockStmt);
|
||||||
@@ -402,12 +289,38 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (is_foreign) {
|
if (is_foreign) {
|
||||||
MapEntity *fp = &c->info.foreign_procs;
|
MapEntity *fp = &c->info.foreigns;
|
||||||
AstNodeProcDecl *proc_decl = &d->proc_decl->ProcDecl;
|
String name = e->token.string;
|
||||||
String name = proc_decl->name->Ident.string;
|
if (pd->foreign_name.len > 0) {
|
||||||
if (proc_decl->foreign_name.len > 0) {
|
name = pd->foreign_name;
|
||||||
name = proc_decl->foreign_name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AstNode *foreign_library = d->proc_lit->ProcLit.foreign_library;
|
||||||
|
if (foreign_library == NULL) {
|
||||||
|
error(e->token, "#foreign procedures must declare which library they are from");
|
||||||
|
} else if (foreign_library->kind != AstNode_Ident) {
|
||||||
|
error_node(foreign_library, "#foreign library names must be an identifier");
|
||||||
|
} else {
|
||||||
|
String name = foreign_library->Ident.string;
|
||||||
|
Entity *found = scope_lookup_entity(c->context.scope, name);
|
||||||
|
if (found == NULL) {
|
||||||
|
if (str_eq(name, str_lit("_"))) {
|
||||||
|
error_node(foreign_library, "`_` cannot be used as a value type");
|
||||||
|
} else {
|
||||||
|
error_node(foreign_library, "Undeclared name: %.*s", LIT(name));
|
||||||
|
}
|
||||||
|
} else if (found->kind != Entity_LibraryName) {
|
||||||
|
error_node(foreign_library, "`_` cannot be used as a library name");
|
||||||
|
} else {
|
||||||
|
// TODO(bill): Extra stuff to do with library names?
|
||||||
|
e->Procedure.foreign_library = found;
|
||||||
|
add_entity_use(c, foreign_library, found);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
e->Procedure.is_foreign = true;
|
||||||
|
e->Procedure.foreign_name = name;
|
||||||
|
|
||||||
HashKey key = hash_string(name);
|
HashKey key = hash_string(name);
|
||||||
Entity **found = map_entity_get(fp, key);
|
Entity **found = map_entity_get(fp, key);
|
||||||
if (found) {
|
if (found) {
|
||||||
@@ -416,30 +329,38 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
|||||||
Type *this_type = base_type(e->type);
|
Type *this_type = base_type(e->type);
|
||||||
Type *other_type = base_type(f->type);
|
Type *other_type = base_type(f->type);
|
||||||
if (!are_signatures_similar_enough(this_type, other_type)) {
|
if (!are_signatures_similar_enough(this_type, other_type)) {
|
||||||
error(ast_node_token(d->proc_decl),
|
error_node(d->proc_lit,
|
||||||
"Redeclaration of #foreign procedure `%.*s` with different type signatures\n"
|
"Redeclaration of #foreign procedure `%.*s` with different type signatures\n"
|
||||||
"\tat %.*s(%td:%td)",
|
"\tat %.*s(%td:%td)",
|
||||||
LIT(name), LIT(pos.file), pos.line, pos.column);
|
LIT(name), LIT(pos.file), pos.line, pos.column);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
map_entity_set(fp, key, e);
|
map_entity_set(fp, key, e);
|
||||||
}
|
}
|
||||||
} else if (is_link_name) {
|
} else {
|
||||||
MapEntity *fp = &c->info.foreign_procs;
|
String name = e->token.string;
|
||||||
AstNodeProcDecl *proc_decl = &d->proc_decl->ProcDecl;
|
if (is_link_name) {
|
||||||
String name = proc_decl->link_name;
|
name = pd->link_name;
|
||||||
|
}
|
||||||
|
|
||||||
HashKey key = hash_string(name);
|
if (is_link_name || is_export) {
|
||||||
Entity **found = map_entity_get(fp, key);
|
MapEntity *fp = &c->info.foreigns;
|
||||||
if (found) {
|
|
||||||
Entity *f = *found;
|
e->Procedure.link_name = name;
|
||||||
TokenPos pos = f->token.pos;
|
|
||||||
error(ast_node_token(d->proc_decl),
|
HashKey key = hash_string(name);
|
||||||
"Non unique #link_name for procedure `%.*s`\n"
|
Entity **found = map_entity_get(fp, key);
|
||||||
"\tother at %.*s(%td:%td)",
|
if (found) {
|
||||||
LIT(name), LIT(pos.file), pos.line, pos.column);
|
Entity *f = *found;
|
||||||
} else {
|
TokenPos pos = f->token.pos;
|
||||||
map_entity_set(fp, key, e);
|
// TODO(bill): Better error message?
|
||||||
|
error_node(d->proc_lit,
|
||||||
|
"Non unique linking name for procedure `%.*s`\n"
|
||||||
|
"\tother at %.*s(%td:%td)",
|
||||||
|
LIT(name), LIT(pos.file), pos.line, pos.column);
|
||||||
|
} else {
|
||||||
|
map_entity_set(fp, key, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -456,12 +377,14 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
|
|||||||
}
|
}
|
||||||
e->flags |= EntityFlag_Visited;
|
e->flags |= EntityFlag_Visited;
|
||||||
|
|
||||||
if (type_expr != NULL)
|
if (type_expr != NULL) {
|
||||||
e->type = check_type_extra(c, type_expr, NULL, NULL);
|
e->type = check_type_extra(c, type_expr, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
if (init_expr == NULL) {
|
if (init_expr == NULL) {
|
||||||
if (type_expr == NULL)
|
if (type_expr == NULL) {
|
||||||
e->type = t_invalid;
|
e->type = t_invalid;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -473,8 +396,9 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (type_expr != NULL) {
|
if (type_expr != NULL) {
|
||||||
for (isize i = 0; i < entity_count; i++)
|
for (isize i = 0; i < entity_count; i++) {
|
||||||
entities[i]->type = e->type;
|
entities[i]->type = e->type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AstNodeArray inits;
|
AstNodeArray inits;
|
||||||
@@ -483,12 +407,65 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
|
|||||||
check_init_variables(c, entities, entity_count, inits, str_lit("variable declaration"));
|
check_init_variables(c, entities, entity_count, inits, str_lit("variable declaration"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
|
||||||
|
if (e->type != NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d == NULL) {
|
||||||
|
DeclInfo **found = map_decl_info_get(&c->info.entities, hash_pointer(e));
|
||||||
|
if (found) {
|
||||||
|
d = *found;
|
||||||
|
} else {
|
||||||
|
// TODO(bill): Err here?
|
||||||
|
e->type = t_invalid;
|
||||||
|
set_base_type(named_type, t_invalid);
|
||||||
|
return;
|
||||||
|
// GB_PANIC("`%.*s` should been declared!", LIT(e->token.string));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckerContext prev = c->context;
|
||||||
|
c->context.scope = d->scope;
|
||||||
|
c->context.decl = d;
|
||||||
|
|
||||||
|
switch (e->kind) {
|
||||||
|
case Entity_Variable:
|
||||||
|
check_var_decl(c, e, d->entities, d->entity_count, d->type_expr, d->init_expr);
|
||||||
|
break;
|
||||||
|
case Entity_Constant:
|
||||||
|
check_const_decl(c, e, d->type_expr, d->init_expr, named_type);
|
||||||
|
break;
|
||||||
|
case Entity_TypeName:
|
||||||
|
check_type_decl(c, e, d->type_expr, named_type);
|
||||||
|
break;
|
||||||
|
case Entity_Procedure:
|
||||||
|
check_proc_lit(c, e, d);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->context = prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body) {
|
void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body) {
|
||||||
GB_ASSERT(body->kind == AstNode_BlockStmt);
|
GB_ASSERT(body->kind == AstNode_BlockStmt);
|
||||||
|
|
||||||
|
String proc_name = {0};
|
||||||
|
if (token.kind == Token_Ident) {
|
||||||
|
proc_name = token.string;
|
||||||
|
} else {
|
||||||
|
// TODO(bill): Better name
|
||||||
|
proc_name = str_lit("(anonymous-procedure)");
|
||||||
|
}
|
||||||
|
|
||||||
CheckerContext old_context = c->context;
|
CheckerContext old_context = c->context;
|
||||||
c->context.scope = decl->scope;
|
c->context.scope = decl->scope;
|
||||||
c->context.decl = decl;
|
c->context.decl = decl;
|
||||||
|
c->context.proc_name = proc_name;
|
||||||
|
|
||||||
|
|
||||||
GB_ASSERT(type->kind == Type_Proc);
|
GB_ASSERT(type->kind == Type_Proc);
|
||||||
if (type->Proc.param_count > 0) {
|
if (type->Proc.param_count > 0) {
|
||||||
@@ -499,6 +476,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
|
|||||||
if (!(e->flags & EntityFlag_Anonymous)) {
|
if (!(e->flags & EntityFlag_Anonymous)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
bool is_immutable = e->Variable.is_immutable;
|
||||||
String name = e->token.string;
|
String name = e->token.string;
|
||||||
Type *t = base_type(type_deref(e->type));
|
Type *t = base_type(type_deref(e->type));
|
||||||
if (is_type_struct(t) || is_type_raw_union(t)) {
|
if (is_type_struct(t) || is_type_raw_union(t)) {
|
||||||
@@ -508,6 +486,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
|
|||||||
Entity *f = (*found)->elements.entries.e[i].value;
|
Entity *f = (*found)->elements.entries.e[i].value;
|
||||||
if (f->kind == Entity_Variable) {
|
if (f->kind == Entity_Variable) {
|
||||||
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
|
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
|
||||||
|
uvar->Variable.is_immutable = is_immutable;
|
||||||
Entity *prev = scope_insert_entity(c->context.scope, uvar);
|
Entity *prev = scope_insert_entity(c->context.scope, uvar);
|
||||||
if (prev != NULL) {
|
if (prev != NULL) {
|
||||||
error(e->token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(prev->token.string));
|
error(e->token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(prev->token.string));
|
||||||
@@ -525,11 +504,14 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
|
|||||||
push_procedure(c, type);
|
push_procedure(c, type);
|
||||||
{
|
{
|
||||||
ast_node(bs, BlockStmt, body);
|
ast_node(bs, BlockStmt, body);
|
||||||
// TODO(bill): Check declarations first (except mutable variable declarations)
|
|
||||||
check_stmt_list(c, bs->stmts, 0);
|
check_stmt_list(c, bs->stmts, 0);
|
||||||
if (type->Proc.result_count > 0) {
|
if (type->Proc.result_count > 0) {
|
||||||
if (!check_is_terminating(body)) {
|
if (!check_is_terminating(body)) {
|
||||||
error(bs->close, "Missing return statement at the end of the procedure");
|
if (token.kind == Token_Ident) {
|
||||||
|
error(bs->close, "Missing return statement at the end of the procedure `%.*s`", LIT(token.string));
|
||||||
|
} else {
|
||||||
|
error(bs->close, "Missing return statement at the end of the procedure");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+2548
-1469
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1943
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
-1488
File diff suppressed because it is too large
Load Diff
+11
-61
@@ -6,78 +6,25 @@ gbAllocator heap_allocator(void) {
|
|||||||
return gb_heap_allocator();
|
return gb_heap_allocator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "unicode.c"
|
||||||
#include "string.c"
|
#include "string.c"
|
||||||
#include "array.c"
|
#include "array.c"
|
||||||
|
|
||||||
gb_global String global_module_path = {0};
|
gb_global String global_module_path = {0};
|
||||||
gb_global bool global_module_path_set = false;
|
gb_global bool global_module_path_set = false;
|
||||||
|
|
||||||
|
gb_global gbScratchMemory scratch_memory = {0};
|
||||||
|
|
||||||
String get_module_dir() {
|
void init_scratch_memory(isize size) {
|
||||||
String path = global_module_path;
|
void *memory = gb_alloc(heap_allocator(), size);
|
||||||
Array(wchar_t) path_buf;
|
gb_scratch_memory_init(&scratch_memory, memory, size);
|
||||||
isize len, i;
|
|
||||||
gbTempArenaMemory tmp;
|
|
||||||
wchar_t *text;
|
|
||||||
|
|
||||||
if (global_module_path_set) {
|
|
||||||
return global_module_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
array_init_count(&path_buf, heap_allocator(), 300);
|
|
||||||
|
|
||||||
len = 0;
|
|
||||||
for (;;) {
|
|
||||||
len = GetModuleFileNameW(NULL, &path_buf.e[0], path_buf.count);
|
|
||||||
if (len == 0) {
|
|
||||||
return make_string(NULL, 0);
|
|
||||||
}
|
|
||||||
if (len < path_buf.count) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
array_resize(&path_buf, 2*path_buf.count + 300);
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
|
|
||||||
|
|
||||||
text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1);
|
|
||||||
|
|
||||||
GetModuleFileNameW(NULL, text, len);
|
|
||||||
path = string16_to_string(heap_allocator(), make_string16(text, len));
|
|
||||||
for (i = path.len-1; i >= 0; i--) {
|
|
||||||
u8 c = path.text[i];
|
|
||||||
if (c == '/' || c == '\\') {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
path.len--;
|
|
||||||
}
|
|
||||||
|
|
||||||
global_module_path = path;
|
|
||||||
global_module_path_set = true;
|
|
||||||
|
|
||||||
gb_temp_arena_memory_end(tmp);
|
|
||||||
|
|
||||||
array_free(&path_buf);
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String path_to_fullpath(gbAllocator a, String s) {
|
gbAllocator scratch_allocator(void) {
|
||||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
|
return gb_scratch_allocator(&scratch_memory);
|
||||||
String16 string16 = string_to_string16(string_buffer_allocator, s);
|
|
||||||
String result = {0};
|
|
||||||
|
|
||||||
DWORD len = GetFullPathNameW(string16.text, 0, NULL, NULL);
|
|
||||||
if (len != 0) {
|
|
||||||
wchar_t *text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1);
|
|
||||||
GetFullPathNameW(string16.text, len, text, NULL);
|
|
||||||
text[len] = 0;
|
|
||||||
result = string16_to_string(a, make_string16(text, len));
|
|
||||||
}
|
|
||||||
gb_temp_arena_memory_end(tmp);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
i64 next_pow2(i64 n) {
|
i64 next_pow2(i64 n) {
|
||||||
if (n <= 0) {
|
if (n <= 0) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -184,6 +131,9 @@ i16 f32_to_f16(f32 value) {
|
|||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
typedef Array(i32) Array_i32;
|
||||||
|
typedef Array(isize) Array_isize;
|
||||||
|
|
||||||
|
|
||||||
#define MAP_TYPE String
|
#define MAP_TYPE String
|
||||||
#define MAP_PROC map_string_
|
#define MAP_PROC map_string_
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
typedef struct Scope Scope;
|
typedef struct Scope Scope;
|
||||||
typedef struct Checker Checker;
|
typedef struct Checker Checker;
|
||||||
typedef struct Type Type;
|
typedef struct Type Type;
|
||||||
typedef enum BuiltinProcId BuiltinProcId;
|
// typedef enum BuiltinProcId BuiltinProcId;
|
||||||
typedef enum ImplicitValueId ImplicitValueId;
|
|
||||||
|
|
||||||
#define ENTITY_KINDS \
|
#define ENTITY_KINDS \
|
||||||
ENTITY_KIND(Invalid) \
|
ENTITY_KIND(Invalid) \
|
||||||
@@ -12,8 +12,8 @@ typedef enum ImplicitValueId ImplicitValueId;
|
|||||||
ENTITY_KIND(Procedure) \
|
ENTITY_KIND(Procedure) \
|
||||||
ENTITY_KIND(Builtin) \
|
ENTITY_KIND(Builtin) \
|
||||||
ENTITY_KIND(ImportName) \
|
ENTITY_KIND(ImportName) \
|
||||||
|
ENTITY_KIND(LibraryName) \
|
||||||
ENTITY_KIND(Nil) \
|
ENTITY_KIND(Nil) \
|
||||||
ENTITY_KIND(ImplicitValue) \
|
|
||||||
ENTITY_KIND(Count)
|
ENTITY_KIND(Count)
|
||||||
|
|
||||||
typedef enum EntityKind {
|
typedef enum EntityKind {
|
||||||
@@ -35,8 +35,20 @@ typedef enum EntityFlag {
|
|||||||
EntityFlag_Field = 1<<3,
|
EntityFlag_Field = 1<<3,
|
||||||
EntityFlag_Param = 1<<4,
|
EntityFlag_Param = 1<<4,
|
||||||
EntityFlag_VectorElem = 1<<5,
|
EntityFlag_VectorElem = 1<<5,
|
||||||
|
EntityFlag_Ellipsis = 1<<6,
|
||||||
|
EntityFlag_NoAlias = 1<<7,
|
||||||
|
EntityFlag_TypeField = 1<<8,
|
||||||
} EntityFlag;
|
} EntityFlag;
|
||||||
|
|
||||||
|
// Zero value means the overloading process is not yet done
|
||||||
|
typedef enum OverloadKind {
|
||||||
|
Overload_Unknown,
|
||||||
|
Overload_No,
|
||||||
|
Overload_Yes,
|
||||||
|
} OverloadKind;
|
||||||
|
|
||||||
|
|
||||||
|
// An Entity is a named "thing" in the language
|
||||||
typedef struct Entity Entity;
|
typedef struct Entity Entity;
|
||||||
struct Entity {
|
struct Entity {
|
||||||
EntityKind kind;
|
EntityKind kind;
|
||||||
@@ -55,29 +67,66 @@ struct Entity {
|
|||||||
ExactValue value;
|
ExactValue value;
|
||||||
} Constant;
|
} Constant;
|
||||||
struct {
|
struct {
|
||||||
i32 field_index;
|
i32 field_index;
|
||||||
i32 field_src_index;
|
i32 field_src_index;
|
||||||
|
bool is_immutable;
|
||||||
|
bool is_thread_local;
|
||||||
} Variable;
|
} Variable;
|
||||||
i32 TypeName;
|
i32 TypeName;
|
||||||
i32 Procedure;
|
|
||||||
struct {
|
struct {
|
||||||
BuiltinProcId id;
|
bool is_foreign;
|
||||||
|
String foreign_name;
|
||||||
|
Entity * foreign_library;
|
||||||
|
String link_name;
|
||||||
|
u64 tags;
|
||||||
|
OverloadKind overload_kind;
|
||||||
|
} Procedure;
|
||||||
|
struct {
|
||||||
|
i32 id;
|
||||||
} Builtin;
|
} Builtin;
|
||||||
struct {
|
struct {
|
||||||
String path;
|
String path;
|
||||||
String name;
|
String name;
|
||||||
Scope *scope;
|
Scope *scope;
|
||||||
bool used;
|
bool used;
|
||||||
} ImportName;
|
} ImportName;
|
||||||
i32 Nil;
|
|
||||||
struct {
|
struct {
|
||||||
// TODO(bill): Should this be a user-level construct rather than compiler-level?
|
String path;
|
||||||
ImplicitValueId id;
|
String name;
|
||||||
Entity * backing;
|
bool used;
|
||||||
} ImplicitValue;
|
} LibraryName;
|
||||||
|
i32 Nil;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
gb_global Entity *e_context = NULL;
|
||||||
|
|
||||||
|
bool is_entity_kind_exported(EntityKind kind) {
|
||||||
|
switch (kind) {
|
||||||
|
case Entity_Builtin:
|
||||||
|
case Entity_ImportName:
|
||||||
|
case Entity_LibraryName:
|
||||||
|
case Entity_Nil:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_entity_exported(Entity *e) {
|
||||||
|
// TODO(bill): Determine the actual exportation rules for imports of entities
|
||||||
|
GB_ASSERT(e != NULL);
|
||||||
|
if (!is_entity_kind_exported(e->kind)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String name = e->token.string;
|
||||||
|
if (name.len == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return name.text[0] != '_';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Entity *alloc_entity(gbAllocator a, EntityKind kind, Scope *scope, Token token, Type *type) {
|
Entity *alloc_entity(gbAllocator a, EntityKind kind, Scope *scope, Token token, Type *type) {
|
||||||
Entity *entity = gb_alloc_item(a, Entity);
|
Entity *entity = gb_alloc_item(a, Entity);
|
||||||
entity->kind = kind;
|
entity->kind = kind;
|
||||||
@@ -87,13 +136,15 @@ Entity *alloc_entity(gbAllocator a, EntityKind kind, Scope *scope, Token token,
|
|||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity *make_entity_variable(gbAllocator a, Scope *scope, Token token, Type *type) {
|
Entity *make_entity_variable(gbAllocator a, Scope *scope, Token token, Type *type, bool is_immutable) {
|
||||||
Entity *entity = alloc_entity(a, Entity_Variable, scope, token, type);
|
Entity *entity = alloc_entity(a, Entity_Variable, scope, token, type);
|
||||||
|
entity->Variable.is_immutable = is_immutable;
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity *make_entity_using_variable(gbAllocator a, Entity *parent, Token token, Type *type) {
|
Entity *make_entity_using_variable(gbAllocator a, Entity *parent, Token token, Type *type) {
|
||||||
GB_ASSERT(parent != NULL);
|
GB_ASSERT(parent != NULL);
|
||||||
|
token.pos = parent->token.pos;
|
||||||
Entity *entity = alloc_entity(a, Entity_Variable, parent->scope, token, type);
|
Entity *entity = alloc_entity(a, Entity_Variable, parent->scope, token, type);
|
||||||
entity->using_parent = parent;
|
entity->using_parent = parent;
|
||||||
entity->flags |= EntityFlag_Anonymous;
|
entity->flags |= EntityFlag_Anonymous;
|
||||||
@@ -112,16 +163,16 @@ Entity *make_entity_type_name(gbAllocator a, Scope *scope, Token token, Type *ty
|
|||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity *make_entity_param(gbAllocator a, Scope *scope, Token token, Type *type, bool anonymous) {
|
Entity *make_entity_param(gbAllocator a, Scope *scope, Token token, Type *type, bool anonymous, bool is_immutable) {
|
||||||
Entity *entity = make_entity_variable(a, scope, token, type);
|
Entity *entity = make_entity_variable(a, scope, token, type, is_immutable);
|
||||||
entity->flags |= EntityFlag_Used;
|
entity->flags |= EntityFlag_Used;
|
||||||
entity->flags |= EntityFlag_Anonymous*(anonymous != 0);
|
if (anonymous) entity->flags |= EntityFlag_Anonymous;
|
||||||
entity->flags |= EntityFlag_Param;
|
entity->flags |= EntityFlag_Param;
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity *make_entity_field(gbAllocator a, Scope *scope, Token token, Type *type, bool anonymous, i32 field_src_index) {
|
Entity *make_entity_field(gbAllocator a, Scope *scope, Token token, Type *type, bool anonymous, i32 field_src_index) {
|
||||||
Entity *entity = make_entity_variable(a, scope, token, type);
|
Entity *entity = make_entity_variable(a, scope, token, type, false);
|
||||||
entity->Variable.field_src_index = field_src_index;
|
entity->Variable.field_src_index = field_src_index;
|
||||||
entity->Variable.field_index = field_src_index;
|
entity->Variable.field_index = field_src_index;
|
||||||
entity->flags |= EntityFlag_Field;
|
entity->flags |= EntityFlag_Field;
|
||||||
@@ -130,7 +181,7 @@ Entity *make_entity_field(gbAllocator a, Scope *scope, Token token, Type *type,
|
|||||||
}
|
}
|
||||||
|
|
||||||
Entity *make_entity_vector_elem(gbAllocator a, Scope *scope, Token token, Type *type, i32 field_src_index) {
|
Entity *make_entity_vector_elem(gbAllocator a, Scope *scope, Token token, Type *type, i32 field_src_index) {
|
||||||
Entity *entity = make_entity_variable(a, scope, token, type);
|
Entity *entity = make_entity_variable(a, scope, token, type, false);
|
||||||
entity->Variable.field_src_index = field_src_index;
|
entity->Variable.field_src_index = field_src_index;
|
||||||
entity->Variable.field_index = field_src_index;
|
entity->Variable.field_index = field_src_index;
|
||||||
entity->flags |= EntityFlag_Field;
|
entity->flags |= EntityFlag_Field;
|
||||||
@@ -138,12 +189,13 @@ Entity *make_entity_vector_elem(gbAllocator a, Scope *scope, Token token, Type *
|
|||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity *make_entity_procedure(gbAllocator a, Scope *scope, Token token, Type *signature_type) {
|
Entity *make_entity_procedure(gbAllocator a, Scope *scope, Token token, Type *signature_type, u64 tags) {
|
||||||
Entity *entity = alloc_entity(a, Entity_Procedure, scope, token, signature_type);
|
Entity *entity = alloc_entity(a, Entity_Procedure, scope, token, signature_type);
|
||||||
|
entity->Procedure.tags = tags;
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity *make_entity_builtin(gbAllocator a, Scope *scope, Token token, Type *type, BuiltinProcId id) {
|
Entity *make_entity_builtin(gbAllocator a, Scope *scope, Token token, Type *type, i32 id) {
|
||||||
Entity *entity = alloc_entity(a, Entity_Builtin, scope, token, type);
|
Entity *entity = alloc_entity(a, Entity_Builtin, scope, token, type);
|
||||||
entity->Builtin.id = id;
|
entity->Builtin.id = id;
|
||||||
return entity;
|
return entity;
|
||||||
@@ -158,22 +210,22 @@ Entity *make_entity_import_name(gbAllocator a, Scope *scope, Token token, Type *
|
|||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Entity *make_entity_library_name(gbAllocator a, Scope *scope, Token token, Type *type,
|
||||||
|
String path, String name) {
|
||||||
|
Entity *entity = alloc_entity(a, Entity_LibraryName, scope, token, type);
|
||||||
|
entity->LibraryName.path = path;
|
||||||
|
entity->LibraryName.name = name;
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
Entity *make_entity_nil(gbAllocator a, String name, Type *type) {
|
Entity *make_entity_nil(gbAllocator a, String name, Type *type) {
|
||||||
Token token = make_token_ident(name);
|
Token token = make_token_ident(name);
|
||||||
Entity *entity = alloc_entity(a, Entity_Nil, NULL, token, type);
|
Entity *entity = alloc_entity(a, Entity_Nil, NULL, token, type);
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity *make_entity_implicit_value(gbAllocator a, String name, Type *type, ImplicitValueId id) {
|
Entity *make_entity_dummy_variable(gbAllocator a, Scope *scope, Token token) {
|
||||||
Token token = make_token_ident(name);
|
|
||||||
Entity *entity = alloc_entity(a, Entity_ImplicitValue, NULL, token, type);
|
|
||||||
entity->ImplicitValue.id = id;
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Entity *make_entity_dummy_variable(gbAllocator a, Scope *file_scope, Token token) {
|
|
||||||
token.string = str_lit("_");
|
token.string = str_lit("_");
|
||||||
return make_entity_variable(a, file_scope, token, NULL);
|
return make_entity_variable(a, scope, token, NULL, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
+124
-29
@@ -21,7 +21,7 @@ typedef enum ExactValueKind {
|
|||||||
typedef struct ExactValue {
|
typedef struct ExactValue {
|
||||||
ExactValueKind kind;
|
ExactValueKind kind;
|
||||||
union {
|
union {
|
||||||
bool value_bool;
|
bool value_bool;
|
||||||
String value_string;
|
String value_string;
|
||||||
i64 value_integer; // NOTE(bill): This must be an integer and not a pointer
|
i64 value_integer; // NOTE(bill): This must be an integer and not a pointer
|
||||||
f64 value_float;
|
f64 value_float;
|
||||||
@@ -54,37 +54,12 @@ ExactValue make_exact_value_string(String string) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExactValue make_exact_value_integer_from_string(String string) {
|
|
||||||
// TODO(bill): Allow for numbers with underscores in them
|
|
||||||
ExactValue result = {ExactValue_Integer};
|
|
||||||
i32 base = 10;
|
|
||||||
if (string.text[0] == '0') {
|
|
||||||
switch (string.text[1]) {
|
|
||||||
case 'b': base = 2; break;
|
|
||||||
case 'o': base = 8; break;
|
|
||||||
case 'd': base = 10; break;
|
|
||||||
case 'x': base = 16; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result.value_integer = gb_str_to_i64(cast(char *)string.text, NULL, base);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ExactValue make_exact_value_integer(i64 i) {
|
ExactValue make_exact_value_integer(i64 i) {
|
||||||
ExactValue result = {ExactValue_Integer};
|
ExactValue result = {ExactValue_Integer};
|
||||||
result.value_integer = i;
|
result.value_integer = i;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExactValue make_exact_value_float_from_string(String string) {
|
|
||||||
// TODO(bill): Allow for numbers with underscores in them
|
|
||||||
ExactValue result = {ExactValue_Float};
|
|
||||||
result.value_float = gb_str_to_f64(cast(char *)string.text, NULL);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ExactValue make_exact_value_float(f64 f) {
|
ExactValue make_exact_value_float(f64 f) {
|
||||||
ExactValue result = {ExactValue_Float};
|
ExactValue result = {ExactValue_Float};
|
||||||
result.value_float = f;
|
result.value_float = f;
|
||||||
@@ -97,6 +72,123 @@ ExactValue make_exact_value_pointer(i64 ptr) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ExactValue make_exact_value_integer_from_string(String string) {
|
||||||
|
// TODO(bill): Allow for numbers with underscores in them
|
||||||
|
i32 base = 10;
|
||||||
|
bool has_prefix = false;
|
||||||
|
if (string.len > 2 && string.text[0] == '0') {
|
||||||
|
switch (string.text[1]) {
|
||||||
|
case 'b': base = 2; has_prefix = true; break;
|
||||||
|
case 'o': base = 8; has_prefix = true; break;
|
||||||
|
case 'd': base = 10; has_prefix = true; break;
|
||||||
|
case 'x': base = 16; has_prefix = true; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 *text = string.text;
|
||||||
|
isize len = string.len;
|
||||||
|
if (has_prefix) {
|
||||||
|
text += 2;
|
||||||
|
len -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
i64 result = 0;
|
||||||
|
for (isize i = 0; i < len; i++) {
|
||||||
|
Rune r = cast(Rune)text[i];
|
||||||
|
if (r == '_') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
i64 v = 0;
|
||||||
|
if (gb_char_is_digit(r)) {
|
||||||
|
v = r - '0';
|
||||||
|
} else if (gb_char_is_hex_digit(r)) {
|
||||||
|
v = gb_hex_digit_to_int(r);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
result *= base;
|
||||||
|
result += v;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return make_exact_value_integer(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ExactValue make_exact_value_float_from_string(String string) {
|
||||||
|
isize i = 0;
|
||||||
|
u8 *str = string.text;
|
||||||
|
isize len = string.len;
|
||||||
|
|
||||||
|
f64 sign = 1.0;
|
||||||
|
if (str[i] == '-') {
|
||||||
|
sign = -1.0;
|
||||||
|
i++;
|
||||||
|
} else if (*str == '+') {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
f64 value = 0.0;
|
||||||
|
for (; i < len; i++) {
|
||||||
|
Rune r = cast(Rune)str[i];
|
||||||
|
if (r == '_') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!gb_char_is_digit(r)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i64 v = r - '0';
|
||||||
|
value *= 10.0;
|
||||||
|
value += v;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str[i] == '.') {
|
||||||
|
f64 pow10 = 10.0;
|
||||||
|
i++;
|
||||||
|
for (; i < string.len; i++) {
|
||||||
|
Rune r = cast(Rune)str[i];
|
||||||
|
if (r == '_') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!gb_char_is_digit(r)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
value += (r-'0')/pow10;
|
||||||
|
pow10 *= 10.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f64 frac = 0;
|
||||||
|
f64 scale = 1.0;
|
||||||
|
if ((str[i] == 'e') || (str[i] == 'E')) {
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if (str[i] == '-') {
|
||||||
|
frac = 1;
|
||||||
|
i++;
|
||||||
|
} else if (str[i] == '+') {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 exp;
|
||||||
|
for (exp = 0; gb_char_is_digit(str[i]); i++) {
|
||||||
|
exp = exp * 10 + (str[i]-'0');
|
||||||
|
}
|
||||||
|
if (exp > 308) exp = 308;
|
||||||
|
|
||||||
|
while (exp >= 50) { scale *= 1e50; exp -= 50; }
|
||||||
|
while (exp >= 8) { scale *= 1e8; exp -= 8; }
|
||||||
|
while (exp > 0) { scale *= 10.0; exp -= 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
f64 result = sign * (frac ? (value / scale) : (value * scale));
|
||||||
|
return make_exact_value_float(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ExactValue make_exact_value_from_basic_literal(Token token) {
|
ExactValue make_exact_value_from_basic_literal(Token token) {
|
||||||
switch (token.kind) {
|
switch (token.kind) {
|
||||||
case Token_String: return make_exact_value_string(token.string);
|
case Token_String: return make_exact_value_string(token.string);
|
||||||
@@ -182,8 +274,7 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
|
|||||||
case ExactValue_Invalid:
|
case ExactValue_Invalid:
|
||||||
return v;
|
return v;
|
||||||
case ExactValue_Integer:
|
case ExactValue_Integer:
|
||||||
i = v.value_integer;
|
i = ~v.value_integer;
|
||||||
i = ~i;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
goto failure;
|
goto failure;
|
||||||
@@ -191,8 +282,10 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
|
|||||||
|
|
||||||
// NOTE(bill): unsigned integers will be negative and will need to be
|
// NOTE(bill): unsigned integers will be negative and will need to be
|
||||||
// limited to the types precision
|
// limited to the types precision
|
||||||
if (precision > 0)
|
// IMPORTANT NOTE(bill): Max precision is 64 bits as that's how integers are stored
|
||||||
|
if (0 < precision && precision < 64) {
|
||||||
i &= ~((~0ll)<<precision);
|
i &= ~((~0ll)<<precision);
|
||||||
|
}
|
||||||
|
|
||||||
return make_exact_value_integer(i);
|
return make_exact_value_integer(i);
|
||||||
} break;
|
} break;
|
||||||
@@ -306,6 +399,7 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
|
|||||||
case Token_Shr: c = a >> b; break;
|
case Token_Shr: c = a >> b; break;
|
||||||
default: goto error;
|
default: goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return make_exact_value_integer(c);
|
return make_exact_value_integer(c);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@@ -323,6 +417,7 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
|
|||||||
}
|
}
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
; // MSVC accepts this??? apparently you cannot declare variables immediately after labels...
|
||||||
ExactValue error_value = {0};
|
ExactValue error_value = {0};
|
||||||
// gb_printf_err("Invalid binary operation: %s\n", token_kind_to_string(op));
|
// gb_printf_err("Invalid binary operation: %s\n", token_kind_to_string(op));
|
||||||
return error_value;
|
return error_value;
|
||||||
|
|||||||
+119
-24
@@ -1,4 +1,4 @@
|
|||||||
/* gb.h - v0.26d - Ginger Bill's C Helper Library - public domain
|
/* gb.h - v0.27 - Ginger Bill's C Helper Library - public domain
|
||||||
- no warranty implied; use at your own risk
|
- no warranty implied; use at your own risk
|
||||||
|
|
||||||
This is a single header file with a bunch of useful stuff
|
This is a single header file with a bunch of useful stuff
|
||||||
@@ -58,6 +58,7 @@ TODOS
|
|||||||
- More date & time functions
|
- More date & time functions
|
||||||
|
|
||||||
VERSION HISTORY
|
VERSION HISTORY
|
||||||
|
0.27 - OSX fixes and Linux gbAffinity
|
||||||
0.26d - Minor changes to how gbFile works
|
0.26d - Minor changes to how gbFile works
|
||||||
0.26c - gb_str_to_f* fix
|
0.26c - gb_str_to_f* fix
|
||||||
0.26b - Minor fixes
|
0.26b - Minor fixes
|
||||||
@@ -276,6 +277,8 @@ extern "C" {
|
|||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(GB_SYSTEM_WINDOWS)
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
#if !defined(GB_NO_WINDOWS_H)
|
#if !defined(GB_NO_WINDOWS_H)
|
||||||
#define NOMINMAX 1
|
#define NOMINMAX 1
|
||||||
@@ -296,6 +299,9 @@ extern "C" {
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
#ifndef _IOSC11_SOURCE
|
||||||
|
#define _IOSC11_SOURCE
|
||||||
|
#endif
|
||||||
#include <stdlib.h> // NOTE(bill): malloc on linux
|
#include <stdlib.h> // NOTE(bill): malloc on linux
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#if !defined(GB_SYSTEM_OSX)
|
#if !defined(GB_SYSTEM_OSX)
|
||||||
@@ -309,18 +315,18 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(GB_SYSTEM_OSX)
|
#if defined(GB_SYSTEM_OSX)
|
||||||
#include <mach/mach.h>
|
#include <mach/mach.h>
|
||||||
#include <mach/mach_init.h>
|
#include <mach/mach_init.h>
|
||||||
#include <mach/mach_time.h>
|
#include <mach/mach_time.h>
|
||||||
#include <mach/thread_act.h>
|
#include <mach/thread_act.h>
|
||||||
#include <mach/thread_policy.h>
|
#include <mach/thread_policy.h>
|
||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
#include <copyfile.h>
|
#include <copyfile.h>
|
||||||
#include <mach/clock.h>
|
#include <mach/clock.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(GB_SYSTEM_UNIX)
|
#if defined(GB_SYSTEM_UNIX)
|
||||||
#include <semaphore.h>
|
#include <semaphore.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -699,7 +705,7 @@ extern "C++" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef gb_is_between
|
#ifndef gb_is_between
|
||||||
#define gb_is_between(x, lower, upper) (((x) >= (lower)) && ((x) <= (upper)))
|
#define gb_is_between(x, lower, upper) (((lower) <= (x)) && ((x) <= (upper)))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef gb_abs
|
#ifndef gb_abs
|
||||||
@@ -1003,7 +1009,12 @@ typedef struct gbAffinity {
|
|||||||
} gbAffinity;
|
} gbAffinity;
|
||||||
|
|
||||||
#elif defined(GB_SYSTEM_LINUX)
|
#elif defined(GB_SYSTEM_LINUX)
|
||||||
#error TODO(bill): Implement gbAffinity for linux
|
typedef struct gbAffinity {
|
||||||
|
b32 is_accurate;
|
||||||
|
isize core_count;
|
||||||
|
isize thread_count;
|
||||||
|
isize threads_per_core;
|
||||||
|
} gbAffinity;
|
||||||
#else
|
#else
|
||||||
#error TODO(bill): Unknown system
|
#error TODO(bill): Unknown system
|
||||||
#endif
|
#endif
|
||||||
@@ -4112,7 +4123,7 @@ gb_inline i64 gb_atomic64_fetch_and(gbAtomic64 volatile *a, i64 operand) {
|
|||||||
|
|
||||||
gb_inline i64 gb_atomic64_fetch_or(gbAtomic64 volatile *a, i64 operand) {
|
gb_inline i64 gb_atomic64_fetch_or(gbAtomic64 volatile *a, i64 operand) {
|
||||||
#if defined(GB_ARCH_64_BIT)
|
#if defined(GB_ARCH_64_BIT)
|
||||||
return _InterlockedAnd64(cast(i64 volatile *)a, operand);
|
return _InterlockedOr64(cast(i64 volatile *)a, operand);
|
||||||
#elif GB_CPU_X86
|
#elif GB_CPU_X86
|
||||||
i64 expected = a->value;
|
i64 expected = a->value;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@@ -4819,18 +4830,15 @@ GB_ALLOCATOR_PROC(gb_heap_allocator_proc) {
|
|||||||
#else
|
#else
|
||||||
// TODO(bill): *nix version that's decent
|
// TODO(bill): *nix version that's decent
|
||||||
case gbAllocation_Alloc: {
|
case gbAllocation_Alloc: {
|
||||||
gbAllocationHeader *header;
|
posix_memalign(&ptr, alignment, size);
|
||||||
isize total_size = size + alignment + gb_size_of(gbAllocationHeader);
|
|
||||||
ptr = malloc(total_size);
|
if (flags & gbAllocatorFlag_ClearToZero) {
|
||||||
header = cast(gbAllocationHeader *)ptr;
|
|
||||||
ptr = gb_align_forward(header+1, alignment);
|
|
||||||
gb_allocation_header_fill(header, ptr, size);
|
|
||||||
if (flags & gbAllocatorFlag_ClearToZero)
|
|
||||||
gb_zero_size(ptr, size);
|
gb_zero_size(ptr, size);
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case gbAllocation_Free: {
|
case gbAllocation_Free: {
|
||||||
free(gb_allocation_header(old_memory));
|
free(old_memory);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case gbAllocation_Resize: {
|
case gbAllocation_Resize: {
|
||||||
@@ -4927,7 +4935,7 @@ isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) {
|
|||||||
void gb_affinity_init(gbAffinity *a) {
|
void gb_affinity_init(gbAffinity *a) {
|
||||||
usize count, count_size = gb_size_of(count);
|
usize count, count_size = gb_size_of(count);
|
||||||
|
|
||||||
a->is_accurate = false;
|
a->is_accurate = false;
|
||||||
a->thread_count = 1;
|
a->thread_count = 1;
|
||||||
a->core_count = 1;
|
a->core_count = 1;
|
||||||
a->threads_per_core = 1;
|
a->threads_per_core = 1;
|
||||||
@@ -4977,7 +4985,83 @@ isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(GB_SYSTEM_LINUX)
|
#elif defined(GB_SYSTEM_LINUX)
|
||||||
#error TODO(bill): Implement gbAffinity for linux
|
// IMPORTANT TODO(bill): This gbAffinity stuff for linux needs be improved a lot!
|
||||||
|
// NOTE(zangent): I have to read /proc/cpuinfo to get the number of threads per core.
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
void gb_affinity_init(gbAffinity *a) {
|
||||||
|
b32 accurate = true;
|
||||||
|
isize threads = 0;
|
||||||
|
|
||||||
|
a->thread_count = 1;
|
||||||
|
a->core_count = sysconf(_SC_NPROCESSORS_ONLN);
|
||||||
|
a->threads_per_core = 1;
|
||||||
|
|
||||||
|
|
||||||
|
if(a->core_count <= 0) {
|
||||||
|
a->core_count = 1;
|
||||||
|
accurate = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parsing /proc/cpuinfo to get the number of threads per core.
|
||||||
|
// NOTE(zangent): This calls the CPU's threads "cores", although the wording
|
||||||
|
// is kind of weird. This should be right, though.
|
||||||
|
if (fopen("/proc/cpuinfo", "r") != NULL) {
|
||||||
|
for (;;) {
|
||||||
|
// The 'temporary char'. Everything goes into this char,
|
||||||
|
// so that we can check against EOF at the end of this loop.
|
||||||
|
char c;
|
||||||
|
|
||||||
|
#define AF__CHECK(letter) ((c = getc(cpu_info)) == letter)
|
||||||
|
if (AF__CHECK('c') && AF__CHECK('p') && AF__CHECK('u') && AF__CHECK(' ') &&
|
||||||
|
AF__CHECK('c') && AF__CHECK('o') && AF__CHECK('r') && AF__CHECK('e') && AF__CHECK('s')) {
|
||||||
|
// We're on a CPU info line.
|
||||||
|
while (!AF__CHECK(EOF)) {
|
||||||
|
if (c == '\n') {
|
||||||
|
break;
|
||||||
|
} else if (c < '0' || '9' > c) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
threads = threads * 10 + (c - '0');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
while (!AF__CHECK('\n')) {
|
||||||
|
if (c==EOF) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (c == EOF) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#undef AF__CHECK
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (threads == 0) {
|
||||||
|
threads = 1;
|
||||||
|
accurate = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
a->threads_per_core = threads;
|
||||||
|
a->thread_count = a->threads_per_core * a->core_count;
|
||||||
|
a->is_accurate = accurate;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void gb_affinity_destroy(gbAffinity *a) {
|
||||||
|
gb_unused(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
b32 gb_affinity_set(gbAffinity *a, isize core, isize thread_index) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) {
|
||||||
|
GB_ASSERT(0 <= core && core < a->core_count);
|
||||||
|
return a->threads_per_core;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
#error TODO(bill): Unknown system
|
#error TODO(bill): Unknown system
|
||||||
#endif
|
#endif
|
||||||
@@ -7758,7 +7842,18 @@ char *gb_path_get_full_name(gbAllocator a, char const *path) {
|
|||||||
return gb_alloc_str_len(a, buf, len+1);
|
return gb_alloc_str_len(a, buf, len+1);
|
||||||
#else
|
#else
|
||||||
// TODO(bill): Make work on *nix, etc.
|
// TODO(bill): Make work on *nix, etc.
|
||||||
return gb_alloc_str_len(a, path, gb_strlen(path));
|
char* p = realpath(path, 0);
|
||||||
|
GB_ASSERT(p && "file does not exist");
|
||||||
|
|
||||||
|
isize len = gb_strlen(p);
|
||||||
|
|
||||||
|
// bill... gb_alloc_str_len refused to work for this...
|
||||||
|
char* ret = gb_alloc(a, sizeof(char) * len + 1);
|
||||||
|
gb_memmove(ret, p, len);
|
||||||
|
ret[len] = 0;
|
||||||
|
free(p);
|
||||||
|
|
||||||
|
return ret;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+128
-130
@@ -1,95 +1,93 @@
|
|||||||
// Optimizations for the SSA code
|
// Optimizations for the IR code
|
||||||
|
|
||||||
void ssa_opt_add_operands(ssaValueArray *ops, ssaInstr *i) {
|
void ir_opt_add_operands(irValueArray *ops, irInstr *i) {
|
||||||
switch (i->kind) {
|
switch (i->kind) {
|
||||||
case ssaInstr_Comment:
|
case irInstr_Comment:
|
||||||
break;
|
break;
|
||||||
case ssaInstr_Local:
|
case irInstr_Local:
|
||||||
break;
|
break;
|
||||||
case ssaInstr_ZeroInit:
|
case irInstr_ZeroInit:
|
||||||
array_add(ops, i->ZeroInit.address);
|
array_add(ops, i->ZeroInit.address);
|
||||||
break;
|
break;
|
||||||
case ssaInstr_Store:
|
case irInstr_Store:
|
||||||
array_add(ops, i->Store.address);
|
array_add(ops, i->Store.address);
|
||||||
array_add(ops, i->Store.value);
|
array_add(ops, i->Store.value);
|
||||||
break;
|
break;
|
||||||
case ssaInstr_Load:
|
case irInstr_Load:
|
||||||
array_add(ops, i->Load.address);
|
array_add(ops, i->Load.address);
|
||||||
break;
|
break;
|
||||||
case ssaInstr_ArrayElementPtr:
|
case irInstr_ArrayElementPtr:
|
||||||
array_add(ops, i->ArrayElementPtr.address);
|
array_add(ops, i->ArrayElementPtr.address);
|
||||||
array_add(ops, i->ArrayElementPtr.elem_index);
|
array_add(ops, i->ArrayElementPtr.elem_index);
|
||||||
break;
|
break;
|
||||||
case ssaInstr_StructElementPtr:
|
case irInstr_StructElementPtr:
|
||||||
array_add(ops, i->StructElementPtr.address);
|
array_add(ops, i->StructElementPtr.address);
|
||||||
break;
|
break;
|
||||||
case ssaInstr_PtrOffset:
|
case irInstr_PtrOffset:
|
||||||
array_add(ops, i->PtrOffset.address);
|
array_add(ops, i->PtrOffset.address);
|
||||||
array_add(ops, i->PtrOffset.offset);
|
array_add(ops, i->PtrOffset.offset);
|
||||||
break;
|
break;
|
||||||
case ssaInstr_ArrayExtractValue:
|
case irInstr_StructExtractValue:
|
||||||
array_add(ops, i->ArrayExtractValue.address);
|
|
||||||
break;
|
|
||||||
case ssaInstr_StructExtractValue:
|
|
||||||
array_add(ops, i->StructExtractValue.address);
|
array_add(ops, i->StructExtractValue.address);
|
||||||
break;
|
break;
|
||||||
case ssaInstr_Conv:
|
case irInstr_Conv:
|
||||||
array_add(ops, i->Conv.value);
|
array_add(ops, i->Conv.value);
|
||||||
break;
|
break;
|
||||||
case ssaInstr_Jump:
|
case irInstr_Jump:
|
||||||
break;
|
break;
|
||||||
case ssaInstr_If:
|
case irInstr_If:
|
||||||
array_add(ops, i->If.cond);
|
array_add(ops, i->If.cond);
|
||||||
break;
|
break;
|
||||||
case ssaInstr_Return:
|
case irInstr_Return:
|
||||||
if (i->Return.value != NULL) {
|
if (i->Return.value != NULL) {
|
||||||
array_add(ops, i->Return.value);
|
array_add(ops, i->Return.value);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ssaInstr_Select:
|
case irInstr_Select:
|
||||||
array_add(ops, i->Select.cond);
|
array_add(ops, i->Select.cond);
|
||||||
break;
|
break;
|
||||||
case ssaInstr_Phi:
|
case irInstr_Phi:
|
||||||
for_array(j, i->Phi.edges) {
|
for_array(j, i->Phi.edges) {
|
||||||
array_add(ops, i->Phi.edges.e[j]);
|
array_add(ops, i->Phi.edges.e[j]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ssaInstr_Unreachable: break;
|
case irInstr_Unreachable:
|
||||||
case ssaInstr_BinaryOp:
|
break;
|
||||||
|
case irInstr_UnaryOp:
|
||||||
|
array_add(ops, i->UnaryOp.expr);
|
||||||
|
break;
|
||||||
|
case irInstr_BinaryOp:
|
||||||
array_add(ops, i->BinaryOp.left);
|
array_add(ops, i->BinaryOp.left);
|
||||||
array_add(ops, i->BinaryOp.right);
|
array_add(ops, i->BinaryOp.right);
|
||||||
break;
|
break;
|
||||||
case ssaInstr_Call:
|
case irInstr_Call:
|
||||||
array_add(ops, i->Call.value);
|
array_add(ops, i->Call.value);
|
||||||
for (isize j = 0; j < i->Call.arg_count; j++) {
|
for (isize j = 0; j < i->Call.arg_count; j++) {
|
||||||
array_add(ops, i->Call.args[j]);
|
array_add(ops, i->Call.args[j]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ssaInstr_VectorExtractElement:
|
// case irInstr_VectorExtractElement:
|
||||||
array_add(ops, i->VectorExtractElement.vector);
|
// array_add(ops, i->VectorExtractElement.vector);
|
||||||
array_add(ops, i->VectorExtractElement.index);
|
// array_add(ops, i->VectorExtractElement.index);
|
||||||
|
// break;
|
||||||
|
// case irInstr_VectorInsertElement:
|
||||||
|
// array_add(ops, i->VectorInsertElement.vector);
|
||||||
|
// array_add(ops, i->VectorInsertElement.elem);
|
||||||
|
// array_add(ops, i->VectorInsertElement.index);
|
||||||
|
// break;
|
||||||
|
// case irInstr_VectorShuffle:
|
||||||
|
// array_add(ops, i->VectorShuffle.vector);
|
||||||
|
// break;
|
||||||
|
case irInstr_StartupRuntime:
|
||||||
break;
|
break;
|
||||||
case ssaInstr_VectorInsertElement:
|
case irInstr_BoundsCheck:
|
||||||
array_add(ops, i->VectorInsertElement.vector);
|
|
||||||
array_add(ops, i->VectorInsertElement.elem);
|
|
||||||
array_add(ops, i->VectorInsertElement.index);
|
|
||||||
break;
|
|
||||||
case ssaInstr_VectorShuffle:
|
|
||||||
array_add(ops, i->VectorShuffle.vector);
|
|
||||||
break;
|
|
||||||
case ssaInstr_StartupRuntime:
|
|
||||||
break;
|
|
||||||
case ssaInstr_BoundsCheck:
|
|
||||||
array_add(ops, i->BoundsCheck.index);
|
array_add(ops, i->BoundsCheck.index);
|
||||||
array_add(ops, i->BoundsCheck.len);
|
array_add(ops, i->BoundsCheck.len);
|
||||||
break;
|
break;
|
||||||
case ssaInstr_SliceBoundsCheck:
|
case irInstr_SliceBoundsCheck:
|
||||||
array_add(ops, i->SliceBoundsCheck.low);
|
array_add(ops, i->SliceBoundsCheck.low);
|
||||||
array_add(ops, i->SliceBoundsCheck.high);
|
array_add(ops, i->SliceBoundsCheck.high);
|
||||||
array_add(ops, i->SliceBoundsCheck.max);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,26 +95,26 @@ void ssa_opt_add_operands(ssaValueArray *ops, ssaInstr *i) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void ssa_opt_block_replace_pred(ssaBlock *b, ssaBlock *from, ssaBlock *to) {
|
void ir_opt_block_replace_pred(irBlock *b, irBlock *from, irBlock *to) {
|
||||||
for_array(i, b->preds) {
|
for_array(i, b->preds) {
|
||||||
ssaBlock *pred = b->preds.e[i];
|
irBlock *pred = b->preds.e[i];
|
||||||
if (pred == from) {
|
if (pred == from) {
|
||||||
b->preds.e[i] = to;
|
b->preds.e[i] = to;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ssa_opt_block_replace_succ(ssaBlock *b, ssaBlock *from, ssaBlock *to) {
|
void ir_opt_block_replace_succ(irBlock *b, irBlock *from, irBlock *to) {
|
||||||
for_array(i, b->succs) {
|
for_array(i, b->succs) {
|
||||||
ssaBlock *succ = b->succs.e[i];
|
irBlock *succ = b->succs.e[i];
|
||||||
if (succ == from) {
|
if (succ == from) {
|
||||||
b->succs.e[i] = to;
|
b->succs.e[i] = to;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ssa_opt_block_has_phi(ssaBlock *b) {
|
bool ir_opt_block_has_phi(irBlock *b) {
|
||||||
return b->instrs.e[0]->Instr.kind == ssaInstr_Phi;
|
return b->instrs.e[0]->Instr.kind == irInstr_Phi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -128,11 +126,11 @@ bool ssa_opt_block_has_phi(ssaBlock *b) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
ssaValueArray ssa_get_block_phi_nodes(ssaBlock *b) {
|
irValueArray ir_get_block_phi_nodes(irBlock *b) {
|
||||||
ssaValueArray phis = {0};
|
irValueArray phis = {0};
|
||||||
for_array(i, b->instrs) {
|
for_array(i, b->instrs) {
|
||||||
ssaInstr *instr = &b->instrs.e[i]->Instr;
|
irInstr *instr = &b->instrs.e[i]->Instr;
|
||||||
if (instr->kind != ssaInstr_Phi) {
|
if (instr->kind != irInstr_Phi) {
|
||||||
phis = b->instrs;
|
phis = b->instrs;
|
||||||
phis.count = i;
|
phis.count = i;
|
||||||
return phis;
|
return phis;
|
||||||
@@ -141,15 +139,15 @@ ssaValueArray ssa_get_block_phi_nodes(ssaBlock *b) {
|
|||||||
return phis;
|
return phis;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ssa_remove_pred(ssaBlock *b, ssaBlock *p) {
|
void ir_remove_pred(irBlock *b, irBlock *p) {
|
||||||
ssaValueArray phis = ssa_get_block_phi_nodes(b);
|
irValueArray phis = ir_get_block_phi_nodes(b);
|
||||||
isize i = 0;
|
isize i = 0;
|
||||||
for_array(j, b->preds) {
|
for_array(j, b->preds) {
|
||||||
ssaBlock *pred = b->preds.e[j];
|
irBlock *pred = b->preds.e[j];
|
||||||
if (pred != p) {
|
if (pred != p) {
|
||||||
b->preds.e[i] = b->preds.e[j];
|
b->preds.e[i] = b->preds.e[j];
|
||||||
for_array(k, phis) {
|
for_array(k, phis) {
|
||||||
ssaInstrPhi *phi = &phis.e[k]->Instr.Phi;
|
irInstrPhi *phi = &phis.e[k]->Instr.Phi;
|
||||||
phi->edges.e[i] = phi->edges.e[j];
|
phi->edges.e[i] = phi->edges.e[j];
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
@@ -157,16 +155,16 @@ void ssa_remove_pred(ssaBlock *b, ssaBlock *p) {
|
|||||||
}
|
}
|
||||||
b->preds.count = i;
|
b->preds.count = i;
|
||||||
for_array(k, phis) {
|
for_array(k, phis) {
|
||||||
ssaInstrPhi *phi = &phis.e[k]->Instr.Phi;
|
irInstrPhi *phi = &phis.e[k]->Instr.Phi;
|
||||||
phi->edges.count = i;
|
phi->edges.count = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ssa_remove_dead_blocks(ssaProcedure *proc) {
|
void ir_remove_dead_blocks(irProcedure *proc) {
|
||||||
isize j = 0;
|
isize j = 0;
|
||||||
for_array(i, proc->blocks) {
|
for_array(i, proc->blocks) {
|
||||||
ssaBlock *b = proc->blocks.e[i];
|
irBlock *b = proc->blocks.e[i];
|
||||||
if (b == NULL) {
|
if (b == NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -177,34 +175,34 @@ void ssa_remove_dead_blocks(ssaProcedure *proc) {
|
|||||||
proc->blocks.count = j;
|
proc->blocks.count = j;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ssa_mark_reachable(ssaBlock *b) {
|
void ir_mark_reachable(irBlock *b) {
|
||||||
isize const WHITE = 0;
|
isize const WHITE = 0;
|
||||||
isize const BLACK = -1;
|
isize const BLACK = -1;
|
||||||
b->index = BLACK;
|
b->index = BLACK;
|
||||||
for_array(i, b->succs) {
|
for_array(i, b->succs) {
|
||||||
ssaBlock *succ = b->succs.e[i];
|
irBlock *succ = b->succs.e[i];
|
||||||
if (succ->index == WHITE) {
|
if (succ->index == WHITE) {
|
||||||
ssa_mark_reachable(succ);
|
ir_mark_reachable(succ);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ssa_remove_unreachable_blocks(ssaProcedure *proc) {
|
void ir_remove_unreachable_blocks(irProcedure *proc) {
|
||||||
isize const WHITE = 0;
|
isize const WHITE = 0;
|
||||||
isize const BLACK = -1;
|
isize const BLACK = -1;
|
||||||
for_array(i, proc->blocks) {
|
for_array(i, proc->blocks) {
|
||||||
proc->blocks.e[i]->index = WHITE;
|
proc->blocks.e[i]->index = WHITE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssa_mark_reachable(proc->blocks.e[0]);
|
ir_mark_reachable(proc->blocks.e[0]);
|
||||||
|
|
||||||
for_array(i, proc->blocks) {
|
for_array(i, proc->blocks) {
|
||||||
ssaBlock *b = proc->blocks.e[i];
|
irBlock *b = proc->blocks.e[i];
|
||||||
if (b->index == WHITE) {
|
if (b->index == WHITE) {
|
||||||
for_array(j, b->succs) {
|
for_array(j, b->succs) {
|
||||||
ssaBlock *c = b->succs.e[j];
|
irBlock *c = b->succs.e[j];
|
||||||
if (c->index == BLACK) {
|
if (c->index == BLACK) {
|
||||||
ssa_remove_pred(c, b);
|
ir_remove_pred(c, b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// NOTE(bill): Mark as empty but don't actually free it
|
// NOTE(bill): Mark as empty but don't actually free it
|
||||||
@@ -212,26 +210,26 @@ void ssa_remove_unreachable_blocks(ssaProcedure *proc) {
|
|||||||
proc->blocks.e[i] = NULL;
|
proc->blocks.e[i] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ssa_remove_dead_blocks(proc);
|
ir_remove_dead_blocks(proc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ssa_opt_block_fusion(ssaProcedure *proc, ssaBlock *a) {
|
bool ir_opt_block_fusion(irProcedure *proc, irBlock *a) {
|
||||||
if (a->succs.count != 1) {
|
if (a->succs.count != 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ssaBlock *b = a->succs.e[0];
|
irBlock *b = a->succs.e[0];
|
||||||
if (b->preds.count != 1) {
|
if (b->preds.count != 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ssa_opt_block_has_phi(b)) {
|
if (ir_opt_block_has_phi(b)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
array_pop(&a->instrs); // Remove branch at end
|
array_pop(&a->instrs); // Remove branch at end
|
||||||
for_array(i, b->instrs) {
|
for_array(i, b->instrs) {
|
||||||
array_add(&a->instrs, b->instrs.e[i]);
|
array_add(&a->instrs, b->instrs.e[i]);
|
||||||
ssa_set_instr_parent(b->instrs.e[i], a);
|
ir_set_instr_parent(b->instrs.e[i], a);
|
||||||
}
|
}
|
||||||
|
|
||||||
array_clear(&a->succs);
|
array_clear(&a->succs);
|
||||||
@@ -241,28 +239,28 @@ bool ssa_opt_block_fusion(ssaProcedure *proc, ssaBlock *a) {
|
|||||||
|
|
||||||
// Fix preds links
|
// Fix preds links
|
||||||
for_array(i, b->succs) {
|
for_array(i, b->succs) {
|
||||||
ssa_opt_block_replace_pred(b->succs.e[i], b, a);
|
ir_opt_block_replace_pred(b->succs.e[i], b, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
proc->blocks.e[b->index] = NULL;
|
proc->blocks.e[b->index] = NULL;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ssa_opt_blocks(ssaProcedure *proc) {
|
void ir_opt_blocks(irProcedure *proc) {
|
||||||
ssa_remove_unreachable_blocks(proc);
|
ir_remove_unreachable_blocks(proc);
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
bool changed = true;
|
bool changed = true;
|
||||||
while (changed) {
|
while (changed) {
|
||||||
changed = false;
|
changed = false;
|
||||||
for_array(i, proc->blocks) {
|
for_array(i, proc->blocks) {
|
||||||
ssaBlock *b = proc->blocks.e[i];
|
irBlock *b = proc->blocks.e[i];
|
||||||
if (b == NULL) {
|
if (b == NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
GB_ASSERT(b->index == i);
|
GB_ASSERT_MSG(b->index == i, "%d, %td", b->index, i);
|
||||||
|
|
||||||
if (ssa_opt_block_fusion(proc, b)) {
|
if (ir_opt_block_fusion(proc, b)) {
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
// TODO(bill): other simple block optimizations
|
// TODO(bill): other simple block optimizations
|
||||||
@@ -270,25 +268,25 @@ void ssa_opt_blocks(ssaProcedure *proc) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ssa_remove_dead_blocks(proc);
|
ir_remove_dead_blocks(proc);
|
||||||
}
|
}
|
||||||
void ssa_opt_build_referrers(ssaProcedure *proc) {
|
void ir_opt_build_referrers(irProcedure *proc) {
|
||||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena);
|
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena);
|
||||||
|
|
||||||
ssaValueArray ops = {0}; // NOTE(bill): Act as a buffer
|
irValueArray ops = {0}; // NOTE(bill): Act as a buffer
|
||||||
array_init_reserve(&ops, proc->module->tmp_allocator, 64); // HACK(bill): This _could_ overflow the temp arena
|
array_init_reserve(&ops, proc->module->tmp_allocator, 64); // HACK(bill): This _could_ overflow the temp arena
|
||||||
for_array(i, proc->blocks) {
|
for_array(i, proc->blocks) {
|
||||||
ssaBlock *b = proc->blocks.e[i];
|
irBlock *b = proc->blocks.e[i];
|
||||||
for_array(j, b->instrs) {
|
for_array(j, b->instrs) {
|
||||||
ssaValue *instr = b->instrs.e[j];
|
irValue *instr = b->instrs.e[j];
|
||||||
array_clear(&ops);
|
array_clear(&ops);
|
||||||
ssa_opt_add_operands(&ops, &instr->Instr);
|
ir_opt_add_operands(&ops, &instr->Instr);
|
||||||
for_array(k, ops) {
|
for_array(k, ops) {
|
||||||
ssaValue *op = ops.e[k];
|
irValue *op = ops.e[k];
|
||||||
if (op == NULL) {
|
if (op == NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ssaValueArray *refs = ssa_value_referrers(op);
|
irValueArray *refs = ir_value_referrers(op);
|
||||||
if (refs != NULL) {
|
if (refs != NULL) {
|
||||||
array_add(refs, instr);
|
array_add(refs, instr);
|
||||||
}
|
}
|
||||||
@@ -307,36 +305,36 @@ void ssa_opt_build_referrers(ssaProcedure *proc) {
|
|||||||
|
|
||||||
// State of Lengauer-Tarjan algorithm
|
// State of Lengauer-Tarjan algorithm
|
||||||
// Based on this paper: http://jgaa.info/accepted/2006/GeorgiadisTarjanWerneck2006.10.1.pdf
|
// Based on this paper: http://jgaa.info/accepted/2006/GeorgiadisTarjanWerneck2006.10.1.pdf
|
||||||
typedef struct ssaLTState {
|
typedef struct irLTState {
|
||||||
isize count;
|
isize count;
|
||||||
// NOTE(bill): These are arrays
|
// NOTE(bill): These are arrays
|
||||||
ssaBlock **sdom; // Semidominator
|
irBlock **sdom; // Semidominator
|
||||||
ssaBlock **parent; // Parent in DFS traversal of CFG
|
irBlock **parent; // Parent in DFS traversal of CFG
|
||||||
ssaBlock **ancestor;
|
irBlock **ancestor;
|
||||||
} ssaLTState;
|
} irLTState;
|
||||||
|
|
||||||
// §2.2 - bottom of page
|
// §2.2 - bottom of page
|
||||||
void ssa_lt_link(ssaLTState *lt, ssaBlock *p, ssaBlock *q) {
|
void ir_lt_link(irLTState *lt, irBlock *p, irBlock *q) {
|
||||||
lt->ancestor[q->index] = p;
|
lt->ancestor[q->index] = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
i32 ssa_lt_depth_first_search(ssaLTState *lt, ssaBlock *p, i32 i, ssaBlock **preorder) {
|
i32 ir_lt_depth_first_search(irLTState *lt, irBlock *p, i32 i, irBlock **preorder) {
|
||||||
preorder[i] = p;
|
preorder[i] = p;
|
||||||
p->dom.pre = i++;
|
p->dom.pre = i++;
|
||||||
lt->sdom[p->index] = p;
|
lt->sdom[p->index] = p;
|
||||||
ssa_lt_link(lt, NULL, p);
|
ir_lt_link(lt, NULL, p);
|
||||||
for_array(index, p->succs) {
|
for_array(index, p->succs) {
|
||||||
ssaBlock *q = p->succs.e[index];
|
irBlock *q = p->succs.e[index];
|
||||||
if (lt->sdom[q->index] == NULL) {
|
if (lt->sdom[q->index] == NULL) {
|
||||||
lt->parent[q->index] = p;
|
lt->parent[q->index] = p;
|
||||||
i = ssa_lt_depth_first_search(lt, q, i, preorder);
|
i = ir_lt_depth_first_search(lt, q, i, preorder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssaBlock *ssa_lt_eval(ssaLTState *lt, ssaBlock *v) {
|
irBlock *ir_lt_eval(irLTState *lt, irBlock *v) {
|
||||||
ssaBlock *u = v;
|
irBlock *u = v;
|
||||||
for (;
|
for (;
|
||||||
lt->ancestor[v->index] != NULL;
|
lt->ancestor[v->index] != NULL;
|
||||||
v = lt->ancestor[v->index]) {
|
v = lt->ancestor[v->index]) {
|
||||||
@@ -347,16 +345,16 @@ ssaBlock *ssa_lt_eval(ssaLTState *lt, ssaBlock *v) {
|
|||||||
return u;
|
return u;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct ssaDomPrePost {
|
typedef struct irDomPrePost {
|
||||||
i32 pre, post;
|
i32 pre, post;
|
||||||
} ssaDomPrePost;
|
} irDomPrePost;
|
||||||
|
|
||||||
ssaDomPrePost ssa_opt_number_dom_tree(ssaBlock *v, i32 pre, i32 post) {
|
irDomPrePost ir_opt_number_dom_tree(irBlock *v, i32 pre, i32 post) {
|
||||||
ssaDomPrePost result = {pre, post};
|
irDomPrePost result = {pre, post};
|
||||||
|
|
||||||
v->dom.pre = pre++;
|
v->dom.pre = pre++;
|
||||||
for_array(i, v->dom.children) {
|
for_array(i, v->dom.children) {
|
||||||
result = ssa_opt_number_dom_tree(v->dom.children.e[i], result.pre, result.post);
|
result = ir_opt_number_dom_tree(v->dom.children.e[i], result.pre, result.post);
|
||||||
}
|
}
|
||||||
v->dom.post = post++;
|
v->dom.post = post++;
|
||||||
|
|
||||||
@@ -366,35 +364,35 @@ ssaDomPrePost ssa_opt_number_dom_tree(ssaBlock *v, i32 pre, i32 post) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// NOTE(bill): Requires `ssa_opt_blocks` to be called before this
|
// NOTE(bill): Requires `ir_opt_blocks` to be called before this
|
||||||
void ssa_opt_build_dom_tree(ssaProcedure *proc) {
|
void ir_opt_build_dom_tree(irProcedure *proc) {
|
||||||
// Based on this paper: http://jgaa.info/accepted/2006/GeorgiadisTarjanWerneck2006.10.1.pdf
|
// Based on this paper: http://jgaa.info/accepted/2006/GeorgiadisTarjanWerneck2006.10.1.pdf
|
||||||
|
|
||||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena);
|
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena);
|
||||||
|
|
||||||
isize n = proc->blocks.count;
|
isize n = proc->blocks.count;
|
||||||
ssaBlock **buf = gb_alloc_array(proc->module->tmp_allocator, ssaBlock *, 5*n);
|
irBlock **buf = gb_alloc_array(proc->module->tmp_allocator, irBlock *, 5*n);
|
||||||
|
|
||||||
ssaLTState lt = {0};
|
irLTState lt = {0};
|
||||||
lt.count = n;
|
lt.count = n;
|
||||||
lt.sdom = &buf[0*n];
|
lt.sdom = &buf[0*n];
|
||||||
lt.parent = &buf[1*n];
|
lt.parent = &buf[1*n];
|
||||||
lt.ancestor = &buf[2*n];
|
lt.ancestor = &buf[2*n];
|
||||||
|
|
||||||
ssaBlock **preorder = &buf[3*n];
|
irBlock **preorder = &buf[3*n];
|
||||||
ssaBlock **buckets = &buf[4*n];
|
irBlock **buckets = &buf[4*n];
|
||||||
ssaBlock *root = proc->blocks.e[0];
|
irBlock *root = proc->blocks.e[0];
|
||||||
|
|
||||||
// Step 1 - number vertices
|
// Step 1 - number vertices
|
||||||
i32 pre_num = ssa_lt_depth_first_search(<, root, 0, preorder);
|
i32 pre_num = ir_lt_depth_first_search(<, root, 0, preorder);
|
||||||
gb_memmove(buckets, preorder, n*gb_size_of(preorder[0]));
|
gb_memmove(buckets, preorder, n*gb_size_of(preorder[0]));
|
||||||
|
|
||||||
for (i32 i = n-1; i > 0; i--) {
|
for (i32 i = n-1; i > 0; i--) {
|
||||||
ssaBlock *w = preorder[i];
|
irBlock *w = preorder[i];
|
||||||
|
|
||||||
// Step 3 - Implicitly define idom for nodes
|
// Step 3 - Implicitly define idom for nodes
|
||||||
for (ssaBlock *v = buckets[i]; v != w; v = buckets[v->dom.pre]) {
|
for (irBlock *v = buckets[i]; v != w; v = buckets[v->dom.pre]) {
|
||||||
ssaBlock *u = ssa_lt_eval(<, v);
|
irBlock *u = ir_lt_eval(<, v);
|
||||||
if (lt.sdom[u->index]->dom.pre < i) {
|
if (lt.sdom[u->index]->dom.pre < i) {
|
||||||
v->dom.idom = u;
|
v->dom.idom = u;
|
||||||
} else {
|
} else {
|
||||||
@@ -405,14 +403,14 @@ void ssa_opt_build_dom_tree(ssaProcedure *proc) {
|
|||||||
// Step 2 - Compute all sdoms
|
// Step 2 - Compute all sdoms
|
||||||
lt.sdom[w->index] = lt.parent[w->index];
|
lt.sdom[w->index] = lt.parent[w->index];
|
||||||
for_array(pred_index, w->preds) {
|
for_array(pred_index, w->preds) {
|
||||||
ssaBlock *v = w->preds.e[pred_index];
|
irBlock *v = w->preds.e[pred_index];
|
||||||
ssaBlock *u = ssa_lt_eval(<, v);
|
irBlock *u = ir_lt_eval(<, v);
|
||||||
if (lt.sdom[u->index]->dom.pre < lt.sdom[w->index]->dom.pre) {
|
if (lt.sdom[u->index]->dom.pre < lt.sdom[w->index]->dom.pre) {
|
||||||
lt.sdom[w->index] = lt.sdom[u->index];
|
lt.sdom[w->index] = lt.sdom[u->index];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ssa_lt_link(<, lt.parent[w->index], w);
|
ir_lt_link(<, lt.parent[w->index], w);
|
||||||
|
|
||||||
if (lt.parent[w->index] == lt.sdom[w->index]) {
|
if (lt.parent[w->index] == lt.sdom[w->index]) {
|
||||||
w->dom.idom = lt.parent[w->index];
|
w->dom.idom = lt.parent[w->index];
|
||||||
@@ -423,13 +421,13 @@ void ssa_opt_build_dom_tree(ssaProcedure *proc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The rest of Step 3
|
// The rest of Step 3
|
||||||
for (ssaBlock *v = buckets[0]; v != root; v = buckets[v->dom.pre]) {
|
for (irBlock *v = buckets[0]; v != root; v = buckets[v->dom.pre]) {
|
||||||
v->dom.idom = root;
|
v->dom.idom = root;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 4 - Explicitly define idom for nodes (in preorder)
|
// Step 4 - Explicitly define idom for nodes (in preorder)
|
||||||
for (isize i = 1; i < n; i++) {
|
for (isize i = 1; i < n; i++) {
|
||||||
ssaBlock *w = preorder[i];
|
irBlock *w = preorder[i];
|
||||||
if (w == root) {
|
if (w == root) {
|
||||||
w->dom.idom = NULL;
|
w->dom.idom = NULL;
|
||||||
} else {
|
} else {
|
||||||
@@ -448,32 +446,32 @@ void ssa_opt_build_dom_tree(ssaProcedure *proc) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ssa_opt_number_dom_tree(root, 0, 0);
|
ir_opt_number_dom_tree(root, 0, 0);
|
||||||
|
|
||||||
gb_temp_arena_memory_end(tmp);
|
gb_temp_arena_memory_end(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ssa_opt_mem2reg(ssaProcedure *proc) {
|
void ir_opt_mem2reg(irProcedure *proc) {
|
||||||
// TODO(bill): ssa_opt_mem2reg
|
// TODO(bill): ir_opt_mem2reg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void ssa_opt_tree(ssaGen *s) {
|
void ir_opt_tree(irGen *s) {
|
||||||
s->opt_called = true;
|
s->opt_called = true;
|
||||||
|
|
||||||
for_array(member_index, s->module.procs) {
|
for_array(member_index, s->module.procs) {
|
||||||
ssaProcedure *proc = s->module.procs.e[member_index];
|
irProcedure *proc = s->module.procs.e[member_index];
|
||||||
if (proc->blocks.count == 0) { // Prototype/external procedure
|
if (proc->blocks.count == 0) { // Prototype/external procedure
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssa_opt_blocks(proc);
|
ir_opt_blocks(proc);
|
||||||
#if 1
|
#if 0
|
||||||
ssa_opt_build_referrers(proc);
|
ir_opt_build_referrers(proc);
|
||||||
ssa_opt_build_dom_tree(proc);
|
ir_opt_build_dom_tree(proc);
|
||||||
|
|
||||||
// TODO(bill): ssa optimization
|
// TODO(bill): ir optimization
|
||||||
// [ ] cse (common-subexpression) elim
|
// [ ] cse (common-subexpression) elim
|
||||||
// [ ] copy elim
|
// [ ] copy elim
|
||||||
// [ ] dead code elim
|
// [ ] dead code elim
|
||||||
@@ -484,10 +482,10 @@ void ssa_opt_tree(ssaGen *s) {
|
|||||||
// [ ] lift/mem2reg
|
// [ ] lift/mem2reg
|
||||||
// [ ] lift/mem2reg
|
// [ ] lift/mem2reg
|
||||||
|
|
||||||
ssa_opt_mem2reg(proc);
|
ir_opt_mem2reg(proc);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
GB_ASSERT(proc->blocks.count > 0);
|
GB_ASSERT(proc->blocks.count > 0);
|
||||||
ssa_number_proc_registers(proc);
|
ir_number_proc_registers(proc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1589
File diff suppressed because it is too large
Load Diff
+149
-82
@@ -1,22 +1,24 @@
|
|||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
#define VERSION_STRING "v0.0.3d"
|
|
||||||
|
|
||||||
#include "common.c"
|
#include "common.c"
|
||||||
#include "timings.c"
|
#include "timings.c"
|
||||||
#include "unicode.c"
|
#include "build_settings.c"
|
||||||
#include "tokenizer.c"
|
#include "tokenizer.c"
|
||||||
#include "parser.c"
|
#include "parser.c"
|
||||||
// #include "printer.c"
|
// #include "printer.c"
|
||||||
#include "checker/checker.c"
|
#include "checker.c"
|
||||||
#include "ssa.c"
|
// #include "ssa.c"
|
||||||
#include "ssa_opt.c"
|
#include "ir.c"
|
||||||
#include "ssa_print.c"
|
#include "ir_opt.c"
|
||||||
|
#include "ir_print.c"
|
||||||
// #include "vm.c"
|
// #include "vm.c"
|
||||||
|
|
||||||
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
// NOTE(bill): `name` is used in debugging and profiling modes
|
// NOTE(bill): `name` is used in debugging and profiling modes
|
||||||
i32 win32_exec_command_line_app(char *name, char *fmt, ...) {
|
i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
|
||||||
STARTUPINFOW start_info = {gb_size_of(STARTUPINFOW)};
|
STARTUPINFOW start_info = {gb_size_of(STARTUPINFOW)};
|
||||||
PROCESS_INFORMATION pi = {0};
|
PROCESS_INFORMATION pi = {0};
|
||||||
char cmd_line[4096] = {0};
|
char cmd_line[4096] = {0};
|
||||||
@@ -58,50 +60,75 @@ i32 win32_exec_command_line_app(char *name, char *fmt, ...) {
|
|||||||
gb_temp_arena_memory_end(tmp);
|
gb_temp_arena_memory_end(tmp);
|
||||||
return exit_code;
|
return exit_code;
|
||||||
}
|
}
|
||||||
|
#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
|
||||||
|
i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
|
||||||
|
|
||||||
typedef enum ArchKind {
|
char cmd_line[4096] = {0};
|
||||||
ArchKind_x64,
|
isize cmd_len;
|
||||||
ArchKind_x86,
|
va_list va;
|
||||||
} ArchKind;
|
String cmd;
|
||||||
|
i32 exit_code = 0;
|
||||||
|
|
||||||
typedef struct ArchData {
|
va_start(va, fmt);
|
||||||
BaseTypeSizes sizes;
|
cmd_len = gb_snprintf_va(cmd_line, gb_size_of(cmd_line), fmt, va);
|
||||||
String llc_flags;
|
va_end(va);
|
||||||
String link_flags;
|
cmd = make_string(cast(u8 *)&cmd_line, cmd_len-1);
|
||||||
} ArchData;
|
|
||||||
|
|
||||||
ArchData make_arch_data(ArchKind kind) {
|
exit_code = system(&cmd_line[0]);
|
||||||
ArchData data = {0};
|
|
||||||
|
|
||||||
switch (kind) {
|
// pid_t pid = fork();
|
||||||
case ArchKind_x64:
|
// int status = 0;
|
||||||
default:
|
|
||||||
data.sizes.word_size = 8;
|
|
||||||
data.sizes.max_align = 16;
|
|
||||||
data.llc_flags = str_lit("-march=x86-64 ");
|
|
||||||
data.link_flags = str_lit("/machine:x64 ");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ArchKind_x86:
|
// if(pid == 0) {
|
||||||
data.sizes.word_size = 4;
|
// // in child, pid == 0.
|
||||||
data.sizes.max_align = 8;
|
// int ret = execvp(cmd.text, (char* const*) cmd.text);
|
||||||
data.llc_flags = str_lit("-march=x86 ");
|
|
||||||
data.link_flags = str_lit("/machine:x86 ");
|
// if(ret == -1) {
|
||||||
break;
|
// gb_printf_err("Failed to execute command:\n\t%s\n", cmd_line);
|
||||||
|
|
||||||
|
// // we're in the child, so returning won't do us any good -- just quit.
|
||||||
|
// exit(-1);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // unreachable
|
||||||
|
// abort();
|
||||||
|
// } else {
|
||||||
|
// // wait for child to finish, then we can continue cleanup
|
||||||
|
|
||||||
|
// int s = 0;
|
||||||
|
// waitpid(pid, &s, 0);
|
||||||
|
|
||||||
|
// status = WEXITSTATUS(s);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// exit_code = status;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void print_usage_line(i32 indent, char *fmt, ...) {
|
||||||
|
while (indent --> 0) {
|
||||||
|
gb_printf_err("\t");
|
||||||
}
|
}
|
||||||
|
va_list va;
|
||||||
return data;
|
va_start(va, fmt);
|
||||||
|
gb_printf_err_va(fmt, va);
|
||||||
|
va_end(va);
|
||||||
|
gb_printf_err("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void usage(char *argv0) {
|
void usage(char *argv0) {
|
||||||
gb_printf_err("%s is a tool for managing Odin source code\n", argv0);
|
print_usage_line(0, "%s is a tool for managing Odin source code", argv0);
|
||||||
gb_printf_err("Usage:");
|
print_usage_line(0, "Usage:");
|
||||||
gb_printf_err("\n\t%s command [arguments]\n", argv0);
|
print_usage_line(1, "%s command [arguments]", argv0);
|
||||||
gb_printf_err("Commands:");
|
print_usage_line(0, "Commands:");
|
||||||
gb_printf_err("\n\tbuild compile .odin file");
|
print_usage_line(1, "build compile .odin file as executable");
|
||||||
gb_printf_err("\n\trun compile and run .odin file");
|
print_usage_line(1, "build_dll compile .odin file as dll");
|
||||||
gb_printf_err("\n\tversion print Odin version");
|
print_usage_line(1, "run compile and run .odin file");
|
||||||
gb_printf_err("\n\n");
|
print_usage_line(1, "version print version");
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
@@ -113,12 +140,13 @@ int main(int argc, char **argv) {
|
|||||||
Timings timings = {0};
|
Timings timings = {0};
|
||||||
timings_init(&timings, str_lit("Total Time"), 128);
|
timings_init(&timings, str_lit("Total Time"), 128);
|
||||||
// defer (timings_destroy(&timings));
|
// defer (timings_destroy(&timings));
|
||||||
|
|
||||||
#if 1
|
|
||||||
init_string_buffer_memory();
|
init_string_buffer_memory();
|
||||||
|
init_scratch_memory(gb_megabytes(10));
|
||||||
init_global_error_collector();
|
init_global_error_collector();
|
||||||
|
|
||||||
String module_dir = get_module_dir();
|
#if 1
|
||||||
|
|
||||||
|
init_build_context();
|
||||||
|
|
||||||
init_universal_scope();
|
init_universal_scope();
|
||||||
|
|
||||||
@@ -126,12 +154,27 @@ int main(int argc, char **argv) {
|
|||||||
bool run_output = false;
|
bool run_output = false;
|
||||||
String arg1 = make_string_c(argv[1]);
|
String arg1 = make_string_c(argv[1]);
|
||||||
if (str_eq(arg1, str_lit("run"))) {
|
if (str_eq(arg1, str_lit("run"))) {
|
||||||
run_output = true;
|
if (argc != 3) {
|
||||||
|
usage(argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
init_filename = argv[2];
|
init_filename = argv[2];
|
||||||
|
run_output = true;
|
||||||
|
} else if (str_eq(arg1, str_lit("build_dll"))) {
|
||||||
|
if (argc != 3) {
|
||||||
|
usage(argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
init_filename = argv[2];
|
||||||
|
build_context.is_dll = true;
|
||||||
} else if (str_eq(arg1, str_lit("build"))) {
|
} else if (str_eq(arg1, str_lit("build"))) {
|
||||||
|
if (argc != 3) {
|
||||||
|
usage(argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
init_filename = argv[2];
|
init_filename = argv[2];
|
||||||
} else if (str_eq(arg1, str_lit("version"))) {
|
} else if (str_eq(arg1, str_lit("version"))) {
|
||||||
gb_printf("%s version %s", argv[0], VERSION_STRING);
|
gb_printf("%s version %.*s", argv[0], LIT(build_context.ODIN_VERSION));
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
@@ -157,38 +200,48 @@ int main(int argc, char **argv) {
|
|||||||
timings_start_section(&timings, str_lit("type check"));
|
timings_start_section(&timings, str_lit("type check"));
|
||||||
|
|
||||||
Checker checker = {0};
|
Checker checker = {0};
|
||||||
ArchData arch_data = make_arch_data(ArchKind_x64);
|
|
||||||
|
|
||||||
init_checker(&checker, &parser, arch_data.sizes);
|
init_checker(&checker, &parser, &build_context);
|
||||||
// defer (destroy_checker(&checker));
|
// defer (destroy_checker(&checker));
|
||||||
|
|
||||||
check_parsed_files(&checker);
|
check_parsed_files(&checker);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#if 1
|
#if 0
|
||||||
|
if (global_error_collector.count != 0) {
|
||||||
ssaGen ssa = {0};
|
|
||||||
if (!ssa_gen_init(&ssa, &checker)) {
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
// defer (ssa_gen_destroy(&ssa));
|
|
||||||
|
|
||||||
timings_start_section(&timings, str_lit("ssa gen"));
|
if (checker.parser->total_token_count < 2) {
|
||||||
ssa_gen_tree(&ssa);
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
timings_start_section(&timings, str_lit("ssa opt"));
|
if (!ssa_generate(&checker.info)) {
|
||||||
ssa_opt_tree(&ssa);
|
return 1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
irGen ir_gen = {0};
|
||||||
|
if (!ir_gen_init(&ir_gen, &checker)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// defer (ssa_gen_destroy(&ir_gen));
|
||||||
|
|
||||||
timings_start_section(&timings, str_lit("ssa print"));
|
timings_start_section(&timings, str_lit("llvm ir gen"));
|
||||||
ssa_print_llvm_ir(&ssa);
|
ir_gen_tree(&ir_gen);
|
||||||
|
|
||||||
|
timings_start_section(&timings, str_lit("llvm ir opt tree"));
|
||||||
|
ir_opt_tree(&ir_gen);
|
||||||
|
|
||||||
|
timings_start_section(&timings, str_lit("llvm ir print"));
|
||||||
|
print_llvm_ir(&ir_gen);
|
||||||
|
|
||||||
// prof_print_all();
|
// prof_print_all();
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
timings_start_section(&timings, str_lit("llvm-opt"));
|
timings_start_section(&timings, str_lit("llvm-opt"));
|
||||||
|
|
||||||
char const *output_name = ssa.output_file.filename;
|
char const *output_name = ir_gen.output_file.filename;
|
||||||
isize base_name_len = gb_path_extension(output_name)-1 - output_name;
|
isize base_name_len = gb_path_extension(output_name)-1 - output_name;
|
||||||
String output = make_string(cast(u8 *)output_name, base_name_len);
|
String output = make_string(cast(u8 *)output_name, base_name_len);
|
||||||
|
|
||||||
@@ -197,8 +250,8 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
i32 exit_code = 0;
|
i32 exit_code = 0;
|
||||||
// For more passes arguments: http://llvm.org/docs/Passes.html
|
// For more passes arguments: http://llvm.org/docs/Passes.html
|
||||||
exit_code = win32_exec_command_line_app("llvm-opt",
|
exit_code = system_exec_command_line_app("llvm-opt", false,
|
||||||
"%.*sbin/opt %s -o %.*s.bc "
|
"\"%.*sbin/opt\" \"%s\" -o \"%.*s\".bc "
|
||||||
"-mem2reg "
|
"-mem2reg "
|
||||||
"-memcpyopt "
|
"-memcpyopt "
|
||||||
"-die "
|
"-die "
|
||||||
@@ -206,48 +259,61 @@ int main(int argc, char **argv) {
|
|||||||
// "-dce "
|
// "-dce "
|
||||||
// "-S "
|
// "-S "
|
||||||
"",
|
"",
|
||||||
LIT(module_dir),
|
LIT(build_context.ODIN_ROOT),
|
||||||
output_name, LIT(output));
|
output_name, LIT(output));
|
||||||
if (exit_code != 0) {
|
if (exit_code != 0) {
|
||||||
return exit_code;
|
return exit_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 1
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
timings_start_section(&timings, str_lit("llvm-llc"));
|
timings_start_section(&timings, str_lit("llvm-llc"));
|
||||||
// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
|
// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
|
||||||
exit_code = win32_exec_command_line_app("llvm-llc",
|
exit_code = system_exec_command_line_app("llvm-llc", false,
|
||||||
"%.*sbin/llc %.*s.bc -filetype=obj -O%d "
|
"\"%.*sbin/llc\" \"%.*s.bc\" -filetype=obj -O%d "
|
||||||
"%.*s "
|
"%.*s "
|
||||||
// "-debug-pass=Arguments "
|
// "-debug-pass=Arguments "
|
||||||
"",
|
"",
|
||||||
LIT(module_dir),
|
LIT(build_context.ODIN_ROOT),
|
||||||
LIT(output),
|
LIT(output),
|
||||||
optimization_level,
|
optimization_level,
|
||||||
LIT(arch_data.llc_flags));
|
LIT(build_context.llc_flags));
|
||||||
if (exit_code != 0) {
|
if (exit_code != 0) {
|
||||||
return exit_code;
|
return exit_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
timings_start_section(&timings, str_lit("msvc-link"));
|
timings_start_section(&timings, str_lit("msvc-link"));
|
||||||
|
|
||||||
gbString lib_str = gb_string_make(heap_allocator(), "Kernel32.lib");
|
gbString lib_str = gb_string_make(heap_allocator(), "");
|
||||||
// defer (gb_string_free(lib_str));
|
// defer (gb_string_free(lib_str));
|
||||||
char lib_str_buf[1024] = {0};
|
char lib_str_buf[1024] = {0};
|
||||||
for_array(i, parser.foreign_libraries) {
|
for_array(i, ir_gen.module.foreign_library_paths) {
|
||||||
String lib = parser.foreign_libraries.e[i];
|
String lib = ir_gen.module.foreign_library_paths.e[i];
|
||||||
|
// gb_printf_err("Linking lib: %.*s\n", LIT(lib));
|
||||||
isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
|
isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
|
||||||
" %.*s.lib", LIT(lib));
|
" \"%.*s\"", LIT(lib));
|
||||||
lib_str = gb_string_appendc(lib_str, lib_str_buf);
|
lib_str = gb_string_appendc(lib_str, lib_str_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
exit_code = win32_exec_command_line_app("msvc-link",
|
char *output_ext = "exe";
|
||||||
"link %.*s.obj -OUT:%.*s.exe %s "
|
char *link_settings = "";
|
||||||
|
if (build_context.is_dll) {
|
||||||
|
output_ext = "dll";
|
||||||
|
link_settings = "/DLL";
|
||||||
|
} else {
|
||||||
|
link_settings = "/ENTRY:mainCRTStartup";
|
||||||
|
}
|
||||||
|
|
||||||
|
exit_code = system_exec_command_line_app("msvc-link", true,
|
||||||
|
"link \"%.*s\".obj -OUT:\"%.*s.%s\" %s "
|
||||||
"/defaultlib:libcmt "
|
"/defaultlib:libcmt "
|
||||||
"/nologo /incremental:no /opt:ref /subsystem:console "
|
"/nologo /incremental:no /opt:ref /subsystem:CONSOLE "
|
||||||
" %.*s "
|
" %.*s "
|
||||||
|
" %s "
|
||||||
"",
|
"",
|
||||||
LIT(output), LIT(output),
|
LIT(output), LIT(output), output_ext,
|
||||||
lib_str, LIT(arch_data.link_flags));
|
lib_str, LIT(build_context.link_flags),
|
||||||
|
link_settings
|
||||||
|
);
|
||||||
if (exit_code != 0) {
|
if (exit_code != 0) {
|
||||||
return exit_code;
|
return exit_code;
|
||||||
}
|
}
|
||||||
@@ -255,15 +321,16 @@ int main(int argc, char **argv) {
|
|||||||
// timings_print_all(&timings);
|
// timings_print_all(&timings);
|
||||||
|
|
||||||
if (run_output) {
|
if (run_output) {
|
||||||
win32_exec_command_line_app("odin run",
|
system_exec_command_line_app("odin run", false, "%.*s.exe", cast(int)base_name_len, output_name);
|
||||||
"%.*s.exe", cast(int)base_name_len, output_name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error Implement build stuff for this platform
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,9 @@
|
|||||||
#define MAP_NAME MapString
|
#define MAP_NAME MapString
|
||||||
#include "map.c"
|
#include "map.c"
|
||||||
*/
|
*/
|
||||||
|
// A `Map` is an unordered hash table which can allow for a key to point to multiple values
|
||||||
|
// with the use of the `multi_*` procedures.
|
||||||
|
// TODO(bill): I should probably allow the `multi_*` stuff to be #ifdefed out
|
||||||
|
|
||||||
#ifndef MAP_UTIL_STUFF
|
#ifndef MAP_UTIL_STUFF
|
||||||
#define MAP_UTIL_STUFF
|
#define MAP_UTIL_STUFF
|
||||||
@@ -320,6 +323,7 @@ void _J2(MAP_PROC,multi_insert)(MAP_NAME *h, HashKey key, MAP_TYPE value) {
|
|||||||
if (h->hashes.count == 0) {
|
if (h->hashes.count == 0) {
|
||||||
_J2(MAP_PROC,grow)(h);
|
_J2(MAP_PROC,grow)(h);
|
||||||
}
|
}
|
||||||
|
// Make
|
||||||
fr = _J2(MAP_PROC,_find)(h, key);
|
fr = _J2(MAP_PROC,_find)(h, key);
|
||||||
i = _J2(MAP_PROC,_add_entry)(h, key);
|
i = _J2(MAP_PROC,_add_entry)(h, key);
|
||||||
if (fr.entry_prev < 0) {
|
if (fr.entry_prev < 0) {
|
||||||
@@ -329,6 +333,7 @@ void _J2(MAP_PROC,multi_insert)(MAP_NAME *h, HashKey key, MAP_TYPE value) {
|
|||||||
}
|
}
|
||||||
h->entries.e[i].next = fr.entry_index;
|
h->entries.e[i].next = fr.entry_index;
|
||||||
h->entries.e[i].value = value;
|
h->entries.e[i].value = value;
|
||||||
|
// Grow if needed
|
||||||
if (_J2(MAP_PROC,_full)(h)) {
|
if (_J2(MAP_PROC,_full)(h)) {
|
||||||
_J2(MAP_PROC,grow)(h);
|
_J2(MAP_PROC,grow)(h);
|
||||||
}
|
}
|
||||||
|
|||||||
+1975
-1324
File diff suppressed because it is too large
Load Diff
-1439
File diff suppressed because it is too large
Load Diff
+76
-30
@@ -15,8 +15,11 @@ typedef struct String {
|
|||||||
} String;
|
} String;
|
||||||
// NOTE(bill): used for printf style arguments
|
// NOTE(bill): used for printf style arguments
|
||||||
#define LIT(x) ((int)(x).len), (x).text
|
#define LIT(x) ((int)(x).len), (x).text
|
||||||
|
#define STR_LIT(c_str) {cast(u8 *)c_str, gb_size_of(c_str)-1}
|
||||||
|
#define str_lit(c_str) (String){cast(u8 *)c_str, gb_size_of(c_str)-1}
|
||||||
|
|
||||||
|
|
||||||
|
// NOTE(bill): String16 is only used for Windows due to its file directories
|
||||||
typedef struct String16 {
|
typedef struct String16 {
|
||||||
wchar_t *text;
|
wchar_t *text;
|
||||||
isize len;
|
isize len;
|
||||||
@@ -46,7 +49,6 @@ gb_inline String make_string_c(char *text) {
|
|||||||
return make_string(cast(u8 *)cast(void *)text, gb_strlen(text));
|
return make_string(cast(u8 *)cast(void *)text, gb_strlen(text));
|
||||||
}
|
}
|
||||||
|
|
||||||
#define str_lit(c_str) make_string(cast(u8 *)c_str, gb_size_of(c_str)-1)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -108,19 +110,6 @@ GB_COMPARE_PROC(string_cmp_proc) {
|
|||||||
return string_compare(x, y);
|
return string_compare(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// gb_inline bool operator ==(String a, String b) { return are_strings_equal(a, b) != 0; }
|
|
||||||
// gb_inline bool operator !=(String a, String b) { return !operator==(a, b); }
|
|
||||||
// gb_inline bool operator < (String a, String b) { return string_compare(a, b) < 0; }
|
|
||||||
// gb_inline bool operator > (String a, String b) { return string_compare(a, b) > 0; }
|
|
||||||
// gb_inline bool operator <=(String a, String b) { return string_compare(a, b) <= 0; }
|
|
||||||
// gb_inline bool operator >=(String a, String b) { return string_compare(a, b) >= 0; }
|
|
||||||
|
|
||||||
// template <size_t N> gb_inline bool operator ==(String a, char const (&b)[N]) { return a == make_string(cast(u8 *)b, N-1); }
|
|
||||||
// template <size_t N> gb_inline bool operator !=(String a, char const (&b)[N]) { return a != make_string(cast(u8 *)b, N-1); }
|
|
||||||
// template <size_t N> gb_inline bool operator ==(char const (&a)[N], String b) { return make_string(cast(u8 *)a, N-1) == b; }
|
|
||||||
// template <size_t N> gb_inline bool operator !=(char const (&a)[N], String b) { return make_string(cast(u8 *)a, N-1) != b; }
|
|
||||||
|
|
||||||
gb_inline bool str_eq(String a, String b) { return a.len == b.len ? gb_memcompare(a.text, b.text, a.len) == 0 : false; }
|
gb_inline bool str_eq(String a, String b) { return a.len == b.len ? gb_memcompare(a.text, b.text, a.len) == 0 : false; }
|
||||||
gb_inline bool str_ne(String a, String b) { return !str_eq(a, b); }
|
gb_inline bool str_ne(String a, String b) { return !str_eq(a, b); }
|
||||||
gb_inline bool str_lt(String a, String b) { return string_compare(a, b) < 0; }
|
gb_inline bool str_lt(String a, String b) { return string_compare(a, b) < 0; }
|
||||||
@@ -157,16 +146,37 @@ gb_inline isize string_extension_position(String str) {
|
|||||||
return dot_pos;
|
return dot_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String string_trim_whitespace(String str) {
|
||||||
|
while (str.len > 0 && rune_is_whitespace(str.text[str.len-1])) {
|
||||||
|
str.len--;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (str.len > 0 && rune_is_whitespace(str.text[0])) {
|
||||||
|
str.text++;
|
||||||
|
str.len--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
gb_inline bool string_has_extension(String str, String ext) {
|
gb_inline bool string_has_extension(String str, String ext) {
|
||||||
if (str.len > ext.len+1) {
|
str = string_trim_whitespace(str);
|
||||||
u8 *s = str.text+str.len - ext.len-1;
|
if (str.len <= ext.len+1) {
|
||||||
if (s[0] == '.') {
|
|
||||||
s++;
|
|
||||||
return gb_memcompare(s, ext.text, ext.len) == 0;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
isize len = str.len;
|
||||||
|
for (isize i = len-1; i >= 0; i--) {
|
||||||
|
if (str.text[i] == '.') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
if (len == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 *s = str.text + len;
|
||||||
|
return gb_memcompare(s, ext.text, ext.len) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool string_contains_char(String s, u8 c) {
|
bool string_contains_char(String s, u8 c) {
|
||||||
@@ -178,6 +188,47 @@ bool string_contains_char(String s, u8 c) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
|
int convert_multibyte_to_widechar(char *multibyte_input, int input_length, wchar_t *output, int output_size) {
|
||||||
|
return MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, multibyte_input, input_length, output, output_size);
|
||||||
|
}
|
||||||
|
int convert_widechar_to_multibyte(wchar_t *widechar_input, int input_length, char *output, int output_size) {
|
||||||
|
return WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, widechar_input, input_length, output, output_size, NULL, NULL);
|
||||||
|
}
|
||||||
|
#elif defined(GB_SYSTEM_UNIX) || defined(GB_SYSTEM_OSX)
|
||||||
|
|
||||||
|
#include <iconv.h>
|
||||||
|
|
||||||
|
int convert_multibyte_to_widechar(char *multibyte_input, int input_length, wchar_t *output, int output_size) {
|
||||||
|
iconv_t conv = iconv_open("WCHAR_T", "UTF-8");
|
||||||
|
size_t result = iconv(conv, cast(char **)&multibyte_input, &input_length, cast(char **)&output, &output_size);
|
||||||
|
iconv_close(conv);
|
||||||
|
|
||||||
|
return (int) result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int convert_widechar_to_multibyte(wchar_t* widechar_input, int input_length, char* output, int output_size) {
|
||||||
|
iconv_t conv = iconv_open("UTF-8", "WCHAR_T");
|
||||||
|
size_t result = iconv(conv, (char**) &widechar_input, &input_length, (char**) &output, &output_size);
|
||||||
|
iconv_close(conv);
|
||||||
|
|
||||||
|
return (int) result;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#error Implement system
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// TODO(bill): Make this non-windows specific
|
// TODO(bill): Make this non-windows specific
|
||||||
String16 string_to_string16(gbAllocator a, String s) {
|
String16 string_to_string16(gbAllocator a, String s) {
|
||||||
int len, len1;
|
int len, len1;
|
||||||
@@ -187,16 +238,14 @@ String16 string_to_string16(gbAllocator a, String s) {
|
|||||||
return make_string16(NULL, 0);
|
return make_string16(NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
|
len = convert_multibyte_to_widechar(cast(char *)s.text, s.len, NULL, 0);
|
||||||
cast(char *)s.text, s.len, NULL, 0);
|
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
return make_string16(NULL, 0);
|
return make_string16(NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
text = gb_alloc_array(a, wchar_t, len+1);
|
text = gb_alloc_array(a, wchar_t, len+1);
|
||||||
|
|
||||||
len1 = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
|
len1 = convert_multibyte_to_widechar(cast(char *)s.text, s.len, text, len);
|
||||||
cast(char *)s.text, s.len, text, len);
|
|
||||||
if (len1 == 0) {
|
if (len1 == 0) {
|
||||||
gb_free(a, text);
|
gb_free(a, text);
|
||||||
return make_string16(NULL, 0);
|
return make_string16(NULL, 0);
|
||||||
@@ -214,16 +263,14 @@ String string16_to_string(gbAllocator a, String16 s) {
|
|||||||
return make_string(NULL, 0);
|
return make_string(NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
|
len = convert_widechar_to_multibyte(s.text, s.len, NULL, 0);
|
||||||
s.text, s.len, NULL, 0, NULL, NULL);
|
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
return make_string(NULL, 0);
|
return make_string(NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
text = gb_alloc_array(a, u8, len+1);
|
text = gb_alloc_array(a, u8, len+1);
|
||||||
|
|
||||||
len1 = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
|
len1 = convert_widechar_to_multibyte(s.text, s.len, cast(char *)text, len);
|
||||||
s.text, s.len, cast(char *)text, len, NULL, NULL);
|
|
||||||
if (len1 == 0) {
|
if (len1 == 0) {
|
||||||
gb_free(a, text);
|
gb_free(a, text);
|
||||||
return make_string(NULL, 0);
|
return make_string(NULL, 0);
|
||||||
@@ -249,7 +296,6 @@ String string16_to_string(gbAllocator a, String16 s) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool unquote_char(String s, u8 quote, Rune *rune, bool *multiple_bytes, String *tail_string) {
|
bool unquote_char(String s, u8 quote, Rune *rune, bool *multiple_bytes, String *tail_string) {
|
||||||
u8 c;
|
u8 c;
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ typedef struct Timings {
|
|||||||
} Timings;
|
} Timings;
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
u64 win32_time_stamp_time_now(void) {
|
u64 win32_time_stamp_time_now(void) {
|
||||||
LARGE_INTEGER counter;
|
LARGE_INTEGER counter;
|
||||||
QueryPerformanceCounter(&counter);
|
QueryPerformanceCounter(&counter);
|
||||||
@@ -27,9 +28,44 @@ u64 win32_time_stamp__freq(void) {
|
|||||||
return win32_perf_count_freq.QuadPart;
|
return win32_perf_count_freq.QuadPart;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
u64 unix_time_stamp_time_now(void) {
|
||||||
|
struct timespec ts;
|
||||||
|
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
|
||||||
|
|
||||||
|
return (ts.tv_sec * 1000000000) + ts.tv_nsec;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 unix_time_stamp__freq(void) {
|
||||||
|
gb_local_persist u64 freq = 0;
|
||||||
|
|
||||||
|
if (freq == 0) {
|
||||||
|
struct timespec ts;
|
||||||
|
clock_getres(CLOCK_PROCESS_CPUTIME_ID, &ts);
|
||||||
|
|
||||||
|
// that would be an absurd resolution (or lack thereof)
|
||||||
|
GB_ASSERT(ts.tv_sec == 0);
|
||||||
|
|
||||||
|
freq = cast(u64) ((1.0 / ts.tv_nsec) * 1000000000.0);
|
||||||
|
|
||||||
|
GB_ASSERT(freq != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error Implement system
|
||||||
|
#endif
|
||||||
|
|
||||||
u64 time_stamp_time_now(void) {
|
u64 time_stamp_time_now(void) {
|
||||||
#if defined(GB_SYSTEM_WINDOWS)
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
return win32_time_stamp_time_now();
|
return win32_time_stamp_time_now();
|
||||||
|
#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
|
||||||
|
return unix_time_stamp_time_now();
|
||||||
#else
|
#else
|
||||||
#error time_stamp_time_now
|
#error time_stamp_time_now
|
||||||
#endif
|
#endif
|
||||||
@@ -38,6 +74,8 @@ u64 time_stamp_time_now(void) {
|
|||||||
u64 time_stamp__freq(void) {
|
u64 time_stamp__freq(void) {
|
||||||
#if defined(GB_SYSTEM_WINDOWS)
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
return win32_time_stamp__freq();
|
return win32_time_stamp__freq();
|
||||||
|
#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
|
||||||
|
return unix_time_stamp__freq();
|
||||||
#else
|
#else
|
||||||
#error time_stamp__freq
|
#error time_stamp__freq
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+301
-189
@@ -1,112 +1,118 @@
|
|||||||
#define TOKEN_KINDS \
|
#define TOKEN_KINDS \
|
||||||
TOKEN_KIND(Token_Invalid, "Invalid"), \
|
TOKEN_KIND(Token_Invalid, "Invalid"), \
|
||||||
TOKEN_KIND(Token_EOF, "EOF"), \
|
TOKEN_KIND(Token_EOF, "EOF"), \
|
||||||
TOKEN_KIND(Token_Comment, "Comment"), \
|
TOKEN_KIND(Token_Comment, "Comment"), \
|
||||||
\
|
\
|
||||||
TOKEN_KIND(Token__LiteralBegin, "_LiteralBegin"), \
|
TOKEN_KIND(Token__LiteralBegin, "_LiteralBegin"), \
|
||||||
TOKEN_KIND(Token_Identifier, "Identifier"), \
|
TOKEN_KIND(Token_Ident, "identifier"), \
|
||||||
TOKEN_KIND(Token_Integer, "Integer"), \
|
TOKEN_KIND(Token_Integer, "integer"), \
|
||||||
TOKEN_KIND(Token_Float, "Float"), \
|
TOKEN_KIND(Token_Float, "float"), \
|
||||||
TOKEN_KIND(Token_Rune, "Rune"), \
|
TOKEN_KIND(Token_Rune, "rune"), \
|
||||||
TOKEN_KIND(Token_String, "String"), \
|
TOKEN_KIND(Token_String, "string"), \
|
||||||
TOKEN_KIND(Token__LiteralEnd, "_LiteralEnd"), \
|
TOKEN_KIND(Token__LiteralEnd, "_LiteralEnd"), \
|
||||||
\
|
\
|
||||||
TOKEN_KIND(Token__OperatorBegin, "_OperatorBegin"), \
|
TOKEN_KIND(Token__OperatorBegin, "_OperatorBegin"), \
|
||||||
TOKEN_KIND(Token_Eq, "="), \
|
TOKEN_KIND(Token_Eq, "="), \
|
||||||
TOKEN_KIND(Token_Not, "!"), \
|
TOKEN_KIND(Token_Not, "!"), \
|
||||||
TOKEN_KIND(Token_Hash, "#"), \
|
TOKEN_KIND(Token_Hash, "#"), \
|
||||||
TOKEN_KIND(Token_At, "@"), \
|
TOKEN_KIND(Token_At, "@"), \
|
||||||
TOKEN_KIND(Token_Pointer, "^"), \
|
TOKEN_KIND(Token_Dollar, "$"), \
|
||||||
TOKEN_KIND(Token_Maybe, "?"), \
|
TOKEN_KIND(Token_Pointer, "^"), \
|
||||||
TOKEN_KIND(Token_Add, "+"), \
|
TOKEN_KIND(Token_Question, "?"), \
|
||||||
TOKEN_KIND(Token_Sub, "-"), \
|
TOKEN_KIND(Token_Add, "+"), \
|
||||||
TOKEN_KIND(Token_Mul, "*"), \
|
TOKEN_KIND(Token_Sub, "-"), \
|
||||||
TOKEN_KIND(Token_Quo, "/"), \
|
TOKEN_KIND(Token_Mul, "*"), \
|
||||||
TOKEN_KIND(Token_Mod, "%"), \
|
TOKEN_KIND(Token_Quo, "/"), \
|
||||||
TOKEN_KIND(Token_And, "&"), \
|
TOKEN_KIND(Token_Mod, "%"), \
|
||||||
TOKEN_KIND(Token_Or, "|"), \
|
TOKEN_KIND(Token_And, "&"), \
|
||||||
TOKEN_KIND(Token_Xor, "~"), \
|
TOKEN_KIND(Token_Or, "|"), \
|
||||||
TOKEN_KIND(Token_AndNot, "&~"), \
|
TOKEN_KIND(Token_Xor, "~"), \
|
||||||
TOKEN_KIND(Token_Shl, "<<"), \
|
TOKEN_KIND(Token_AndNot, "&~"), \
|
||||||
TOKEN_KIND(Token_Shr, ">>"), \
|
TOKEN_KIND(Token_Shl, "<<"), \
|
||||||
\
|
TOKEN_KIND(Token_Shr, ">>"), \
|
||||||
TOKEN_KIND(Token_as, "as"), \
|
|
||||||
TOKEN_KIND(Token_transmute, "transmute"), \
|
|
||||||
TOKEN_KIND(Token_down_cast, "down_cast"), \
|
|
||||||
TOKEN_KIND(Token_union_cast, "union_cast"), \
|
|
||||||
\
|
\
|
||||||
TOKEN_KIND(Token_CmpAnd, "&&"), \
|
TOKEN_KIND(Token_CmpAnd, "&&"), \
|
||||||
TOKEN_KIND(Token_CmpOr, "||"), \
|
TOKEN_KIND(Token_CmpOr, "||"), \
|
||||||
\
|
\
|
||||||
TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \
|
TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \
|
||||||
TOKEN_KIND(Token_AddEq, "+="), \
|
TOKEN_KIND(Token_AddEq, "+="), \
|
||||||
TOKEN_KIND(Token_SubEq, "-="), \
|
TOKEN_KIND(Token_SubEq, "-="), \
|
||||||
TOKEN_KIND(Token_MulEq, "*="), \
|
TOKEN_KIND(Token_MulEq, "*="), \
|
||||||
TOKEN_KIND(Token_QuoEq, "/="), \
|
TOKEN_KIND(Token_QuoEq, "/="), \
|
||||||
TOKEN_KIND(Token_ModEq, "%="), \
|
TOKEN_KIND(Token_ModEq, "%="), \
|
||||||
TOKEN_KIND(Token_AndEq, "&="), \
|
TOKEN_KIND(Token_AndEq, "&="), \
|
||||||
TOKEN_KIND(Token_OrEq, "|="), \
|
TOKEN_KIND(Token_OrEq, "|="), \
|
||||||
TOKEN_KIND(Token_XorEq, "~="), \
|
TOKEN_KIND(Token_XorEq, "~="), \
|
||||||
TOKEN_KIND(Token_AndNotEq, "&~="), \
|
TOKEN_KIND(Token_AndNotEq, "&~="), \
|
||||||
TOKEN_KIND(Token_ShlEq, "<<="), \
|
TOKEN_KIND(Token_ShlEq, "<<="), \
|
||||||
TOKEN_KIND(Token_ShrEq, ">>="), \
|
TOKEN_KIND(Token_ShrEq, ">>="), \
|
||||||
TOKEN_KIND(Token_CmpAndEq, "&&="), \
|
TOKEN_KIND(Token_CmpAndEq, "&&="), \
|
||||||
TOKEN_KIND(Token_CmpOrEq, "||="), \
|
TOKEN_KIND(Token_CmpOrEq, "||="), \
|
||||||
TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \
|
TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \
|
||||||
TOKEN_KIND(Token_Increment, "++"), \
|
|
||||||
TOKEN_KIND(Token_Decrement, "--"), \
|
|
||||||
TOKEN_KIND(Token_ArrowRight, "->"), \
|
TOKEN_KIND(Token_ArrowRight, "->"), \
|
||||||
TOKEN_KIND(Token_ArrowLeft, "<-"), \
|
TOKEN_KIND(Token_ArrowLeft, "<-"), \
|
||||||
|
TOKEN_KIND(Token_Inc, "++"), \
|
||||||
|
TOKEN_KIND(Token_Dec, "--"), \
|
||||||
\
|
\
|
||||||
TOKEN_KIND(Token__ComparisonBegin, "_ComparisonBegin"), \
|
TOKEN_KIND(Token__ComparisonBegin, "_ComparisonBegin"), \
|
||||||
TOKEN_KIND(Token_CmpEq, "=="), \
|
TOKEN_KIND(Token_CmpEq, "=="), \
|
||||||
TOKEN_KIND(Token_NotEq, "!="), \
|
TOKEN_KIND(Token_NotEq, "!="), \
|
||||||
TOKEN_KIND(Token_Lt, "<"), \
|
TOKEN_KIND(Token_Lt, "<"), \
|
||||||
TOKEN_KIND(Token_Gt, ">"), \
|
TOKEN_KIND(Token_Gt, ">"), \
|
||||||
TOKEN_KIND(Token_LtEq, "<="), \
|
TOKEN_KIND(Token_LtEq, "<="), \
|
||||||
TOKEN_KIND(Token_GtEq, ">="), \
|
TOKEN_KIND(Token_GtEq, ">="), \
|
||||||
TOKEN_KIND(Token__ComparisonEnd, "_ComparisonEnd"), \
|
TOKEN_KIND(Token__ComparisonEnd, "_ComparisonEnd"), \
|
||||||
\
|
\
|
||||||
TOKEN_KIND(Token_OpenParen, "("), \
|
TOKEN_KIND(Token_OpenParen, "("), \
|
||||||
TOKEN_KIND(Token_CloseParen, ")"), \
|
TOKEN_KIND(Token_CloseParen, ")"), \
|
||||||
TOKEN_KIND(Token_OpenBracket, "["), \
|
TOKEN_KIND(Token_OpenBracket, "["), \
|
||||||
TOKEN_KIND(Token_CloseBracket, "]"), \
|
TOKEN_KIND(Token_CloseBracket, "]"), \
|
||||||
TOKEN_KIND(Token_OpenBrace, "{"), \
|
TOKEN_KIND(Token_OpenBrace, "{"), \
|
||||||
TOKEN_KIND(Token_CloseBrace, "}"), \
|
TOKEN_KIND(Token_CloseBrace, "}"), \
|
||||||
TOKEN_KIND(Token_Colon, ":"), \
|
TOKEN_KIND(Token_Colon, ":"), \
|
||||||
TOKEN_KIND(Token_Semicolon, ";"), \
|
TOKEN_KIND(Token_Semicolon, ";"), \
|
||||||
TOKEN_KIND(Token_Period, "."), \
|
TOKEN_KIND(Token_Period, "."), \
|
||||||
TOKEN_KIND(Token_Comma, ","), \
|
TOKEN_KIND(Token_Comma, ","), \
|
||||||
TOKEN_KIND(Token_Ellipsis, ".."), \
|
TOKEN_KIND(Token_Ellipsis, ".."), \
|
||||||
TOKEN_KIND(Token_RangeExclusive, "..<"), \
|
/* TOKEN_KIND(Token_HalfOpenRange, "..<"), */ \
|
||||||
TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \
|
TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \
|
||||||
\
|
\
|
||||||
TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
||||||
TOKEN_KIND(Token_type, "type"), \
|
TOKEN_KIND(Token_when, "when"), \
|
||||||
TOKEN_KIND(Token_proc, "proc"), \
|
TOKEN_KIND(Token_if, "if"), \
|
||||||
TOKEN_KIND(Token_match, "match"), \
|
TOKEN_KIND(Token_else, "else"), \
|
||||||
TOKEN_KIND(Token_break, "break"), \
|
TOKEN_KIND(Token_for, "for"), \
|
||||||
TOKEN_KIND(Token_continue, "continue"), \
|
TOKEN_KIND(Token_in, "in"), \
|
||||||
TOKEN_KIND(Token_fallthrough, "fallthrough"), \
|
TOKEN_KIND(Token_match, "match"), \
|
||||||
TOKEN_KIND(Token_case, "case"), \
|
TOKEN_KIND(Token_default, "default"), \
|
||||||
TOKEN_KIND(Token_default, "default"), \
|
TOKEN_KIND(Token_case, "case"), \
|
||||||
TOKEN_KIND(Token_then, "then"), \
|
TOKEN_KIND(Token_break, "break"), \
|
||||||
TOKEN_KIND(Token_if, "if"), \
|
TOKEN_KIND(Token_continue, "continue"), \
|
||||||
TOKEN_KIND(Token_else, "else"), \
|
TOKEN_KIND(Token_fallthrough, "fallthrough"), \
|
||||||
TOKEN_KIND(Token_for, "for"), \
|
TOKEN_KIND(Token_defer, "defer"), \
|
||||||
TOKEN_KIND(Token_range, "range"), \
|
TOKEN_KIND(Token_return, "return"), \
|
||||||
TOKEN_KIND(Token_defer, "defer"), \
|
TOKEN_KIND(Token_give, "give"), \
|
||||||
TOKEN_KIND(Token_return, "return"), \
|
TOKEN_KIND(Token_proc, "proc"), \
|
||||||
TOKEN_KIND(Token_struct, "struct"), \
|
TOKEN_KIND(Token_macro, "macro"), \
|
||||||
TOKEN_KIND(Token_union, "union"), \
|
TOKEN_KIND(Token_struct, "struct"), \
|
||||||
TOKEN_KIND(Token_raw_union, "raw_union"), \
|
TOKEN_KIND(Token_union, "union"), \
|
||||||
TOKEN_KIND(Token_enum, "enum"), \
|
TOKEN_KIND(Token_raw_union, "raw_union"), \
|
||||||
TOKEN_KIND(Token_using, "using"), \
|
TOKEN_KIND(Token_enum, "enum"), \
|
||||||
TOKEN_KIND(Token_asm, "asm"), \
|
TOKEN_KIND(Token_vector, "vector"), \
|
||||||
TOKEN_KIND(Token_volatile, "volatile"), \
|
TOKEN_KIND(Token_static, "static"), \
|
||||||
TOKEN_KIND(Token_atomic, "atomic"), \
|
TOKEN_KIND(Token_dynamic, "dynamic"), \
|
||||||
TOKEN_KIND(Token_push_allocator, "push_allocator"), \
|
TOKEN_KIND(Token_map, "map"), \
|
||||||
TOKEN_KIND(Token_push_context, "push_context"), \
|
TOKEN_KIND(Token_using, "using"), \
|
||||||
|
TOKEN_KIND(Token_no_alias, "no_alias"), \
|
||||||
|
TOKEN_KIND(Token_immutable, "immutable"), \
|
||||||
|
TOKEN_KIND(Token_cast, "cast"), \
|
||||||
|
TOKEN_KIND(Token_transmute, "transmute"), \
|
||||||
|
TOKEN_KIND(Token_down_cast, "down_cast"), \
|
||||||
|
TOKEN_KIND(Token_union_cast, "union_cast"), \
|
||||||
|
TOKEN_KIND(Token_context, "context"), \
|
||||||
|
TOKEN_KIND(Token_push_context, "push_context"), \
|
||||||
|
TOKEN_KIND(Token_push_allocator, "push_allocator"), \
|
||||||
|
TOKEN_KIND(Token_asm, "asm"), \
|
||||||
TOKEN_KIND(Token__KeywordEnd, "_KeywordEnd"), \
|
TOKEN_KIND(Token__KeywordEnd, "_KeywordEnd"), \
|
||||||
TOKEN_KIND(Token_Count, "")
|
TOKEN_KIND(Token_Count, "")
|
||||||
|
|
||||||
@@ -141,11 +147,10 @@ i32 token_pos_cmp(TokenPos a, TokenPos b) {
|
|||||||
return (a.line < b.line) ? -1 : +1;
|
return (a.line < b.line) ? -1 : +1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool token_pos_are_equal(TokenPos a, TokenPos b) {
|
bool token_pos_eq(TokenPos a, TokenPos b) {
|
||||||
return token_pos_cmp(a, b) == 0;
|
return token_pos_cmp(a, b) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(bill): Text is UTF-8, thus why u8 and not char
|
|
||||||
typedef struct Token {
|
typedef struct Token {
|
||||||
TokenKind kind;
|
TokenKind kind;
|
||||||
String string;
|
String string;
|
||||||
@@ -153,10 +158,10 @@ typedef struct Token {
|
|||||||
} Token;
|
} Token;
|
||||||
|
|
||||||
Token empty_token = {Token_Invalid};
|
Token empty_token = {Token_Invalid};
|
||||||
Token blank_token = {Token_Identifier, {cast(u8 *)"_", 1}};
|
Token blank_token = {Token_Ident, {cast(u8 *)"_", 1}};
|
||||||
|
|
||||||
Token make_token_ident(String s) {
|
Token make_token_ident(String s) {
|
||||||
Token t = {Token_Identifier, s};
|
Token t = {Token_Ident, s};
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,67 +179,98 @@ void init_global_error_collector(void) {
|
|||||||
gb_mutex_init(&global_error_collector.mutex);
|
gb_mutex_init(&global_error_collector.mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void warning_va(Token token, char *fmt, va_list va) {
|
||||||
void warning(Token token, char *fmt, ...) {
|
|
||||||
gb_mutex_lock(&global_error_collector.mutex);
|
gb_mutex_lock(&global_error_collector.mutex);
|
||||||
|
|
||||||
global_error_collector.warning_count++;
|
global_error_collector.warning_count++;
|
||||||
// NOTE(bill): Duplicate error, skip it
|
// NOTE(bill): Duplicate error, skip it
|
||||||
if (!token_pos_are_equal(global_error_collector.prev, token.pos)) {
|
if (!token_pos_eq(global_error_collector.prev, token.pos)) {
|
||||||
va_list va;
|
|
||||||
|
|
||||||
global_error_collector.prev = token.pos;
|
global_error_collector.prev = token.pos;
|
||||||
|
|
||||||
va_start(va, fmt);
|
|
||||||
gb_printf_err("%.*s(%td:%td) Warning: %s\n",
|
gb_printf_err("%.*s(%td:%td) Warning: %s\n",
|
||||||
LIT(token.pos.file), token.pos.line, token.pos.column,
|
LIT(token.pos.file), token.pos.line, token.pos.column,
|
||||||
gb_bprintf_va(fmt, va));
|
gb_bprintf_va(fmt, va));
|
||||||
va_end(va);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gb_mutex_unlock(&global_error_collector.mutex);
|
gb_mutex_unlock(&global_error_collector.mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void error(Token token, char *fmt, ...) {
|
void error_va(Token token, char *fmt, va_list va) {
|
||||||
gb_mutex_lock(&global_error_collector.mutex);
|
gb_mutex_lock(&global_error_collector.mutex);
|
||||||
|
|
||||||
global_error_collector.count++;
|
global_error_collector.count++;
|
||||||
// NOTE(bill): Duplicate error, skip it
|
// NOTE(bill): Duplicate error, skip it
|
||||||
if (!token_pos_are_equal(global_error_collector.prev, token.pos)) {
|
if (!token_pos_eq(global_error_collector.prev, token.pos)) {
|
||||||
va_list va;
|
|
||||||
|
|
||||||
global_error_collector.prev = token.pos;
|
global_error_collector.prev = token.pos;
|
||||||
|
|
||||||
va_start(va, fmt);
|
|
||||||
gb_printf_err("%.*s(%td:%td) %s\n",
|
gb_printf_err("%.*s(%td:%td) %s\n",
|
||||||
LIT(token.pos.file), token.pos.line, token.pos.column,
|
LIT(token.pos.file), token.pos.line, token.pos.column,
|
||||||
gb_bprintf_va(fmt, va));
|
gb_bprintf_va(fmt, va));
|
||||||
va_end(va);
|
} else if (token.pos.line == 0) {
|
||||||
|
gb_printf_err("Error: %s\n", gb_bprintf_va(fmt, va));
|
||||||
}
|
}
|
||||||
|
|
||||||
gb_mutex_unlock(&global_error_collector.mutex);
|
gb_mutex_unlock(&global_error_collector.mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void syntax_error(Token token, char *fmt, ...) {
|
void syntax_error_va(Token token, char *fmt, va_list va) {
|
||||||
gb_mutex_lock(&global_error_collector.mutex);
|
gb_mutex_lock(&global_error_collector.mutex);
|
||||||
|
|
||||||
global_error_collector.count++;
|
global_error_collector.count++;
|
||||||
// NOTE(bill): Duplicate error, skip it
|
// NOTE(bill): Duplicate error, skip it
|
||||||
if (!token_pos_are_equal(global_error_collector.prev, token.pos)) {
|
if (!token_pos_eq(global_error_collector.prev, token.pos)) {
|
||||||
va_list va;
|
|
||||||
|
|
||||||
global_error_collector.prev = token.pos;
|
global_error_collector.prev = token.pos;
|
||||||
|
|
||||||
va_start(va, fmt);
|
|
||||||
gb_printf_err("%.*s(%td:%td) Syntax Error: %s\n",
|
gb_printf_err("%.*s(%td:%td) Syntax Error: %s\n",
|
||||||
LIT(token.pos.file), token.pos.line, token.pos.column,
|
LIT(token.pos.file), token.pos.line, token.pos.column,
|
||||||
gb_bprintf_va(fmt, va));
|
gb_bprintf_va(fmt, va));
|
||||||
va_end(va);
|
} else if (token.pos.line == 0) {
|
||||||
|
gb_printf_err("Error: %s\n", gb_bprintf_va(fmt, va));
|
||||||
}
|
}
|
||||||
|
|
||||||
gb_mutex_unlock(&global_error_collector.mutex);
|
gb_mutex_unlock(&global_error_collector.mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void syntax_warning_va(Token token, char *fmt, va_list va) {
|
||||||
|
gb_mutex_lock(&global_error_collector.mutex);
|
||||||
|
global_error_collector.warning_count++;
|
||||||
|
// NOTE(bill): Duplicate error, skip it
|
||||||
|
if (!token_pos_eq(global_error_collector.prev, token.pos)) {
|
||||||
|
global_error_collector.prev = token.pos;
|
||||||
|
gb_printf_err("%.*s(%td:%td) Syntax Warning: %s\n",
|
||||||
|
LIT(token.pos.file), token.pos.line, token.pos.column,
|
||||||
|
gb_bprintf_va(fmt, va));
|
||||||
|
} else if (token.pos.line == 0) {
|
||||||
|
gb_printf_err("Warning: %s\n", gb_bprintf_va(fmt, va));
|
||||||
|
}
|
||||||
|
|
||||||
|
gb_mutex_unlock(&global_error_collector.mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void warning(Token token, char *fmt, ...) {
|
||||||
|
va_list va;
|
||||||
|
va_start(va, fmt);
|
||||||
|
warning_va(token, fmt, va);
|
||||||
|
va_end(va);
|
||||||
|
}
|
||||||
|
|
||||||
|
void error(Token token, char *fmt, ...) {
|
||||||
|
va_list va;
|
||||||
|
va_start(va, fmt);
|
||||||
|
error_va(token, fmt, va);
|
||||||
|
va_end(va);
|
||||||
|
}
|
||||||
|
|
||||||
|
void syntax_error(Token token, char *fmt, ...) {
|
||||||
|
va_list va;
|
||||||
|
va_start(va, fmt);
|
||||||
|
syntax_error_va(token, fmt, va);
|
||||||
|
va_end(va);
|
||||||
|
}
|
||||||
|
|
||||||
|
void syntax_warning(Token token, char *fmt, ...) {
|
||||||
|
va_list va;
|
||||||
|
va_start(va, fmt);
|
||||||
|
syntax_warning_va(token, fmt, va);
|
||||||
|
va_end(va);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void compiler_error(char *fmt, ...) {
|
void compiler_error(char *fmt, ...) {
|
||||||
va_list va;
|
va_list va;
|
||||||
@@ -250,20 +286,20 @@ void compiler_error(char *fmt, ...) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
gb_inline bool token_is_literal(Token t) {
|
gb_inline bool token_is_literal(TokenKind t) {
|
||||||
return gb_is_between(t.kind, Token__LiteralBegin+1, Token__LiteralEnd-1);
|
return gb_is_between(t, Token__LiteralBegin+1, Token__LiteralEnd-1);
|
||||||
}
|
}
|
||||||
gb_inline bool token_is_operator(Token t) {
|
gb_inline bool token_is_operator(TokenKind t) {
|
||||||
return gb_is_between(t.kind, Token__OperatorBegin+1, Token__OperatorEnd-1);
|
return gb_is_between(t, Token__OperatorBegin+1, Token__OperatorEnd-1);
|
||||||
}
|
}
|
||||||
gb_inline bool token_is_keyword(Token t) {
|
gb_inline bool token_is_keyword(TokenKind t) {
|
||||||
return gb_is_between(t.kind, Token__KeywordBegin+1, Token__KeywordEnd-1);
|
return gb_is_between(t, Token__KeywordBegin+1, Token__KeywordEnd-1);
|
||||||
}
|
}
|
||||||
gb_inline bool token_is_comparison(Token t) {
|
gb_inline bool token_is_comparison(TokenKind t) {
|
||||||
return gb_is_between(t.kind, Token__ComparisonBegin+1, Token__ComparisonEnd-1);
|
return gb_is_between(t, Token__ComparisonBegin+1, Token__ComparisonEnd-1);
|
||||||
}
|
}
|
||||||
gb_inline bool token_is_shift(Token t) {
|
gb_inline bool token_is_shift(TokenKind t) {
|
||||||
return t.kind == Token_Shl || t.kind == Token_Shr;
|
return t == Token_Shl || t == Token_Shr;
|
||||||
}
|
}
|
||||||
|
|
||||||
gb_inline void print_token(Token t) { gb_printf("%.*s\n", LIT(t.string)); }
|
gb_inline void print_token(Token t) { gb_printf("%.*s\n", LIT(t.string)); }
|
||||||
@@ -281,6 +317,14 @@ typedef enum TokenizerInitError {
|
|||||||
} TokenizerInitError;
|
} TokenizerInitError;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct TokenizerState {
|
||||||
|
Rune curr_rune; // current character
|
||||||
|
u8 * curr; // character pos
|
||||||
|
u8 * read_curr; // pos from start
|
||||||
|
u8 * line; // current line pos
|
||||||
|
isize line_count;
|
||||||
|
} TokenizerState;
|
||||||
|
|
||||||
typedef struct Tokenizer {
|
typedef struct Tokenizer {
|
||||||
String fullpath;
|
String fullpath;
|
||||||
u8 *start;
|
u8 *start;
|
||||||
@@ -297,11 +341,31 @@ typedef struct Tokenizer {
|
|||||||
} Tokenizer;
|
} Tokenizer;
|
||||||
|
|
||||||
|
|
||||||
|
TokenizerState save_tokenizer_state(Tokenizer *t) {
|
||||||
|
TokenizerState state = {0};
|
||||||
|
state.curr_rune = t->curr_rune;
|
||||||
|
state.curr = t->curr;
|
||||||
|
state.read_curr = t->read_curr;
|
||||||
|
state.line = t->line;
|
||||||
|
state.line_count = t->line_count;
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void restore_tokenizer_state(Tokenizer *t, TokenizerState *state) {
|
||||||
|
t->curr_rune = state->curr_rune;
|
||||||
|
t->curr = state->curr;
|
||||||
|
t->read_curr = state->read_curr;
|
||||||
|
t->line = state->line;
|
||||||
|
t->line_count = state->line_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void tokenizer_err(Tokenizer *t, char *msg, ...) {
|
void tokenizer_err(Tokenizer *t, char *msg, ...) {
|
||||||
va_list va;
|
va_list va;
|
||||||
isize column = t->read_curr - t->line+1;
|
isize column = t->read_curr - t->line+1;
|
||||||
if (column < 1)
|
if (column < 1) {
|
||||||
column = 1;
|
column = 1;
|
||||||
|
}
|
||||||
|
|
||||||
gb_printf_err("%.*s(%td:%td) Syntax error: ", LIT(t->fullpath), t->line_count, column);
|
gb_printf_err("%.*s(%td:%td) Syntax error: ", LIT(t->fullpath), t->line_count, column);
|
||||||
|
|
||||||
@@ -401,7 +465,10 @@ gb_inline void destroy_tokenizer(Tokenizer *t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void tokenizer_skip_whitespace(Tokenizer *t) {
|
void tokenizer_skip_whitespace(Tokenizer *t) {
|
||||||
while (rune_is_whitespace(t->curr_rune)) {
|
while (t->curr_rune == ' ' ||
|
||||||
|
t->curr_rune == '\t' ||
|
||||||
|
t->curr_rune == '\n' ||
|
||||||
|
t->curr_rune == '\r') {
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -417,16 +484,18 @@ gb_inline i32 digit_value(Rune r) {
|
|||||||
return 16; // NOTE(bill): Larger than highest possible
|
return 16; // NOTE(bill): Larger than highest possible
|
||||||
}
|
}
|
||||||
|
|
||||||
gb_inline void scan_mantissa(Tokenizer *t, i32 base) {
|
gb_inline void scan_mantissa(Tokenizer *t, i32 base, bool allow_underscore) {
|
||||||
// TODO(bill): Allow for underscores in numbers as a number separator
|
if (allow_underscore) {
|
||||||
// TODO(bill): Is this a good idea?
|
while (digit_value(t->curr_rune) < base || t->curr_rune == '_') {
|
||||||
// while (digit_value(t->curr_rune) < base || t->curr_rune == '_')
|
advance_to_next_rune(t);
|
||||||
while (digit_value(t->curr_rune) < base) {
|
}
|
||||||
advance_to_next_rune(t);
|
} else {
|
||||||
|
while (digit_value(t->curr_rune) < base) {
|
||||||
|
advance_to_next_rune(t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) {
|
Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) {
|
||||||
Token token = {0};
|
Token token = {0};
|
||||||
token.kind = Token_Integer;
|
token.kind = Token_Integer;
|
||||||
@@ -437,7 +506,7 @@ Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) {
|
|||||||
|
|
||||||
if (seen_decimal_point) {
|
if (seen_decimal_point) {
|
||||||
token.kind = Token_Float;
|
token.kind = Token_Float;
|
||||||
scan_mantissa(t, 10);
|
scan_mantissa(t, 10, true);
|
||||||
goto exponent;
|
goto exponent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -446,27 +515,31 @@ Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) {
|
|||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
if (t->curr_rune == 'b') { // Binary
|
if (t->curr_rune == 'b') { // Binary
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
scan_mantissa(t, 2);
|
scan_mantissa(t, 2, true);
|
||||||
if (t->curr - prev <= 2)
|
if (t->curr - prev <= 2) {
|
||||||
token.kind = Token_Invalid;
|
token.kind = Token_Invalid;
|
||||||
|
}
|
||||||
} else if (t->curr_rune == 'o') { // Octal
|
} else if (t->curr_rune == 'o') { // Octal
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
scan_mantissa(t, 8);
|
scan_mantissa(t, 8, true);
|
||||||
if (t->curr - prev <= 2)
|
if (t->curr - prev <= 2) {
|
||||||
token.kind = Token_Invalid;
|
token.kind = Token_Invalid;
|
||||||
|
}
|
||||||
} else if (t->curr_rune == 'd') { // Decimal
|
} else if (t->curr_rune == 'd') { // Decimal
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
scan_mantissa(t, 10);
|
scan_mantissa(t, 10, true);
|
||||||
if (t->curr - prev <= 2)
|
if (t->curr - prev <= 2) {
|
||||||
token.kind = Token_Invalid;
|
token.kind = Token_Invalid;
|
||||||
|
}
|
||||||
} else if (t->curr_rune == 'x') { // Hexadecimal
|
} else if (t->curr_rune == 'x') { // Hexadecimal
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
scan_mantissa(t, 16);
|
scan_mantissa(t, 16, true);
|
||||||
if (t->curr - prev <= 2)
|
if (t->curr - prev <= 2) {
|
||||||
token.kind = Token_Invalid;
|
token.kind = Token_Invalid;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
seen_decimal_point = false;
|
seen_decimal_point = false;
|
||||||
scan_mantissa(t, 10);
|
scan_mantissa(t, 10, true);
|
||||||
|
|
||||||
if (t->curr_rune == '.' || t->curr_rune == 'e' || t->curr_rune == 'E') {
|
if (t->curr_rune == '.' || t->curr_rune == 'e' || t->curr_rune == 'E') {
|
||||||
seen_decimal_point = true;
|
seen_decimal_point = true;
|
||||||
@@ -478,13 +551,20 @@ Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) {
|
|||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
scan_mantissa(t, 10);
|
scan_mantissa(t, 10, true);
|
||||||
|
|
||||||
fraction:
|
fraction:
|
||||||
if (t->curr_rune == '.') {
|
if (t->curr_rune == '.') {
|
||||||
token.kind = Token_Float;
|
// HACK(bill): This may be inefficient
|
||||||
|
TokenizerState state = save_tokenizer_state(t);
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
scan_mantissa(t, 10);
|
if (digit_value(t->curr_rune) >= 10) {
|
||||||
|
// TODO(bill): Clean up this shit
|
||||||
|
restore_tokenizer_state(t, &state);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
token.kind = Token_Float;
|
||||||
|
scan_mantissa(t, 10, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
exponent:
|
exponent:
|
||||||
@@ -494,9 +574,10 @@ exponent:
|
|||||||
if (t->curr_rune == '-' || t->curr_rune == '+') {
|
if (t->curr_rune == '-' || t->curr_rune == '+') {
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
}
|
}
|
||||||
scan_mantissa(t, 10);
|
scan_mantissa(t, 10, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
token.string.len = t->curr - token.string.text;
|
token.string.len = t->curr - token.string.text;
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
@@ -605,19 +686,63 @@ gb_inline TokenKind token_kind_dub_eq(Tokenizer *t, Rune sing_rune, TokenKind si
|
|||||||
return sing;
|
return sing;
|
||||||
}
|
}
|
||||||
|
|
||||||
Token tokenizer_get_token(Tokenizer *t) {
|
void tokenizer__fle_update(Tokenizer *t) {
|
||||||
Token token = {0};
|
t->curr_rune = '/';
|
||||||
Rune curr_rune;
|
t->curr = t->curr-1;
|
||||||
|
t->read_curr = t->curr+1;
|
||||||
|
advance_to_next_rune(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE(bill): needed if comment is straight after a "semicolon"
|
||||||
|
bool tokenizer_find_line_end(Tokenizer *t) {
|
||||||
|
while (t->curr_rune == '/' || t->curr_rune == '*') {
|
||||||
|
if (t->curr_rune == '/') {
|
||||||
|
tokenizer__fle_update(t);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
advance_to_next_rune(t);
|
||||||
|
while (t->curr_rune >= 0) {
|
||||||
|
Rune r = t->curr_rune;
|
||||||
|
if (r == '\n') {
|
||||||
|
tokenizer__fle_update(t);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
advance_to_next_rune(t);
|
||||||
|
if (r == '*' && t->curr_rune == '/') {
|
||||||
|
advance_to_next_rune(t);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenizer_skip_whitespace(t);
|
||||||
|
if (t->curr_rune < 0 || t->curr_rune == '\n') {
|
||||||
|
tokenizer__fle_update(t);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (t->curr_rune != '/') {
|
||||||
|
tokenizer__fle_update(t);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
advance_to_next_rune(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenizer__fle_update(t);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Token tokenizer_get_token(Tokenizer *t) {
|
||||||
tokenizer_skip_whitespace(t);
|
tokenizer_skip_whitespace(t);
|
||||||
|
|
||||||
|
Token token = {0};
|
||||||
token.string = make_string(t->curr, 1);
|
token.string = make_string(t->curr, 1);
|
||||||
token.pos.file = t->fullpath;
|
token.pos.file = t->fullpath;
|
||||||
token.pos.line = t->line_count;
|
token.pos.line = t->line_count;
|
||||||
token.pos.column = t->curr - t->line + 1;
|
token.pos.column = t->curr - t->line + 1;
|
||||||
|
|
||||||
curr_rune = t->curr_rune;
|
Rune curr_rune = t->curr_rune;
|
||||||
if (rune_is_letter(curr_rune)) {
|
if (rune_is_letter(curr_rune)) {
|
||||||
token.kind = Token_Identifier;
|
token.kind = Token_Ident;
|
||||||
while (rune_is_letter(t->curr_rune) || rune_is_digit(t->curr_rune)) {
|
while (rune_is_letter(t->curr_rune) || rune_is_digit(t->curr_rune)) {
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
}
|
}
|
||||||
@@ -626,20 +751,10 @@ Token tokenizer_get_token(Tokenizer *t) {
|
|||||||
|
|
||||||
// NOTE(bill): All keywords are > 1
|
// NOTE(bill): All keywords are > 1
|
||||||
if (token.string.len > 1) {
|
if (token.string.len > 1) {
|
||||||
if (str_eq(token.string, token_strings[Token_as])) {
|
for (i32 k = Token__KeywordBegin+1; k < Token__KeywordEnd; k++) {
|
||||||
token.kind = Token_as;
|
if (str_eq(token.string, token_strings[k])) {
|
||||||
} else if (str_eq(token.string, token_strings[Token_transmute])) {
|
token.kind = cast(TokenKind)k;
|
||||||
token.kind = Token_transmute;
|
break;
|
||||||
} else if (str_eq(token.string, token_strings[Token_down_cast])) {
|
|
||||||
token.kind = Token_down_cast;
|
|
||||||
} else if (str_eq(token.string, token_strings[Token_union_cast])) {
|
|
||||||
token.kind = Token_union_cast;
|
|
||||||
} else {
|
|
||||||
for (i32 k = Token__KeywordBegin+1; k < Token__KeywordEnd; k++) {
|
|
||||||
if (str_eq(token.string, token_strings[k])) {
|
|
||||||
token.kind = cast(TokenKind)k;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -741,42 +856,41 @@ Token tokenizer_get_token(Tokenizer *t) {
|
|||||||
|
|
||||||
case '.':
|
case '.':
|
||||||
token.kind = Token_Period; // Default
|
token.kind = Token_Period; // Default
|
||||||
if (gb_is_between(t->curr_rune, '0', '9')) { // Might be a number
|
if (t->curr_rune == '.') { // Could be an ellipsis
|
||||||
token = scan_number_to_token(t, true);
|
|
||||||
} else if (t->curr_rune == '.') { // Could be an ellipsis
|
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
token.kind = Token_Ellipsis;
|
token.kind = Token_Ellipsis;
|
||||||
if (t->curr_rune == '<') {
|
// if (t->curr_rune == '<') {
|
||||||
advance_to_next_rune(t);
|
// advance_to_next_rune(t);
|
||||||
token.kind = Token_RangeExclusive;
|
// token.kind = Token_HalfOpenRange;
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '#': token.kind = Token_Hash; break;
|
case '#': token.kind = Token_Hash; break;
|
||||||
case '@': token.kind = Token_At; break;
|
case '@': token.kind = Token_At; break;
|
||||||
|
case '$': token.kind = Token_Dollar; break;
|
||||||
|
case '?': token.kind = Token_Question; break;
|
||||||
case '^': token.kind = Token_Pointer; break;
|
case '^': token.kind = Token_Pointer; break;
|
||||||
case '?': token.kind = Token_Maybe; break;
|
|
||||||
case ';': token.kind = Token_Semicolon; break;
|
case ';': token.kind = Token_Semicolon; break;
|
||||||
case ',': token.kind = Token_Comma; break;
|
case ',': token.kind = Token_Comma; break;
|
||||||
|
case ':': token.kind = Token_Colon; break;
|
||||||
case '(': token.kind = Token_OpenParen; break;
|
case '(': token.kind = Token_OpenParen; break;
|
||||||
case ')': token.kind = Token_CloseParen; break;
|
case ')': token.kind = Token_CloseParen; break;
|
||||||
case '[': token.kind = Token_OpenBracket; break;
|
case '[': token.kind = Token_OpenBracket; break;
|
||||||
case ']': token.kind = Token_CloseBracket; break;
|
case ']': token.kind = Token_CloseBracket; break;
|
||||||
case '{': token.kind = Token_OpenBrace; break;
|
case '{': token.kind = Token_OpenBrace; break;
|
||||||
case '}': token.kind = Token_CloseBrace; break;
|
case '}': token.kind = Token_CloseBrace; break;
|
||||||
case ':': token.kind = Token_Colon; break;
|
|
||||||
|
|
||||||
case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq); break;
|
case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq); break;
|
||||||
case '%': token.kind = token_kind_variant2(t, Token_Mod, Token_ModEq); break;
|
case '%': token.kind = token_kind_variant2(t, Token_Mod, Token_ModEq); break;
|
||||||
case '=': token.kind = token_kind_variant2(t, Token_Eq, Token_CmpEq); break;
|
case '=': token.kind = token_kind_variant2(t, Token_Eq, Token_CmpEq); break;
|
||||||
case '~': token.kind = token_kind_variant2(t, Token_Xor, Token_XorEq); break;
|
case '~': token.kind = token_kind_variant2(t, Token_Xor, Token_XorEq); break;
|
||||||
case '!': token.kind = token_kind_variant2(t, Token_Not, Token_NotEq); break;
|
case '!': token.kind = token_kind_variant2(t, Token_Not, Token_NotEq); break;
|
||||||
case '+': token.kind = token_kind_variant3(t, Token_Add, Token_AddEq, '+', Token_Increment); break;
|
case '+': token.kind = token_kind_variant3(t, Token_Add, Token_AddEq, '+', Token_Inc); break;
|
||||||
case '-': token.kind = token_kind_variant4(t, Token_Sub, Token_SubEq, '-', Token_Decrement, '>', Token_ArrowRight); break;
|
case '-': token.kind = token_kind_variant4(t, Token_Sub, Token_SubEq, '-', Token_Dec, '>', Token_ArrowRight); break;
|
||||||
case '/': {
|
case '/': {
|
||||||
if (t->curr_rune == '/') {
|
if (t->curr_rune == '/') {
|
||||||
while (t->curr_rune != '\n') {
|
while (t->curr_rune != '\n' && t->curr_rune != GB_RUNE_EOF) {
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
}
|
}
|
||||||
token.kind = Token_Comment;
|
token.kind = Token_Comment;
|
||||||
@@ -813,9 +927,7 @@ Token tokenizer_get_token(Tokenizer *t) {
|
|||||||
token.kind = token_kind_dub_eq(t, '<', Token_Lt, Token_LtEq, Token_Shl, Token_ShlEq);
|
token.kind = token_kind_dub_eq(t, '<', Token_Lt, Token_LtEq, Token_Shl, Token_ShlEq);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case '>':
|
case '>': token.kind = token_kind_dub_eq(t, '>', Token_Gt, Token_GtEq, Token_Shr, Token_ShrEq); break;
|
||||||
token.kind = token_kind_dub_eq(t, '>', Token_Gt, Token_GtEq, Token_Shr, Token_ShrEq);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '&':
|
case '&':
|
||||||
token.kind = Token_And;
|
token.kind = Token_And;
|
||||||
|
|||||||
+2170
File diff suppressed because it is too large
Load Diff
+1
-25
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
|
|
||||||
|
|
||||||
bool rune_is_letter(Rune r) {
|
bool rune_is_letter(Rune r) {
|
||||||
if ((r < 0x80 && gb_char_is_alpha(cast(char)r)) ||
|
if ((r < 0x80 && gb_char_is_alpha(cast(char)r)) ||
|
||||||
r == '_') {
|
r == '_') {
|
||||||
@@ -39,28 +40,3 @@ bool rune_is_whitespace(Rune r) {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool is_string_an_identifier(String s) {
|
|
||||||
isize offset = 0;
|
|
||||||
if (s.len < 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
while (offset < s.len) {
|
|
||||||
bool ok = false;
|
|
||||||
Rune r = -1;
|
|
||||||
isize size = gb_utf8_decode(s.text+offset, s.len-offset, &r);
|
|
||||||
if (offset == 0) {
|
|
||||||
ok = rune_is_letter(r);
|
|
||||||
} else {
|
|
||||||
ok = rune_is_letter(r) || rune_is_digit(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ok) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
offset += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
return offset == s.len;
|
|
||||||
}
|
|
||||||
|
|||||||
+66
-44
@@ -166,24 +166,24 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_encode_char(utf8proc_int32_t uc, ut
|
|||||||
if (uc < 0x00) {
|
if (uc < 0x00) {
|
||||||
return 0;
|
return 0;
|
||||||
} else if (uc < 0x80) {
|
} else if (uc < 0x80) {
|
||||||
dst[0] = uc;
|
dst[0] = (utf8proc_uint8_t) uc;
|
||||||
return 1;
|
return 1;
|
||||||
} else if (uc < 0x800) {
|
} else if (uc < 0x800) {
|
||||||
dst[0] = 0xC0 + (uc >> 6);
|
dst[0] = (utf8proc_uint8_t)(0xC0 + (uc >> 6));
|
||||||
dst[1] = 0x80 + (uc & 0x3F);
|
dst[1] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
|
||||||
return 2;
|
return 2;
|
||||||
// Note: we allow encoding 0xd800-0xdfff here, so as not to change
|
// Note: we allow encoding 0xd800-0xdfff here, so as not to change
|
||||||
// the API, however, these are actually invalid in UTF-8
|
// the API, however, these are actually invalid in UTF-8
|
||||||
} else if (uc < 0x10000) {
|
} else if (uc < 0x10000) {
|
||||||
dst[0] = 0xE0 + (uc >> 12);
|
dst[0] = (utf8proc_uint8_t)(0xE0 + (uc >> 12));
|
||||||
dst[1] = 0x80 + ((uc >> 6) & 0x3F);
|
dst[1] = (utf8proc_uint8_t)(0x80 + ((uc >> 6) & 0x3F));
|
||||||
dst[2] = 0x80 + (uc & 0x3F);
|
dst[2] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
|
||||||
return 3;
|
return 3;
|
||||||
} else if (uc < 0x110000) {
|
} else if (uc < 0x110000) {
|
||||||
dst[0] = 0xF0 + (uc >> 18);
|
dst[0] = (utf8proc_uint8_t)(0xF0 + (uc >> 18));
|
||||||
dst[1] = 0x80 + ((uc >> 12) & 0x3F);
|
dst[1] = (utf8proc_uint8_t)(0x80 + ((uc >> 12) & 0x3F));
|
||||||
dst[2] = 0x80 + ((uc >> 6) & 0x3F);
|
dst[2] = (utf8proc_uint8_t)(0x80 + ((uc >> 6) & 0x3F));
|
||||||
dst[3] = 0x80 + (uc & 0x3F);
|
dst[3] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
|
||||||
return 4;
|
return 4;
|
||||||
} else return 0;
|
} else return 0;
|
||||||
}
|
}
|
||||||
@@ -193,28 +193,28 @@ static utf8proc_ssize_t unsafe_encode_char(utf8proc_int32_t uc, utf8proc_uint8_t
|
|||||||
if (uc < 0x00) {
|
if (uc < 0x00) {
|
||||||
return 0;
|
return 0;
|
||||||
} else if (uc < 0x80) {
|
} else if (uc < 0x80) {
|
||||||
dst[0] = uc;
|
dst[0] = (utf8proc_uint8_t)uc;
|
||||||
return 1;
|
return 1;
|
||||||
} else if (uc < 0x800) {
|
} else if (uc < 0x800) {
|
||||||
dst[0] = 0xC0 + (uc >> 6);
|
dst[0] = (utf8proc_uint8_t)(0xC0 + (uc >> 6));
|
||||||
dst[1] = 0x80 + (uc & 0x3F);
|
dst[1] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
|
||||||
return 2;
|
return 2;
|
||||||
} else if (uc == 0xFFFF) {
|
} else if (uc == 0xFFFF) {
|
||||||
dst[0] = 0xFF;
|
dst[0] = (utf8proc_uint8_t)0xFF;
|
||||||
return 1;
|
return 1;
|
||||||
} else if (uc == 0xFFFE) {
|
} else if (uc == 0xFFFE) {
|
||||||
dst[0] = 0xFE;
|
dst[0] = (utf8proc_uint8_t)0xFE;
|
||||||
return 1;
|
return 1;
|
||||||
} else if (uc < 0x10000) {
|
} else if (uc < 0x10000) {
|
||||||
dst[0] = 0xE0 + (uc >> 12);
|
dst[0] = (utf8proc_uint8_t)(0xE0 + (uc >> 12));
|
||||||
dst[1] = 0x80 + ((uc >> 6) & 0x3F);
|
dst[1] = (utf8proc_uint8_t)(0x80 + ((uc >> 6) & 0x3F));
|
||||||
dst[2] = 0x80 + (uc & 0x3F);
|
dst[2] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
|
||||||
return 3;
|
return 3;
|
||||||
} else if (uc < 0x110000) {
|
} else if (uc < 0x110000) {
|
||||||
dst[0] = 0xF0 + (uc >> 18);
|
dst[0] = (utf8proc_uint8_t)(0xF0 + (uc >> 18));
|
||||||
dst[1] = 0x80 + ((uc >> 12) & 0x3F);
|
dst[1] = (utf8proc_uint8_t)(0x80 + ((uc >> 12) & 0x3F));
|
||||||
dst[2] = 0x80 + ((uc >> 6) & 0x3F);
|
dst[2] = (utf8proc_uint8_t)(0x80 + ((uc >> 6) & 0x3F));
|
||||||
dst[3] = 0x80 + (uc & 0x3F);
|
dst[3] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
|
||||||
return 4;
|
return 4;
|
||||||
} else return 0;
|
} else return 0;
|
||||||
}
|
}
|
||||||
@@ -383,7 +383,7 @@ UTF8PROC_DLLEXPORT int utf8proc_charwidth(utf8proc_int32_t c) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
UTF8PROC_DLLEXPORT utf8proc_category_t utf8proc_category(utf8proc_int32_t c) {
|
UTF8PROC_DLLEXPORT utf8proc_category_t utf8proc_category(utf8proc_int32_t c) {
|
||||||
return (utf8proc_category_t)utf8proc_get_property(c)->category;
|
return utf8proc_get_property(c)->category;
|
||||||
}
|
}
|
||||||
|
|
||||||
UTF8PROC_DLLEXPORT const char *utf8proc_category_string(utf8proc_int32_t c) {
|
UTF8PROC_DLLEXPORT const char *utf8proc_category_string(utf8proc_int32_t c) {
|
||||||
@@ -391,11 +391,9 @@ UTF8PROC_DLLEXPORT const char *utf8proc_category_string(utf8proc_int32_t c) {
|
|||||||
return s[utf8proc_category(c)];
|
return s[utf8proc_category(c)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define utf8proc_decompose_lump(replacement_uc) \
|
#define utf8proc_decompose_lump(replacement_uc) \
|
||||||
return utf8proc_decompose_char((utf8proc_int32_t)(replacement_uc), dst, bufsize, \
|
return utf8proc_decompose_char((replacement_uc), dst, bufsize, \
|
||||||
(utf8proc_option_t)((utf8proc_int32_t)options & ~UTF8PROC_LUMP), last_boundclass)
|
options & ~UTF8PROC_LUMP, last_boundclass)
|
||||||
|
|
||||||
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_char(utf8proc_int32_t uc, utf8proc_int32_t *dst, utf8proc_ssize_t bufsize, utf8proc_option_t options, int *last_boundclass) {
|
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_char(utf8proc_int32_t uc, utf8proc_int32_t *dst, utf8proc_ssize_t bufsize, utf8proc_option_t options, int *last_boundclass) {
|
||||||
const utf8proc_property_t *property;
|
const utf8proc_property_t *property;
|
||||||
@@ -458,12 +456,12 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_char(utf8proc_int32_t uc,
|
|||||||
category == UTF8PROC_CATEGORY_ME) return 0;
|
category == UTF8PROC_CATEGORY_ME) return 0;
|
||||||
}
|
}
|
||||||
if (options & UTF8PROC_CASEFOLD) {
|
if (options & UTF8PROC_CASEFOLD) {
|
||||||
if ((utf8proc_int16_t)property->casefold_seqindex != UINT16_MAX) {
|
if (property->casefold_seqindex != UINT16_MAX) {
|
||||||
return seqindex_write_char_decomposed(property->casefold_seqindex, dst, bufsize, options, last_boundclass);
|
return seqindex_write_char_decomposed(property->casefold_seqindex, dst, bufsize, options, last_boundclass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (options & (UTF8PROC_COMPOSE|UTF8PROC_DECOMPOSE)) {
|
if (options & (UTF8PROC_COMPOSE|UTF8PROC_DECOMPOSE)) {
|
||||||
if ((utf8proc_int16_t)property->decomp_seqindex != UINT16_MAX &&
|
if (property->decomp_seqindex != UINT16_MAX &&
|
||||||
(!property->decomp_type || (options & UTF8PROC_COMPAT))) {
|
(!property->decomp_type || (options & UTF8PROC_COMPAT))) {
|
||||||
return seqindex_write_char_decomposed(property->decomp_seqindex, dst, bufsize, options, last_boundclass);
|
return seqindex_write_char_decomposed(property->decomp_seqindex, dst, bufsize, options, last_boundclass);
|
||||||
}
|
}
|
||||||
@@ -485,6 +483,14 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_char(utf8proc_int32_t uc,
|
|||||||
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose(
|
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose(
|
||||||
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen,
|
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen,
|
||||||
utf8proc_int32_t *buffer, utf8proc_ssize_t bufsize, utf8proc_option_t options
|
utf8proc_int32_t *buffer, utf8proc_ssize_t bufsize, utf8proc_option_t options
|
||||||
|
) {
|
||||||
|
return utf8proc_decompose_custom(str, strlen, buffer, bufsize, options, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_custom(
|
||||||
|
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen,
|
||||||
|
utf8proc_int32_t *buffer, utf8proc_ssize_t bufsize, utf8proc_option_t options,
|
||||||
|
utf8proc_custom_func custom_func, void *custom_data
|
||||||
) {
|
) {
|
||||||
/* strlen will be ignored, if UTF8PROC_NULLTERM is set in options */
|
/* strlen will be ignored, if UTF8PROC_NULLTERM is set in options */
|
||||||
utf8proc_ssize_t wpos = 0;
|
utf8proc_ssize_t wpos = 0;
|
||||||
@@ -511,6 +517,9 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose(
|
|||||||
rpos += utf8proc_iterate(str + rpos, strlen - rpos, &uc);
|
rpos += utf8proc_iterate(str + rpos, strlen - rpos, &uc);
|
||||||
if (uc < 0) return UTF8PROC_ERROR_INVALIDUTF8;
|
if (uc < 0) return UTF8PROC_ERROR_INVALIDUTF8;
|
||||||
}
|
}
|
||||||
|
if (custom_func != NULL) {
|
||||||
|
uc = custom_func(uc, custom_data); /* user-specified custom mapping */
|
||||||
|
}
|
||||||
decomp_result = utf8proc_decompose_char(
|
decomp_result = utf8proc_decompose_char(
|
||||||
uc, buffer + wpos, (bufsize > wpos) ? (bufsize - wpos) : 0, options,
|
uc, buffer + wpos, (bufsize > wpos) ? (bufsize - wpos) : 0, options,
|
||||||
&boundclass
|
&boundclass
|
||||||
@@ -545,9 +554,8 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose(
|
|||||||
return wpos;
|
return wpos;
|
||||||
}
|
}
|
||||||
|
|
||||||
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_reencode(utf8proc_int32_t *buffer, utf8proc_ssize_t length, utf8proc_option_t options) {
|
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_normalize_utf32(utf8proc_int32_t *buffer, utf8proc_ssize_t length, utf8proc_option_t options) {
|
||||||
/* UTF8PROC_NULLTERM option will be ignored, 'length' is never ignored
|
/* UTF8PROC_NULLTERM option will be ignored, 'length' is never ignored */
|
||||||
ASSERT: 'buffer' has one spare byte of free space at the end! */
|
|
||||||
if (options & (UTF8PROC_NLF2LS | UTF8PROC_NLF2PS | UTF8PROC_STRIPCC)) {
|
if (options & (UTF8PROC_NLF2LS | UTF8PROC_NLF2PS | UTF8PROC_STRIPCC)) {
|
||||||
utf8proc_ssize_t rpos;
|
utf8proc_ssize_t rpos;
|
||||||
utf8proc_ssize_t wpos = 0;
|
utf8proc_ssize_t wpos = 0;
|
||||||
@@ -621,7 +629,7 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_reencode(utf8proc_int32_t *buffer,
|
|||||||
starter_property = unsafe_get_property(*starter);
|
starter_property = unsafe_get_property(*starter);
|
||||||
}
|
}
|
||||||
if (starter_property->comb_index < 0x8000 &&
|
if (starter_property->comb_index < 0x8000 &&
|
||||||
(utf8proc_int16_t)current_property->comb_index != UINT16_MAX &&
|
current_property->comb_index != UINT16_MAX &&
|
||||||
current_property->comb_index >= 0x8000) {
|
current_property->comb_index >= 0x8000) {
|
||||||
int sidx = starter_property->comb_index;
|
int sidx = starter_property->comb_index;
|
||||||
int idx = (current_property->comb_index & 0x3FFF) - utf8proc_combinations[sidx];
|
int idx = (current_property->comb_index & 0x3FFF) - utf8proc_combinations[sidx];
|
||||||
@@ -655,6 +663,14 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_reencode(utf8proc_int32_t *buffer,
|
|||||||
}
|
}
|
||||||
length = wpos;
|
length = wpos;
|
||||||
}
|
}
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_reencode(utf8proc_int32_t *buffer, utf8proc_ssize_t length, utf8proc_option_t options) {
|
||||||
|
/* UTF8PROC_NULLTERM option will be ignored, 'length' is never ignored
|
||||||
|
ASSERT: 'buffer' has one spare byte of free space at the end! */
|
||||||
|
length = utf8proc_normalize_utf32(buffer, length, options);
|
||||||
|
if (length < 0) return length;
|
||||||
{
|
{
|
||||||
utf8proc_ssize_t rpos, wpos = 0;
|
utf8proc_ssize_t rpos, wpos = 0;
|
||||||
utf8proc_int32_t uc;
|
utf8proc_int32_t uc;
|
||||||
@@ -676,15 +692,22 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_reencode(utf8proc_int32_t *buffer,
|
|||||||
|
|
||||||
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map(
|
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map(
|
||||||
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options
|
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options
|
||||||
|
) {
|
||||||
|
return utf8proc_map_custom(str, strlen, dstptr, options, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map_custom(
|
||||||
|
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options,
|
||||||
|
utf8proc_custom_func custom_func, void *custom_data
|
||||||
) {
|
) {
|
||||||
utf8proc_int32_t *buffer;
|
utf8proc_int32_t *buffer;
|
||||||
utf8proc_ssize_t result;
|
utf8proc_ssize_t result;
|
||||||
*dstptr = NULL;
|
*dstptr = NULL;
|
||||||
result = utf8proc_decompose(str, strlen, NULL, 0, options);
|
result = utf8proc_decompose_custom(str, strlen, NULL, 0, options, custom_func, custom_data);
|
||||||
if (result < 0) return result;
|
if (result < 0) return result;
|
||||||
buffer = (utf8proc_int32_t *) malloc(result * sizeof(utf8proc_int32_t) + 1);
|
buffer = (utf8proc_int32_t *) malloc(result * sizeof(utf8proc_int32_t) + 1);
|
||||||
if (!buffer) return UTF8PROC_ERROR_NOMEM;
|
if (!buffer) return UTF8PROC_ERROR_NOMEM;
|
||||||
result = utf8proc_decompose(str, strlen, buffer, result, options);
|
result = utf8proc_decompose_custom(str, strlen, buffer, result, options, custom_func, custom_data);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
free(buffer);
|
free(buffer);
|
||||||
return result;
|
return result;
|
||||||
@@ -705,29 +728,28 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map(
|
|||||||
|
|
||||||
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFD(const utf8proc_uint8_t *str) {
|
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFD(const utf8proc_uint8_t *str) {
|
||||||
utf8proc_uint8_t *retval;
|
utf8proc_uint8_t *retval;
|
||||||
utf8proc_map(str, 0, &retval, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE |
|
utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE |
|
||||||
UTF8PROC_DECOMPOSE));
|
UTF8PROC_DECOMPOSE);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFC(const utf8proc_uint8_t *str) {
|
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFC(const utf8proc_uint8_t *str) {
|
||||||
utf8proc_uint8_t *retval;
|
utf8proc_uint8_t *retval;
|
||||||
utf8proc_map(str, 0, &retval, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE |
|
utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE |
|
||||||
UTF8PROC_COMPOSE));
|
UTF8PROC_COMPOSE);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKD(const utf8proc_uint8_t *str) {
|
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKD(const utf8proc_uint8_t *str) {
|
||||||
utf8proc_uint8_t *retval;
|
utf8proc_uint8_t *retval;
|
||||||
utf8proc_map(str, 0, &retval, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE |
|
utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE |
|
||||||
UTF8PROC_DECOMPOSE | UTF8PROC_COMPAT));
|
UTF8PROC_DECOMPOSE | UTF8PROC_COMPAT);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC(const utf8proc_uint8_t *str) {
|
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC(const utf8proc_uint8_t *str) {
|
||||||
utf8proc_uint8_t *retval;
|
utf8proc_uint8_t *retval;
|
||||||
utf8proc_map(str, 0, &retval, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE |
|
utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE |
|
||||||
UTF8PROC_COMPOSE | UTF8PROC_COMPAT));
|
UTF8PROC_COMPOSE | UTF8PROC_COMPAT);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+81
-25
@@ -71,14 +71,15 @@
|
|||||||
/** The MAJOR version number (increased when backwards API compatibility is broken). */
|
/** The MAJOR version number (increased when backwards API compatibility is broken). */
|
||||||
#define UTF8PROC_VERSION_MAJOR 2
|
#define UTF8PROC_VERSION_MAJOR 2
|
||||||
/** The MINOR version number (increased when new functionality is added in a backwards-compatible manner). */
|
/** The MINOR version number (increased when new functionality is added in a backwards-compatible manner). */
|
||||||
#define UTF8PROC_VERSION_MINOR 0
|
#define UTF8PROC_VERSION_MINOR 1
|
||||||
/** The PATCH version (increased for fixes that do not change the API). */
|
/** The PATCH version (increased for fixes that do not change the API). */
|
||||||
#define UTF8PROC_VERSION_PATCH 2
|
#define UTF8PROC_VERSION_PATCH 0
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/types.h>
|
|
||||||
#ifdef _MSC_VER
|
#if defined(_MSC_VER) && _MSC_VER < 1800
|
||||||
|
// MSVC prior to 2013 lacked stdbool.h and inttypes.h
|
||||||
typedef signed char utf8proc_int8_t;
|
typedef signed char utf8proc_int8_t;
|
||||||
typedef unsigned char utf8proc_uint8_t;
|
typedef unsigned char utf8proc_uint8_t;
|
||||||
typedef short utf8proc_int16_t;
|
typedef short utf8proc_int16_t;
|
||||||
@@ -93,12 +94,18 @@ typedef int utf8proc_ssize_t;
|
|||||||
typedef unsigned int utf8proc_size_t;
|
typedef unsigned int utf8proc_size_t;
|
||||||
# endif
|
# endif
|
||||||
# ifndef __cplusplus
|
# ifndef __cplusplus
|
||||||
|
// emulate C99 bool
|
||||||
typedef unsigned char utf8proc_bool;
|
typedef unsigned char utf8proc_bool;
|
||||||
// enum {false, true};
|
# ifndef __bool_true_false_are_defined
|
||||||
|
# define false 0
|
||||||
|
# define true 1
|
||||||
|
# define __bool_true_false_are_defined 1
|
||||||
|
# endif
|
||||||
# else
|
# else
|
||||||
typedef bool utf8proc_bool;
|
typedef bool utf8proc_bool;
|
||||||
# endif
|
# endif
|
||||||
#else
|
#else
|
||||||
|
# include <stddef.h>
|
||||||
# include <stdbool.h>
|
# include <stdbool.h>
|
||||||
# include <inttypes.h>
|
# include <inttypes.h>
|
||||||
typedef int8_t utf8proc_int8_t;
|
typedef int8_t utf8proc_int8_t;
|
||||||
@@ -108,22 +115,12 @@ typedef uint16_t utf8proc_uint16_t;
|
|||||||
typedef int32_t utf8proc_int32_t;
|
typedef int32_t utf8proc_int32_t;
|
||||||
typedef uint32_t utf8proc_uint32_t;
|
typedef uint32_t utf8proc_uint32_t;
|
||||||
typedef size_t utf8proc_size_t;
|
typedef size_t utf8proc_size_t;
|
||||||
typedef ssize_t utf8proc_ssize_t;
|
typedef ptrdiff_t utf8proc_ssize_t;
|
||||||
typedef bool utf8proc_bool;
|
typedef bool utf8proc_bool;
|
||||||
#endif
|
#endif
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#define UTF8PROC_DLLEXPORT
|
||||||
# ifdef UTF8PROC_EXPORTS
|
|
||||||
# define UTF8PROC_DLLEXPORT __declspec(dllexport)
|
|
||||||
# else
|
|
||||||
# define UTF8PROC_DLLEXPORT /*__declspec(dllimport)*/
|
|
||||||
# endif
|
|
||||||
#elif __GNUC__ >= 4
|
|
||||||
# define UTF8PROC_DLLEXPORT __attribute__ ((visibility("default")))
|
|
||||||
#else
|
|
||||||
# define UTF8PROC_DLLEXPORT
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -134,7 +131,7 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef UINT16_MAX
|
#ifndef UINT16_MAX
|
||||||
# define UINT16_MAX ~(utf8proc_uint16_t)0
|
# define UINT16_MAX 65535U
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -373,6 +370,13 @@ typedef enum {
|
|||||||
UTF8PROC_BOUNDCLASS_E_BASE_GAZ = 18, /**< E_BASE + GLUE_AFTER_ZJW */
|
UTF8PROC_BOUNDCLASS_E_BASE_GAZ = 18, /**< E_BASE + GLUE_AFTER_ZJW */
|
||||||
} utf8proc_boundclass_t;
|
} utf8proc_boundclass_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function pointer type passed to @ref utf8proc_map_custom and
|
||||||
|
* @ref utf8proc_decompose_custom, which is used to specify a user-defined
|
||||||
|
* mapping of codepoints to be applied in conjunction with other mappings.
|
||||||
|
*/
|
||||||
|
typedef utf8proc_int32_t (*utf8proc_custom_func)(utf8proc_int32_t codepoint, void *data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Array containing the byte lengths of a UTF-8 encoded codepoint based
|
* Array containing the byte lengths of a UTF-8 encoded codepoint based
|
||||||
* on the first byte.
|
* on the first byte.
|
||||||
@@ -480,6 +484,7 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_char(
|
|||||||
* `buffer` (which must contain at least `bufsize` entries). In case of
|
* `buffer` (which must contain at least `bufsize` entries). In case of
|
||||||
* success, the number of codepoints written is returned; in case of an
|
* success, the number of codepoints written is returned; in case of an
|
||||||
* error, a negative error code is returned (@ref utf8proc_errmsg).
|
* error, a negative error code is returned (@ref utf8proc_errmsg).
|
||||||
|
* See @ref utf8proc_decompose_custom to supply additional transformations.
|
||||||
*
|
*
|
||||||
* If the number of written codepoints would be bigger than `bufsize`, the
|
* If the number of written codepoints would be bigger than `bufsize`, the
|
||||||
* required buffer size is returned, while the buffer will be overwritten with
|
* required buffer size is returned, while the buffer will be overwritten with
|
||||||
@@ -491,8 +496,20 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose(
|
|||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reencodes the sequence of `length` codepoints pointed to by `buffer`
|
* The same as @ref utf8proc_decompose, but also takes a `custom_func` mapping function
|
||||||
* UTF-8 data in-place (i.e., the result is also stored in `buffer`).
|
* that is called on each codepoint in `str` before any other transformations
|
||||||
|
* (along with a `custom_data` pointer that is passed through to `custom_func`).
|
||||||
|
* The `custom_func` argument is ignored if it is `NULL`. See also @ref utf8proc_map_custom.
|
||||||
|
*/
|
||||||
|
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_custom(
|
||||||
|
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen,
|
||||||
|
utf8proc_int32_t *buffer, utf8proc_ssize_t bufsize, utf8proc_option_t options,
|
||||||
|
utf8proc_custom_func custom_func, void *custom_data
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizes the sequence of `length` codepoints pointed to by `buffer`
|
||||||
|
* in-place (i.e., the result is also stored in `buffer`).
|
||||||
*
|
*
|
||||||
* @param buffer the (native-endian UTF-32) unicode codepoints to re-encode.
|
* @param buffer the (native-endian UTF-32) unicode codepoints to re-encode.
|
||||||
* @param length the length (in codepoints) of the buffer.
|
* @param length the length (in codepoints) of the buffer.
|
||||||
@@ -507,9 +524,37 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose(
|
|||||||
* the unicode versioning stability
|
* the unicode versioning stability
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* In case of success, the length (in bytes) of the resulting UTF-8 string is
|
* In case of success, the length (in codepoints) of the normalized UTF-32 string is
|
||||||
* returned; otherwise, a negative error code is returned (@ref utf8proc_errmsg).
|
* returned; otherwise, a negative error code is returned (@ref utf8proc_errmsg).
|
||||||
*
|
*
|
||||||
|
* @warning The entries of the array pointed to by `str` have to be in the
|
||||||
|
* range `0x0000` to `0x10FFFF`. Otherwise, the program might crash!
|
||||||
|
*/
|
||||||
|
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_normalize_utf32(utf8proc_int32_t *buffer, utf8proc_ssize_t length, utf8proc_option_t options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reencodes the sequence of `length` codepoints pointed to by `buffer`
|
||||||
|
* UTF-8 data in-place (i.e., the result is also stored in `buffer`).
|
||||||
|
* Can optionally normalize the UTF-32 sequence prior to UTF-8 conversion.
|
||||||
|
*
|
||||||
|
* @param buffer the (native-endian UTF-32) unicode codepoints to re-encode.
|
||||||
|
* @param length the length (in codepoints) of the buffer.
|
||||||
|
* @param options a bitwise or (`|`) of one or more of the following flags:
|
||||||
|
* - @ref UTF8PROC_NLF2LS - convert LF, CRLF, CR and NEL into LS
|
||||||
|
* - @ref UTF8PROC_NLF2PS - convert LF, CRLF, CR and NEL into PS
|
||||||
|
* - @ref UTF8PROC_NLF2LF - convert LF, CRLF, CR and NEL into LF
|
||||||
|
* - @ref UTF8PROC_STRIPCC - strip or convert all non-affected control characters
|
||||||
|
* - @ref UTF8PROC_COMPOSE - try to combine decomposed codepoints into composite
|
||||||
|
* codepoints
|
||||||
|
* - @ref UTF8PROC_STABLE - prohibit combining characters that would violate
|
||||||
|
* the unicode versioning stability
|
||||||
|
* - @ref UTF8PROC_CHARBOUND - insert 0xFF bytes before each grapheme cluster
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* In case of success, the length (in bytes) of the resulting nul-terminated
|
||||||
|
* UTF-8 string is returned; otherwise, a negative error code is returned
|
||||||
|
* (@ref utf8proc_errmsg).
|
||||||
|
*
|
||||||
* @warning The amount of free space pointed to by `buffer` must
|
* @warning The amount of free space pointed to by `buffer` must
|
||||||
* exceed the amount of the input data by one byte, and the
|
* exceed the amount of the input data by one byte, and the
|
||||||
* entries of the array pointed to by `str` have to be in the
|
* entries of the array pointed to by `str` have to be in the
|
||||||
@@ -595,7 +640,8 @@ UTF8PROC_DLLEXPORT const char *utf8proc_category_string(utf8proc_int32_t codepoi
|
|||||||
* in any case the result will be NULL terminated (though it might
|
* in any case the result will be NULL terminated (though it might
|
||||||
* contain NULL characters with the string if `str` contained NULL
|
* contain NULL characters with the string if `str` contained NULL
|
||||||
* characters). Other flags in the `options` field are passed to the
|
* characters). Other flags in the `options` field are passed to the
|
||||||
* functions defined above, and regarded as described.
|
* functions defined above, and regarded as described. See also
|
||||||
|
* @ref utfproc_map_custom to supply a custom codepoint transformation.
|
||||||
*
|
*
|
||||||
* In case of success the length of the new string is returned,
|
* In case of success the length of the new string is returned,
|
||||||
* otherwise a negative error code is returned.
|
* otherwise a negative error code is returned.
|
||||||
@@ -607,6 +653,17 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map(
|
|||||||
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options
|
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like @ref utf8proc_map, but also takes a `custom_func` mapping function
|
||||||
|
* that is called on each codepoint in `str` before any other transformations
|
||||||
|
* (along with a `custom_data` pointer that is passed through to `custom_func`).
|
||||||
|
* The `custom_func` argument is ignored if it is `NULL`.
|
||||||
|
*/
|
||||||
|
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map_custom(
|
||||||
|
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options,
|
||||||
|
utf8proc_custom_func custom_func, void *custom_data
|
||||||
|
);
|
||||||
|
|
||||||
/** @name Unicode normalization
|
/** @name Unicode normalization
|
||||||
*
|
*
|
||||||
* Returns a pointer to newly allocated memory of a NFD, NFC, NFKD or NFKC
|
* Returns a pointer to newly allocated memory of a NFD, NFC, NFKD or NFKC
|
||||||
@@ -619,9 +676,9 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map(
|
|||||||
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFD(const utf8proc_uint8_t *str);
|
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFD(const utf8proc_uint8_t *str);
|
||||||
/** NFC normalization (@ref UTF8PROC_COMPOSE). */
|
/** NFC normalization (@ref UTF8PROC_COMPOSE). */
|
||||||
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFC(const utf8proc_uint8_t *str);
|
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFC(const utf8proc_uint8_t *str);
|
||||||
/** NFD normalization (@ref UTF8PROC_DECOMPOSE and @ref UTF8PROC_COMPAT). */
|
/** NFKD normalization (@ref UTF8PROC_DECOMPOSE and @ref UTF8PROC_COMPAT). */
|
||||||
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKD(const utf8proc_uint8_t *str);
|
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKD(const utf8proc_uint8_t *str);
|
||||||
/** NFD normalization (@ref UTF8PROC_COMPOSE and @ref UTF8PROC_COMPAT). */
|
/** NFKC normalization (@ref UTF8PROC_COMPOSE and @ref UTF8PROC_COMPAT). */
|
||||||
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC(const utf8proc_uint8_t *str);
|
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC(const utf8proc_uint8_t *str);
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
@@ -630,4 +687,3 @@ UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC(const utf8proc_uint8_t *str);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
#pragma warning(push)
|
static const utf8proc_uint16_t utf8proc_sequences[] = {
|
||||||
#pragma warning(disable: 4838)
|
|
||||||
|
|
||||||
const utf8proc_uint16_t utf8proc_sequences[] = {
|
|
||||||
97, 98, 99, 100, 101, 102, 103,
|
97, 98, 99, 100, 101, 102, 103,
|
||||||
104, 105, 106, 107, 108, 109, 110, 111,
|
104, 105, 106, 107, 108, 109, 110, 111,
|
||||||
112, 113, 114, 115, 116, 117, 118, 119,
|
112, 113, 114, 115, 116, 117, 118, 119,
|
||||||
@@ -1179,7 +1176,7 @@ const utf8proc_uint16_t utf8proc_sequences[] = {
|
|||||||
56603, 55354, 56604, 55354, 56605, 55354, 56606, 55354,
|
56603, 55354, 56604, 55354, 56605, 55354, 56606, 55354,
|
||||||
56607, 55354, 56608, 55354, 56609, };
|
56607, 55354, 56608, 55354, 56609, };
|
||||||
|
|
||||||
const utf8proc_uint16_t utf8proc_stage1table[] = {
|
static const utf8proc_uint16_t utf8proc_stage1table[] = {
|
||||||
0, 256, 512, 768, 1024, 1280, 1536,
|
0, 256, 512, 768, 1024, 1280, 1536,
|
||||||
1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584,
|
1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584,
|
||||||
3840, 4096, 4352, 4608, 4864, 5120, 5376, 5632,
|
3840, 4096, 4352, 4608, 4864, 5120, 5376, 5632,
|
||||||
@@ -1726,7 +1723,7 @@ const utf8proc_uint16_t utf8proc_stage1table[] = {
|
|||||||
18432, 18432, 18432, 18432, 18432, 18432, 18432, 18432,
|
18432, 18432, 18432, 18432, 18432, 18432, 18432, 18432,
|
||||||
38656, };
|
38656, };
|
||||||
|
|
||||||
const utf8proc_uint16_t utf8proc_stage2table[] = {
|
static const utf8proc_uint16_t utf8proc_stage2table[] = {
|
||||||
1, 2, 2, 2, 2, 2, 2,
|
1, 2, 2, 2, 2, 2, 2,
|
||||||
2, 2, 3, 4, 3, 5, 6, 2,
|
2, 2, 3, 4, 3, 5, 6, 2,
|
||||||
2, 2, 2, 2, 2, 2, 2, 2,
|
2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
@@ -5899,7 +5896,7 @@ const utf8proc_uint16_t utf8proc_stage2table[] = {
|
|||||||
540, 540, 540, 1180, 0, 0, 0, 0,
|
540, 540, 540, 1180, 0, 0, 0, 0,
|
||||||
0, 1154, 1154, 1154, 1154, 1154, 1154, 1154,
|
0, 1154, 1154, 1154, 1154, 1154, 1154, 1154,
|
||||||
1154, 1154, 1154, 0, 0, 0, 0, 1103,
|
1154, 1154, 1154, 0, 0, 0, 0, 1103,
|
||||||
1158, 0, 0, 0, 0, 0, 0, 0,
|
1103, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
@@ -6593,7 +6590,7 @@ const utf8proc_uint16_t utf8proc_stage2table[] = {
|
|||||||
3984, 3984, 3984, 3984, 3984, 3984, 3984, 0,
|
3984, 3984, 3984, 3984, 3984, 3984, 3984, 0,
|
||||||
0, };
|
0, };
|
||||||
|
|
||||||
const utf8proc_property_t utf8proc_properties[] = {
|
static const utf8proc_property_t utf8proc_properties[] = {
|
||||||
{0, 0, 0, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false,false,false,false, 0, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
{0, 0, 0, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false,false,false,false, 0, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
||||||
{UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_BN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL},
|
{UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_BN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL},
|
||||||
{UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_BN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL},
|
{UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_BN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL},
|
||||||
@@ -7850,7 +7847,7 @@ const utf8proc_property_t utf8proc_properties[] = {
|
|||||||
{UTF8PROC_CATEGORY_MN, 122, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND},
|
{UTF8PROC_CATEGORY_MN, 122, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND},
|
||||||
{UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 9523, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
{UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 9523, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
||||||
{UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 9525, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
{UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 9525, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
||||||
{UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NOBREAK, 1335, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
{UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NOBREAK, 1335, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
||||||
{UTF8PROC_CATEGORY_MN, 216, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND},
|
{UTF8PROC_CATEGORY_MN, 216, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND},
|
||||||
{UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
{UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
||||||
{UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
{UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
||||||
@@ -10478,7 +10475,7 @@ const utf8proc_property_t utf8proc_properties[] = {
|
|||||||
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1470, UINT16_MAX, 1470, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1470, UINT16_MAX, 1470, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
||||||
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1478, UINT16_MAX, 1478, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1478, UINT16_MAX, 1478, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
||||||
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5132, UINT16_MAX, 5132, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5132, UINT16_MAX, 5132, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
||||||
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1480, UINT16_MAX, 1480, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1480, UINT16_MAX, 1480, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
||||||
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5133, UINT16_MAX, 5133, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5133, UINT16_MAX, 5133, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
||||||
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5134, UINT16_MAX, 5134, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5134, UINT16_MAX, 5134, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
||||||
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1482, UINT16_MAX, 1482, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1482, UINT16_MAX, 1482, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
||||||
@@ -12168,7 +12165,7 @@ const utf8proc_property_t utf8proc_properties[] = {
|
|||||||
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6787, UINT16_MAX, 6787, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6787, UINT16_MAX, 6787, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
||||||
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6789, UINT16_MAX, 6789, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6789, UINT16_MAX, 6789, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
||||||
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6791, UINT16_MAX, 6791, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6791, UINT16_MAX, 6791, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
||||||
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6793, UINT16_MAX, 6793, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6793, UINT16_MAX, 6793, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
||||||
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6795, UINT16_MAX, 6795, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6795, UINT16_MAX, 6795, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
||||||
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6797, UINT16_MAX, 6797, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6797, UINT16_MAX, 6797, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
||||||
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6799, UINT16_MAX, 6799, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6799, UINT16_MAX, 6799, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
||||||
@@ -12204,7 +12201,7 @@ const utf8proc_property_t utf8proc_properties[] = {
|
|||||||
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9104, UINT16_MAX, 9104, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9104, UINT16_MAX, 9104, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
||||||
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9106, UINT16_MAX, 9106, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9106, UINT16_MAX, 9106, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
||||||
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9108, UINT16_MAX, 9108, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9108, UINT16_MAX, 9108, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
||||||
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9110, UINT16_MAX, 9110, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9110, UINT16_MAX, 9110, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
||||||
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9112, UINT16_MAX, 9112, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9112, UINT16_MAX, 9112, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
||||||
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9114, UINT16_MAX, 9114, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9114, UINT16_MAX, 9114, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
||||||
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9116, UINT16_MAX, 9116, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9116, UINT16_MAX, 9116, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
||||||
@@ -13423,7 +13420,7 @@ const utf8proc_property_t utf8proc_properties[] = {
|
|||||||
{UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7975, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
{UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7975, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
|
||||||
};
|
};
|
||||||
|
|
||||||
const utf8proc_uint16_t utf8proc_combinations[] = {
|
static const utf8proc_uint16_t utf8proc_combinations[] = {
|
||||||
0, 46, 192, 193, 194, 195, 196, 197, 0,
|
0, 46, 192, 193, 194, 195, 196, 197, 0,
|
||||||
256, 258, 260, 550, 461, 0, 0, 512,
|
256, 258, 260, 550, 461, 0, 0, 512,
|
||||||
514, 0, 0, 0, 0, 0, 0, 0,
|
514, 0, 0, 0, 0, 0, 0, 0,
|
||||||
@@ -14386,5 +14383,3 @@ const utf8proc_uint16_t utf8proc_combinations[] = {
|
|||||||
72, 75,
|
72, 75,
|
||||||
1, 53694, 1, 53696,
|
1, 53694, 1, 53696,
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma warning(pop)
|
|
||||||
|
|||||||
Reference in New Issue
Block a user