mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-05 19:21:37 -07:00
Compare commits
106 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a75ccb6fbc | |||
| 188b290dd5 | |||
| c6ff961088 | |||
| c26990c22d | |||
| c34d839f9f | |||
| 5562364a98 | |||
| 32150e401e | |||
| aaec8bf423 | |||
| 0fcbda951a | |||
| e2734a2dc6 | |||
| 5adfbec847 | |||
| 4ef4605d6d | |||
| 2aa402f462 | |||
| 00f6bee454 | |||
| 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 |
+2
-3
@@ -252,6 +252,5 @@ paket-files/
|
||||
|
||||
# Project Specific
|
||||
*.sln
|
||||
!misc/llvm-bim/lli.exe
|
||||
!misc/llvm-bim/opt.exe
|
||||
builds
|
||||
builds/
|
||||
bin/
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<img src="logo-slim.png" alt="Odin logo" height="74">
|
||||
<img src="misc/logo-slim.png" alt="Odin logo" height="74">
|
||||
|
||||
# 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
|
||||
* high performance
|
||||
* 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)
|
||||
* [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)
|
||||
* [when, for, & procedure overloading](https://www.youtube.com/watch?v=OzeOekzyZK8)
|
||||
|
||||
## Requirements to build and run
|
||||
|
||||
@@ -26,31 +27,30 @@ Odin is fast, concise, readable, pragmatic and open sourced. It is designed with
|
||||
* MSVC 2015 installed (C99 support)
|
||||
* Requires MSVC's link.exe as the linker
|
||||
- run `vcvarsall.bat` to setup the path
|
||||
* [LLVM binaries](https://github.com/gingerBill/Odin/releases/tag/llvm-4.0-windows) for `opt.exe` and `llc.exe`
|
||||
|
||||
## Warnings
|
||||
|
||||
* This is still highly in development and the language's design is quite volatile.
|
||||
* Syntax is definitely not fixed
|
||||
* Syntax is not fixed.
|
||||
|
||||
## Roadmap
|
||||
|
||||
Not in any particular order
|
||||
Not in any particular order and not be implemented
|
||||
|
||||
* Custom backend to replace LLVM
|
||||
- Improve SSA design to accommodate for lowering to a "bytecode"
|
||||
- SSA optimizations
|
||||
- COFF generation
|
||||
- linker
|
||||
* Type safe "macros"
|
||||
* Documentation generator for "Entities"
|
||||
* Multiple architecture support
|
||||
* Inline assembly
|
||||
* Linking options
|
||||
- Executable
|
||||
- Static/Dynamic Library
|
||||
* Debug information
|
||||
* Compile Time Execution (CTE)
|
||||
- More metaprogramming madness
|
||||
- Compiler as a library
|
||||
- AST inspection and modification
|
||||
* CTE-based build system
|
||||
* Replace LLVM backend with my own custom backend
|
||||
* Improve SSA design to accommodate for lowering to a "bytecode"
|
||||
* SSA optimizations
|
||||
* Documentation Generator for "Entities"
|
||||
* Multiple Architecture support
|
||||
* Debug Information
|
||||
- pdb format too
|
||||
* Command line tooling
|
||||
* Compiler internals:
|
||||
* Command Line Tooling
|
||||
* Compiler Internals:
|
||||
- Big numbers library
|
||||
|
||||
- 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.
@@ -5,7 +5,6 @@ set exe_name=odin.exe
|
||||
|
||||
:: Debug = 0, Release = 1
|
||||
set release_mode=1
|
||||
|
||||
set compiler_flags= -nologo -Oi -TC -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR-
|
||||
|
||||
if %release_mode% EQU 0 ( rem Debug
|
||||
@@ -46,14 +45,11 @@ del *.ilk > NUL 2> NUL
|
||||
cl %compiler_settings% "src\main.c" ^
|
||||
/link %linker_settings% -OUT:%exe_name% ^
|
||||
&& odin run code/demo.odin
|
||||
rem && odin build_dll code/example.odin ^
|
||||
rem && odin run code/demo.odin
|
||||
rem && odin build code/metagen.odin ^
|
||||
rem && call "code\metagen.exe" "src\ast_nodes.metagen"
|
||||
rem && odin run code/Jaze/src/main.odin
|
||||
|
||||
rem pushd src\asm
|
||||
rem nasm hellope.asm -fwin64 -o hellope.obj ^
|
||||
rem && cl /nologo hellope.obj /link kernel32.lib /entry:main ^
|
||||
rem && hellope.exe
|
||||
rem popd
|
||||
del *.obj > NUL 2> NUL
|
||||
|
||||
:end_of_build
|
||||
|
||||
|
||||
+315
-65
@@ -1,70 +1,320 @@
|
||||
#foreign_system_library "winmm" when ODIN_OS == "windows";
|
||||
#import win32 "sys/windows.odin" when ODIN_OS == "windows";
|
||||
#import "atomic.odin";
|
||||
#import "hash.odin";
|
||||
#import "mem.odin";
|
||||
#import "opengl.odin";
|
||||
#import "strconv.odin";
|
||||
#import "sync.odin";
|
||||
#import win32 "sys/windows.odin";
|
||||
|
||||
#import "fmt.odin";
|
||||
#import "os.odin";
|
||||
#import "math.odin";
|
||||
|
||||
timeGetTime :: proc() -> u32 #foreign #dll_import
|
||||
GetSystemTimeAsFileTime :: proc(SystemTimeAsFileTime : ^win32.FILETIME) #foreign #dll_import
|
||||
|
||||
GetCommandLineArguments :: proc() -> []string {
|
||||
argString := win32.GetCommandLineA();
|
||||
fullArgString := to_odin_string(argString);
|
||||
// Count Spaces
|
||||
for r : fullArgString {
|
||||
fmt.println(r);
|
||||
}
|
||||
main :: proc() {
|
||||
when true {
|
||||
/*
|
||||
Added:
|
||||
* Unexported entities and fields using an underscore prefix
|
||||
- See `sync.odin` and explain
|
||||
|
||||
Removed:
|
||||
* Maybe/option types
|
||||
* Remove `type` keyword and other "reserved" keywords
|
||||
* ..< and ... removed and replace with .. (half-closed range)
|
||||
|
||||
Changed:
|
||||
* `compile_assert` and `assert`return the value of the condition for semantic reasons
|
||||
* 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
|
||||
*/
|
||||
|
||||
{
|
||||
Fruit :: enum {
|
||||
APPLE,
|
||||
BANANA,
|
||||
COCONUT,
|
||||
}
|
||||
fmt.println(Fruit.names);
|
||||
}
|
||||
|
||||
{
|
||||
A :: struct {x, y: f32};
|
||||
B :: struct #align 16 {x, y: f32};
|
||||
fmt.println("align_of(A) =", align_of(A));
|
||||
fmt.println("align_of(B) =", align_of(B));
|
||||
}
|
||||
|
||||
{
|
||||
// Removal of ..< and ...
|
||||
for i in 0..16 {
|
||||
}
|
||||
// Is similar to
|
||||
for _i := 0; _i < 16; _i++ { immutable i := _i;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
#label thing
|
||||
for i in 0..10 {
|
||||
for j in i+1..10 {
|
||||
if j == 2 {
|
||||
fmt.println(i, j);
|
||||
continue thing;
|
||||
}
|
||||
if j == 3 {
|
||||
break thing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Works with, `for`, `for in`, `match`, `match in`
|
||||
// NOTE(bill): This solves most of the problems I need `goto` for
|
||||
}
|
||||
|
||||
{
|
||||
t := type_info(int);
|
||||
using Type_Info;
|
||||
match i in t {
|
||||
case Integer, Float:
|
||||
fmt.println("It's a number");
|
||||
}
|
||||
|
||||
|
||||
x: any = 123;
|
||||
#label foo
|
||||
match i in x {
|
||||
case int, f32:
|
||||
fmt.println("It's an int or f32");
|
||||
break foo;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
cond := true;
|
||||
x: int;
|
||||
if cond {
|
||||
x = 3;
|
||||
} else {
|
||||
x = 4;
|
||||
}
|
||||
|
||||
|
||||
// Ternary operator
|
||||
y := cond ? 3 : 4;
|
||||
|
||||
FOO :: true ? 123 : 432; // Constant ternary expression
|
||||
fmt.println("Ternary values:", y, FOO);
|
||||
}
|
||||
|
||||
{
|
||||
// Slices now store a capacity
|
||||
buf: [256]byte;
|
||||
s: []byte;
|
||||
s = buf[..0]; // == buf[0..0];
|
||||
fmt.println("count =", s.count);
|
||||
fmt.println("capacity =", s.capacity);
|
||||
append(s, 1, 2, 3);
|
||||
fmt.println(s);
|
||||
|
||||
s = buf[1..2..3];
|
||||
fmt.println("count =", s.count);
|
||||
fmt.println("capacity =", s.capacity);
|
||||
fmt.println(s);
|
||||
|
||||
clear(s); // Sets count to zero
|
||||
s.count = 0; // Equivalent
|
||||
}
|
||||
|
||||
{
|
||||
Foo :: struct {
|
||||
x, y, z: f32,
|
||||
ok: bool,
|
||||
flags: u32,
|
||||
}
|
||||
foo_array: [256]Foo;
|
||||
foo_as_bytes: []byte = slice_to_bytes(foo_array[..]);
|
||||
// Useful for things like
|
||||
// os.write(handle, foo_as_bytes);
|
||||
|
||||
foo_slice := slice_ptr(cast(^Foo)foo_as_bytes.data, foo_as_bytes.count/size_of(Foo), foo_as_bytes.capacity/size_of(Foo));
|
||||
// Question: Should there be a bytes_to_slice procedure or is it clearer to do this even if it is error prone?
|
||||
// And if so what would the syntax be?
|
||||
// slice_transmute([]Foo, foo_as_bytes);
|
||||
}
|
||||
|
||||
{
|
||||
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
|
||||
}
|
||||
|
||||
{
|
||||
// fmt.* changes
|
||||
// bprint* returns `int` (bytes written)
|
||||
// sprint* returns `string` (bytes written as a string)
|
||||
|
||||
data: [256]byte;
|
||||
str := fmt.sprintf(data[..0], "Hellope %d %s %c", 123, "others", '!');
|
||||
fmt.println(str);
|
||||
|
||||
buf := data[..0];
|
||||
count := fmt.bprintf(^buf, "Hellope %d %s %c", 123, "others", '!');
|
||||
fmt.println(cast(string)buf[..count]);
|
||||
|
||||
// NOTE(bill): We may change this but because this is a library feature, I am not that bothered yet
|
||||
}
|
||||
|
||||
{
|
||||
x: [dynamic]f64;
|
||||
reserve(x, 16);
|
||||
defer free(x); // `free` is overloaded for numerous types
|
||||
// Number literals can have underscores in them for readability
|
||||
append(x, 2_000_000.500_000, 3, 5, 7); // variadic append
|
||||
|
||||
for p, i in x {
|
||||
if i > 0 { fmt.print(", "); }
|
||||
fmt.print(p);
|
||||
}
|
||||
fmt.println();
|
||||
}
|
||||
|
||||
{
|
||||
// Dynamic array "literals"
|
||||
x := [dynamic]f64{2_000_000.500_000, 3, 5, 7};
|
||||
defer free(x);
|
||||
fmt.println(x); // fmt.print* supports printing of dynamic types
|
||||
clear(x);
|
||||
fmt.println(x);
|
||||
}
|
||||
|
||||
{
|
||||
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);
|
||||
|
||||
delete(m, "c"); // deletes entry with key "c"
|
||||
_, found := m["c"];
|
||||
assert(!found);
|
||||
|
||||
fmt.println(m);
|
||||
clear(m);
|
||||
fmt.println(m);
|
||||
|
||||
// NOTE: Fixed size maps are planned but we have not yet implemented
|
||||
// them as we have had no need for them as of yet
|
||||
}
|
||||
|
||||
{
|
||||
Vector3 :: struct{x, y, z: f32};
|
||||
Quaternion :: struct{x, y, z, w: f32};
|
||||
|
||||
Entity :: union {
|
||||
// Common Fields
|
||||
id: u64,
|
||||
name: string,
|
||||
using position: Vector3,
|
||||
orientation: Quaternion,
|
||||
flags: u32,
|
||||
|
||||
// Variants
|
||||
Frog{
|
||||
ribbit_volume: f32,
|
||||
jump_height: f32,
|
||||
},
|
||||
Door{
|
||||
openness: f32,
|
||||
},
|
||||
Map{
|
||||
width, height: f32,
|
||||
place_positions: []Vector3,
|
||||
place_names: []string,
|
||||
},
|
||||
}
|
||||
|
||||
entity: Entity;
|
||||
// implicit conversion from variant to base type
|
||||
entity = Entity.Frog{
|
||||
id = 1337,
|
||||
ribbit_volume = 0.5,
|
||||
jump_height = 2.1,
|
||||
/*other data */
|
||||
};
|
||||
|
||||
entity.name = "Frank";
|
||||
entity.position = Vector3{1, 4, 9};
|
||||
|
||||
using Entity;
|
||||
match e in entity {
|
||||
case Frog:
|
||||
fmt.println("Ribbit");
|
||||
case Door:
|
||||
fmt.println("Creak");
|
||||
case Map:
|
||||
fmt.println("Rustle");
|
||||
default:
|
||||
fmt.println("Just a normal entity");
|
||||
}
|
||||
|
||||
if frog, ok := union_cast(Frog)entity; ok {
|
||||
fmt.printf("The frog jumps %f feet high at %v\n", frog.jump_height, frog.position);
|
||||
}
|
||||
|
||||
// Panics if not the correct type
|
||||
frog: Frog;
|
||||
frog = union_cast(Frog)entity;
|
||||
frog, _ = union_cast(Frog)entity; // ignore error and force cast
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
to_odin_string :: proc(c: ^byte) -> string {
|
||||
s: string;
|
||||
s.data = c;
|
||||
while (c + s.count)^ != 0 {
|
||||
s.count += 1;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
//("Hellope!\x00" as string).data
|
||||
|
||||
MAGIC_VALUE :: 0xCA5E713F;
|
||||
|
||||
timing_file_header :: struct #ordered {
|
||||
MagicValue : u32;
|
||||
}
|
||||
|
||||
timing_file_date :: struct #ordered {
|
||||
E : [2]u32;
|
||||
}
|
||||
|
||||
timing_file_entry_flag :: enum {
|
||||
Complete = 0x1,
|
||||
NoErrors = 0x2,
|
||||
}
|
||||
|
||||
timing_file_entry :: struct #ordered {
|
||||
StarDate : timing_file_date;
|
||||
Flags : u32;
|
||||
MillisecondsElapsed : u32;
|
||||
}
|
||||
|
||||
timing_entry_array :: struct #ordered {
|
||||
Entries : []timing_file_entry;
|
||||
}
|
||||
|
||||
GetClock :: proc () -> u32 {
|
||||
return timeGetTime();
|
||||
}
|
||||
|
||||
GetDate :: proc() -> timing_file_date {
|
||||
Result : timing_file_date;
|
||||
FileTime : win32.FILETIME;
|
||||
GetSystemTimeAsFileTime(^FileTime);
|
||||
|
||||
Result.E[0] = FileTime.lo;
|
||||
Result.E[1] = FileTime.hi;
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
main :: proc () {
|
||||
EntryClock := GetClock();
|
||||
GetCommandLineArguments();
|
||||
}
|
||||
|
||||
+86
-86
@@ -1,10 +1,10 @@
|
||||
#import "fmt.odin"
|
||||
#import "fmt.odin";
|
||||
|
||||
#foreign_system_library "Ws2_32" when ODIN_OS == "windows"
|
||||
#foreign_system_library ws2 "Ws2_32.lib" when ODIN_OS == "windows";
|
||||
|
||||
|
||||
SOCKET :: type uint
|
||||
INVALID_SOCKET :: ~(0 as SOCKET)
|
||||
SOCKET :: #type uint;
|
||||
INVALID_SOCKET :: ~(cast(SOCKET)0);
|
||||
|
||||
AF :: enum i32 {
|
||||
UNSPEC = 0, // unspecified
|
||||
@@ -35,111 +35,111 @@ AF :: enum i32 {
|
||||
SIP = 24, // Simple Internet Protocol
|
||||
PIP = 25, // Help Identify PIP packets
|
||||
MAX = 26,
|
||||
}
|
||||
};
|
||||
|
||||
SOCK_STREAM :: 1
|
||||
SOCKET_ERROR :: -1
|
||||
IPPROTO_TCP :: 6
|
||||
AI_PASSIVE :: 0x0020
|
||||
SOMAXCONN :: 128
|
||||
SOCK_STREAM :: 1;
|
||||
SOCKET_ERROR :: -1;
|
||||
IPPROTO_TCP :: 6;
|
||||
AI_PASSIVE :: 0x0020;
|
||||
SOMAXCONN :: 128;
|
||||
|
||||
SD_RECEIVE :: 0
|
||||
SD_SEND :: 1
|
||||
SD_BOTH :: 2
|
||||
SD_RECEIVE :: 0;
|
||||
SD_SEND :: 1;
|
||||
SD_BOTH :: 2;
|
||||
|
||||
WSADESCRIPTION_LEN :: 256
|
||||
WSASYS_STATUS_LEN :: 128
|
||||
WSADESCRIPTION_LEN :: 256;
|
||||
WSASYS_STATUS_LEN :: 128;
|
||||
WSADATA :: struct #ordered {
|
||||
version: i16
|
||||
high_version: i16
|
||||
version: i16,
|
||||
high_version: i16,
|
||||
|
||||
|
||||
// NOTE(bill): This is x64 ordering
|
||||
max_sockets: u16
|
||||
max_udp_dg: u16
|
||||
vendor_info: ^byte
|
||||
description: [WSADESCRIPTION_LEN+1]byte
|
||||
system_status: [WSASYS_STATUS_LEN+1]byte
|
||||
max_sockets: u16,
|
||||
max_udp_dg: u16,
|
||||
vendor_info: ^byte,
|
||||
description: [WSADESCRIPTION_LEN+1]byte,
|
||||
system_status: [WSASYS_STATUS_LEN+1]byte,
|
||||
}
|
||||
|
||||
addrinfo :: struct #ordered {
|
||||
flags: i32
|
||||
family: i32
|
||||
socktype: i32
|
||||
protocol: i32
|
||||
addrlen: uint
|
||||
canonname: ^u8
|
||||
addr: ^sockaddr
|
||||
next: ^addrinfo
|
||||
flags: i32,
|
||||
family: i32,
|
||||
socktype: i32,
|
||||
protocol: i32,
|
||||
addrlen: uint,
|
||||
canonname: ^u8,
|
||||
addr: ^sockaddr,
|
||||
next: ^addrinfo,
|
||||
}
|
||||
|
||||
sockaddr :: struct #ordered {
|
||||
family: u16
|
||||
data: [14]byte
|
||||
family: u16,
|
||||
data: [14]byte,
|
||||
}
|
||||
|
||||
|
||||
WSAStartup :: proc(version_requested: i16, data: ^WSADATA) -> i32 #foreign #dll_import
|
||||
WSACleanup :: proc() -> i32 #foreign #dll_import
|
||||
getaddrinfo :: proc(node_name, service_name: ^u8, hints: ^addrinfo, result: ^^addrinfo) -> i32 #foreign #dll_import
|
||||
freeaddrinfo :: proc(ai: ^addrinfo) #foreign #dll_import
|
||||
socket :: proc(af, type_, protocol: i32) -> SOCKET #foreign #dll_import
|
||||
closesocket :: proc(s: SOCKET) -> i32 #foreign #dll_import
|
||||
bind :: proc(s: SOCKET, name: ^sockaddr, name_len: i32) -> i32 #foreign #dll_import
|
||||
listen :: proc(s: SOCKET, back_log: i32) -> i32 #foreign #dll_import
|
||||
accept :: proc(s: SOCKET, addr: ^sockaddr, addr_len: i32) -> SOCKET #foreign #dll_import
|
||||
recv :: 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 #dll_import
|
||||
shutdown :: proc(s: SOCKET, how: i32) -> i32 #foreign #dll_import
|
||||
WSAGetLastError :: proc() -> i32 #foreign #dll_import
|
||||
WSAStartup :: proc(version_requested: i16, data: ^WSADATA) -> i32 #foreign ws2;
|
||||
WSACleanup :: proc() -> i32 #foreign ws2;
|
||||
getaddrinfo :: proc(node_name, service_name: ^u8, hints: ^addrinfo, result: ^^addrinfo) -> i32 #foreign ws2;
|
||||
freeaddrinfo :: proc(ai: ^addrinfo) #foreign ws2;
|
||||
socket :: proc(af, type_, protocol: i32) -> SOCKET #foreign ws2;
|
||||
closesocket :: proc(s: SOCKET) -> i32 #foreign ws2;
|
||||
bind :: proc(s: SOCKET, name: ^sockaddr, name_len: i32) -> i32 #foreign ws2;
|
||||
listen :: proc(s: SOCKET, back_log: i32) -> i32 #foreign ws2;
|
||||
accept :: proc(s: SOCKET, addr: ^sockaddr, addr_len: i32) -> SOCKET #foreign ws2;
|
||||
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 ws2;
|
||||
shutdown :: proc(s: SOCKET, how: i32) -> i32 #foreign ws2;
|
||||
WSAGetLastError :: proc() -> i32 #foreign ws2;
|
||||
|
||||
to_c_string :: proc(s: string) -> ^byte {
|
||||
c_str := new_slice(byte, s.count+1)
|
||||
assert(c_str.data != nil)
|
||||
copy(c_str, s as []byte)
|
||||
c_str[s.count] = 0
|
||||
return c_str.data
|
||||
c_str := new_slice(byte, s.count+1);
|
||||
assert(c_str.data != nil);
|
||||
copy(c_str, cast([]byte)s);
|
||||
c_str[s.count] = 0;
|
||||
return c_str.data;
|
||||
}
|
||||
|
||||
run :: proc() {
|
||||
wsa: WSADATA
|
||||
res: ^addrinfo = nil
|
||||
hints: addrinfo
|
||||
s, client: SOCKET
|
||||
wsa: WSADATA;
|
||||
res: ^addrinfo = nil;
|
||||
hints: addrinfo;
|
||||
s, client: SOCKET;
|
||||
|
||||
if WSAStartup(2 | (2 << 8), ^wsa) != 0 {
|
||||
fmt.println("WSAStartup failed: ", WSAGetLastError())
|
||||
return
|
||||
fmt.println("WSAStartup failed: ", WSAGetLastError());
|
||||
return;
|
||||
}
|
||||
defer WSACleanup()
|
||||
defer WSACleanup();
|
||||
|
||||
hints.family = AF.INET as i32
|
||||
hints.socktype = SOCK_STREAM
|
||||
hints.protocol = IPPROTO_TCP
|
||||
hints.flags = AI_PASSIVE
|
||||
hints.family = cast(i32)AF.INET;
|
||||
hints.socktype = SOCK_STREAM;
|
||||
hints.protocol = IPPROTO_TCP;
|
||||
hints.flags = AI_PASSIVE;
|
||||
|
||||
if getaddrinfo(nil, to_c_string("8080"), ^hints, ^res) != 0 {
|
||||
fmt.println("getaddrinfo failed: ", WSAGetLastError())
|
||||
return
|
||||
fmt.println("getaddrinfo failed: ", WSAGetLastError());
|
||||
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 {
|
||||
fmt.println("socket failed: ", WSAGetLastError())
|
||||
return
|
||||
fmt.println("socket failed: ", WSAGetLastError());
|
||||
return;
|
||||
}
|
||||
defer closesocket(s)
|
||||
defer closesocket(s);
|
||||
|
||||
bind(s, res.addr, res.addrlen as i32)
|
||||
listen(s, SOMAXCONN)
|
||||
bind(s, res.addr, cast(i32)res.addrlen);
|
||||
listen(s, SOMAXCONN);
|
||||
|
||||
client = accept(s, nil, 0)
|
||||
client = accept(s, nil, 0);
|
||||
if client == INVALID_SOCKET {
|
||||
fmt.println("socket failed: ", WSAGetLastError())
|
||||
return
|
||||
fmt.println("socket failed: ", WSAGetLastError());
|
||||
return;
|
||||
}
|
||||
defer closesocket(client)
|
||||
defer closesocket(client);
|
||||
|
||||
html :=
|
||||
`HTTP/1.1 200 OK
|
||||
@@ -154,27 +154,27 @@ Content-type: text/html
|
||||
<h1 style="color: orange;">Odin Server Demo</h1>
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
`;
|
||||
|
||||
buf: [1024]byte
|
||||
buf: [1024]byte;
|
||||
for {
|
||||
bytes := recv(client, ^buf[0], buf.count as i32, 0)
|
||||
bytes := recv(client, ^buf[0], cast(i32)buf.count, 0);
|
||||
if bytes > 0 {
|
||||
// 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 {
|
||||
fmt.println("send failed: ", WSAGetLastError())
|
||||
return
|
||||
fmt.println("send failed: ", WSAGetLastError());
|
||||
return;
|
||||
}
|
||||
break
|
||||
break;
|
||||
} else if bytes == 0 {
|
||||
fmt.println("Connection closing...")
|
||||
break
|
||||
fmt.println("Connection closing...");
|
||||
break;
|
||||
} else {
|
||||
fmt.println("recv failed: ", WSAGetLastError())
|
||||
return
|
||||
fmt.println("recv failed: ", WSAGetLastError());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
shutdown(client, SD_SEND)
|
||||
shutdown(client, SD_SEND);
|
||||
}
|
||||
|
||||
+103
-100
@@ -1,83 +1,86 @@
|
||||
#import "fmt.odin"
|
||||
#import "os.odin"
|
||||
#import "mem.odin"
|
||||
// #import "http_test.odin" as ht
|
||||
// #import "game.odin" as game
|
||||
// #import "punity.odin" as pn
|
||||
#import "fmt.odin";
|
||||
#import "os.odin";
|
||||
#import "mem.odin";
|
||||
// #import "http_test.odin" as ht;
|
||||
// #import "game.odin" as game;
|
||||
// #import "punity.odin" as pn;
|
||||
|
||||
main :: proc() {
|
||||
// struct_padding()
|
||||
// bounds_checking()
|
||||
// type_introspection()
|
||||
// any_type()
|
||||
// crazy_introspection()
|
||||
// namespaces_and_files()
|
||||
// miscellany()
|
||||
// ht.run()
|
||||
// game.run()
|
||||
// {
|
||||
// init :: proc(c: ^pn.Core) {}
|
||||
// step :: proc(c: ^pn.Core) {}
|
||||
struct_padding();
|
||||
bounds_checking();
|
||||
type_introspection();
|
||||
any_type();
|
||||
crazy_introspection();
|
||||
namespaces_and_files();
|
||||
miscellany();
|
||||
|
||||
// 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() {
|
||||
{
|
||||
A :: struct {
|
||||
a: u8
|
||||
b: u32
|
||||
c: u16
|
||||
a: u8,
|
||||
b: u32,
|
||||
c: u16,
|
||||
}
|
||||
|
||||
B :: struct {
|
||||
a: [7]u8
|
||||
b: [3]u16
|
||||
c: u8
|
||||
d: u16
|
||||
a: [7]u8,
|
||||
b: [3]u16,
|
||||
c: u8,
|
||||
d: u16,
|
||||
}
|
||||
|
||||
fmt.println("size_of(A):", size_of(A))
|
||||
fmt.println("size_of(B):", size_of(B))
|
||||
fmt.println("size_of(A):", size_of(A));
|
||||
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
|
||||
}
|
||||
{
|
||||
A :: struct #ordered {
|
||||
a: u8
|
||||
b: u32
|
||||
c: u16
|
||||
a: u8,
|
||||
b: u32,
|
||||
c: u16,
|
||||
}
|
||||
|
||||
B :: struct #ordered {
|
||||
a: [7]u8
|
||||
b: [3]u16
|
||||
c: u8
|
||||
d: u16
|
||||
a: [7]u8,
|
||||
b: [3]u16,
|
||||
c: u8,
|
||||
d: u16,
|
||||
}
|
||||
|
||||
fmt.println("size_of(A):", size_of(A))
|
||||
fmt.println("size_of(B):", size_of(B))
|
||||
fmt.println("size_of(A):", size_of(A));
|
||||
fmt.println("size_of(B):", size_of(B));
|
||||
|
||||
// C-style structure layout
|
||||
}
|
||||
{
|
||||
A :: struct #packed {
|
||||
a: u8
|
||||
b: u32
|
||||
c: u16
|
||||
a: u8,
|
||||
b: u32,
|
||||
c: u16,
|
||||
}
|
||||
|
||||
B :: struct #packed {
|
||||
a: [7]u8
|
||||
b: [3]u16
|
||||
c: u8
|
||||
d: u16
|
||||
a: [7]u8,
|
||||
b: [3]u16,
|
||||
c: u8,
|
||||
d: u16,
|
||||
}
|
||||
|
||||
fmt.println("size_of(A):", size_of(A))
|
||||
fmt.println("size_of(B):", size_of(B))
|
||||
fmt.println("size_of(A):", size_of(A));
|
||||
fmt.println("size_of(B):", size_of(B));
|
||||
|
||||
// Useful for explicit layout
|
||||
}
|
||||
@@ -119,7 +122,7 @@ struct_padding :: proc() {
|
||||
}
|
||||
|
||||
bounds_checking :: proc() {
|
||||
x: [4]int
|
||||
x: [4]int;
|
||||
// x[-1] = 0; // Compile Time
|
||||
// x[4] = 0; // Compile Time
|
||||
|
||||
@@ -132,9 +135,9 @@ bounds_checking :: proc() {
|
||||
// Works for arrays, strings, slices, and related procedures & operations
|
||||
|
||||
{
|
||||
base: [10]int
|
||||
s := base[2:6]
|
||||
a, b := -1, 6
|
||||
base: [10]int;
|
||||
s := base[2:6];
|
||||
a, b := -1, 6;
|
||||
|
||||
#no_bounds_check {
|
||||
s[a] = 0;
|
||||
@@ -154,69 +157,69 @@ bounds_checking :: proc() {
|
||||
|
||||
type_introspection :: proc() {
|
||||
{
|
||||
info: ^Type_Info
|
||||
x: int
|
||||
info: ^Type_Info;
|
||||
x: int;
|
||||
|
||||
info = type_info(int) // by type
|
||||
info = type_info_of_val(x) // by value
|
||||
info = type_info(int); // by type
|
||||
info = type_info_of_val(x); // by value
|
||||
// See: runtime.odin
|
||||
|
||||
match type i : info {
|
||||
match type i in info {
|
||||
case Type_Info.Integer:
|
||||
fmt.println("integer!")
|
||||
fmt.println("integer!");
|
||||
case Type_Info.Float:
|
||||
fmt.println("float!")
|
||||
fmt.println("float!");
|
||||
default:
|
||||
fmt.println("potato!")
|
||||
fmt.println("potato!");
|
||||
}
|
||||
|
||||
// Unsafe cast
|
||||
integer_info := info as ^Type_Info.Integer
|
||||
integer_info := cast(^Type_Info.Integer)info;
|
||||
}
|
||||
|
||||
{
|
||||
Vector2 :: struct { x, y: f32 }
|
||||
Vector3 :: struct { x, y, z: f32 }
|
||||
|
||||
v1: Vector2
|
||||
v2: Vector3
|
||||
v3: Vector3
|
||||
v1: Vector2;
|
||||
v2: Vector3;
|
||||
v3: Vector3;
|
||||
|
||||
t1 := type_info_of_val(v1)
|
||||
t2 := type_info_of_val(v2)
|
||||
t3 := type_info_of_val(v3)
|
||||
t1 := type_info_of_val(v1);
|
||||
t2 := type_info_of_val(v2);
|
||||
t3 := type_info_of_val(v3);
|
||||
|
||||
fmt.println()
|
||||
fmt.print("Type of v1 is:\n\t", t1)
|
||||
fmt.println();
|
||||
fmt.print("Type of v1 is:\n\t", t1);
|
||||
|
||||
fmt.println()
|
||||
fmt.print("Type of v2 is:\n\t", t2)
|
||||
fmt.println();
|
||||
fmt.print("Type of v2 is:\n\t", t2);
|
||||
|
||||
fmt.println("\n")
|
||||
fmt.println("t1 == t2:", t1 == t2)
|
||||
fmt.println("t2 == t3:", t2 == t3)
|
||||
fmt.println("\n");
|
||||
fmt.println("t1 == t2:", t1 == t2);
|
||||
fmt.println("t2 == t3:", t2 == t3);
|
||||
}
|
||||
}
|
||||
|
||||
any_type :: proc() {
|
||||
a: any
|
||||
a: any;
|
||||
|
||||
x: int = 123
|
||||
y: f64 = 6.28
|
||||
z: string = "Yo-Yo Ma"
|
||||
x: int = 123;
|
||||
y: f64 = 6.28;
|
||||
z: string = "Yo-Yo Ma";
|
||||
// All types can be implicit cast to `any`
|
||||
a = x
|
||||
a = y
|
||||
a = z
|
||||
a = a // This the "identity" type, it doesn't get converted
|
||||
a = x;
|
||||
a = y;
|
||||
a = z;
|
||||
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
|
||||
// data - rawptr to the data
|
||||
// type_info - pointer to the type info
|
||||
|
||||
fmt.println(x, y, z)
|
||||
fmt.println(x, y, z);
|
||||
// See: fmt.odin
|
||||
// For variadic any procedures in action
|
||||
}
|
||||
@@ -232,15 +235,15 @@ crazy_introspection :: proc() {
|
||||
TOMATO,
|
||||
}
|
||||
|
||||
s: string
|
||||
s = enum_to_string(Fruit.PEACH)
|
||||
fmt.println(s)
|
||||
s: string;
|
||||
// s = enum_to_string(Fruit.PEACH);
|
||||
fmt.println(s);
|
||||
|
||||
f := Fruit.GRAPE
|
||||
s = enum_to_string(f)
|
||||
fmt.println(s)
|
||||
f := Fruit.GRAPE;
|
||||
// s = enum_to_string(f);
|
||||
fmt.println(s);
|
||||
|
||||
fmt.println(f)
|
||||
fmt.println(f);
|
||||
// See: runtime.odin
|
||||
}
|
||||
|
||||
@@ -259,15 +262,15 @@ crazy_introspection :: proc() {
|
||||
TOMATO,
|
||||
}
|
||||
|
||||
fruit_ti := type_info(Fruit)
|
||||
name := (fruit_ti as ^Type_Info.Named).name // Unsafe casts
|
||||
info := type_info_base(fruit_ti) as ^Type_Info.Enum // Unsafe casts
|
||||
fruit_ti := type_info(Fruit);
|
||||
name := (cast(^Type_Info.Named)fruit_ti).name; // Unsafe casts
|
||||
info := cast(^Type_Info.Enum)type_info_base(fruit_ti); // Unsafe casts
|
||||
|
||||
fmt.printf("% :: enum % {\n", name, info.base);
|
||||
for i := 0; i < info.values.count; i++ {
|
||||
fmt.printf("\t%\t= %,\n", info.names[i], info.values[i])
|
||||
for i := 0; i < info.values.count; i += 1 {
|
||||
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!
|
||||
}
|
||||
@@ -275,10 +278,10 @@ crazy_introspection :: proc() {
|
||||
{
|
||||
Vector3 :: struct {x, y, z: f32}
|
||||
|
||||
a := Vector3{x = 1, y = 4, z = 9}
|
||||
fmt.println(a)
|
||||
b := Vector3{x = 9, y = 3, z = 1}
|
||||
fmt.println(b)
|
||||
a := Vector3{x = 1, y = 4, z = 9};
|
||||
fmt.println(a);
|
||||
b := Vector3{x = 9, y = 3, z = 1};
|
||||
fmt.println(b);
|
||||
|
||||
// NOTE(bill): See fmt.odin
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
+167
-160
@@ -1,34 +1,35 @@
|
||||
#import "win32.odin"
|
||||
#import "fmt.odin"
|
||||
#import "os.odin"
|
||||
#import win32 "sys/windows.odin";
|
||||
#import "fmt.odin";
|
||||
#import "os.odin";
|
||||
#import "mem.odin";
|
||||
|
||||
CANVAS_WIDTH :: 128
|
||||
CANVAS_HEIGHT :: 128
|
||||
CANVAS_SCALE :: 3
|
||||
FRAME_TIME :: 1.0/30.0
|
||||
WINDOW_TITLE :: "Punity\x00"
|
||||
CANVAS_WIDTH :: 128;
|
||||
CANVAS_HEIGHT :: 128;
|
||||
CANVAS_SCALE :: 3;
|
||||
FRAME_TIME :: 1.0/30.0;
|
||||
WINDOW_TITLE :: "Punity\x00";
|
||||
|
||||
_ := compile_assert(CANVAS_WIDTH % 16 == 0)
|
||||
_ := compile_assert(CANVAS_WIDTH % 16 == 0);
|
||||
|
||||
WINDOW_WIDTH :: CANVAS_WIDTH * CANVAS_SCALE
|
||||
WINDOW_HEIGHT :: CANVAS_HEIGHT * CANVAS_SCALE
|
||||
WINDOW_WIDTH :: CANVAS_WIDTH * CANVAS_SCALE;
|
||||
WINDOW_HEIGHT :: CANVAS_HEIGHT * CANVAS_SCALE;
|
||||
|
||||
|
||||
STACK_CAPACITY :: 1<<20
|
||||
STORAGE_CAPACITY :: 1<<20
|
||||
STACK_CAPACITY :: 1<<20;
|
||||
STORAGE_CAPACITY :: 1<<20;
|
||||
|
||||
DRAW_LIST_RESERVE :: 128
|
||||
DRAW_LIST_RESERVE :: 128;
|
||||
|
||||
MAX_KEYS :: 256
|
||||
MAX_KEYS :: 256;
|
||||
|
||||
Core :: struct {
|
||||
stack: ^Bank
|
||||
storage: ^Bank
|
||||
stack: ^Bank,
|
||||
storage: ^Bank,
|
||||
|
||||
running: bool
|
||||
key_modifiers: u32
|
||||
key_states: [MAX_KEYS]byte
|
||||
key_deltas: [MAX_KEYS]byte
|
||||
running: bool,
|
||||
key_modifiers: u32,
|
||||
key_states: [MAX_KEYS]byte,
|
||||
key_deltas: [MAX_KEYS]byte,
|
||||
|
||||
perf_frame,
|
||||
perf_frame_inner,
|
||||
@@ -36,70 +37,66 @@ Core :: struct {
|
||||
perf_audio,
|
||||
perf_blit,
|
||||
perf_blit_cvt,
|
||||
perf_blit_gdi: Perf_Span
|
||||
perf_blit_gdi: Perf_Span,
|
||||
|
||||
frame: i64
|
||||
frame: i64,
|
||||
|
||||
canvas: Canvas
|
||||
draw_list: ^Draw_List
|
||||
canvas: Canvas,
|
||||
draw_list: ^Draw_List,
|
||||
}
|
||||
|
||||
Perf_Span :: struct {
|
||||
stamp: f64
|
||||
delta: f32
|
||||
stamp: f64,
|
||||
delta: f32,
|
||||
}
|
||||
|
||||
Bank :: struct {
|
||||
memory: []byte
|
||||
cursor: int
|
||||
memory: []byte,
|
||||
cursor: int,
|
||||
}
|
||||
|
||||
Bank_State :: struct {
|
||||
state: Bank
|
||||
bank: ^Bank
|
||||
state: Bank,
|
||||
bank: ^Bank,
|
||||
}
|
||||
|
||||
|
||||
Color :: raw_union {
|
||||
using channels: struct{ a, b, g, r: byte; }
|
||||
rgba: u32
|
||||
using channels: struct{a, b, g, r: byte},
|
||||
rgba: u32,
|
||||
}
|
||||
|
||||
Palette :: struct {
|
||||
colors: [256]Color
|
||||
colors_count: byte
|
||||
colors: [256]Color,
|
||||
colors_count: byte,
|
||||
}
|
||||
|
||||
|
||||
Rect :: raw_union {
|
||||
using minmax: struct {
|
||||
min_x, min_y, max_x, max_y: int
|
||||
}
|
||||
using pos: struct {
|
||||
left, top, right, bottom: int
|
||||
}
|
||||
e: [4]int
|
||||
using minmax: struct {min_x, min_y, max_x, max_y: int},
|
||||
using pos: struct {left, top, right, bottom: int},
|
||||
e: [4]int,
|
||||
}
|
||||
|
||||
Bitmap :: struct {
|
||||
pixels: []byte
|
||||
width: int
|
||||
height: int
|
||||
pixels: []byte,
|
||||
width: int,
|
||||
height: int,
|
||||
}
|
||||
|
||||
Font :: struct {
|
||||
using bitmap: Bitmap
|
||||
char_width: int
|
||||
char_height: int
|
||||
using bitmap: Bitmap,
|
||||
char_width: int,
|
||||
char_height: int,
|
||||
}
|
||||
|
||||
Canvas :: struct {
|
||||
using bitmap: ^Bitmap
|
||||
palette: Palette
|
||||
translate_x: int
|
||||
translate_y: int
|
||||
clip: Rect
|
||||
font: ^Font
|
||||
using bitmap: ^Bitmap,
|
||||
palette: Palette,
|
||||
translate_x: int,
|
||||
translate_y: int,
|
||||
clip: Rect,
|
||||
font: ^Font,
|
||||
}
|
||||
|
||||
DrawFlag :: enum {
|
||||
@@ -109,12 +106,9 @@ DrawFlag :: enum {
|
||||
MASK = 1<<2,
|
||||
}
|
||||
|
||||
|
||||
Draw_Item :: struct {}
|
||||
Draw_List :: struct {
|
||||
Item :: struct {
|
||||
|
||||
}
|
||||
items: []Item
|
||||
items: []Draw_Item,
|
||||
}
|
||||
|
||||
Key :: enum {
|
||||
@@ -268,112 +262,112 @@ Key :: enum {
|
||||
BACKSLASH = 92, /* \ */
|
||||
RIGHT_BRACKET = 93, /* ] */
|
||||
GRAVE_ACCENT = 96, /* ` */
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
key_down :: proc(k: Key) -> bool {
|
||||
return _core.key_states[k] != 0
|
||||
return _core.key_states[k] != 0;
|
||||
}
|
||||
|
||||
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 {
|
||||
assert(win32_perf_count_freq != 0)
|
||||
assert(win32_perf_count_freq != 0);
|
||||
|
||||
counter: i64
|
||||
win32.QueryPerformanceCounter(^counter)
|
||||
result := counter as f64 / win32_perf_count_freq as f64
|
||||
return result
|
||||
counter: i64;
|
||||
win32.QueryPerformanceCounter(^counter);
|
||||
result := cast(f64)counter / cast(f64)win32_perf_count_freq;
|
||||
return result;
|
||||
}
|
||||
|
||||
_core: Core
|
||||
_core: Core;
|
||||
|
||||
run :: proc(user_init, user_step: proc(c: ^Core)) {
|
||||
using win32
|
||||
using win32;
|
||||
|
||||
_core.running = true
|
||||
_core.running = true;
|
||||
|
||||
win32_proc :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #no_inline #stdcall {
|
||||
win32_proc :: proc(hwnd: win32.HWND, msg: u32, wparam: win32.WPARAM, lparam: win32.LPARAM) -> win32.LRESULT #no_inline #cc_c {
|
||||
win32_app_key_mods :: proc() -> u32 {
|
||||
mods: u32 = 0
|
||||
mods: u32 = 0;
|
||||
|
||||
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) {
|
||||
mods |= Key.MOD_CONTROL as u32
|
||||
mods |= cast(u32)Key.MOD_CONTROL;
|
||||
}
|
||||
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) {
|
||||
mods |= Key.MOD_SUPER as u32
|
||||
mods |= cast(u32)Key.MOD_SUPER;
|
||||
}
|
||||
|
||||
return mods
|
||||
return mods;
|
||||
}
|
||||
|
||||
match msg {
|
||||
case WM_KEYDOWN:
|
||||
_core.key_modifiers = win32_app_key_mods()
|
||||
_core.key_modifiers = win32_app_key_mods();
|
||||
if wparam < MAX_KEYS {
|
||||
_core.key_states[wparam] = 1
|
||||
_core.key_deltas[wparam] = 1
|
||||
_core.key_states[wparam] = 1;
|
||||
_core.key_deltas[wparam] = 1;
|
||||
}
|
||||
return 0
|
||||
return 0;
|
||||
|
||||
case WM_KEYUP:
|
||||
_core.key_modifiers = win32_app_key_mods()
|
||||
_core.key_modifiers = win32_app_key_mods();
|
||||
if wparam < MAX_KEYS {
|
||||
_core.key_states[wparam] = 0
|
||||
_core.key_deltas[wparam] = 1
|
||||
_core.key_states[wparam] = 0;
|
||||
_core.key_deltas[wparam] = 1;
|
||||
}
|
||||
return 0
|
||||
return 0;
|
||||
|
||||
case WM_CLOSE:
|
||||
PostQuitMessage(0)
|
||||
_core.running = false
|
||||
return 0
|
||||
PostQuitMessage(0);
|
||||
_core.running = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return DefWindowProcA(hwnd, msg, wparam, lparam)
|
||||
return DefWindowProcA(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
|
||||
window_class := WNDCLASSEXA{
|
||||
class_name = ("Punity\x00" as string).data, // C-style string
|
||||
size = size_of(WNDCLASSEXA) as u32,
|
||||
class_name = (cast(string)"Punity\x00").data, // C-style string
|
||||
size = size_of(WNDCLASSEXA),
|
||||
style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
|
||||
instance = GetModuleHandleA(nil) as HINSTANCE,
|
||||
instance = cast(HINSTANCE)GetModuleHandleA(nil),
|
||||
wnd_proc = win32_proc,
|
||||
// wnd_proc = DefWindowProcA,
|
||||
background = GetStockObject(BLACK_BRUSH) as HBRUSH,
|
||||
}
|
||||
background = cast(HBRUSH)GetStockObject(BLACK_BRUSH),
|
||||
};
|
||||
|
||||
if RegisterClassExA(^window_class) == 0 {
|
||||
fmt.fprintln(os.stderr, "RegisterClassExA failed")
|
||||
return
|
||||
fmt.fprintln(os.stderr, "RegisterClassExA failed");
|
||||
return;
|
||||
}
|
||||
|
||||
screen_width := GetSystemMetrics(SM_CXSCREEN)
|
||||
screen_height := GetSystemMetrics(SM_CYSCREEN)
|
||||
screen_width := GetSystemMetrics(SM_CXSCREEN);
|
||||
screen_height := GetSystemMetrics(SM_CYSCREEN);
|
||||
|
||||
rc: RECT
|
||||
rc.left = (screen_width - WINDOW_WIDTH) / 2
|
||||
rc.top = (screen_height - WINDOW_HEIGHT) / 2
|
||||
rc.right = rc.left + WINDOW_WIDTH
|
||||
rc.bottom = rc.top + WINDOW_HEIGHT
|
||||
rc: RECT;
|
||||
rc.left = (screen_width - WINDOW_WIDTH) / 2;
|
||||
rc.top = (screen_height - WINDOW_HEIGHT) / 2;
|
||||
rc.right = rc.left + WINDOW_WIDTH;
|
||||
rc.bottom = rc.top + WINDOW_HEIGHT;
|
||||
|
||||
style: u32 = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX
|
||||
assert(AdjustWindowRect(^rc, style, 0) != 0)
|
||||
style: u32 = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
|
||||
assert(AdjustWindowRect(^rc, style, 0) != 0);
|
||||
|
||||
wt := WINDOW_TITLE
|
||||
wt := WINDOW_TITLE;
|
||||
|
||||
win32_window := CreateWindowExA(0,
|
||||
window_class.class_name,
|
||||
@@ -382,101 +376,114 @@ run :: proc(user_init, user_step: proc(c: ^Core)) {
|
||||
rc.left, rc.top,
|
||||
rc.right-rc.left, rc.bottom-rc.top,
|
||||
nil, nil, window_class.instance,
|
||||
nil)
|
||||
nil);
|
||||
|
||||
if win32_window == nil {
|
||||
fmt.fprintln(os.stderr, "CreateWindowExA failed")
|
||||
return
|
||||
fmt.fprintln(os.stderr, "CreateWindowExA failed");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
window_bmi: BITMAPINFO
|
||||
window_bmi.size = size_of(BITMAPINFO.HEADER) as u32
|
||||
window_bmi.width = CANVAS_WIDTH
|
||||
window_bmi.height = CANVAS_HEIGHT
|
||||
window_bmi.planes = 1
|
||||
window_bmi.bit_count = 32
|
||||
window_bmi.compression = BI_RGB
|
||||
window_bmi: BITMAPINFO;
|
||||
window_bmi.size = size_of(BITMAPINFOHEADER);
|
||||
window_bmi.width = CANVAS_WIDTH;
|
||||
window_bmi.height = CANVAS_HEIGHT;
|
||||
window_bmi.planes = 1;
|
||||
window_bmi.bit_count = 32;
|
||||
window_bmi.compression = BI_RGB;
|
||||
|
||||
|
||||
user_init(^_core)
|
||||
user_init(^_core);
|
||||
|
||||
ShowWindow(win32_window, SW_SHOW);
|
||||
|
||||
window_buffer := new_slice(u32, CANVAS_WIDTH * CANVAS_HEIGHT);
|
||||
defer free(window_buffer);
|
||||
|
||||
|
||||
ShowWindow(win32_window, SW_SHOW)
|
||||
|
||||
window_buffer := new_slice(u32, CANVAS_WIDTH * CANVAS_HEIGHT)
|
||||
assert(window_buffer.data != nil)
|
||||
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
|
||||
prev_time = time_now()
|
||||
curr_time = time_now()
|
||||
total_time : f64 = 0
|
||||
offset_x := 0
|
||||
offset_y := 0
|
||||
dt: f64;
|
||||
prev_time := time_now();
|
||||
curr_time := time_now();
|
||||
total_time : f64 = 0;
|
||||
offset_x := 0;
|
||||
offset_y := 0;
|
||||
|
||||
message: MSG
|
||||
message: MSG;
|
||||
for _core.running {
|
||||
curr_time = time_now()
|
||||
dt = curr_time - prev_time
|
||||
prev_time = curr_time
|
||||
total_time += dt
|
||||
curr_time = time_now();
|
||||
dt = curr_time - prev_time;
|
||||
prev_time = curr_time;
|
||||
total_time += dt;
|
||||
|
||||
offset_x += 1
|
||||
offset_y += 2
|
||||
offset_x += 1;
|
||||
offset_y += 2;
|
||||
|
||||
{
|
||||
data: [128]byte
|
||||
buf := data[:0]
|
||||
fmt.bprintf(^buf, "Punity: % ms\x00", dt*1000)
|
||||
win32.SetWindowTextA(win32_window, buf.data)
|
||||
data: [128]byte;
|
||||
buf: fmt.Buffer;
|
||||
buf.data = data[:];
|
||||
fmt.bprintf(^buf, "Punity: %.4f ms\x00", dt*1000);
|
||||
win32.SetWindowTextA(win32_window, ^buf[0]);
|
||||
}
|
||||
|
||||
|
||||
for y := 0; y < CANVAS_HEIGHT; y++ {
|
||||
for x := 0; x < CANVAS_WIDTH; x++ {
|
||||
g := (x % 32) * 8
|
||||
b := (y % 32) * 8
|
||||
window_buffer[x + y*CANVAS_WIDTH] = (g << 8 | b) as u32
|
||||
for y := 0; y < CANVAS_HEIGHT; y += 1 {
|
||||
for x := 0; x < CANVAS_WIDTH; x += 1 {
|
||||
g := (x % 32) * 8;
|
||||
b := (y % 32) * 8;
|
||||
window_buffer[x + y*CANVAS_WIDTH] = cast(u32)(g << 8 | b);
|
||||
}
|
||||
}
|
||||
|
||||
_core.key_deltas = nil
|
||||
mem.zero(^_core.key_deltas[0], size_of_val(_core.key_deltas));
|
||||
|
||||
for PeekMessageA(^message, nil, 0, 0, PM_REMOVE) != 0 {
|
||||
if message.message == WM_QUIT {
|
||||
_core.running = false
|
||||
_core.running = false;
|
||||
}
|
||||
TranslateMessage(^message)
|
||||
DispatchMessageA(^message)
|
||||
TranslateMessage(^message);
|
||||
DispatchMessageA(^message);
|
||||
}
|
||||
|
||||
user_step(^_core)
|
||||
user_step(^_core);
|
||||
|
||||
dc := GetDC(win32_window)
|
||||
dc := GetDC(win32_window);
|
||||
StretchDIBits(dc,
|
||||
0, 0, CANVAS_WIDTH * CANVAS_SCALE, CANVAS_HEIGHT * CANVAS_SCALE,
|
||||
0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
|
||||
window_buffer.data,
|
||||
^window_bmi,
|
||||
DIB_RGB_COLORS,
|
||||
SRCCOPY)
|
||||
ReleaseDC(win32_window, dc)
|
||||
SRCCOPY);
|
||||
ReleaseDC(win32_window, dc);
|
||||
|
||||
|
||||
{
|
||||
delta := time_now() - prev_time
|
||||
ms := ((FRAME_TIME - delta) * 1000) as i32
|
||||
delta := time_now() - prev_time;
|
||||
ms := cast(i32)((FRAME_TIME - delta) * 1000);
|
||||
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);
|
||||
}
|
||||
|
||||
+3
-3
@@ -5,10 +5,10 @@ thing :: proc() {
|
||||
}*/
|
||||
|
||||
|
||||
#import "fmt.odin" as format
|
||||
#import "fmt.odin";
|
||||
|
||||
thing :: proc() {
|
||||
format.println("Hello2!")
|
||||
main :: proc() {
|
||||
fmt.println("hello, world!");
|
||||
}
|
||||
|
||||
|
||||
|
||||
+507
-136
@@ -4,6 +4,7 @@
|
||||
#import "fmt.odin";
|
||||
#import "mem.odin";
|
||||
#import "utf8.odin";
|
||||
#import "hash.odin";
|
||||
|
||||
// IMPORTANT NOTE(bill): `type_info` & `type_info_val` cannot be used within a
|
||||
// #shared_global_scope due to the internals of the compiler.
|
||||
@@ -13,77 +14,91 @@
|
||||
|
||||
// IMPORTANT NOTE(bill): Do not change the order of any of this data
|
||||
// The compiler relies upon this _exact_ order
|
||||
Type_Info_Member :: struct #ordered {
|
||||
name: string; // can be empty if tuple
|
||||
type_info: ^Type_Info;
|
||||
offset: int; // offsets are not used in tuples
|
||||
Type_Info_Enum_Value :: raw_union {
|
||||
f: f64,
|
||||
i: i64,
|
||||
}
|
||||
// NOTE(bill): This must match the compiler's
|
||||
Calling_Convention :: enum {
|
||||
ODIN = 0,
|
||||
C = 1,
|
||||
STD = 2,
|
||||
FAST = 3,
|
||||
}
|
||||
|
||||
Type_Info_Record :: struct #ordered {
|
||||
fields: []Type_Info_Member;
|
||||
size: int; // in bytes
|
||||
align: int; // in bytes
|
||||
packed: bool;
|
||||
ordered: bool;
|
||||
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: 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: Type_Info_Record;
|
||||
Struct: Type_Info_Record;
|
||||
Union: Type_Info_Record;
|
||||
Raw_Union: Type_Info_Record;
|
||||
Enum: struct #ordered {
|
||||
base: ^Type_Info;
|
||||
names: []string;
|
||||
// TODO(bill): store values some how. Maybe using a raw_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 {
|
||||
if info == nil {
|
||||
return nil;
|
||||
}
|
||||
base := info;
|
||||
match type i : base {
|
||||
match i in base {
|
||||
case Type_Info.Named:
|
||||
base = i.base;
|
||||
}
|
||||
@@ -91,50 +106,53 @@ type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
|
||||
}
|
||||
|
||||
|
||||
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"
|
||||
|
||||
__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"
|
||||
|
||||
assume :: proc(cond: bool) #foreign __llvm_core "llvm.assume";
|
||||
|
||||
__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";
|
||||
|
||||
|
||||
|
||||
|
||||
// IMPORTANT NOTE(bill): Must be in this order (as the compiler relies upon it)
|
||||
Allocator_Mode :: enum u8 {
|
||||
ALLOC = iota,
|
||||
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_Proc :: #type proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, flags: u64) -> rawptr;
|
||||
Allocator :: struct #ordered {
|
||||
procedure: Allocator_Proc;
|
||||
data: rawptr;
|
||||
procedure: Allocator_Proc,
|
||||
data: rawptr,
|
||||
}
|
||||
|
||||
Context :: struct #ordered {
|
||||
thread_id: int;
|
||||
thread_id: int,
|
||||
|
||||
allocator: Allocator;
|
||||
allocator: Allocator,
|
||||
|
||||
user_data: rawptr;
|
||||
user_index: int;
|
||||
user_data: rawptr,
|
||||
user_index: int,
|
||||
}
|
||||
|
||||
#thread_local __context: Context;
|
||||
@@ -162,13 +180,21 @@ alloc_align :: proc(size, alignment: int) -> rawptr #inline {
|
||||
return a.procedure(a.data, Allocator_Mode.ALLOC, size, alignment, nil, 0, 0);
|
||||
}
|
||||
|
||||
free :: proc(ptr: rawptr) #inline {
|
||||
__check_context();
|
||||
a := context.allocator;
|
||||
if ptr != nil {
|
||||
a.procedure(a.data, Allocator_Mode.FREE, 0, 0, ptr, 0, 0);
|
||||
free_ptr_with_allocator :: proc(a: Allocator, ptr: rawptr) #inline {
|
||||
if ptr == nil {
|
||||
return;
|
||||
}
|
||||
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 {
|
||||
__check_context();
|
||||
a := context.allocator;
|
||||
@@ -215,46 +241,21 @@ default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
|
||||
using Allocator_Mode;
|
||||
|
||||
when false {
|
||||
match mode {
|
||||
case ALLOC:
|
||||
total_size := size + alignment + size_of(mem.AllocationHeader);
|
||||
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);
|
||||
match mode {
|
||||
case ALLOC:
|
||||
return os.heap_alloc(size);
|
||||
|
||||
case FREE:
|
||||
os.heap_free(mem.allocation_header(old_memory));
|
||||
return nil;
|
||||
case FREE:
|
||||
os.heap_free(old_memory);
|
||||
return nil;
|
||||
|
||||
case FREE_ALL:
|
||||
// NOTE(bill): Does nothing
|
||||
case FREE_ALL:
|
||||
// NOTE(bill): Does nothing
|
||||
|
||||
case RESIZE:
|
||||
total_size := size + alignment + size_of(mem.AllocationHeader);
|
||||
ptr := os.heap_resize(mem.allocation_header(old_memory), 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);
|
||||
}
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
case RESIZE:
|
||||
ptr := os.heap_resize(old_memory, size);
|
||||
assert(ptr != nil);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
return nil;
|
||||
@@ -284,11 +285,11 @@ __string_eq :: proc(a, b: string) -> bool {
|
||||
if a.data == b.data {
|
||||
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 {
|
||||
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); }
|
||||
@@ -299,38 +300,408 @@ __string_ge :: proc(a, b: string) -> bool #inline { return __string_cmp(a, b) >=
|
||||
|
||||
|
||||
__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);
|
||||
__debug_trap();
|
||||
}
|
||||
__panic :: proc(file: string, line, column: int, msg: string) #inline {
|
||||
fmt.fprintf(os.stderr, "%s(%d:%d) Panic: %s\n",
|
||||
file, line, column, msg);
|
||||
__debug_trap();
|
||||
}
|
||||
|
||||
__bounds_check_error :: proc(file: string, line, column: int, index, count: int) {
|
||||
if 0 <= index && index < count {
|
||||
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);
|
||||
__debug_trap();
|
||||
}
|
||||
|
||||
__slice_expr_error :: proc(file: string, line, column: int, low, high: int) {
|
||||
if 0 <= low && low <= high {
|
||||
__slice_expr_error :: proc(file: string, line, column: int, low, high, max: int) {
|
||||
if 0 <= low && low <= high && high <= max {
|
||||
return;
|
||||
}
|
||||
fmt.fprintf(os.stderr, "%(%:%) Invalid slice indices: [%:%]\n",
|
||||
file, line, column, low, high);
|
||||
fmt.fprintf(os.stderr, "%s(%d:%d) Invalid slice indices: [%d..%d..%d]\n",
|
||||
file, line, column, low, high, max);
|
||||
__debug_trap();
|
||||
}
|
||||
__substring_expr_error :: proc(file: string, line, column: int, low, high: int) {
|
||||
if 0 <= low && low <= high {
|
||||
return;
|
||||
}
|
||||
fmt.fprintf(os.stderr, "%(%:%) Invalid substring indices: [%:%]\n",
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
__string_decode_rune :: proc(s: string) -> (rune, int) #inline {
|
||||
return utf8.decode_rune(s);
|
||||
}
|
||||
|
||||
|
||||
__mem_set :: proc(data: rawptr, value: i32, len: int) -> rawptr {
|
||||
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, cast(byte)value, len, 1, false);
|
||||
return data;
|
||||
}
|
||||
__mem_zero :: proc(data: rawptr, len: int) -> rawptr {
|
||||
return __mem_set(data, 0, len);
|
||||
}
|
||||
__mem_copy :: proc(dst, src: rawptr, len: int) -> rawptr {
|
||||
// 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_core "llvm.memmove.p0i8.p0i8.i64";
|
||||
llvm_memmove_64bit(dst, src, len, 1, false);
|
||||
return dst;
|
||||
}
|
||||
__mem_copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr {
|
||||
// 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_core "llvm.memcpy.p0i8.p0i8.i64";
|
||||
llvm_memcpy_64bit(dst, src, len, 1, false);
|
||||
return dst;
|
||||
}
|
||||
|
||||
__mem_compare :: proc(a, b: ^byte, n: int) -> int {
|
||||
for i in 0..n {
|
||||
match {
|
||||
case (a+i)^ < (b+i)^:
|
||||
return -1;
|
||||
case (a+i)^ > (b+i)^:
|
||||
return +1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Raw_Any :: struct #ordered {
|
||||
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);
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
+33
-34
@@ -5,97 +5,96 @@
|
||||
_ := compile_assert(ODIN_ARCH == "amd64"); // TODO(bill): x86 version
|
||||
|
||||
|
||||
yield_thread :: proc() { win32._mm_pause(); }
|
||||
yield_thread :: proc() { win32.mm_pause(); }
|
||||
mfence :: proc() { win32.ReadWriteBarrier(); }
|
||||
sfence :: proc() { win32.WriteBarrier(); }
|
||||
lfence :: proc() { win32.ReadBarrier(); }
|
||||
|
||||
|
||||
load32 :: proc(a: ^i32) -> i32 {
|
||||
load :: proc(a: ^i32) -> i32 {
|
||||
return a^;
|
||||
}
|
||||
store32 :: proc(a: ^i32, value: i32) {
|
||||
store :: proc(a: ^i32, value: i32) {
|
||||
a^ = value;
|
||||
}
|
||||
compare_exchange32 :: proc(a: ^i32, expected, desired: i32) -> i32 {
|
||||
compare_exchange :: proc(a: ^i32, expected, desired: i32) -> i32 {
|
||||
return win32.InterlockedCompareExchange(a, desired, expected);
|
||||
}
|
||||
exchanged32 :: proc(a: ^i32, desired: i32) -> i32 {
|
||||
exchanged :: proc(a: ^i32, desired: i32) -> i32 {
|
||||
return win32.InterlockedExchange(a, desired);
|
||||
}
|
||||
fetch_add32 :: proc(a: ^i32, operand: i32) -> i32 {
|
||||
fetch_add :: proc(a: ^i32, operand: i32) -> i32 {
|
||||
return win32.InterlockedExchangeAdd(a, operand);
|
||||
|
||||
}
|
||||
fetch_and32 :: proc(a: ^i32, operand: i32) -> i32 {
|
||||
fetch_and :: proc(a: ^i32, operand: i32) -> i32 {
|
||||
return win32.InterlockedAnd(a, operand);
|
||||
|
||||
}
|
||||
fetch_or32 :: proc(a: ^i32, operand: i32) -> i32 {
|
||||
fetch_or :: proc(a: ^i32, operand: i32) -> i32 {
|
||||
return win32.InterlockedOr(a, operand);
|
||||
}
|
||||
spin_lock32 :: proc(a: ^i32, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
|
||||
old_value := compare_exchange32(a, 1, 0);
|
||||
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;
|
||||
while old_value != 0 && (time_out < 0 || counter < time_out) {
|
||||
counter += 1;
|
||||
for old_value != 0 && (time_out < 0 || counter < time_out) {
|
||||
counter++;
|
||||
yield_thread();
|
||||
old_value = compare_exchange32(a, 1, 0);
|
||||
old_value = compare_exchange(a, 1, 0);
|
||||
mfence();
|
||||
}
|
||||
return old_value == 0;
|
||||
}
|
||||
spin_unlock32 :: proc(a: ^i32) {
|
||||
store32(a, 0);
|
||||
spin_unlock :: proc(a: ^i32) {
|
||||
store(a, 0);
|
||||
mfence();
|
||||
}
|
||||
try_acquire_lock32 :: proc(a: ^i32) -> bool {
|
||||
try_acquire_lock :: proc(a: ^i32) -> bool {
|
||||
yield_thread();
|
||||
old_value := compare_exchange32(a, 1, 0);
|
||||
old_value := compare_exchange(a, 1, 0);
|
||||
mfence();
|
||||
return old_value == 0;
|
||||
}
|
||||
|
||||
|
||||
load64 :: proc(a: ^i64) -> i64 {
|
||||
load :: proc(a: ^i64) -> i64 {
|
||||
return a^;
|
||||
}
|
||||
store64 :: proc(a: ^i64, value: i64) {
|
||||
store :: proc(a: ^i64, value: i64) {
|
||||
a^ = value;
|
||||
}
|
||||
compare_exchange64 :: proc(a: ^i64, expected, desired: i64) -> i64 {
|
||||
compare_exchange :: proc(a: ^i64, expected, desired: i64) -> i64 {
|
||||
return win32.InterlockedCompareExchange64(a, desired, expected);
|
||||
}
|
||||
exchanged64 :: proc(a: ^i64, desired: i64) -> i64 {
|
||||
exchanged :: proc(a: ^i64, desired: i64) -> i64 {
|
||||
return win32.InterlockedExchange64(a, desired);
|
||||
}
|
||||
fetch_add64 :: proc(a: ^i64, operand: i64) -> i64 {
|
||||
fetch_add :: proc(a: ^i64, operand: i64) -> i64 {
|
||||
return win32.InterlockedExchangeAdd64(a, operand);
|
||||
}
|
||||
fetch_and64 :: proc(a: ^i64, operand: i64) -> i64 {
|
||||
fetch_and :: proc(a: ^i64, operand: i64) -> i64 {
|
||||
return win32.InterlockedAnd64(a, operand);
|
||||
}
|
||||
fetch_or64 :: proc(a: ^i64, operand: i64) -> i64 {
|
||||
fetch_or :: proc(a: ^i64, operand: i64) -> i64 {
|
||||
return win32.InterlockedOr64(a, operand);
|
||||
}
|
||||
spin_lock64 :: proc(a: ^i64, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
|
||||
old_value := compare_exchange64(a, 1, 0);
|
||||
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;
|
||||
while old_value != 0 && (time_out < 0 || counter < time_out) {
|
||||
counter += 1;
|
||||
for old_value != 0 && (time_out < 0 || counter < time_out) {
|
||||
counter++;
|
||||
yield_thread();
|
||||
old_value = compare_exchange64(a, 1, 0);
|
||||
old_value = compare_exchange(a, 1, 0);
|
||||
mfence();
|
||||
}
|
||||
return old_value == 0;
|
||||
}
|
||||
spin_unlock64 :: proc(a: ^i64) {
|
||||
store64(a, 0);
|
||||
spin_unlock :: proc(a: ^i64) {
|
||||
store(a, 0);
|
||||
mfence();
|
||||
}
|
||||
try_acquire_lock64 :: proc(a: ^i64) -> bool {
|
||||
try_acquire_lock :: proc(a: ^i64) -> bool {
|
||||
yield_thread();
|
||||
old_value := compare_exchange64(a, 1, 0);
|
||||
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;
|
||||
}
|
||||
+949
-472
File diff suppressed because it is too large
Load Diff
+102
-64
@@ -1,77 +1,112 @@
|
||||
crc32 :: proc(data: rawptr, len: int) -> u32 {
|
||||
result := ~(0 as u32);
|
||||
s := slice_ptr(data as ^u8, len);
|
||||
for i : 0..<len {
|
||||
b := s[i] as u32;
|
||||
result = result>>8 ~ __CRC32_TABLE[(result ~ b) & 0xff];
|
||||
crc32 :: proc(data: []byte) -> u32 {
|
||||
result := ~cast(u32)0;
|
||||
for b in data {
|
||||
result = result>>8 ~ _crc32_table[(result ~ cast(u32)b) & 0xff];
|
||||
}
|
||||
return ~result;
|
||||
}
|
||||
crc64 :: proc(data: rawptr, len: int) -> u64 {
|
||||
result := ~(0 as u64);
|
||||
s := slice_ptr(data as ^u8, len);
|
||||
for i : 0..<len {
|
||||
b := s[i] as u64;
|
||||
result = result>>8 ~ __CRC64_TABLE[(result ~ b) & 0xff];
|
||||
crc64 :: proc(data: []byte) -> u64 {
|
||||
result := ~cast(u64)0;
|
||||
for b in data {
|
||||
result = result>>8 ~ _crc64_table[(result ~ cast(u64)b) & 0xff];
|
||||
}
|
||||
return ~result;
|
||||
}
|
||||
|
||||
fnv32 :: proc(data: rawptr, len: int) -> u32 {
|
||||
s := slice_ptr(data as ^u8, len);
|
||||
|
||||
fnv32 :: proc(data: []byte) -> u32 {
|
||||
h: u32 = 0x811c9dc5;
|
||||
for i : 0..<len {
|
||||
h = (h * 0x01000193) ~ s[i] as u32;
|
||||
for b in data {
|
||||
h = (h * 0x01000193) ~ cast(u32)b;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
fnv64 :: proc(data: rawptr, len: int) -> u64 {
|
||||
s := slice_ptr(data as ^u8, len);
|
||||
|
||||
fnv64 :: proc(data: []byte) -> u64 {
|
||||
h: u64 = 0xcbf29ce484222325;
|
||||
for i : 0..<len {
|
||||
h = (h * 0x100000001b3) ~ s[i] as u64;
|
||||
for b in data {
|
||||
h = (h * 0x100000001b3) ~ cast(u64)b;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
fnv32a :: proc(data: rawptr, len: int) -> u32 {
|
||||
s := slice_ptr(data as ^u8, len);
|
||||
|
||||
fnv32a :: proc(data: []byte) -> u32 {
|
||||
h: u32 = 0x811c9dc5;
|
||||
for i : 0..<len {
|
||||
h = (h ~ s[i] as u32) * 0x01000193;
|
||||
for b in data {
|
||||
h = (h ~ cast(u32)b) * 0x01000193;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
fnv64a :: proc(data: rawptr, len: int) -> u64 {
|
||||
s := slice_ptr(data as ^u8, len);
|
||||
|
||||
h :u64 = 0xcbf29ce484222325;
|
||||
for i : 0..<len {
|
||||
h = (h ~ s[i] as u64) * 0x100000001b3;
|
||||
fnv64a :: proc(data: []byte) -> u64 {
|
||||
h: u64 = 0xcbf29ce484222325;
|
||||
for b in data {
|
||||
h = (h ~ cast(u64)b) * 0x100000001b3;
|
||||
}
|
||||
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;
|
||||
nblocks := data.count/4;
|
||||
p := data.data;
|
||||
p1 := p + 4*nblocks;
|
||||
|
||||
for ; p < p1; p += 4 {
|
||||
k1 := (cast(^u32)p)^;
|
||||
|
||||
k1 *= c1_32;
|
||||
k1 = (k1 << 15) | (k1 >> 17);
|
||||
k1 *= c2_32;
|
||||
|
||||
h1 ~= k1;
|
||||
h1 = (h1 << 13) | (h1 >> 19);
|
||||
h1 = h1*5 + 0xe6546b64;
|
||||
}
|
||||
|
||||
tail := data[nblocks*4 ..];
|
||||
|
||||
k1: u32;
|
||||
match tail.count&3 {
|
||||
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;
|
||||
}
|
||||
|
||||
h1 ~= cast(u32)data.count;
|
||||
|
||||
h1 ~= h1 >> 16;
|
||||
h1 *= 0x85ebca6b;
|
||||
h1 ~= h1 >> 13;
|
||||
h1 *= 0xc2b2ae35;
|
||||
h1 ~= h1 >> 16;
|
||||
|
||||
return h1;
|
||||
}
|
||||
|
||||
murmur64 :: proc(data: []byte) -> u64 {
|
||||
SEED :: 0x9747b28c;
|
||||
|
||||
when size_of(int) == 8 {
|
||||
when false && size_of(int) == 8 {
|
||||
m :: 0xc6a4a7935bd1e995;
|
||||
r :: 47;
|
||||
|
||||
h: u64 = SEED ~ (len as u64 * m);
|
||||
h: u64 = SEED ~ (cast(u64)data.count * m);
|
||||
data64 := slice_ptr(cast(^u64)^data[0], data.count/size_of(u64));
|
||||
|
||||
data := slice_ptr(data_ as ^u64, len/size_of(u64));
|
||||
data2 := slice_ptr(data_ as ^u8, len);
|
||||
|
||||
for i : 0 ..< data.count {
|
||||
k := data[i];
|
||||
for _, i in data64 {
|
||||
k := data64[i];
|
||||
|
||||
k *= m;
|
||||
k ~= k>>r;
|
||||
@@ -81,15 +116,15 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
|
||||
h *= m;
|
||||
}
|
||||
|
||||
match len & 7 {
|
||||
case 7: h ~= data2[6] as u64 << 48; fallthrough;
|
||||
case 6: h ~= data2[5] as u64 << 40; fallthrough;
|
||||
case 5: h ~= data2[4] as u64 << 32; fallthrough;
|
||||
case 4: h ~= data2[3] as u64 << 24; fallthrough;
|
||||
case 3: h ~= data2[2] as u64 << 16; fallthrough;
|
||||
case 2: h ~= data2[1] as u64 << 8; fallthrough;
|
||||
match data.count&7 {
|
||||
case 7: h ~= cast(u64)data[6] << 48; fallthrough;
|
||||
case 6: h ~= cast(u64)data[5] << 40; fallthrough;
|
||||
case 5: h ~= cast(u64)data[4] << 32; fallthrough;
|
||||
case 4: h ~= cast(u64)data[3] << 24; fallthrough;
|
||||
case 3: h ~= cast(u64)data[2] << 16; fallthrough;
|
||||
case 2: h ~= cast(u64)data[1] << 8; fallthrough;
|
||||
case 1:
|
||||
h ~= data2[0] as u64;
|
||||
h ~= cast(u64)data[0];
|
||||
h *= m;
|
||||
}
|
||||
|
||||
@@ -102,15 +137,16 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
|
||||
m :: 0x5bd1e995;
|
||||
r :: 24;
|
||||
|
||||
h1: u32 = SEED as u32 ~ len as u32;
|
||||
h1: u32 = cast(u32)SEED ~ cast(u32)data.count;
|
||||
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;
|
||||
while len >= 8 {
|
||||
for len >= 8 {
|
||||
k1, k2: u32;
|
||||
k1 = data[i]; i += 1;
|
||||
k1 = data32[i]; i++;
|
||||
k1 *= m;
|
||||
k1 ~= k1>>r;
|
||||
k1 *= m;
|
||||
@@ -118,7 +154,7 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
|
||||
h1 ~= k1;
|
||||
len -= 4;
|
||||
|
||||
k2 = data[i]; i += 1;
|
||||
k2 = data32[i]; i++;
|
||||
k2 *= m;
|
||||
k2 ~= k2>>r;
|
||||
k2 *= m;
|
||||
@@ -129,7 +165,7 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
|
||||
|
||||
if len >= 4 {
|
||||
k1: u32;
|
||||
k1 = data[i]; i += 1;
|
||||
k1 = data32[i]; i++;
|
||||
k1 *= m;
|
||||
k1 ~= k1>>r;
|
||||
k1 *= m;
|
||||
@@ -138,13 +174,16 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
|
||||
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 {
|
||||
case 3: h2 ~= data8[2] as u32 << 16; fallthrough;
|
||||
case 2: h2 ~= data8[1] as u32 << 8; fallthrough;
|
||||
case 3:
|
||||
h2 ~= cast(u32)data8[2] << 16;
|
||||
fallthrough;
|
||||
case 2:
|
||||
h2 ~= cast(u32)data8[1] << 8;
|
||||
fallthrough;
|
||||
case 1:
|
||||
h2 ~= data8[0] as u32;
|
||||
h2 ~= cast(u32)data8[0];
|
||||
h2 *= m;
|
||||
}
|
||||
|
||||
@@ -157,14 +196,13 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
|
||||
h2 ~= h1>>19;
|
||||
h2 *= m;
|
||||
|
||||
h := (h1 as u64)<<32 | h2 as u64;
|
||||
h := cast(u64)(h1)<<32 | cast(u64)(h2);
|
||||
return h;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
__CRC32_TABLE := [256]u32{
|
||||
immutable _crc32_table := [256]u32{
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
|
||||
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
||||
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||
@@ -230,7 +268,7 @@ __CRC32_TABLE := [256]u32{
|
||||
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
|
||||
};
|
||||
__CRC64_TABLE := [256]u64{
|
||||
immutable _crc64_table := [256]u64{
|
||||
0x0000000000000000, 0x42f0e1eba9ea3693, 0x85e1c3d753d46d26, 0xc711223cfa3e5bb5,
|
||||
0x493366450e42ecdf, 0x0bc387aea7a8da4c, 0xccd2a5925d9681f9, 0x8e224479f47cb76a,
|
||||
0x9266cc8a1c85d9be, 0xd0962d61b56fef2d, 0x17870f5d4f51b498, 0x5577eeb6e6bb820b,
|
||||
|
||||
+95
-80
@@ -24,63 +24,79 @@ Mat2 :: [2]Vec2;
|
||||
Mat3 :: [3]Vec3;
|
||||
Mat4 :: [4]Vec4;
|
||||
|
||||
sqrt32 :: proc(x: f32) -> f32 #foreign "llvm.sqrt.f32"
|
||||
sqrt64 :: proc(x: f64) -> f64 #foreign "llvm.sqrt.f64"
|
||||
sqrt :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.sqrt.f32";
|
||||
sqrt :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.sqrt.f64";
|
||||
|
||||
sin32 :: proc(x: f32) -> f32 #foreign "llvm.sin.f32"
|
||||
sin64 :: proc(x: f64) -> f64 #foreign "llvm.sin.f64"
|
||||
sin :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.sin.f32";
|
||||
sin :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.sin.f64";
|
||||
|
||||
cos32 :: proc(x: f32) -> f32 #foreign "llvm.cos.f32"
|
||||
cos64 :: proc(x: f64) -> f64 #foreign "llvm.cos.f64"
|
||||
cos :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.cos.f32";
|
||||
cos :: proc(x: f64) -> f64 #foreign __llvm_core "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); }
|
||||
tan :: proc(x: f32) -> f32 #inline { return sin(x)/cos(x); }
|
||||
tan :: proc(x: f64) -> f64 #inline { return sin(x)/cos(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; }
|
||||
|
||||
sign32 :: proc(x: f32) -> f32 { if x >= 0 { return +1; } return -1; }
|
||||
sign64 :: proc(x: f64) -> f64 { if x >= 0 { return +1; } return -1; }
|
||||
pow :: proc(x, power: f32) -> f32 #foreign __llvm_core "llvm.pow.f32";
|
||||
pow :: proc(x, power: f64) -> f64 #foreign __llvm_core "llvm.pow.f64";
|
||||
|
||||
|
||||
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; }
|
||||
|
||||
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 {
|
||||
if x >= 0 {
|
||||
return floor32(x + 0.5);
|
||||
}
|
||||
return ceil32(x - 0.5);
|
||||
}
|
||||
floor32 :: proc(x: f32) -> f32 {
|
||||
if x >= 0 {
|
||||
return x as int as f32;
|
||||
}
|
||||
return (x-0.5) as int as f32;
|
||||
}
|
||||
ceil32 :: proc(x: f32) -> f32 {
|
||||
if x < 0 {
|
||||
return x as int as f32;
|
||||
}
|
||||
return ((x as int)+1) as f32;
|
||||
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";
|
||||
|
||||
|
||||
copy_sign :: proc(x, y: f32) -> f32 {
|
||||
ix := transmute(u32)x;
|
||||
iy := transmute(u32)y;
|
||||
ix &= 0x7fff_ffff;
|
||||
ix |= iy & 0x8000_0000;
|
||||
return transmute(f32)ix;
|
||||
}
|
||||
|
||||
remainder32 :: proc(x, y: f32) -> f32 {
|
||||
return x - round32(x/y) * y;
|
||||
copy_sign :: proc(x, y: f64) -> f64 {
|
||||
ix := transmute(u64)x;
|
||||
iy := transmute(u64)y;
|
||||
ix &= 0x7fff_ffff_ffff_ff;
|
||||
ix |= iy & 0x8000_0000_0000_0000;
|
||||
return transmute(f64)ix;
|
||||
}
|
||||
|
||||
fmod32 :: proc(x, y: f32) -> f32 {
|
||||
round :: proc(x: f32) -> f32 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); }
|
||||
round :: proc(x: f64) -> f64 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); }
|
||||
|
||||
floor :: proc(x: f32) -> f32 { return x >= 0 ? cast(f32)cast(i64)x : cast(f32)cast(i64)(x-0.5); } // TODO: Get accurate versions
|
||||
floor :: proc(x: f64) -> f64 { return x >= 0 ? cast(f64)cast(i64)x : cast(f64)cast(i64)(x-0.5); } // TODO: Get accurate versions
|
||||
|
||||
ceil :: proc(x: f32) -> f32 { return x < 0 ? cast(f32)cast(i64)x : cast(f32)cast(i64)(x+1); } // TODO: Get accurate versions
|
||||
ceil :: proc(x: f64) -> f64 { return x < 0 ? cast(f64)cast(i64)x : cast(f64)cast(i64)(x+1); } // TODO: Get accurate versions
|
||||
|
||||
remainder :: proc(x, y: f32) -> f32 { return x - round(x/y) * y; }
|
||||
remainder :: proc(x, y: f64) -> f64 { return x - round(x/y) * y; }
|
||||
|
||||
mod :: proc(x, y: f32) -> f32 {
|
||||
y = abs(y);
|
||||
result := remainder32(abs(x), y);
|
||||
if sign32(result) < 0 {
|
||||
result := remainder(abs(x), y);
|
||||
if sign(result) < 0 {
|
||||
result += y;
|
||||
}
|
||||
return copy_sign32(result, x);
|
||||
return copy_sign(result, x);
|
||||
}
|
||||
mod :: proc(x, y: f64) -> f64 {
|
||||
y = abs(y);
|
||||
result := remainder(abs(x), y);
|
||||
if sign(result) < 0 {
|
||||
result += y;
|
||||
}
|
||||
return copy_sign(result, x);
|
||||
}
|
||||
|
||||
|
||||
@@ -89,44 +105,43 @@ to_degrees :: proc(radians: f32) -> f32 { return radians * 360 / TAU; }
|
||||
|
||||
|
||||
|
||||
dot :: proc(a, b: Vec2) -> f32 { c := a*b; return c.x + c.y; }
|
||||
dot :: proc(a, b: Vec3) -> f32 { c := a*b; return c.x + c.y + c.z; }
|
||||
dot :: proc(a, b: Vec4) -> f32 { c := a*b; return c.x + c.y + c.z + c.w; }
|
||||
|
||||
dot2 :: 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; }
|
||||
dot4 :: 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);
|
||||
b := swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0);
|
||||
return a - b;
|
||||
}
|
||||
|
||||
|
||||
vec2_mag :: proc(v: Vec2) -> f32 { return sqrt32(dot2(v, v)); }
|
||||
vec3_mag :: proc(v: Vec3) -> f32 { return sqrt32(dot3(v, v)); }
|
||||
vec4_mag :: proc(v: Vec4) -> f32 { return sqrt32(dot4(v, v)); }
|
||||
mag :: proc(v: Vec2) -> f32 { return sqrt(dot(v, v)); }
|
||||
mag :: proc(v: Vec3) -> f32 { return sqrt(dot(v, v)); }
|
||||
mag :: proc(v: Vec4) -> f32 { return sqrt(dot(v, v)); }
|
||||
|
||||
vec2_norm :: proc(v: Vec2) -> Vec2 { return v / Vec2{vec2_mag(v)}; }
|
||||
vec3_norm :: proc(v: Vec3) -> Vec3 { return v / Vec3{vec3_mag(v)}; }
|
||||
vec4_norm :: proc(v: Vec4) -> Vec4 { return v / Vec4{vec4_mag(v)}; }
|
||||
norm :: proc(v: Vec2) -> Vec2 { return v / Vec2{mag(v)}; }
|
||||
norm :: proc(v: Vec3) -> Vec3 { return v / Vec3{mag(v)}; }
|
||||
norm :: proc(v: Vec4) -> Vec4 { return v / Vec4{mag(v)}; }
|
||||
|
||||
vec2_norm0 :: proc(v: Vec2) -> Vec2 {
|
||||
m := vec2_mag(v);
|
||||
norm0 :: proc(v: Vec2) -> Vec2 {
|
||||
m := mag(v);
|
||||
if m == 0 {
|
||||
return Vec2{0};
|
||||
}
|
||||
return v / Vec2{m};
|
||||
}
|
||||
|
||||
vec3_norm0 :: proc(v: Vec3) -> Vec3 {
|
||||
m := vec3_mag(v);
|
||||
norm0 :: proc(v: Vec3) -> Vec3 {
|
||||
m := mag(v);
|
||||
if m == 0 {
|
||||
return Vec3{0};
|
||||
}
|
||||
return v / Vec3{m};
|
||||
}
|
||||
|
||||
vec4_norm0 :: proc(v: Vec4) -> Vec4 {
|
||||
m := vec4_mag(v);
|
||||
norm0 :: proc(v: Vec4) -> Vec4 {
|
||||
m := mag(v);
|
||||
if m == 0 {
|
||||
return Vec4{0};
|
||||
}
|
||||
@@ -145,18 +160,18 @@ mat4_identity :: proc() -> Mat4 {
|
||||
}
|
||||
|
||||
mat4_transpose :: proc(m: Mat4) -> Mat4 {
|
||||
for j : 0..<4 {
|
||||
for i : 0..<4 {
|
||||
for j in 0..4 {
|
||||
for i in 0..4 {
|
||||
m[i][j], m[j][i] = m[j][i], m[i][j];
|
||||
}
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
mat4_mul :: proc(a, b: Mat4) -> Mat4 {
|
||||
mul :: proc(a, b: Mat4) -> Mat4 {
|
||||
c: Mat4;
|
||||
for j : 0..<4 {
|
||||
for i : 0..<4 {
|
||||
for j in 0..4 {
|
||||
for i in 0..4 {
|
||||
c[j][i] = a[0][i]*b[j][0] +
|
||||
a[1][i]*b[j][1] +
|
||||
a[2][i]*b[j][2] +
|
||||
@@ -166,7 +181,7 @@ mat4_mul :: proc(a, b: Mat4) -> Mat4 {
|
||||
return c;
|
||||
}
|
||||
|
||||
mat4_mul_vec4 :: proc(m: Mat4, v: Vec4) -> Vec4 {
|
||||
mul :: proc(m: Mat4, v: Vec4) -> 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][1]*v.x + m[1][1]*v.y + m[2][1]*v.z + m[3][1]*v.w,
|
||||
@@ -175,7 +190,7 @@ mat4_mul_vec4 :: proc(m: Mat4, v: Vec4) -> Vec4 {
|
||||
};
|
||||
}
|
||||
|
||||
mat4_inverse :: proc(m: Mat4) -> Mat4 {
|
||||
inverse :: proc(m: Mat4) -> Mat4 {
|
||||
o: Mat4;
|
||||
|
||||
sf00 := m[2][2] * m[3][3] - m[3][2] * m[2][3];
|
||||
@@ -254,10 +269,10 @@ mat4_translate :: proc(v: Vec3) -> Mat4 {
|
||||
}
|
||||
|
||||
mat4_rotate :: proc(v: Vec3, angle_radians: f32) -> Mat4 {
|
||||
c := cos32(angle_radians);
|
||||
s := sin32(angle_radians);
|
||||
c := cos(angle_radians);
|
||||
s := sin(angle_radians);
|
||||
|
||||
a := vec3_norm(v);
|
||||
a := norm(v);
|
||||
t := a * Vec3{1-c};
|
||||
|
||||
rot := mat4_identity();
|
||||
@@ -280,14 +295,14 @@ mat4_rotate :: proc(v: Vec3, angle_radians: f32) -> Mat4 {
|
||||
return rot;
|
||||
}
|
||||
|
||||
mat4_scale :: proc(m: Mat4, v: Vec3) -> Mat4 {
|
||||
scale :: proc(m: Mat4, v: Vec3) -> Mat4 {
|
||||
m[0][0] *= v.x;
|
||||
m[1][1] *= v.y;
|
||||
m[2][2] *= v.z;
|
||||
return m;
|
||||
}
|
||||
|
||||
mat4_scalef :: proc(m: Mat4, s: f32) -> Mat4 {
|
||||
scale :: proc(m: Mat4, s: f32) -> Mat4 {
|
||||
m[0][0] *= s;
|
||||
m[1][1] *= s;
|
||||
m[2][2] *= s;
|
||||
@@ -295,23 +310,23 @@ mat4_scalef :: proc(m: Mat4, s: f32) -> Mat4 {
|
||||
}
|
||||
|
||||
|
||||
mat4_look_at :: proc(eye, centre, up: Vec3) -> Mat4 {
|
||||
f := vec3_norm(centre - eye);
|
||||
s := vec3_norm(cross3(f, up));
|
||||
u := cross3(s, f);
|
||||
look_at :: proc(eye, centre, up: Vec3) -> Mat4 {
|
||||
f := norm(centre - eye);
|
||||
s := norm(cross(f, up));
|
||||
u := cross(s, f);
|
||||
|
||||
m: Mat4;
|
||||
|
||||
m[0] = Vec4{+s.x, +s.y, +s.z, 0};
|
||||
m[1] = Vec4{+u.x, +u.y, +u.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;
|
||||
}
|
||||
mat4_perspective :: proc(fovy, aspect, near, far: f32) -> Mat4 {
|
||||
perspective :: proc(fovy, aspect, near, far: f32) -> 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[1][1] = 1.0 / (tan_half_fovy);
|
||||
m[2][2] = -(far + near) / (far - near);
|
||||
@@ -321,7 +336,7 @@ mat4_perspective :: proc(fovy, aspect, near, far: f32) -> Mat4 {
|
||||
}
|
||||
|
||||
|
||||
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[0][0] = +2.0 / (right - left);
|
||||
m[1][1] = +2.0 / (top - bottom);
|
||||
|
||||
+67
-108
@@ -1,71 +1,33 @@
|
||||
#import "fmt.odin";
|
||||
#import "os.odin";
|
||||
|
||||
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(data, value as byte, len, 1, false);
|
||||
return data;
|
||||
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 {
|
||||
return __mem_set(data, value, len);
|
||||
}
|
||||
|
||||
zero :: proc(data: rawptr, len: int) -> rawptr #link_name "__mem_zero" {
|
||||
return set(data, 0, len);
|
||||
zero :: proc(data: rawptr, len: int) -> rawptr {
|
||||
return __mem_zero(data, len);
|
||||
}
|
||||
|
||||
copy :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy" {
|
||||
// NOTE(bill): This _must_ 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(dst, src, len, 1, false);
|
||||
return dst;
|
||||
copy :: proc(dst, src: rawptr, len: int) -> rawptr {
|
||||
return __mem_copy(dst, src, len);
|
||||
}
|
||||
|
||||
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
|
||||
llvm_memcpy_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign "llvm.memcpy.p0i8.p0i8.i64"
|
||||
llvm_memcpy_64bit(dst, src, len, 1, false);
|
||||
return dst;
|
||||
copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr {
|
||||
return __mem_copy_non_overlapping(dst, src, len);
|
||||
}
|
||||
|
||||
compare :: proc(dst, src: rawptr, n: int) -> int #link_name "__mem_compare" {
|
||||
// Translation of http://mgronhol.github.io/fast-strcmp/
|
||||
a := slice_ptr(dst as ^byte, n);
|
||||
b := slice_ptr(src as ^byte, n);
|
||||
|
||||
fast := n/size_of(int) + 1;
|
||||
offset := (fast-1)*size_of(int);
|
||||
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 {
|
||||
if (la[curr_block] ~ lb[curr_block]) != 0 {
|
||||
for pos : curr_block*size_of(int) ..< n {
|
||||
if (a[pos] ~ b[pos]) != 0 {
|
||||
return a[pos] as int - b[pos] as int;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for _ : offset ..< n {
|
||||
if (a[offset] ~ b[offset]) != 0 {
|
||||
return a[offset] as int - b[offset] as int;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
compare :: proc(a, b: []byte) -> int {
|
||||
return __mem_compare(a.data, b.data, min(a.count, b.count));
|
||||
}
|
||||
|
||||
|
||||
|
||||
kilobytes :: proc(x: int) -> int #inline { return (x) * 1024; }
|
||||
megabytes :: proc(x: int) -> int #inline { return kilobytes(x) * 1024; }
|
||||
gigabytes :: proc(x: int) -> int #inline { return gigabytes(x) * 1024; }
|
||||
terabytes :: proc(x: int) -> int #inline { return terabytes(x) * 1024; }
|
||||
gigabytes :: proc(x: int) -> int #inline { return megabytes(x) * 1024; }
|
||||
terabytes :: proc(x: int) -> int #inline { return gigabytes(x) * 1024; }
|
||||
|
||||
is_power_of_two :: proc(x: int) -> bool {
|
||||
if x <= 0 {
|
||||
@@ -77,36 +39,38 @@ is_power_of_two :: proc(x: int) -> bool {
|
||||
align_forward :: proc(ptr: rawptr, align: int) -> rawptr {
|
||||
assert(is_power_of_two(align));
|
||||
|
||||
a := align as uint;
|
||||
p := ptr as uint;
|
||||
a := cast(uint)align;
|
||||
p := cast(uint)ptr;
|
||||
modulo := p & (a-1);
|
||||
if modulo != 0 {
|
||||
p += a - modulo;
|
||||
}
|
||||
return p as rawptr;
|
||||
return cast(rawptr)p;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Allocation_Header :: struct {
|
||||
size: int;
|
||||
size: int,
|
||||
}
|
||||
|
||||
allocation_header_fill :: proc(header: ^Allocation_Header, data: rawptr, size: int) {
|
||||
header.size = size;
|
||||
ptr := (header+1) as ^int;
|
||||
ptr := cast(^int)(header+1);
|
||||
|
||||
while i := 0; ptr as rawptr < data {
|
||||
for i := 0; cast(rawptr)ptr < data; i++ {
|
||||
(ptr+i)^ = -1;
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
allocation_header :: proc(data: rawptr) -> ^Allocation_Header {
|
||||
p := data as ^int;
|
||||
while (p-1)^ == -1 {
|
||||
if data == nil {
|
||||
return nil;
|
||||
}
|
||||
p := cast(^int)data;
|
||||
for (p-1)^ == -1 {
|
||||
p = (p-1);
|
||||
}
|
||||
return (p as ^Allocation_Header)-1;
|
||||
return cast(^Allocation_Header)p-1;
|
||||
}
|
||||
|
||||
|
||||
@@ -115,15 +79,15 @@ allocation_header :: proc(data: rawptr) -> ^Allocation_Header {
|
||||
|
||||
// Custom allocators
|
||||
Arena :: struct {
|
||||
backing: Allocator;
|
||||
offset: int;
|
||||
memory: []byte;
|
||||
temp_count: int;
|
||||
backing: Allocator,
|
||||
offset: int,
|
||||
memory: []byte,
|
||||
temp_count: int,
|
||||
}
|
||||
|
||||
Arena_Temp_Memory :: struct {
|
||||
arena: ^Arena;
|
||||
original_count: int;
|
||||
arena: ^Arena,
|
||||
original_count: int,
|
||||
}
|
||||
|
||||
|
||||
@@ -132,7 +96,7 @@ Arena_Temp_Memory :: struct {
|
||||
|
||||
init_arena_from_memory :: proc(using a: ^Arena, data: []byte) {
|
||||
backing = Allocator{};
|
||||
memory = data[:0];
|
||||
memory = data[..0];
|
||||
temp_count = 0;
|
||||
}
|
||||
|
||||
@@ -145,8 +109,8 @@ init_arena_from_context :: proc(using a: ^Arena, size: int) {
|
||||
free_arena :: proc(using a: ^Arena) {
|
||||
if backing.procedure != nil {
|
||||
push_allocator backing {
|
||||
free(memory.data);
|
||||
memory = memory[0:0];
|
||||
free(memory);
|
||||
memory = nil;
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
@@ -163,7 +127,7 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
|
||||
using Allocator_Mode;
|
||||
arena := allocator_data as ^Arena;
|
||||
arena := cast(^Arena)allocator_data;
|
||||
|
||||
match mode {
|
||||
case ALLOC:
|
||||
@@ -198,7 +162,7 @@ begin_arena_temp_memory :: proc(a: ^Arena) -> Arena_Temp_Memory {
|
||||
tmp: Arena_Temp_Memory;
|
||||
tmp.arena = a;
|
||||
tmp.original_count = a.memory.count;
|
||||
a.temp_count += 1;
|
||||
a.temp_count++;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@@ -206,7 +170,7 @@ end_arena_temp_memory :: proc(using tmp: Arena_Temp_Memory) {
|
||||
assert(arena.memory.count >= original_count);
|
||||
assert(arena.temp_count > 0);
|
||||
arena.memory.count = original_count;
|
||||
arena.temp_count -= 1;
|
||||
arena.temp_count--;
|
||||
}
|
||||
|
||||
|
||||
@@ -232,8 +196,7 @@ align_of_type_info :: proc(type_info: ^Type_Info) -> int {
|
||||
WORD_SIZE :: size_of(int);
|
||||
MAX_ALIGN :: size_of([vector 64]f64); // TODO(bill): Should these constants be builtin constants?
|
||||
using Type_Info;
|
||||
|
||||
match type info : type_info {
|
||||
match info in type_info {
|
||||
case Named:
|
||||
return align_of_type_info(info.base);
|
||||
case Integer:
|
||||
@@ -244,27 +207,35 @@ align_of_type_info :: proc(type_info: ^Type_Info) -> int {
|
||||
return WORD_SIZE;
|
||||
case Boolean:
|
||||
return 1;
|
||||
case Any:
|
||||
return WORD_SIZE;
|
||||
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 Dynamic_Array:
|
||||
return WORD_SIZE;
|
||||
case Slice:
|
||||
return WORD_SIZE;
|
||||
case Vector:
|
||||
size := size_of_type_info(info.elem);
|
||||
count := max(prev_pow2(info.count as i64), 1) as int;
|
||||
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;
|
||||
@@ -278,23 +249,21 @@ align_formula :: proc(size, align: int) -> int {
|
||||
size_of_type_info :: proc(type_info: ^Type_Info) -> int {
|
||||
WORD_SIZE :: size_of(int);
|
||||
using Type_Info;
|
||||
match type info : type_info {
|
||||
match info in type_info {
|
||||
case Named:
|
||||
return size_of_type_info(info.base);
|
||||
case Integer:
|
||||
return info.size;
|
||||
case Float:
|
||||
return info.size;
|
||||
case Any:
|
||||
return 2*WORD_SIZE;
|
||||
case String:
|
||||
return 2*WORD_SIZE;
|
||||
case Boolean:
|
||||
return 1;
|
||||
case Any:
|
||||
return 2*WORD_SIZE;
|
||||
case Pointer:
|
||||
return WORD_SIZE;
|
||||
case Maybe:
|
||||
return size_of_type_info(info.elem) + 1;
|
||||
case Procedure:
|
||||
return WORD_SIZE;
|
||||
case Array:
|
||||
@@ -306,39 +275,29 @@ size_of_type_info :: proc(type_info: ^Type_Info) -> int {
|
||||
align := align_of_type_info(info.elem);
|
||||
alignment := align_formula(size, align);
|
||||
return alignment*(count-1) + size;
|
||||
case Dynamic_Array:
|
||||
return size_of(rawptr) + 2*size_of(int) + size_of(Allocator);
|
||||
case Slice:
|
||||
return 3*WORD_SIZE;
|
||||
return 2*WORD_SIZE;
|
||||
case Vector:
|
||||
is_bool :: proc(type_info: ^Type_Info) -> bool {
|
||||
match type info : type_info {
|
||||
case Named:
|
||||
return is_bool(info.base);
|
||||
case Boolean:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
count := info.count;
|
||||
if count == 0 {
|
||||
return 0;
|
||||
}
|
||||
bit_size := 8*size_of_type_info(info.elem);
|
||||
if is_bool(info.elem) {
|
||||
// NOTE(bill): LLVM can store booleans as 1 bit because a boolean _is_ an `i1`
|
||||
// Silly LLVM spec
|
||||
bit_size = 1;
|
||||
}
|
||||
total_size_in_bits := bit_size * count;
|
||||
total_size := (total_size_in_bits+7)/8;
|
||||
return total_size;
|
||||
|
||||
size := size_of_type_info(info.elem);
|
||||
align := align_of_type_info(info.elem);
|
||||
alignment := align_formula(size, align);
|
||||
return alignment*(count-1) + size;
|
||||
case Struct:
|
||||
return info.size;
|
||||
case Union:
|
||||
return info.size;
|
||||
case Raw_Union:
|
||||
return info.size;
|
||||
case Enum:
|
||||
return size_of_type_info(info.base);
|
||||
case Map:
|
||||
return size_of_type_info(info.generated_struct);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
+112
-110
@@ -1,154 +1,156 @@
|
||||
#foreign_system_library "opengl32" when ODIN_OS == "windows";
|
||||
#foreign_system_library lib "opengl32.lib" when ODIN_OS == "windows";
|
||||
#import win32 "sys/windows.odin" when ODIN_OS == "windows";
|
||||
#include "opengl_constants.odin";
|
||||
#import "sys/wgl.odin" when ODIN_OS == "windows";
|
||||
#load "opengl_constants.odin";
|
||||
|
||||
Clear :: proc(mask: u32) #foreign "glClear"
|
||||
ClearColor :: proc(r, g, b, a: f32) #foreign "glClearColor"
|
||||
Begin :: proc(mode: i32) #foreign "glBegin"
|
||||
End :: proc() #foreign "glEnd"
|
||||
Finish :: proc() #foreign "glFinish"
|
||||
BlendFunc :: proc(sfactor, dfactor: i32) #foreign "glBlendFunc"
|
||||
Enable :: proc(cap: i32) #foreign "glEnable"
|
||||
Disable :: proc(cap: i32) #foreign "glDisable"
|
||||
GenTextures :: proc(count: i32, result: ^u32) #foreign "glGenTextures"
|
||||
DeleteTextures:: proc(count: i32, result: ^u32) #foreign "glDeleteTextures"
|
||||
TexParameteri :: proc(target, pname, param: i32) #foreign "glTexParameteri"
|
||||
TexParameterf :: proc(target: i32, pname: i32, param: f32) #foreign "glTexParameterf"
|
||||
BindTexture :: proc(target: i32, texture: u32) #foreign "glBindTexture"
|
||||
LoadIdentity :: proc() #foreign "glLoadIdentity"
|
||||
Viewport :: proc(x, y, width, height: i32) #foreign "glViewport"
|
||||
Ortho :: proc(left, right, bottom, top, near, far: f64) #foreign "glOrtho"
|
||||
Color3f :: proc(r, g, b: f32) #foreign "glColor3f"
|
||||
Vertex3f :: proc(x, y, z: f32) #foreign "glVertex3f"
|
||||
Clear :: proc(mask: u32) #foreign lib "glClear";
|
||||
ClearColor :: proc(r, g, b, a: f32) #foreign lib "glClearColor";
|
||||
Begin :: proc(mode: i32) #foreign lib "glBegin";
|
||||
End :: proc() #foreign lib "glEnd";
|
||||
Finish :: proc() #foreign lib "glFinish";
|
||||
BlendFunc :: proc(sfactor, dfactor: i32) #foreign lib "glBlendFunc";
|
||||
Enable :: proc(cap: i32) #foreign lib "glEnable";
|
||||
Disable :: proc(cap: i32) #foreign lib "glDisable";
|
||||
GenTextures :: proc(count: i32, result: ^u32) #foreign lib "glGenTextures";
|
||||
DeleteTextures:: proc(count: i32, result: ^u32) #foreign lib "glDeleteTextures";
|
||||
TexParameteri :: proc(target, pname, param: i32) #foreign lib "glTexParameteri";
|
||||
TexParameterf :: proc(target: i32, pname: i32, param: f32) #foreign lib "glTexParameterf";
|
||||
BindTexture :: proc(target: i32, texture: u32) #foreign lib "glBindTexture";
|
||||
LoadIdentity :: proc() #foreign lib "glLoadIdentity";
|
||||
Viewport :: proc(x, y, width, height: i32) #foreign lib "glViewport";
|
||||
Ortho :: proc(left, right, bottom, top, near, far: f64) #foreign lib "glOrtho";
|
||||
Color3f :: proc(r, g, b: f32) #foreign lib "glColor3f";
|
||||
Vertex3f :: proc(x, y, z: f32) #foreign lib "glVertex3f";
|
||||
GetError :: proc() -> i32 #foreign lib "glGetError";
|
||||
GetString :: proc(name: i32) -> ^byte #foreign lib "glGetString";
|
||||
GetIntegerv :: proc(name: i32, v: ^i32) #foreign lib "glGetIntegerv";
|
||||
TexCoord2f :: proc(x, y: f32) #foreign lib "glTexCoord2f";
|
||||
TexImage2D :: proc(target, level, internal_format,
|
||||
width, height, border,
|
||||
format, _type: i32, pixels: rawptr) #foreign "glTexImage2D"
|
||||
|
||||
GetError :: proc() -> i32 #foreign "glGetError"
|
||||
GetString :: proc(name: i32) -> ^byte #foreign "glGetString"
|
||||
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() #cc_c {
|
||||
assert(name[name.count-1] == 0);
|
||||
res := win32.wglGetProcAddress(name.data);
|
||||
res := wgl.GetProcAddress(name.data);
|
||||
if res == nil {
|
||||
res = win32.GetProcAddress(_libgl, name.data);
|
||||
}
|
||||
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) #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;
|
||||
|
||||
DrawArrays: proc(mode, first: i32, count: u32) #cc_c;
|
||||
DrawElements: proc(mode: i32, count: u32, type_: i32, indices: rawptr) #cc_c;
|
||||
DrawArrays: proc(mode, first: i32, count: u32) #cc_c;
|
||||
DrawElements: proc(mode: i32, count: u32, type_: i32, indices: rawptr) #cc_c;
|
||||
|
||||
MapBuffer: proc(target, access: i32) -> rawptr #cc_c;
|
||||
UnmapBuffer: proc(target: i32) #cc_c;
|
||||
MapBuffer: proc(target, access: i32) -> rawptr #cc_c;
|
||||
UnmapBuffer: proc(target: i32) #cc_c;
|
||||
|
||||
VertexAttribPointer: proc(index: u32, size, type_: i32, normalized: i32, stride: u32, pointer: rawptr) #cc_c;
|
||||
VertexAttribPointer: proc(index: u32, size, type_: i32, normalized: i32, stride: u32, pointer: rawptr) #cc_c;
|
||||
EnableVertexAttribArray: proc(index: u32) #cc_c;
|
||||
|
||||
CreateShader: proc(shader_type: i32) -> u32 #cc_c;
|
||||
ShaderSource: proc(shader: u32, count: u32, str: ^^byte, length: ^i32) #cc_c;
|
||||
CompileShader: proc(shader: u32) #cc_c;
|
||||
CreateProgram: proc() -> u32 #cc_c;
|
||||
AttachShader: proc(program, shader: u32) #cc_c;
|
||||
DetachShader: proc(program, shader: u32) #cc_c;
|
||||
DeleteShader: proc(shader: u32) #cc_c;
|
||||
LinkProgram: proc(program: u32) #cc_c;
|
||||
UseProgram: proc(program: u32) #cc_c;
|
||||
DeleteProgram: proc(program: u32) #cc_c;
|
||||
CreateShader: proc(shader_type: i32) -> u32 #cc_c;
|
||||
ShaderSource: proc(shader: u32, count: u32, str: ^^byte, length: ^i32) #cc_c;
|
||||
CompileShader: proc(shader: u32) #cc_c;
|
||||
CreateProgram: proc() -> u32 #cc_c;
|
||||
AttachShader: proc(program, shader: u32) #cc_c;
|
||||
DetachShader: proc(program, shader: u32) #cc_c;
|
||||
DeleteShader: proc(shader: u32) #cc_c;
|
||||
LinkProgram: proc(program: u32) #cc_c;
|
||||
UseProgram: proc(program: u32) #cc_c;
|
||||
DeleteProgram: proc(program: u32) #cc_c;
|
||||
|
||||
|
||||
GetShaderiv: proc(shader: u32, pname: i32, params: ^i32) #cc_c;
|
||||
GetProgramiv: proc(program: u32, pname: i32, params: ^i32) #cc_c;
|
||||
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) #cc_c;
|
||||
GetShaderiv: proc(shader: u32, pname: i32, params: ^i32) #cc_c;
|
||||
GetProgramiv: proc(program: u32, pname: i32, params: ^i32) #cc_c;
|
||||
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) #cc_c;
|
||||
|
||||
ActiveTexture: proc(texture: i32) #cc_c;
|
||||
GenerateMipmap: proc(target: i32) #cc_c;
|
||||
ActiveTexture: proc(texture: i32) #cc_c;
|
||||
GenerateMipmap: proc(target: i32) #cc_c;
|
||||
|
||||
SamplerParameteri: proc(sampler: u32, pname: i32, param: i32) #cc_c;
|
||||
SamplerParameterf: proc(sampler: u32, pname: i32, param: f32) #cc_c;
|
||||
SamplerParameteriv: proc(sampler: u32, pname: i32, params: ^i32) #cc_c;
|
||||
SamplerParameterfv: proc(sampler: u32, pname: i32, params: ^f32) #cc_c;
|
||||
SamplerParameterIiv: proc(sampler: u32, pname: i32, params: ^i32) #cc_c;
|
||||
SamplerParameterIuiv: proc(sampler: u32, pname: i32, params: ^u32) #cc_c;
|
||||
SamplerParameteri: proc(sampler: u32, pname: i32, param: i32) #cc_c;
|
||||
SamplerParameterf: proc(sampler: u32, pname: i32, param: f32) #cc_c;
|
||||
SamplerParameteriv: proc(sampler: u32, pname: i32, params: ^i32) #cc_c;
|
||||
SamplerParameterfv: proc(sampler: u32, pname: i32, params: ^f32) #cc_c;
|
||||
SamplerParameterIiv: proc(sampler: u32, pname: i32, params: ^i32) #cc_c;
|
||||
SamplerParameterIuiv: proc(sampler: u32, pname: i32, params: ^u32) #cc_c;
|
||||
|
||||
|
||||
Uniform1i: proc(loc: i32, v0: i32) #cc_c;
|
||||
Uniform2i: proc(loc: i32, v0, v1: i32) #cc_c;
|
||||
Uniform3i: proc(loc: i32, v0, v1, v2: i32) #cc_c;
|
||||
Uniform4i: proc(loc: i32, v0, v1, v2, v3: i32) #cc_c;
|
||||
Uniform1f: proc(loc: i32, v0: f32) #cc_c;
|
||||
Uniform2f: proc(loc: i32, v0, v1: f32) #cc_c;
|
||||
Uniform3f: proc(loc: i32, v0, v1, v2: f32) #cc_c;
|
||||
Uniform4f: proc(loc: i32, v0, v1, v2, v3: f32) #cc_c;
|
||||
UniformMatrix4fv: proc(loc: i32, count: u32, transpose: i32, value: ^f32) #cc_c;
|
||||
Uniform1i: proc(loc: i32, v0: i32) #cc_c;
|
||||
Uniform2i: proc(loc: i32, v0, v1: i32) #cc_c;
|
||||
Uniform3i: proc(loc: i32, v0, v1, v2: i32) #cc_c;
|
||||
Uniform4i: proc(loc: i32, v0, v1, v2, v3: i32) #cc_c;
|
||||
Uniform1f: proc(loc: i32, v0: f32) #cc_c;
|
||||
Uniform2f: proc(loc: i32, v0, v1: f32) #cc_c;
|
||||
Uniform3f: proc(loc: i32, v0, v1, v2: f32) #cc_c;
|
||||
Uniform4f: proc(loc: i32, v0, v1, v2, v3: f32) #cc_c;
|
||||
UniformMatrix4fv: proc(loc: i32, count: u32, transpose: i32, value: ^f32) #cc_c;
|
||||
|
||||
GetUniformLocation: proc(program: u32, name: ^byte) -> i32 #cc_c;
|
||||
GetUniformLocation: proc(program: u32, name: ^byte) -> i32 #cc_c;
|
||||
|
||||
init :: proc() {
|
||||
set_proc_address :: proc(p: rawptr, name: string) #inline { (p as ^(proc() #cc_c))^ = 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(^GenVertexArrays, "glGenVertexArrays\x00");
|
||||
set_proc_address(^GenSamplers, "glGenSamplers\x00");
|
||||
set_proc_address(^BindBuffer, "glBindBuffer\x00");
|
||||
set_proc_address(^BindSampler, "glBindSampler\x00");
|
||||
set_proc_address(^BindVertexArray, "glBindVertexArray\x00");
|
||||
set_proc_address(^BufferData, "glBufferData\x00");
|
||||
set_proc_address(^BufferSubData, "glBufferSubData\x00");
|
||||
set_proc_address(^GenBuffers, "glGenBuffers\x00");
|
||||
set_proc_address(^GenVertexArrays, "glGenVertexArrays\x00");
|
||||
set_proc_address(^GenSamplers, "glGenSamplers\x00");
|
||||
set_proc_address(^BindBuffer, "glBindBuffer\x00");
|
||||
set_proc_address(^BindSampler, "glBindSampler\x00");
|
||||
set_proc_address(^BindVertexArray, "glBindVertexArray\x00");
|
||||
set_proc_address(^BufferData, "glBufferData\x00");
|
||||
set_proc_address(^BufferSubData, "glBufferSubData\x00");
|
||||
|
||||
set_proc_address(^DrawArrays, "glDrawArrays\x00");
|
||||
set_proc_address(^DrawElements, "glDrawElements\x00");
|
||||
set_proc_address(^DrawArrays, "glDrawArrays\x00");
|
||||
set_proc_address(^DrawElements, "glDrawElements\x00");
|
||||
|
||||
set_proc_address(^MapBuffer, "glMapBuffer\x00");
|
||||
set_proc_address(^UnmapBuffer, "glUnmapBuffer\x00");
|
||||
set_proc_address(^MapBuffer, "glMapBuffer\x00");
|
||||
set_proc_address(^UnmapBuffer, "glUnmapBuffer\x00");
|
||||
|
||||
set_proc_address(^VertexAttribPointer, "glVertexAttribPointer\x00");
|
||||
set_proc_address(^EnableVertexAttribArray, "glEnableVertexAttribArray\x00");
|
||||
|
||||
set_proc_address(^CreateShader, "glCreateShader\x00");
|
||||
set_proc_address(^ShaderSource, "glShaderSource\x00");
|
||||
set_proc_address(^CompileShader, "glCompileShader\x00");
|
||||
set_proc_address(^CreateProgram, "glCreateProgram\x00");
|
||||
set_proc_address(^AttachShader, "glAttachShader\x00");
|
||||
set_proc_address(^DetachShader, "glDetachShader\x00");
|
||||
set_proc_address(^DeleteShader, "glDeleteShader\x00");
|
||||
set_proc_address(^LinkProgram, "glLinkProgram\x00");
|
||||
set_proc_address(^UseProgram, "glUseProgram\x00");
|
||||
set_proc_address(^DeleteProgram, "glDeleteProgram\x00");
|
||||
set_proc_address(^CreateShader, "glCreateShader\x00");
|
||||
set_proc_address(^ShaderSource, "glShaderSource\x00");
|
||||
set_proc_address(^CompileShader, "glCompileShader\x00");
|
||||
set_proc_address(^CreateProgram, "glCreateProgram\x00");
|
||||
set_proc_address(^AttachShader, "glAttachShader\x00");
|
||||
set_proc_address(^DetachShader, "glDetachShader\x00");
|
||||
set_proc_address(^DeleteShader, "glDeleteShader\x00");
|
||||
set_proc_address(^LinkProgram, "glLinkProgram\x00");
|
||||
set_proc_address(^UseProgram, "glUseProgram\x00");
|
||||
set_proc_address(^DeleteProgram, "glDeleteProgram\x00");
|
||||
|
||||
set_proc_address(^GetShaderiv, "glGetShaderiv\x00");
|
||||
set_proc_address(^GetProgramiv, "glGetProgramiv\x00");
|
||||
set_proc_address(^GetShaderInfoLog, "glGetShaderInfoLog\x00");
|
||||
set_proc_address(^GetProgramInfoLog, "glGetProgramInfoLog\x00");
|
||||
set_proc_address(^GetShaderiv, "glGetShaderiv\x00");
|
||||
set_proc_address(^GetProgramiv, "glGetProgramiv\x00");
|
||||
set_proc_address(^GetShaderInfoLog, "glGetShaderInfoLog\x00");
|
||||
set_proc_address(^GetProgramInfoLog, "glGetProgramInfoLog\x00");
|
||||
|
||||
set_proc_address(^ActiveTexture, "glActiveTexture\x00");
|
||||
set_proc_address(^GenerateMipmap, "glGenerateMipmap\x00");
|
||||
set_proc_address(^ActiveTexture, "glActiveTexture\x00");
|
||||
set_proc_address(^GenerateMipmap, "glGenerateMipmap\x00");
|
||||
|
||||
set_proc_address(^Uniform1i, "glUniform1i\x00");
|
||||
set_proc_address(^UniformMatrix4fv, "glUniformMatrix4fv\x00");
|
||||
set_proc_address(^Uniform1i, "glUniform1i\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(^SamplerParameterf, "glSamplerParameterf\x00");
|
||||
set_proc_address(^SamplerParameteriv, "glSamplerParameteriv\x00");
|
||||
set_proc_address(^SamplerParameterfv, "glSamplerParameterfv\x00");
|
||||
set_proc_address(^SamplerParameterIiv, "glSamplerParameterIiv\x00");
|
||||
set_proc_address(^SamplerParameterIuiv, "glSamplerParameterIuiv\x00");
|
||||
set_proc_address(^SamplerParameteri, "glSamplerParameteri\x00");
|
||||
set_proc_address(^SamplerParameterf, "glSamplerParameterf\x00");
|
||||
set_proc_address(^SamplerParameteriv, "glSamplerParameteriv\x00");
|
||||
set_proc_address(^SamplerParameterfv, "glSamplerParameterfv\x00");
|
||||
set_proc_address(^SamplerParameterIiv, "glSamplerParameterIiv\x00");
|
||||
set_proc_address(^SamplerParameterIuiv, "glSamplerParameterIuiv\x00");
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -1,2 +1,3 @@
|
||||
#include "os_windows.odin" when ODIN_OS == "windows"
|
||||
#load "os_windows.odin" when ODIN_OS == "windows";
|
||||
#load "os_x.odin" when ODIN_OS == "osx";
|
||||
|
||||
|
||||
+107
-98
@@ -1,12 +1,12 @@
|
||||
#import win32 "sys/windows.odin";
|
||||
#import w "sys/windows.odin";
|
||||
#import "fmt.odin";
|
||||
|
||||
|
||||
Handle :: uint;
|
||||
Handle :: int;
|
||||
File_Time :: u64;
|
||||
Error :: int;
|
||||
Errno :: int;
|
||||
|
||||
INVALID_HANDLE: Handle : ~(0 as Handle);
|
||||
INVALID_HANDLE: Handle : -1;
|
||||
|
||||
|
||||
O_RDONLY :: 0x00000;
|
||||
@@ -22,60 +22,59 @@ O_SYNC :: 0x01000;
|
||||
O_ASYNC :: 0x02000;
|
||||
O_CLOEXEC :: 0x80000;
|
||||
|
||||
ERROR_NONE: Error : 0;
|
||||
ERROR_FILE_NOT_FOUND: Error : 2;
|
||||
ERROR_PATH_NOT_FOUND: Error : 3;
|
||||
ERROR_ACCESS_DENIED: Error : 5;
|
||||
ERROR_NO_MORE_FILES: Error : 18;
|
||||
ERROR_HANDLE_EOF: Error : 38;
|
||||
ERROR_NETNAME_DELETED: Error : 64;
|
||||
ERROR_FILE_EXISTS: Error : 80;
|
||||
ERROR_BROKEN_PIPE: Error : 109;
|
||||
ERROR_BUFFER_OVERFLOW: Error : 111;
|
||||
ERROR_INSUFFICIENT_BUFFER: Error : 122;
|
||||
ERROR_MOD_NOT_FOUND: Error : 126;
|
||||
ERROR_PROC_NOT_FOUND: Error : 127;
|
||||
ERROR_DIR_NOT_EMPTY: Error : 145;
|
||||
ERROR_ALREADY_EXISTS: Error : 183;
|
||||
ERROR_ENVVAR_NOT_FOUND: Error : 203;
|
||||
ERROR_MORE_DATA: Error : 234;
|
||||
ERROR_OPERATION_ABORTED: Error : 995;
|
||||
ERROR_IO_PENDING: Error : 997;
|
||||
ERROR_NOT_FOUND: Error : 1168;
|
||||
ERROR_PRIVILEGE_NOT_HELD: Error : 1314;
|
||||
WSAEACCES: Error : 10013;
|
||||
WSAECONNRESET: Error : 10054;
|
||||
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: Error : 1<<29 + 0;
|
||||
ERROR_FILE_IS_PIPE: Errno : 1<<29 + 0;
|
||||
|
||||
|
||||
|
||||
|
||||
open :: proc(path: string, mode: int, perm: u32) -> (Handle, Error) {
|
||||
using win32;
|
||||
open :: proc(path: string, mode: int, perm: u32) -> (Handle, Errno) {
|
||||
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;
|
||||
case O_RDONLY: access = w.FILE_GENERIC_READ;
|
||||
case O_WRONLY: access = w.FILE_GENERIC_WRITE;
|
||||
case O_RDWR: access = w.FILE_GENERIC_READ | w.FILE_GENERIC_WRITE;
|
||||
}
|
||||
|
||||
if mode&O_CREAT != 0 {
|
||||
access |= FILE_GENERIC_WRITE;
|
||||
access |= w.FILE_GENERIC_WRITE;
|
||||
}
|
||||
if mode&O_APPEND != 0 {
|
||||
access &~= FILE_GENERIC_WRITE;
|
||||
access |= FILE_APPEND_DATA;
|
||||
access &~= w.FILE_GENERIC_WRITE;
|
||||
access |= w.FILE_APPEND_DATA;
|
||||
}
|
||||
|
||||
share_mode := (FILE_SHARE_READ|FILE_SHARE_WRITE) as u32;
|
||||
sa: ^SECURITY_ATTRIBUTES = nil;
|
||||
sa_inherit := SECURITY_ATTRIBUTES{length = size_of(SECURITY_ATTRIBUTES), inherit_handle = 1};
|
||||
share_mode := cast(u32)(w.FILE_SHARE_READ|w.FILE_SHARE_WRITE);
|
||||
sa: ^w.Security_Attributes = nil;
|
||||
sa_inherit := w.Security_Attributes{length = size_of(w.Security_Attributes), inherit_handle = 1};
|
||||
if mode&O_CLOEXEC == 0 {
|
||||
sa = ^sa_inherit;
|
||||
}
|
||||
@@ -83,84 +82,85 @@ open :: proc(path: string, mode: int, perm: u32) -> (Handle, Error) {
|
||||
create_mode: u32;
|
||||
match {
|
||||
case mode&(O_CREAT|O_EXCL) == (O_CREAT | O_EXCL):
|
||||
create_mode = CREATE_NEW;
|
||||
create_mode = w.CREATE_NEW;
|
||||
case mode&(O_CREAT|O_TRUNC) == (O_CREAT | O_TRUNC):
|
||||
create_mode = CREATE_ALWAYS;
|
||||
create_mode = w.CREATE_ALWAYS;
|
||||
case mode&O_CREAT == O_CREAT:
|
||||
create_mode = OPEN_ALWAYS;
|
||||
create_mode = w.OPEN_ALWAYS;
|
||||
case mode&O_TRUNC == O_TRUNC:
|
||||
create_mode = TRUNCATE_EXISTING;
|
||||
create_mode = w.TRUNCATE_EXISTING;
|
||||
default:
|
||||
create_mode = OPEN_EXISTING;
|
||||
create_mode = w.OPEN_EXISTING;
|
||||
}
|
||||
|
||||
buf: [300]byte;
|
||||
copy(buf[:], path as []byte);
|
||||
copy(buf[..], cast([]byte)path);
|
||||
|
||||
handle := CreateFileA(^buf[0], access, share_mode, sa, create_mode, FILE_ATTRIBUTE_NORMAL, nil) as Handle;
|
||||
if handle == INVALID_HANDLE {
|
||||
handle := cast(Handle)w.CreateFileA(^buf[0], access, share_mode, sa, create_mode, w.FILE_ATTRIBUTE_NORMAL, nil);
|
||||
if handle != INVALID_HANDLE {
|
||||
return handle, ERROR_NONE;
|
||||
}
|
||||
err := GetLastError();
|
||||
return INVALID_HANDLE, err as Error;
|
||||
err := w.GetLastError();
|
||||
return INVALID_HANDLE, cast(Errno)err;
|
||||
}
|
||||
|
||||
close :: proc(fd: Handle) {
|
||||
win32.CloseHandle(fd as win32.HANDLE);
|
||||
w.CloseHandle(cast(w.Handle)fd);
|
||||
}
|
||||
|
||||
write :: proc(fd: Handle, data: []byte) -> (int, Error) {
|
||||
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||
bytes_written: i32;
|
||||
e := win32.WriteFile(fd as win32.HANDLE, data.data, data.count as i32, ^bytes_written, nil);
|
||||
if e != 0 {
|
||||
return 0, e as Error;
|
||||
e := w.WriteFile(cast(w.Handle)fd, data.data, cast(i32)data.count, ^bytes_written, nil);
|
||||
if e == w.FALSE {
|
||||
err := w.GetLastError();
|
||||
return 0, cast(Errno)err;
|
||||
}
|
||||
return bytes_written as int, ERROR_NONE;
|
||||
return cast(int)bytes_written, ERROR_NONE;
|
||||
}
|
||||
|
||||
read :: proc(fd: Handle, data: []byte) -> (int, Error) {
|
||||
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||
bytes_read: i32;
|
||||
e := win32.ReadFile(fd as win32.HANDLE, data.data, data.count as u32, ^bytes_read, nil);
|
||||
if e != win32.FALSE {
|
||||
err := win32.GetLastError();
|
||||
return 0, err as Error;
|
||||
e := w.ReadFile(cast(w.Handle)fd, data.data, cast(u32)data.count, ^bytes_read, nil);
|
||||
if e == w.FALSE {
|
||||
err := w.GetLastError();
|
||||
return 0, cast(Errno)err;
|
||||
}
|
||||
return bytes_read as int, ERROR_NONE;
|
||||
return cast(int)bytes_read, ERROR_NONE;
|
||||
}
|
||||
|
||||
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) {
|
||||
using win32;
|
||||
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
||||
using w;
|
||||
w: u32;
|
||||
match whence {
|
||||
case 0: w = FILE_BEGIN;
|
||||
case 1: w = FILE_CURRENT;
|
||||
case 2: w = FILE_END;
|
||||
}
|
||||
hi := (offset>>32) as i32;
|
||||
lo := offset as i32;
|
||||
ft := GetFileType(fd as HANDLE);
|
||||
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(fd as HANDLE, lo, ^hi, w);
|
||||
dw_ptr := SetFilePointer(cast(Handle)fd, lo, ^hi, w);
|
||||
if dw_ptr == INVALID_SET_FILE_POINTER {
|
||||
err := GetLastError();
|
||||
return 0, err as Error;
|
||||
return 0, cast(Errno)err;
|
||||
}
|
||||
return (hi as i64)<<32 + (dw_ptr as i64), ERROR_NONE;
|
||||
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);
|
||||
stdin := get_std_handle(w.STD_INPUT_HANDLE);
|
||||
stdout := get_std_handle(w.STD_OUTPUT_HANDLE);
|
||||
stderr := get_std_handle(w.STD_ERROR_HANDLE);
|
||||
|
||||
|
||||
get_std_handle :: proc(h: int) -> Handle {
|
||||
fd := win32.GetStdHandle(h as i32);
|
||||
win32.SetHandleInformation(fd, win32.HANDLE_FLAG_INHERIT, 0);
|
||||
return fd as Handle;
|
||||
fd := w.GetStdHandle(cast(i32)h);
|
||||
w.SetHandleInformation(fd, w.HANDLE_FLAG_INHERIT, 0);
|
||||
return cast(Handle)fd;
|
||||
}
|
||||
|
||||
|
||||
@@ -169,28 +169,28 @@ get_std_handle :: proc(h: int) -> Handle {
|
||||
|
||||
|
||||
last_write_time :: proc(fd: Handle) -> File_Time {
|
||||
file_info: win32.BY_HANDLE_FILE_INFORMATION;
|
||||
win32.GetFileInformationByHandle(fd as win32.HANDLE, ^file_info);
|
||||
lo := file_info.last_write_time.lo as File_Time;
|
||||
hi := file_info.last_write_time.hi as File_Time;
|
||||
file_info: w.By_Handle_File_Information;
|
||||
w.GetFileInformationByHandle(cast(w.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;
|
||||
last_write_time: w.Filetime;
|
||||
data: w.File_Attribute_Data;
|
||||
buf: [1024]byte;
|
||||
|
||||
assert(buf.count > name.count);
|
||||
|
||||
copy(buf[:], name as []byte);
|
||||
copy(buf[..], cast([]byte)name);
|
||||
|
||||
if win32.GetFileAttributesExA(^buf[0], win32.GetFileExInfoStandard, ^data) != 0 {
|
||||
if w.GetFileAttributesExA(^buf[0], w.GetFileExInfoStandard, ^data) != 0 {
|
||||
last_write_time = data.last_write_time;
|
||||
}
|
||||
|
||||
l := last_write_time.lo as File_Time;
|
||||
h := last_write_time.hi as File_Time;
|
||||
l := cast(File_Time)last_write_time.lo;
|
||||
h := cast(File_Time)last_write_time.hi;
|
||||
return l | h << 32;
|
||||
}
|
||||
|
||||
@@ -200,7 +200,7 @@ last_write_time_by_name :: proc(name: string) -> File_Time {
|
||||
|
||||
read_entire_file :: proc(name: string) -> ([]byte, bool) {
|
||||
buf: [300]byte;
|
||||
copy(buf[:], name as []byte);
|
||||
copy(buf[..], cast([]byte)name);
|
||||
|
||||
fd, err := open(name, O_RDONLY, 0);
|
||||
if err != ERROR_NONE {
|
||||
@@ -209,7 +209,7 @@ read_entire_file :: proc(name: string) -> ([]byte, bool) {
|
||||
defer close(fd);
|
||||
|
||||
length: i64;
|
||||
file_size_ok := win32.GetFileSizeEx(fd as win32.HANDLE, ^length) != 0;
|
||||
file_size_ok := w.GetFileSizeEx(cast(w.Handle)fd, ^length) != 0;
|
||||
if !file_size_ok {
|
||||
return nil, false;
|
||||
}
|
||||
@@ -222,23 +222,23 @@ read_entire_file :: proc(name: string) -> ([]byte, bool) {
|
||||
single_read_length: i32;
|
||||
total_read: i64;
|
||||
|
||||
while total_read < length {
|
||||
for total_read < length {
|
||||
remaining := length - total_read;
|
||||
to_read: u32;
|
||||
MAX :: 1<<32-1;
|
||||
if remaining <= MAX {
|
||||
to_read = remaining as u32;
|
||||
to_read = cast(u32)remaining;
|
||||
} else {
|
||||
to_read = MAX;
|
||||
}
|
||||
|
||||
win32.ReadFile(fd as win32.HANDLE, ^data[total_read], to_read, ^single_read_length, nil);
|
||||
w.ReadFile(cast(w.Handle)fd, ^data[total_read], to_read, ^single_read_length, nil);
|
||||
if single_read_length <= 0 {
|
||||
free(data.data);
|
||||
free(data);
|
||||
return nil, false;
|
||||
}
|
||||
|
||||
total_read += single_read_length as i64;
|
||||
total_read += cast(i64)single_read_length;
|
||||
}
|
||||
|
||||
return data, true;
|
||||
@@ -247,25 +247,34 @@ read_entire_file :: proc(name: string) -> ([]byte, bool) {
|
||||
|
||||
|
||||
heap_alloc :: proc(size: int) -> rawptr {
|
||||
return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, size);
|
||||
return w.HeapAlloc(w.GetProcessHeap(), w.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);
|
||||
if new_size == 0 {
|
||||
heap_free(ptr);
|
||||
return nil;
|
||||
}
|
||||
if ptr == nil {
|
||||
return heap_alloc(new_size);
|
||||
}
|
||||
return w.HeapReAlloc(w.GetProcessHeap(), w.HEAP_ZERO_MEMORY, ptr, new_size);
|
||||
}
|
||||
heap_free :: proc(ptr: rawptr) {
|
||||
win32.HeapFree(win32.GetProcessHeap(), 0, ptr);
|
||||
if ptr == nil {
|
||||
return;
|
||||
}
|
||||
w.HeapFree(w.GetProcessHeap(), 0, ptr);
|
||||
}
|
||||
|
||||
|
||||
exit :: proc(code: int) {
|
||||
win32.ExitProcess(code as u32);
|
||||
w.ExitProcess(cast(u32)code);
|
||||
}
|
||||
|
||||
|
||||
|
||||
current_thread_id :: proc() -> int {
|
||||
GetCurrentThreadId :: proc() -> u32 #foreign #dll_import
|
||||
return GetCurrentThreadId() as int;
|
||||
return cast(int)w.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,367 @@
|
||||
#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, 8*size_of(uint), digits, 0);
|
||||
}
|
||||
append_int :: proc(buf: []byte, i: i64, base: int) -> string {
|
||||
return append_bits(buf, cast(u64)i, base, true, 8*size_of(int), 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";
|
||||
|
||||
|
||||
is_integer_negative :: proc(u: u64, is_signed: bool, bit_size: int) -> (unsigned: u64, neg: bool) {
|
||||
neg := false;
|
||||
if is_signed {
|
||||
match bit_size {
|
||||
case 8:
|
||||
i := cast(i8)u;
|
||||
neg = i < 0;
|
||||
if neg { i = -i; }
|
||||
u = cast(u64)i;
|
||||
case 16:
|
||||
i := cast(i16)u;
|
||||
neg = i < 0;
|
||||
if neg { i = -i; }
|
||||
u = cast(u64)i;
|
||||
case 32:
|
||||
i := cast(i32)u;
|
||||
neg = i < 0;
|
||||
if neg { i = -i; }
|
||||
u = cast(u64)i;
|
||||
case 64:
|
||||
i := cast(i64)u;
|
||||
neg = i < 0;
|
||||
if neg { i = -i; }
|
||||
u = cast(u64)i;
|
||||
default:
|
||||
panic("is_integer_negative: Unknown integer size");
|
||||
}
|
||||
}
|
||||
return u, neg;
|
||||
}
|
||||
|
||||
|
||||
append_bits :: proc(buf: []byte, u: u64, base: int, is_signed: bool, bit_size: int, 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;
|
||||
|
||||
neg: bool;
|
||||
u, neg = is_integer_negative(u, is_signed, bit_size);
|
||||
|
||||
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 12: i--; a[i] = 'z';
|
||||
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;
|
||||
}
|
||||
+32
-32
@@ -2,89 +2,89 @@
|
||||
#import "atomic.odin";
|
||||
|
||||
Semaphore :: struct {
|
||||
handle: win32.HANDLE;
|
||||
_handle: win32.Handle,
|
||||
}
|
||||
|
||||
Mutex :: struct {
|
||||
semaphore: Semaphore;
|
||||
counter: i32;
|
||||
owner: i32;
|
||||
recursion: i32;
|
||||
_semaphore: Semaphore,
|
||||
_counter: i32,
|
||||
_owner: i32,
|
||||
_recursion: i32,
|
||||
}
|
||||
|
||||
current_thread_id :: proc() -> i32 {
|
||||
return win32.GetCurrentThreadId() as i32;
|
||||
return cast(i32)win32.GetCurrentThreadId();
|
||||
}
|
||||
|
||||
semaphore_init :: proc(s: ^Semaphore) {
|
||||
s.handle = win32.CreateSemaphoreA(nil, 0, 1<<31-1, nil);
|
||||
s._handle = win32.CreateSemaphoreA(nil, 0, 1<<31-1, nil);
|
||||
}
|
||||
|
||||
semaphore_destroy :: proc(s: ^Semaphore) {
|
||||
win32.CloseHandle(s.handle);
|
||||
win32.CloseHandle(s._handle);
|
||||
}
|
||||
|
||||
semaphore_post :: proc(s: ^Semaphore, count: int) {
|
||||
win32.ReleaseSemaphore(s.handle, count as i32, nil);
|
||||
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);
|
||||
win32.WaitForSingleObject(s._handle, win32.INFINITE);
|
||||
}
|
||||
|
||||
|
||||
mutex_init :: proc(m: ^Mutex) {
|
||||
atomic.store32(^m.counter, 0);
|
||||
atomic.store32(^m.owner, current_thread_id());
|
||||
semaphore_init(^m.semaphore);
|
||||
m.recursion = 0;
|
||||
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);
|
||||
semaphore_destroy(^m._semaphore);
|
||||
}
|
||||
mutex_lock :: proc(m: ^Mutex) {
|
||||
thread_id := current_thread_id();
|
||||
if atomic.fetch_add32(^m.counter, 1) > 0 {
|
||||
if thread_id != atomic.load32(^m.owner) {
|
||||
semaphore_wait(^m.semaphore);
|
||||
if atomic.fetch_add(^m._counter, 1) > 0 {
|
||||
if thread_id != atomic.load(^m._owner) {
|
||||
semaphore_wait(^m._semaphore);
|
||||
}
|
||||
}
|
||||
atomic.store32(^m.owner, thread_id);
|
||||
m.recursion += 1;
|
||||
atomic.store(^m._owner, thread_id);
|
||||
m._recursion++;
|
||||
}
|
||||
mutex_try_lock :: proc(m: ^Mutex) -> bool {
|
||||
thread_id := current_thread_id();
|
||||
if atomic.load32(^m.owner) == thread_id {
|
||||
atomic.fetch_add32(^m.counter, 1);
|
||||
if atomic.load(^m._owner) == thread_id {
|
||||
atomic.fetch_add(^m._counter, 1);
|
||||
} else {
|
||||
expected: i32 = 0;
|
||||
if atomic.load32(^m.counter) != 0 {
|
||||
if atomic.load(^m._counter) != 0 {
|
||||
return false;
|
||||
}
|
||||
if atomic.compare_exchange32(^m.counter, expected, 1) == 0 {
|
||||
if atomic.compare_exchange(^m._counter, expected, 1) == 0 {
|
||||
return false;
|
||||
}
|
||||
atomic.store32(^m.owner, thread_id);
|
||||
atomic.store(^m._owner, thread_id);
|
||||
}
|
||||
m.recursion += 1;
|
||||
m._recursion++;
|
||||
return true;
|
||||
}
|
||||
mutex_unlock :: proc(m: ^Mutex) {
|
||||
recursion: i32;
|
||||
thread_id := current_thread_id();
|
||||
assert(thread_id == atomic.load32(^m.owner));
|
||||
assert(thread_id == atomic.load(^m._owner));
|
||||
|
||||
m.recursion -= 1;
|
||||
recursion = m.recursion;
|
||||
m._recursion--;
|
||||
recursion = m._recursion;
|
||||
if recursion == 0 {
|
||||
atomic.store32(^m.owner, thread_id);
|
||||
atomic.store(^m._owner, thread_id);
|
||||
}
|
||||
|
||||
if atomic.fetch_add32(^m.counter, -1) > 1 {
|
||||
if atomic.fetch_add(^m._counter, -1) > 1 {
|
||||
if recursion == 0 {
|
||||
semaphore_release(^m.semaphore);
|
||||
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;
|
||||
Color_Ref :: u32;
|
||||
|
||||
Layer_Plane_Descriptor :: 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: Color_Ref,
|
||||
}
|
||||
|
||||
Point_Float :: struct #ordered {
|
||||
x, y: f32,
|
||||
}
|
||||
|
||||
Glyph_Metrics_Float :: struct #ordered {
|
||||
black_box_x: f32,
|
||||
black_box_y: f32,
|
||||
glyph_origin: Point_Float,
|
||||
cell_inc_x: f32,
|
||||
cell_inc_y: f32,
|
||||
}
|
||||
|
||||
Create_Context_Attribs_ARB_Type :: #type proc(hdc: Hdc, hshareContext: rawptr, attribList: ^i32) -> Hglrc;
|
||||
Choose_Pixel_Format_ARB_Type :: #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: ^Layer_Plane_Descriptor) -> 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: ^Color_Ref) -> 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: ^Color_Ref) -> 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: ^Glyph_Metrics_Float) -> Bool #foreign opengl32 "wglUseFontOutlines";
|
||||
+253
-181
@@ -1,28 +1,30 @@
|
||||
#foreign_system_library "user32" when ODIN_OS == "windows";
|
||||
#foreign_system_library "gdi32" when ODIN_OS == "windows";
|
||||
#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";
|
||||
#foreign_system_library "shell32.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: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT;
|
||||
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;
|
||||
Bool :: i32;
|
||||
Wnd_Proc :: #type proc(Hwnd, u32, Wparam, Lparam) -> Lresult #cc_c;
|
||||
|
||||
|
||||
INVALID_HANDLE_VALUE :: (-1 as int) as HANDLE;
|
||||
INVALID_HANDLE :: cast(Handle)~cast(int)0;
|
||||
|
||||
FALSE: BOOL : 0;
|
||||
TRUE: BOOL : 1;
|
||||
FALSE: Bool : 0;
|
||||
TRUE: Bool : 1;
|
||||
|
||||
CS_VREDRAW :: 0x0001;
|
||||
CS_HREDRAW :: 0x0002;
|
||||
@@ -38,15 +40,23 @@ 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;
|
||||
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 :: 1 as HBRUSH;
|
||||
COLOR_BACKGROUND :: cast(Hbrush)(cast(int)1);
|
||||
BLACK_BRUSH :: 4;
|
||||
|
||||
SM_CXSCREEN :: 0;
|
||||
@@ -55,62 +65,68 @@ SM_CYSCREEN :: 1;
|
||||
SW_SHOW :: 5;
|
||||
|
||||
|
||||
POINT :: struct #ordered {
|
||||
x, y: i32;
|
||||
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;
|
||||
WndClassExA :: struct #ordered {
|
||||
size, style: u32,
|
||||
wnd_proc: Wnd_Proc,
|
||||
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;
|
||||
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;
|
||||
Rect :: struct #ordered {
|
||||
left: i32,
|
||||
top: i32,
|
||||
right: i32,
|
||||
bottom: i32,
|
||||
}
|
||||
|
||||
FILETIME :: struct #ordered {
|
||||
lo, hi: u32;
|
||||
Filetime :: struct #ordered {
|
||||
lo, hi: u32,
|
||||
}
|
||||
|
||||
BY_HANDLE_FILE_INFORMATION :: struct #ordered {
|
||||
file_attributes: 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;
|
||||
last_write_time: Filetime,
|
||||
volume_serial_number,
|
||||
file_size_high,
|
||||
file_size_low,
|
||||
number_of_links,
|
||||
file_index_high,
|
||||
file_index_low: u32;
|
||||
file_index_low: u32,
|
||||
}
|
||||
|
||||
FILE_ATTRIBUTE_DATA :: struct #ordered {
|
||||
file_attributes: u32;
|
||||
File_Attribute_Data :: struct #ordered {
|
||||
file_attributes: u32,
|
||||
creation_time,
|
||||
last_access_time,
|
||||
last_write_time: FILETIME;
|
||||
last_write_time: Filetime,
|
||||
file_size_high,
|
||||
file_size_low: u32;
|
||||
file_size_low: u32,
|
||||
}
|
||||
|
||||
GET_FILEEX_INFO_LEVELS :: i32;
|
||||
@@ -118,43 +134,46 @@ GET_FILEEX_INFO_LEVELS :: 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
|
||||
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 #dll_import
|
||||
QueryPerformanceCounter :: proc(result: ^i64) -> i32 #foreign #dll_import
|
||||
QueryPerformanceFrequency :: proc(result: ^i64) -> i32 #foreign kernel32;
|
||||
QueryPerformanceCounter :: proc(result: ^i64) -> i32 #foreign kernel32;
|
||||
|
||||
Sleep :: proc(ms: i32) -> i32 #foreign #dll_import
|
||||
Sleep :: proc(ms: i32) -> i32 #foreign kernel32;
|
||||
|
||||
OutputDebugStringA :: proc(c_str: ^u8) #foreign #dll_import
|
||||
OutputDebugStringA :: proc(c_str: ^u8) #foreign kernel32;
|
||||
|
||||
|
||||
RegisterClassExA :: proc(wc: ^WNDCLASSEXA) -> ATOM #foreign #dll_import
|
||||
RegisterClassExA :: proc(wc: ^WndClassExA) -> i16 #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 #dll_import
|
||||
parent: Hwnd, menu: Hmenu, instance: Hinstance,
|
||||
param: rawptr) -> Hwnd #foreign user32;
|
||||
|
||||
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
|
||||
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 #dll_import
|
||||
DefWindowProcA :: proc(hwnd: Hwnd, msg: u32, wparam: Wparam, lparam: Lparam) -> Lresult #foreign user32;
|
||||
|
||||
AdjustWindowRect :: proc(rect: ^RECT, style: u32, menu: BOOL) -> BOOL #foreign #dll_import
|
||||
GetActiveWindow :: proc() -> HWND #foreign #dll_import
|
||||
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 {
|
||||
@@ -163,28 +182,36 @@ GetQueryPerformanceFrequency :: proc() -> i64 {
|
||||
return r;
|
||||
}
|
||||
|
||||
GetCommandLineA :: proc() -> ^u8 #foreign #dll_import
|
||||
GetSystemMetrics :: proc(index: i32) -> i32 #foreign #dll_import
|
||||
GetCurrentThreadId :: proc() -> u32 #foreign #dll_import
|
||||
GetCommandLineA :: proc() -> ^u8 #foreign kernel32;
|
||||
GetCommandLineW :: proc() -> ^u16 #foreign kernel32;
|
||||
GetSystemMetrics :: proc(index: i32) -> i32 #foreign kernel32;
|
||||
GetCurrentThreadId :: proc() -> u32 #foreign kernel32;
|
||||
CommandLineToArgvW :: proc(cmd_list: ^u16, num_args: ^i32) -> ^^u16 #foreign shell32;
|
||||
|
||||
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 #dll_import
|
||||
GetStdHandle :: proc(h: i32) -> HANDLE #foreign #dll_import
|
||||
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 #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
|
||||
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 #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
|
||||
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 #dll_import
|
||||
SetFilePointer :: proc(file_handle: HANDLE, distance_to_move: i32, distance_to_move_high: ^i32, move_method: u32) -> u32 #foreign #dll_import
|
||||
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 #dll_import
|
||||
SetHandleInformation :: proc(obj: Handle, mask, flags: u32) -> Bool #foreign kernel32;
|
||||
|
||||
HANDLE_FLAG_INHERIT :: 1;
|
||||
HANDLE_FLAG_PROTECT_FROM_CLOSE :: 2;
|
||||
@@ -217,13 +244,13 @@ TRUNCATE_EXISTING :: 5;
|
||||
FILE_ATTRIBUTE_READONLY :: 0x00000001;
|
||||
FILE_ATTRIBUTE_HIDDEN :: 0x00000002;
|
||||
FILE_ATTRIBUTE_SYSTEM :: 0x00000004;
|
||||
FILE_ATTRIBUTE_DIRECTORY :: 0x00000010;
|
||||
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_REPARSE_Point :: 0x00000400;
|
||||
FILE_ATTRIBUTE_COMPRESSED :: 0x00000800;
|
||||
FILE_ATTRIBUTE_OFFLINE :: 0x00001000;
|
||||
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED :: 0x00002000;
|
||||
@@ -233,95 +260,153 @@ FILE_TYPE_DISK :: 0x0001;
|
||||
FILE_TYPE_CHAR :: 0x0002;
|
||||
FILE_TYPE_PIPE :: 0x0003;
|
||||
|
||||
INVALID_SET_FILE_POINTER :: ~(0 as u32);
|
||||
INVALID_SET_FILE_POINTER :: ~cast(u32)0;
|
||||
|
||||
|
||||
|
||||
|
||||
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
|
||||
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;
|
||||
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 #dll_import
|
||||
ReleaseSemaphore :: proc(semaphore: HANDLE, release_count: i32, previous_count: ^i32) -> BOOL #foreign #dll_import
|
||||
WaitForSingleObject :: proc(handle: HANDLE, milliseconds: u32) -> u32 #foreign #dll_import
|
||||
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
|
||||
InterlockedExchange :: proc(dst: ^i32, desired: i32) -> i32 #foreign
|
||||
InterlockedExchangeAdd :: proc(dst: ^i32, desired: i32) -> i32 #foreign
|
||||
InterlockedAnd :: proc(dst: ^i32, desired: i32) -> i32 #foreign
|
||||
InterlockedOr :: proc(dst: ^i32, desired: i32) -> i32 #foreign
|
||||
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
|
||||
InterlockedExchange64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign
|
||||
InterlockedExchangeAdd64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign
|
||||
InterlockedAnd64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign
|
||||
InterlockedOr64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign
|
||||
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
|
||||
ReadWriteBarrier :: proc() #foreign
|
||||
WriteBarrier :: proc() #foreign
|
||||
ReadBarrier :: proc() #foreign
|
||||
mm_pause :: proc() #foreign kernel32 "_mm_pause";
|
||||
ReadWriteBarrier :: proc() #foreign kernel32;
|
||||
WriteBarrier :: proc() #foreign kernel32;
|
||||
ReadBarrier :: proc() #foreign kernel32;
|
||||
|
||||
|
||||
// GDI
|
||||
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;
|
||||
|
||||
|
||||
|
||||
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;
|
||||
|
||||
|
||||
Monitor_Info :: struct #ordered {
|
||||
size: u32,
|
||||
monitor: Rect,
|
||||
work: Rect,
|
||||
flags: u32,
|
||||
}
|
||||
BITMAPINFO :: struct #ordered {
|
||||
using header: BITMAPINFOHEADER;
|
||||
colors: [1]RGBQUAD;
|
||||
|
||||
Window_Placement :: struct #ordered {
|
||||
length: u32,
|
||||
flags: u32,
|
||||
show_cmd: u32,
|
||||
min_pos: Point,
|
||||
max_pos: Point,
|
||||
normal_pos: Rect,
|
||||
}
|
||||
|
||||
GetMonitorInfoA :: proc(monitor: Hmonitor, mi: ^Monitor_Info) -> 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: ^Window_Placement) -> Bool #foreign user32;
|
||||
SetWindowPlacement :: proc(wnd: Hwnd, wndpl: ^Window_Placement) -> 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; }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Bitmap_Info_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,
|
||||
}
|
||||
Bitmap_Info :: struct #ordered {
|
||||
using header: Bitmap_Info_Header,
|
||||
colors: [1]Rgb_Quad,
|
||||
}
|
||||
|
||||
|
||||
RGBQUAD :: struct #ordered {
|
||||
blue, green, red, reserved: byte;
|
||||
}
|
||||
Rgb_Quad :: struct #ordered { blue, green, red, reserved: byte }
|
||||
|
||||
BI_RGB :: 0;
|
||||
DIB_RGB_COLORS :: 0x00;
|
||||
SRCCOPY: u32 : 0x00cc0020;
|
||||
|
||||
|
||||
StretchDIBits :: proc (hdc: HDC,
|
||||
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,
|
||||
bits: rawptr, bits_info: ^Bitmap_Info,
|
||||
usage: u32,
|
||||
rop: u32) -> i32 #foreign #dll_import
|
||||
rop: u32) -> i32 #foreign gdi32;
|
||||
|
||||
|
||||
|
||||
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
|
||||
|
||||
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;
|
||||
@@ -346,15 +431,11 @@ PFD_DEPTH_DONTCARE :: 0x20000000;
|
||||
PFD_DOUBLEBUFFER_DONTCARE :: 0x40000000;
|
||||
PFD_STEREO_DONTCARE :: 0x80000000;
|
||||
|
||||
HGLRC :: HANDLE;
|
||||
PROC :: type proc() #cc_c;
|
||||
wglCreateContextAttribsARBType :: proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC;
|
||||
|
||||
|
||||
PIXELFORMATDESCRIPTOR :: struct #ordered {
|
||||
size,
|
||||
version,
|
||||
flags: u32;
|
||||
flags: u32,
|
||||
|
||||
pixel_type,
|
||||
color_bits,
|
||||
@@ -375,36 +456,27 @@ PIXELFORMATDESCRIPTOR :: struct #ordered {
|
||||
stencil_bits,
|
||||
aux_buffers,
|
||||
layer_type,
|
||||
reserved: byte;
|
||||
reserved: byte,
|
||||
|
||||
layer_mask,
|
||||
visible_mask,
|
||||
damage_mask: u32;
|
||||
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
|
||||
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 #dll_import
|
||||
GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign #dll_import
|
||||
|
||||
is_key_down :: proc(key: Key_Code) -> bool #inline { return GetAsyncKeyState(key as i32) < 0; }
|
||||
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,
|
||||
@@ -541,7 +613,7 @@ Key_Code :: enum i32 {
|
||||
RCONTROL = 0xA3,
|
||||
LMENU = 0xA4,
|
||||
RMENU = 0xA5,
|
||||
PROCESSKEY = 0xE5,
|
||||
ProcESSKEY = 0xE5,
|
||||
ATTN = 0xF6,
|
||||
CRSEL = 0xF7,
|
||||
EXSEL = 0xF8,
|
||||
|
||||
+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;
|
||||
}
|
||||
+107
-53
@@ -1,18 +1,36 @@
|
||||
RUNE_ERROR :: '\ufffd';
|
||||
RUNE_SELF :: 0x80;
|
||||
RUNE_BOM :: 0xfeff;
|
||||
RUNE_EOF :: ~(0 as rune);
|
||||
RUNE_EOF :: ~cast(rune)0;
|
||||
MAX_RUNE :: '\U0010ffff';
|
||||
UTF_MAX :: 4;
|
||||
|
||||
SURROGATE_MIN :: 0xd800;
|
||||
SURROGATE_MAX :: 0xdfff;
|
||||
|
||||
Accept_Range :: struct {
|
||||
lo, hi: u8;
|
||||
}
|
||||
T1 :: 0b0000_0000;
|
||||
TX :: 0b1000_0000;
|
||||
T2 :: 0b1100_0000;
|
||||
T3 :: 0b1110_0000;
|
||||
T4 :: 0b1111_0000;
|
||||
T5 :: 0b1111_1000;
|
||||
|
||||
accept_ranges := [5]Accept_Range{
|
||||
MASKX :: 0b0011_1111;
|
||||
MASK2 :: 0b0001_1111;
|
||||
MASK3 :: 0b0000_1111;
|
||||
MASK4 :: 0b0000_0111;
|
||||
|
||||
RUNE1_MAX :: 1<<7 - 1;
|
||||
RUNE2_MAX :: 1<<11 - 1;
|
||||
RUNE3_MAX :: 1<<16 - 1;
|
||||
|
||||
// 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},
|
||||
{0xa0, 0xbf},
|
||||
{0x80, 0x9f},
|
||||
@@ -20,7 +38,7 @@ accept_ranges := [5]Accept_Range{
|
||||
{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, // 0x10-0x1f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f
|
||||
@@ -42,15 +60,15 @@ accept_sizes := [256]byte{
|
||||
|
||||
encode_rune :: proc(r: rune) -> ([4]byte, int) {
|
||||
buf: [4]byte;
|
||||
i := r as u32;
|
||||
i := cast(u32)r;
|
||||
mask: byte : 0x3f;
|
||||
if i <= 1<<7-1 {
|
||||
buf[0] = r as byte;
|
||||
buf[0] = cast(byte)r;
|
||||
return buf, 1;
|
||||
}
|
||||
if i <= 1<<11-1 {
|
||||
buf[0] = 0xc0 | (r>>6) as byte;
|
||||
buf[1] = 0x80 | (r) as byte & mask;
|
||||
buf[0] = 0xc0 | cast(byte)(r>>6);
|
||||
buf[1] = 0x80 | cast(byte)r & mask;
|
||||
return buf, 2;
|
||||
}
|
||||
|
||||
@@ -61,64 +79,98 @@ encode_rune :: proc(r: rune) -> ([4]byte, int) {
|
||||
}
|
||||
|
||||
if i <= 1<<16-1 {
|
||||
buf[0] = 0xe0 | (r>>12) as byte;
|
||||
buf[1] = 0x80 | (r>>6) as byte & mask;
|
||||
buf[2] = 0x80 | (r) as byte & mask;
|
||||
buf[0] = 0xe0 | cast(byte)(r>>12);
|
||||
buf[1] = 0x80 | cast(byte)(r>>6) & mask;
|
||||
buf[2] = 0x80 | cast(byte)r & mask;
|
||||
return buf, 3;
|
||||
}
|
||||
|
||||
buf[0] = 0xf0 | (r>>18) as byte;
|
||||
buf[1] = 0x80 | (r>>12) as byte & mask;
|
||||
buf[2] = 0x80 | (r>>6) as byte & mask;
|
||||
buf[3] = 0x80 | (r) as byte & mask;
|
||||
buf[0] = 0xf0 | cast(byte)(r>>18);
|
||||
buf[1] = 0x80 | cast(byte)(r>>12) & mask;
|
||||
buf[2] = 0x80 | cast(byte)(r>>6) & mask;
|
||||
buf[3] = 0x80 | cast(byte)r & mask;
|
||||
return buf, 4;
|
||||
}
|
||||
|
||||
decode_rune :: proc(s: string) -> (rune, int) {
|
||||
decode_rune :: proc(s: string) -> (rune, int) #inline { return decode_rune(cast([]byte)s); }
|
||||
decode_rune :: proc(s: []byte) -> (rune, int) {
|
||||
n := s.count;
|
||||
if n < 1 {
|
||||
return RUNE_ERROR, 0;
|
||||
}
|
||||
b0 := s[0];
|
||||
x := accept_sizes[b0];
|
||||
if x >= 0xf0 {
|
||||
mask := (x as rune << 31) >> 31; // all zeros or all ones
|
||||
return (b0 as rune) &~ mask | RUNE_ERROR&mask, 1;
|
||||
s0 := s[0];
|
||||
x := accept_sizes[s0];
|
||||
if x >= 0xF0 {
|
||||
mask := cast(rune)(x) << 31 >> 31; // NOTE(bill): Create 0x0000 or 0xffff.
|
||||
return cast(rune)(s[0])&~mask | RUNE_ERROR&mask, 1;
|
||||
}
|
||||
size := x & 7;
|
||||
ar := accept_ranges[x>>4];
|
||||
if n < size as int {
|
||||
sz := x & 7;
|
||||
accept := accept_ranges[x>>4];
|
||||
if n < cast(int)sz {
|
||||
return RUNE_ERROR, 1;
|
||||
}
|
||||
b1 := s[1];
|
||||
if b1 < ar.lo || ar.hi < b1 {
|
||||
if b1 < accept.lo || accept.hi < b1 {
|
||||
return RUNE_ERROR, 1;
|
||||
}
|
||||
|
||||
MASK_X :: 0b00111111;
|
||||
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;
|
||||
if sz == 2 {
|
||||
return cast(rune)(s0&MASK2)<<6 | cast(rune)(b1&MASKX), 2;
|
||||
}
|
||||
b2 := s[2];
|
||||
if b2 < 0x80 || 0xbf < b2 {
|
||||
if b2 < LOCB || HICB < b2 {
|
||||
return RUNE_ERROR, 1;
|
||||
}
|
||||
if size == 3 {
|
||||
return (b0&MASK_3) as rune <<12 | (b1&MASK_X) as rune <<6 | (b2&MASK_X) as rune, 3;
|
||||
if sz == 3 {
|
||||
return cast(rune)(s0&MASK3)<<12 | cast(rune)(b1&MASKX)<<6 | cast(rune)(b2&MASKX), 3;
|
||||
}
|
||||
b3 := s[3];
|
||||
if b3 < 0x80 || 0xbf < b3 {
|
||||
if b3 < LOCB || HICB < b3 {
|
||||
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 {
|
||||
if r < 0 {
|
||||
return false;
|
||||
@@ -132,18 +184,17 @@ valid_rune :: proc(r: rune) -> bool {
|
||||
|
||||
valid_string :: proc(s: string) -> bool {
|
||||
n := s.count;
|
||||
i := 0;
|
||||
while i < n {
|
||||
for i := 0; i < n; {
|
||||
si := s[i];
|
||||
if si < RUNE_SELF { // ascii
|
||||
i += 1;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
x := accept_sizes[si];
|
||||
if x == 0xf1 {
|
||||
return false;
|
||||
}
|
||||
size := (x & 7) as int;
|
||||
size := cast(int)(x & 7);
|
||||
if i+size > n {
|
||||
return false;
|
||||
}
|
||||
@@ -164,25 +215,28 @@ valid_string :: proc(s: string) -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
rune_count :: proc(s: string) -> int {
|
||||
rune_start :: proc(b: byte) -> bool #inline { return b&0xc0 != 0x80; }
|
||||
|
||||
rune_count :: proc(s: string) -> int #inline { return rune_count(cast([]byte)s); }
|
||||
rune_count :: proc(s: []byte) -> int {
|
||||
count := 0;
|
||||
n := s.count;
|
||||
i := 0;
|
||||
while i < n {
|
||||
defer count += 1;
|
||||
|
||||
for i := 0; i < n; {
|
||||
defer count++;
|
||||
si := s[i];
|
||||
if si < RUNE_SELF { // ascii
|
||||
i += 1;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
x := accept_sizes[si];
|
||||
if x == 0xf1 {
|
||||
i += 1;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
size := (x & 7) as int;
|
||||
size := cast(int)(x & 7);
|
||||
if i+size > n {
|
||||
i += 1;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
ar := accept_ranges[x>>4];
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
@echo off
|
||||
setlocal EnableDelayedExpansion
|
||||
|
||||
set file_input=%1
|
||||
set name=%1
|
||||
FOR %%f IN (name) do (
|
||||
FOR %%g in (!%%f!) do set "%%f=%%~ng"
|
||||
)
|
||||
|
||||
call clang -O2 -c %file_input% -o %name%.o ^
|
||||
&& call ar %name%.o -rcs %name%.lib
|
||||
|
Before Width: | Height: | Size: 246 KiB After Width: | Height: | Size: 246 KiB |
@@ -1,4 +0,0 @@
|
||||
@echo off
|
||||
|
||||
|
||||
rem call clang -c -emit-llvm -DGB_IMPLEMENTATION -DGB_DEF=GB_DLL_EXPORT ..\src\gb\gb.h
|
||||
+2
-8
@@ -87,14 +87,8 @@ void array__set_capacity(void *ptr, isize capacity, isize element_size) {
|
||||
x->count = capacity;
|
||||
}
|
||||
|
||||
{
|
||||
// TODO(bill): Resize rather than copy and delete
|
||||
void *new_data = gb_alloc(x->allocator, element_size*capacity);
|
||||
gb_memmove(new_data, x->e, element_size*x->count);
|
||||
gb_free(x->allocator, x->e);
|
||||
x->capacity = capacity;
|
||||
x->e = new_data;
|
||||
}
|
||||
x->e = gb_resize(x->allocator, x->e, element_size*x->capacity, element_size*capacity);
|
||||
x->capacity = capacity;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,17 +1,27 @@
|
||||
// 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
|
||||
|
||||
i64 word_size;
|
||||
i64 max_align;
|
||||
// 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
|
||||
@@ -22,6 +32,7 @@ typedef struct BuildContext {
|
||||
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;
|
||||
@@ -71,6 +82,64 @@ String odin_root_dir(void) {
|
||||
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);
|
||||
@@ -86,6 +155,17 @@ String path_to_fullpath(gbAllocator a, String s) {
|
||||
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) {
|
||||
@@ -123,37 +203,23 @@ String get_fullpath_core(gbAllocator a, String path) {
|
||||
return res;
|
||||
}
|
||||
|
||||
String get_filepath_extension(String path) {
|
||||
isize dot = 0;
|
||||
bool seen_slash = false;
|
||||
for (isize i = path.len-1; i >= 0; i--) {
|
||||
u8 c = path.text[i];
|
||||
if (c == '/' || c == '\\') {
|
||||
seen_slash = true;
|
||||
}
|
||||
|
||||
if (c == '.') {
|
||||
if (seen_slash) {
|
||||
return str_lit("");
|
||||
}
|
||||
|
||||
dot = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return make_string(path.text, dot);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void init_build_context(BuildContext *bc) {
|
||||
void init_build_context(void) {
|
||||
BuildContext *bc = &build_context;
|
||||
bc->ODIN_VENDOR = str_lit("odin");
|
||||
bc->ODIN_VERSION = str_lit("0.0.5d");
|
||||
bc->ODIN_VERSION = str_lit("0.1.3");
|
||||
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
|
||||
@@ -12,6 +12,7 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
|
||||
gbString expr_str = expr_to_string(operand->expr);
|
||||
|
||||
// TODO(bill): is this a good enough error message?
|
||||
// TODO(bill): Actually allow built in procedures to be passed around and thus be created on use
|
||||
error_node(operand->expr,
|
||||
"Cannot assign builtin procedure `%s` in %.*s",
|
||||
expr_str,
|
||||
@@ -40,6 +41,7 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
|
||||
}
|
||||
t = default_type(t);
|
||||
}
|
||||
GB_ASSERT(is_type_typed(t));
|
||||
e->type = t;
|
||||
}
|
||||
|
||||
@@ -60,23 +62,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
|
||||
// an extra allocation
|
||||
Array(Operand) operands;
|
||||
ArrayOperand operands = {0};
|
||||
array_init_reserve(&operands, c->tmp_allocator, 2*lhs_count);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
check_unpack_arguments(c, lhs_count, &operands, inits, true);
|
||||
|
||||
isize rhs_count = operands.count;
|
||||
for_array(i, operands) {
|
||||
@@ -85,100 +73,17 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArra
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
isize max = gb_min(lhs_count, rhs_count);
|
||||
for (isize i = 0; i < max; i++) {
|
||||
check_init_variable(c, lhs[i], &operands.e[i], context_name);
|
||||
}
|
||||
|
||||
if (rhs_count > 0 && lhs_count != rhs_count) {
|
||||
error(lhs[0]->token, "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (lhs[0]->kind == Entity_Variable &&
|
||||
lhs[0]->Variable.is_let) {
|
||||
if (lhs_count != rhs_count) {
|
||||
error(lhs[0]->token, "`let` variables must be initialized, `%td` = `%td`", lhs_count, rhs_count);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
gb_temp_arena_memory_end(tmp);
|
||||
}
|
||||
|
||||
void check_var_decl_node(Checker *c, AstNodeValueDecl *vd) {
|
||||
GB_ASSERT(vd->is_var == true);
|
||||
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_node(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);
|
||||
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_arity_match(c, vd);
|
||||
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) {
|
||||
if (operand->mode == Addressing_Invalid ||
|
||||
operand->type == t_invalid ||
|
||||
@@ -249,9 +154,6 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
|
||||
}
|
||||
e->flags |= EntityFlag_Visited;
|
||||
|
||||
c->context.iota = e->Constant.value;
|
||||
e->Constant.value = (ExactValue){0};
|
||||
|
||||
if (type_expr) {
|
||||
Type *t = check_type(c, type_expr);
|
||||
if (!is_type_constant_type(t)) {
|
||||
@@ -259,7 +161,6 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
|
||||
error_node(type_expr, "Invalid constant type `%s`", str);
|
||||
gb_string_free(str);
|
||||
e->type = t_invalid;
|
||||
c->context.iota = (ExactValue){0};
|
||||
return;
|
||||
}
|
||||
e->type = t;
|
||||
@@ -270,9 +171,6 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
|
||||
check_expr_or_type(c, &operand, init);
|
||||
}
|
||||
if (operand.mode == Addressing_Type) {
|
||||
c->context.iota = (ExactValue){0};
|
||||
|
||||
e->Constant.value = (ExactValue){0};
|
||||
e->kind = Entity_TypeName;
|
||||
|
||||
DeclInfo *d = c->context.decl;
|
||||
@@ -282,10 +180,10 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
|
||||
}
|
||||
|
||||
check_init_constant(c, e, &operand);
|
||||
c->context.iota = (ExactValue){0};
|
||||
|
||||
if (operand.mode == Addressing_Invalid) {
|
||||
error(e->token, "Illegal cyclic declaration");
|
||||
if (operand.mode == Addressing_Invalid ||
|
||||
base_type(operand.type) == t_invalid) {
|
||||
error(e->token, "Invalid declaration type");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -379,11 +277,6 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
|
||||
error_node(pd->body, "A procedure tagged as `#foreign` cannot have a body");
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
GB_ASSERT(pd->body->kind == AstNode_BlockStmt);
|
||||
@@ -391,12 +284,35 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
|
||||
}
|
||||
|
||||
if (is_foreign) {
|
||||
MapEntity *fp = &c->info.foreign_procs;
|
||||
MapEntity *fp = &c->info.foreigns;
|
||||
String name = e->token.string;
|
||||
if (pd->foreign_name.len > 0) {
|
||||
name = pd->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;
|
||||
|
||||
@@ -423,7 +339,7 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
|
||||
}
|
||||
|
||||
if (is_link_name || is_export) {
|
||||
MapEntity *fp = &c->info.foreign_procs;
|
||||
MapEntity *fp = &c->info.foreigns;
|
||||
|
||||
e->Procedure.link_name = name;
|
||||
|
||||
@@ -487,6 +403,56 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
|
||||
}
|
||||
|
||||
|
||||
void check_alias_decl(Checker *c, Entity *e, AstNode *expr) {
|
||||
GB_ASSERT(e->type == NULL);
|
||||
GB_ASSERT(e->kind == Entity_Alias);
|
||||
|
||||
if (e->flags & EntityFlag_Visited) {
|
||||
e->type = t_invalid;
|
||||
return;
|
||||
}
|
||||
e->flags |= EntityFlag_Visited;
|
||||
e->type = t_invalid;
|
||||
|
||||
expr = unparen_expr(expr);
|
||||
|
||||
if (expr->kind == AstNode_Alias) {
|
||||
error_node(expr, "#alias of an #alias is not allowed");
|
||||
return;
|
||||
}
|
||||
|
||||
if (expr->kind == AstNode_Ident) {
|
||||
Operand o = {0};
|
||||
Entity *f = check_ident(c, &o, expr, NULL, NULL, true);
|
||||
if (f != NULL) {
|
||||
e->Alias.original = f;
|
||||
e->type = f->type;
|
||||
}
|
||||
return;
|
||||
} else if (expr->kind == AstNode_SelectorExpr) {
|
||||
Operand o = {0};
|
||||
Entity *f = check_selector(c, &o, expr, NULL);
|
||||
if (f != NULL) {
|
||||
e->Alias.original = f;
|
||||
e->type = f->type;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Operand o = {0};
|
||||
check_expr_or_type(c, &o, expr);
|
||||
if (o.mode == Addressing_Invalid) {
|
||||
return;
|
||||
}
|
||||
switch (o.mode) {
|
||||
case Addressing_Type:
|
||||
e->type = o.type;
|
||||
break;
|
||||
default:
|
||||
error_node(expr, "#alias declarations only allow types");
|
||||
}
|
||||
}
|
||||
|
||||
void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
|
||||
if (e->type != NULL) {
|
||||
return;
|
||||
@@ -522,6 +488,9 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
|
||||
case Entity_Procedure:
|
||||
check_proc_lit(c, e, d);
|
||||
break;
|
||||
case Entity_Alias:
|
||||
check_alias_decl(c, e, d->init_expr);
|
||||
break;
|
||||
}
|
||||
|
||||
c->context = prev;
|
||||
@@ -532,9 +501,19 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
|
||||
void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body) {
|
||||
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;
|
||||
c->context.scope = decl->scope;
|
||||
c->context.decl = decl;
|
||||
c->context.proc_name = proc_name;
|
||||
|
||||
|
||||
GB_ASSERT(type->kind == Type_Proc);
|
||||
if (type->Proc.param_count > 0) {
|
||||
@@ -545,6 +524,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
|
||||
if (!(e->flags & EntityFlag_Anonymous)) {
|
||||
continue;
|
||||
}
|
||||
bool is_immutable = e->Variable.is_immutable;
|
||||
String name = e->token.string;
|
||||
Type *t = base_type(type_deref(e->type));
|
||||
if (is_type_struct(t) || is_type_raw_union(t)) {
|
||||
@@ -554,6 +534,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
|
||||
Entity *f = (*found)->elements.entries.e[i].value;
|
||||
if (f->kind == Entity_Variable) {
|
||||
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);
|
||||
if (prev != NULL) {
|
||||
error(e->token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(prev->token.string));
|
||||
+2511
-1603
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -6,12 +6,24 @@ gbAllocator heap_allocator(void) {
|
||||
return gb_heap_allocator();
|
||||
}
|
||||
|
||||
#include "unicode.c"
|
||||
#include "string.c"
|
||||
#include "array.c"
|
||||
|
||||
gb_global String global_module_path = {0};
|
||||
gb_global bool global_module_path_set = false;
|
||||
|
||||
gb_global gbScratchMemory scratch_memory = {0};
|
||||
|
||||
void init_scratch_memory(isize size) {
|
||||
void *memory = gb_alloc(heap_allocator(), size);
|
||||
gb_scratch_memory_init(&scratch_memory, memory, size);
|
||||
}
|
||||
|
||||
gbAllocator scratch_allocator(void) {
|
||||
return gb_scratch_allocator(&scratch_memory);
|
||||
}
|
||||
|
||||
|
||||
i64 next_pow2(i64 n) {
|
||||
if (n <= 0) {
|
||||
@@ -119,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_PROC map_string_
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
typedef struct Scope Scope;
|
||||
typedef struct Checker Checker;
|
||||
typedef struct Type Type;
|
||||
typedef enum BuiltinProcId BuiltinProcId;
|
||||
typedef enum ImplicitValueId ImplicitValueId;
|
||||
// typedef enum BuiltinProcId BuiltinProcId;
|
||||
|
||||
|
||||
#define ENTITY_KINDS \
|
||||
ENTITY_KIND(Invalid) \
|
||||
@@ -12,14 +12,16 @@ typedef enum ImplicitValueId ImplicitValueId;
|
||||
ENTITY_KIND(Procedure) \
|
||||
ENTITY_KIND(Builtin) \
|
||||
ENTITY_KIND(ImportName) \
|
||||
ENTITY_KIND(LibraryName) \
|
||||
ENTITY_KIND(Alias) \
|
||||
ENTITY_KIND(Nil) \
|
||||
ENTITY_KIND(ImplicitValue) \
|
||||
ENTITY_KIND(Count)
|
||||
ENTITY_KIND(Label)
|
||||
|
||||
typedef enum EntityKind {
|
||||
#define ENTITY_KIND(k) GB_JOIN2(Entity_, k),
|
||||
ENTITY_KINDS
|
||||
#undef ENTITY_KIND
|
||||
Entity_Count,
|
||||
} EntityKind;
|
||||
|
||||
String const entity_strings[] = {
|
||||
@@ -35,8 +37,20 @@ typedef enum EntityFlag {
|
||||
EntityFlag_Field = 1<<3,
|
||||
EntityFlag_Param = 1<<4,
|
||||
EntityFlag_VectorElem = 1<<5,
|
||||
EntityFlag_Ellipsis = 1<<6,
|
||||
EntityFlag_NoAlias = 1<<7,
|
||||
EntityFlag_TypeField = 1<<8,
|
||||
} 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;
|
||||
struct Entity {
|
||||
EntityKind kind;
|
||||
@@ -58,16 +72,19 @@ struct Entity {
|
||||
i32 field_index;
|
||||
i32 field_src_index;
|
||||
bool is_immutable;
|
||||
bool is_thread_local;
|
||||
} Variable;
|
||||
i32 TypeName;
|
||||
struct {
|
||||
bool is_foreign;
|
||||
String foreign_name;
|
||||
String link_name;
|
||||
u64 tags;
|
||||
bool is_foreign;
|
||||
String foreign_name;
|
||||
Entity * foreign_library;
|
||||
String link_name;
|
||||
u64 tags;
|
||||
OverloadKind overload_kind;
|
||||
} Procedure;
|
||||
struct {
|
||||
BuiltinProcId id;
|
||||
i32 id;
|
||||
} Builtin;
|
||||
struct {
|
||||
String path;
|
||||
@@ -75,17 +92,48 @@ struct Entity {
|
||||
Scope *scope;
|
||||
bool used;
|
||||
} ImportName;
|
||||
struct {
|
||||
String path;
|
||||
String name;
|
||||
bool used;
|
||||
} LibraryName;
|
||||
struct {
|
||||
Entity *original;
|
||||
} Alias;
|
||||
i32 Nil;
|
||||
struct {
|
||||
// TODO(bill): Should this be a user-level construct rather than compiler-level?
|
||||
ImplicitValueId id;
|
||||
Entity * backing;
|
||||
} ImplicitValue;
|
||||
String name;
|
||||
AstNode *node;
|
||||
} Label;
|
||||
};
|
||||
};
|
||||
|
||||
gb_global Entity *e_context = NULL;
|
||||
|
||||
Entity *e_iota = 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) {
|
||||
@@ -97,13 +145,15 @@ Entity *alloc_entity(gbAllocator a, EntityKind kind, Scope *scope, Token token,
|
||||
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->Variable.is_immutable = is_immutable;
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_using_variable(gbAllocator a, Entity *parent, Token token, Type *type) {
|
||||
GB_ASSERT(parent != NULL);
|
||||
token.pos = parent->token.pos;
|
||||
Entity *entity = alloc_entity(a, Entity_Variable, parent->scope, token, type);
|
||||
entity->using_parent = parent;
|
||||
entity->flags |= EntityFlag_Anonymous;
|
||||
@@ -122,16 +172,16 @@ Entity *make_entity_type_name(gbAllocator a, Scope *scope, Token token, Type *ty
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_param(gbAllocator a, Scope *scope, Token token, Type *type, bool anonymous) {
|
||||
Entity *entity = make_entity_variable(a, scope, token, type);
|
||||
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, is_immutable);
|
||||
entity->flags |= EntityFlag_Used;
|
||||
entity->flags |= EntityFlag_Anonymous*(anonymous != 0);
|
||||
if (anonymous) entity->flags |= EntityFlag_Anonymous;
|
||||
entity->flags |= EntityFlag_Param;
|
||||
return entity;
|
||||
}
|
||||
|
||||
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_index = field_src_index;
|
||||
entity->flags |= EntityFlag_Field;
|
||||
@@ -140,7 +190,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 *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_index = field_src_index;
|
||||
entity->flags |= EntityFlag_Field;
|
||||
@@ -154,7 +204,7 @@ Entity *make_entity_procedure(gbAllocator a, Scope *scope, Token token, Type *si
|
||||
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->Builtin.id = id;
|
||||
return entity;
|
||||
@@ -169,22 +219,38 @@ Entity *make_entity_import_name(gbAllocator a, Scope *scope, Token token, Type *
|
||||
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_alias(gbAllocator a, Scope *scope, Token token, Type *type,
|
||||
Entity *original) {
|
||||
Entity *entity = alloc_entity(a, Entity_Alias, scope, token, type);
|
||||
entity->Alias.original = original;
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_nil(gbAllocator a, String name, Type *type) {
|
||||
Token token = make_token_ident(name);
|
||||
Entity *entity = alloc_entity(a, Entity_Nil, NULL, token, type);
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_implicit_value(gbAllocator a, String name, Type *type, ImplicitValueId id) {
|
||||
Token token = make_token_ident(name);
|
||||
Entity *entity = alloc_entity(a, Entity_ImplicitValue, NULL, token, type);
|
||||
entity->ImplicitValue.id = id;
|
||||
Entity *make_entity_label(gbAllocator a, Scope *scope, Token token, Type *type,
|
||||
AstNode *node) {
|
||||
Entity *entity = alloc_entity(a, Entity_Label, scope, token, type);
|
||||
entity->Label.node = node;
|
||||
return entity;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Entity *make_entity_dummy_variable(gbAllocator a, Scope *scope, Token token) {
|
||||
token.string = str_lit("_");
|
||||
return make_entity_variable(a, scope, token, NULL);
|
||||
return make_entity_variable(a, scope, token, NULL, false);
|
||||
}
|
||||
|
||||
+155
-55
@@ -35,78 +35,176 @@ HashKey hash_exact_value(ExactValue v) {
|
||||
}
|
||||
|
||||
|
||||
ExactValue make_exact_value_compound(AstNode *node) {
|
||||
ExactValue exact_value_compound(AstNode *node) {
|
||||
ExactValue result = {ExactValue_Compound};
|
||||
result.value_compound = node;
|
||||
return result;
|
||||
}
|
||||
|
||||
ExactValue make_exact_value_bool(bool b) {
|
||||
ExactValue exact_value_bool(bool b) {
|
||||
ExactValue result = {ExactValue_Bool};
|
||||
result.value_bool = (b != 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
ExactValue make_exact_value_string(String string) {
|
||||
ExactValue exact_value_string(String string) {
|
||||
// TODO(bill): Allow for numbers with underscores in them
|
||||
ExactValue result = {ExactValue_String};
|
||||
result.value_string = string;
|
||||
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.len > 2 && 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 exact_value_integer(i64 i) {
|
||||
ExactValue result = {ExactValue_Integer};
|
||||
result.value_integer = i;
|
||||
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 exact_value_float(f64 f) {
|
||||
ExactValue result = {ExactValue_Float};
|
||||
result.value_float = f;
|
||||
return result;
|
||||
}
|
||||
|
||||
ExactValue make_exact_value_pointer(i64 ptr) {
|
||||
ExactValue exact_value_pointer(i64 ptr) {
|
||||
ExactValue result = {ExactValue_Pointer};
|
||||
result.value_pointer = ptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
ExactValue make_exact_value_from_basic_literal(Token token) {
|
||||
|
||||
ExactValue 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 'z': base = 12; 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;
|
||||
v = digit_value(r);
|
||||
if (v >= base) {
|
||||
break;
|
||||
}
|
||||
result *= base;
|
||||
result += v;
|
||||
}
|
||||
|
||||
|
||||
return exact_value_integer(result);
|
||||
}
|
||||
|
||||
|
||||
|
||||
ExactValue 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;
|
||||
}
|
||||
i64 v = digit_value(r);
|
||||
if (v >= 10) {
|
||||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
i64 v = digit_value(r);
|
||||
if (v >= 10) {
|
||||
break;
|
||||
}
|
||||
value += v/pow10;
|
||||
pow10 *= 10.0;
|
||||
}
|
||||
}
|
||||
|
||||
bool frac = false;
|
||||
f64 scale = 1.0;
|
||||
if ((str[i] == 'e') || (str[i] == 'E')) {
|
||||
i++;
|
||||
|
||||
if (str[i] == '-') {
|
||||
frac = true;
|
||||
i++;
|
||||
} else if (str[i] == '+') {
|
||||
i++;
|
||||
}
|
||||
|
||||
u32 exp = 0;
|
||||
for (; i < len; i++) {
|
||||
Rune r = cast(Rune)str[i];
|
||||
if (r == '_') {
|
||||
continue;
|
||||
}
|
||||
u32 d = cast(u32)digit_value(r);
|
||||
if (d >= 10) {
|
||||
break;
|
||||
}
|
||||
exp = exp * 10 + d;
|
||||
}
|
||||
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 exact_value_float(result);
|
||||
}
|
||||
|
||||
|
||||
ExactValue exact_value_from_basic_literal(Token token) {
|
||||
switch (token.kind) {
|
||||
case Token_String: return make_exact_value_string(token.string);
|
||||
case Token_Integer: return make_exact_value_integer_from_string(token.string);
|
||||
case Token_Float: return make_exact_value_float_from_string(token.string);
|
||||
case Token_String: return exact_value_string(token.string);
|
||||
case Token_Integer: return exact_value_integer_from_string(token.string);
|
||||
case Token_Float: return exact_value_float_from_string(token.string);
|
||||
case Token_Rune: {
|
||||
Rune r = GB_RUNE_INVALID;
|
||||
gb_utf8_decode(token.string.text, token.string.len, &r);
|
||||
// gb_printf("%.*s rune: %d\n", LIT(token.string), r);
|
||||
return make_exact_value_integer(r);
|
||||
return exact_value_integer(r);
|
||||
}
|
||||
default:
|
||||
GB_PANIC("Invalid token for basic literal");
|
||||
@@ -125,12 +223,12 @@ ExactValue exact_value_to_integer(ExactValue v) {
|
||||
i64 i = cast(i64)v.value_float;
|
||||
f64 f = cast(f64)i;
|
||||
if (f == v.value_float) {
|
||||
return make_exact_value_integer(i);
|
||||
return exact_value_integer(i);
|
||||
}
|
||||
} break;
|
||||
|
||||
case ExactValue_Pointer:
|
||||
return make_exact_value_integer(cast(i64)cast(intptr)v.value_pointer);
|
||||
return exact_value_integer(cast(i64)cast(intptr)v.value_pointer);
|
||||
}
|
||||
ExactValue r = {ExactValue_Invalid};
|
||||
return r;
|
||||
@@ -139,7 +237,7 @@ ExactValue exact_value_to_integer(ExactValue v) {
|
||||
ExactValue exact_value_to_float(ExactValue v) {
|
||||
switch (v.kind) {
|
||||
case ExactValue_Integer:
|
||||
return make_exact_value_float(cast(i64)v.value_integer);
|
||||
return exact_value_float(cast(i64)v.value_integer);
|
||||
case ExactValue_Float:
|
||||
return v;
|
||||
}
|
||||
@@ -182,8 +280,7 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
|
||||
case ExactValue_Invalid:
|
||||
return v;
|
||||
case ExactValue_Integer:
|
||||
i = v.value_integer;
|
||||
i = ~i;
|
||||
i = ~v.value_integer;
|
||||
break;
|
||||
default:
|
||||
goto failure;
|
||||
@@ -191,17 +288,19 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
|
||||
|
||||
// NOTE(bill): unsigned integers will be negative and will need to be
|
||||
// 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);
|
||||
}
|
||||
|
||||
return make_exact_value_integer(i);
|
||||
return exact_value_integer(i);
|
||||
} break;
|
||||
|
||||
case Token_Not: {
|
||||
switch (v.kind) {
|
||||
case ExactValue_Invalid: return v;
|
||||
case ExactValue_Bool:
|
||||
return make_exact_value_bool(!v.value_bool);
|
||||
return exact_value_bool(!v.value_bool);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
@@ -255,7 +354,7 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
|
||||
return;
|
||||
case ExactValue_Float:
|
||||
// TODO(bill): Is this good enough?
|
||||
*x = make_exact_value_float(cast(f64)x->value_integer);
|
||||
*x = exact_value_float(cast(f64)x->value_integer);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@@ -279,10 +378,10 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
|
||||
|
||||
case ExactValue_Bool:
|
||||
switch (op) {
|
||||
case Token_CmpAnd: return make_exact_value_bool(x.value_bool && y.value_bool);
|
||||
case Token_CmpOr: return make_exact_value_bool(x.value_bool || y.value_bool);
|
||||
case Token_And: return make_exact_value_bool(x.value_bool & y.value_bool);
|
||||
case Token_Or: return make_exact_value_bool(x.value_bool | y.value_bool);
|
||||
case Token_CmpAnd: return exact_value_bool(x.value_bool && y.value_bool);
|
||||
case Token_CmpOr: return exact_value_bool(x.value_bool || y.value_bool);
|
||||
case Token_And: return exact_value_bool(x.value_bool & y.value_bool);
|
||||
case Token_Or: return exact_value_bool(x.value_bool | y.value_bool);
|
||||
default: goto error;
|
||||
}
|
||||
break;
|
||||
@@ -295,7 +394,7 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
|
||||
case Token_Add: c = a + b; break;
|
||||
case Token_Sub: c = a - b; break;
|
||||
case Token_Mul: c = a * b; break;
|
||||
case Token_Quo: return make_exact_value_float(fmod(cast(f64)a, cast(f64)b));
|
||||
case Token_Quo: return exact_value_float(fmod(cast(f64)a, cast(f64)b));
|
||||
case Token_QuoEq: c = a / b; break; // NOTE(bill): Integer division
|
||||
case Token_Mod: c = a % b; break;
|
||||
case Token_And: c = a & b; break;
|
||||
@@ -307,23 +406,24 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
|
||||
default: goto error;
|
||||
}
|
||||
|
||||
return make_exact_value_integer(c);
|
||||
return exact_value_integer(c);
|
||||
} break;
|
||||
|
||||
case ExactValue_Float: {
|
||||
f64 a = x.value_float;
|
||||
f64 b = y.value_float;
|
||||
switch (op) {
|
||||
case Token_Add: return make_exact_value_float(a + b);
|
||||
case Token_Sub: return make_exact_value_float(a - b);
|
||||
case Token_Mul: return make_exact_value_float(a * b);
|
||||
case Token_Quo: return make_exact_value_float(a / b);
|
||||
case Token_Add: return exact_value_float(a + b);
|
||||
case Token_Sub: return exact_value_float(a - b);
|
||||
case Token_Mul: return exact_value_float(a * b);
|
||||
case Token_Quo: return exact_value_float(a / b);
|
||||
default: goto error;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
error:
|
||||
; // MSVC accepts this??? apparently you cannot declare variables immediately after labels...
|
||||
ExactValue error_value = {0};
|
||||
// gb_printf_err("Invalid binary operation: %s\n", token_kind_to_string(op));
|
||||
return error_value;
|
||||
|
||||
+431
-146
File diff suppressed because it is too large
Load Diff
+14
-17
@@ -27,9 +27,6 @@ void ir_opt_add_operands(irValueArray *ops, irInstr *i) {
|
||||
array_add(ops, i->PtrOffset.address);
|
||||
array_add(ops, i->PtrOffset.offset);
|
||||
break;
|
||||
case irInstr_ArrayExtractValue:
|
||||
array_add(ops, i->ArrayExtractValue.address);
|
||||
break;
|
||||
case irInstr_StructExtractValue:
|
||||
array_add(ops, i->StructExtractValue.address);
|
||||
break;
|
||||
@@ -69,18 +66,18 @@ void ir_opt_add_operands(irValueArray *ops, irInstr *i) {
|
||||
array_add(ops, i->Call.args[j]);
|
||||
}
|
||||
break;
|
||||
case irInstr_VectorExtractElement:
|
||||
array_add(ops, i->VectorExtractElement.vector);
|
||||
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_VectorExtractElement:
|
||||
// array_add(ops, i->VectorExtractElement.vector);
|
||||
// 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;
|
||||
case irInstr_BoundsCheck:
|
||||
@@ -261,7 +258,7 @@ void ir_opt_blocks(irProcedure *proc) {
|
||||
if (b == NULL) {
|
||||
continue;
|
||||
}
|
||||
GB_ASSERT(b->index == i);
|
||||
GB_ASSERT_MSG(b->index == i, "%d, %td", b->index, i);
|
||||
|
||||
if (ir_opt_block_fusion(proc, b)) {
|
||||
changed = true;
|
||||
@@ -470,7 +467,7 @@ void ir_opt_tree(irGen *s) {
|
||||
}
|
||||
|
||||
ir_opt_blocks(proc);
|
||||
#if 1
|
||||
#if 0
|
||||
ir_opt_build_referrers(proc);
|
||||
ir_opt_build_dom_tree(proc);
|
||||
|
||||
|
||||
+237
-168
@@ -137,69 +137,82 @@ void ir_print_encoded_global(irFileBuffer *f, String name, bool remove_prefix) {
|
||||
|
||||
|
||||
void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
|
||||
BaseTypeSizes s = m->sizes;
|
||||
i64 word_bits = 8*s.word_size;
|
||||
i64 word_bits = 8*build_context.word_size;
|
||||
GB_ASSERT_NOT_NULL(t);
|
||||
t = default_type(t);
|
||||
GB_ASSERT(is_type_typed(t));
|
||||
|
||||
switch (t->kind) {
|
||||
case Type_Basic:
|
||||
switch (t->Basic.kind) {
|
||||
case Basic_bool: ir_fprintf(f, "i1"); break;
|
||||
case Basic_i8: ir_fprintf(f, "i8"); break;
|
||||
case Basic_u8: ir_fprintf(f, "i8"); break;
|
||||
case Basic_i16: ir_fprintf(f, "i16"); break;
|
||||
case Basic_u16: ir_fprintf(f, "i16"); break;
|
||||
case Basic_i32: ir_fprintf(f, "i32"); break;
|
||||
case Basic_u32: ir_fprintf(f, "i32"); break;
|
||||
case Basic_i64: ir_fprintf(f, "i64"); break;
|
||||
case Basic_u64: ir_fprintf(f, "i64"); break;
|
||||
// case Basic_i128: ir_fprintf(f, "i128"); break;
|
||||
// case Basic_u128: ir_fprintf(f, "i128"); break;
|
||||
// case Basic_f16: ir_fprintf(f, "half"); break;
|
||||
case Basic_f32: ir_fprintf(f, "float"); break;
|
||||
case Basic_f64: ir_fprintf(f, "double"); break;
|
||||
// case Basic_f128: ir_fprintf(f, "fp128"); break;
|
||||
case Basic_rawptr: ir_fprintf(f, "%%..rawptr"); break;
|
||||
case Basic_string: ir_fprintf(f, "%%..string"); break;
|
||||
case Basic_uint: ir_fprintf(f, "i%lld", word_bits); break;
|
||||
case Basic_int: ir_fprintf(f, "i%lld", word_bits); break;
|
||||
case Basic_any: ir_fprintf(f, "%%..any"); break;
|
||||
case Basic_bool: ir_fprintf(f, "i1"); return;
|
||||
case Basic_i8: ir_fprintf(f, "i8"); return;
|
||||
case Basic_u8: ir_fprintf(f, "i8"); return;
|
||||
case Basic_i16: ir_fprintf(f, "i16"); return;
|
||||
case Basic_u16: ir_fprintf(f, "i16"); return;
|
||||
case Basic_i32: ir_fprintf(f, "i32"); return;
|
||||
case Basic_u32: ir_fprintf(f, "i32"); return;
|
||||
case Basic_i64: ir_fprintf(f, "i64"); return;
|
||||
case Basic_u64: ir_fprintf(f, "i64"); return;
|
||||
// case Basic_i128: ir_fprintf(f, "i128"); return;
|
||||
// case Basic_u128: ir_fprintf(f, "i128"); return;
|
||||
// case Basic_f16: ir_fprintf(f, "half"); return;
|
||||
case Basic_f32: ir_fprintf(f, "float"); return;
|
||||
case Basic_f64: ir_fprintf(f, "double"); return;
|
||||
// case Basic_f128: ir_fprintf(f, "fp128"); return;
|
||||
case Basic_rawptr: ir_fprintf(f, "%%..rawptr"); return;
|
||||
case Basic_string: ir_fprintf(f, "%%..string"); return;
|
||||
case Basic_uint: ir_fprintf(f, "i%lld", word_bits); return;
|
||||
case Basic_int: ir_fprintf(f, "i%lld", word_bits); return;
|
||||
case Basic_any: ir_fprintf(f, "%%..any"); return;
|
||||
}
|
||||
break;
|
||||
case Type_Pointer:
|
||||
ir_print_type(f, m, t->Pointer.elem);
|
||||
ir_fprintf(f, "*");
|
||||
break;
|
||||
case Type_Maybe:
|
||||
ir_fprintf(f, "{");
|
||||
ir_print_type(f, m, t->Maybe.elem);
|
||||
ir_fprintf(f, ", ");
|
||||
ir_print_type(f, m, t_bool);
|
||||
ir_fprintf(f, "}");
|
||||
break;
|
||||
return;
|
||||
case Type_Array:
|
||||
ir_fprintf(f, "[%lld x ", t->Array.count);
|
||||
ir_print_type(f, m, t->Array.elem);
|
||||
ir_fprintf(f, "]");
|
||||
break;
|
||||
case Type_Vector:
|
||||
ir_fprintf(f, "<%lld x ", t->Vector.count);
|
||||
return;
|
||||
case Type_Vector: {
|
||||
i64 align = type_align_of(heap_allocator(), t);
|
||||
i64 count = t->Vector.count;
|
||||
ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x ", align, count);
|
||||
ir_print_type(f, m, t->Vector.elem);
|
||||
ir_fprintf(f, "]}");
|
||||
return;
|
||||
}
|
||||
/* ir_fprintf(f, "<%lld x ", t->Vector.count);
|
||||
ir_print_type(f, m, t->Vector.elem);
|
||||
ir_fprintf(f, ">");
|
||||
break;
|
||||
return; */
|
||||
case Type_Slice:
|
||||
ir_fprintf(f, "{");
|
||||
ir_print_type(f, m, t->Slice.elem);
|
||||
ir_fprintf(f, "*, i%lld, i%lld}", word_bits, word_bits);
|
||||
break;
|
||||
return;
|
||||
case Type_DynamicArray:
|
||||
ir_fprintf(f, "{");
|
||||
ir_print_type(f, m, t->DynamicArray.elem);
|
||||
ir_fprintf(f, "*, i%lld, i%lld,", word_bits, word_bits);
|
||||
ir_print_type(f, m, t_allocator);
|
||||
ir_fprintf(f, "}");
|
||||
return;
|
||||
case Type_Record: {
|
||||
switch (t->Record.kind) {
|
||||
case TypeRecord_Struct:
|
||||
if (t->Record.struct_is_packed) {
|
||||
if (t->Record.is_packed) {
|
||||
ir_fprintf(f, "<");
|
||||
}
|
||||
ir_fprintf(f, "{");
|
||||
if (t->Record.custom_align > 0) {
|
||||
ir_fprintf(f, "[0 x <%lld x i8>]", t->Record.custom_align);
|
||||
if (t->Record.field_count > 0) {
|
||||
ir_fprintf(f, ", ");
|
||||
}
|
||||
}
|
||||
for (isize i = 0; i < t->Record.field_count; i++) {
|
||||
if (i > 0) {
|
||||
ir_fprintf(f, ", ");
|
||||
@@ -207,27 +220,27 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
|
||||
ir_print_type(f, m, t->Record.fields[i]->type);
|
||||
}
|
||||
ir_fprintf(f, "}");
|
||||
if (t->Record.struct_is_packed) {
|
||||
if (t->Record.is_packed) {
|
||||
ir_fprintf(f, ">");
|
||||
}
|
||||
break;
|
||||
return;
|
||||
case TypeRecord_Union: {
|
||||
// NOTE(bill): The zero size array is used to fix the alignment used in a structure as
|
||||
// LLVM takes the first element's alignment as the entire alignment (like C)
|
||||
i64 size_of_union = type_size_of(s, heap_allocator(), t) - s.word_size;
|
||||
i64 align_of_union = type_align_of(s, heap_allocator(), t);
|
||||
i64 size_of_union = type_size_of(heap_allocator(), t) - build_context.word_size;
|
||||
i64 align_of_union = type_align_of(heap_allocator(), t);
|
||||
ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8], i%lld}", align_of_union, size_of_union, word_bits);
|
||||
} break;
|
||||
} return;
|
||||
case TypeRecord_RawUnion: {
|
||||
// NOTE(bill): The zero size array is used to fix the alignment used in a structure as
|
||||
// LLVM takes the first element's alignment as the entire alignment (like C)
|
||||
i64 size_of_union = type_size_of(s, heap_allocator(), t);
|
||||
i64 align_of_union = type_align_of(s, heap_allocator(), t);
|
||||
i64 size_of_union = type_size_of(heap_allocator(), t);
|
||||
i64 align_of_union = type_align_of(heap_allocator(), t);
|
||||
ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8]}", align_of_union, size_of_union);
|
||||
} break;
|
||||
} return;
|
||||
case TypeRecord_Enum:
|
||||
ir_print_type(f, m, base_enum_type(t));
|
||||
break;
|
||||
return;
|
||||
}
|
||||
} break;
|
||||
|
||||
@@ -240,7 +253,7 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
|
||||
} else {
|
||||
ir_print_type(f, m, base_type(t));
|
||||
}
|
||||
break;
|
||||
return;
|
||||
case Type_Tuple:
|
||||
if (t->Tuple.variable_count == 1) {
|
||||
ir_print_type(f, m, t->Tuple.variables[0]->type);
|
||||
@@ -254,7 +267,7 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
|
||||
}
|
||||
ir_fprintf(f, "}");
|
||||
}
|
||||
break;
|
||||
return;
|
||||
case Type_Proc: {
|
||||
if (t->Proc.result_count == 0) {
|
||||
ir_fprintf(f, "void");
|
||||
@@ -270,6 +283,11 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
|
||||
ir_print_type(f, m, params->variables[i]->type);
|
||||
}
|
||||
ir_fprintf(f, ")*");
|
||||
} return;
|
||||
|
||||
case Type_Map: {
|
||||
GB_ASSERT(t->Map.generated_struct_type != NULL);
|
||||
ir_print_type(f, m, t->Map.generated_struct_type);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
@@ -280,29 +298,15 @@ void ir_print_compound_element(irFileBuffer *f, irModule *m, ExactValue v, Type
|
||||
ir_print_type(f, m, elem_type);
|
||||
ir_fprintf(f, " ");
|
||||
|
||||
if (v.kind != ExactValue_Invalid && is_type_maybe(elem_type)) {
|
||||
Type *t = base_type(elem_type)->Maybe.elem;
|
||||
ir_fprintf(f, "{");
|
||||
ir_print_type(f, m, t);
|
||||
ir_fprintf(f, " ");
|
||||
}
|
||||
|
||||
if (v.kind == ExactValue_Invalid || base_type(elem_type) == t_any) {
|
||||
ir_fprintf(f, "zeroinitializer");
|
||||
} else {
|
||||
ir_print_exact_value(f, m, v, elem_type);
|
||||
}
|
||||
|
||||
if (v.kind != ExactValue_Invalid && is_type_maybe(elem_type)) {
|
||||
ir_fprintf(f, ", ");
|
||||
ir_print_type(f, m, t_bool);
|
||||
ir_fprintf(f, " ");
|
||||
ir_fprintf(f, "true}");
|
||||
}
|
||||
}
|
||||
|
||||
void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *type) {
|
||||
type = base_type(base_enum_type(type));
|
||||
type = core_type(type);
|
||||
if (is_type_float(type)) {
|
||||
value = exact_value_to_float(value);
|
||||
} else if (is_type_integer(type)) {
|
||||
@@ -360,7 +364,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
||||
}
|
||||
} break;
|
||||
case ExactValue_Float: {
|
||||
GB_ASSERT(is_type_float(type));
|
||||
GB_ASSERT_MSG(is_type_float(type), "%s", type_to_string(type));
|
||||
type = base_type(type);
|
||||
u64 u = *cast(u64*)&value.value_float;
|
||||
switch (type->Basic.kind) {
|
||||
@@ -450,9 +454,14 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
||||
break;
|
||||
}
|
||||
|
||||
ir_fprintf(f, "<");
|
||||
i64 align = type_align_of(m->allocator, type);
|
||||
i64 count = type->Vector.count;
|
||||
Type *elem_type = type->Vector.elem;
|
||||
|
||||
ir_fprintf(f, "{[0 x <%lld x i8>] zeroinitializer, [%lld x ", align, count);
|
||||
ir_print_type(f, m, elem_type);
|
||||
ir_fprintf(f, "][");
|
||||
|
||||
if (elem_count == 1 && type->Vector.count > 1) {
|
||||
TypeAndValue *tav = type_and_value_of_expression(m->info, cl->elems.e[0]);
|
||||
GB_ASSERT(tav != NULL);
|
||||
@@ -474,7 +483,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
||||
}
|
||||
}
|
||||
|
||||
ir_fprintf(f, ">");
|
||||
ir_fprintf(f, "]}");
|
||||
} else if (is_type_struct(type)) {
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&m->tmp_arena);
|
||||
|
||||
@@ -517,7 +526,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
||||
|
||||
|
||||
|
||||
if (type->Record.struct_is_packed) {
|
||||
if (type->Record.is_packed) {
|
||||
ir_fprintf(f, "<");
|
||||
}
|
||||
ir_fprintf(f, "{");
|
||||
@@ -534,7 +543,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
||||
|
||||
|
||||
ir_fprintf(f, "}");
|
||||
if (type->Record.struct_is_packed) {
|
||||
if (type->Record.is_packed) {
|
||||
ir_fprintf(f, ">");
|
||||
}
|
||||
|
||||
@@ -607,8 +616,6 @@ void ir_print_value(irFileBuffer *f, irModule *m, irValue *value, Type *type_hin
|
||||
ir_print_type(f, m, t_int);
|
||||
ir_fprintf(f, " 0, i32 0), ");
|
||||
ir_print_type(f, m, t_int);
|
||||
ir_fprintf(f, " %lld, ", cs->count);
|
||||
ir_print_type(f, m, t_int);
|
||||
ir_fprintf(f, " %lld}", cs->count);
|
||||
}
|
||||
} break;
|
||||
@@ -657,6 +664,11 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
||||
ir_fprintf(f, "\t");
|
||||
|
||||
switch (instr->kind) {
|
||||
default: {
|
||||
GB_PANIC("<unknown instr> %d\n", instr->kind);
|
||||
ir_fprintf(f, "; <unknown instr> %d\n", instr->kind);
|
||||
} break;
|
||||
|
||||
case irInstr_StartupRuntime: {
|
||||
ir_fprintf(f, "call void ");
|
||||
ir_print_encoded_global(f, str_lit(IR_STARTUP_RUNTIME_PROC_NAME), false);
|
||||
@@ -671,7 +683,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
||||
Type *type = instr->Local.entity->type;
|
||||
ir_fprintf(f, "%%%d = alloca ", value->index);
|
||||
ir_print_type(f, m, type);
|
||||
ir_fprintf(f, ", align %lld\n", type_align_of(m->sizes, m->allocator, type));
|
||||
ir_fprintf(f, ", align %lld\n", type_align_of(m->allocator, type));
|
||||
} break;
|
||||
|
||||
case irInstr_ZeroInit: {
|
||||
@@ -684,7 +696,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
||||
} break;
|
||||
|
||||
case irInstr_Store: {
|
||||
Type *type = ir_type(instr->Store.value);
|
||||
Type *type = type_deref(ir_type(instr->Store.address));
|
||||
ir_fprintf(f, "store ");
|
||||
ir_print_type(f, m, type);
|
||||
ir_fprintf(f, " ");
|
||||
@@ -704,7 +716,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
||||
ir_print_type(f, m, type);
|
||||
ir_fprintf(f, "* ");
|
||||
ir_print_value(f, m, instr->Load.address, type);
|
||||
ir_fprintf(f, ", align %lld\n", type_align_of(m->sizes, m->allocator, type));
|
||||
ir_fprintf(f, ", align %lld\n", type_align_of(m->allocator, type));
|
||||
} break;
|
||||
|
||||
case irInstr_ArrayElementPtr: {
|
||||
@@ -719,6 +731,10 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
||||
ir_fprintf(f, ", ");
|
||||
ir_print_type(f, m, t_int);
|
||||
ir_fprintf(f, " 0, ");
|
||||
if (is_type_vector(type_deref(et))) {
|
||||
ir_print_type(f, m, t_i32);
|
||||
ir_fprintf(f, " 1, ");
|
||||
}
|
||||
|
||||
irValue *index =instr->ArrayElementPtr.elem_index;
|
||||
Type *t = ir_type(index);
|
||||
@@ -731,6 +747,13 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
||||
case irInstr_StructElementPtr: {
|
||||
Type *et = ir_type(instr->StructElementPtr.address);
|
||||
ir_fprintf(f, "%%%d = getelementptr inbounds ", value->index);
|
||||
i32 index = instr->StructElementPtr.elem_index;
|
||||
Type *st = base_type(type_deref(et));
|
||||
if (is_type_struct(st)) {
|
||||
if (st->Record.custom_align > 0) {
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
ir_print_type(f, m, type_deref(et));
|
||||
ir_fprintf(f, ", ");
|
||||
@@ -741,7 +764,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
||||
ir_print_type(f, m, t_int);
|
||||
ir_fprintf(f, " 0, ");
|
||||
ir_print_type(f, m, t_i32);
|
||||
ir_fprintf(f, " %d", instr->StructElementPtr.elem_index);
|
||||
ir_fprintf(f, " %d", index);
|
||||
ir_fprintf(f, "\n");
|
||||
} break;
|
||||
|
||||
@@ -789,24 +812,22 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
||||
ir_fprintf(f, "\n");
|
||||
} break;
|
||||
|
||||
case irInstr_ArrayExtractValue: {
|
||||
Type *et = ir_type(instr->ArrayExtractValue.address);
|
||||
ir_fprintf(f, "%%%d = extractvalue ", value->index);
|
||||
|
||||
ir_print_type(f, m, et);
|
||||
ir_fprintf(f, " ");
|
||||
ir_print_value(f, m, instr->ArrayExtractValue.address, et);
|
||||
ir_fprintf(f, ", %d\n", instr->ArrayExtractValue.index);
|
||||
} break;
|
||||
|
||||
case irInstr_StructExtractValue: {
|
||||
Type *et = ir_type(instr->StructExtractValue.address);
|
||||
ir_fprintf(f, "%%%d = extractvalue ", value->index);
|
||||
i32 index = instr->StructExtractValue.index;
|
||||
Type *st = base_type(et);
|
||||
if (is_type_struct(st)) {
|
||||
if (st->Record.custom_align > 0) {
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ir_print_type(f, m, et);
|
||||
ir_fprintf(f, " ");
|
||||
ir_print_value(f, m, instr->StructExtractValue.address, et);
|
||||
ir_fprintf(f, ", %d\n", instr->StructExtractValue.index);
|
||||
ir_fprintf(f, ", %d\n", index);
|
||||
} break;
|
||||
|
||||
case irInstr_UnionTagPtr: {
|
||||
@@ -823,6 +844,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
||||
ir_fprintf(f, " 0, ");
|
||||
ir_print_type(f, m, t_i32);
|
||||
ir_fprintf(f, " %d", 2);
|
||||
ir_fprintf(f, " ; UnionTagPtr");
|
||||
ir_fprintf(f, "\n");
|
||||
} break;
|
||||
|
||||
@@ -833,7 +855,9 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
||||
ir_print_type(f, m, et);
|
||||
ir_fprintf(f, " ");
|
||||
ir_print_value(f, m, instr->UnionTagValue.address, et);
|
||||
ir_fprintf(f, ", %d\n", 2);
|
||||
ir_fprintf(f, ", %d", 2);
|
||||
ir_fprintf(f, " ; UnionTagValue");
|
||||
ir_fprintf(f, "\n");
|
||||
} break;
|
||||
|
||||
case irInstr_Jump: {;
|
||||
@@ -918,7 +942,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
||||
switch (uo->op) {
|
||||
case Token_Sub:
|
||||
if (is_type_float(elem_type)) {
|
||||
ir_print_exact_value(f, m, make_exact_value_float(0), type);
|
||||
ir_print_exact_value(f, m, exact_value_float(0), elem_type);
|
||||
} else {
|
||||
ir_fprintf(f, "0");
|
||||
}
|
||||
@@ -938,6 +962,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
||||
irInstrBinaryOp *bo = &value->Instr.BinaryOp;
|
||||
Type *type = base_type(ir_type(bo->left));
|
||||
Type *elem_type = type;
|
||||
GB_ASSERT(!is_type_vector(elem_type));
|
||||
while (elem_type->kind == Type_Vector) {
|
||||
elem_type = base_type(elem_type->Vector.elem);
|
||||
}
|
||||
@@ -1078,6 +1103,9 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
||||
ir_fprintf(f, ", ");
|
||||
}
|
||||
ir_print_type(f, m, t);
|
||||
if (e->flags&EntityFlag_NoAlias) {
|
||||
ir_fprintf(f, " noalias");
|
||||
}
|
||||
ir_fprintf(f, " ");
|
||||
irValue *arg = call->args[i];
|
||||
ir_print_value(f, m, arg, t);
|
||||
@@ -1101,85 +1129,85 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
||||
ir_fprintf(f, "\n");
|
||||
} break;
|
||||
|
||||
case irInstr_VectorExtractElement: {
|
||||
Type *vt = ir_type(instr->VectorExtractElement.vector);
|
||||
Type *it = ir_type(instr->VectorExtractElement.index);
|
||||
ir_fprintf(f, "%%%d = extractelement ", value->index);
|
||||
// case irInstr_VectorExtractElement: {
|
||||
// Type *vt = ir_type(instr->VectorExtractElement.vector);
|
||||
// Type *it = ir_type(instr->VectorExtractElement.index);
|
||||
// ir_fprintf(f, "%%%d = extractelement ", value->index);
|
||||
|
||||
ir_print_type(f, m, vt);
|
||||
ir_fprintf(f, " ");
|
||||
ir_print_value(f, m, instr->VectorExtractElement.vector, vt);
|
||||
ir_fprintf(f, ", ");
|
||||
ir_print_type(f, m, it);
|
||||
ir_fprintf(f, " ");
|
||||
ir_print_value(f, m, instr->VectorExtractElement.index, it);
|
||||
ir_fprintf(f, "\n");
|
||||
} break;
|
||||
// ir_print_type(f, m, vt);
|
||||
// ir_fprintf(f, " ");
|
||||
// ir_print_value(f, m, instr->VectorExtractElement.vector, vt);
|
||||
// ir_fprintf(f, ", ");
|
||||
// ir_print_type(f, m, it);
|
||||
// ir_fprintf(f, " ");
|
||||
// ir_print_value(f, m, instr->VectorExtractElement.index, it);
|
||||
// ir_fprintf(f, "\n");
|
||||
// } break;
|
||||
|
||||
case irInstr_VectorInsertElement: {
|
||||
irInstrVectorInsertElement *ie = &instr->VectorInsertElement;
|
||||
Type *vt = ir_type(ie->vector);
|
||||
ir_fprintf(f, "%%%d = insertelement ", value->index);
|
||||
// case irInstr_VectorInsertElement: {
|
||||
// irInstrVectorInsertElement *ie = &instr->VectorInsertElement;
|
||||
// Type *vt = ir_type(ie->vector);
|
||||
// ir_fprintf(f, "%%%d = insertelement ", value->index);
|
||||
|
||||
ir_print_type(f, m, vt);
|
||||
ir_fprintf(f, " ");
|
||||
ir_print_value(f, m, ie->vector, vt);
|
||||
ir_fprintf(f, ", ");
|
||||
// ir_print_type(f, m, vt);
|
||||
// ir_fprintf(f, " ");
|
||||
// ir_print_value(f, m, ie->vector, vt);
|
||||
// ir_fprintf(f, ", ");
|
||||
|
||||
ir_print_type(f, m, ir_type(ie->elem));
|
||||
ir_fprintf(f, " ");
|
||||
ir_print_value(f, m, ie->elem, ir_type(ie->elem));
|
||||
ir_fprintf(f, ", ");
|
||||
// ir_print_type(f, m, ir_type(ie->elem));
|
||||
// ir_fprintf(f, " ");
|
||||
// ir_print_value(f, m, ie->elem, ir_type(ie->elem));
|
||||
// ir_fprintf(f, ", ");
|
||||
|
||||
ir_print_type(f, m, ir_type(ie->index));
|
||||
ir_fprintf(f, " ");
|
||||
ir_print_value(f, m, ie->index, ir_type(ie->index));
|
||||
// ir_print_type(f, m, ir_type(ie->index));
|
||||
// ir_fprintf(f, " ");
|
||||
// ir_print_value(f, m, ie->index, ir_type(ie->index));
|
||||
|
||||
ir_fprintf(f, "\n");
|
||||
} break;
|
||||
// ir_fprintf(f, "\n");
|
||||
// } break;
|
||||
|
||||
case irInstr_VectorShuffle: {
|
||||
irInstrVectorShuffle *sv = &instr->VectorShuffle;
|
||||
Type *vt = ir_type(sv->vector);
|
||||
ir_fprintf(f, "%%%d = shufflevector ", value->index);
|
||||
// case irInstr_VectorShuffle: {
|
||||
// irInstrVectorShuffle *sv = &instr->VectorShuffle;
|
||||
// Type *vt = ir_type(sv->vector);
|
||||
// ir_fprintf(f, "%%%d = shufflevector ", value->index);
|
||||
|
||||
ir_print_type(f, m, vt);
|
||||
ir_fprintf(f, " ");
|
||||
ir_print_value(f, m, sv->vector, vt);
|
||||
ir_fprintf(f, ", ");
|
||||
// ir_print_type(f, m, vt);
|
||||
// ir_fprintf(f, " ");
|
||||
// ir_print_value(f, m, sv->vector, vt);
|
||||
// ir_fprintf(f, ", ");
|
||||
|
||||
ir_print_type(f, m, vt);
|
||||
ir_fprintf(f, " ");
|
||||
ir_print_value(f, m, sv->vector, vt);
|
||||
ir_fprintf(f, ", ");
|
||||
// ir_print_type(f, m, vt);
|
||||
// ir_fprintf(f, " ");
|
||||
// ir_print_value(f, m, sv->vector, vt);
|
||||
// ir_fprintf(f, ", ");
|
||||
|
||||
ir_fprintf(f, "<%td x i32> <", sv->index_count);
|
||||
for (isize i = 0; i < sv->index_count; i++) {
|
||||
if (i > 0) {
|
||||
ir_fprintf(f, ", ");
|
||||
}
|
||||
ir_fprintf(f, "i32 %d", sv->indices[i]);
|
||||
}
|
||||
ir_fprintf(f, ">");
|
||||
ir_fprintf(f, "\n");
|
||||
} break;
|
||||
// ir_fprintf(f, "<%td x i32> <", sv->index_count);
|
||||
// for (isize i = 0; i < sv->index_count; i++) {
|
||||
// if (i > 0) {
|
||||
// ir_fprintf(f, ", ");
|
||||
// }
|
||||
// ir_fprintf(f, "i32 %d", sv->indices[i]);
|
||||
// }
|
||||
// ir_fprintf(f, ">");
|
||||
// ir_fprintf(f, "\n");
|
||||
// } break;
|
||||
|
||||
case irInstr_BoundsCheck: {
|
||||
irInstrBoundsCheck *bc = &instr->BoundsCheck;
|
||||
ir_fprintf(f, "call void ");
|
||||
ir_print_encoded_global(f, str_lit("__bounds_check_error"), false);
|
||||
ir_fprintf(f, "(");
|
||||
ir_print_compound_element(f, m, make_exact_value_string(bc->pos.file), t_string);
|
||||
ir_print_compound_element(f, m, exact_value_string(bc->pos.file), t_string);
|
||||
ir_fprintf(f, ", ");
|
||||
|
||||
ir_print_type(f, m, t_int);
|
||||
ir_fprintf(f, " ");
|
||||
ir_print_exact_value(f, m, make_exact_value_integer(bc->pos.line), t_int);
|
||||
ir_print_exact_value(f, m, exact_value_integer(bc->pos.line), t_int);
|
||||
ir_fprintf(f, ", ");
|
||||
|
||||
ir_print_type(f, m, t_int);
|
||||
ir_fprintf(f, " ");
|
||||
ir_print_exact_value(f, m, make_exact_value_integer(bc->pos.column), t_int);
|
||||
ir_print_exact_value(f, m, exact_value_integer(bc->pos.column), t_int);
|
||||
ir_fprintf(f, ", ");
|
||||
|
||||
ir_print_type(f, m, t_int);
|
||||
@@ -1204,17 +1232,17 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
||||
}
|
||||
|
||||
ir_fprintf(f, "(");
|
||||
ir_print_compound_element(f, m, make_exact_value_string(bc->pos.file), t_string);
|
||||
ir_print_compound_element(f, m, exact_value_string(bc->pos.file), t_string);
|
||||
ir_fprintf(f, ", ");
|
||||
|
||||
ir_print_type(f, m, t_int);
|
||||
ir_fprintf(f, " ");
|
||||
ir_print_exact_value(f, m, make_exact_value_integer(bc->pos.line), t_int);
|
||||
ir_print_exact_value(f, m, exact_value_integer(bc->pos.line), t_int);
|
||||
ir_fprintf(f, ", ");
|
||||
|
||||
ir_print_type(f, m, t_int);
|
||||
ir_fprintf(f, " ");
|
||||
ir_print_exact_value(f, m, make_exact_value_integer(bc->pos.column), t_int);
|
||||
ir_print_exact_value(f, m, exact_value_integer(bc->pos.column), t_int);
|
||||
ir_fprintf(f, ", ");
|
||||
|
||||
ir_print_type(f, m, t_int);
|
||||
@@ -1226,13 +1254,37 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
||||
ir_fprintf(f, " ");
|
||||
ir_print_value(f, m, bc->high, t_int);
|
||||
|
||||
if (!bc->is_substring) {
|
||||
ir_fprintf(f, ", ");
|
||||
ir_print_type(f, m, t_int);
|
||||
ir_fprintf(f, " ");
|
||||
ir_print_value(f, m, bc->max, t_int);
|
||||
}
|
||||
|
||||
ir_fprintf(f, ")\n");
|
||||
} break;
|
||||
|
||||
case irInstr_DebugDeclare: {
|
||||
/* irInstrDebugDeclare *dd = &instr->DebugDeclare;
|
||||
Type *vt = ir_type(dd->value);
|
||||
irDebugInfo *di = dd->debug_info;
|
||||
Entity *e = dd->entity;
|
||||
String name = e->token.string;
|
||||
TokenPos pos = e->token.pos;
|
||||
// gb_printf("debug_declare %.*s\n", LIT(dd->entity->token.string));
|
||||
ir_fprintf(f, "call void @llvm.dbg.declare(");
|
||||
ir_fprintf(f, "metadata ");
|
||||
ir_print_type(f, m, vt);
|
||||
ir_fprintf(f, " ");
|
||||
ir_print_value(f, m, dd->value, vt);
|
||||
ir_fprintf(f, ", metadata !DILocalVariable(name: \"");
|
||||
ir_print_escape_string(f, name, false);
|
||||
ir_fprintf(f, "\", scope: !%d, line: %td)", di->id, pos.line);
|
||||
ir_fprintf(f, ", metadata !DIExpression()");
|
||||
ir_fprintf(f, ")");
|
||||
ir_fprintf(f, ", !dbg !DILocation(line: %td, column: %td, scope: !%d)", pos.line, pos.column, di->id);
|
||||
|
||||
default: {
|
||||
GB_PANIC("<unknown instr> %d\n", instr->kind);
|
||||
ir_fprintf(f, "; <unknown instr> %d\n", instr->kind);
|
||||
ir_fprintf(f, "\n"); */
|
||||
} break;
|
||||
}
|
||||
}
|
||||
@@ -1241,13 +1293,13 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
||||
void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
|
||||
if (proc->body == NULL) {
|
||||
ir_fprintf(f, "declare ");
|
||||
if (proc->tags & ProcTag_dll_import) {
|
||||
ir_fprintf(f, "dllimport ");
|
||||
}
|
||||
// if (proc->tags & ProcTag_dll_import) {
|
||||
// ir_fprintf(f, "dllimport ");
|
||||
// }
|
||||
} else {
|
||||
ir_fprintf(f, "\n");
|
||||
ir_fprintf(f, "define ");
|
||||
if (m->build_context->is_dll) {
|
||||
if (build_context.is_dll) {
|
||||
// if (proc->tags & (ProcTag_export|ProcTag_dll_export)) {
|
||||
if (proc->tags & (ProcTag_export)) {
|
||||
ir_fprintf(f, "dllexport ");
|
||||
@@ -1277,6 +1329,9 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
|
||||
ir_fprintf(f, ", ");
|
||||
}
|
||||
ir_print_type(f, m, e->type);
|
||||
if (e->flags&EntityFlag_NoAlias) {
|
||||
ir_fprintf(f, " noalias");
|
||||
}
|
||||
if (proc->body != NULL) {
|
||||
if (!str_eq(e->token.string, str_lit("")) &&
|
||||
!str_eq(e->token.string, str_lit("_"))) {
|
||||
@@ -1298,11 +1353,14 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
|
||||
}
|
||||
|
||||
|
||||
if (proc->module->generate_debug_info && proc->entity != NULL) {
|
||||
if (proc->entity != NULL) {
|
||||
if (proc->body != NULL) {
|
||||
irDebugInfo *di = *map_ir_debug_info_get(&proc->module->debug_info, hash_pointer(proc->entity));
|
||||
GB_ASSERT(di->kind == irDebugInfo_Proc);
|
||||
ir_fprintf(f, "!dbg !%d ", di->id);
|
||||
irDebugInfo **di_ = map_ir_debug_info_get(&proc->module->debug_info, hash_pointer(proc->entity));
|
||||
if (di_ != NULL) {
|
||||
irDebugInfo *di = *di_;
|
||||
GB_ASSERT(di->kind == irDebugInfo_Proc);
|
||||
// ir_fprintf(f, "!dbg !%d ", di->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1350,10 +1408,6 @@ void print_llvm_ir(irGen *ir) {
|
||||
irFileBuffer buf = {0}, *f = &buf;
|
||||
ir_file_buffer_init(f, &ir->output_file);
|
||||
|
||||
if (m->layout.len > 0) {
|
||||
ir_fprintf(f, "target datalayout = \"%.*s\"\n", LIT(m->layout));
|
||||
}
|
||||
|
||||
ir_print_encoded_local(f, str_lit("..string"));
|
||||
ir_fprintf(f, " = type {i8*, ");
|
||||
ir_print_type(f, m, t_int);
|
||||
@@ -1368,6 +1422,8 @@ void print_llvm_ir(irGen *ir) {
|
||||
ir_print_type(f, m, t_rawptr);
|
||||
ir_fprintf(f, "} ; Basic_any\n");
|
||||
|
||||
ir_fprintf(f, "declare void @llvm.dbg.declare(metadata, metadata, metadata) nounwind readnone \n");
|
||||
|
||||
|
||||
for_array(member_index, m->members.entries) {
|
||||
MapIrValueEntry *entry = &m->members.entries.e[member_index];
|
||||
@@ -1420,6 +1476,9 @@ void print_llvm_ir(irGen *ir) {
|
||||
}
|
||||
ir_print_encoded_global(f, g->entity->token.string, in_global_scope);
|
||||
ir_fprintf(f, " = ");
|
||||
if (g->is_foreign) {
|
||||
ir_fprintf(f, "external ");
|
||||
}
|
||||
if (g->is_thread_local) {
|
||||
ir_fprintf(f, "thread_local ");
|
||||
}
|
||||
@@ -1439,19 +1498,30 @@ void print_llvm_ir(irGen *ir) {
|
||||
|
||||
ir_print_type(f, m, g->entity->type);
|
||||
ir_fprintf(f, " ");
|
||||
if (g->value != NULL) {
|
||||
ir_print_value(f, m, g->value, g->entity->type);
|
||||
} else {
|
||||
ir_fprintf(f, "zeroinitializer");
|
||||
if (!g->is_foreign) {
|
||||
if (g->value != NULL) {
|
||||
ir_print_value(f, m, g->value, g->entity->type);
|
||||
} else {
|
||||
ir_fprintf(f, "zeroinitializer");
|
||||
}
|
||||
}
|
||||
ir_fprintf(f, "\n");
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
if (m->generate_debug_info) {
|
||||
// if (m->generate_debug_info) {
|
||||
{
|
||||
ir_fprintf(f, "\n");
|
||||
|
||||
i32 diec = m->debug_info.entries.count;
|
||||
|
||||
ir_fprintf(f, "!llvm.dbg.cu = !{!0}\n");
|
||||
ir_fprintf(f, "!llvm.ident = !{!%d}\n", diec+3);
|
||||
ir_fprintf(f, "!%d = !{i32 2, !\"Dwarf Version\", i32 4}\n", diec+0);
|
||||
ir_fprintf(f, "!%d = !{i32 2, !\"Debug Info Version\", i32 3}\n", diec+1);
|
||||
ir_fprintf(f, "!%d = !{i32 1, !\"PIC Level\", i32 2}\n", diec+2);
|
||||
ir_fprintf(f, "!%d = !{!\"clang version 3.9.0 (branches/release_39)\"}\n", diec+3);
|
||||
|
||||
for_array(di_index, m->debug_info.entries) {
|
||||
MapIrDebugInfoEntry *entry = &m->debug_info.entries.e[di_index];
|
||||
@@ -1460,19 +1530,18 @@ void print_llvm_ir(irGen *ir) {
|
||||
|
||||
switch (di->kind) {
|
||||
case irDebugInfo_CompileUnit: {
|
||||
auto *cu = &di->CompileUnit;
|
||||
irDebugInfo *file = *map_ir_debug_info_get(&m->debug_info, hash_pointer(cu->file));
|
||||
irDebugInfo *file = *map_ir_debug_info_get(&m->debug_info, hash_pointer(di->CompileUnit.file));
|
||||
ir_fprintf(f,
|
||||
"distinct !DICompileUnit("
|
||||
"language: DW_LANG_Go, " // Is this good enough?
|
||||
"file: !%d, "
|
||||
"producer: \"%.*s\", "
|
||||
"producer: \"clang version 3.9.0 (branches/release_39)\", "
|
||||
"flags: \"\", "
|
||||
"runtimeVersion: 0, "
|
||||
"isOptimized: false, "
|
||||
"emissionKind: FullDebug"
|
||||
")",
|
||||
file->id, LIT(cu->producer));
|
||||
file->id);
|
||||
|
||||
} break;
|
||||
case irDebugInfo_File:
|
||||
|
||||
+82
-29
@@ -2,22 +2,23 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define USE_CUSTOM_BACKEND false
|
||||
|
||||
#include "common.c"
|
||||
#include "timings.c"
|
||||
#include "unicode.c"
|
||||
#include "build.c"
|
||||
#include "build_settings.c"
|
||||
#include "tokenizer.c"
|
||||
#include "parser.c"
|
||||
// #include "printer.c"
|
||||
#include "checker/checker.c"
|
||||
// #include "ssa.c"
|
||||
#include "checker.c"
|
||||
#include "ssa.c"
|
||||
#include "ir.c"
|
||||
#include "ir_opt.c"
|
||||
#include "ir_print.c"
|
||||
// #include "vm.c"
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
// NOTE(bill): `name` is used in debugging and profiling modes
|
||||
i32 win32_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
|
||||
i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
|
||||
STARTUPINFOW start_info = {gb_size_of(STARTUPINFOW)};
|
||||
PROCESS_INFORMATION pi = {0};
|
||||
char cmd_line[4096] = {0};
|
||||
@@ -59,6 +60,54 @@ i32 win32_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
|
||||
gb_temp_arena_memory_end(tmp);
|
||||
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, ...) {
|
||||
|
||||
char cmd_line[4096] = {0};
|
||||
isize cmd_len;
|
||||
va_list va;
|
||||
String cmd;
|
||||
i32 exit_code = 0;
|
||||
|
||||
va_start(va, fmt);
|
||||
cmd_len = gb_snprintf_va(cmd_line, gb_size_of(cmd_line), fmt, va);
|
||||
va_end(va);
|
||||
cmd = make_string(cast(u8 *)&cmd_line, cmd_len-1);
|
||||
|
||||
exit_code = system(&cmd_line[0]);
|
||||
|
||||
// pid_t pid = fork();
|
||||
// int status = 0;
|
||||
|
||||
// if(pid == 0) {
|
||||
// // in child, pid == 0.
|
||||
// int ret = execvp(cmd.text, (char* const*) cmd.text);
|
||||
|
||||
// if(ret == -1) {
|
||||
// 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) {
|
||||
@@ -92,14 +141,15 @@ int main(int argc, char **argv) {
|
||||
timings_init(&timings, str_lit("Total Time"), 128);
|
||||
// defer (timings_destroy(&timings));
|
||||
init_string_buffer_memory();
|
||||
init_scratch_memory(gb_megabytes(10));
|
||||
init_global_error_collector();
|
||||
|
||||
|
||||
#if 1
|
||||
|
||||
BuildContext build_context = {0};
|
||||
init_build_context(&build_context);
|
||||
init_build_context();
|
||||
|
||||
init_universal_scope(&build_context);
|
||||
init_universal_scope();
|
||||
|
||||
char *init_filename = NULL;
|
||||
bool run_output = false;
|
||||
@@ -159,7 +209,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
|
||||
#endif
|
||||
#if 0
|
||||
#if USE_CUSTOM_BACKEND
|
||||
if (global_error_collector.count != 0) {
|
||||
return 1;
|
||||
}
|
||||
@@ -168,12 +218,12 @@ int main(int argc, char **argv) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
ssa_generate(&checker.info, &build_context);
|
||||
#endif
|
||||
#if 1
|
||||
|
||||
if (!ssa_generate(&parser, &checker.info)) {
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
irGen ir_gen = {0};
|
||||
if (!ir_gen_init(&ir_gen, &checker, &build_context)) {
|
||||
if (!ir_gen_init(&ir_gen, &checker)) {
|
||||
return 1;
|
||||
}
|
||||
// defer (ssa_gen_destroy(&ir_gen));
|
||||
@@ -189,7 +239,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
// prof_print_all();
|
||||
|
||||
#if 1
|
||||
#if 1
|
||||
timings_start_section(&timings, str_lit("llvm-opt"));
|
||||
|
||||
char const *output_name = ir_gen.output_file.filename;
|
||||
@@ -201,8 +251,8 @@ int main(int argc, char **argv) {
|
||||
|
||||
i32 exit_code = 0;
|
||||
// For more passes arguments: http://llvm.org/docs/Passes.html
|
||||
exit_code = win32_exec_command_line_app("llvm-opt", false,
|
||||
"%.*sbin/opt %s -o %.*s.bc "
|
||||
exit_code = system_exec_command_line_app("llvm-opt", false,
|
||||
"\"%.*sbin/opt\" \"%s\" -o \"%.*s\".bc "
|
||||
"-mem2reg "
|
||||
"-memcpyopt "
|
||||
"-die "
|
||||
@@ -216,11 +266,11 @@ int main(int argc, char **argv) {
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
#if 1
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
timings_start_section(&timings, str_lit("llvm-llc"));
|
||||
// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
|
||||
exit_code = win32_exec_command_line_app("llvm-llc", false,
|
||||
"%.*sbin/llc %.*s.bc -filetype=obj -O%d "
|
||||
exit_code = system_exec_command_line_app("llvm-llc", false,
|
||||
"\"%.*sbin/llc\" \"%.*s.bc\" -filetype=obj -O%d "
|
||||
"%.*s "
|
||||
// "-debug-pass=Arguments "
|
||||
"",
|
||||
@@ -234,13 +284,14 @@ int main(int argc, char **argv) {
|
||||
|
||||
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));
|
||||
char lib_str_buf[1024] = {0};
|
||||
for_array(i, checker.info.foreign_libraries) {
|
||||
String lib = checker.info.foreign_libraries.e[i];
|
||||
for_array(i, ir_gen.module.foreign_library_paths) {
|
||||
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),
|
||||
" %.*s.lib", LIT(lib));
|
||||
" \"%.*s\"", LIT(lib));
|
||||
lib_str = gb_string_appendc(lib_str, lib_str_buf);
|
||||
}
|
||||
|
||||
@@ -253,8 +304,8 @@ int main(int argc, char **argv) {
|
||||
link_settings = "/ENTRY:mainCRTStartup";
|
||||
}
|
||||
|
||||
exit_code = win32_exec_command_line_app("msvc-link", true,
|
||||
"link %.*s.obj -OUT:%.*s.%s %s "
|
||||
exit_code = system_exec_command_line_app("msvc-link", true,
|
||||
"link \"%.*s\".obj -OUT:\"%.*s.%s\" %s "
|
||||
"/defaultlib:libcmt "
|
||||
"/nologo /incremental:no /opt:ref /subsystem:CONSOLE "
|
||||
" %.*s "
|
||||
@@ -271,14 +322,16 @@ int main(int argc, char **argv) {
|
||||
// timings_print_all(&timings);
|
||||
|
||||
if (run_output) {
|
||||
win32_exec_command_line_app("odin run", false, "%.*s.exe", cast(int)base_name_len, output_name);
|
||||
system_exec_command_line_app("odin run", false, "%.*s.exe", cast(int)base_name_len, output_name);
|
||||
}
|
||||
|
||||
#else
|
||||
#error Implement build stuff for this platform
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
#define MAP_NAME MapString
|
||||
#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
|
||||
#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) {
|
||||
_J2(MAP_PROC,grow)(h);
|
||||
}
|
||||
// Make
|
||||
fr = _J2(MAP_PROC,_find)(h, key);
|
||||
i = _J2(MAP_PROC,_add_entry)(h, key);
|
||||
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].value = value;
|
||||
// Grow if needed
|
||||
if (_J2(MAP_PROC,_full)(h)) {
|
||||
_J2(MAP_PROC,grow)(h);
|
||||
}
|
||||
|
||||
+1341
-941
File diff suppressed because it is too large
Load Diff
+277
@@ -0,0 +1,277 @@
|
||||
#define SSA_OPS \
|
||||
SSA_OP(Invalid)\
|
||||
\
|
||||
SSA_OP(Unknown)\
|
||||
\
|
||||
SSA_OP(Comment) /* Does nothing */\
|
||||
\
|
||||
SSA_OP(SP) /* Stack Pointer */\
|
||||
SSA_OP(SB) /* Stack Base */\
|
||||
SSA_OP(Addr) /* Address of something - special rules for certain types when loading and storing (e.g. Maps) */\
|
||||
\
|
||||
SSA_OP(Local)\
|
||||
SSA_OP(Global)\
|
||||
SSA_OP(Proc)\
|
||||
\
|
||||
SSA_OP(Load)\
|
||||
SSA_OP(Store)\
|
||||
SSA_OP(Move)\
|
||||
SSA_OP(LoadReg)\
|
||||
SSA_OP(StoreReg)\
|
||||
SSA_OP(Zero) /* Zero initialize */\
|
||||
\
|
||||
SSA_OP(ArrayIndex) /* Index for a fixed array */\
|
||||
SSA_OP(PtrIndex) /* Index for a struct/tuple/etc */\
|
||||
SSA_OP(PtrOffset)\
|
||||
SSA_OP(ValueIndex) /* Extract for a value from a register */\
|
||||
\
|
||||
SSA_OP(Phi)\
|
||||
SSA_OP(Copy)\
|
||||
\
|
||||
/* TODO(bill): calling conventions */\
|
||||
SSA_OP(CallOdin)\
|
||||
SSA_OP(CallC)\
|
||||
SSA_OP(CallStd)\
|
||||
SSA_OP(CallFast)\
|
||||
\
|
||||
SSA_OP(BoundsCheck)\
|
||||
SSA_OP(SliceBoundsCheck)\
|
||||
\
|
||||
/* Built in operations/procedures */\
|
||||
SSA_OP(Bswap16)\
|
||||
SSA_OP(Bswap32)\
|
||||
SSA_OP(Bswap64)\
|
||||
\
|
||||
SSA_OP(Assume)\
|
||||
SSA_OP(DebugTrap)\
|
||||
SSA_OP(Trap)\
|
||||
SSA_OP(ReadCycleCounter)\
|
||||
\
|
||||
\
|
||||
SSA_OP(ConstBool)\
|
||||
SSA_OP(ConstString)\
|
||||
SSA_OP(ConstSlice)\
|
||||
SSA_OP(ConstNil)\
|
||||
SSA_OP(Const8)\
|
||||
SSA_OP(Const16)\
|
||||
SSA_OP(Const32)\
|
||||
SSA_OP(Const64)\
|
||||
SSA_OP(Const32F)\
|
||||
SSA_OP(Const64F)\
|
||||
\
|
||||
/* These should be all the operations I could possibly need for the mean time */\
|
||||
SSA_OP(Add8)\
|
||||
SSA_OP(Add16)\
|
||||
SSA_OP(Add32)\
|
||||
SSA_OP(Add64)\
|
||||
SSA_OP(AddPtr)\
|
||||
SSA_OP(Add32F)\
|
||||
SSA_OP(Add64F)\
|
||||
SSA_OP(Sub8)\
|
||||
SSA_OP(Sub16)\
|
||||
SSA_OP(Sub32)\
|
||||
SSA_OP(Sub64)\
|
||||
SSA_OP(SubPtr)\
|
||||
SSA_OP(Sub32F)\
|
||||
SSA_OP(Sub64F)\
|
||||
SSA_OP(Mul8)\
|
||||
SSA_OP(Mul16)\
|
||||
SSA_OP(Mul32)\
|
||||
SSA_OP(Mul64)\
|
||||
SSA_OP(Mul32F)\
|
||||
SSA_OP(Mul64F)\
|
||||
SSA_OP(Div8)\
|
||||
SSA_OP(Div8U)\
|
||||
SSA_OP(Div16)\
|
||||
SSA_OP(Div16U)\
|
||||
SSA_OP(Div32)\
|
||||
SSA_OP(Div32U)\
|
||||
SSA_OP(Div64)\
|
||||
SSA_OP(Div64U)\
|
||||
SSA_OP(Div32F)\
|
||||
SSA_OP(Div64F)\
|
||||
SSA_OP(Mod8)\
|
||||
SSA_OP(Mod8U)\
|
||||
SSA_OP(Mod16)\
|
||||
SSA_OP(Mod16U)\
|
||||
SSA_OP(Mod32)\
|
||||
SSA_OP(Mod32U)\
|
||||
SSA_OP(Mod64)\
|
||||
SSA_OP(Mod64U)\
|
||||
\
|
||||
SSA_OP(And8)\
|
||||
SSA_OP(And16)\
|
||||
SSA_OP(And32)\
|
||||
SSA_OP(And64)\
|
||||
SSA_OP(Or8)\
|
||||
SSA_OP(Or16)\
|
||||
SSA_OP(Or32)\
|
||||
SSA_OP(Or64)\
|
||||
SSA_OP(Xor8)\
|
||||
SSA_OP(Xor16)\
|
||||
SSA_OP(Xor32)\
|
||||
SSA_OP(Xor64)\
|
||||
SSA_OP(AndNot8)\
|
||||
SSA_OP(AndNot16)\
|
||||
SSA_OP(AndNot32)\
|
||||
SSA_OP(AndNot64)\
|
||||
\
|
||||
SSA_OP(Lsh8x8)\
|
||||
SSA_OP(Lsh8x16)\
|
||||
SSA_OP(Lsh8x32)\
|
||||
SSA_OP(Lsh8x64)\
|
||||
SSA_OP(Lsh16x8)\
|
||||
SSA_OP(Lsh16x16)\
|
||||
SSA_OP(Lsh16x32)\
|
||||
SSA_OP(Lsh16x64)\
|
||||
SSA_OP(Lsh32x8)\
|
||||
SSA_OP(Lsh32x16)\
|
||||
SSA_OP(Lsh32x32)\
|
||||
SSA_OP(Lsh32x64)\
|
||||
SSA_OP(Lsh64x8)\
|
||||
SSA_OP(Lsh64x16)\
|
||||
SSA_OP(Lsh64x32)\
|
||||
SSA_OP(Lsh64x64)\
|
||||
SSA_OP(Rsh8x8)\
|
||||
SSA_OP(Rsh8x16)\
|
||||
SSA_OP(Rsh8x32)\
|
||||
SSA_OP(Rsh8x64)\
|
||||
SSA_OP(Rsh16x8)\
|
||||
SSA_OP(Rsh16x16)\
|
||||
SSA_OP(Rsh16x32)\
|
||||
SSA_OP(Rsh16x64)\
|
||||
SSA_OP(Rsh32x8)\
|
||||
SSA_OP(Rsh32x16)\
|
||||
SSA_OP(Rsh32x32)\
|
||||
SSA_OP(Rsh32x64)\
|
||||
SSA_OP(Rsh64x8)\
|
||||
SSA_OP(Rsh64x16)\
|
||||
SSA_OP(Rsh64x32)\
|
||||
SSA_OP(Rsh64x64)\
|
||||
SSA_OP(Rsh8Ux8)\
|
||||
SSA_OP(Rsh8Ux16)\
|
||||
SSA_OP(Rsh8Ux32)\
|
||||
SSA_OP(Rsh8Ux64)\
|
||||
SSA_OP(Rsh16Ux8)\
|
||||
SSA_OP(Rsh16Ux16)\
|
||||
SSA_OP(Rsh16Ux32)\
|
||||
SSA_OP(Rsh16Ux64)\
|
||||
SSA_OP(Rsh32Ux8)\
|
||||
SSA_OP(Rsh32Ux16)\
|
||||
SSA_OP(Rsh32Ux32)\
|
||||
SSA_OP(Rsh32Ux64)\
|
||||
SSA_OP(Rsh64Ux8)\
|
||||
SSA_OP(Rsh64Ux16)\
|
||||
SSA_OP(Rsh64Ux32)\
|
||||
SSA_OP(Rsh64Ux64)\
|
||||
\
|
||||
SSA_OP(Eq8)\
|
||||
SSA_OP(Eq16)\
|
||||
SSA_OP(Eq32)\
|
||||
SSA_OP(Eq64)\
|
||||
SSA_OP(EqPtr)\
|
||||
SSA_OP(Eq32F)\
|
||||
SSA_OP(Eq64F)\
|
||||
SSA_OP(Ne8)\
|
||||
SSA_OP(Ne16)\
|
||||
SSA_OP(Ne32)\
|
||||
SSA_OP(Ne64)\
|
||||
SSA_OP(NePtr)\
|
||||
SSA_OP(Ne32F)\
|
||||
SSA_OP(Ne64F)\
|
||||
SSA_OP(Lt8)\
|
||||
SSA_OP(Lt16)\
|
||||
SSA_OP(Lt32)\
|
||||
SSA_OP(Lt64)\
|
||||
SSA_OP(LtPtr)\
|
||||
SSA_OP(Lt32F)\
|
||||
SSA_OP(Lt64F)\
|
||||
SSA_OP(Gt8)\
|
||||
SSA_OP(Gt16)\
|
||||
SSA_OP(Gt32)\
|
||||
SSA_OP(Gt64)\
|
||||
SSA_OP(GtPtr)\
|
||||
SSA_OP(Gt32F)\
|
||||
SSA_OP(Gt64F)\
|
||||
SSA_OP(Le8)\
|
||||
SSA_OP(Le16)\
|
||||
SSA_OP(Le32)\
|
||||
SSA_OP(Le64)\
|
||||
SSA_OP(LePtr)\
|
||||
SSA_OP(Le32F)\
|
||||
SSA_OP(Le64F)\
|
||||
SSA_OP(Ge8)\
|
||||
SSA_OP(Ge16)\
|
||||
SSA_OP(Ge32)\
|
||||
SSA_OP(Ge64)\
|
||||
SSA_OP(GePtr)\
|
||||
SSA_OP(Ge32F)\
|
||||
SSA_OP(Ge64F)\
|
||||
\
|
||||
SSA_OP(NotB)\
|
||||
SSA_OP(EqB)\
|
||||
SSA_OP(NeB)\
|
||||
\
|
||||
SSA_OP(Neg8)\
|
||||
SSA_OP(Neg16)\
|
||||
SSA_OP(Neg32)\
|
||||
SSA_OP(Neg64)\
|
||||
SSA_OP(Neg32F)\
|
||||
SSA_OP(Neg64F)\
|
||||
\
|
||||
SSA_OP(Not8)\
|
||||
SSA_OP(Not16)\
|
||||
SSA_OP(Not32)\
|
||||
SSA_OP(Not64)\
|
||||
\
|
||||
SSA_OP(SignExt8to16)\
|
||||
SSA_OP(SignExt8to32)\
|
||||
SSA_OP(SignExt8to64)\
|
||||
SSA_OP(SignExt16to32)\
|
||||
SSA_OP(SignExt16to64)\
|
||||
SSA_OP(SignExt32to64)\
|
||||
SSA_OP(ZeroExt8to16)\
|
||||
SSA_OP(ZeroExt8to32)\
|
||||
SSA_OP(ZeroExt8to64)\
|
||||
SSA_OP(ZeroExt16to32)\
|
||||
SSA_OP(ZeroExt16to64)\
|
||||
SSA_OP(ZeroExt32to64)\
|
||||
SSA_OP(Trunc16to8)\
|
||||
SSA_OP(Trunc32to8)\
|
||||
SSA_OP(Trunc32to16)\
|
||||
SSA_OP(Trunc64to8)\
|
||||
SSA_OP(Trunc64to16)\
|
||||
SSA_OP(Trunc64to32)\
|
||||
\
|
||||
SSA_OP(Cvt32to32F)\
|
||||
SSA_OP(Cvt32to64F)\
|
||||
SSA_OP(Cvt64to32F)\
|
||||
SSA_OP(Cvt64to64F)\
|
||||
SSA_OP(Cvt32Fto32)\
|
||||
SSA_OP(Cvt32Fto64)\
|
||||
SSA_OP(Cvt64Fto32)\
|
||||
SSA_OP(Cvt64Fto64)\
|
||||
SSA_OP(Cvt32Fto64F)\
|
||||
SSA_OP(Cvt64Fto32F)\
|
||||
SSA_OP(Cvt32Uto32F)\
|
||||
SSA_OP(Cvt32Uto64F)\
|
||||
SSA_OP(Cvt32Fto32U)\
|
||||
SSA_OP(Cvt64Fto32U)\
|
||||
SSA_OP(Cvt64Uto32F)\
|
||||
SSA_OP(Cvt64Uto64F)\
|
||||
SSA_OP(Cvt32Fto64U)\
|
||||
SSA_OP(Cvt64Fto64U)\
|
||||
|
||||
|
||||
enum ssaOp {
|
||||
#define SSA_OP(k) GB_JOIN2(ssaOp_, k),
|
||||
SSA_OPS
|
||||
#undef SSA_OP
|
||||
};
|
||||
typedef enum ssaOp ssaOp;
|
||||
|
||||
String const ssa_op_strings[] = {
|
||||
#define SSA_OP(k) {cast(u8 *)#k, gb_size_of(#k)-1},
|
||||
SSA_OPS
|
||||
#undef SSA_OP
|
||||
};
|
||||
+76
-17
@@ -15,8 +15,11 @@ typedef struct String {
|
||||
} String;
|
||||
// NOTE(bill): used for printf style arguments
|
||||
#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 {
|
||||
wchar_t *text;
|
||||
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));
|
||||
}
|
||||
|
||||
#define str_lit(c_str) make_string(cast(u8 *)c_str, gb_size_of(c_str)-1)
|
||||
|
||||
|
||||
|
||||
@@ -144,16 +146,37 @@ gb_inline isize string_extension_position(String str) {
|
||||
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) {
|
||||
if (str.len > ext.len+1) {
|
||||
u8 *s = str.text+str.len - ext.len-1;
|
||||
if (s[0] == '.') {
|
||||
s++;
|
||||
return gb_memcompare(s, ext.text, ext.len) == 0;
|
||||
}
|
||||
str = string_trim_whitespace(str);
|
||||
if (str.len <= ext.len+1) {
|
||||
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) {
|
||||
@@ -165,6 +188,47 @@ bool string_contains_char(String s, u8 c) {
|
||||
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
|
||||
String16 string_to_string16(gbAllocator a, String s) {
|
||||
int len, len1;
|
||||
@@ -174,16 +238,14 @@ String16 string_to_string16(gbAllocator a, String s) {
|
||||
return make_string16(NULL, 0);
|
||||
}
|
||||
|
||||
len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
|
||||
cast(char *)s.text, s.len, NULL, 0);
|
||||
len = convert_multibyte_to_widechar(cast(char *)s.text, s.len, NULL, 0);
|
||||
if (len == 0) {
|
||||
return make_string16(NULL, 0);
|
||||
}
|
||||
|
||||
text = gb_alloc_array(a, wchar_t, len+1);
|
||||
|
||||
len1 = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
|
||||
cast(char *)s.text, s.len, text, len);
|
||||
len1 = convert_multibyte_to_widechar(cast(char *)s.text, s.len, text, len);
|
||||
if (len1 == 0) {
|
||||
gb_free(a, text);
|
||||
return make_string16(NULL, 0);
|
||||
@@ -201,16 +263,14 @@ String string16_to_string(gbAllocator a, String16 s) {
|
||||
return make_string(NULL, 0);
|
||||
}
|
||||
|
||||
len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
|
||||
s.text, s.len, NULL, 0, NULL, NULL);
|
||||
len = convert_widechar_to_multibyte(s.text, s.len, NULL, 0);
|
||||
if (len == 0) {
|
||||
return make_string(NULL, 0);
|
||||
}
|
||||
|
||||
text = gb_alloc_array(a, u8, len+1);
|
||||
|
||||
len1 = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
|
||||
s.text, s.len, cast(char *)text, len, NULL, NULL);
|
||||
len1 = convert_widechar_to_multibyte(s.text, s.len, cast(char *)text, len);
|
||||
if (len1 == 0) {
|
||||
gb_free(a, text);
|
||||
return make_string(NULL, 0);
|
||||
@@ -236,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) {
|
||||
u8 c;
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ typedef struct Timings {
|
||||
} Timings;
|
||||
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
u64 win32_time_stamp_time_now(void) {
|
||||
LARGE_INTEGER counter;
|
||||
QueryPerformanceCounter(&counter);
|
||||
@@ -27,9 +28,44 @@ u64 win32_time_stamp__freq(void) {
|
||||
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) {
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
return win32_time_stamp_time_now();
|
||||
#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
|
||||
return unix_time_stamp_time_now();
|
||||
#else
|
||||
#error time_stamp_time_now
|
||||
#endif
|
||||
@@ -38,6 +74,8 @@ u64 time_stamp_time_now(void) {
|
||||
u64 time_stamp__freq(void) {
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
return win32_time_stamp__freq();
|
||||
#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
|
||||
return unix_time_stamp__freq();
|
||||
#else
|
||||
#error time_stamp__freq
|
||||
#endif
|
||||
|
||||
+168
-183
@@ -1,113 +1,118 @@
|
||||
#define TOKEN_KINDS \
|
||||
TOKEN_KIND(Token_Invalid, "Invalid"), \
|
||||
TOKEN_KIND(Token_EOF, "EOF"), \
|
||||
TOKEN_KIND(Token_EOF, "EOF"), \
|
||||
TOKEN_KIND(Token_Comment, "Comment"), \
|
||||
\
|
||||
TOKEN_KIND(Token__LiteralBegin, "_LiteralBegin"), \
|
||||
TOKEN_KIND(Token_Ident, "identifier"), \
|
||||
TOKEN_KIND(Token_Integer, "integer"), \
|
||||
TOKEN_KIND(Token_Float, "float"), \
|
||||
TOKEN_KIND(Token_Rune, "rune"), \
|
||||
TOKEN_KIND(Token_String, "string"), \
|
||||
TOKEN_KIND(Token__LiteralEnd, "_LiteralEnd"), \
|
||||
TOKEN_KIND(Token_Ident, "identifier"), \
|
||||
TOKEN_KIND(Token_Integer, "integer"), \
|
||||
TOKEN_KIND(Token_Float, "float"), \
|
||||
TOKEN_KIND(Token_Rune, "rune"), \
|
||||
TOKEN_KIND(Token_String, "string"), \
|
||||
TOKEN_KIND(Token__LiteralEnd, "_LiteralEnd"), \
|
||||
\
|
||||
TOKEN_KIND(Token__OperatorBegin, "_OperatorBegin"), \
|
||||
TOKEN_KIND(Token_Eq, "="), \
|
||||
TOKEN_KIND(Token_Not, "!"), \
|
||||
TOKEN_KIND(Token_Hash, "#"), \
|
||||
TOKEN_KIND(Token_At, "@"), \
|
||||
TOKEN_KIND(Token_Pointer, "^"), \
|
||||
TOKEN_KIND(Token_Maybe, "?"), \
|
||||
TOKEN_KIND(Token_Add, "+"), \
|
||||
TOKEN_KIND(Token_Sub, "-"), \
|
||||
TOKEN_KIND(Token_Mul, "*"), \
|
||||
TOKEN_KIND(Token_Quo, "/"), \
|
||||
TOKEN_KIND(Token_Mod, "%"), \
|
||||
TOKEN_KIND(Token_And, "&"), \
|
||||
TOKEN_KIND(Token_Or, "|"), \
|
||||
TOKEN_KIND(Token_Xor, "~"), \
|
||||
TOKEN_KIND(Token_AndNot, "&~"), \
|
||||
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_Eq, "="), \
|
||||
TOKEN_KIND(Token_Not, "!"), \
|
||||
TOKEN_KIND(Token_Hash, "#"), \
|
||||
TOKEN_KIND(Token_At, "@"), \
|
||||
TOKEN_KIND(Token_Dollar, "$"), \
|
||||
TOKEN_KIND(Token_Pointer, "^"), \
|
||||
TOKEN_KIND(Token_Question, "?"), \
|
||||
TOKEN_KIND(Token_Add, "+"), \
|
||||
TOKEN_KIND(Token_Sub, "-"), \
|
||||
TOKEN_KIND(Token_Mul, "*"), \
|
||||
TOKEN_KIND(Token_Quo, "/"), \
|
||||
TOKEN_KIND(Token_Mod, "%"), \
|
||||
TOKEN_KIND(Token_And, "&"), \
|
||||
TOKEN_KIND(Token_Or, "|"), \
|
||||
TOKEN_KIND(Token_Xor, "~"), \
|
||||
TOKEN_KIND(Token_AndNot, "&~"), \
|
||||
TOKEN_KIND(Token_Shl, "<<"), \
|
||||
TOKEN_KIND(Token_Shr, ">>"), \
|
||||
\
|
||||
TOKEN_KIND(Token_CmpAnd, "&&"), \
|
||||
TOKEN_KIND(Token_CmpOr, "||"), \
|
||||
TOKEN_KIND(Token_CmpOr, "||"), \
|
||||
\
|
||||
TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \
|
||||
TOKEN_KIND(Token_AddEq, "+="), \
|
||||
TOKEN_KIND(Token_SubEq, "-="), \
|
||||
TOKEN_KIND(Token_MulEq, "*="), \
|
||||
TOKEN_KIND(Token_QuoEq, "/="), \
|
||||
TOKEN_KIND(Token_ModEq, "%="), \
|
||||
TOKEN_KIND(Token_AndEq, "&="), \
|
||||
TOKEN_KIND(Token_OrEq, "|="), \
|
||||
TOKEN_KIND(Token_XorEq, "~="), \
|
||||
TOKEN_KIND(Token_AndNotEq, "&~="), \
|
||||
TOKEN_KIND(Token_ShlEq, "<<="), \
|
||||
TOKEN_KIND(Token_ShrEq, ">>="), \
|
||||
TOKEN_KIND(Token_CmpAndEq, "&&="), \
|
||||
TOKEN_KIND(Token_CmpOrEq, "||="), \
|
||||
TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \
|
||||
TOKEN_KIND(Token_AddEq, "+="), \
|
||||
TOKEN_KIND(Token_SubEq, "-="), \
|
||||
TOKEN_KIND(Token_MulEq, "*="), \
|
||||
TOKEN_KIND(Token_QuoEq, "/="), \
|
||||
TOKEN_KIND(Token_ModEq, "%="), \
|
||||
TOKEN_KIND(Token_AndEq, "&="), \
|
||||
TOKEN_KIND(Token_OrEq, "|="), \
|
||||
TOKEN_KIND(Token_XorEq, "~="), \
|
||||
TOKEN_KIND(Token_AndNotEq, "&~="), \
|
||||
TOKEN_KIND(Token_ShlEq, "<<="), \
|
||||
TOKEN_KIND(Token_ShrEq, ">>="), \
|
||||
TOKEN_KIND(Token_CmpAndEq, "&&="), \
|
||||
TOKEN_KIND(Token_CmpOrEq, "||="), \
|
||||
TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \
|
||||
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_CmpEq, "=="), \
|
||||
TOKEN_KIND(Token_NotEq, "!="), \
|
||||
TOKEN_KIND(Token_Lt, "<"), \
|
||||
TOKEN_KIND(Token_Gt, ">"), \
|
||||
TOKEN_KIND(Token_LtEq, "<="), \
|
||||
TOKEN_KIND(Token_GtEq, ">="), \
|
||||
TOKEN_KIND(Token_Lt, "<"), \
|
||||
TOKEN_KIND(Token_Gt, ">"), \
|
||||
TOKEN_KIND(Token_LtEq, "<="), \
|
||||
TOKEN_KIND(Token_GtEq, ">="), \
|
||||
TOKEN_KIND(Token__ComparisonEnd, "_ComparisonEnd"), \
|
||||
\
|
||||
TOKEN_KIND(Token_OpenParen, "("), \
|
||||
TOKEN_KIND(Token_CloseParen, ")"), \
|
||||
TOKEN_KIND(Token_OpenBracket, "["), \
|
||||
TOKEN_KIND(Token_CloseBracket, "]"), \
|
||||
TOKEN_KIND(Token_OpenBrace, "{"), \
|
||||
TOKEN_KIND(Token_CloseBrace, "}"), \
|
||||
TOKEN_KIND(Token_Colon, ":"), \
|
||||
TOKEN_KIND(Token_Semicolon, ";"), \
|
||||
TOKEN_KIND(Token_Period, "."), \
|
||||
TOKEN_KIND(Token_Comma, ","), \
|
||||
TOKEN_KIND(Token_Ellipsis, "..."), \
|
||||
TOKEN_KIND(Token_Interval, "..<"), \
|
||||
TOKEN_KIND(Token_OpenParen, "("), \
|
||||
TOKEN_KIND(Token_CloseParen, ")"), \
|
||||
TOKEN_KIND(Token_OpenBracket, "["), \
|
||||
TOKEN_KIND(Token_CloseBracket, "]"), \
|
||||
TOKEN_KIND(Token_OpenBrace, "{"), \
|
||||
TOKEN_KIND(Token_CloseBrace, "}"), \
|
||||
TOKEN_KIND(Token_Colon, ":"), \
|
||||
TOKEN_KIND(Token_Semicolon, ";"), \
|
||||
TOKEN_KIND(Token_Period, "."), \
|
||||
TOKEN_KIND(Token_Comma, ","), \
|
||||
TOKEN_KIND(Token_Ellipsis, ".."), \
|
||||
/* TOKEN_KIND(Token_HalfOpenRange, "..<"), */ \
|
||||
TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \
|
||||
\
|
||||
TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
||||
TOKEN_KIND(Token_type, "type"), \
|
||||
TOKEN_KIND(Token_proc, "proc"), \
|
||||
TOKEN_KIND(Token_macro, "macro"), \
|
||||
TOKEN_KIND(Token_match, "match"), \
|
||||
TOKEN_KIND(Token_break, "break"), \
|
||||
TOKEN_KIND(Token_continue, "continue"), \
|
||||
TOKEN_KIND(Token_fallthrough, "fallthrough"), \
|
||||
TOKEN_KIND(Token_case, "case"), \
|
||||
TOKEN_KIND(Token_default, "default"), \
|
||||
TOKEN_KIND(Token_then, "then"), \
|
||||
TOKEN_KIND(Token_if, "if"), \
|
||||
TOKEN_KIND(Token_else, "else"), \
|
||||
TOKEN_KIND(Token_while, "while"), \
|
||||
TOKEN_KIND(Token_for, "for"), \
|
||||
TOKEN_KIND(Token_when, "when"), \
|
||||
TOKEN_KIND(Token_range, "range"), \
|
||||
TOKEN_KIND(Token_defer, "defer"), \
|
||||
TOKEN_KIND(Token_return, "return"), \
|
||||
TOKEN_KIND(Token_give, "give"), \
|
||||
TOKEN_KIND(Token_struct, "struct"), \
|
||||
TOKEN_KIND(Token_union, "union"), \
|
||||
TOKEN_KIND(Token_raw_union, "raw_union"), \
|
||||
TOKEN_KIND(Token_enum, "enum"), \
|
||||
TOKEN_KIND(Token_vector, "vector"), \
|
||||
TOKEN_KIND(Token_using, "using"), \
|
||||
TOKEN_KIND(Token_asm, "asm"), \
|
||||
TOKEN_KIND(Token_push_allocator, "push_allocator"), \
|
||||
TOKEN_KIND(Token_push_context, "push_context"), \
|
||||
TOKEN_KIND(Token_when, "when"), \
|
||||
TOKEN_KIND(Token_if, "if"), \
|
||||
TOKEN_KIND(Token_else, "else"), \
|
||||
TOKEN_KIND(Token_for, "for"), \
|
||||
TOKEN_KIND(Token_in, "in"), \
|
||||
TOKEN_KIND(Token_match, "match"), \
|
||||
TOKEN_KIND(Token_default, "default"), \
|
||||
TOKEN_KIND(Token_case, "case"), \
|
||||
TOKEN_KIND(Token_break, "break"), \
|
||||
TOKEN_KIND(Token_continue, "continue"), \
|
||||
TOKEN_KIND(Token_fallthrough, "fallthrough"), \
|
||||
TOKEN_KIND(Token_defer, "defer"), \
|
||||
TOKEN_KIND(Token_return, "return"), \
|
||||
TOKEN_KIND(Token_give, "give"), \
|
||||
TOKEN_KIND(Token_proc, "proc"), \
|
||||
TOKEN_KIND(Token_macro, "macro"), \
|
||||
TOKEN_KIND(Token_struct, "struct"), \
|
||||
TOKEN_KIND(Token_union, "union"), \
|
||||
TOKEN_KIND(Token_raw_union, "raw_union"), \
|
||||
TOKEN_KIND(Token_enum, "enum"), \
|
||||
TOKEN_KIND(Token_vector, "vector"), \
|
||||
TOKEN_KIND(Token_static, "static"), \
|
||||
TOKEN_KIND(Token_dynamic, "dynamic"), \
|
||||
TOKEN_KIND(Token_map, "map"), \
|
||||
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_Count, "")
|
||||
|
||||
@@ -146,7 +151,6 @@ bool token_pos_eq(TokenPos a, TokenPos b) {
|
||||
return token_pos_cmp(a, b) == 0;
|
||||
}
|
||||
|
||||
// NOTE(bill): Text is UTF-8, thus why u8 and not char
|
||||
typedef struct Token {
|
||||
TokenKind kind;
|
||||
String string;
|
||||
@@ -221,6 +225,23 @@ void syntax_error_va(Token token, char *fmt, va_list va) {
|
||||
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;
|
||||
@@ -243,6 +264,13 @@ void syntax_error(Token token, char *fmt, ...) {
|
||||
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, ...) {
|
||||
va_list va;
|
||||
@@ -258,20 +286,20 @@ void compiler_error(char *fmt, ...) {
|
||||
|
||||
|
||||
|
||||
gb_inline bool token_is_literal(Token t) {
|
||||
return gb_is_between(t.kind, Token__LiteralBegin+1, Token__LiteralEnd-1);
|
||||
gb_inline bool token_is_literal(TokenKind t) {
|
||||
return gb_is_between(t, Token__LiteralBegin+1, Token__LiteralEnd-1);
|
||||
}
|
||||
gb_inline bool token_is_operator(Token t) {
|
||||
return gb_is_between(t.kind, Token__OperatorBegin+1, Token__OperatorEnd-1);
|
||||
gb_inline bool token_is_operator(TokenKind t) {
|
||||
return gb_is_between(t, Token__OperatorBegin+1, Token__OperatorEnd-1);
|
||||
}
|
||||
gb_inline bool token_is_keyword(Token t) {
|
||||
return gb_is_between(t.kind, Token__KeywordBegin+1, Token__KeywordEnd-1);
|
||||
gb_inline bool token_is_keyword(TokenKind t) {
|
||||
return gb_is_between(t, Token__KeywordBegin+1, Token__KeywordEnd-1);
|
||||
}
|
||||
gb_inline bool token_is_comparison(Token t) {
|
||||
return gb_is_between(t.kind, Token__ComparisonBegin+1, Token__ComparisonEnd-1);
|
||||
gb_inline bool token_is_comparison(TokenKind t) {
|
||||
return gb_is_between(t, Token__ComparisonBegin+1, Token__ComparisonEnd-1);
|
||||
}
|
||||
gb_inline bool token_is_shift(Token t) {
|
||||
return t.kind == Token_Shl || t.kind == Token_Shr;
|
||||
gb_inline bool token_is_shift(TokenKind t) {
|
||||
return t == Token_Shl || t == Token_Shr;
|
||||
}
|
||||
|
||||
gb_inline void print_token(Token t) { gb_printf("%.*s\n", LIT(t.string)); }
|
||||
@@ -457,15 +485,11 @@ gb_inline i32 digit_value(Rune r) {
|
||||
}
|
||||
|
||||
gb_inline void scan_mantissa(Tokenizer *t, i32 base) {
|
||||
// TODO(bill): Allow for underscores in numbers as a number separator
|
||||
// TODO(bill): Is this a good idea?
|
||||
// while (digit_value(t->curr_rune) < base || t->curr_rune == '_')
|
||||
while (digit_value(t->curr_rune) < base) {
|
||||
while (digit_value(t->curr_rune) < base || t->curr_rune == '_') {
|
||||
advance_to_next_rune(t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) {
|
||||
Token token = {0};
|
||||
token.kind = Token_Integer;
|
||||
@@ -501,6 +525,12 @@ Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) {
|
||||
if (t->curr - prev <= 2) {
|
||||
token.kind = Token_Invalid;
|
||||
}
|
||||
} else if (t->curr_rune == 'z') { // Dozenal
|
||||
advance_to_next_rune(t);
|
||||
scan_mantissa(t, 12);
|
||||
if (t->curr - prev <= 2) {
|
||||
token.kind = Token_Invalid;
|
||||
}
|
||||
} else if (t->curr_rune == 'x') { // Hexadecimal
|
||||
advance_to_next_rune(t);
|
||||
scan_mantissa(t, 16);
|
||||
@@ -528,7 +558,7 @@ fraction:
|
||||
// HACK(bill): This may be inefficient
|
||||
TokenizerState state = save_tokenizer_state(t);
|
||||
advance_to_next_rune(t);
|
||||
if (t->curr_rune == '.') {
|
||||
if (digit_value(t->curr_rune) >= 10) {
|
||||
// TODO(bill): Clean up this shit
|
||||
restore_tokenizer_state(t, &state);
|
||||
goto end;
|
||||
@@ -721,20 +751,10 @@ Token tokenizer_get_token(Tokenizer *t) {
|
||||
|
||||
// NOTE(bill): All keywords are > 1
|
||||
if (token.string.len > 1) {
|
||||
if (str_eq(token.string, token_strings[Token_as])) {
|
||||
token.kind = Token_as;
|
||||
} else if (str_eq(token.string, token_strings[Token_transmute])) {
|
||||
token.kind = Token_transmute;
|
||||
} 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;
|
||||
}
|
||||
for (i32 k = Token__KeywordBegin+1; k < Token__KeywordEnd; k++) {
|
||||
if (str_eq(token.string, token_strings[k])) {
|
||||
token.kind = cast(TokenKind)k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -836,71 +856,38 @@ Token tokenizer_get_token(Tokenizer *t) {
|
||||
|
||||
case '.':
|
||||
token.kind = Token_Period; // Default
|
||||
if (gb_is_between(t->curr_rune, '0', '9')) { // Might be a number
|
||||
token = scan_number_to_token(t, true);
|
||||
} else if (t->curr_rune == '.') { // Could be an ellipsis
|
||||
if (t->curr_rune == '.') { // Could be an ellipsis
|
||||
advance_to_next_rune(t);
|
||||
if (t->curr_rune == '.') {
|
||||
advance_to_next_rune(t);
|
||||
token.kind = Token_Ellipsis;
|
||||
} else if (t->curr_rune == '<') {
|
||||
advance_to_next_rune(t);
|
||||
token.kind = Token_Interval;
|
||||
}
|
||||
token.kind = Token_Ellipsis;
|
||||
// if (t->curr_rune == '<') {
|
||||
// advance_to_next_rune(t);
|
||||
// token.kind = Token_HalfOpenRange;
|
||||
// }
|
||||
}
|
||||
break;
|
||||
|
||||
case '#':
|
||||
token.kind = Token_Hash;
|
||||
break;
|
||||
case '@':
|
||||
token.kind = Token_At;
|
||||
break;
|
||||
case '^':
|
||||
token.kind = Token_Pointer;
|
||||
break;
|
||||
case '?':
|
||||
token.kind = Token_Maybe;
|
||||
break;
|
||||
case ';':
|
||||
token.kind = Token_Semicolon;
|
||||
break;
|
||||
case ',':
|
||||
token.kind = Token_Comma;
|
||||
break;
|
||||
case ':':
|
||||
token.kind = Token_Colon;
|
||||
break;
|
||||
case '(':
|
||||
token.kind = Token_OpenParen;
|
||||
break;
|
||||
case ')':
|
||||
token.kind = Token_CloseParen;
|
||||
break;
|
||||
case '[':
|
||||
token.kind = Token_OpenBracket;
|
||||
break;
|
||||
case ']':
|
||||
token.kind = Token_CloseBracket;
|
||||
break;
|
||||
case '{':
|
||||
token.kind = Token_OpenBrace;
|
||||
break;
|
||||
case '}':
|
||||
token.kind = Token_CloseBrace;
|
||||
break;
|
||||
case '#': token.kind = Token_Hash; 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_Semicolon; break;
|
||||
case ',': token.kind = Token_Comma; break;
|
||||
case ':': token.kind = Token_Colon; break;
|
||||
case '(': token.kind = Token_OpenParen; break;
|
||||
case ')': token.kind = Token_CloseParen; break;
|
||||
case '[': token.kind = Token_OpenBracket; break;
|
||||
case ']': token.kind = Token_CloseBracket; break;
|
||||
case '{': token.kind = Token_OpenBrace; break;
|
||||
case '}': token.kind = Token_CloseBrace; 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_Eq, Token_CmpEq); 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_Add, Token_AddEq);
|
||||
break;
|
||||
case '-':
|
||||
token.kind = token_kind_variant3(t, Token_Sub, Token_SubEq, '>', Token_ArrowRight);
|
||||
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_Eq, Token_CmpEq); 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_variant3(t, Token_Add, Token_AddEq, '+', Token_Inc); break;
|
||||
case '-': token.kind = token_kind_variant4(t, Token_Sub, Token_SubEq, '-', Token_Dec, '>', Token_ArrowRight); break;
|
||||
case '/': {
|
||||
if (t->curr_rune == '/') {
|
||||
while (t->curr_rune != '\n' && t->curr_rune != GB_RUNE_EOF) {
|
||||
@@ -940,9 +927,7 @@ Token tokenizer_get_token(Tokenizer *t) {
|
||||
token.kind = token_kind_dub_eq(t, '<', Token_Lt, Token_LtEq, Token_Shl, Token_ShlEq);
|
||||
}
|
||||
break;
|
||||
case '>':
|
||||
token.kind = token_kind_dub_eq(t, '>', Token_Gt, Token_GtEq, Token_Shr, Token_ShrEq);
|
||||
break;
|
||||
case '>': token.kind = token_kind_dub_eq(t, '>', Token_Gt, Token_GtEq, Token_Shr, Token_ShrEq); break;
|
||||
|
||||
case '&':
|
||||
token.kind = Token_And;
|
||||
|
||||
+740
-265
File diff suppressed because it is too large
Load Diff
+1
-25
@@ -6,6 +6,7 @@
|
||||
|
||||
#pragma warning(pop)
|
||||
|
||||
|
||||
bool rune_is_letter(Rune r) {
|
||||
if ((r < 0x80 && gb_char_is_alpha(cast(char)r)) ||
|
||||
r == '_') {
|
||||
@@ -39,28 +40,3 @@ bool rune_is_whitespace(Rune r) {
|
||||
}
|
||||
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) {
|
||||
return 0;
|
||||
} else if (uc < 0x80) {
|
||||
dst[0] = uc;
|
||||
dst[0] = (utf8proc_uint8_t) uc;
|
||||
return 1;
|
||||
} else if (uc < 0x800) {
|
||||
dst[0] = 0xC0 + (uc >> 6);
|
||||
dst[1] = 0x80 + (uc & 0x3F);
|
||||
dst[0] = (utf8proc_uint8_t)(0xC0 + (uc >> 6));
|
||||
dst[1] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
|
||||
return 2;
|
||||
// Note: we allow encoding 0xd800-0xdfff here, so as not to change
|
||||
// the API, however, these are actually invalid in UTF-8
|
||||
} else if (uc < 0x10000) {
|
||||
dst[0] = 0xE0 + (uc >> 12);
|
||||
dst[1] = 0x80 + ((uc >> 6) & 0x3F);
|
||||
dst[2] = 0x80 + (uc & 0x3F);
|
||||
dst[0] = (utf8proc_uint8_t)(0xE0 + (uc >> 12));
|
||||
dst[1] = (utf8proc_uint8_t)(0x80 + ((uc >> 6) & 0x3F));
|
||||
dst[2] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
|
||||
return 3;
|
||||
} else if (uc < 0x110000) {
|
||||
dst[0] = 0xF0 + (uc >> 18);
|
||||
dst[1] = 0x80 + ((uc >> 12) & 0x3F);
|
||||
dst[2] = 0x80 + ((uc >> 6) & 0x3F);
|
||||
dst[3] = 0x80 + (uc & 0x3F);
|
||||
dst[0] = (utf8proc_uint8_t)(0xF0 + (uc >> 18));
|
||||
dst[1] = (utf8proc_uint8_t)(0x80 + ((uc >> 12) & 0x3F));
|
||||
dst[2] = (utf8proc_uint8_t)(0x80 + ((uc >> 6) & 0x3F));
|
||||
dst[3] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
|
||||
return 4;
|
||||
} else return 0;
|
||||
}
|
||||
@@ -193,28 +193,28 @@ static utf8proc_ssize_t unsafe_encode_char(utf8proc_int32_t uc, utf8proc_uint8_t
|
||||
if (uc < 0x00) {
|
||||
return 0;
|
||||
} else if (uc < 0x80) {
|
||||
dst[0] = uc;
|
||||
dst[0] = (utf8proc_uint8_t)uc;
|
||||
return 1;
|
||||
} else if (uc < 0x800) {
|
||||
dst[0] = 0xC0 + (uc >> 6);
|
||||
dst[1] = 0x80 + (uc & 0x3F);
|
||||
dst[0] = (utf8proc_uint8_t)(0xC0 + (uc >> 6));
|
||||
dst[1] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
|
||||
return 2;
|
||||
} else if (uc == 0xFFFF) {
|
||||
dst[0] = 0xFF;
|
||||
dst[0] = (utf8proc_uint8_t)0xFF;
|
||||
return 1;
|
||||
} else if (uc == 0xFFFE) {
|
||||
dst[0] = 0xFE;
|
||||
dst[0] = (utf8proc_uint8_t)0xFE;
|
||||
return 1;
|
||||
} else if (uc < 0x10000) {
|
||||
dst[0] = 0xE0 + (uc >> 12);
|
||||
dst[1] = 0x80 + ((uc >> 6) & 0x3F);
|
||||
dst[2] = 0x80 + (uc & 0x3F);
|
||||
dst[0] = (utf8proc_uint8_t)(0xE0 + (uc >> 12));
|
||||
dst[1] = (utf8proc_uint8_t)(0x80 + ((uc >> 6) & 0x3F));
|
||||
dst[2] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
|
||||
return 3;
|
||||
} else if (uc < 0x110000) {
|
||||
dst[0] = 0xF0 + (uc >> 18);
|
||||
dst[1] = 0x80 + ((uc >> 12) & 0x3F);
|
||||
dst[2] = 0x80 + ((uc >> 6) & 0x3F);
|
||||
dst[3] = 0x80 + (uc & 0x3F);
|
||||
dst[0] = (utf8proc_uint8_t)(0xF0 + (uc >> 18));
|
||||
dst[1] = (utf8proc_uint8_t)(0x80 + ((uc >> 12) & 0x3F));
|
||||
dst[2] = (utf8proc_uint8_t)(0x80 + ((uc >> 6) & 0x3F));
|
||||
dst[3] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
|
||||
return 4;
|
||||
} 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) {
|
||||
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) {
|
||||
@@ -391,11 +391,9 @@ UTF8PROC_DLLEXPORT const char *utf8proc_category_string(utf8proc_int32_t c) {
|
||||
return s[utf8proc_category(c)];
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define utf8proc_decompose_lump(replacement_uc) \
|
||||
return utf8proc_decompose_char((utf8proc_int32_t)(replacement_uc), dst, bufsize, \
|
||||
(utf8proc_option_t)((utf8proc_int32_t)options & ~UTF8PROC_LUMP), last_boundclass)
|
||||
return utf8proc_decompose_char((replacement_uc), dst, bufsize, \
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
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))) {
|
||||
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(
|
||||
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen,
|
||||
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 */
|
||||
utf8proc_ssize_t wpos = 0;
|
||||
@@ -511,6 +517,9 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose(
|
||||
rpos += utf8proc_iterate(str + rpos, strlen - rpos, &uc);
|
||||
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(
|
||||
uc, buffer + wpos, (bufsize > wpos) ? (bufsize - wpos) : 0, options,
|
||||
&boundclass
|
||||
@@ -545,9 +554,8 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose(
|
||||
return wpos;
|
||||
}
|
||||
|
||||
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! */
|
||||
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 */
|
||||
if (options & (UTF8PROC_NLF2LS | UTF8PROC_NLF2PS | UTF8PROC_STRIPCC)) {
|
||||
utf8proc_ssize_t rpos;
|
||||
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);
|
||||
}
|
||||
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) {
|
||||
int sidx = starter_property->comb_index;
|
||||
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;
|
||||
}
|
||||
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_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(
|
||||
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_ssize_t result;
|
||||
*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;
|
||||
buffer = (utf8proc_int32_t *) malloc(result * sizeof(utf8proc_int32_t) + 1);
|
||||
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) {
|
||||
free(buffer);
|
||||
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_uint8_t *retval;
|
||||
utf8proc_map(str, 0, &retval, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE |
|
||||
UTF8PROC_DECOMPOSE));
|
||||
utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE |
|
||||
UTF8PROC_DECOMPOSE);
|
||||
return retval;
|
||||
}
|
||||
|
||||
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFC(const utf8proc_uint8_t *str) {
|
||||
utf8proc_uint8_t *retval;
|
||||
utf8proc_map(str, 0, &retval, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE |
|
||||
UTF8PROC_COMPOSE));
|
||||
utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE |
|
||||
UTF8PROC_COMPOSE);
|
||||
return retval;
|
||||
}
|
||||
|
||||
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKD(const utf8proc_uint8_t *str) {
|
||||
utf8proc_uint8_t *retval;
|
||||
utf8proc_map(str, 0, &retval, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE |
|
||||
UTF8PROC_DECOMPOSE | UTF8PROC_COMPAT));
|
||||
utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE |
|
||||
UTF8PROC_DECOMPOSE | UTF8PROC_COMPAT);
|
||||
return retval;
|
||||
}
|
||||
|
||||
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC(const utf8proc_uint8_t *str) {
|
||||
utf8proc_uint8_t *retval;
|
||||
utf8proc_map(str, 0, &retval, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE |
|
||||
UTF8PROC_COMPOSE | UTF8PROC_COMPAT));
|
||||
utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE |
|
||||
UTF8PROC_COMPOSE | UTF8PROC_COMPAT);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
+81
-25
@@ -71,14 +71,15 @@
|
||||
/** The MAJOR version number (increased when backwards API compatibility is broken). */
|
||||
#define UTF8PROC_VERSION_MAJOR 2
|
||||
/** 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). */
|
||||
#define UTF8PROC_VERSION_PATCH 2
|
||||
#define UTF8PROC_VERSION_PATCH 0
|
||||
/** @} */
|
||||
|
||||
#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 unsigned char utf8proc_uint8_t;
|
||||
typedef short utf8proc_int16_t;
|
||||
@@ -93,12 +94,18 @@ typedef int utf8proc_ssize_t;
|
||||
typedef unsigned int utf8proc_size_t;
|
||||
# endif
|
||||
# ifndef __cplusplus
|
||||
// emulate C99 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
|
||||
typedef bool utf8proc_bool;
|
||||
# endif
|
||||
#else
|
||||
# include <stddef.h>
|
||||
# include <stdbool.h>
|
||||
# include <inttypes.h>
|
||||
typedef int8_t utf8proc_int8_t;
|
||||
@@ -108,22 +115,12 @@ typedef uint16_t utf8proc_uint16_t;
|
||||
typedef int32_t utf8proc_int32_t;
|
||||
typedef uint32_t utf8proc_uint32_t;
|
||||
typedef size_t utf8proc_size_t;
|
||||
typedef ssize_t utf8proc_ssize_t;
|
||||
typedef ptrdiff_t utf8proc_ssize_t;
|
||||
typedef bool utf8proc_bool;
|
||||
#endif
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
# 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
|
||||
#define UTF8PROC_DLLEXPORT
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -134,7 +131,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef UINT16_MAX
|
||||
# define UINT16_MAX ~(utf8proc_uint16_t)0
|
||||
# define UINT16_MAX 65535U
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -373,6 +370,13 @@ typedef enum {
|
||||
UTF8PROC_BOUNDCLASS_E_BASE_GAZ = 18, /**< E_BASE + GLUE_AFTER_ZJW */
|
||||
} 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
|
||||
* 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
|
||||
* success, the number of codepoints written is returned; in case of an
|
||||
* 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
|
||||
* 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`
|
||||
* UTF-8 data in-place (i.e., the result is also stored in `buffer`).
|
||||
* The same as @ref utf8proc_decompose, 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`. 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 length the length (in codepoints) of the buffer.
|
||||
@@ -507,9 +524,37 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose(
|
||||
* the unicode versioning stability
|
||||
*
|
||||
* @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).
|
||||
*
|
||||
* @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
|
||||
* 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
|
||||
@@ -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
|
||||
* contain NULL characters with the string if `str` contained NULL
|
||||
* 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,
|
||||
* 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
|
||||
);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* 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);
|
||||
/** NFC normalization (@ref UTF8PROC_COMPOSE). */
|
||||
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);
|
||||
/** 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);
|
||||
/** @} */
|
||||
|
||||
@@ -630,4 +687,3 @@ UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC(const utf8proc_uint8_t *str);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4838)
|
||||
|
||||
const utf8proc_uint16_t utf8proc_sequences[] = {
|
||||
static const utf8proc_uint16_t utf8proc_sequences[] = {
|
||||
97, 98, 99, 100, 101, 102, 103,
|
||||
104, 105, 106, 107, 108, 109, 110, 111,
|
||||
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,
|
||||
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,
|
||||
1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584,
|
||||
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,
|
||||
38656, };
|
||||
|
||||
const utf8proc_uint16_t utf8proc_stage2table[] = {
|
||||
static const utf8proc_uint16_t utf8proc_stage2table[] = {
|
||||
1, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 3, 4, 3, 5, 6, 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,
|
||||
0, 1154, 1154, 1154, 1154, 1154, 1154, 1154,
|
||||
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,
|
||||
@@ -6593,7 +6590,7 @@ const utf8proc_uint16_t utf8proc_stage2table[] = {
|
||||
3984, 3984, 3984, 3984, 3984, 3984, 3984, 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},
|
||||
{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},
|
||||
@@ -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_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_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_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},
|
||||
@@ -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, 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, 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, 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},
|
||||
@@ -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, 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, 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, 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},
|
||||
@@ -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, 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, 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, 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},
|
||||
@@ -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},
|
||||
};
|
||||
|
||||
const utf8proc_uint16_t utf8proc_combinations[] = {
|
||||
static const utf8proc_uint16_t utf8proc_combinations[] = {
|
||||
0, 46, 192, 193, 194, 195, 196, 197, 0,
|
||||
256, 258, 260, 550, 461, 0, 0, 512,
|
||||
514, 0, 0, 0, 0, 0, 0, 0,
|
||||
@@ -14386,5 +14383,3 @@ const utf8proc_uint16_t utf8proc_combinations[] = {
|
||||
72, 75,
|
||||
1, 53694, 1, 53696,
|
||||
};
|
||||
|
||||
#pragma warning(pop)
|
||||
|
||||
Reference in New Issue
Block a user