Compare commits

...

33 Commits

Author SHA1 Message Date
Ginger Bill 6e1864d21c Remove all binaries 2017-03-03 11:13:05 +00:00
Ginger Bill fb2d611dcd Update llvm binaries to latest version; Update utf8proc; 2017-03-03 11:09:37 +00:00
Ginger Bill 9e8c9be1ea Allow pointers to append; Fix strconv stuff; new_slice allows for capacity 2017-03-02 19:24:34 +00:00
Ginger Bill 9bc37f4400 fmt.odin uses ^[]byte rather than custom Buffer type 2017-02-26 15:34:02 +00:00
Ginger Bill f29e303ce7 Slices now have a capacity. 2017-02-26 15:14:08 +00:00
Ginger Bill 3c9143957c Ellipsis is now just ..; Remove half-closed range operator and treat all of them as half-closed; slice expression uses ..; 2017-02-26 14:19:03 +00:00
Ginger Bill 18b3c0b2fc Fix fmt integer width printing 2017-02-26 09:42:24 +00:00
Ginger Bill c59f6b7d0b ++ -- statements; add strconv.odin (and replace some of the fmt procs); Fix ~ on 64 bit constants; Fix integer casts from smaller to larger size 2017-02-26 00:44:26 +00:00
Ginger Bill 67ed8a9a4a Fix Tuple type info bug
Caused by not having type safe tagged unions :P (Silly C)
2017-02-24 22:56:34 +00:00
Ginger Bill 4cc4d604bc Add core/strings.odin 2017-02-24 21:11:05 +00:00
Ginger Bill eec709c545 Fix fmt.odin printing enums 2017-02-24 20:55:35 +00:00
Ginger Bill 9b2f5c359a v0.1.1 2017-02-24 19:48:18 +00:00
Ginger Bill a982c51c30 Fix minor bugs in IR for slices 2017-02-23 22:22:56 +00:00
Ginger Bill 047c0e4bcc A decent union type with common fields and variants 2017-02-21 21:21:54 +00:00
Ginger Bill a94dfdf21d Begin changing union syntax 2017-02-19 19:55:19 +00:00
Ginger Bill c0d5237b75 Unexported struct fields on selectors 2017-02-19 12:47:02 +00:00
Ginger Bill 6fdcbefe5d Unexported struct fields 2017-02-19 12:38:49 +00:00
Ginger Bill 3cec2550d9 delete for maps 2017-02-19 11:50:42 +00:00
Ginger Bill 758dd9ba16 Fix overloading bug due to #import .; Add sys/wgl.odin 2017-02-19 11:35:33 +00:00
Ginger Bill 0c37aa9ea0 Fix overloading bug due to comparison of named types 2017-02-18 22:19:35 +00:00
Ginger Bill 9ff474f387 Named return values but do not affect other declarations 2017-02-18 12:02:11 +00:00
Ginger Bill d2f9d20833 Change ternary expression precedence 2017-02-18 10:41:48 +00:00
Ginger Bill 71100ed427 Ternary expression (removed if and block expression) 2017-02-14 19:26:32 +00:00
Ginger Bill 3ecf3505fd Ignore previous silly commit :P I shouldn't have move it 2017-02-14 17:34:02 +00:00
Ginger Bill daa1cd55a1 Move error handling for casting 2017-02-14 17:33:11 +00:00
Ginger Bill 2722de65b7 Prevent cast on pointer to union types 2017-02-14 17:24:56 +00:00
Ginger Bill 8b5e3428a1 Optional ok for union_cast (similar to map indices) 2017-02-14 16:37:24 +00:00
Ginger Bill d1f65097c4 Fix immutable rules; add some general documentation
immutable is still a little weird and not completely what you'd expect. Maybe just not having it is better.
2017-02-14 15:19:29 +00:00
Ginger Bill 74d15ab84b Reimplement immutable with different rules. 2017-02-14 12:35:50 +00:00
Ginger Bill 763cd2649d Fix index assignment rules for indirection 2017-02-14 12:21:02 +00:00
Ginger Bill bd27c24fab Use a global to store the build context information 2017-02-12 21:27:13 +00:00
Ginger Bill 282f8bb06f Fix issue #23 2017-02-12 11:41:06 +00:00
Ginger Bill b9ed546ce0 Record type field names 2017-02-12 11:31:04 +00:00
46 changed files with 4036 additions and 3303 deletions
+1
View File
@@ -255,3 +255,4 @@ paket-files/
!misc/llvm-bim/lli.exe
!misc/llvm-bim/opt.exe
builds
bin
-200
View File
@@ -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
View File
@@ -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.
-70
View File
@@ -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
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+2 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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();
+257
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+9 -9
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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");
}
+3 -3
View File
@@ -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 {
+336
View File
@@ -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;
}
+15
View File
@@ -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
View File
@@ -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);
}
}
}
+72
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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];
+14 -23
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+120 -77
View File
@@ -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
View File
@@ -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);
}
}
}
+3
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+798 -531
View File
File diff suppressed because it is too large Load Diff
+82 -35
View File
@@ -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
View File
@@ -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));
+3
View File
@@ -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
View File
@@ -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, &params, &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, &params, &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:
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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
+10 -15
View File
@@ -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)