mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-05 03:01:38 -07:00
Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6e1864d21c | |||
| fb2d611dcd | |||
| 9e8c9be1ea | |||
| 9bc37f4400 | |||
| f29e303ce7 | |||
| 3c9143957c | |||
| 18b3c0b2fc | |||
| c59f6b7d0b | |||
| 67ed8a9a4a | |||
| 4cc4d604bc | |||
| eec709c545 | |||
| 9b2f5c359a | |||
| a982c51c30 | |||
| 047c0e4bcc | |||
| a94dfdf21d | |||
| c0d5237b75 | |||
| 6fdcbefe5d | |||
| 3cec2550d9 | |||
| 758dd9ba16 | |||
| 0c37aa9ea0 | |||
| 9ff474f387 | |||
| d2f9d20833 | |||
| 71100ed427 | |||
| 3ecf3505fd | |||
| daa1cd55a1 | |||
| 2722de65b7 | |||
| 8b5e3428a1 | |||
| d1f65097c4 | |||
| 74d15ab84b | |||
| 763cd2649d | |||
| bd27c24fab | |||
| 282f8bb06f | |||
| b9ed546ce0 |
@@ -255,3 +255,4 @@ paket-files/
|
||||
!misc/llvm-bim/lli.exe
|
||||
!misc/llvm-bim/opt.exe
|
||||
builds
|
||||
bin
|
||||
|
||||
@@ -1,200 +0,0 @@
|
||||
This file is a list of the people responsible for ensuring that patches for a
|
||||
particular part of LLVM are reviewed, either by themself or by someone else.
|
||||
They are also the gatekeepers for their part of LLVM, with the final word on
|
||||
what goes in or not.
|
||||
|
||||
The list is sorted by surname and formatted to allow easy grepping and
|
||||
beautification by scripts. The fields are: name (N), email (E), web-address
|
||||
(W), PGP key ID and fingerprint (P), description (D), and snail-mail address
|
||||
(S). Each entry should contain at least the (N), (E) and (D) fields.
|
||||
|
||||
N: Joe Abbey
|
||||
E: jabbey@arxan.com
|
||||
D: LLVM Bitcode (lib/Bitcode/* include/llvm/Bitcode/*)
|
||||
|
||||
N: Owen Anderson
|
||||
E: resistor@mac.com
|
||||
D: SelectionDAG (lib/CodeGen/SelectionDAG/*)
|
||||
|
||||
N: Rafael Avila de Espindola
|
||||
E: rafael.espindola@gmail.com
|
||||
D: Gold plugin (tools/gold/*)
|
||||
|
||||
N: Justin Bogner
|
||||
E: mail@justinbogner.com
|
||||
D: InstrProfiling and related parts of ProfileData
|
||||
|
||||
N: Chandler Carruth
|
||||
E: chandlerc@gmail.com
|
||||
E: chandlerc@google.com
|
||||
D: Config, ADT, Support, inlining & related passes, SROA/mem2reg & related passes, CMake, library layering
|
||||
|
||||
N: Evan Cheng
|
||||
E: evan.cheng@apple.com
|
||||
D: parts of code generator not covered by someone else
|
||||
|
||||
N: Eric Christopher
|
||||
E: echristo@gmail.com
|
||||
D: Debug Information, autotools/configure/make build, inline assembly
|
||||
|
||||
N: Greg Clayton
|
||||
E: gclayton@apple.com
|
||||
D: LLDB
|
||||
|
||||
N: Marshall Clow
|
||||
E: mclow.lists@gmail.com
|
||||
D: libc++
|
||||
|
||||
N: Peter Collingbourne
|
||||
E: peter@pcc.me.uk
|
||||
D: llgo
|
||||
|
||||
N: Quentin Colombet
|
||||
E: qcolombet@apple.com
|
||||
D: Register allocators
|
||||
|
||||
N: Duncan P. N. Exon Smith
|
||||
E: dexonsmith@apple.com
|
||||
D: Branch weights and BlockFrequencyInfo
|
||||
|
||||
N: Hal Finkel
|
||||
E: hfinkel@anl.gov
|
||||
D: BBVectorize, the loop reroller, alias analysis and the PowerPC target
|
||||
|
||||
N: Dan Gohman
|
||||
E: sunfish@mozilla.com
|
||||
D: WebAssembly Backend (lib/Target/WebAssembly/*)
|
||||
|
||||
N: Renato Golin
|
||||
E: renato.golin@linaro.org
|
||||
D: ARM Linux support
|
||||
|
||||
N: Venkatraman Govindaraju
|
||||
E: venkatra@cs.wisc.edu
|
||||
D: Sparc Backend (lib/Target/Sparc/*)
|
||||
|
||||
N: Tobias Grosser
|
||||
E: tobias@grosser.es
|
||||
D: Polly
|
||||
|
||||
N: James Grosbach
|
||||
E: grosbach@apple.com
|
||||
D: MC layer
|
||||
|
||||
N: Justin Holewinski
|
||||
E: jholewinski@nvidia.com
|
||||
D: NVPTX Target (lib/Target/NVPTX/*)
|
||||
|
||||
N: Lang Hames
|
||||
E: lhames@gmail.com
|
||||
D: MCJIT, RuntimeDyld and JIT event listeners
|
||||
|
||||
N: Galina Kistanova
|
||||
E: gkistanova@gmail.com
|
||||
D: LLVM Buildbot
|
||||
|
||||
N: Anton Korobeynikov
|
||||
E: anton@korobeynikov.info
|
||||
D: Exception handling, Windows codegen, ARM EABI
|
||||
|
||||
N: Benjamin Kramer
|
||||
E: benny.kra@gmail.com
|
||||
D: DWARF Parser
|
||||
|
||||
N: Sergei Larin
|
||||
E: slarin@codeaurora.org
|
||||
D: VLIW Instruction Scheduling, Packetization
|
||||
|
||||
N: Chris Lattner
|
||||
E: sabre@nondot.org
|
||||
W: http://nondot.org/~sabre/
|
||||
D: Everything not covered by someone else
|
||||
|
||||
N: David Majnemer
|
||||
E: david.majnemer@gmail.com
|
||||
D: IR Constant Folder, InstCombine
|
||||
|
||||
N: Dylan McKay
|
||||
E: dylanmckay34@gmail.com
|
||||
D: AVR Backend
|
||||
|
||||
N: Tim Northover
|
||||
E: t.p.northover@gmail.com
|
||||
D: AArch64 backend, misc ARM backend
|
||||
|
||||
N: Diego Novillo
|
||||
E: dnovillo@google.com
|
||||
D: SampleProfile and related parts of ProfileData
|
||||
|
||||
N: Jakob Olesen
|
||||
E: stoklund@2pi.dk
|
||||
D: TableGen
|
||||
|
||||
N: Richard Osborne
|
||||
E: richard@xmos.com
|
||||
D: XCore Backend
|
||||
|
||||
N: Krzysztof Parzyszek
|
||||
E: kparzysz@codeaurora.org
|
||||
D: Hexagon Backend
|
||||
|
||||
N: Paul Robinson
|
||||
E: paul_robinson@playstation.sony.com
|
||||
D: Sony PlayStation®4 support
|
||||
|
||||
N: Chad Rosier
|
||||
E: mcrosier@codeaurora.org
|
||||
D: Fast-Isel
|
||||
|
||||
N: Nadav Rotem
|
||||
E: nrotem@apple.com
|
||||
D: X86 Backend, Loop Vectorizer
|
||||
|
||||
N: Daniel Sanders
|
||||
E: daniel.sanders@imgtec.com
|
||||
D: MIPS Backend (lib/Target/Mips/*)
|
||||
|
||||
N: Duncan Sands
|
||||
E: baldrick@free.fr
|
||||
D: DragonEgg
|
||||
|
||||
N: Kostya Serebryany
|
||||
E: kcc@google.com
|
||||
D: AddressSanitizer, ThreadSanitizer (LLVM parts)
|
||||
|
||||
N: Michael Spencer
|
||||
E: bigcheesegs@gmail.com
|
||||
D: Windows parts of Support, Object, ar, nm, objdump, ranlib, size
|
||||
|
||||
N: Alexei Starovoitov
|
||||
E: alexei.starovoitov@gmail.com
|
||||
D: BPF backend
|
||||
|
||||
N: Tom Stellard
|
||||
E: thomas.stellard@amd.com
|
||||
E: mesa-dev@lists.freedesktop.org
|
||||
D: Release manager for the 3.5 and 3.6 branches, R600 Backend, libclc
|
||||
|
||||
N: Evgeniy Stepanov
|
||||
E: eugenis@google.com
|
||||
D: MemorySanitizer (LLVM part)
|
||||
|
||||
N: Andrew Trick
|
||||
E: atrick@apple.com
|
||||
D: IndVar Simplify, Loop Strength Reduction, Instruction Scheduling
|
||||
|
||||
N: Ulrich Weigand
|
||||
E: uweigand@de.ibm.com
|
||||
D: SystemZ Backend
|
||||
|
||||
N: Bill Wendling
|
||||
E: isanbard@gmail.com
|
||||
D: libLTO, IR Linker
|
||||
|
||||
N: Peter Zotov
|
||||
E: whitequark@whitequark.org
|
||||
D: OCaml bindings
|
||||
|
||||
N: Andrey Churbanov
|
||||
E: andrey.churbanov@intel.com
|
||||
D: OpenMP runtime library
|
||||
-467
@@ -1,467 +0,0 @@
|
||||
This file is a partial list of people who have contributed to the LLVM
|
||||
project. If you have contributed a patch or made some other contribution to
|
||||
LLVM, please submit a patch to this file to add yourself, and it will be
|
||||
done!
|
||||
|
||||
The list is sorted by surname and formatted to allow easy grepping and
|
||||
beautification by scripts. The fields are: name (N), email (E), web-address
|
||||
(W), PGP key ID and fingerprint (P), description (D), snail-mail address
|
||||
(S), and (I) IRC handle.
|
||||
|
||||
|
||||
N: Vikram Adve
|
||||
E: vadve@cs.uiuc.edu
|
||||
W: http://www.cs.uiuc.edu/~vadve/
|
||||
D: The Sparc64 backend, provider of much wisdom, and motivator for LLVM
|
||||
|
||||
N: Owen Anderson
|
||||
E: resistor@mac.com
|
||||
D: LCSSA pass and related LoopUnswitch work
|
||||
D: GVNPRE pass, DataLayout refactoring, random improvements
|
||||
|
||||
N: Henrik Bach
|
||||
D: MingW Win32 API portability layer
|
||||
|
||||
N: Aaron Ballman
|
||||
E: aaron@aaronballman.com
|
||||
D: __declspec attributes, Windows support, general bug fixing
|
||||
|
||||
N: Nate Begeman
|
||||
E: natebegeman@mac.com
|
||||
D: PowerPC backend developer
|
||||
D: Target-independent code generator and analysis improvements
|
||||
|
||||
N: Daniel Berlin
|
||||
E: dberlin@dberlin.org
|
||||
D: ET-Forest implementation.
|
||||
D: Sparse bitmap
|
||||
|
||||
N: David Blaikie
|
||||
E: dblaikie@gmail.com
|
||||
D: General bug fixing/fit & finish, mostly in Clang
|
||||
|
||||
N: Neil Booth
|
||||
E: neil@daikokuya.co.uk
|
||||
D: APFloat implementation.
|
||||
|
||||
N: Misha Brukman
|
||||
E: brukman+llvm@uiuc.edu
|
||||
W: http://misha.brukman.net
|
||||
D: Portions of X86 and Sparc JIT compilers, PowerPC backend
|
||||
D: Incremental bitcode loader
|
||||
|
||||
N: Cameron Buschardt
|
||||
E: buschard@uiuc.edu
|
||||
D: The `mem2reg' pass - promotes values stored in memory to registers
|
||||
|
||||
N: Brendon Cahoon
|
||||
E: bcahoon@codeaurora.org
|
||||
D: Loop unrolling with run-time trip counts.
|
||||
|
||||
N: Chandler Carruth
|
||||
E: chandlerc@gmail.com
|
||||
E: chandlerc@google.com
|
||||
D: Hashing algorithms and interfaces
|
||||
D: Inline cost analysis
|
||||
D: Machine block placement pass
|
||||
D: SROA
|
||||
|
||||
N: Casey Carter
|
||||
E: ccarter@uiuc.edu
|
||||
D: Fixes to the Reassociation pass, various improvement patches
|
||||
|
||||
N: Evan Cheng
|
||||
E: evan.cheng@apple.com
|
||||
D: ARM and X86 backends
|
||||
D: Instruction scheduler improvements
|
||||
D: Register allocator improvements
|
||||
D: Loop optimizer improvements
|
||||
D: Target-independent code generator improvements
|
||||
|
||||
N: Dan Villiom Podlaski Christiansen
|
||||
E: danchr@gmail.com
|
||||
E: danchr@cs.au.dk
|
||||
W: http://villiom.dk
|
||||
D: LLVM Makefile improvements
|
||||
D: Clang diagnostic & driver tweaks
|
||||
S: Aarhus, Denmark
|
||||
|
||||
N: Jeff Cohen
|
||||
E: jeffc@jolt-lang.org
|
||||
W: http://jolt-lang.org
|
||||
D: Native Win32 API portability layer
|
||||
|
||||
N: John T. Criswell
|
||||
E: criswell@uiuc.edu
|
||||
D: Original Autoconf support, documentation improvements, bug fixes
|
||||
|
||||
N: Anshuman Dasgupta
|
||||
E: adasgupt@codeaurora.org
|
||||
D: Deterministic finite automaton based infrastructure for VLIW packetization
|
||||
|
||||
N: Stefanus Du Toit
|
||||
E: stefanus.du.toit@intel.com
|
||||
D: Bug fixes and minor improvements
|
||||
|
||||
N: Rafael Avila de Espindola
|
||||
E: rafael.espindola@gmail.com
|
||||
D: The ARM backend
|
||||
|
||||
N: Dave Estes
|
||||
E: cestes@codeaurora.org
|
||||
D: AArch64 machine description for Cortex-A53
|
||||
|
||||
N: Alkis Evlogimenos
|
||||
E: alkis@evlogimenos.com
|
||||
D: Linear scan register allocator, many codegen improvements, Java frontend
|
||||
|
||||
N: Hal Finkel
|
||||
E: hfinkel@anl.gov
|
||||
D: Basic-block autovectorization, PowerPC backend improvements
|
||||
|
||||
N: Eric Fiselier
|
||||
E: eric@efcs.ca
|
||||
D: LIT patches and documentation.
|
||||
|
||||
N: Ryan Flynn
|
||||
E: pizza@parseerror.com
|
||||
D: Miscellaneous bug fixes
|
||||
|
||||
N: Brian Gaeke
|
||||
E: gaeke@uiuc.edu
|
||||
W: http://www.students.uiuc.edu/~gaeke/
|
||||
D: Portions of X86 static and JIT compilers; initial SparcV8 backend
|
||||
D: Dynamic trace optimizer
|
||||
D: FreeBSD/X86 compatibility fixes, the llvm-nm tool
|
||||
|
||||
N: Nicolas Geoffray
|
||||
E: nicolas.geoffray@lip6.fr
|
||||
W: http://www-src.lip6.fr/homepages/Nicolas.Geoffray/
|
||||
D: PPC backend fixes for Linux
|
||||
|
||||
N: Louis Gerbarg
|
||||
E: lgg@apple.com
|
||||
D: Portions of the PowerPC backend
|
||||
|
||||
N: Saem Ghani
|
||||
E: saemghani@gmail.com
|
||||
D: Callgraph class cleanups
|
||||
|
||||
N: Mikhail Glushenkov
|
||||
E: foldr@codedgers.com
|
||||
D: Author of llvmc2
|
||||
|
||||
N: Dan Gohman
|
||||
E: sunfish@mozilla.com
|
||||
D: Miscellaneous bug fixes
|
||||
D: WebAssembly Backend
|
||||
|
||||
N: David Goodwin
|
||||
E: david@goodwinz.net
|
||||
D: Thumb-2 code generator
|
||||
|
||||
N: David Greene
|
||||
E: greened@obbligato.org
|
||||
D: Miscellaneous bug fixes
|
||||
D: Register allocation refactoring
|
||||
|
||||
N: Gabor Greif
|
||||
E: ggreif@gmail.com
|
||||
D: Improvements for space efficiency
|
||||
|
||||
N: James Grosbach
|
||||
E: grosbach@apple.com
|
||||
I: grosbach
|
||||
D: SjLj exception handling support
|
||||
D: General fixes and improvements for the ARM back-end
|
||||
D: MCJIT
|
||||
D: ARM integrated assembler and assembly parser
|
||||
D: Led effort for the backend formerly known as ARM64
|
||||
|
||||
N: Lang Hames
|
||||
E: lhames@gmail.com
|
||||
D: PBQP-based register allocator
|
||||
|
||||
N: Gordon Henriksen
|
||||
E: gordonhenriksen@mac.com
|
||||
D: Pluggable GC support
|
||||
D: C interface
|
||||
D: Ocaml bindings
|
||||
|
||||
N: Raul Fernandes Herbster
|
||||
E: raul@dsc.ufcg.edu.br
|
||||
D: JIT support for ARM
|
||||
|
||||
N: Paolo Invernizzi
|
||||
E: arathorn@fastwebnet.it
|
||||
D: Visual C++ compatibility fixes
|
||||
|
||||
N: Patrick Jenkins
|
||||
E: patjenk@wam.umd.edu
|
||||
D: Nightly Tester
|
||||
|
||||
N: Dale Johannesen
|
||||
E: dalej@apple.com
|
||||
D: ARM constant islands improvements
|
||||
D: Tail merging improvements
|
||||
D: Rewrite X87 back end
|
||||
D: Use APFloat for floating point constants widely throughout compiler
|
||||
D: Implement X87 long double
|
||||
|
||||
N: Brad Jones
|
||||
E: kungfoomaster@nondot.org
|
||||
D: Support for packed types
|
||||
|
||||
N: Rod Kay
|
||||
E: rkay@auroraux.org
|
||||
D: Author of LLVM Ada bindings
|
||||
|
||||
N: Eric Kidd
|
||||
W: http://randomhacks.net/
|
||||
D: llvm-config script
|
||||
|
||||
N: Anton Korobeynikov
|
||||
E: asl@math.spbu.ru
|
||||
D: Mingw32 fixes, cross-compiling support, stdcall/fastcall calling conv.
|
||||
D: x86/linux PIC codegen, aliases, regparm/visibility attributes
|
||||
D: Switch lowering refactoring
|
||||
|
||||
N: Sumant Kowshik
|
||||
E: kowshik@uiuc.edu
|
||||
D: Author of the original C backend
|
||||
|
||||
N: Benjamin Kramer
|
||||
E: benny.kra@gmail.com
|
||||
D: Miscellaneous bug fixes
|
||||
|
||||
N: Sundeep Kushwaha
|
||||
E: sundeepk@codeaurora.org
|
||||
D: Implemented DFA-based target independent VLIW packetizer
|
||||
|
||||
N: Christopher Lamb
|
||||
E: christopher.lamb@gmail.com
|
||||
D: aligned load/store support, parts of noalias and restrict support
|
||||
D: vreg subreg infrastructure, X86 codegen improvements based on subregs
|
||||
D: address spaces
|
||||
|
||||
N: Jim Laskey
|
||||
E: jlaskey@apple.com
|
||||
D: Improvements to the PPC backend, instruction scheduling
|
||||
D: Debug and Dwarf implementation
|
||||
D: Auto upgrade mangler
|
||||
D: llvm-gcc4 svn wrangler
|
||||
|
||||
N: Chris Lattner
|
||||
E: sabre@nondot.org
|
||||
W: http://nondot.org/~sabre/
|
||||
D: Primary architect of LLVM
|
||||
|
||||
N: Tanya Lattner (Tanya Brethour)
|
||||
E: tonic@nondot.org
|
||||
W: http://nondot.org/~tonic/
|
||||
D: The initial llvm-ar tool, converted regression testsuite to dejagnu
|
||||
D: Modulo scheduling in the SparcV9 backend
|
||||
D: Release manager (1.7+)
|
||||
|
||||
N: Sylvestre Ledru
|
||||
E: sylvestre@debian.org
|
||||
W: http://sylvestre.ledru.info/
|
||||
W: http://llvm.org/apt/
|
||||
D: Debian and Ubuntu packaging
|
||||
D: Continuous integration with jenkins
|
||||
|
||||
N: Andrew Lenharth
|
||||
E: alenhar2@cs.uiuc.edu
|
||||
W: http://www.lenharth.org/~andrewl/
|
||||
D: Alpha backend
|
||||
D: Sampling based profiling
|
||||
|
||||
N: Nick Lewycky
|
||||
E: nicholas@mxc.ca
|
||||
D: PredicateSimplifier pass
|
||||
|
||||
N: Tony Linthicum, et. al.
|
||||
E: tlinth@codeaurora.org
|
||||
D: Backend for Qualcomm's Hexagon VLIW processor.
|
||||
|
||||
N: Bruno Cardoso Lopes
|
||||
E: bruno.cardoso@gmail.com
|
||||
I: bruno
|
||||
W: http://brunocardoso.cc
|
||||
D: Mips backend
|
||||
D: Random ARM integrated assembler and assembly parser improvements
|
||||
D: General X86 AVX1 support
|
||||
|
||||
N: Duraid Madina
|
||||
E: duraid@octopus.com.au
|
||||
W: http://kinoko.c.u-tokyo.ac.jp/~duraid/
|
||||
D: IA64 backend, BigBlock register allocator
|
||||
|
||||
N: John McCall
|
||||
E: rjmccall@apple.com
|
||||
D: Clang semantic analysis and IR generation
|
||||
|
||||
N: Michael McCracken
|
||||
E: michael.mccracken@gmail.com
|
||||
D: Line number support for llvmgcc
|
||||
|
||||
N: Vladimir Merzliakov
|
||||
E: wanderer@rsu.ru
|
||||
D: Test suite fixes for FreeBSD
|
||||
|
||||
N: Scott Michel
|
||||
E: scottm@aero.org
|
||||
D: Added STI Cell SPU backend.
|
||||
|
||||
N: Kai Nacke
|
||||
E: kai@redstar.de
|
||||
D: Support for implicit TLS model used with MS VC runtime
|
||||
D: Dumping of Win64 EH structures
|
||||
|
||||
N: Takumi Nakamura
|
||||
E: geek4civic@gmail.com
|
||||
E: chapuni@hf.rim.or.jp
|
||||
D: Cygwin and MinGW support.
|
||||
D: Win32 tweaks.
|
||||
S: Yokohama, Japan
|
||||
|
||||
N: Edward O'Callaghan
|
||||
E: eocallaghan@auroraux.org
|
||||
W: http://www.auroraux.org
|
||||
D: Add Clang support with various other improvements to utils/NewNightlyTest.pl
|
||||
D: Fix and maintain Solaris & AuroraUX support for llvm, various build warnings
|
||||
D: and error clean ups.
|
||||
|
||||
N: Morten Ofstad
|
||||
E: morten@hue.no
|
||||
D: Visual C++ compatibility fixes
|
||||
|
||||
N: Jakob Stoklund Olesen
|
||||
E: stoklund@2pi.dk
|
||||
D: Machine code verifier
|
||||
D: Blackfin backend
|
||||
D: Fast register allocator
|
||||
D: Greedy register allocator
|
||||
|
||||
N: Richard Osborne
|
||||
E: richard@xmos.com
|
||||
D: XCore backend
|
||||
|
||||
N: Devang Patel
|
||||
E: dpatel@apple.com
|
||||
D: LTO tool, PassManager rewrite, Loop Pass Manager, Loop Rotate
|
||||
D: GCC PCH Integration (llvm-gcc), llvm-gcc improvements
|
||||
D: Optimizer improvements, Loop Index Split
|
||||
|
||||
N: Ana Pazos
|
||||
E: apazos@codeaurora.org
|
||||
D: Fixes and improvements to the AArch64 backend
|
||||
|
||||
N: Wesley Peck
|
||||
E: peckw@wesleypeck.com
|
||||
W: http://wesleypeck.com/
|
||||
D: MicroBlaze backend
|
||||
|
||||
N: Francois Pichet
|
||||
E: pichet2000@gmail.com
|
||||
D: MSVC support
|
||||
|
||||
N: Vladimir Prus
|
||||
W: http://vladimir_prus.blogspot.com
|
||||
E: ghost@cs.msu.su
|
||||
D: Made inst_iterator behave like a proper iterator, LowerConstantExprs pass
|
||||
|
||||
N: Kalle Raiskila
|
||||
E: kalle.rasikila@nokia.com
|
||||
D: Some bugfixes to CellSPU
|
||||
|
||||
N: Xerxes Ranby
|
||||
E: xerxes@zafena.se
|
||||
D: Cmake dependency chain and various bug fixes
|
||||
|
||||
N: Alex Rosenberg
|
||||
E: alexr@leftfield.org
|
||||
I: arosenberg
|
||||
D: ARM calling conventions rewrite, hard float support
|
||||
|
||||
N: Chad Rosier
|
||||
E: mcrosier@codeaurora.org
|
||||
I: mcrosier
|
||||
D: AArch64 fast instruction selection pass
|
||||
D: Fixes and improvements to the ARM fast-isel pass
|
||||
D: Fixes and improvements to the AArch64 backend
|
||||
|
||||
N: Nadav Rotem
|
||||
E: nrotem@apple.com
|
||||
D: X86 code generation improvements, Loop Vectorizer.
|
||||
|
||||
N: Roman Samoilov
|
||||
E: roman@codedgers.com
|
||||
D: MSIL backend
|
||||
|
||||
N: Duncan Sands
|
||||
E: baldrick@free.fr
|
||||
I: baldrick
|
||||
D: Ada support in llvm-gcc
|
||||
D: Dragonegg plugin
|
||||
D: Exception handling improvements
|
||||
D: Type legalizer rewrite
|
||||
|
||||
N: Ruchira Sasanka
|
||||
E: sasanka@uiuc.edu
|
||||
D: Graph coloring register allocator for the Sparc64 backend
|
||||
|
||||
N: Arnold Schwaighofer
|
||||
E: arnold.schwaighofer@gmail.com
|
||||
D: Tail call optimization for the x86 backend
|
||||
|
||||
N: Shantonu Sen
|
||||
E: ssen@apple.com
|
||||
D: Miscellaneous bug fixes
|
||||
|
||||
N: Anand Shukla
|
||||
E: ashukla@cs.uiuc.edu
|
||||
D: The `paths' pass
|
||||
|
||||
N: Michael J. Spencer
|
||||
E: bigcheesegs@gmail.com
|
||||
D: Shepherding Windows COFF support into MC.
|
||||
D: Lots of Windows stuff.
|
||||
|
||||
N: Reid Spencer
|
||||
E: rspencer@reidspencer.com
|
||||
W: http://reidspencer.com/
|
||||
D: Lots of stuff, see: http://wiki.llvm.org/index.php/User:Reid
|
||||
|
||||
N: Alp Toker
|
||||
E: alp@nuanti.com
|
||||
W: http://atoker.com/
|
||||
D: C++ frontend next generation standards implementation
|
||||
|
||||
N: Craig Topper
|
||||
E: craig.topper@gmail.com
|
||||
D: X86 codegen and disassembler improvements. AVX2 support.
|
||||
|
||||
N: Edwin Torok
|
||||
E: edwintorok@gmail.com
|
||||
D: Miscellaneous bug fixes
|
||||
|
||||
N: Adam Treat
|
||||
E: manyoso@yahoo.com
|
||||
D: C++ bugs filed, and C++ front-end bug fixes.
|
||||
|
||||
N: Lauro Ramos Venancio
|
||||
E: lauro.venancio@indt.org.br
|
||||
D: ARM backend improvements
|
||||
D: Thread Local Storage implementation
|
||||
|
||||
N: Bill Wendling
|
||||
I: wendling
|
||||
E: isanbard@gmail.com
|
||||
D: Release manager, IR Linker, LTO
|
||||
D: Bunches of stuff
|
||||
|
||||
N: Bob Wilson
|
||||
E: bob.wilson@acm.org
|
||||
D: Advanced SIMD (NEON) support in the ARM backend.
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
==============================================================================
|
||||
LLVM Release License
|
||||
==============================================================================
|
||||
University of Illinois/NCSA
|
||||
Open Source License
|
||||
|
||||
Copyright (c) 2003-2015 University of Illinois at Urbana-Champaign.
|
||||
All rights reserved.
|
||||
|
||||
Developed by:
|
||||
|
||||
LLVM Team
|
||||
|
||||
University of Illinois at Urbana-Champaign
|
||||
|
||||
http://llvm.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal with
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimers.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimers in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of the LLVM Team, University of Illinois at
|
||||
Urbana-Champaign, nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this Software without specific
|
||||
prior written permission.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
|
||||
SOFTWARE.
|
||||
|
||||
==============================================================================
|
||||
Copyrights and Licenses for Third Party Software Distributed with LLVM:
|
||||
==============================================================================
|
||||
The LLVM software contains code written by third parties. Such software will
|
||||
have its own individual LICENSE.TXT file in the directory in which it appears.
|
||||
This file will describe the copyrights, license, and restrictions which apply
|
||||
to that code.
|
||||
|
||||
The disclaimer of warranty in the University of Illinois Open Source License
|
||||
applies to all code in the LLVM Distribution, and nothing in any of the
|
||||
other licenses gives permission to use the names of the LLVM Team or the
|
||||
University of Illinois to endorse or promote products derived from this
|
||||
Software.
|
||||
|
||||
The following pieces of software have additional or alternate copyrights,
|
||||
licenses, and/or restrictions:
|
||||
|
||||
Program Directory
|
||||
------- ---------
|
||||
Autoconf llvm/autoconf
|
||||
llvm/projects/ModuleMaker/autoconf
|
||||
Google Test llvm/utils/unittest/googletest
|
||||
OpenBSD regex llvm/lib/Support/{reg*, COPYRIGHT.regex}
|
||||
pyyaml tests llvm/test/YAMLParser/{*.data, LICENSE.TXT}
|
||||
ARM contributions llvm/lib/Target/ARM/LICENSE.TXT
|
||||
md5 contributions llvm/lib/Support/MD5.cpp llvm/include/llvm/Support/MD5.h
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -4,7 +4,7 @@
|
||||
set exe_name=odin.exe
|
||||
|
||||
:: Debug = 0, Release = 1
|
||||
set release_mode=1
|
||||
set release_mode=0
|
||||
set compiler_flags= -nologo -Oi -TC -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR-
|
||||
|
||||
if %release_mode% EQU 0 ( rem Debug
|
||||
@@ -45,6 +45,7 @@ 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 code/Jaze/src/main.odin
|
||||
rem && odin build_dll code/example.odin ^
|
||||
rem odin run code/demo.odin
|
||||
|
||||
|
||||
+45
-5
@@ -1,11 +1,32 @@
|
||||
#import "fmt.odin";
|
||||
#import "atomic.odin";
|
||||
#import "hash.odin";
|
||||
#import "math.odin";
|
||||
#import "mem.odin";
|
||||
#import "opengl.odin";
|
||||
#import "os.odin";
|
||||
#import "strconv.odin";
|
||||
#import "sync.odin";
|
||||
|
||||
main :: proc() {
|
||||
// buf: [64]byte;
|
||||
// // len := strconv.generic_ftoa(buf[..], 123.5431, 'f', 4, 64);
|
||||
// x := 624.123;
|
||||
// s := strconv.format_float(buf[..], x, 'f', 6, 64);
|
||||
// fmt.println(s);
|
||||
// fmt.printf("%3d\n", 102);
|
||||
|
||||
s := new_slice(int, 0, 10);
|
||||
append(s, 1, 2, 6, 3, 6, 5, 5, 5, 5, 1, 2);
|
||||
fmt.println(s);
|
||||
|
||||
|
||||
when false {
|
||||
/*
|
||||
Version 0.1.0
|
||||
Version 0.1.1
|
||||
|
||||
Added:
|
||||
* Dynamic Arrays `[...]Type`
|
||||
* Dynamic Arrays `[dynamic]Type`
|
||||
* Dynamic Maps `map[Key]Value`
|
||||
* Dynamic array and map literals
|
||||
* Custom struct alignemnt `struct #align 8 { bar: i8 }`
|
||||
@@ -15,10 +36,20 @@ main :: proc() {
|
||||
* Entities prefixes with an underscore do not get exported on imports
|
||||
* Overloaded `free` for pointers, slices, strings, dynamic arrays, and dynamic maps
|
||||
* enum types have an implict `names` field, a []string of all the names in that enum
|
||||
* immutable variables are "completely immutable" - rules need a full explanation
|
||||
* `slice_to_bytes` - convert any slice to a slice of bytes
|
||||
* `union_cast` allows for optional ok check
|
||||
* Record type field `names` (struct/raw_union/enum)
|
||||
* ?: ternary operator
|
||||
* Unions with variants and common fields
|
||||
* New built-in procedures
|
||||
- `delete` to delete map entries `delete(m, key)`
|
||||
- `clear` to clear dynamic maps and arrays `clear(map_or_array)`
|
||||
- `reserve` to reserve space for the dynamic maps and arrays `reserve(map_or_array)`
|
||||
* Unexported entities and fields using an underscore prefix
|
||||
|
||||
Removed:
|
||||
* Maybe/option types
|
||||
* immutable variables
|
||||
* Remove `type` keyword and other "reserved" keywords
|
||||
* `compile_assert` and `assert`return the value of the condition for semantic reasons
|
||||
|
||||
@@ -29,13 +60,21 @@ main :: proc() {
|
||||
* match x in y {} // For type match statements
|
||||
* Version numbering now starts from 0.1.0 and uses the convention:
|
||||
- major.minor.patch
|
||||
* Core library additions to Windows specific stuff
|
||||
|
||||
Fixes:
|
||||
* Many fmt.* fixes
|
||||
* Overloading bug due to comparison of named types
|
||||
* Overloading bug due to `#import .` collision
|
||||
* disallow a `cast` from pointers of unions
|
||||
* Minor bugs in generated IR code for slices
|
||||
|
||||
To come very Soon™:
|
||||
* Linux and OS X builds (unofficial ones do exist already)
|
||||
*/
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
Fruit :: enum {
|
||||
@@ -85,7 +124,7 @@ main :: proc() {
|
||||
}
|
||||
|
||||
{
|
||||
x: [...]f64;
|
||||
x: [dynamic]f64;
|
||||
reserve(x, 16);
|
||||
defer free(x);
|
||||
append(x, 2_000_000.500_000, 3, 5, 7);
|
||||
@@ -98,7 +137,7 @@ main :: proc() {
|
||||
}
|
||||
|
||||
{
|
||||
x := [...]f64{2_000_000.500_000, 3, 5, 7};
|
||||
x := [dynamic]f64{2_000_000.500_000, 3, 5, 7};
|
||||
defer free(x);
|
||||
fmt.println(x);
|
||||
}
|
||||
@@ -124,4 +163,5 @@ main :: proc() {
|
||||
// align_of([vector 7]i32) != align_of([7]i32) // this may be the case
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+89
-78
@@ -14,25 +14,11 @@
|
||||
|
||||
// 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 may not be used in tuples
|
||||
}
|
||||
Type_Info_Record :: struct #ordered {
|
||||
fields: []Type_Info_Member,
|
||||
size: int, // in bytes
|
||||
align: int, // in bytes
|
||||
packed: bool,
|
||||
ordered: bool,
|
||||
custom_align: bool,
|
||||
}
|
||||
Type_Info_Enum_Value :: raw_union {
|
||||
f: f64,
|
||||
i: i64,
|
||||
}
|
||||
|
||||
// NOTE(bill): This much the same as the compiler's
|
||||
// NOTE(bill): This must match the compiler's
|
||||
Calling_Convention :: enum {
|
||||
ODIN = 0,
|
||||
C = 1,
|
||||
@@ -40,59 +26,61 @@ Calling_Convention :: enum {
|
||||
FAST = 3,
|
||||
}
|
||||
|
||||
Type_Info_Record :: struct #ordered {
|
||||
types: []^Type_Info,
|
||||
names: []string,
|
||||
offsets: []int, // offsets may not be used in tuples
|
||||
size: int, // in bytes
|
||||
align: int, // in bytes
|
||||
packed: bool,
|
||||
ordered: bool,
|
||||
custom_align: bool,
|
||||
}
|
||||
|
||||
Type_Info :: union {
|
||||
Named: 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
|
||||
},
|
||||
String: struct #ordered {},
|
||||
Boolean: struct #ordered {},
|
||||
Any: struct #ordered {},
|
||||
Pointer: struct #ordered {
|
||||
Named{name: string, base: ^Type_Info},
|
||||
Integer{size: int, signed: bool},
|
||||
Float{size: int},
|
||||
String{},
|
||||
Boolean{},
|
||||
Any{},
|
||||
Pointer{
|
||||
elem: ^Type_Info, // nil -> rawptr
|
||||
},
|
||||
Procedure: struct #ordered {
|
||||
Procedure{
|
||||
params: ^Type_Info, // Type_Info.Tuple
|
||||
results: ^Type_Info, // Type_Info.Tuple
|
||||
variadic: bool,
|
||||
convention: Calling_Convention,
|
||||
},
|
||||
Array: struct #ordered {
|
||||
Array{
|
||||
elem: ^Type_Info,
|
||||
elem_size: int,
|
||||
count: int,
|
||||
},
|
||||
Dynamic_Array: struct #ordered {
|
||||
elem: ^Type_Info,
|
||||
elem_size: 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,
|
||||
},
|
||||
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, // Only really used for procedures
|
||||
Struct: Type_Info_Record,
|
||||
Union: Type_Info_Record,
|
||||
Raw_Union: Type_Info_Record,
|
||||
Enum: struct #ordered {
|
||||
Enum{
|
||||
base: ^Type_Info,
|
||||
names: []string,
|
||||
values: []Type_Info_Enum_Value,
|
||||
},
|
||||
Map: struct #ordered {
|
||||
Map{
|
||||
key: ^Type_Info,
|
||||
value: ^Type_Info,
|
||||
generated_struct: ^Type_Info,
|
||||
@@ -100,9 +88,10 @@ Type_Info :: union {
|
||||
},
|
||||
}
|
||||
|
||||
// // NOTE(bill): only the ones that are needed (not all types)
|
||||
// // This will be set by the compiler
|
||||
// immutable __type_infos: []Type_Info;
|
||||
|
||||
// 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 {
|
||||
@@ -318,32 +307,43 @@ __assert :: proc(file: string, line, column: int, msg: string) #inline {
|
||||
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, "%s(%d:%d) Index %d is out of bounds range 0..<%d\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, "%s(%d:%d) Invalid slice indices: [%d:%d]\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, "%s(%d:%d) Invalid substring indices: [%d:%d]\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);
|
||||
@@ -361,8 +361,9 @@ Raw_String :: struct #ordered {
|
||||
};
|
||||
|
||||
Raw_Slice :: struct #ordered {
|
||||
data: rawptr,
|
||||
count: int,
|
||||
data: rawptr,
|
||||
count: int,
|
||||
capacity: int,
|
||||
};
|
||||
|
||||
Raw_Dynamic_Array :: struct #ordered {
|
||||
@@ -373,7 +374,7 @@ Raw_Dynamic_Array :: struct #ordered {
|
||||
};
|
||||
|
||||
Raw_Dynamic_Map :: struct #ordered {
|
||||
hashes: [...]int,
|
||||
hashes: [dynamic]int,
|
||||
entries: Raw_Dynamic_Array,
|
||||
};
|
||||
|
||||
@@ -447,10 +448,30 @@ __dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: in
|
||||
data := cast(^byte)array.data;
|
||||
assert(data != nil);
|
||||
mem.zero(data + (elem_size*array.count), elem_size);
|
||||
array.count += 1;
|
||||
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);
|
||||
@@ -504,7 +525,7 @@ __dynamic_map_rehash :: proc(using header: __Map_Header, new_count: int) {
|
||||
nm.hashes[i] = -1;
|
||||
}
|
||||
|
||||
for i := 0; i < nm.entries.count; i += 1 {
|
||||
for i := 0; i < nm.entries.count; i++ {
|
||||
entry_header := __dynamic_map_get_entry(new_header, i);
|
||||
data := cast(^byte)entry_header;
|
||||
|
||||
@@ -623,7 +644,7 @@ __dynamic_map_add_entry :: proc(using h: __Map_Header, key: __Map_Key) -> int {
|
||||
}
|
||||
|
||||
|
||||
__dynamic_map_remove :: proc(using h: __Map_Header, key: __Map_Key) {
|
||||
__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);
|
||||
@@ -643,7 +664,7 @@ __dynamic_map_erase :: proc(using h: __Map_Header, fr: __Map_Find_Result) {
|
||||
}
|
||||
|
||||
if fr.entry_index == m.entries.count-1 {
|
||||
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);
|
||||
@@ -653,13 +674,3 @@ __dynamic_map_erase :: proc(using h: __Map_Header, fr: __Map_Find_Result) {
|
||||
m.hashes[last.hash_index] = fr.entry_index;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
__print_ti_ptr :: proc(ti: ^Type_Info) {
|
||||
fmt.println(ti);
|
||||
match e in ti {
|
||||
case Type_Info.Enum:
|
||||
fmt.println(e.names);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -37,7 +37,7 @@ spin_lock :: proc(a: ^i32, time_out: int) -> bool { // NOTE(bill) time_out = -1
|
||||
old_value := compare_exchange(a, 1, 0);
|
||||
counter := 0;
|
||||
for old_value != 0 && (time_out < 0 || counter < time_out) {
|
||||
counter += 1;
|
||||
counter++;
|
||||
yield_thread();
|
||||
old_value = compare_exchange(a, 1, 0);
|
||||
mfence();
|
||||
@@ -81,7 +81,7 @@ spin_lock :: proc(a: ^i64, time_out: int) -> bool { // NOTE(bill) time_out = -1
|
||||
old_value := compare_exchange(a, 1, 0);
|
||||
counter := 0;
|
||||
for old_value != 0 && (time_out < 0 || counter < time_out) {
|
||||
counter += 1;
|
||||
counter++;
|
||||
yield_thread();
|
||||
old_value = compare_exchange(a, 1, 0);
|
||||
mfence();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
+368
-389
File diff suppressed because it is too large
Load Diff
+9
-9
@@ -1,14 +1,14 @@
|
||||
crc32 :: proc(data: []byte) -> u32 {
|
||||
result := ~cast(u32)0;
|
||||
for b in data {
|
||||
result = result>>8 ~ __CRC32_TABLE[(result ~ cast(u32)b) & 0xff];
|
||||
result = result>>8 ~ _crc32_table[(result ~ cast(u32)b) & 0xff];
|
||||
}
|
||||
return ~result;
|
||||
}
|
||||
crc64 :: proc(data: []byte) -> u64 {
|
||||
result := ~cast(u64)0;
|
||||
for b in data {
|
||||
result = result>>8 ~ __CRC64_TABLE[(result ~ cast(u64)b) & 0xff];
|
||||
result = result>>8 ~ _crc64_table[(result ~ cast(u64)b) & 0xff];
|
||||
}
|
||||
return ~result;
|
||||
}
|
||||
@@ -66,7 +66,7 @@ murmur32 :: proc(data: []byte) -> u32 {
|
||||
h1 = h1*5 + 0xe6546b64;
|
||||
}
|
||||
|
||||
tail := data[nblocks*4:];
|
||||
tail := data[nblocks*4 ..];
|
||||
|
||||
k1: u32;
|
||||
match tail.count&3 {
|
||||
@@ -146,7 +146,7 @@ murmur64 :: proc(data: []byte) -> u64 {
|
||||
i := 0;
|
||||
for len >= 8 {
|
||||
k1, k2: u32;
|
||||
k1 = data32[i]; i += 1;
|
||||
k1 = data32[i]; i++;
|
||||
k1 *= m;
|
||||
k1 ~= k1>>r;
|
||||
k1 *= m;
|
||||
@@ -154,7 +154,7 @@ murmur64 :: proc(data: []byte) -> u64 {
|
||||
h1 ~= k1;
|
||||
len -= 4;
|
||||
|
||||
k2 = data32[i]; i += 1;
|
||||
k2 = data32[i]; i++;
|
||||
k2 *= m;
|
||||
k2 ~= k2>>r;
|
||||
k2 *= m;
|
||||
@@ -165,7 +165,7 @@ murmur64 :: proc(data: []byte) -> u64 {
|
||||
|
||||
if len >= 4 {
|
||||
k1: u32;
|
||||
k1 = data32[i]; i += 1;
|
||||
k1 = data32[i]; i++;
|
||||
k1 *= m;
|
||||
k1 ~= k1>>r;
|
||||
k1 *= m;
|
||||
@@ -174,7 +174,7 @@ murmur64 :: proc(data: []byte) -> u64 {
|
||||
len -= 4;
|
||||
}
|
||||
|
||||
data8 := slice_to_bytes(data32[i:])[:3];
|
||||
data8 := slice_to_bytes(data32[i..])[..3];
|
||||
match len {
|
||||
case 3:
|
||||
h2 ~= cast(u32)data8[2] << 16;
|
||||
@@ -202,7 +202,7 @@ murmur64 :: proc(data: []byte) -> u64 {
|
||||
}
|
||||
|
||||
|
||||
__CRC32_TABLE := [256]u32{
|
||||
immutable _crc32_table := [256]u32{
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
|
||||
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
||||
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||
@@ -268,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,
|
||||
|
||||
+4
-4
@@ -151,8 +151,8 @@ mat4_identity :: proc() -> Mat4 {
|
||||
}
|
||||
|
||||
mat4_transpose :: proc(m: Mat4) -> Mat4 {
|
||||
for j in 0..<4 {
|
||||
for i in 0..<4 {
|
||||
for j in 0..4 {
|
||||
for i in 0..4 {
|
||||
m[i][j], m[j][i] = m[j][i], m[i][j];
|
||||
}
|
||||
}
|
||||
@@ -161,8 +161,8 @@ mat4_transpose :: proc(m: Mat4) -> Mat4 {
|
||||
|
||||
mul :: proc(a, b: Mat4) -> Mat4 {
|
||||
c: Mat4;
|
||||
for j in 0..<4 {
|
||||
for i in 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] +
|
||||
|
||||
+5
-5
@@ -32,7 +32,7 @@ copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "_
|
||||
|
||||
compare :: proc(a, b: []byte) -> int #link_name "__mem_compare" {
|
||||
n := min(a.count, b.count);
|
||||
for i in 0..<n {
|
||||
for i in 0..n {
|
||||
match {
|
||||
case a[i] < b[i]:
|
||||
return -1;
|
||||
@@ -79,7 +79,7 @@ allocation_header_fill :: proc(header: ^Allocation_Header, data: rawptr, size: i
|
||||
header.size = size;
|
||||
ptr := cast(^int)(header+1);
|
||||
|
||||
for i := 0; cast(rawptr)ptr < data; i += 1 {
|
||||
for i := 0; cast(rawptr)ptr < data; i++ {
|
||||
(ptr+i)^ = -1;
|
||||
}
|
||||
}
|
||||
@@ -117,7 +117,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;
|
||||
}
|
||||
|
||||
@@ -183,7 +183,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;
|
||||
}
|
||||
|
||||
@@ -191,7 +191,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--;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+89
-88
@@ -1,5 +1,6 @@
|
||||
#foreign_system_library lib "opengl32.lib" when ODIN_OS == "windows";
|
||||
#import win32 "sys/windows.odin" when ODIN_OS == "windows";
|
||||
#import "sys/wgl.odin" when ODIN_OS == "windows";
|
||||
#load "opengl_constants.odin";
|
||||
|
||||
Clear :: proc(mask: u32) #foreign lib "glClear";
|
||||
@@ -20,13 +21,13 @@ Viewport :: proc(x, y, width, height: i32) #foreign lib "gl
|
||||
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 lib "glTexImage2D";
|
||||
|
||||
GetError :: proc() -> i32 #foreign lib "glGetError";
|
||||
GetString :: proc(name: i32) -> ^byte #foreign lib "glGetString";
|
||||
GetIntegerv :: proc(name: i32, v: ^i32) #foreign lib "glGetIntegerv";
|
||||
format, type: i32, pixels: rawptr) #foreign lib "glTexImage2D";
|
||||
|
||||
|
||||
string_data :: proc(s: string) -> ^u8 #inline { return ^s[0]; }
|
||||
@@ -35,121 +36,121 @@ _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 { (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");
|
||||
}
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ open :: proc(path: string, mode: int, perm: u32) -> (Handle, Errno) {
|
||||
}
|
||||
|
||||
buf: [300]byte;
|
||||
copy(buf[:], cast([]byte)path);
|
||||
copy(buf[..], cast([]byte)path);
|
||||
|
||||
handle := cast(Handle)CreateFileA(^buf[0], access, share_mode, sa, create_mode, FILE_ATTRIBUTE_NORMAL, nil);
|
||||
if handle != INVALID_HANDLE {
|
||||
@@ -184,7 +184,7 @@ last_write_time_by_name :: proc(name: string) -> File_Time {
|
||||
|
||||
assert(buf.count > name.count);
|
||||
|
||||
copy(buf[:], cast([]byte)name);
|
||||
copy(buf[..], cast([]byte)name);
|
||||
|
||||
if win32.GetFileAttributesExA(^buf[0], win32.GetFileExInfoStandard, ^data) != 0 {
|
||||
last_write_time = data.last_write_time;
|
||||
@@ -201,7 +201,7 @@ last_write_time_by_name :: proc(name: string) -> File_Time {
|
||||
|
||||
read_entire_file :: proc(name: string) -> ([]byte, bool) {
|
||||
buf: [300]byte;
|
||||
copy(buf[:], cast([]byte)name);
|
||||
copy(buf[..], cast([]byte)name);
|
||||
|
||||
fd, err := open(name, O_RDONLY, 0);
|
||||
if err != ERROR_NONE {
|
||||
|
||||
@@ -0,0 +1,336 @@
|
||||
#import . "decimal.odin";
|
||||
#import "math.odin";
|
||||
|
||||
Int_Flag :: enum {
|
||||
PREFIX = 1<<0,
|
||||
PLUS = 1<<1,
|
||||
SPACE = 1<<2,
|
||||
}
|
||||
|
||||
|
||||
parse_bool :: proc(s: string) -> (result: bool, ok: bool) {
|
||||
match s {
|
||||
case "1", "t", "T", "true", "TRUE", "True":
|
||||
return true, true;
|
||||
case "0", "f", "F", "false", "FALSE", "False":
|
||||
return false, true;
|
||||
}
|
||||
return false, false;
|
||||
}
|
||||
|
||||
append_bool :: proc(buf: []byte, b: bool) -> string {
|
||||
s := b ? "true" : "false";
|
||||
append(buf, ..cast([]byte)s);
|
||||
return cast(string)buf;
|
||||
}
|
||||
|
||||
append_uint :: proc(buf: []byte, u: u64, base: int) -> string {
|
||||
return append_bits(buf, u, base, false, digits, 0);
|
||||
}
|
||||
append_int :: proc(buf: []byte, i: i64, base: int) -> string {
|
||||
return append_bits(buf, cast(u64)i, base, i < 0, digits, 0);
|
||||
}
|
||||
itoa :: proc(buf: []byte, i: int) -> string {
|
||||
return append_int(buf, cast(i64)i, 10);
|
||||
}
|
||||
|
||||
append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string {
|
||||
return cast(string)generic_ftoa(buf, f, fmt, prec, bit_size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Decimal_Slice :: struct {
|
||||
digits: []byte,
|
||||
count: int,
|
||||
decimal_point: int,
|
||||
neg: bool,
|
||||
}
|
||||
|
||||
Float_Info :: struct {
|
||||
mantbits: uint,
|
||||
expbits: uint,
|
||||
bias: int,
|
||||
}
|
||||
|
||||
f32_info := Float_Info{23, 8, -127};
|
||||
f64_info := Float_Info{52, 11, -1023};
|
||||
|
||||
|
||||
generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> []byte {
|
||||
bits: u64;
|
||||
flt: ^Float_Info;
|
||||
match bit_size {
|
||||
case 32:
|
||||
bits = cast(u64)transmute(u32)cast(f32)val;
|
||||
flt = ^f32_info;
|
||||
case 64:
|
||||
bits = transmute(u64)val;
|
||||
flt = ^f64_info;
|
||||
default:
|
||||
panic("strconv: invalid bit_size");
|
||||
}
|
||||
|
||||
neg := bits>>(flt.expbits+flt.mantbits) != 0;
|
||||
exp := cast(int)(bits>>flt.mantbits) & (1<<flt.expbits - 1);
|
||||
mant := bits & (cast(u64)1 << flt.mantbits - 1);
|
||||
|
||||
match exp {
|
||||
case 1<<flt.expbits - 1:
|
||||
s: string;
|
||||
if mant != 0 {
|
||||
s = "NaN";
|
||||
} else if neg {
|
||||
s = "-Inf";
|
||||
} else {
|
||||
s = "+Inf";
|
||||
}
|
||||
append(buf, ..cast([]byte)s);
|
||||
return buf;
|
||||
|
||||
case 0: // denormalized
|
||||
exp++;
|
||||
|
||||
default:
|
||||
mant |= cast(u64)1 << flt.mantbits;
|
||||
}
|
||||
|
||||
exp += flt.bias;
|
||||
|
||||
d_: Decimal;
|
||||
d := ^d_;
|
||||
assign(d, mant);
|
||||
shift(d, exp - cast(int)flt.mantbits);
|
||||
digs: Decimal_Slice;
|
||||
shortest := prec < 0;
|
||||
if shortest {
|
||||
round_shortest(d, mant, exp, flt);
|
||||
digs = Decimal_Slice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point};
|
||||
match fmt {
|
||||
case 'e', 'E': prec = digs.count-1;
|
||||
case 'f', 'F': prec = max(digs.count-digs.decimal_point, 0);
|
||||
case 'g', 'G': prec = digs.count;
|
||||
}
|
||||
} else {
|
||||
match fmt {
|
||||
case 'e', 'E': round(d, prec+1);
|
||||
case 'f', 'F': round(d, d.decimal_point+prec);
|
||||
case 'g', 'G':
|
||||
if prec == 0 {
|
||||
prec = 1;
|
||||
}
|
||||
round(d, prec);
|
||||
}
|
||||
|
||||
digs = Decimal_Slice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point};
|
||||
}
|
||||
return format_digits(buf, shortest, neg, digs, prec, fmt);
|
||||
}
|
||||
|
||||
|
||||
|
||||
format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slice, prec: int, fmt: byte) -> []byte {
|
||||
match fmt {
|
||||
case 'f', 'F':
|
||||
add_bytes :: proc(dst: ^[]byte, w: ^int, bytes: ..byte) {
|
||||
for b in bytes {
|
||||
if dst.capacity <= w^ {
|
||||
break;
|
||||
}
|
||||
dst.count++;
|
||||
dst[w^] = b;
|
||||
w^++;
|
||||
}
|
||||
}
|
||||
|
||||
dst := buf[..];
|
||||
w := 0;
|
||||
if neg {
|
||||
add_bytes(^dst, ^w, '-');
|
||||
} else {
|
||||
add_bytes(^dst, ^w, '+');
|
||||
}
|
||||
|
||||
// integer, padded with zeros when needed
|
||||
if digs.decimal_point > 0 {
|
||||
m := min(digs.count, digs.decimal_point);
|
||||
add_bytes(^dst, ^w, ..digs.digits[..m]);
|
||||
for ; m < digs.decimal_point; m++ {
|
||||
add_bytes(^dst, ^w, '0');
|
||||
}
|
||||
} else {
|
||||
add_bytes(^dst, ^w, '0');
|
||||
}
|
||||
|
||||
|
||||
// fractional part
|
||||
if prec > 0 {
|
||||
add_bytes(^dst, ^w, '.');
|
||||
for i in 0..prec {
|
||||
c: byte = '0';
|
||||
if j := digs.decimal_point + i; 0 <= j && j < digs.count {
|
||||
c = digs.digits[j];
|
||||
}
|
||||
add_bytes(^dst, ^w, c);
|
||||
}
|
||||
}
|
||||
|
||||
return buf[..w];
|
||||
|
||||
case 'e', 'E':
|
||||
panic("strconv: e/E float printing is not yet supported");
|
||||
return buf; // TODO
|
||||
|
||||
case 'g', 'G':
|
||||
panic("strconv: g/G float printing is not yet supported");
|
||||
return buf; // TODO
|
||||
}
|
||||
|
||||
c: [2]byte;
|
||||
c[0] = '%';
|
||||
c[1] = fmt;
|
||||
append(buf, ..c[..]);
|
||||
return buf;
|
||||
}
|
||||
|
||||
round_shortest :: proc(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) {
|
||||
if mant == 0 { // If mantissa is zero, the number is zero
|
||||
d.count = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
10^(dp-nd) > 2^(exp-mantbits)
|
||||
log2(10) * (dp-nd) > exp-mantbits
|
||||
log(2) >~ 0.332
|
||||
332*(dp-nd) >= 100*(exp-mantbits)
|
||||
*/
|
||||
minexp := flt.bias+1;
|
||||
if exp > minexp && 332*(d.decimal_point-d.count) >= 100*(exp - cast(int)flt.mantbits) {
|
||||
// Number is already its shortest
|
||||
return;
|
||||
}
|
||||
|
||||
upper_: Decimal; upper: = ^upper_;
|
||||
assign(upper, 2*mant - 1);
|
||||
shift(upper, exp - cast(int)flt.mantbits - 1);
|
||||
|
||||
mantlo: u64;
|
||||
explo: int;
|
||||
if mant > 1<<flt.mantbits || exp == minexp {
|
||||
mantlo = mant-1;
|
||||
explo = exp;
|
||||
} else {
|
||||
mantlo = 2*mant - 1;
|
||||
explo = exp-1;
|
||||
}
|
||||
lower_: Decimal; lower: = ^lower_;
|
||||
assign(lower, 2*mantlo + 1);
|
||||
shift(lower, explo - cast(int)flt.mantbits - 1);
|
||||
|
||||
inclusive := mant%2 == 0;
|
||||
|
||||
for i in 0..d.count {
|
||||
l: byte = '0'; // lower digit
|
||||
if i < lower.count {
|
||||
l = lower.digits[i];
|
||||
}
|
||||
m := d.digits[i]; // middle digit
|
||||
u: byte = '0'; // upper digit
|
||||
if i < upper.count {
|
||||
u = upper.digits[i];
|
||||
}
|
||||
|
||||
ok_round_down := l != m || inclusive && i+1 == lower.count;
|
||||
ok_round_up := m != u && (inclusive || m+1 < u || i+1 < upper.count);
|
||||
|
||||
if (ok_round_down && ok_round_up) {
|
||||
round(d, i+1);
|
||||
return;
|
||||
}
|
||||
if (ok_round_down) {
|
||||
round_down(d, i+1);
|
||||
return;
|
||||
}
|
||||
if (ok_round_up) {
|
||||
round_up(d, i+1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MAX_BASE :: 32;
|
||||
immutable digits := "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
|
||||
append_bits :: proc(buf: []byte, u: u64, base: int, neg: bool, digits: string, flags: Int_Flag) -> string {
|
||||
is_pow2 :: proc(x: i64) -> bool {
|
||||
if (x <= 0) {
|
||||
return false;
|
||||
}
|
||||
return x&(x-1) == 0;
|
||||
}
|
||||
|
||||
if base < 2 || base > MAX_BASE {
|
||||
panic("strconv: illegal base passed to append_bits");
|
||||
}
|
||||
|
||||
a: [65]byte;
|
||||
i := a.count;
|
||||
if neg {
|
||||
u = -u;
|
||||
}
|
||||
|
||||
if is_pow2(cast(i64)base) {
|
||||
b := cast(u64)base;
|
||||
m := cast(uint)b - 1;
|
||||
for u >= b {
|
||||
i--;
|
||||
a[i] = digits[cast(uint)u & m];
|
||||
u >>= b;
|
||||
}
|
||||
i--;
|
||||
a[i] = digits[cast(uint)u];
|
||||
} else {
|
||||
b := cast(u64)base;
|
||||
for u >= b {
|
||||
i--;
|
||||
q := u / b;
|
||||
a[i] = digits[cast(uint)(u-q*b)];
|
||||
u = q;
|
||||
}
|
||||
|
||||
i--;
|
||||
a[i] = digits[cast(uint)u];
|
||||
}
|
||||
|
||||
if flags&Int_Flag.PREFIX != 0 {
|
||||
ok := true;
|
||||
match base {
|
||||
case 2: i--; a[i] = 'b';
|
||||
case 8: i--; a[i] = 'o';
|
||||
case 10: i--; a[i] = 'd';
|
||||
case 16: i--; a[i] = 'x';
|
||||
default: ok = false;
|
||||
}
|
||||
if ok {
|
||||
i--;
|
||||
a[i] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
if neg {
|
||||
i--; a[i] = '-';
|
||||
} else if flags&Int_Flag.PLUS != 0 {
|
||||
i--; a[i] = '+';
|
||||
} else if flags&Int_Flag.SPACE != 0 {
|
||||
i--; a[i] = ' ';
|
||||
}
|
||||
|
||||
|
||||
append(buf, ..a[i..]);
|
||||
return cast(string)buf;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
new_c_string :: proc(s: string) -> ^byte {
|
||||
c := new_slice(byte, s.count+1);
|
||||
copy(c, cast([]byte)s);
|
||||
c[s.count] = 0;
|
||||
return c.data;
|
||||
}
|
||||
|
||||
to_odin_string :: proc(c: ^byte) -> string {
|
||||
s: string;
|
||||
s.data = c;
|
||||
for (c+s.count)^ != 0 {
|
||||
s.count++;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
+31
-31
@@ -2,14 +2,14 @@
|
||||
#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 {
|
||||
@@ -17,74 +17,74 @@ current_thread_id :: proc() -> i32 {
|
||||
}
|
||||
|
||||
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, cast(i32)count, 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.store(^m.counter, 0);
|
||||
atomic.store(^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_add(^m.counter, 1) > 0 {
|
||||
if thread_id != atomic.load(^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.store(^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.load(^m.owner) == thread_id {
|
||||
atomic.fetch_add(^m.counter, 1);
|
||||
if atomic.load(^m._owner) == thread_id {
|
||||
atomic.fetch_add(^m._counter, 1);
|
||||
} else {
|
||||
expected: i32 = 0;
|
||||
if atomic.load(^m.counter) != 0 {
|
||||
if atomic.load(^m._counter) != 0 {
|
||||
return false;
|
||||
}
|
||||
if atomic.compare_exchange(^m.counter, expected, 1) == 0 {
|
||||
if atomic.compare_exchange(^m._counter, expected, 1) == 0 {
|
||||
return false;
|
||||
}
|
||||
atomic.store(^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.load(^m.owner));
|
||||
assert(thread_id == atomic.load(^m._owner));
|
||||
|
||||
m.recursion -= 1;
|
||||
recursion = m.recursion;
|
||||
m._recursion--;
|
||||
recursion = m._recursion;
|
||||
if recursion == 0 {
|
||||
atomic.store(^m.owner, thread_id);
|
||||
atomic.store(^m._owner, thread_id);
|
||||
}
|
||||
|
||||
if atomic.fetch_add(^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;
|
||||
COLORREF :: u32;
|
||||
|
||||
LAYERPLANEDESCRIPTOR :: struct #ordered {
|
||||
size: u16,
|
||||
version: u16,
|
||||
flags: u32,
|
||||
pixel_type: byte,
|
||||
color_bits: byte,
|
||||
red_bits: byte,
|
||||
red_shift: byte,
|
||||
green_bits: byte,
|
||||
green_shift: byte,
|
||||
blue_bits: byte,
|
||||
blue_shift: byte,
|
||||
alpha_bits: byte,
|
||||
alpha_shift: byte,
|
||||
accum_bits: byte,
|
||||
accum_red_bits: byte,
|
||||
accum_green_bits: byte,
|
||||
accum_blue_bits: byte,
|
||||
accum_alpha_bits: byte,
|
||||
depth_bits: byte,
|
||||
stencil_bits: byte,
|
||||
aux_buffers: byte,
|
||||
layer_type: byte,
|
||||
reserved: byte,
|
||||
transparent: COLORREF,
|
||||
}
|
||||
|
||||
POINTFLOAT :: struct #ordered {
|
||||
x, y: f32,
|
||||
}
|
||||
|
||||
GLYPHMETRICSFLOAT :: struct #ordered {
|
||||
black_box_x: f32,
|
||||
black_box_y: f32,
|
||||
glyph_origin: POINTFLOAT,
|
||||
cell_inc_x: f32,
|
||||
cell_inc_y: f32,
|
||||
}
|
||||
|
||||
CreateContextAttribsARBType :: #type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC;
|
||||
ChoosePixelFormatARBType :: #type proc(hdc: HDC, attrib_i_list: ^i32, attrib_f_list: ^f32, max_formats: u32, formats: ^i32, num_formats : ^u32) -> BOOL #cc_c;
|
||||
|
||||
|
||||
CreateContext :: proc(hdc: HDC) -> HGLRC #foreign opengl32 "wglCreateContext";
|
||||
MakeCurrent :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign opengl32 "wglMakeCurrent";
|
||||
GetProcAddress :: proc(c_str: ^u8) -> PROC #foreign opengl32 "wglGetProcAddress";
|
||||
DeleteContext :: proc(hglrc: HGLRC) -> BOOL #foreign opengl32 "wglDeleteContext";
|
||||
CopyContext :: proc(src, dst: HGLRC, mask: u32) -> BOOL #foreign opengl32 "wglCopyContext";
|
||||
CreateLayerContext :: proc(hdc: HDC, layer_plane: i32) -> HGLRC #foreign opengl32 "wglCreateLayerContext";
|
||||
DescribeLayerPlane :: proc(hdc: HDC, pixel_format, layer_plane: i32, bytes: u32, pd: ^LAYERPLANEDESCRIPTOR) -> BOOL #foreign opengl32 "wglDescribeLayerPlane";
|
||||
GetCurrentContext :: proc() -> HGLRC #foreign opengl32 "wglGetCurrentContext";
|
||||
GetCurrentDC :: proc() -> HDC #foreign opengl32 "wglGetCurrentDC";
|
||||
GetLayerPaletteEntries :: proc(hdc: HDC, layer_plane, start, entries: i32, cr: ^COLORREF) -> i32 #foreign opengl32 "wglGetLayerPaletteEntries";
|
||||
RealizeLayerPalette :: proc(hdc: HDC, layer_plane: i32, realize: BOOL) -> BOOL #foreign opengl32 "wglRealizeLayerPalette";
|
||||
SetLayerPaletteEntries :: proc(hdc: HDC, layer_plane, start, entries: i32, cr: ^COLORREF) -> i32 #foreign opengl32 "wglSetLayerPaletteEntries";
|
||||
ShareLists :: proc(hglrc1, hglrc2: HGLRC) -> BOOL #foreign opengl32 "wglShareLists";
|
||||
SwapLayerBuffers :: proc(hdc: HDC, planes: u32) -> BOOL #foreign opengl32 "wglSwapLayerBuffers";
|
||||
UseFontBitmaps :: proc(hdc: HDC, first, count, list_base: u32) -> BOOL #foreign opengl32 "wglUseFontBitmaps";
|
||||
UseFontOutlines :: proc(hdc: HDC, first, count, list_base: u32, deviation, extrusion: f32, format: i32, gmf: ^GLYPHMETRICSFLOAT) -> BOOL #foreign opengl32 "wglUseFontOutlines";
|
||||
+81
-22
@@ -2,7 +2,6 @@
|
||||
#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 "opengl32.lib" when ODIN_OS == "windows";
|
||||
|
||||
HANDLE :: rawptr;
|
||||
HWND :: HANDLE;
|
||||
@@ -41,11 +40,19 @@ 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;
|
||||
|
||||
@@ -165,6 +172,9 @@ DefWindowProcA :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) ->
|
||||
AdjustWindowRect :: proc(rect: ^RECT, style: u32, menu: BOOL) -> BOOL #foreign user32;
|
||||
GetActiveWindow :: proc() -> HWND #foreign user32;
|
||||
|
||||
DestroyWindow :: proc(wnd: HWND) -> BOOL #foreign user32;
|
||||
DescribePixelFormat :: proc(dc: HDC, pixel_format: i32, bytes : u32, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign user32;
|
||||
|
||||
|
||||
GetQueryPerformanceFrequency :: proc() -> i64 {
|
||||
r: i64;
|
||||
@@ -295,6 +305,68 @@ ReadBarrier :: proc() #foreign kernel32;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
HMONITOR :: HANDLE;
|
||||
|
||||
GWL_STYLE :: -16;
|
||||
|
||||
HWND_TOP :: cast(HWND)cast(uint)0;
|
||||
|
||||
MONITOR_DEFAULTTONULL :: 0x00000000;
|
||||
MONITOR_DEFAULTTOPRIMARY :: 0x00000001;
|
||||
MONITOR_DEFAULTTONEAREST :: 0x00000002;
|
||||
|
||||
SWP_FRAMECHANGED :: 0x0020;
|
||||
SWP_NOOWNERZORDER :: 0x0200;
|
||||
SWP_NOZORDER :: 0x0004;
|
||||
SWP_NOSIZE :: 0x0001;
|
||||
SWP_NOMOVE :: 0x0002;
|
||||
|
||||
|
||||
MONITORINFO :: struct #ordered {
|
||||
size: u32,
|
||||
monitor: RECT,
|
||||
work: RECT,
|
||||
flags: u32,
|
||||
}
|
||||
|
||||
WINDOWPLACEMENT :: struct #ordered {
|
||||
length: u32,
|
||||
flags: u32,
|
||||
show_cmd: u32,
|
||||
min_pos: POINT,
|
||||
max_pos: POINT,
|
||||
normal_pos: RECT,
|
||||
}
|
||||
|
||||
GetMonitorInfoA :: proc(monitor: HMONITOR, mi: ^MONITORINFO) -> BOOL #foreign user32;
|
||||
MonitorFromWindow :: proc(wnd: HWND, flags : u32) -> HMONITOR #foreign user32;
|
||||
|
||||
SetWindowPos :: proc(wnd: HWND, wndInsertAfter: HWND, x, y, width, height: i32, flags: u32) #foreign user32 "SetWindowPos";
|
||||
|
||||
GetWindowPlacement :: proc(wnd: HWND, wndpl: ^WINDOWPLACEMENT) -> BOOL #foreign user32;
|
||||
SetWindowPlacement :: proc(wnd: HWND, wndpl: ^WINDOWPLACEMENT) -> BOOL #foreign user32;
|
||||
|
||||
GetWindowLongPtrA :: proc(wnd: HWND, index: i32) -> i64 #foreign user32;
|
||||
SetWindowLongPtrA :: proc(wnd: HWND, index: i32, new: i64) -> i64 #foreign user32;
|
||||
|
||||
GetWindowText :: proc(wnd: HWND, str: ^byte, maxCount: i32) -> i32 #foreign user32;
|
||||
|
||||
HIWORD :: proc(wParam: WPARAM) -> u16 { return cast(u16)((cast(u32)wParam >> 16) & 0xffff); }
|
||||
HIWORD :: proc(lParam: LPARAM) -> u16 { return cast(u16)((cast(u32)lParam >> 16) & 0xffff); }
|
||||
LOWORD :: proc(wParam: WPARAM) -> u16 { return cast(u16)wParam; }
|
||||
LOWORD :: proc(lParam: LPARAM) -> u16 { return cast(u16)lParam; }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
BITMAPINFOHEADER :: struct #ordered {
|
||||
size: u32,
|
||||
width, height: i32,
|
||||
@@ -357,10 +429,6 @@ PFD_DEPTH_DONTCARE :: 0x20000000;
|
||||
PFD_DOUBLEBUFFER_DONTCARE :: 0x40000000;
|
||||
PFD_STEREO_DONTCARE :: 0x80000000;
|
||||
|
||||
HGLRC :: HANDLE;
|
||||
PROC :: #type proc() #cc_c;
|
||||
wglCreateContextAttribsARBType :: #type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC;
|
||||
|
||||
|
||||
PIXELFORMATDESCRIPTOR :: struct #ordered {
|
||||
size,
|
||||
@@ -393,23 +461,14 @@ PIXELFORMATDESCRIPTOR :: struct #ordered {
|
||||
damage_mask: u32,
|
||||
}
|
||||
|
||||
GetDC :: proc(h: HANDLE) -> HDC #foreign user32;
|
||||
SetPixelFormat :: proc(hdc: HDC, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR ) -> BOOL #foreign gdi32;
|
||||
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;
|
||||
|
||||
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 opengl32;
|
||||
wglMakeCurrent :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign opengl32;
|
||||
wglGetProcAddress :: proc(c_str: ^u8) -> PROC #foreign opengl32;
|
||||
wglDeleteContext :: proc(hglrc: HGLRC) -> BOOL #foreign opengl32;
|
||||
|
||||
PROC :: #type proc() #cc_c;
|
||||
|
||||
|
||||
GetKeyState :: proc(v_key: i32) -> i16 #foreign user32;
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
is_signed :: proc(info: ^Type_Info) -> bool {
|
||||
if is_integer(info) {
|
||||
i := cast(^Type_Info.Integer)info;
|
||||
i := union_cast(^Type_Info.Integer)info;
|
||||
return i.signed;
|
||||
}
|
||||
if is_float(info) {
|
||||
|
||||
+53
-9
@@ -30,7 +30,7 @@ HICB :: 0b1011_1111;
|
||||
|
||||
Accept_Range :: struct { lo, hi: u8 }
|
||||
|
||||
accept_ranges := [5]Accept_Range{
|
||||
immutable accept_ranges := [5]Accept_Range{
|
||||
{0x80, 0xbf},
|
||||
{0xa0, 0xbf},
|
||||
{0x80, 0x9f},
|
||||
@@ -38,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
|
||||
@@ -92,7 +92,8 @@ encode_rune :: proc(r: rune) -> ([4]byte, int) {
|
||||
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;
|
||||
@@ -130,6 +131,46 @@ decode_rune :: proc(s: string) -> (rune, int) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
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;
|
||||
@@ -146,7 +187,7 @@ valid_string :: proc(s: string) -> bool {
|
||||
for i := 0; i < n; {
|
||||
si := s[i];
|
||||
if si < RUNE_SELF { // ascii
|
||||
i += 1;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
x := accept_sizes[si];
|
||||
@@ -174,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;
|
||||
|
||||
for i := 0; i < n; {
|
||||
defer count += 1;
|
||||
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 := cast(int)(x & 7);
|
||||
if i+size > n {
|
||||
i += 1;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
ar := accept_ranges[x>>4];
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
// 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
|
||||
@@ -6,13 +8,20 @@ typedef struct BuildContext {
|
||||
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
|
||||
@@ -129,25 +138,6 @@ String odin_root_dir(void) {
|
||||
#error Implement system
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
String path_to_fullpath(gbAllocator a, String s) {
|
||||
@@ -216,9 +206,10 @@ String get_fullpath_core(gbAllocator a, String path) {
|
||||
|
||||
|
||||
|
||||
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.1.0");
|
||||
bc->ODIN_VERSION = str_lit("0.1.1");
|
||||
bc->ODIN_ROOT = odin_root_dir();
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
+2
-13
@@ -72,25 +72,14 @@ 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);
|
||||
}
|
||||
|
||||
@@ -300,7 +289,7 @@ 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;
|
||||
@@ -355,7 +344,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;
|
||||
|
||||
|
||||
+675
-593
File diff suppressed because it is too large
Load Diff
+120
-77
@@ -30,11 +30,6 @@ void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) {
|
||||
case AstNode_ReturnStmt:
|
||||
error_node(n, "Statements after this `return` are never executed");
|
||||
break;
|
||||
case AstNode_ExprStmt:
|
||||
if (n->ExprStmt.expr->kind == AstNode_GiveExpr) {
|
||||
error_node(n, "A `give` must be the last statement in a block");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,40 +177,40 @@ bool check_is_terminating(AstNode *node) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
|
||||
if (op_a->mode == Addressing_Invalid ||
|
||||
(op_a->type == t_invalid && op_a->mode != Addressing_Overload)) {
|
||||
Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
|
||||
if (rhs->mode == Addressing_Invalid ||
|
||||
(rhs->type == t_invalid && rhs->mode != Addressing_Overload)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AstNode *node = unparen_expr(lhs);
|
||||
AstNode *node = unparen_expr(lhs_node);
|
||||
|
||||
// NOTE(bill): Ignore assignments to `_`
|
||||
if (node->kind == AstNode_Ident &&
|
||||
str_eq(node->Ident.string, str_lit("_"))) {
|
||||
add_entity_definition(&c->info, node, NULL);
|
||||
check_assignment(c, op_a, NULL, str_lit("assignment to `_` identifier"));
|
||||
if (op_a->mode == Addressing_Invalid) {
|
||||
check_assignment(c, rhs, NULL, str_lit("assignment to `_` identifier"));
|
||||
if (rhs->mode == Addressing_Invalid) {
|
||||
return NULL;
|
||||
}
|
||||
return op_a->type;
|
||||
return rhs->type;
|
||||
}
|
||||
|
||||
Entity *e = NULL;
|
||||
bool used = false;
|
||||
Operand op_b = {Addressing_Invalid};
|
||||
Operand lhs = {Addressing_Invalid};
|
||||
|
||||
|
||||
check_expr(c, &op_b, lhs);
|
||||
if (op_b.mode == Addressing_Invalid ||
|
||||
op_b.type == t_invalid) {
|
||||
check_expr(c, &lhs, lhs_node);
|
||||
if (lhs.mode == Addressing_Invalid ||
|
||||
lhs.type == t_invalid) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
if (op_a->mode == Addressing_Overload) {
|
||||
isize overload_count = op_a->overload_count;
|
||||
Entity **procs = op_a->overload_entities;
|
||||
if (rhs->mode == Addressing_Overload) {
|
||||
isize overload_count = rhs->overload_count;
|
||||
Entity **procs = rhs->overload_entities;
|
||||
GB_ASSERT(procs != NULL && overload_count > 0);
|
||||
|
||||
// NOTE(bill): These should be done
|
||||
@@ -227,19 +222,19 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
|
||||
Operand x = {0};
|
||||
x.mode = Addressing_Value;
|
||||
x.type = t;
|
||||
if (check_is_assignable_to(c, &x, op_b.type)) {
|
||||
if (check_is_assignable_to(c, &x, lhs.type)) {
|
||||
e = procs[i];
|
||||
add_entity_use(c, op_a->expr, e);
|
||||
add_entity_use(c, rhs->expr, e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (e != NULL) {
|
||||
// HACK TODO(bill): Should the entities be freed as it's technically a leak
|
||||
op_a->mode = Addressing_Value;
|
||||
op_a->type = e->type;
|
||||
op_a->overload_count = 0;
|
||||
op_a->overload_entities = NULL;
|
||||
rhs->mode = Addressing_Value;
|
||||
rhs->type = e->type;
|
||||
rhs->overload_count = 0;
|
||||
rhs->overload_entities = NULL;
|
||||
}
|
||||
} else {
|
||||
if (node->kind == AstNode_Ident) {
|
||||
@@ -256,43 +251,60 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
|
||||
e->flags |= EntityFlag_Used;
|
||||
}
|
||||
|
||||
Type *assignment_type = op_b.type;
|
||||
switch (op_b.mode) {
|
||||
Type *assignment_type = lhs.type;
|
||||
switch (lhs.mode) {
|
||||
case Addressing_Invalid:
|
||||
return NULL;
|
||||
|
||||
case Addressing_Variable:
|
||||
case Addressing_MapIndex:
|
||||
break;
|
||||
case Addressing_MapIndex: {
|
||||
AstNode *ln = unparen_expr(lhs_node);
|
||||
if (ln->kind == AstNode_IndexExpr) {
|
||||
AstNode *x = ln->IndexExpr.expr;
|
||||
TypeAndValue *tav = type_and_value_of_expression(&c->info, x);
|
||||
GB_ASSERT(tav != NULL);
|
||||
if (tav->mode != Addressing_Variable) {
|
||||
if (!is_type_pointer(tav->type)) {
|
||||
gbString str = expr_to_string(lhs.expr);
|
||||
error_node(lhs.expr, "Cannot assign to the value of a map `%s`", str);
|
||||
gb_string_free(str);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
default: {
|
||||
if (op_b.expr->kind == AstNode_SelectorExpr) {
|
||||
if (lhs.expr->kind == AstNode_SelectorExpr) {
|
||||
// NOTE(bill): Extra error checks
|
||||
Operand op_c = {Addressing_Invalid};
|
||||
ast_node(se, SelectorExpr, op_b.expr);
|
||||
ast_node(se, SelectorExpr, lhs.expr);
|
||||
check_expr(c, &op_c, se->expr);
|
||||
if (op_c.mode == Addressing_MapIndex) {
|
||||
gbString str = expr_to_string(op_b.expr);
|
||||
error_node(op_b.expr, "Cannot assign to record field `%s` in map", str);
|
||||
gbString str = expr_to_string(lhs.expr);
|
||||
error_node(lhs.expr, "Cannot assign to record field `%s` in map", str);
|
||||
gb_string_free(str);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
gbString str = expr_to_string(op_b.expr);
|
||||
if (e != NULL && e->kind == Entity_Variable && e->Variable.is_immutable) {
|
||||
error_node(op_b.expr, "Cannot assign to an immutable: `%s`", str);
|
||||
gbString str = expr_to_string(lhs.expr);
|
||||
if (lhs.mode == Addressing_Immutable) {
|
||||
error_node(lhs.expr, "Cannot assign to an immutable: `%s`", str);
|
||||
} else {
|
||||
error_node(op_b.expr, "Cannot assign to `%s`", str);
|
||||
error_node(lhs.expr, "Cannot assign to `%s`", str);
|
||||
}
|
||||
gb_string_free(str);
|
||||
} break;
|
||||
}
|
||||
|
||||
check_assignment(c, op_a, assignment_type, str_lit("assignment"));
|
||||
if (op_a->mode == Addressing_Invalid) {
|
||||
check_assignment(c, rhs, assignment_type, str_lit("assignment"));
|
||||
if (rhs->mode == Addressing_Invalid) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return op_a->type;
|
||||
return rhs->type;
|
||||
}
|
||||
|
||||
bool check_valid_type_match_type(Type *type, bool *is_union_ptr, bool *is_any) {
|
||||
@@ -396,12 +408,6 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
if (operand.expr->kind == AstNode_CallExpr) {
|
||||
return;
|
||||
}
|
||||
if (operand.expr->kind == AstNode_GiveExpr) {
|
||||
if ((flags&Stmt_GiveAllowed) != 0) {
|
||||
return;
|
||||
}
|
||||
error_node(node, "Illegal use of `give`");
|
||||
}
|
||||
gbString expr_str = expr_to_string(operand.expr);
|
||||
error_node(node, "Expression is not used: `%s`", expr_str);
|
||||
gb_string_free(expr_str);
|
||||
@@ -415,44 +421,81 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
check_stmt(c, ts->stmt, flags);
|
||||
case_end;
|
||||
|
||||
case_ast_node(s, IncDecStmt, node);
|
||||
TokenKind op = s->op.kind;
|
||||
switch (op) {
|
||||
case Token_Inc: op = Token_Add; break;
|
||||
case Token_Dec: op = Token_Sub; break;
|
||||
default:
|
||||
error_node(node, "Invalid inc/dec operation");
|
||||
return;
|
||||
}
|
||||
|
||||
Operand x = {0};
|
||||
check_expr(c, &x, s->expr);
|
||||
if (x.mode == Addressing_Invalid) {
|
||||
return;
|
||||
}
|
||||
if (!is_type_integer(x.type) && !is_type_float(x.type)) {
|
||||
gbString e = expr_to_string(s->expr);
|
||||
gbString t = type_to_string(x.type);
|
||||
error_node(node, "%s%.*s used on non-numeric type %s", e, LIT(s->op.string), t);
|
||||
gb_string_free(t);
|
||||
gb_string_free(e);
|
||||
return;
|
||||
}
|
||||
AstNode *left = s->expr;
|
||||
AstNode *right = gb_alloc_item(c->allocator, AstNode);
|
||||
right->kind = AstNode_BasicLit;
|
||||
right->BasicLit.pos = s->op.pos;
|
||||
right->BasicLit.kind = Token_Integer;
|
||||
right->BasicLit.string = str_lit("1");
|
||||
|
||||
AstNode *be = gb_alloc_item(c->allocator, AstNode);
|
||||
be->kind = AstNode_BinaryExpr;
|
||||
be->BinaryExpr.op = s->op;
|
||||
be->BinaryExpr.op.kind = op;
|
||||
be->BinaryExpr.left = left;
|
||||
be->BinaryExpr.right = right;
|
||||
check_binary_expr(c, &x, be);
|
||||
if (x.mode == Addressing_Invalid) {
|
||||
return;
|
||||
}
|
||||
check_assignment_variable(c, &x, left);
|
||||
case_end;
|
||||
|
||||
case_ast_node(as, AssignStmt, node);
|
||||
switch (as->op.kind) {
|
||||
case Token_Eq: {
|
||||
// a, b, c = 1, 2, 3; // Multisided
|
||||
if (as->lhs.count == 0) {
|
||||
|
||||
isize lhs_count = as->lhs.count;
|
||||
if (lhs_count == 0) {
|
||||
error(as->op, "Missing lhs in assignment statement");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(bill): This is a very similar to check_init_variables, should I merge the two some how or just
|
||||
// leave it?
|
||||
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
|
||||
|
||||
// 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;
|
||||
array_init_reserve(&operands, c->tmp_allocator, 2 * as->lhs.count);
|
||||
ArrayOperand operands = {0};
|
||||
array_init_reserve(&operands, c->tmp_allocator, 2 * lhs_count);
|
||||
check_unpack_arguments(c, lhs_count, &operands, as->rhs, true);
|
||||
|
||||
for_array(i, as->rhs) {
|
||||
AstNode *rhs = as->rhs.e[i];
|
||||
Operand o = {0};
|
||||
check_multi_expr(c, &o, rhs);
|
||||
if (o.type->kind != Type_Tuple) {
|
||||
array_add(&operands, o);
|
||||
} else {
|
||||
TypeTuple *tuple = &o.type->Tuple;
|
||||
for (isize j = 0; j < tuple->variable_count; j++) {
|
||||
o.type = tuple->variables[j]->type;
|
||||
array_add(&operands, o);
|
||||
}
|
||||
isize rhs_count = operands.count;
|
||||
for_array(i, operands) {
|
||||
if (operands.e[i].mode == Addressing_Invalid) {
|
||||
rhs_count--;
|
||||
}
|
||||
}
|
||||
|
||||
isize lhs_count = as->lhs.count;
|
||||
isize rhs_count = operands.count;
|
||||
|
||||
isize operand_count = gb_min(as->lhs.count, operands.count);
|
||||
for (isize i = 0; i < operand_count; i++) {
|
||||
AstNode *lhs = as->lhs.e[i];
|
||||
check_assignment_variable(c, &operands.e[i], lhs);
|
||||
isize max = gb_min(lhs_count, rhs_count);
|
||||
for (isize i = 0; i < max; i++) {
|
||||
check_assignment_variable(c, &operands.e[i], as->lhs.e[i]);
|
||||
}
|
||||
if (lhs_count != rhs_count) {
|
||||
error_node(as->lhs.e[0], "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
|
||||
@@ -591,8 +634,9 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
if (fs->post != NULL) {
|
||||
check_stmt(c, fs->post, 0);
|
||||
|
||||
if (fs->post->kind != AstNode_AssignStmt) {
|
||||
error_node(fs->post, "`for` statement post statement must be an assignment");
|
||||
if (fs->post->kind != AstNode_AssignStmt &&
|
||||
fs->post->kind != AstNode_IncDecStmt) {
|
||||
error_node(fs->post, "`for` statement post statement must be a simple statement");
|
||||
}
|
||||
}
|
||||
check_stmt(c, fs->body, new_flags);
|
||||
@@ -671,8 +715,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
|
||||
TokenKind op = Token_Lt;
|
||||
switch (ie->op.kind) {
|
||||
case Token_HalfOpenRange: op = Token_Lt; break;
|
||||
case Token_Ellipsis: op = Token_LtEq; break;
|
||||
case Token_Ellipsis: op = Token_Lt; break;
|
||||
default: error(ie->op, "Invalid range operator"); break;
|
||||
}
|
||||
bool ok = compare_exact_values(Token_Lt, a, b);
|
||||
@@ -1029,8 +1072,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
if (is_union_ptr) {
|
||||
GB_ASSERT(is_type_union(bt));
|
||||
bool tag_type_found = false;
|
||||
for (isize i = 0; i < bt->Record.field_count; i++) {
|
||||
Entity *f = bt->Record.fields[i];
|
||||
for (isize i = 0; i < bt->Record.variant_count; i++) {
|
||||
Entity *f = bt->Record.variants[i];
|
||||
if (are_types_identical(f->type, y.type)) {
|
||||
tag_type_found = true;
|
||||
break;
|
||||
@@ -1038,8 +1081,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
}
|
||||
if (!tag_type_found) {
|
||||
gbString type_str = type_to_string(y.type);
|
||||
error_node(y.expr,
|
||||
"Unknown tag type, got `%s`", type_str);
|
||||
error_node(y.expr, "Unknown tag type, got `%s`", type_str);
|
||||
gb_string_free(type_str);
|
||||
continue;
|
||||
}
|
||||
@@ -1163,8 +1205,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
case Entity_TypeName: {
|
||||
Type *t = base_type(e->type);
|
||||
if (is_type_union(t)) {
|
||||
for (isize i = 0; i < t->Record.field_count; i++) {
|
||||
Entity *f = t->Record.fields[i];
|
||||
for (isize i = 0; i < t->Record.variant_count; i++) {
|
||||
Entity *f = t->Record.variants[i];
|
||||
Entity *found = scope_insert_entity(c->context.scope, f);
|
||||
if (found != NULL) {
|
||||
gbString expr_str = expr_to_string(expr);
|
||||
@@ -1216,6 +1258,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
case Entity_Variable: {
|
||||
Type *t = base_type(type_deref(e->type));
|
||||
if (is_type_struct(t) || is_type_raw_union(t)) {
|
||||
// TODO(bill): Make it work for unions too
|
||||
Scope **found = map_scope_get(&c->info.scopes, hash_pointer(t->Record.node));
|
||||
GB_ASSERT(found != NULL);
|
||||
for_array(i, (*found)->elements.entries) {
|
||||
|
||||
+94
-71
@@ -30,6 +30,7 @@ typedef enum BuiltinProcId {
|
||||
BuiltinProc_reserve,
|
||||
BuiltinProc_clear,
|
||||
BuiltinProc_append,
|
||||
BuiltinProc_delete,
|
||||
|
||||
BuiltinProc_size_of,
|
||||
BuiltinProc_size_of_val,
|
||||
@@ -67,12 +68,13 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
|
||||
{STR_LIT(""), 0, false, Expr_Stmt},
|
||||
|
||||
{STR_LIT("new"), 1, false, Expr_Expr},
|
||||
{STR_LIT("new_slice"), 2, false, Expr_Expr},
|
||||
{STR_LIT("new_slice"), 2, true, Expr_Expr},
|
||||
{STR_LIT("free"), 1, false, Expr_Stmt},
|
||||
|
||||
{STR_LIT("reserve"), 2, false, Expr_Stmt},
|
||||
{STR_LIT("clear"), 1, false, Expr_Stmt},
|
||||
{STR_LIT("append"), 1, true, Expr_Expr},
|
||||
{STR_LIT("delete"), 2, false, Expr_Stmt},
|
||||
|
||||
{STR_LIT("size_of"), 1, false, Expr_Expr},
|
||||
{STR_LIT("size_of_val"), 1, false, Expr_Expr},
|
||||
@@ -106,29 +108,29 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
|
||||
};
|
||||
|
||||
|
||||
|
||||
typedef enum AddressingMode {
|
||||
Addressing_Invalid,
|
||||
|
||||
Addressing_NoValue,
|
||||
Addressing_Value,
|
||||
Addressing_Variable,
|
||||
Addressing_Constant,
|
||||
Addressing_Type,
|
||||
Addressing_Builtin,
|
||||
Addressing_Overload,
|
||||
Addressing_MapIndex,
|
||||
|
||||
Addressing_Count,
|
||||
} AddressingMode;
|
||||
|
||||
#include "types.c"
|
||||
|
||||
#define MAP_TYPE Entity *
|
||||
#define MAP_PROC map_entity_
|
||||
#define MAP_NAME MapEntity
|
||||
#include "map.c"
|
||||
typedef enum AddressingMode {
|
||||
Addressing_Invalid, // invalid addressing mode
|
||||
Addressing_NoValue, // no value (void in C)
|
||||
Addressing_Value, // computed value (rvalue)
|
||||
Addressing_Immutable, // immutable computed value (const rvalue)
|
||||
Addressing_Variable, // addressable variable (lvalue)
|
||||
Addressing_Constant, // constant & type will be a of Type_Basic (stripping Type_Named)
|
||||
Addressing_Type, // type
|
||||
Addressing_Builtin, // built in procedure
|
||||
Addressing_Overload, // overloaded procedure
|
||||
Addressing_MapIndex, // map index expression -
|
||||
// lhs: acts like a Variable
|
||||
// rhs: acts like OptionalOk
|
||||
Addressing_OptionalOk, // rhs: acts like a value with an optional boolean part (for existence check)
|
||||
} AddressingMode;
|
||||
|
||||
// Operand is used as an intermediate value whilst checking
|
||||
// Operands store an addressing mode, the expression being evaluated,
|
||||
// its type and node, and other specific information for certain
|
||||
// addressing modes
|
||||
// Its zero-value is a valid "invalid operand"
|
||||
typedef struct Operand {
|
||||
AddressingMode mode;
|
||||
Type * type;
|
||||
@@ -149,7 +151,9 @@ bool is_operand_value(Operand o) {
|
||||
switch (o.mode) {
|
||||
case Addressing_Value:
|
||||
case Addressing_Variable:
|
||||
case Addressing_Immutable:
|
||||
case Addressing_Constant:
|
||||
case Addressing_MapIndex:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -159,7 +163,7 @@ bool is_operand_nil(Operand o) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
// DeclInfo is used to store information of certain declarations to allow for "any order" usage
|
||||
typedef struct DeclInfo {
|
||||
Scope *scope;
|
||||
|
||||
@@ -173,6 +177,17 @@ typedef struct DeclInfo {
|
||||
MapBool deps; // Key: Entity *
|
||||
} DeclInfo;
|
||||
|
||||
// ProcedureInfo stores the information needed for checking a procedure
|
||||
typedef struct ProcedureInfo {
|
||||
AstFile * file;
|
||||
Token token;
|
||||
DeclInfo *decl;
|
||||
Type * type; // Type_Procedure
|
||||
AstNode * body; // AstNode_BlockStmt
|
||||
u32 tags;
|
||||
} ProcedureInfo;
|
||||
|
||||
// ExprInfo stores information used for "untyped" expressions
|
||||
typedef struct ExprInfo {
|
||||
bool is_lhs; // Debug info
|
||||
AddressingMode mode;
|
||||
@@ -185,14 +200,12 @@ ExprInfo make_expr_info(bool is_lhs, AddressingMode mode, Type *type, ExactValue
|
||||
return ei;
|
||||
}
|
||||
|
||||
typedef struct ProcedureInfo {
|
||||
AstFile * file;
|
||||
Token token;
|
||||
DeclInfo *decl;
|
||||
Type * type; // Type_Procedure
|
||||
AstNode * body; // AstNode_BlockStmt
|
||||
u32 tags;
|
||||
} ProcedureInfo;
|
||||
|
||||
|
||||
#define MAP_TYPE Entity *
|
||||
#define MAP_PROC map_entity_
|
||||
#define MAP_NAME MapEntity
|
||||
#include "map.c"
|
||||
|
||||
typedef struct Scope {
|
||||
Scope * parent;
|
||||
@@ -248,6 +261,7 @@ typedef struct DelayedDecl {
|
||||
} DelayedDecl;
|
||||
|
||||
typedef struct CheckerContext {
|
||||
Scope * file_scope;
|
||||
Scope * scope;
|
||||
DeclInfo * decl;
|
||||
u32 stmt_state_flags;
|
||||
@@ -256,7 +270,7 @@ typedef struct CheckerContext {
|
||||
Type * type_hint;
|
||||
} CheckerContext;
|
||||
|
||||
// NOTE(bill): Symbol tables
|
||||
// CheckerInfo stores all the symbol information for a type-checked program
|
||||
typedef struct CheckerInfo {
|
||||
MapTypeAndValue types; // Key: AstNode * | Expression -> Type (and value)
|
||||
MapEntity definitions; // Key: AstNode * | Identifier -> Entity
|
||||
@@ -264,7 +278,7 @@ typedef struct CheckerInfo {
|
||||
MapScope scopes; // Key: AstNode * | Node -> Scope
|
||||
MapExprInfo untyped; // Key: AstNode * | Expression -> ExprInfo
|
||||
MapDeclInfo entities; // Key: Entity *
|
||||
MapEntity foreign_procs; // Key: String
|
||||
MapEntity foreigns; // Key: String
|
||||
MapAstFile files; // Key: String (full path)
|
||||
MapIsize type_info_map; // Key: Type *
|
||||
isize type_info_count;
|
||||
@@ -275,13 +289,11 @@ typedef struct Checker {
|
||||
CheckerInfo info;
|
||||
|
||||
AstFile * curr_ast_file;
|
||||
BaseTypeSizes sizes;
|
||||
Scope * global_scope;
|
||||
Array(ProcedureInfo) procs; // NOTE(bill): Procedures to check
|
||||
Array(DelayedDecl) delayed_imports;
|
||||
Array(DelayedDecl) delayed_foreign_libraries;
|
||||
|
||||
|
||||
gbArena arena;
|
||||
gbArena tmp_arena;
|
||||
gbAllocator allocator;
|
||||
@@ -391,9 +403,7 @@ void check_open_scope(Checker *c, AstNode *node) {
|
||||
node = unparen_expr(node);
|
||||
GB_ASSERT(node->kind == AstNode_Invalid ||
|
||||
is_ast_node_stmt(node) ||
|
||||
is_ast_node_type(node) ||
|
||||
node->kind == AstNode_BlockExpr ||
|
||||
node->kind == AstNode_IfExpr );
|
||||
is_ast_node_type(node));
|
||||
Scope *scope = make_scope(c->context.scope, c->allocator);
|
||||
add_scope(c, node, scope);
|
||||
if (node->kind == AstNode_ProcType) {
|
||||
@@ -591,7 +601,8 @@ void add_global_string_constant(gbAllocator a, String name, String value) {
|
||||
}
|
||||
|
||||
|
||||
void init_universal_scope(BuildContext *bc) {
|
||||
void init_universal_scope(void) {
|
||||
BuildContext *bc = &build_context;
|
||||
// NOTE(bill): No need to free these
|
||||
gbAllocator a = heap_allocator();
|
||||
universal_scope = make_scope(NULL, a);
|
||||
@@ -650,7 +661,7 @@ void init_checker_info(CheckerInfo *i) {
|
||||
map_scope_init(&i->scopes, a);
|
||||
map_decl_info_init(&i->entities, a);
|
||||
map_expr_info_init(&i->untyped, a);
|
||||
map_entity_init(&i->foreign_procs, a);
|
||||
map_entity_init(&i->foreigns, a);
|
||||
map_isize_init(&i->type_info_map, a);
|
||||
map_ast_file_init(&i->files, a);
|
||||
i->type_info_count = 0;
|
||||
@@ -664,7 +675,7 @@ void destroy_checker_info(CheckerInfo *i) {
|
||||
map_scope_destroy(&i->scopes);
|
||||
map_decl_info_destroy(&i->entities);
|
||||
map_expr_info_destroy(&i->untyped);
|
||||
map_entity_destroy(&i->foreign_procs);
|
||||
map_entity_destroy(&i->foreigns);
|
||||
map_isize_destroy(&i->type_info_map);
|
||||
map_ast_file_destroy(&i->files);
|
||||
}
|
||||
@@ -675,8 +686,6 @@ void init_checker(Checker *c, Parser *parser, BuildContext *bc) {
|
||||
|
||||
c->parser = parser;
|
||||
init_checker_info(&c->info);
|
||||
c->sizes.word_size = bc->word_size;
|
||||
c->sizes.max_align = bc->max_align;
|
||||
|
||||
array_init(&c->proc_stack, a);
|
||||
array_init(&c->procs, a);
|
||||
@@ -945,6 +954,10 @@ void add_type_info_type(Checker *c, Type *t) {
|
||||
break;
|
||||
case TypeRecord_Union:
|
||||
add_type_info_type(c, t_int);
|
||||
for (isize i = 0; i < bt->Record.variant_count; i++) {
|
||||
Entity *f = bt->Record.variants[i];
|
||||
add_type_info_type(c, f->type);
|
||||
}
|
||||
/* fallthrough */
|
||||
default:
|
||||
for (isize i = 0; i < bt->Record.field_count; i++) {
|
||||
@@ -1010,6 +1023,7 @@ void add_curr_ast_file(Checker *c, AstFile *file) {
|
||||
c->curr_ast_file = file;
|
||||
c->context.decl = file->decl_info;
|
||||
c->context.scope = file->scope;
|
||||
c->context.file_scope = file->scope;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1079,44 +1093,41 @@ void init_preload(Checker *c) {
|
||||
}
|
||||
|
||||
if (t_type_info == NULL) {
|
||||
Entity *type_info_entity = find_core_entity(c, str_lit("Type_Info"));
|
||||
Entity *type_info_member_entity = find_core_entity(c, str_lit("Type_Info_Member"));
|
||||
Entity *type_info_enum_value_entity = find_core_entity(c, str_lit("Type_Info_Enum_Value"));
|
||||
Entity *type_info_entity = find_core_entity(c, str_lit("Type_Info"));
|
||||
|
||||
t_type_info = type_info_entity->type;
|
||||
t_type_info_ptr = make_type_pointer(c->allocator, t_type_info);
|
||||
GB_ASSERT(is_type_union(type_info_entity->type));
|
||||
TypeRecord *record = &base_type(type_info_entity->type)->Record;
|
||||
|
||||
t_type_info_member = type_info_member_entity->type;
|
||||
t_type_info_member_ptr = make_type_pointer(c->allocator, t_type_info_member);
|
||||
|
||||
t_type_info_enum_value = type_info_enum_value_entity->type;
|
||||
t_type_info_record = find_core_entity(c, str_lit("Type_Info_Record"))->type;
|
||||
t_type_info_record_ptr = make_type_pointer(c->allocator, t_type_info_record);
|
||||
t_type_info_enum_value = find_core_entity(c, str_lit("Type_Info_Enum_Value"))->type;
|
||||
t_type_info_enum_value_ptr = make_type_pointer(c->allocator, t_type_info_enum_value);
|
||||
|
||||
|
||||
|
||||
if (record->field_count != 19) {
|
||||
if (record->variant_count != 19) {
|
||||
compiler_error("Invalid `Type_Info` layout");
|
||||
}
|
||||
t_type_info_named = record->fields[ 1]->type;
|
||||
t_type_info_integer = record->fields[ 2]->type;
|
||||
t_type_info_float = record->fields[ 3]->type;
|
||||
t_type_info_string = record->fields[ 4]->type;
|
||||
t_type_info_boolean = record->fields[ 5]->type;
|
||||
t_type_info_any = record->fields[ 6]->type;
|
||||
t_type_info_pointer = record->fields[ 7]->type;
|
||||
t_type_info_procedure = record->fields[ 8]->type;
|
||||
t_type_info_array = record->fields[ 9]->type;
|
||||
t_type_info_dynamic_array = record->fields[10]->type;
|
||||
t_type_info_slice = record->fields[11]->type;
|
||||
t_type_info_vector = record->fields[12]->type;
|
||||
t_type_info_tuple = record->fields[13]->type;
|
||||
t_type_info_struct = record->fields[14]->type;
|
||||
t_type_info_union = record->fields[15]->type;
|
||||
t_type_info_raw_union = record->fields[16]->type;
|
||||
t_type_info_enum = record->fields[17]->type;
|
||||
t_type_info_map = record->fields[18]->type;
|
||||
t_type_info_named = record->variants[ 1]->type;
|
||||
t_type_info_integer = record->variants[ 2]->type;
|
||||
t_type_info_float = record->variants[ 3]->type;
|
||||
t_type_info_string = record->variants[ 4]->type;
|
||||
t_type_info_boolean = record->variants[ 5]->type;
|
||||
t_type_info_any = record->variants[ 6]->type;
|
||||
t_type_info_pointer = record->variants[ 7]->type;
|
||||
t_type_info_procedure = record->variants[ 8]->type;
|
||||
t_type_info_array = record->variants[ 9]->type;
|
||||
t_type_info_dynamic_array = record->variants[10]->type;
|
||||
t_type_info_slice = record->variants[11]->type;
|
||||
t_type_info_vector = record->variants[12]->type;
|
||||
t_type_info_tuple = record->variants[13]->type;
|
||||
t_type_info_struct = record->variants[14]->type;
|
||||
t_type_info_raw_union = record->variants[15]->type;
|
||||
t_type_info_union = record->variants[16]->type;
|
||||
t_type_info_enum = record->variants[17]->type;
|
||||
t_type_info_map = record->variants[18]->type;
|
||||
|
||||
t_type_info_named_ptr = make_type_pointer(c->allocator, t_type_info_named);
|
||||
t_type_info_integer_ptr = make_type_pointer(c->allocator, t_type_info_integer);
|
||||
@@ -1132,8 +1143,8 @@ void init_preload(Checker *c) {
|
||||
t_type_info_vector_ptr = make_type_pointer(c->allocator, t_type_info_vector);
|
||||
t_type_info_tuple_ptr = make_type_pointer(c->allocator, t_type_info_tuple);
|
||||
t_type_info_struct_ptr = make_type_pointer(c->allocator, t_type_info_struct);
|
||||
t_type_info_union_ptr = make_type_pointer(c->allocator, t_type_info_union);
|
||||
t_type_info_raw_union_ptr = make_type_pointer(c->allocator, t_type_info_raw_union);
|
||||
t_type_info_union_ptr = make_type_pointer(c->allocator, t_type_info_union);
|
||||
t_type_info_enum_ptr = make_type_pointer(c->allocator, t_type_info_enum);
|
||||
t_type_info_map_ptr = make_type_pointer(c->allocator, t_type_info_map);
|
||||
}
|
||||
@@ -1239,6 +1250,9 @@ void check_procedure_overloading(Checker *c, Entity *e) {
|
||||
ProcTypeOverloadKind kind = are_proc_types_overload_safe(p->type, q->type);
|
||||
switch (kind) {
|
||||
case ProcOverload_Identical:
|
||||
error(p->token, "Overloaded procedure `%.*s` as the same type as another procedure in this scope", LIT(name));
|
||||
is_invalid = true;
|
||||
break;
|
||||
case ProcOverload_CallingConvention:
|
||||
error(p->token, "Overloaded procedure `%.*s` as the same type as another procedure in this scope", LIT(name));
|
||||
is_invalid = true;
|
||||
@@ -1387,8 +1401,14 @@ void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope)
|
||||
di->entities = entities;
|
||||
di->type_expr = vd->type;
|
||||
di->init_expr = vd->values.e[0];
|
||||
|
||||
|
||||
if (vd->flags & VarDeclFlag_thread_local) {
|
||||
error_node(decl, "#thread_local variable declarations cannot have initialization values");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for_array(i, vd->names) {
|
||||
AstNode *name = vd->names.e[i];
|
||||
AstNode *value = NULL;
|
||||
@@ -1400,8 +1420,9 @@ void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope)
|
||||
continue;
|
||||
}
|
||||
Entity *e = make_entity_variable(c->allocator, c->context.scope, name->Ident, NULL, vd->flags & VarDeclFlag_immutable);
|
||||
e->Variable.is_thread_local = vd->flags & VarDeclFlag_thread_local;
|
||||
e->Variable.is_thread_local = (vd->flags & VarDeclFlag_thread_local) != 0;
|
||||
e->identifier = name;
|
||||
|
||||
if (vd->flags & VarDeclFlag_using) {
|
||||
vd->flags &= ~VarDeclFlag_using; // NOTE(bill): This error will be only caught once
|
||||
error_node(name, "`using` is not allowed at the file scope");
|
||||
@@ -1723,6 +1744,8 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
|
||||
Entity *e = make_entity_import_name(c->allocator, parent_scope, id->import_name, t_invalid,
|
||||
id->fullpath, id->import_name.string,
|
||||
scope);
|
||||
|
||||
|
||||
add_entity(c, parent_scope, NULL, e);
|
||||
}
|
||||
}
|
||||
@@ -1886,7 +1909,7 @@ void check_parsed_files(Checker *c) {
|
||||
if (e->kind == Entity_TypeName) {
|
||||
if (e->type != NULL) {
|
||||
// i64 size = type_size_of(c->sizes, c->allocator, e->type);
|
||||
i64 align = type_align_of(c->sizes, c->allocator, e->type);
|
||||
i64 align = type_align_of(c->allocator, e->type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,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_
|
||||
|
||||
+7
-3
@@ -40,12 +40,15 @@ typedef enum EntityFlag {
|
||||
EntityFlag_TypeField = 1<<8,
|
||||
} EntityFlag;
|
||||
|
||||
// Zero value means the overloading process is not yet done
|
||||
typedef enum OverloadKind {
|
||||
Overload_No = -1,
|
||||
Overload_Unknown = 0,
|
||||
Overload_Yes = +1,
|
||||
Overload_Unknown,
|
||||
Overload_No,
|
||||
Overload_Yes,
|
||||
} OverloadKind;
|
||||
|
||||
|
||||
// An Entity is a named "thing" in the language
|
||||
typedef struct Entity Entity;
|
||||
struct Entity {
|
||||
EntityKind kind;
|
||||
@@ -110,6 +113,7 @@ bool is_entity_kind_exported(EntityKind kind) {
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
+4
-3
@@ -274,8 +274,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;
|
||||
@@ -283,8 +282,10 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
|
||||
|
||||
// NOTE(bill): unsigned integers will be negative and will need to be
|
||||
// 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);
|
||||
} break;
|
||||
|
||||
+1
-1
@@ -705,7 +705,7 @@ extern "C++" {
|
||||
#endif
|
||||
|
||||
#ifndef gb_is_between
|
||||
#define gb_is_between(x, lower, upper) (((x) >= (lower)) && ((x) <= (upper)))
|
||||
#define gb_is_between(x, lower, upper) (((lower) <= (x)) && ((x) <= (upper)))
|
||||
#endif
|
||||
|
||||
#ifndef gb_abs
|
||||
|
||||
+82
-35
@@ -137,8 +137,7 @@ 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));
|
||||
@@ -178,7 +177,7 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
|
||||
ir_fprintf(f, "]");
|
||||
return;
|
||||
case Type_Vector: {
|
||||
i64 align = type_align_of(s, heap_allocator(), t);
|
||||
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);
|
||||
@@ -196,7 +195,7 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
|
||||
return;
|
||||
case Type_DynamicArray:
|
||||
ir_fprintf(f, "{");
|
||||
ir_print_type(f, m, t->Slice.elem);
|
||||
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, "}");
|
||||
@@ -204,7 +203,7 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
|
||||
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, "{");
|
||||
@@ -221,22 +220,22 @@ 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, ">");
|
||||
}
|
||||
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);
|
||||
} 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);
|
||||
} return;
|
||||
case TypeRecord_Enum:
|
||||
@@ -455,7 +454,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
||||
break;
|
||||
}
|
||||
|
||||
i64 align = type_align_of(m->sizes, m->allocator, type);
|
||||
i64 align = type_align_of(m->allocator, type);
|
||||
i64 count = type->Vector.count;
|
||||
Type *elem_type = type->Vector.elem;
|
||||
|
||||
@@ -527,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, "{");
|
||||
@@ -544,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, ">");
|
||||
}
|
||||
|
||||
@@ -617,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;
|
||||
@@ -667,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);
|
||||
@@ -681,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: {
|
||||
@@ -714,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: {
|
||||
@@ -842,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;
|
||||
|
||||
@@ -852,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: {;
|
||||
@@ -1249,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;
|
||||
}
|
||||
}
|
||||
@@ -1270,7 +1299,7 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
|
||||
} 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 ");
|
||||
@@ -1324,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1394,6 +1426,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];
|
||||
@@ -1446,6 +1480,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 ");
|
||||
}
|
||||
@@ -1465,19 +1502,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];
|
||||
@@ -1486,19 +1534,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:
|
||||
|
||||
+9
-9
@@ -2,9 +2,10 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#include "common.c"
|
||||
#include "timings.c"
|
||||
#include "build.c"
|
||||
#include "build_settings.c"
|
||||
#include "tokenizer.c"
|
||||
#include "parser.c"
|
||||
// #include "printer.c"
|
||||
@@ -145,10 +146,9 @@ int main(int argc, char **argv) {
|
||||
|
||||
#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;
|
||||
@@ -217,12 +217,12 @@ int main(int argc, char **argv) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
ssa_generate(&checker.info, &build_context);
|
||||
#endif
|
||||
#if 1
|
||||
|
||||
if (!ssa_generate(&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));
|
||||
|
||||
@@ -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
|
||||
|
||||
+336
-303
@@ -84,9 +84,9 @@ typedef enum ProcCallingConvention {
|
||||
} ProcCallingConvention;
|
||||
|
||||
typedef enum VarDeclFlag {
|
||||
VarDeclFlag_thread_local = 1<<0,
|
||||
VarDeclFlag_using = 1<<1,
|
||||
VarDeclFlag_immutable = 1<<2,
|
||||
VarDeclFlag_using = 1<<0,
|
||||
VarDeclFlag_immutable = 1<<1,
|
||||
VarDeclFlag_thread_local = 1<<2,
|
||||
} VarDeclFlag;
|
||||
|
||||
typedef enum StmtStateFlag {
|
||||
@@ -111,7 +111,9 @@ AstNodeArray make_ast_node_array(AstFile *f) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
// NOTE(bill): This massive define is so it is possible to create a discriminated union (and extra debug info)
|
||||
// for the AstNode. I personally prefer discriminated unions over subtype polymorphism as I can preallocate
|
||||
// all the nodes and even memcpy in a different kind of node
|
||||
#define AST_NODE_KINDS \
|
||||
AST_NODE_KIND(Ident, "identifier", Token) \
|
||||
AST_NODE_KIND(Implicit, "implicit", Token) \
|
||||
@@ -149,8 +151,9 @@ AST_NODE_KIND(_ExprBegin, "", i32) \
|
||||
AST_NODE_KIND(DerefExpr, "dereference expression", struct { Token op; AstNode *expr; }) \
|
||||
AST_NODE_KIND(SliceExpr, "slice expression", struct { \
|
||||
AstNode *expr; \
|
||||
Token open, close, interval; \
|
||||
AstNode *low, *high; \
|
||||
Token open, close; \
|
||||
bool index3; \
|
||||
AstNode *low, *high, *max; \
|
||||
}) \
|
||||
AST_NODE_KIND(CallExpr, "call expression", struct { \
|
||||
AstNode * proc; \
|
||||
@@ -166,24 +169,9 @@ AST_NODE_KIND(_ExprBegin, "", i32) \
|
||||
Token open; \
|
||||
Token close; \
|
||||
}) \
|
||||
AST_NODE_KIND(CastExpr, "cast expression", struct { Token token; AstNode *type, *expr; Token open, close; }) \
|
||||
AST_NODE_KIND(FieldValue, "field value", struct { Token eq; AstNode *field, *value; }) \
|
||||
AST_NODE_KIND(BlockExpr, "block expr", struct { \
|
||||
AstNodeArray stmts; \
|
||||
Token open, close; \
|
||||
AstNode *give_node; \
|
||||
}) \
|
||||
AST_NODE_KIND(GiveExpr, "give expression", struct { \
|
||||
Token token; \
|
||||
AstNodeArray results; \
|
||||
}) \
|
||||
AST_NODE_KIND(IfExpr, "if expression", struct { \
|
||||
Token token; \
|
||||
AstNode *init; \
|
||||
AstNode *cond; \
|
||||
AstNode *body; \
|
||||
AstNode *else_expr; \
|
||||
}) \
|
||||
AST_NODE_KIND(CastExpr, "cast expression", struct { Token token; AstNode *type, *expr; Token open, close; }) \
|
||||
AST_NODE_KIND(FieldValue, "field value", struct { Token eq; AstNode *field, *value; }) \
|
||||
AST_NODE_KIND(TernaryExpr, "ternary expression", struct { AstNode *cond, *x, *y; }) \
|
||||
AST_NODE_KIND(IntervalExpr, "interval expression", struct { Token op; AstNode *left, *right; }) \
|
||||
AST_NODE_KIND(_ExprEnd, "", i32) \
|
||||
AST_NODE_KIND(_StmtBegin, "", i32) \
|
||||
@@ -199,6 +187,10 @@ AST_NODE_KIND(_StmtBegin, "", i32) \
|
||||
Token op; \
|
||||
AstNodeArray lhs, rhs; \
|
||||
}) \
|
||||
AST_NODE_KIND(IncDecStmt, "increment decrement statement", struct { \
|
||||
Token op; \
|
||||
AstNode *expr; \
|
||||
}) \
|
||||
AST_NODE_KIND(_ComplexStmtBegin, "", i32) \
|
||||
AST_NODE_KIND(BlockStmt, "block statement", struct { \
|
||||
AstNodeArray stmts; \
|
||||
@@ -315,16 +307,24 @@ AST_NODE_KIND(_DeclEnd, "", i32) \
|
||||
AstNode * type; \
|
||||
u32 flags; \
|
||||
}) \
|
||||
AST_NODE_KIND(FieldList, "field list", struct { \
|
||||
Token token; \
|
||||
AstNodeArray list; \
|
||||
}) \
|
||||
AST_NODE_KIND(UnionField, "union field", struct { \
|
||||
AstNode *name; \
|
||||
AstNode *list; \
|
||||
}) \
|
||||
AST_NODE_KIND(_TypeBegin, "", i32) \
|
||||
AST_NODE_KIND(HelperType, "type", struct { \
|
||||
Token token; \
|
||||
AstNode *type; \
|
||||
}) \
|
||||
AST_NODE_KIND(ProcType, "procedure type", struct { \
|
||||
Token token; \
|
||||
AstNodeArray params; \
|
||||
AstNodeArray results; \
|
||||
u64 tags; \
|
||||
Token token; \
|
||||
AstNode *params; \
|
||||
AstNode *results; \
|
||||
u64 tags; \
|
||||
ProcCallingConvention calling_convention; \
|
||||
}) \
|
||||
AST_NODE_KIND(PointerType, "pointer type", struct { \
|
||||
@@ -354,9 +354,10 @@ AST_NODE_KIND(_TypeBegin, "", i32) \
|
||||
AstNode *align; \
|
||||
}) \
|
||||
AST_NODE_KIND(UnionType, "union type", struct { \
|
||||
Token token; \
|
||||
Token token; \
|
||||
AstNodeArray fields; \
|
||||
isize field_count; \
|
||||
isize field_count; \
|
||||
AstNodeArray variants; \
|
||||
}) \
|
||||
AST_NODE_KIND(RawUnionType, "raw union type", struct { \
|
||||
Token token; \
|
||||
@@ -463,9 +464,7 @@ Token ast_node_token(AstNode *node) {
|
||||
case AstNode_CastExpr: return node->CastExpr.token;
|
||||
case AstNode_FieldValue: return node->FieldValue.eq;
|
||||
case AstNode_DerefExpr: return node->DerefExpr.op;
|
||||
case AstNode_BlockExpr: return node->BlockExpr.open;
|
||||
case AstNode_GiveExpr: return node->GiveExpr.token;
|
||||
case AstNode_IfExpr: return node->IfExpr.token;
|
||||
case AstNode_TernaryExpr: return ast_node_token(node->TernaryExpr.cond);
|
||||
case AstNode_IntervalExpr: return ast_node_token(node->IntervalExpr.left);
|
||||
|
||||
case AstNode_BadStmt: return node->BadStmt.begin;
|
||||
@@ -473,6 +472,7 @@ Token ast_node_token(AstNode *node) {
|
||||
case AstNode_ExprStmt: return ast_node_token(node->ExprStmt.expr);
|
||||
case AstNode_TagStmt: return node->TagStmt.token;
|
||||
case AstNode_AssignStmt: return node->AssignStmt.op;
|
||||
case AstNode_IncDecStmt: return ast_node_token(node->IncDecStmt.expr);
|
||||
case AstNode_BlockStmt: return node->BlockStmt.open;
|
||||
case AstNode_IfStmt: return node->IfStmt.token;
|
||||
case AstNode_WhenStmt: return node->WhenStmt.token;
|
||||
@@ -494,14 +494,15 @@ Token ast_node_token(AstNode *node) {
|
||||
case AstNode_ForeignLibrary: return node->ForeignLibrary.token;
|
||||
|
||||
|
||||
case AstNode_Field: {
|
||||
case AstNode_Field:
|
||||
if (node->Field.names.count > 0) {
|
||||
return ast_node_token(node->Field.names.e[0]);
|
||||
} else {
|
||||
return ast_node_token(node->Field.type);
|
||||
}
|
||||
}
|
||||
|
||||
return ast_node_token(node->Field.type);
|
||||
case AstNode_FieldList:
|
||||
return node->FieldList.token;
|
||||
case AstNode_UnionField:
|
||||
return ast_node_token(node->UnionField.name);
|
||||
|
||||
case AstNode_HelperType: return node->HelperType.token;
|
||||
case AstNode_ProcType: return node->ProcType.token;
|
||||
@@ -667,14 +668,15 @@ AstNode *ast_index_expr(AstFile *f, AstNode *expr, AstNode *index, Token open, T
|
||||
}
|
||||
|
||||
|
||||
AstNode *ast_slice_expr(AstFile *f, AstNode *expr, Token open, Token close, Token interval, AstNode *low, AstNode *high) {
|
||||
AstNode *ast_slice_expr(AstFile *f, AstNode *expr, Token open, Token close, bool index3, AstNode *low, AstNode *high, AstNode *max) {
|
||||
AstNode *result = make_ast_node(f, AstNode_SliceExpr);
|
||||
result->SliceExpr.expr = expr;
|
||||
result->SliceExpr.open = open;
|
||||
result->SliceExpr.close = close;
|
||||
result->SliceExpr.interval = interval;
|
||||
result->SliceExpr.index3 = index3;
|
||||
result->SliceExpr.low = low;
|
||||
result->SliceExpr.high = high;
|
||||
result->SliceExpr.max = max;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -770,29 +772,11 @@ AstNode *ast_compound_lit(AstFile *f, AstNode *type, AstNodeArray elems, Token o
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
AstNode *ast_block_expr(AstFile *f, AstNodeArray stmts, Token open, Token close) {
|
||||
AstNode *result = make_ast_node(f, AstNode_BlockExpr);
|
||||
result->BlockExpr.stmts = stmts;
|
||||
result->BlockExpr.open = open;
|
||||
result->BlockExpr.close = close;
|
||||
return result;
|
||||
}
|
||||
|
||||
AstNode *ast_give_expr(AstFile *f, Token token, AstNodeArray results) {
|
||||
AstNode *result = make_ast_node(f, AstNode_GiveExpr);
|
||||
result->GiveExpr.token = token;
|
||||
result->GiveExpr.results = results;
|
||||
return result;
|
||||
}
|
||||
|
||||
AstNode *ast_if_expr(AstFile *f, Token token, AstNode *init, AstNode *cond, AstNode *body, AstNode *else_expr) {
|
||||
AstNode *result = make_ast_node(f, AstNode_IfExpr);
|
||||
result->IfExpr.token = token;
|
||||
result->IfExpr.init = init;
|
||||
result->IfExpr.cond = cond;
|
||||
result->IfExpr.body = body;
|
||||
result->IfExpr.else_expr = else_expr;
|
||||
AstNode *ast_ternary_expr(AstFile *f, AstNode *cond, AstNode *x, AstNode *y) {
|
||||
AstNode *result = make_ast_node(f, AstNode_TernaryExpr);
|
||||
result->TernaryExpr.cond = cond;
|
||||
result->TernaryExpr.x = x;
|
||||
result->TernaryExpr.y = y;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -825,6 +809,16 @@ AstNode *ast_assign_stmt(AstFile *f, Token op, AstNodeArray lhs, AstNodeArray rh
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
AstNode *ast_inc_dec_stmt(AstFile *f, Token op, AstNode *expr) {
|
||||
AstNode *result = make_ast_node(f, AstNode_IncDecStmt);
|
||||
result->IncDecStmt.op = op;
|
||||
result->IncDecStmt.expr = expr;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AstNode *ast_block_stmt(AstFile *f, AstNodeArray stmts, Token open, Token close) {
|
||||
AstNode *result = make_ast_node(f, AstNode_BlockStmt);
|
||||
result->BlockStmt.stmts = stmts;
|
||||
@@ -989,6 +983,19 @@ AstNode *ast_field(AstFile *f, AstNodeArray names, AstNode *type, u32 flags) {
|
||||
return result;
|
||||
}
|
||||
|
||||
AstNode *ast_field_list(AstFile *f, Token token, AstNodeArray list) {
|
||||
AstNode *result = make_ast_node(f, AstNode_FieldList);
|
||||
result->FieldList.token = token;
|
||||
result->FieldList.list = list;
|
||||
return result;
|
||||
}
|
||||
AstNode *ast_union_field(AstFile *f, AstNode *name, AstNode *list) {
|
||||
AstNode *result = make_ast_node(f, AstNode_UnionField);
|
||||
result->UnionField.name = name;
|
||||
result->UnionField.list = list;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
AstNode *ast_helper_type(AstFile *f, Token token, AstNode *type) {
|
||||
AstNode *result = make_ast_node(f, AstNode_HelperType);
|
||||
@@ -998,7 +1005,7 @@ AstNode *ast_helper_type(AstFile *f, Token token, AstNode *type) {
|
||||
}
|
||||
|
||||
|
||||
AstNode *ast_proc_type(AstFile *f, Token token, AstNodeArray params, AstNodeArray results, u64 tags, ProcCallingConvention calling_convention) {
|
||||
AstNode *ast_proc_type(AstFile *f, Token token, AstNode *params, AstNode *results, u64 tags, ProcCallingConvention calling_convention) {
|
||||
AstNode *result = make_ast_node(f, AstNode_ProcType);
|
||||
result->ProcType.token = token;
|
||||
result->ProcType.params = params;
|
||||
@@ -1039,7 +1046,7 @@ AstNode *ast_vector_type(AstFile *f, Token token, AstNode *count, AstNode *elem)
|
||||
}
|
||||
|
||||
AstNode *ast_struct_type(AstFile *f, Token token, AstNodeArray fields, isize field_count,
|
||||
bool is_packed, bool is_ordered, AstNode *align) {
|
||||
bool is_packed, bool is_ordered, AstNode *align) {
|
||||
AstNode *result = make_ast_node(f, AstNode_StructType);
|
||||
result->StructType.token = token;
|
||||
result->StructType.fields = fields;
|
||||
@@ -1051,11 +1058,12 @@ AstNode *ast_struct_type(AstFile *f, Token token, AstNodeArray fields, isize fie
|
||||
}
|
||||
|
||||
|
||||
AstNode *ast_union_type(AstFile *f, Token token, AstNodeArray fields, isize field_count) {
|
||||
AstNode *ast_union_type(AstFile *f, Token token, AstNodeArray fields, isize field_count, AstNodeArray variants) {
|
||||
AstNode *result = make_ast_node(f, AstNode_UnionType);
|
||||
result->UnionType.token = token;
|
||||
result->UnionType.fields = fields;
|
||||
result->UnionType.field_count = field_count;
|
||||
result->UnionType.variants = variants;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1323,13 +1331,13 @@ void expect_semicolon(AstFile *f, AstNode *s) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
switch (s->kind) {
|
||||
case AstNode_GiveExpr:
|
||||
if (f->curr_token.kind == Token_CloseBrace) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// switch (s->kind) {
|
||||
// case AstNode_GiveExpr:
|
||||
// if (f->curr_token.kind == Token_CloseBrace) {
|
||||
// return;
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
}
|
||||
syntax_error(prev_token, "Expected `;` after %.*s, got %.*s",
|
||||
LIT(ast_node_strings[s->kind]), LIT(token_strings[prev_token.kind]));
|
||||
@@ -1345,7 +1353,6 @@ AstNode * parse_proc_type(AstFile *f, AstNode **foreign_library, String *fore
|
||||
AstNodeArray parse_stmt_list(AstFile *f);
|
||||
AstNode * parse_stmt(AstFile *f);
|
||||
AstNode * parse_body(AstFile *f);
|
||||
void parse_proc_signature(AstFile *f, AstNodeArray *params, AstNodeArray *results);
|
||||
|
||||
|
||||
|
||||
@@ -1614,72 +1621,72 @@ AstNode *convert_stmt_to_expr(AstFile *f, AstNode *statement, String kind) {
|
||||
|
||||
|
||||
|
||||
AstNode *parse_block_expr(AstFile *f) {
|
||||
AstNodeArray stmts = {0};
|
||||
Token open, close;
|
||||
open = expect_token(f, Token_OpenBrace);
|
||||
f->expr_level++;
|
||||
stmts = parse_stmt_list(f);
|
||||
f->expr_level--;
|
||||
close = expect_token(f, Token_CloseBrace);
|
||||
return ast_block_expr(f, stmts, open, close);
|
||||
}
|
||||
// AstNode *parse_block_expr(AstFile *f) {
|
||||
// AstNodeArray stmts = {0};
|
||||
// Token open, close;
|
||||
// open = expect_token(f, Token_OpenBrace);
|
||||
// f->expr_level++;
|
||||
// stmts = parse_stmt_list(f);
|
||||
// f->expr_level--;
|
||||
// close = expect_token(f, Token_CloseBrace);
|
||||
// return ast_block_expr(f, stmts, open, close);
|
||||
// }
|
||||
|
||||
AstNode *parse_if_expr(AstFile *f) {
|
||||
if (f->curr_proc == NULL) {
|
||||
syntax_error(f->curr_token, "You cannot use an if expression in the file scope");
|
||||
return ast_bad_stmt(f, f->curr_token, f->curr_token);
|
||||
}
|
||||
// AstNode *parse_if_expr(AstFile *f) {
|
||||
// if (f->curr_proc == NULL) {
|
||||
// syntax_error(f->curr_token, "You cannot use an if expression in the file scope");
|
||||
// return ast_bad_stmt(f, f->curr_token, f->curr_token);
|
||||
// }
|
||||
|
||||
Token token = expect_token(f, Token_if);
|
||||
AstNode *init = NULL;
|
||||
AstNode *cond = NULL;
|
||||
AstNode *body = NULL;
|
||||
AstNode *else_expr = NULL;
|
||||
// Token token = expect_token(f, Token_if);
|
||||
// AstNode *init = NULL;
|
||||
// AstNode *cond = NULL;
|
||||
// AstNode *body = NULL;
|
||||
// AstNode *else_expr = NULL;
|
||||
|
||||
isize prev_level = f->expr_level;
|
||||
f->expr_level = -1;
|
||||
// isize prev_level = f->expr_level;
|
||||
// f->expr_level = -1;
|
||||
|
||||
if (allow_token(f, Token_Semicolon)) {
|
||||
cond = parse_expr(f, false);
|
||||
} else {
|
||||
init = parse_simple_stmt(f, false);
|
||||
if (allow_token(f, Token_Semicolon)) {
|
||||
cond = parse_expr(f, false);
|
||||
} else {
|
||||
cond = convert_stmt_to_expr(f, init, str_lit("boolean expression"));
|
||||
init = NULL;
|
||||
}
|
||||
}
|
||||
// if (allow_token(f, Token_Semicolon)) {
|
||||
// cond = parse_expr(f, false);
|
||||
// } else {
|
||||
// init = parse_simple_stmt(f, false);
|
||||
// if (allow_token(f, Token_Semicolon)) {
|
||||
// cond = parse_expr(f, false);
|
||||
// } else {
|
||||
// cond = convert_stmt_to_expr(f, init, str_lit("boolean expression"));
|
||||
// init = NULL;
|
||||
// }
|
||||
// }
|
||||
|
||||
f->expr_level = prev_level;
|
||||
// f->expr_level = prev_level;
|
||||
|
||||
if (cond == NULL) {
|
||||
syntax_error(f->curr_token, "Expected condition for if statement");
|
||||
}
|
||||
// if (cond == NULL) {
|
||||
// syntax_error(f->curr_token, "Expected condition for if statement");
|
||||
// }
|
||||
|
||||
body = parse_block_expr(f);
|
||||
// body = parse_block_expr(f);
|
||||
|
||||
if (allow_token(f, Token_else)) {
|
||||
switch (f->curr_token.kind) {
|
||||
case Token_if:
|
||||
else_expr = parse_if_expr(f);
|
||||
break;
|
||||
case Token_OpenBrace:
|
||||
else_expr = parse_block_expr(f);
|
||||
break;
|
||||
default:
|
||||
syntax_error(f->curr_token, "Expected if expression block statement");
|
||||
else_expr = ast_bad_expr(f, f->curr_token, f->tokens.e[f->curr_token_index+1]);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
syntax_error(f->curr_token, "An if expression must have an else clause");
|
||||
return ast_bad_stmt(f, f->curr_token, f->tokens.e[f->curr_token_index+1]);
|
||||
}
|
||||
// if (allow_token(f, Token_else)) {
|
||||
// switch (f->curr_token.kind) {
|
||||
// case Token_if:
|
||||
// else_expr = parse_if_expr(f);
|
||||
// break;
|
||||
// case Token_OpenBrace:
|
||||
// else_expr = parse_block_expr(f);
|
||||
// break;
|
||||
// default:
|
||||
// syntax_error(f->curr_token, "Expected if expression block statement");
|
||||
// else_expr = ast_bad_expr(f, f->curr_token, f->tokens.e[f->curr_token_index+1]);
|
||||
// break;
|
||||
// }
|
||||
// } else {
|
||||
// syntax_error(f->curr_token, "An if expression must have an else clause");
|
||||
// return ast_bad_stmt(f, f->curr_token, f->tokens.e[f->curr_token_index+1]);
|
||||
// }
|
||||
|
||||
return ast_if_expr(f, token, init, cond, body, else_expr);
|
||||
}
|
||||
// return ast_if_expr(f, token, init, cond, body, else_expr);
|
||||
// }
|
||||
|
||||
AstNode *parse_operand(AstFile *f, bool lhs) {
|
||||
AstNode *operand = NULL; // Operand
|
||||
@@ -1793,16 +1800,16 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
|
||||
return type;
|
||||
}
|
||||
|
||||
case Token_if:
|
||||
if (!lhs && f->expr_level >= 0) {
|
||||
return parse_if_expr(f);
|
||||
}
|
||||
break;
|
||||
case Token_OpenBrace:
|
||||
if (!lhs && f->expr_level >= 0) {
|
||||
return parse_block_expr(f);
|
||||
}
|
||||
break;
|
||||
// case Token_if:
|
||||
// if (!lhs && f->expr_level >= 0) {
|
||||
// return parse_if_expr(f);
|
||||
// }
|
||||
// break;
|
||||
// case Token_OpenBrace:
|
||||
// if (!lhs && f->expr_level >= 0) {
|
||||
// return parse_block_expr(f);
|
||||
// }
|
||||
// break;
|
||||
|
||||
default: {
|
||||
AstNode *type = parse_type_or_ident(f);
|
||||
@@ -1940,37 +1947,49 @@ AstNode *parse_atom_expr(AstFile *f, bool lhs) {
|
||||
// TODO(bill): Handle this
|
||||
}
|
||||
Token open = {0}, close = {0}, interval = {0};
|
||||
AstNode *indices[2] = {0};
|
||||
AstNode *indices[3] = {0};
|
||||
isize ellipsis_count = 0;
|
||||
Token ellipses[2] = {0};
|
||||
|
||||
f->expr_level++;
|
||||
open = expect_token(f, Token_OpenBracket);
|
||||
|
||||
// if (f->curr_token.kind != Token_Ellipsis &&
|
||||
// f->curr_token.kind != Token_HalfOpenRange) {
|
||||
if (f->curr_token.kind != Token_Colon) {
|
||||
if (f->curr_token.kind != Token_Ellipsis) {
|
||||
indices[0] = parse_expr(f, false);
|
||||
}
|
||||
bool is_index = true;
|
||||
|
||||
// if (f->curr_token.kind == Token_Ellipsis ||
|
||||
// f->curr_token.kind == Token_HalfOpenRange) {
|
||||
if (f->curr_token.kind == Token_Colon) {
|
||||
is_index = false;
|
||||
interval = f->curr_token;
|
||||
while (f->curr_token.kind == Token_Ellipsis && ellipsis_count < gb_count_of(ellipses)) {
|
||||
ellipses[ellipsis_count++] = f->curr_token;
|
||||
next_token(f);
|
||||
if (f->curr_token.kind != Token_CloseBracket &&
|
||||
if (f->curr_token.kind != Token_Ellipsis &&
|
||||
f->curr_token.kind != Token_CloseBracket &&
|
||||
f->curr_token.kind != Token_EOF) {
|
||||
indices[1] = parse_expr(f, false);
|
||||
indices[ellipsis_count] = parse_expr(f, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
f->expr_level--;
|
||||
close = expect_token(f, Token_CloseBracket);
|
||||
|
||||
if (is_index) {
|
||||
operand = ast_index_expr(f, operand, indices[0], open, close);
|
||||
if (ellipsis_count > 0) {
|
||||
bool index3 = false;
|
||||
if (ellipsis_count == 2) {
|
||||
index3 = true;
|
||||
// 2nd and 3rd index must be present
|
||||
if (indices[1] == NULL) {
|
||||
error(ellipses[0], "2nd index required in 3-index slice expression");
|
||||
indices[1] = ast_bad_expr(f, ellipses[0], ellipses[1]);
|
||||
}
|
||||
if (indices[2] == NULL) {
|
||||
error(ellipses[1], "3rd index required in 3-index slice expression");
|
||||
indices[2] = ast_bad_expr(f, ellipses[1], close);
|
||||
}
|
||||
}
|
||||
operand = ast_slice_expr(f, operand, open, close, index3, indices[0], indices[1], indices[2]);
|
||||
} else {
|
||||
operand = ast_slice_expr(f, operand, open, close, interval, indices[0], indices[1]);
|
||||
operand = ast_index_expr(f, operand, indices[0], open, close);
|
||||
}
|
||||
} break;
|
||||
|
||||
@@ -2040,22 +2059,24 @@ AstNode *parse_unary_expr(AstFile *f, bool lhs) {
|
||||
// NOTE(bill): result == priority
|
||||
i32 token_precedence(TokenKind t) {
|
||||
switch (t) {
|
||||
case Token_CmpOr:
|
||||
case Token_Question:
|
||||
return 1;
|
||||
case Token_CmpAnd:
|
||||
case Token_CmpOr:
|
||||
return 2;
|
||||
case Token_CmpAnd:
|
||||
return 3;
|
||||
case Token_CmpEq:
|
||||
case Token_NotEq:
|
||||
case Token_Lt:
|
||||
case Token_Gt:
|
||||
case Token_LtEq:
|
||||
case Token_GtEq:
|
||||
return 3;
|
||||
return 4;
|
||||
case Token_Add:
|
||||
case Token_Sub:
|
||||
case Token_Or:
|
||||
case Token_Xor:
|
||||
return 4;
|
||||
return 5;
|
||||
case Token_Mul:
|
||||
case Token_Quo:
|
||||
case Token_Mod:
|
||||
@@ -2063,51 +2084,42 @@ i32 token_precedence(TokenKind t) {
|
||||
case Token_AndNot:
|
||||
case Token_Shl:
|
||||
case Token_Shr:
|
||||
return 5;
|
||||
// case Token_as:
|
||||
// case Token_transmute:
|
||||
// case Token_down_cast:
|
||||
// case Token_union_cast:
|
||||
// return 6;
|
||||
return 6;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
AstNode *parse_binary_expr(AstFile *f, bool lhs, i32 prec_in) {
|
||||
AstNode *expression = parse_unary_expr(f, lhs);
|
||||
AstNode *expr = parse_unary_expr(f, lhs);
|
||||
for (i32 prec = token_precedence(f->curr_token.kind); prec >= prec_in; prec--) {
|
||||
for (;;) {
|
||||
AstNode *right;
|
||||
Token op = f->curr_token;
|
||||
i32 op_prec = token_precedence(op.kind);
|
||||
if (op_prec != prec) {
|
||||
// NOTE(bill): This will also catch operators that are not valid "binary" operators
|
||||
break;
|
||||
}
|
||||
expect_operator(f); // NOTE(bill): error checks too
|
||||
if (lhs) {
|
||||
// TODO(bill): error checking
|
||||
lhs = false;
|
||||
}
|
||||
|
||||
switch (op.kind) {
|
||||
/* case Token_as:
|
||||
case Token_transmute:
|
||||
case Token_down_cast:
|
||||
case Token_union_cast:
|
||||
right = parse_type(f);
|
||||
break; */
|
||||
|
||||
default:
|
||||
right = parse_binary_expr(f, false, prec+1);
|
||||
if (op.kind == Token_Question) {
|
||||
AstNode *cond = expr;
|
||||
// Token_Question
|
||||
AstNode *x = parse_expr(f, lhs);
|
||||
Token token_c = expect_token(f, Token_Colon);
|
||||
AstNode *y = parse_expr(f, lhs);
|
||||
expr = ast_ternary_expr(f, cond, x, y);
|
||||
} else {
|
||||
AstNode *right = parse_binary_expr(f, false, prec+1);
|
||||
if (!right) {
|
||||
syntax_error(op, "Expected expression on the right hand side of the binary operator");
|
||||
syntax_error(op, "Expected expression on the right-hand side of the binary operator");
|
||||
}
|
||||
break;
|
||||
expr = ast_binary_expr(f, op, expr, right);
|
||||
}
|
||||
expression = ast_binary_expr(f, op, expression, right);
|
||||
|
||||
lhs = false;
|
||||
}
|
||||
}
|
||||
return expression;
|
||||
return expr;
|
||||
}
|
||||
|
||||
AstNode *parse_expr(AstFile *f, bool lhs) {
|
||||
@@ -2263,7 +2275,6 @@ AstNode *parse_simple_stmt(AstFile *f, bool in_stmt_ok) {
|
||||
allow_token(f, Token_in);
|
||||
AstNode *expr = parse_expr(f, false);
|
||||
switch (f->curr_token.kind) {
|
||||
case Token_HalfOpenRange:
|
||||
case Token_Ellipsis: {
|
||||
Token op = f->curr_token;
|
||||
next_token(f);
|
||||
@@ -2289,6 +2300,13 @@ AstNode *parse_simple_stmt(AstFile *f, bool in_stmt_ok) {
|
||||
return ast_bad_stmt(f, token, f->curr_token);
|
||||
}
|
||||
|
||||
switch (token.kind) {
|
||||
case Token_Inc:
|
||||
case Token_Dec:
|
||||
next_token(f);
|
||||
return ast_inc_dec_stmt(f, token, lhs.e[0]);
|
||||
}
|
||||
|
||||
return ast_expr_stmt(f, lhs.e[0]);
|
||||
}
|
||||
|
||||
@@ -2302,15 +2320,39 @@ AstNode *parse_block_stmt(AstFile *f, b32 is_when) {
|
||||
return parse_body(f);
|
||||
}
|
||||
|
||||
AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind separator, TokenKind follow);
|
||||
|
||||
|
||||
AstNode *parse_results(AstFile *f) {
|
||||
if (!allow_token(f, Token_ArrowRight)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (f->curr_token.kind != Token_OpenParen) {
|
||||
Token begin_token = f->curr_token;
|
||||
AstNodeArray empty_names = {0};
|
||||
AstNodeArray list = make_ast_node_array(f);
|
||||
AstNode *type = parse_type(f);
|
||||
array_add(&list, ast_field(f, empty_names, type, 0));
|
||||
return ast_field_list(f, begin_token, list);
|
||||
}
|
||||
|
||||
AstNode *list = NULL;
|
||||
expect_token(f, Token_OpenParen);
|
||||
list = parse_field_list(f, NULL, 0, Token_Comma, Token_CloseParen);
|
||||
expect_token_after(f, Token_CloseParen, "parameter list");
|
||||
return list;
|
||||
}
|
||||
|
||||
AstNode *parse_proc_type(AstFile *f, AstNode **foreign_library_, String *foreign_name_, String *link_name_) {
|
||||
AstNodeArray params = {0};
|
||||
AstNodeArray results = {0};
|
||||
AstNode *params = {0};
|
||||
AstNode *results = {0};
|
||||
|
||||
Token proc_token = expect_token(f, Token_proc);
|
||||
parse_proc_signature(f, ¶ms, &results);
|
||||
expect_token(f, Token_OpenParen);
|
||||
params = parse_field_list(f, NULL, FieldFlag_Signature, Token_Comma, Token_CloseParen);
|
||||
expect_token_after(f, Token_CloseParen, "parameter list");
|
||||
results = parse_results(f);
|
||||
|
||||
u64 tags = 0;
|
||||
String foreign_name = {0};
|
||||
@@ -2362,7 +2404,7 @@ bool is_token_field_prefix(TokenKind kind) {
|
||||
switch (kind) {
|
||||
case Token_using:
|
||||
case Token_no_alias:
|
||||
// case Token_immutable:
|
||||
case Token_immutable:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -2378,7 +2420,7 @@ u32 parse_field_prefixes(AstFile *f) {
|
||||
switch (f->curr_token.kind) {
|
||||
case Token_using: using_count += 1; next_token(f); break;
|
||||
case Token_no_alias: no_alias_count += 1; next_token(f); break;
|
||||
// case Token_immutable: immutable_count += 1; next_token(f); break;
|
||||
case Token_immutable: immutable_count += 1; next_token(f); break;
|
||||
}
|
||||
}
|
||||
if (using_count > 1) syntax_error(f->curr_token, "Multiple `using` in this field list");
|
||||
@@ -2448,8 +2490,9 @@ AstNodeArray convert_to_ident_list(AstFile *f, AstNodeAndFlagsArray list, bool i
|
||||
return idents;
|
||||
}
|
||||
|
||||
AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags,
|
||||
TokenKind separator, TokenKind follow) {
|
||||
AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind separator, TokenKind follow) {
|
||||
Token start_token = f->curr_token;
|
||||
|
||||
AstNodeArray params = make_ast_node_array(f);
|
||||
AstNodeAndFlagsArray list = {0}; array_init(&list, heap_allocator()); // LEAK(bill):
|
||||
isize total_name_count = 0;
|
||||
@@ -2509,7 +2552,7 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags,
|
||||
}
|
||||
|
||||
if (name_count_) *name_count_ = total_name_count;
|
||||
return params;
|
||||
return ast_field_list(f, start_token, params);
|
||||
}
|
||||
|
||||
for_array(i, list) {
|
||||
@@ -2527,11 +2570,11 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags,
|
||||
}
|
||||
|
||||
if (name_count_) *name_count_ = total_name_count;
|
||||
return params;
|
||||
return ast_field_list(f, start_token, params);
|
||||
}
|
||||
|
||||
|
||||
AstNodeArray parse_record_fields(AstFile *f, isize *field_count_, u32 flags, String context) {
|
||||
AstNode *parse_record_fields(AstFile *f, isize *field_count_, u32 flags, String context) {
|
||||
return parse_field_list(f, field_count_, flags, Token_Comma, Token_CloseBrace);
|
||||
}
|
||||
|
||||
@@ -2576,8 +2619,8 @@ AstNode *parse_type_or_ident(AstFile *f) {
|
||||
AstNode *count_expr = NULL;
|
||||
bool is_vector = false;
|
||||
|
||||
if (f->curr_token.kind == Token_Question) {
|
||||
count_expr = ast_unary_expr(f, expect_token(f, Token_Question), NULL);
|
||||
if (f->curr_token.kind == Token_Ellipsis) {
|
||||
count_expr = ast_unary_expr(f, expect_token(f, Token_Ellipsis), NULL);
|
||||
} else if (f->curr_token.kind == Token_vector) {
|
||||
next_token(f);
|
||||
if (f->curr_token.kind != Token_CloseBracket) {
|
||||
@@ -2588,7 +2631,7 @@ AstNode *parse_type_or_ident(AstFile *f) {
|
||||
syntax_error(f->curr_token, "Vector type missing count");
|
||||
}
|
||||
is_vector = true;
|
||||
} else if (f->curr_token.kind == Token_Ellipsis) {
|
||||
} else if (f->curr_token.kind == Token_dynamic) {
|
||||
next_token(f);
|
||||
expect_token(f, Token_CloseBracket);
|
||||
return ast_dynamic_array_type(f, token, parse_type(f));
|
||||
@@ -2661,29 +2704,84 @@ AstNode *parse_type_or_ident(AstFile *f) {
|
||||
|
||||
Token open = expect_token_after(f, Token_OpenBrace, "struct");
|
||||
isize decl_count = 0;
|
||||
AstNodeArray decls = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("struct"));
|
||||
AstNode *fields = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("struct"));
|
||||
Token close = expect_token(f, Token_CloseBrace);
|
||||
|
||||
AstNodeArray decls = {0};
|
||||
if (fields != NULL) {
|
||||
GB_ASSERT(fields->kind == AstNode_FieldList);
|
||||
decls = fields->FieldList.list;
|
||||
}
|
||||
|
||||
return ast_struct_type(f, token, decls, decl_count, is_packed, is_ordered, align);
|
||||
} break;
|
||||
|
||||
case Token_union: {
|
||||
Token token = expect_token(f, Token_union);
|
||||
Token open = expect_token_after(f, Token_OpenBrace, "union");
|
||||
isize decl_count = 0;
|
||||
AstNodeArray decls = parse_record_fields(f, &decl_count, 0, str_lit("union"));
|
||||
AstNodeArray decls = make_ast_node_array(f);
|
||||
AstNodeArray variants = make_ast_node_array(f);
|
||||
isize total_decl_name_count = 0;
|
||||
|
||||
while (f->curr_token.kind != Token_CloseBrace &&
|
||||
f->curr_token.kind != Token_EOF) {
|
||||
u32 decl_flags = parse_field_prefixes(f);
|
||||
if (decl_flags != 0) {
|
||||
AstNodeArray names = parse_ident_list(f);
|
||||
if (names.count == 0) {
|
||||
syntax_error(f->curr_token, "Empty field declaration");
|
||||
}
|
||||
u32 set_flags = check_field_prefixes(f, names.count, FieldFlag_using, decl_flags);
|
||||
total_decl_name_count += names.count;
|
||||
expect_token_after(f, Token_Colon, "field list");
|
||||
AstNode *type = parse_var_type(f, false);
|
||||
array_add(&decls, ast_field(f, names, type, set_flags));
|
||||
} else {
|
||||
AstNodeArray names = parse_ident_list(f);
|
||||
if (names.count == 0) {
|
||||
break;
|
||||
}
|
||||
if (names.count > 1 || f->curr_token.kind == Token_Colon) {
|
||||
u32 set_flags = check_field_prefixes(f, names.count, FieldFlag_using, decl_flags);
|
||||
total_decl_name_count += names.count;
|
||||
expect_token_after(f, Token_Colon, "field list");
|
||||
AstNode *type = parse_var_type(f, false);
|
||||
array_add(&decls, ast_field(f, names, type, set_flags));
|
||||
} else {
|
||||
AstNode *name = names.e[0];
|
||||
Token open = expect_token(f, Token_OpenBrace);
|
||||
isize decl_count = 0;
|
||||
AstNode *list = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("union"));
|
||||
Token close = expect_token(f, Token_CloseBrace);
|
||||
|
||||
array_add(&variants, ast_union_field(f, name, list));
|
||||
}
|
||||
}
|
||||
if (f->curr_token.kind != Token_Comma) {
|
||||
break;
|
||||
}
|
||||
next_token(f);
|
||||
}
|
||||
|
||||
Token close = expect_token(f, Token_CloseBrace);
|
||||
|
||||
return ast_union_type(f, token, decls, decl_count);
|
||||
|
||||
return ast_union_type(f, token, decls, total_decl_name_count, variants);
|
||||
}
|
||||
|
||||
case Token_raw_union: {
|
||||
Token token = expect_token(f, Token_raw_union);
|
||||
Token open = expect_token_after(f, Token_OpenBrace, "raw_union");
|
||||
isize decl_count = 0;
|
||||
AstNodeArray decls = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("raw_union"));
|
||||
AstNode *fields = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("raw_union"));
|
||||
Token close = expect_token(f, Token_CloseBrace);
|
||||
|
||||
AstNodeArray decls = {0};
|
||||
if (fields != NULL) {
|
||||
GB_ASSERT(fields->kind == AstNode_FieldList);
|
||||
decls = fields->FieldList.list;
|
||||
}
|
||||
|
||||
return ast_raw_union_type(f, token, decls, decl_count);
|
||||
}
|
||||
|
||||
@@ -2723,39 +2821,6 @@ AstNode *parse_type_or_ident(AstFile *f) {
|
||||
}
|
||||
|
||||
|
||||
AstNodeArray parse_results(AstFile *f) {
|
||||
AstNodeArray results = make_ast_node_array(f);
|
||||
if (allow_token(f, Token_ArrowRight)) {
|
||||
if (f->curr_token.kind == Token_OpenParen) {
|
||||
expect_token(f, Token_OpenParen);
|
||||
while (f->curr_token.kind != Token_CloseParen &&
|
||||
f->curr_token.kind != Token_EOF) {
|
||||
array_add(&results, parse_type(f));
|
||||
if (f->curr_token.kind != Token_Comma) {
|
||||
break;
|
||||
}
|
||||
next_token(f);
|
||||
}
|
||||
expect_token(f, Token_CloseParen);
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
array_add(&results, parse_type(f));
|
||||
return results;
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
void parse_proc_signature(AstFile *f,
|
||||
AstNodeArray *params,
|
||||
AstNodeArray *results) {
|
||||
expect_token(f, Token_OpenParen);
|
||||
*params = parse_field_list(f, NULL, FieldFlag_Signature, Token_Comma, Token_CloseParen);
|
||||
expect_token_after(f, Token_CloseParen, "parameter list");
|
||||
*results = parse_results(f);
|
||||
}
|
||||
|
||||
AstNode *parse_body(AstFile *f) {
|
||||
AstNodeArray stmts = {0};
|
||||
Token open, close;
|
||||
@@ -2771,48 +2836,6 @@ AstNode *parse_body(AstFile *f) {
|
||||
return ast_block_stmt(f, stmts, open, close);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
AstNode *parse_proc_decl(AstFile *f) {
|
||||
if (look_ahead_token_kind(f, 1) == Token_OpenParen) {
|
||||
// NOTE(bill): It's an anonymous procedure
|
||||
// NOTE(bill): This look-ahead technically makes the grammar LALR(2)
|
||||
// but is that a problem in practice?
|
||||
return ast_expr_stmt(f, parse_expr(f, true));
|
||||
}
|
||||
|
||||
AstNodeArray params = {0};
|
||||
AstNodeArray results = {0};
|
||||
|
||||
Token proc_token = expect_token(f, Token_proc);
|
||||
AstNode *name = parse_ident(f);
|
||||
parse_proc_signature(f, ¶ms, &results);
|
||||
|
||||
u64 tags = 0;
|
||||
String foreign_name = {0};
|
||||
String link_name = {0};
|
||||
ProcCallingConvention cc = ProcCC_Odin;
|
||||
|
||||
parse_proc_tags(f, &tags, &foreign_name, &link_name, &cc);
|
||||
|
||||
AstNode *proc_type = ast_proc_type(f, proc_token, params, results, tags, cc);
|
||||
AstNode *body = NULL;
|
||||
|
||||
if (f->curr_token.kind == Token_OpenBrace) {
|
||||
if ((tags & ProcTag_foreign) != 0) {
|
||||
syntax_error(proc_token, "A procedure tagged as `#foreign` cannot have a body");
|
||||
}
|
||||
AstNode *curr_proc = f->curr_proc;
|
||||
f->curr_proc = proc_type;
|
||||
body = parse_body(f);
|
||||
f->curr_proc = curr_proc;
|
||||
} else if ((tags & ProcTag_foreign) == 0) {
|
||||
syntax_error(proc_token, "Only a procedure tagged as `#foreign` cannot have a body");
|
||||
}
|
||||
|
||||
return ast_proc_decl(f, name, proc_type, body, tags, foreign_name, link_name);
|
||||
} */
|
||||
|
||||
AstNode *parse_if_stmt(AstFile *f) {
|
||||
if (f->curr_proc == NULL) {
|
||||
syntax_error(f->curr_token, "You cannot use an if statement in the file scope");
|
||||
@@ -2927,27 +2950,27 @@ AstNode *parse_return_stmt(AstFile *f) {
|
||||
}
|
||||
|
||||
|
||||
AstNode *parse_give_stmt(AstFile *f) {
|
||||
if (f->curr_proc == NULL) {
|
||||
syntax_error(f->curr_token, "You cannot use a give statement in the file scope");
|
||||
return ast_bad_stmt(f, f->curr_token, f->curr_token);
|
||||
}
|
||||
if (f->expr_level == 0) {
|
||||
syntax_error(f->curr_token, "A give statement must be used within an expression");
|
||||
return ast_bad_stmt(f, f->curr_token, f->curr_token);
|
||||
}
|
||||
// AstNode *parse_give_stmt(AstFile *f) {
|
||||
// if (f->curr_proc == NULL) {
|
||||
// syntax_error(f->curr_token, "You cannot use a give statement in the file scope");
|
||||
// return ast_bad_stmt(f, f->curr_token, f->curr_token);
|
||||
// }
|
||||
// if (f->expr_level == 0) {
|
||||
// syntax_error(f->curr_token, "A give statement must be used within an expression");
|
||||
// return ast_bad_stmt(f, f->curr_token, f->curr_token);
|
||||
// }
|
||||
|
||||
Token token = expect_token(f, Token_give);
|
||||
AstNodeArray results;
|
||||
if (f->curr_token.kind != Token_Semicolon && f->curr_token.kind != Token_CloseBrace) {
|
||||
results = parse_rhs_expr_list(f);
|
||||
} else {
|
||||
results = make_ast_node_array(f);
|
||||
}
|
||||
AstNode *ge = ast_give_expr(f, token, results);
|
||||
expect_semicolon(f, ge);
|
||||
return ast_expr_stmt(f, ge);
|
||||
}
|
||||
// Token token = expect_token(f, Token_give);
|
||||
// AstNodeArray results;
|
||||
// if (f->curr_token.kind != Token_Semicolon && f->curr_token.kind != Token_CloseBrace) {
|
||||
// results = parse_rhs_expr_list(f);
|
||||
// } else {
|
||||
// results = make_ast_node_array(f);
|
||||
// }
|
||||
// AstNode *ge = ast_give_expr(f, token, results);
|
||||
// expect_semicolon(f, ge);
|
||||
// return ast_expr_stmt(f, ge);
|
||||
// }
|
||||
|
||||
AstNode *parse_for_stmt(AstFile *f) {
|
||||
if (f->curr_proc == NULL) {
|
||||
@@ -3229,7 +3252,7 @@ AstNode *parse_stmt(AstFile *f) {
|
||||
case Token_defer: return parse_defer_stmt(f);
|
||||
case Token_asm: return parse_asm_stmt(f);
|
||||
case Token_return: return parse_return_stmt(f);
|
||||
case Token_give: return parse_give_stmt(f);
|
||||
// case Token_give: return parse_give_stmt(f);
|
||||
|
||||
case Token_break:
|
||||
case Token_continue:
|
||||
@@ -3276,7 +3299,7 @@ AstNode *parse_stmt(AstFile *f) {
|
||||
return ast_bad_stmt(f, token, f->curr_token);
|
||||
} break;
|
||||
|
||||
#if 0
|
||||
#if 1
|
||||
case Token_immutable: {
|
||||
Token token = expect_token(f, Token_immutable);
|
||||
AstNode *node = parse_stmt(f);
|
||||
@@ -3482,8 +3505,18 @@ AstNode *parse_stmt(AstFile *f) {
|
||||
return s;
|
||||
}
|
||||
|
||||
expect_semicolon(f, s);
|
||||
return ast_tag_stmt(f, hash_token, name, parse_stmt(f));
|
||||
|
||||
if (str_eq(tag, str_lit("include"))) {
|
||||
syntax_error(token, "#include is not a valid import declaration kind. Use #load instead");
|
||||
s = ast_bad_stmt(f, token, f->curr_token);
|
||||
} else {
|
||||
syntax_error(token, "Unknown tag directive used: `%.*s`", LIT(tag));
|
||||
s = ast_bad_stmt(f, token, f->curr_token);
|
||||
}
|
||||
|
||||
fix_advance_to_next_stmt(f);
|
||||
|
||||
return s;
|
||||
} break;
|
||||
|
||||
case Token_OpenBrace:
|
||||
|
||||
@@ -19,6 +19,7 @@ typedef struct String {
|
||||
#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;
|
||||
|
||||
+43
-18
@@ -51,8 +51,8 @@ TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \
|
||||
TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \
|
||||
TOKEN_KIND(Token_ArrowRight, "->"), \
|
||||
TOKEN_KIND(Token_ArrowLeft, "<-"), \
|
||||
TOKEN_KIND(Token_Increment, "++"), \
|
||||
TOKEN_KIND(Token_Decrement, "--"), \
|
||||
TOKEN_KIND(Token_Inc, "++"), \
|
||||
TOKEN_KIND(Token_Dec, "--"), \
|
||||
\
|
||||
TOKEN_KIND(Token__ComparisonBegin, "_ComparisonBegin"), \
|
||||
TOKEN_KIND(Token_CmpEq, "=="), \
|
||||
@@ -73,8 +73,8 @@ TOKEN_KIND(Token__ComparisonEnd, "_ComparisonEnd"), \
|
||||
TOKEN_KIND(Token_Semicolon, ";"), \
|
||||
TOKEN_KIND(Token_Period, "."), \
|
||||
TOKEN_KIND(Token_Comma, ","), \
|
||||
TOKEN_KIND(Token_Ellipsis, "..."), \
|
||||
TOKEN_KIND(Token_HalfOpenRange, "..<"), \
|
||||
TOKEN_KIND(Token_Ellipsis, ".."), \
|
||||
/* TOKEN_KIND(Token_HalfOpenRange, "..<"), */ \
|
||||
TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \
|
||||
\
|
||||
TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
||||
@@ -99,9 +99,12 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
||||
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"), \
|
||||
@@ -222,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;
|
||||
@@ -244,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;
|
||||
@@ -831,13 +858,11 @@ Token tokenizer_get_token(Tokenizer *t) {
|
||||
token.kind = Token_Period; // Default
|
||||
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_HalfOpenRange;
|
||||
} else if (t->curr_rune == '.') {
|
||||
advance_to_next_rune(t);
|
||||
token.kind = Token_Ellipsis;
|
||||
}
|
||||
token.kind = Token_Ellipsis;
|
||||
// if (t->curr_rune == '<') {
|
||||
// advance_to_next_rune(t);
|
||||
// token.kind = Token_HalfOpenRange;
|
||||
// }
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -856,13 +881,13 @@ Token tokenizer_get_token(Tokenizer *t) {
|
||||
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_variant3(t, Token_Add, Token_AddEq, '+', Token_Increment); break;
|
||||
case '-': token.kind = token_kind_variant4(t, Token_Sub, Token_SubEq, '-', Token_Decrement, '>', 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) {
|
||||
|
||||
+223
-155
@@ -88,18 +88,21 @@ typedef struct TypeRecord {
|
||||
|
||||
// All record types
|
||||
// Theses are arrays
|
||||
// Entity_Variable - struct/raw_union
|
||||
// Entity_TypeName - union
|
||||
// Entity_Variable - struct/raw_union/union (for common fields)
|
||||
// Entity_Constant - enum
|
||||
Entity **fields;
|
||||
i32 field_count; // == struct_offsets count
|
||||
Entity **fields_in_src_order; // Entity_Variable
|
||||
AstNode *node;
|
||||
|
||||
i64 * struct_offsets;
|
||||
bool struct_are_offsets_set;
|
||||
bool struct_is_packed;
|
||||
bool struct_is_ordered;
|
||||
Entity **fields_in_src_order; // Entity_Variable
|
||||
// Entity_TypeName - union
|
||||
Entity **variants;
|
||||
i32 variant_count;
|
||||
|
||||
i64 * offsets;
|
||||
bool are_offsets_set;
|
||||
bool is_packed;
|
||||
bool is_ordered;
|
||||
|
||||
i64 custom_align; // NOTE(bill): Only used in structs at the moment
|
||||
Entity * names;
|
||||
@@ -178,21 +181,9 @@ typedef struct Type {
|
||||
bool failure;
|
||||
} Type;
|
||||
|
||||
// NOTE(bill): Internal sizes of certain types
|
||||
// string: 2*word_size (ptr+len)
|
||||
// slice: 3*word_size (ptr+len+cap)
|
||||
// array: count*size_of(elem) aligned
|
||||
|
||||
// NOTE(bill): Alignment of structures and other types are to be compatible with C
|
||||
|
||||
typedef struct BaseTypeSizes {
|
||||
i64 word_size;
|
||||
i64 max_align;
|
||||
} BaseTypeSizes;
|
||||
|
||||
|
||||
typedef Array(i32) Array_i32;
|
||||
|
||||
// TODO(bill): Should I add extra information here specifying the kind of selection?
|
||||
// e.g. field, constant, vector field, type field, etc.
|
||||
typedef struct Selection {
|
||||
Entity * entity;
|
||||
Array_i32 index;
|
||||
@@ -208,6 +199,7 @@ Selection make_selection(Entity *entity, Array_i32 index, bool indirect) {
|
||||
void selection_add_index(Selection *s, isize index) {
|
||||
// IMPORTANT NOTE(bill): this requires a stretchy buffer/dynamic array so it requires some form
|
||||
// of heap allocation
|
||||
// TODO(bill): Find a way to use a backing buffer for initial use as the general case is probably .count<3
|
||||
if (s->index.e == NULL) {
|
||||
array_init(&s->index, heap_allocator());
|
||||
}
|
||||
@@ -290,11 +282,12 @@ gb_global Type *t_byte_slice = NULL;
|
||||
gb_global Type *t_string_slice = NULL;
|
||||
|
||||
|
||||
// Type generated for the "preload" file
|
||||
gb_global Type *t_type_info = NULL;
|
||||
gb_global Type *t_type_info_member = NULL;
|
||||
gb_global Type *t_type_info_record = NULL;
|
||||
gb_global Type *t_type_info_enum_value = NULL;
|
||||
gb_global Type *t_type_info_ptr = NULL;
|
||||
gb_global Type *t_type_info_member_ptr = NULL;
|
||||
gb_global Type *t_type_info_record_ptr = NULL;
|
||||
gb_global Type *t_type_info_enum_value_ptr = NULL;
|
||||
|
||||
gb_global Type *t_type_info_named = NULL;
|
||||
@@ -311,12 +304,11 @@ gb_global Type *t_type_info_slice = NULL;
|
||||
gb_global Type *t_type_info_vector = NULL;
|
||||
gb_global Type *t_type_info_tuple = NULL;
|
||||
gb_global Type *t_type_info_struct = NULL;
|
||||
gb_global Type *t_type_info_union = NULL;
|
||||
gb_global Type *t_type_info_raw_union = NULL;
|
||||
gb_global Type *t_type_info_union = NULL;
|
||||
gb_global Type *t_type_info_enum = NULL;
|
||||
gb_global Type *t_type_info_map = NULL;
|
||||
|
||||
|
||||
gb_global Type *t_type_info_named_ptr = NULL;
|
||||
gb_global Type *t_type_info_integer_ptr = NULL;
|
||||
gb_global Type *t_type_info_float_ptr = NULL;
|
||||
@@ -331,13 +323,11 @@ gb_global Type *t_type_info_slice_ptr = NULL;
|
||||
gb_global Type *t_type_info_vector_ptr = NULL;
|
||||
gb_global Type *t_type_info_tuple_ptr = NULL;
|
||||
gb_global Type *t_type_info_struct_ptr = NULL;
|
||||
gb_global Type *t_type_info_union_ptr = NULL;
|
||||
gb_global Type *t_type_info_raw_union_ptr = NULL;
|
||||
gb_global Type *t_type_info_union_ptr = NULL;
|
||||
gb_global Type *t_type_info_enum_ptr = NULL;
|
||||
gb_global Type *t_type_info_map_ptr = NULL;
|
||||
|
||||
|
||||
|
||||
gb_global Type *t_allocator = NULL;
|
||||
gb_global Type *t_allocator_ptr = NULL;
|
||||
gb_global Type *t_context = NULL;
|
||||
@@ -352,8 +342,13 @@ gb_global Type *t_map_header = NULL;
|
||||
|
||||
|
||||
|
||||
i64 type_size_of (gbAllocator allocator, Type *t);
|
||||
i64 type_align_of (gbAllocator allocator, Type *t);
|
||||
i64 type_offset_of (gbAllocator allocator, Type *t, i32 index);
|
||||
gbString type_to_string(Type *type);
|
||||
|
||||
|
||||
|
||||
Type *base_type(Type *t) {
|
||||
for (;;) {
|
||||
if (t == NULL) {
|
||||
@@ -866,8 +861,11 @@ bool are_types_identical(Type *x, Type *y) {
|
||||
case TypeRecord_RawUnion:
|
||||
case TypeRecord_Union:
|
||||
if (x->Record.field_count == y->Record.field_count &&
|
||||
x->Record.struct_is_packed == y->Record.struct_is_packed &&
|
||||
x->Record.struct_is_ordered == y->Record.struct_is_ordered) {
|
||||
x->Record.variant_count == y->Record.variant_count &&
|
||||
x->Record.is_packed == y->Record.is_packed &&
|
||||
x->Record.is_ordered == y->Record.is_ordered &&
|
||||
x->Record.custom_align == y->Record.custom_align) {
|
||||
// TODO(bill); Fix the custom alignment rule
|
||||
for (isize i = 0; i < x->Record.field_count; i++) {
|
||||
if (!are_types_identical(x->Record.fields[i]->type, y->Record.fields[i]->type)) {
|
||||
return false;
|
||||
@@ -876,9 +874,18 @@ bool are_types_identical(Type *x, Type *y) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (isize i = 1; i < x->Record.variant_count; i++) {
|
||||
if (!are_types_identical(x->Record.variants[i]->type, y->Record.variants[i]->type)) {
|
||||
return false;
|
||||
}
|
||||
if (str_ne(x->Record.variants[i]->token.string, y->Record.variants[i]->token.string)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case TypeRecord_Enum:
|
||||
return x == y; // NOTE(bill): All enums are unique
|
||||
}
|
||||
@@ -894,7 +901,7 @@ bool are_types_identical(Type *x, Type *y) {
|
||||
|
||||
case Type_Named:
|
||||
if (y->kind == Type_Named) {
|
||||
return x->Named.base == y->Named.base;
|
||||
return x->Named.type_name == y->Named.type_name;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -929,7 +936,6 @@ bool are_types_identical(Type *x, Type *y) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -970,6 +976,8 @@ bool is_type_cte_safe(Type *type) {
|
||||
|
||||
case Type_DynamicArray:
|
||||
return false;
|
||||
case Type_Map:
|
||||
return false;
|
||||
|
||||
case Type_Vector: // NOTE(bill): This should always to be true but this is for sanity reasons
|
||||
return is_type_cte_safe(type->Vector.elem);
|
||||
@@ -1027,41 +1035,50 @@ typedef enum ProcTypeOverloadKind {
|
||||
ProcTypeOverloadKind are_proc_types_overload_safe(Type *x, Type *y) {
|
||||
if (!is_type_proc(x)) return ProcOverload_NotProcedure;
|
||||
if (!is_type_proc(y)) return ProcOverload_NotProcedure;
|
||||
TypeProc *px = &base_type(x)->Proc;
|
||||
TypeProc *py = &base_type(y)->Proc;
|
||||
TypeProc px = base_type(x)->Proc;
|
||||
TypeProc py = base_type(y)->Proc;
|
||||
|
||||
if (px->calling_convention != py->calling_convention) {
|
||||
if (px.calling_convention != py.calling_convention) {
|
||||
return ProcOverload_CallingConvention;
|
||||
}
|
||||
|
||||
if (px->param_count != py->param_count) {
|
||||
if (px.param_count != py.param_count) {
|
||||
return ProcOverload_ParamCount;
|
||||
}
|
||||
|
||||
for (isize i = 0; i < px->param_count; i++) {
|
||||
Entity *ex = px->params->Tuple.variables[i];
|
||||
Entity *ey = py->params->Tuple.variables[i];
|
||||
for (isize i = 0; i < px.param_count; i++) {
|
||||
Entity *ex = px.params->Tuple.variables[i];
|
||||
Entity *ey = py.params->Tuple.variables[i];
|
||||
if (!are_types_identical(ex->type, ey->type)) {
|
||||
return ProcOverload_ParamTypes;
|
||||
}
|
||||
}
|
||||
// IMPORTANT TODO(bill): Determine the rules for overloading procedures with variadic parameters
|
||||
if (px->variadic != py->variadic) {
|
||||
if (px.variadic != py.variadic) {
|
||||
return ProcOverload_ParamVariadic;
|
||||
}
|
||||
|
||||
if (px->result_count != py->result_count) {
|
||||
if (px.result_count != py.result_count) {
|
||||
return ProcOverload_ResultCount;
|
||||
}
|
||||
|
||||
for (isize i = 0; i < px->result_count; i++) {
|
||||
Entity *ex = px->results->Tuple.variables[i];
|
||||
Entity *ey = py->results->Tuple.variables[i];
|
||||
for (isize i = 0; i < px.result_count; i++) {
|
||||
Entity *ex = px.results->Tuple.variables[i];
|
||||
Entity *ey = py.results->Tuple.variables[i];
|
||||
if (!are_types_identical(ex->type, ey->type)) {
|
||||
return ProcOverload_ResultTypes;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Entity *ex = px.params->Tuple.variables[0];
|
||||
Entity *ey = py.params->Tuple.variables[0];
|
||||
bool ok = are_types_identical(ex->type, ey->type);
|
||||
if (ok) {
|
||||
gb_printf_err("Here\n");
|
||||
}
|
||||
}
|
||||
|
||||
return ProcOverload_Identical;
|
||||
}
|
||||
|
||||
@@ -1073,6 +1090,7 @@ gb_global Entity *entity__any_data = NULL;
|
||||
gb_global Entity *entity__string_data = NULL;
|
||||
gb_global Entity *entity__string_count = NULL;
|
||||
gb_global Entity *entity__slice_count = NULL;
|
||||
gb_global Entity *entity__slice_capacity = NULL;
|
||||
|
||||
gb_global Entity *entity__dynamic_array_count = NULL;
|
||||
gb_global Entity *entity__dynamic_array_capacity = NULL;
|
||||
@@ -1234,6 +1252,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
|
||||
} else if (type->kind == Type_Slice) {
|
||||
String data_str = str_lit("data");
|
||||
String count_str = str_lit("count");
|
||||
String capacity_str = str_lit("capacity");
|
||||
|
||||
if (str_eq(field_name, data_str)) {
|
||||
selection_add_index(&sel, 0);
|
||||
@@ -1248,7 +1267,16 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
|
||||
|
||||
sel.entity = entity__slice_count;
|
||||
return sel;
|
||||
} else if (str_eq(field_name, capacity_str)) {
|
||||
selection_add_index(&sel, 2);
|
||||
if (entity__slice_capacity == NULL) {
|
||||
entity__slice_capacity = make_entity_field(a, NULL, make_token_ident(capacity_str), t_int, false, 2);
|
||||
}
|
||||
|
||||
sel.entity = entity__slice_capacity;
|
||||
return sel;
|
||||
}
|
||||
|
||||
} else if (type->kind == Type_DynamicArray) {
|
||||
String data_str = str_lit("data");
|
||||
String count_str = str_lit("count");
|
||||
@@ -1314,9 +1342,6 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
|
||||
}
|
||||
}
|
||||
|
||||
if (type->kind != Type_Record) {
|
||||
return sel;
|
||||
}
|
||||
if (is_type) {
|
||||
if (type->kind == Type_Record) {
|
||||
if (type->Record.names != NULL &&
|
||||
@@ -1327,14 +1352,12 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
|
||||
}
|
||||
|
||||
if (is_type_union(type)) {
|
||||
// NOTE(bill): The subtype for a union are stored in the fields
|
||||
// as they are "kind of" like variables but not
|
||||
for (isize i = 0; i < type->Record.field_count; i++) {
|
||||
Entity *f = type->Record.fields[i];
|
||||
for (isize i = 1; i < type->Record.variant_count; i++) {
|
||||
Entity *f = type->Record.variants[i];
|
||||
GB_ASSERT(f->kind == Entity_TypeName);
|
||||
String str = f->token.string;
|
||||
|
||||
if (str_eq(field_name, str)) {
|
||||
if (str_eq(str, field_name)) {
|
||||
sel.entity = f;
|
||||
// selection_add_index(&sel, i);
|
||||
return sel;
|
||||
@@ -1369,7 +1392,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (!is_type_union(type)) {
|
||||
} else if (type->kind == Type_Record) {
|
||||
for (isize i = 0; i < type->Record.field_count; i++) {
|
||||
Entity *f = type->Record.fields[i];
|
||||
if (f->kind != Entity_Variable || (f->flags & EntityFlag_Field) == 0) {
|
||||
@@ -1461,12 +1484,8 @@ void type_path_pop(TypePath *tp) {
|
||||
#define FAILURE_ALIGNMENT 0
|
||||
|
||||
|
||||
i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t);
|
||||
i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t);
|
||||
i64 type_offset_of(BaseTypeSizes s, gbAllocator allocator, Type *t, i32 index);
|
||||
|
||||
i64 type_size_of_internal (BaseTypeSizes s, gbAllocator allocator, Type *t, TypePath *path);
|
||||
i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypePath *path);
|
||||
i64 type_size_of_internal (gbAllocator allocator, Type *t, TypePath *path);
|
||||
i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path);
|
||||
|
||||
i64 align_formula(i64 size, i64 align) {
|
||||
if (align > 0) {
|
||||
@@ -1476,32 +1495,32 @@ i64 align_formula(i64 size, i64 align) {
|
||||
return size;
|
||||
}
|
||||
|
||||
i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t) {
|
||||
i64 type_size_of(gbAllocator allocator, Type *t) {
|
||||
if (t == NULL) {
|
||||
return 0;
|
||||
}
|
||||
i64 size;
|
||||
TypePath path = {0};
|
||||
type_path_init(&path);
|
||||
size = type_size_of_internal(s, allocator, t, &path);
|
||||
size = type_size_of_internal(allocator, t, &path);
|
||||
type_path_free(&path);
|
||||
return size;
|
||||
}
|
||||
|
||||
i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t) {
|
||||
i64 type_align_of(gbAllocator allocator, Type *t) {
|
||||
if (t == NULL) {
|
||||
return 1;
|
||||
}
|
||||
i64 align;
|
||||
TypePath path = {0};
|
||||
type_path_init(&path);
|
||||
align = type_align_of_internal(s, allocator, t, &path);
|
||||
align = type_align_of_internal(allocator, t, &path);
|
||||
type_path_free(&path);
|
||||
return align;
|
||||
}
|
||||
|
||||
|
||||
i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypePath *path) {
|
||||
i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
||||
if (t->failure) {
|
||||
return FAILURE_ALIGNMENT;
|
||||
}
|
||||
@@ -1511,11 +1530,11 @@ i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, Type
|
||||
case Type_Basic: {
|
||||
GB_ASSERT(is_type_typed(t));
|
||||
switch (t->kind) {
|
||||
case Basic_string: return s.word_size;
|
||||
case Basic_any: return s.word_size;
|
||||
case Basic_string: return build_context.word_size;
|
||||
case Basic_any: return build_context.word_size;
|
||||
|
||||
case Basic_int: case Basic_uint: case Basic_rawptr:
|
||||
return s.word_size;
|
||||
return build_context.word_size;
|
||||
}
|
||||
} break;
|
||||
|
||||
@@ -1525,17 +1544,17 @@ i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, Type
|
||||
if (path->failure) {
|
||||
return FAILURE_ALIGNMENT;
|
||||
}
|
||||
i64 align = type_align_of_internal(s, allocator, t->Array.elem, path);
|
||||
i64 align = type_align_of_internal(allocator, t->Array.elem, path);
|
||||
type_path_pop(path);
|
||||
return align;
|
||||
}
|
||||
|
||||
case Type_DynamicArray:
|
||||
// data, count, capacity, allocator
|
||||
return s.word_size;
|
||||
return build_context.word_size;
|
||||
|
||||
case Type_Slice:
|
||||
return s.word_size;
|
||||
return build_context.word_size;
|
||||
|
||||
case Type_Vector: {
|
||||
Type *elem = t->Vector.elem;
|
||||
@@ -1543,17 +1562,17 @@ i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, Type
|
||||
if (path->failure) {
|
||||
return FAILURE_ALIGNMENT;
|
||||
}
|
||||
i64 size = type_size_of_internal(s, allocator, t->Vector.elem, path);
|
||||
i64 size = type_size_of_internal(allocator, t->Vector.elem, path);
|
||||
type_path_pop(path);
|
||||
i64 count = gb_max(prev_pow2(t->Vector.count), 1);
|
||||
i64 total = size * count;
|
||||
return gb_clamp(total, 1, s.max_align);
|
||||
return gb_clamp(total, 1, build_context.max_align);
|
||||
} break;
|
||||
|
||||
case Type_Tuple: {
|
||||
i64 max = 1;
|
||||
for (isize i = 0; i < t->Tuple.variable_count; i++) {
|
||||
i64 align = type_align_of_internal(s, allocator, t->Tuple.variables[i]->type, path);
|
||||
i64 align = type_align_of_internal(allocator, t->Tuple.variables[i]->type, path);
|
||||
if (max < align) {
|
||||
max = align;
|
||||
}
|
||||
@@ -1563,7 +1582,7 @@ i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, Type
|
||||
|
||||
case Type_Map: {
|
||||
if (t->Map.count == 0) { // Dynamic
|
||||
return type_align_of_internal(s, allocator, t->Map.generated_struct_type, path);
|
||||
return type_align_of_internal(allocator, t->Map.generated_struct_type, path);
|
||||
}
|
||||
GB_PANIC("TODO(bill): Fixed map alignment");
|
||||
} break;
|
||||
@@ -1572,19 +1591,19 @@ i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, Type
|
||||
switch (t->Record.kind) {
|
||||
case TypeRecord_Struct:
|
||||
if (t->Record.custom_align > 0) {
|
||||
return gb_clamp(t->Record.custom_align, 1, s.max_align);
|
||||
return gb_clamp(t->Record.custom_align, 1, build_context.max_align);
|
||||
}
|
||||
if (t->Record.field_count > 0) {
|
||||
// TODO(bill): What is this supposed to be?
|
||||
if (t->Record.struct_is_packed) {
|
||||
i64 max = s.word_size;
|
||||
if (t->Record.is_packed) {
|
||||
i64 max = build_context.word_size;
|
||||
for (isize i = 0; i < t->Record.field_count; i++) {
|
||||
Type *field_type = t->Record.fields[i]->type;
|
||||
type_path_push(path, field_type);
|
||||
if (path->failure) {
|
||||
return FAILURE_ALIGNMENT;
|
||||
}
|
||||
i64 align = type_align_of_internal(s, allocator, field_type, path);
|
||||
i64 align = type_align_of_internal(allocator, field_type, path);
|
||||
type_path_pop(path);
|
||||
if (max < align) {
|
||||
max = align;
|
||||
@@ -1597,7 +1616,7 @@ i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, Type
|
||||
if (path->failure) {
|
||||
return FAILURE_ALIGNMENT;
|
||||
}
|
||||
i64 align = type_align_of_internal(s, allocator, field_type, path);
|
||||
i64 align = type_align_of_internal(allocator, field_type, path);
|
||||
type_path_pop(path);
|
||||
return align;
|
||||
}
|
||||
@@ -1605,13 +1624,13 @@ i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, Type
|
||||
case TypeRecord_Union: {
|
||||
i64 max = 1;
|
||||
// NOTE(bill): field zero is null
|
||||
for (isize i = 1; i < t->Record.field_count; i++) {
|
||||
Type *field_type = t->Record.fields[i]->type;
|
||||
type_path_push(path, field_type);
|
||||
for (isize i = 1; i < t->Record.variant_count; i++) {
|
||||
Type *variant = t->Record.variants[i]->type;
|
||||
type_path_push(path, variant);
|
||||
if (path->failure) {
|
||||
return FAILURE_ALIGNMENT;
|
||||
}
|
||||
i64 align = type_align_of_internal(s, allocator, field_type, path);
|
||||
i64 align = type_align_of_internal(allocator, variant, path);
|
||||
type_path_pop(path);
|
||||
if (max < align) {
|
||||
max = align;
|
||||
@@ -1620,14 +1639,14 @@ i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, Type
|
||||
return max;
|
||||
} break;
|
||||
case TypeRecord_RawUnion: {
|
||||
i64 max = 1;
|
||||
i64 max = build_context.word_size;
|
||||
for (isize i = 0; i < t->Record.field_count; i++) {
|
||||
Type *field_type = t->Record.fields[i]->type;
|
||||
type_path_push(path, field_type);
|
||||
if (path->failure) {
|
||||
return FAILURE_ALIGNMENT;
|
||||
}
|
||||
i64 align = type_align_of_internal(s, allocator, field_type, path);
|
||||
i64 align = type_align_of_internal(allocator, field_type, path);
|
||||
type_path_pop(path);
|
||||
if (max < align) {
|
||||
max = align;
|
||||
@@ -1639,43 +1658,48 @@ i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, Type
|
||||
} break;
|
||||
}
|
||||
|
||||
// return gb_clamp(next_pow2(type_size_of(s, allocator, t)), 1, s.max_align);
|
||||
// NOTE(bill): Things that are bigger than s.word_size, are actually comprised of smaller types
|
||||
// return gb_clamp(next_pow2(type_size_of(allocator, t)), 1, build_context.max_align);
|
||||
// NOTE(bill): Things that are bigger than build_context.word_size, are actually comprised of smaller types
|
||||
// TODO(bill): Is this correct for 128-bit types (integers)?
|
||||
return gb_clamp(next_pow2(type_size_of_internal(s, allocator, t, path)), 1, s.word_size);
|
||||
return gb_clamp(next_pow2(type_size_of_internal(allocator, t, path)), 1, build_context.word_size);
|
||||
}
|
||||
|
||||
i64 *type_set_offsets_of(BaseTypeSizes s, gbAllocator allocator, Entity **fields, isize field_count, bool is_packed) {
|
||||
i64 *type_set_offsets_of(gbAllocator allocator, Entity **fields, isize field_count, bool is_packed) {
|
||||
i64 *offsets = gb_alloc_array(allocator, i64, field_count);
|
||||
i64 curr_offset = 0;
|
||||
if (is_packed) {
|
||||
for (isize i = 0; i < field_count; i++) {
|
||||
offsets[i] = curr_offset;
|
||||
curr_offset += type_size_of(s, allocator, fields[i]->type);
|
||||
curr_offset += type_size_of(allocator, fields[i]->type);
|
||||
}
|
||||
|
||||
} else {
|
||||
for (isize i = 0; i < field_count; i++) {
|
||||
i64 align = type_align_of(s, allocator, fields[i]->type);
|
||||
i64 align = type_align_of(allocator, fields[i]->type);
|
||||
curr_offset = align_formula(curr_offset, align);
|
||||
offsets[i] = curr_offset;
|
||||
curr_offset += type_size_of(s, allocator, fields[i]->type);
|
||||
curr_offset += type_size_of(allocator, fields[i]->type);
|
||||
}
|
||||
}
|
||||
return offsets;
|
||||
}
|
||||
|
||||
bool type_set_offsets(BaseTypeSizes s, gbAllocator allocator, Type *t) {
|
||||
bool type_set_offsets(gbAllocator allocator, Type *t) {
|
||||
t = base_type(t);
|
||||
if (is_type_struct(t)) {
|
||||
if (!t->Record.struct_are_offsets_set) {
|
||||
t->Record.struct_offsets = type_set_offsets_of(s, allocator, t->Record.fields, t->Record.field_count, t->Record.struct_is_packed);
|
||||
t->Record.struct_are_offsets_set = true;
|
||||
if (!t->Record.are_offsets_set) {
|
||||
t->Record.offsets = type_set_offsets_of(allocator, t->Record.fields, t->Record.field_count, t->Record.is_packed);
|
||||
t->Record.are_offsets_set = true;
|
||||
return true;
|
||||
}
|
||||
} else if (is_type_tuple(t)) {
|
||||
} else if (is_type_union(t)) {
|
||||
if (!t->Record.are_offsets_set) {
|
||||
t->Record.offsets = type_set_offsets_of(allocator, t->Record.fields, t->Record.field_count, false);
|
||||
t->Record.are_offsets_set = true;
|
||||
return true;
|
||||
}
|
||||
} else if (is_type_tuple(t)) {
|
||||
if (!t->Tuple.are_offsets_set) {
|
||||
t->Tuple.offsets = type_set_offsets_of(s, allocator, t->Tuple.variables, t->Tuple.variable_count, false);
|
||||
t->Tuple.offsets = type_set_offsets_of(allocator, t->Tuple.variables, t->Tuple.variable_count, false);
|
||||
t->Tuple.are_offsets_set = true;
|
||||
return true;
|
||||
}
|
||||
@@ -1685,7 +1709,7 @@ bool type_set_offsets(BaseTypeSizes s, gbAllocator allocator, Type *t) {
|
||||
return false;
|
||||
}
|
||||
|
||||
i64 type_size_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypePath *path) {
|
||||
i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
||||
if (t->failure) {
|
||||
return FAILURE_SIZE;
|
||||
}
|
||||
@@ -1699,11 +1723,11 @@ i64 type_size_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypeP
|
||||
return size;
|
||||
}
|
||||
switch (kind) {
|
||||
case Basic_string: return 2*s.word_size;
|
||||
case Basic_any: return 2*s.word_size;
|
||||
case Basic_string: return 2*build_context.word_size;
|
||||
case Basic_any: return 2*build_context.word_size;
|
||||
|
||||
case Basic_int: case Basic_uint: case Basic_rawptr:
|
||||
return s.word_size;
|
||||
return build_context.word_size;
|
||||
}
|
||||
} break;
|
||||
|
||||
@@ -1713,17 +1737,17 @@ i64 type_size_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypeP
|
||||
if (count == 0) {
|
||||
return 0;
|
||||
}
|
||||
align = type_align_of_internal(s, allocator, t->Array.elem, path);
|
||||
align = type_align_of_internal(allocator, t->Array.elem, path);
|
||||
if (path->failure) {
|
||||
return FAILURE_SIZE;
|
||||
}
|
||||
size = type_size_of_internal(s, allocator, t->Array.elem, path);
|
||||
size = type_size_of_internal( allocator, t->Array.elem, path);
|
||||
alignment = align_formula(size, align);
|
||||
return alignment*(count-1) + size;
|
||||
} break;
|
||||
|
||||
case Type_DynamicArray:
|
||||
return 3*s.word_size + type_size_of(s, allocator, t_allocator);
|
||||
return 3*build_context.word_size + type_size_of(allocator, t_allocator);
|
||||
|
||||
case Type_Vector: {
|
||||
#if 0
|
||||
@@ -1736,7 +1760,7 @@ i64 type_size_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypeP
|
||||
if (path->failure) {
|
||||
return FAILURE_SIZE;
|
||||
}
|
||||
bit_size = 8*type_size_of_internal(s, allocator, t->Vector.elem, path);
|
||||
bit_size = 8*type_size_of_internal(allocator, t->Vector.elem, path);
|
||||
type_path_pop(path);
|
||||
if (is_type_boolean(t->Vector.elem)) {
|
||||
bit_size = 1; // NOTE(bill): LLVM can store booleans as 1 bit because a boolean _is_ an `i1`
|
||||
@@ -1751,11 +1775,11 @@ i64 type_size_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypeP
|
||||
if (count == 0) {
|
||||
return 0;
|
||||
}
|
||||
align = type_align_of_internal(s, allocator, t->Vector.elem, path);
|
||||
align = type_align_of_internal(allocator, t->Vector.elem, path);
|
||||
if (path->failure) {
|
||||
return FAILURE_SIZE;
|
||||
}
|
||||
size = type_size_of_internal(s, allocator, t->Vector.elem, path);
|
||||
size = type_size_of_internal( allocator, t->Vector.elem, path);
|
||||
alignment = align_formula(size, align);
|
||||
return alignment*(count-1) + size;
|
||||
#endif
|
||||
@@ -1763,11 +1787,11 @@ i64 type_size_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypeP
|
||||
|
||||
|
||||
case Type_Slice: // ptr + count
|
||||
return 2 * s.word_size;
|
||||
return 3 * build_context.word_size;
|
||||
|
||||
case Type_Map: {
|
||||
if (t->Map.count == 0) { // Dynamic
|
||||
return type_size_of_internal(s, allocator, t->Map.generated_struct_type, path);
|
||||
return type_size_of_internal(allocator, t->Map.generated_struct_type, path);
|
||||
}
|
||||
GB_PANIC("TODO(bill): Fixed map size");
|
||||
}
|
||||
@@ -1778,9 +1802,9 @@ i64 type_size_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypeP
|
||||
if (count == 0) {
|
||||
return 0;
|
||||
}
|
||||
align = type_align_of_internal(s, allocator, t, path);
|
||||
type_set_offsets(s, allocator, t);
|
||||
size = t->Tuple.offsets[count-1] + type_size_of_internal(s, allocator, t->Tuple.variables[count-1]->type, path);
|
||||
align = type_align_of_internal(allocator, t, path);
|
||||
type_set_offsets(allocator, t);
|
||||
size = t->Tuple.offsets[count-1] + type_size_of_internal(allocator, t->Tuple.variables[count-1]->type, path);
|
||||
return align_formula(size, align);
|
||||
} break;
|
||||
|
||||
@@ -1791,44 +1815,44 @@ i64 type_size_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypeP
|
||||
if (count == 0) {
|
||||
return 0;
|
||||
}
|
||||
i64 align = type_align_of_internal(s, allocator, t, path);
|
||||
i64 align = type_align_of_internal(allocator, t, path);
|
||||
if (path->failure) {
|
||||
return FAILURE_SIZE;
|
||||
}
|
||||
type_set_offsets(s, allocator, t);
|
||||
i64 size = t->Record.struct_offsets[count-1] + type_size_of_internal(s, allocator, t->Record.fields[count-1]->type, path);
|
||||
type_set_offsets(allocator, t);
|
||||
i64 size = t->Record.offsets[count-1] + type_size_of_internal(allocator, t->Record.fields[count-1]->type, path);
|
||||
return align_formula(size, align);
|
||||
} break;
|
||||
|
||||
case TypeRecord_Union: {
|
||||
i64 count = t->Record.field_count;
|
||||
i64 align = type_align_of_internal(s, allocator, t, path);
|
||||
i64 count = t->Record.variant_count;
|
||||
i64 align = type_align_of_internal(allocator, t, path);
|
||||
if (path->failure) {
|
||||
return FAILURE_SIZE;
|
||||
}
|
||||
i64 max = 0;
|
||||
// NOTE(bill): Zeroth field is invalid
|
||||
for (isize i = 1; i < count; i++) {
|
||||
i64 size = type_size_of_internal(s, allocator, t->Record.fields[i]->type, path);
|
||||
i64 size = type_size_of_internal(allocator, t->Record.variants[i]->type, path);
|
||||
if (max < size) {
|
||||
max = size;
|
||||
}
|
||||
}
|
||||
// NOTE(bill): Align to int
|
||||
isize size = align_formula(max, s.word_size);
|
||||
size += type_size_of_internal(s, allocator, t_int, path);
|
||||
i64 size = align_formula(max, build_context.word_size);
|
||||
size += type_size_of_internal(allocator, t_int, path);
|
||||
return align_formula(size, align);
|
||||
} break;
|
||||
|
||||
case TypeRecord_RawUnion: {
|
||||
i64 count = t->Record.field_count;
|
||||
i64 align = type_align_of_internal(s, allocator, t, path);
|
||||
i64 align = type_align_of_internal(allocator, t, path);
|
||||
if (path->failure) {
|
||||
return FAILURE_SIZE;
|
||||
}
|
||||
i64 max = 0;
|
||||
for (isize i = 0; i < count; i++) {
|
||||
i64 size = type_size_of_internal(s, allocator, t->Record.fields[i]->type, path);
|
||||
i64 size = type_size_of_internal(allocator, t->Record.fields[i]->type, path);
|
||||
if (max < size) {
|
||||
max = size;
|
||||
}
|
||||
@@ -1841,51 +1865,52 @@ i64 type_size_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypeP
|
||||
}
|
||||
|
||||
// Catch all
|
||||
return s.word_size;
|
||||
return build_context.word_size;
|
||||
}
|
||||
|
||||
i64 type_offset_of(BaseTypeSizes s, gbAllocator allocator, Type *t, i32 index) {
|
||||
i64 type_offset_of(gbAllocator allocator, Type *t, i32 index) {
|
||||
t = base_type(t);
|
||||
if (t->kind == Type_Record && t->Record.kind == TypeRecord_Struct) {
|
||||
type_set_offsets(s, allocator, t);
|
||||
type_set_offsets(allocator, t);
|
||||
if (gb_is_between(index, 0, t->Record.field_count-1)) {
|
||||
return t->Record.struct_offsets[index];
|
||||
return t->Record.offsets[index];
|
||||
}
|
||||
} else if (t->kind == Type_Tuple) {
|
||||
type_set_offsets(s, allocator, t);
|
||||
type_set_offsets(allocator, t);
|
||||
if (gb_is_between(index, 0, t->Tuple.variable_count-1)) {
|
||||
return t->Tuple.offsets[index];
|
||||
}
|
||||
} else if (t->kind == Type_Basic) {
|
||||
if (t->Basic.kind == Basic_string) {
|
||||
switch (index) {
|
||||
case 0: return 0; // data
|
||||
case 1: return s.word_size; // count
|
||||
case 0: return 0; // data
|
||||
case 1: return build_context.word_size; // count
|
||||
}
|
||||
} else if (t->Basic.kind == Basic_any) {
|
||||
switch (index) {
|
||||
case 0: return 0; // type_info
|
||||
case 1: return s.word_size; // data
|
||||
case 0: return 0; // type_info
|
||||
case 1: return build_context.word_size; // data
|
||||
}
|
||||
}
|
||||
} else if (t->kind == Type_Slice) {
|
||||
switch (index) {
|
||||
case 0: return 0; // data
|
||||
case 1: return 1*s.word_size; // count
|
||||
case 0: return 0; // data
|
||||
case 1: return 1*build_context.word_size; // count
|
||||
case 2: return 2*build_context.word_size; // capacity
|
||||
}
|
||||
} else if (t->kind == Type_DynamicArray) {
|
||||
switch (index) {
|
||||
case 0: return 0; // data
|
||||
case 1: return 1*s.word_size; // count
|
||||
case 2: return 2*s.word_size; // capacity
|
||||
case 3: return 3*s.word_size; // allocator
|
||||
case 0: return 0; // data
|
||||
case 1: return 1*build_context.word_size; // count
|
||||
case 2: return 2*build_context.word_size; // capacity
|
||||
case 3: return 3*build_context.word_size; // allocator
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
i64 type_offset_of_from_selection(BaseTypeSizes s, gbAllocator allocator, Type *type, Selection sel) {
|
||||
i64 type_offset_of_from_selection(gbAllocator allocator, Type *type, Selection sel) {
|
||||
GB_ASSERT(sel.indirect == false);
|
||||
|
||||
Type *t = type;
|
||||
@@ -1893,7 +1918,7 @@ i64 type_offset_of_from_selection(BaseTypeSizes s, gbAllocator allocator, Type *
|
||||
for_array(i, sel.index) {
|
||||
isize index = sel.index.e[i];
|
||||
t = base_type(t);
|
||||
offset += type_offset_of(s, allocator, t, index);
|
||||
offset += type_offset_of(allocator, t, index);
|
||||
if (t->kind == Type_Record && t->Record.kind == TypeRecord_Struct) {
|
||||
t = t->Record.fields[index]->type;
|
||||
} else {
|
||||
@@ -1912,6 +1937,13 @@ i64 type_offset_of_from_selection(BaseTypeSizes s, gbAllocator allocator, Type *
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Type_Slice:
|
||||
switch (index) {
|
||||
case 0: t = t_rawptr; break;
|
||||
case 1: t = t_int; break;
|
||||
case 2: t = t_int; break;
|
||||
}
|
||||
break;
|
||||
case Type_DynamicArray:
|
||||
switch (index) {
|
||||
case 0: t = t_rawptr; break;
|
||||
@@ -1920,12 +1952,6 @@ i64 type_offset_of_from_selection(BaseTypeSizes s, gbAllocator allocator, Type *
|
||||
case 3: t = t_allocator; break;
|
||||
}
|
||||
break;
|
||||
case Type_Slice:
|
||||
switch (index) {
|
||||
case 0: t = t_rawptr; break;
|
||||
case 1: t = t_int; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1973,18 +1999,19 @@ gbString write_type_to_string(gbString str, Type *type) {
|
||||
switch (type->Record.kind) {
|
||||
case TypeRecord_Struct:
|
||||
str = gb_string_appendc(str, "struct");
|
||||
if (type->Record.struct_is_packed) {
|
||||
if (type->Record.is_packed) {
|
||||
str = gb_string_appendc(str, " #packed");
|
||||
}
|
||||
if (type->Record.struct_is_ordered) {
|
||||
if (type->Record.is_ordered) {
|
||||
str = gb_string_appendc(str, " #ordered");
|
||||
}
|
||||
str = gb_string_appendc(str, " {");
|
||||
for (isize i = 0; i < type->Record.field_count; i++) {
|
||||
Entity *f = type->Record.fields[i];
|
||||
GB_ASSERT(f->kind == Entity_Variable);
|
||||
if (i > 0)
|
||||
str = gb_string_appendc(str, "; ");
|
||||
if (i > 0) {
|
||||
str = gb_string_appendc(str, ", ");
|
||||
}
|
||||
str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
|
||||
str = gb_string_appendc(str, ": ");
|
||||
str = write_type_to_string(str, f->type);
|
||||
@@ -1994,16 +2021,38 @@ gbString write_type_to_string(gbString str, Type *type) {
|
||||
|
||||
case TypeRecord_Union:
|
||||
str = gb_string_appendc(str, "union{");
|
||||
for (isize i = 1; i < type->Record.field_count; i++) {
|
||||
for (isize i = 0; i < type->Record.field_count; i++) {
|
||||
Entity *f = type->Record.fields[i];
|
||||
GB_ASSERT(f->kind == Entity_TypeName);
|
||||
if (i > 1) {
|
||||
str = gb_string_appendc(str, "; ");
|
||||
GB_ASSERT(f->kind == Entity_Variable);
|
||||
if (i > 0) {
|
||||
str = gb_string_appendc(str, ", ");
|
||||
}
|
||||
str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
|
||||
str = gb_string_appendc(str, ": ");
|
||||
str = write_type_to_string(str, base_type(f->type));
|
||||
}
|
||||
for (isize i = 1; i < type->Record.variant_count; i++) {
|
||||
Entity *f = type->Record.variants[i];
|
||||
GB_ASSERT(f->kind == Entity_TypeName);
|
||||
if (i > 1 || type->Record.field_count > 1) {
|
||||
str = gb_string_appendc(str, ", ");
|
||||
}
|
||||
str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
|
||||
str = gb_string_appendc(str, "{");
|
||||
Type *variant = base_type(f->type);
|
||||
for (isize i = 0; i < variant->Record.field_count; i++) {
|
||||
Entity *f = variant->Record.fields[i];
|
||||
GB_ASSERT(f->kind == Entity_Variable);
|
||||
if (i > 0) {
|
||||
str = gb_string_appendc(str, ", ");
|
||||
}
|
||||
str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
|
||||
str = gb_string_appendc(str, ": ");
|
||||
str = write_type_to_string(str, f->type);
|
||||
}
|
||||
str = gb_string_appendc(str, "{");
|
||||
|
||||
}
|
||||
str = gb_string_appendc(str, "}");
|
||||
break;
|
||||
|
||||
@@ -2021,6 +2070,25 @@ gbString write_type_to_string(gbString str, Type *type) {
|
||||
}
|
||||
str = gb_string_appendc(str, "}");
|
||||
break;
|
||||
|
||||
case TypeRecord_Enum:
|
||||
str = gb_string_appendc(str, "enum");
|
||||
if (type->Record.enum_base_type != NULL) {
|
||||
str = gb_string_appendc(str, " ");
|
||||
str = write_type_to_string(str, type->Record.enum_base_type);
|
||||
}
|
||||
str = gb_string_appendc(str, " {");
|
||||
for (isize i = 0; i < type->Record.field_count; i++) {
|
||||
Entity *f = type->Record.fields[i];
|
||||
GB_ASSERT(f->kind == Entity_Constant);
|
||||
if (i > 0) {
|
||||
str = gb_string_appendc(str, ", ");
|
||||
}
|
||||
str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
|
||||
// str = gb_string_appendc(str, " = ");
|
||||
}
|
||||
str = gb_string_appendc(str, "}");
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#pragma warning(pop)
|
||||
|
||||
|
||||
bool rune_is_letter(Rune r) {
|
||||
if ((r < 0x80 && gb_char_is_alpha(cast(char)r)) ||
|
||||
r == '_') {
|
||||
|
||||
+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