Compare commits

...

66 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
Ginger Bill e1fdd675ce v0.1.0
Added:
 * Dynamic Arrays `[...]Type`
 * Dynamic Maps   `map[Key]Value`
 * Dynamic array and map literals
 * Custom struct alignemnt `struct #align 8 { bar: i8 }`
 * Allow `_` in numbers
 * Variadic `append`
 * fmt.sprint*
 * Entities prefixes with an underscore do not get exported on imports
 * Overloaded `free` for pointers, slices, strings, dynamic arrays, and dynamic maps
 * enum types have an implict `names` field, a []string of all the names in that enum

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

Changed:
 * thread_local -> #thread_local
 * #include -> #load
 * Files only get checked if they are actually used
 * match x in y {} // For type match statements
 * Version numbering now starts from 0.1.0 and uses the convention:
 	- major.minor.patch

Fixes:
 * Many fmt.* fixes

To come very Soon™:
 * Linux and OS X builds (unofficial ones do exist already)
2017-02-11 21:20:57 +00:00
Ginger Bill 4306345ff1 Dynamic array syntax [...]Type; make entities private with a prefix of _; fix extension checking 2017-02-11 17:33:23 +00:00
Ginger Bill 346aa5f71c Only check files that have been truly imported. 2017-02-11 15:50:24 +00:00
Ginger Bill 73d6a55f5c Remove need for type keyword 2017-02-10 16:12:14 +00:00
Ginger Bill f18ae89931 Remove Maybe type; Enum names 2017-02-10 14:59:18 +00:00
Ginger Bill 454d0b5cf5 Fix global maps and initialize the preload types before 2017-02-07 18:13:37 +00:00
Ginger Bill 219ca0ac46 Map type info and fmt printing 2017-02-07 00:10:58 +00:00
Ginger Bill 5796c41357 map immutable fields: count, capacity, allocator 2017-02-06 22:53:48 +00:00
Ginger Bill 8cfae17535 map literals 2017-02-06 22:19:32 +00:00
Ginger Bill df78b8ad3e Make checking map key exists optional 2017-02-06 21:31:27 +00:00
Ginger Bill f11d73ffaa map string keys and for iterator 2017-02-06 20:54:51 +00:00
Ginger Bill c126339090 dynamic map insertion and lookup 2017-02-06 20:23:51 +00:00
Ginger Bill 9f2d9b596d Nearly implement dynamics map, missing insertion 2017-02-06 01:21:23 +00:00
Ginger Bill 00c7489157 Begin writing dynamic map procs and fix using bug in IR 2017-02-05 23:52:01 +00:00
Ginger Bill b1562edccf Add types.odin; Begin work on map 2017-02-05 18:17:55 +00:00
Ginger Bill 2a5b674d33 Custom struct alignment 2017-02-05 15:19:30 +00:00
Ginger Bill 7944b7714f Add build guards around compiling part of the code. 2017-02-01 21:00:32 +00:00
Ginger Bill 205f4664f8 Update code from OSX merge to be consistent with the rest of the code
Remove some dead code whilst I was here too :P
2017-02-01 20:59:14 +00:00
gingerBill c6133587d1 Merge pull request #16 from zhiayang/master
Basic, but sketchy, but somewhat usable, non-windows support
2017-02-01 20:31:57 +00:00
zhiayang 5516e80ab7 Merge branch 'master' of https://github.com/zhiayang/Odin 2017-02-02 04:21:42 +08:00
zhiayang 864310e3da oh boy, basic osx/unix support 2017-02-02 04:20:33 +08:00
Ginger Bill 4e7082a68d Change internals of context; Disable immutable 2017-02-01 17:52:55 +00:00
Ginger Bill 502e63b9c5 Remove dead code 2017-01-30 23:10:44 +00:00
Ginger Bill 34150385d8 Change vector memory layout and operations; for in vector. 2017-01-30 22:31:34 +00:00
Ginger Bill 0ca1b4612c Allow _ in floats 2017-01-29 23:13:50 +00:00
Ginger Bill 9e143a38ce sprint*, variadic append works correctly now. 2017-01-29 21:29:10 +00:00
Ginger Bill 43be91bca3 Variadic append 2017-01-29 20:48:08 +00:00
Ginger Bill 984e36a151 Dynamic arrays 2017-01-29 20:15:16 +00:00
Ginger Bill ec9c8fb8a4 Update README.md 2017-01-29 14:45:12 +00:00
Ginger Bill 3e79ec4aef Fix untyped to any assignments. Fixed crash when arguments with no value are passed 2017-01-29 14:27:55 +00:00
gingerBill 3e257ef8d0 Merge pull request #12 from thebirk/windows-odin-correction
Changed #foreign user32 to gdi32 where this was wrong.
2017-01-28 23:25:55 +00:00
thebirk 626f91f307 Changed #foreign user32 to gdi32 where this was wrong. 2017-01-28 23:23:02 +01:00
Ginger Bill e86c990b75 Overloaded free; 3 dotted ellipsis 2017-01-28 20:16:18 +00:00
56 changed files with 8870 additions and 5529 deletions
+1
View File
@@ -255,3 +255,4 @@ paket-files/
!misc/llvm-bim/lli.exe !misc/llvm-bim/lli.exe
!misc/llvm-bim/opt.exe !misc/llvm-bim/opt.exe
builds builds
bin
+18 -19
View File
@@ -2,7 +2,7 @@
# The Odin Programming Language # The Odin Programming Language
Odin is fast, concise, readable, pragmatic and open sourced. It is designed with the intent of replacing C with the following goals: The Odin programming language is fast, concise, readable, pragmatic and open sourced. It is designed with the intent of replacing C with the following goals:
* simplicity * simplicity
* high performance * high performance
* built for modern systems * built for modern systems
@@ -18,6 +18,7 @@ Odin is fast, concise, readable, pragmatic and open sourced. It is designed with
* [Composition & Refactorability](https://www.youtube.com/watch?v=n1wemZfcbXM) * [Composition & Refactorability](https://www.youtube.com/watch?v=n1wemZfcbXM)
* [Introspection, Modules, and Record Layout](https://www.youtube.com/watch?v=UFq8rhWhx4s) * [Introspection, Modules, and Record Layout](https://www.youtube.com/watch?v=UFq8rhWhx4s)
* [push_allocator & Minimal Dependency Building](https://www.youtube.com/watch?v=f_LGVOAMb78) * [push_allocator & Minimal Dependency Building](https://www.youtube.com/watch?v=f_LGVOAMb78)
* [when, for, & procedure overloading](https://www.youtube.com/watch?v=OzeOekzyZK8)
## Requirements to build and run ## Requirements to build and run
@@ -30,27 +31,25 @@ Odin is fast, concise, readable, pragmatic and open sourced. It is designed with
## Warnings ## Warnings
* This is still highly in development and the language's design is quite volatile. * This is still highly in development and the language's design is quite volatile.
* Syntax is definitely not fixed * Syntax is not fixed.
## Roadmap ## Roadmap
Not in any particular order Not in any particular order and not be implemented
* Custom backend to replace LLVM * Compile Time Execution (CTE)
- Improve SSA design to accommodate for lowering to a "bytecode" - More metaprogramming madness
- SSA optimizations - Compiler as a library
- COFF generation - AST inspection and modification
- linker * CTE-based build system
* Type safe "macros" * Replace LLVM backend with my own custom backend
* Documentation generator for "Entities" * Improve SSA design to accommodate for lowering to a "bytecode"
* Multiple architecture support * SSA optimizations
* Inline assembly * Documentation Generator for "Entities"
* Linking options * Multiple Architecture support
- Executable * Debug Information
- Static/Dynamic Library
* Debug information
- pdb format too - pdb format too
* Command line tooling * Command Line Tooling
* Compiler internals: * Compiler Internals:
- Big numbers library - Big numbers library
- Multithreading for performance increase
-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
@@ -45,8 +45,9 @@ del *.ilk > NUL 2> NUL
cl %compiler_settings% "src\main.c" ^ cl %compiler_settings% "src\main.c" ^
/link %linker_settings% -OUT:%exe_name% ^ /link %linker_settings% -OUT:%exe_name% ^
&& odin run code/demo.odin && odin run code/demo.odin
rem && odin build code/Jaze/src/main.odin
rem && odin build_dll code/example.odin ^ rem && odin build_dll code/example.odin ^
rem odin run code/punity.odin rem odin run code/demo.odin
rem pushd src\asm rem pushd src\asm
rem nasm hellope.asm -fwin64 -o hellope.obj ^ rem nasm hellope.asm -fwin64 -o hellope.obj ^
+146 -258
View File
@@ -1,279 +1,167 @@
#import "fmt.odin"; #import "fmt.odin";
#import "utf8.odin"; #import "atomic.odin";
// #import "atomic.odin"; #import "hash.odin";
// #import "hash.odin"; #import "math.odin";
// #import "math.odin"; #import "mem.odin";
// #import "mem.odin"; #import "opengl.odin";
// #import "opengl.odin"; #import "os.odin";
// #import "os.odin"; #import "strconv.odin";
// #import "sync.odin"; #import "sync.odin";
// #import win32 "sys/windows.odin";
main :: proc() { main :: proc() {
syntax(); // 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);
syntax :: proc() { s := new_slice(int, 0, 10);
// Cyclic type checking append(s, 1, 2, 6, 3, 6, 5, 5, 5, 5, 1, 2);
// Uncomment to see the error fmt.println(s);
// A :: struct {b: B};
// B :: struct {a: A};
x: int;
y := cast(f32)x;
z := transmute(u32)y;
// down_cast, union_cast as similar too
when false {
/*
Version 0.1.1
// Basic directives Added:
fmt.printf("Basic directives = %s(%d): %s\n", #file, #line, #procedure); * Dynamic Arrays `[dynamic]Type`
// NOTE: new and improved `printf` * Dynamic Maps `map[Key]Value`
// TODO: It does need accurate float printing * Dynamic array and map literals
* Custom struct alignemnt `struct #align 8 { bar: i8 }`
* Allow `_` in numbers
* Variadic `append`
* fmt.sprint*
* Entities prefixes with an underscore do not get exported on imports
* Overloaded `free` for pointers, slices, strings, dynamic arrays, and dynamic maps
* enum types have an implict `names` field, a []string of all the names in that enum
* immutable variables are "completely immutable" - rules need a full explanation
* `slice_to_bytes` - convert any slice to a slice of bytes
* `union_cast` allows for optional ok check
* Record type field `names` (struct/raw_union/enum)
* ?: ternary operator
* Unions with variants and common fields
* New built-in procedures
- `delete` to delete map entries `delete(m, key)`
- `clear` to clear dynamic maps and arrays `clear(map_or_array)`
- `reserve` to reserve space for the dynamic maps and arrays `reserve(map_or_array)`
* Unexported entities and fields using an underscore prefix
Removed:
* Maybe/option types
* Remove `type` keyword and other "reserved" keywords
* `compile_assert` and `assert`return the value of the condition for semantic reasons
Changed:
* thread_local -> #thread_local
* #include -> #load
* Files only get checked if they are actually used
* match x in y {} // For type match statements
* Version numbering now starts from 0.1.0 and uses the convention:
- major.minor.patch
* Core library additions to Windows specific stuff
// record fields use the same syntax a procedure signatures Fixes:
Thing1 :: struct { * Many fmt.* fixes
x: f32, * Overloading bug due to comparison of named types
y: int, * Overloading bug due to `#import .` collision
z: ^[]int, * disallow a `cast` from pointers of unions
}; * Minor bugs in generated IR code for slices
Thing2 :: struct {x: f32, y: int, z: ^[]int};
// Slice interals are now just a `ptr+count` To come very Soon:
slice: []int; compile_assert(size_of_val(slice) == 2*size_of(int)); * Linux and OS X builds (unofficial ones do exist already)
*/
{
// Helper type - Help the reader understand what it is quicker
My_Int :: type int;
My_Proc :: type proc(int) -> f32;
// All declarations with : are either variable or constant
// To make these declarations syntactically consistent
v_variable := 123;
c_constant :: 123;
c_type1 :: int;
c_type2 :: []int;
c_proc :: proc() { /* code here */ };
x += 1;
x -= 1;
// ++ and -- have been removed
// x++;
// x--;
// Question: Should they be added again?
// They were removed as they are redundant and statements, not expressions
// like in C/C++
// You can now build files as a `.dll`
// `odin build_dll demo.odin`
// Next part
prefixes();
}
Prefix_Type :: struct {x: int, y: f32, z: rawptr};
thread_local my_tls: Prefix_Type;
prefixes :: proc() {
using var: Prefix_Type;
immutable const := Prefix_Type{1, 2, nil};
var.x = 123;
x = 123;
// const.x = 123; // const is immutable
foo :: proc(using immutable pt: Prefix_Type, immutable int_ptr: ^int) {
// int_ptr = nil; // Not valid
int_ptr^ = 123; // Is valid
} }
{
Fruit :: enum {
// Same as C99's `restrict` APPLE,
bar :: proc(no_alias a, b: ^int) { BANANA,
// Assumes a never equals b so it can perform optimizations with that fact COCONUT,
}
when_statements();
}
when_statements :: proc() {
X :: 123 + 12;
Y :: X/5;
COND :: Y > 0;
when COND {
fmt.println("Y > 0");
} else {
fmt.println("Y <= 0");
}
when false {
this_code_does_not_exist(123, 321);
but_its_syntax_is_valid();
x :: ^^^^int;
}
foreign_procedures();
}
#foreign_system_library win32_user "user32.lib" when ODIN_OS == "windows";
// NOTE: This is done on purpose for two reasons:
// * Makes it clear where the platform specific stuff is
// * Removes the need to solve the travelling salesman problem when importing files :P
foreign_procedures :: proc() {
ShowWindow :: proc(hwnd: rawptr, cmd_show: i32) -> i32 #foreign win32_user;
show_window :: proc(hwnd: rawptr, cmd_show: i32) -> i32 #foreign win32_user "ShowWindow";
// NOTE: If that library doesn't get used, it doesn't get linked with
// NOTE: There is not link checking yet to see if that procedure does come from that library
// See sys/windows.odin for more examples
special_expressions();
}
special_expressions :: proc() {
// Block expression
x := {
a: f32 = 123;
b := a-123;
c := b/a;
give c;
}; // semicolon is required as it's an expression
y := if x < 50 {
give x;
} else {
// TODO: Type cohesion is not yet finished
give 123;
}; // semicolon is required as it's an expression
// This is allows for inline blocks of code and will be a useful feature to have when
// macros will be implemented into the language
loops();
}
loops :: proc() {
// The C-style for loop
for i := 0; i < 123; i += 1 {
break;
}
for i := 0; i < 123; {
break;
}
for false {
break;
}
for {
break;
}
for i in 0..<123 { // 123 exclusive
}
for i in 0..122 { // 122 inclusive
}
for val, idx in 12..<16 {
fmt.println(val, idx);
}
primes := [..]int{2, 3, 5, 7, 11, 13, 17, 19};
for p in primes {
fmt.println(p);
}
// Pointers to arrays, slices, or strings are allowed
for _ in ^primes {
// ignore the value and just iterate across it
}
name := "你好,世界";
fmt.println(name);
for r in name {
compile_assert(type_of_val(r) == rune);
fmt.printf("%r\n", r);
}
when false {
for i, size := 0; i < name.count; i += size {
r: rune;
r, size = utf8.decode_rune(name[i:]);
fmt.printf("%r\n", r);
} }
fmt.println(Fruit.names);
}
{
m: map[f32]int;
reserve(m, 16);
defer free(m);
m[1.0] = 1278;
m[2.0] = 7643;
m[3.0] = 564;
_, ok := m[3.0];
c := m[3.0];
assert(ok && c == 564);
fmt.print("map[");
i := 0;
for val, key in m {
if i > 0 {
fmt.print(", ");
}
fmt.printf("%v=%v", key, val);
i += 1;
}
fmt.println("]");
}
{
m := map[string]u32{
"a" = 56,
"b" = 13453,
"c" = 7654,
};
defer free(m);
c := m["c"];
_, ok := m["c"];
assert(ok && c == 7654);
fmt.println(m);
}
{
x: [dynamic]f64;
reserve(x, 16);
defer free(x);
append(x, 2_000_000.500_000, 3, 5, 7);
for p, i in x {
if i > 0 { fmt.print(", "); }
fmt.print(p);
}
fmt.println();
}
{
x := [dynamic]f64{2_000_000.500_000, 3, 5, 7};
defer free(x);
fmt.println(x);
} }
{
Vec3 :: [vector 3]f32;
procedure_overloading(); x := Vec3{1, 2, 3};
y := Vec3{4, 5, 6};
fmt.println(x < y);
fmt.println(x + y);
fmt.println(x - y);
fmt.println(x * y);
fmt.println(x / y);
for i in x {
fmt.println(i);
}
compile_assert(size_of([vector 7]bool) == size_of([7]bool));
compile_assert(size_of([vector 7]i32) == size_of([7]i32));
// align_of([vector 7]i32) != align_of([7]i32) // this may be the case
}
}
} }
procedure_overloading :: proc() {
THINGF :: 14451.1;
THINGI :: 14451;
foo :: proc() {
fmt.printf("Zero args\n");
}
foo :: proc(i: int) {
fmt.printf("int arg, i=%d\n", i);
}
foo :: proc(f: f64) {
i := cast(int)f;
fmt.printf("f64 arg, f=%d\n", i);
}
foo();
foo(THINGF);
// foo(THINGI); // 14451 is just a number so it could go to either procedures
foo(cast(int)THINGI);
foo :: proc(x: ^i32) -> (int, int) {
fmt.println("^int");
return 123, cast(int)(x^);
}
foo :: proc(x: rawptr) {
fmt.println("rawptr");
}
a: i32 = 123;
b: f32;
c: rawptr;
fmt.println(foo(^a));
foo(^b);
foo(c);
// foo(nil); // nil could go to numerous types thus the ambiguity
f: proc();
f = foo; // The correct `foo` to chosen
f();
// See math.odin and atomic.odin for more examples
}
+86 -86
View File
@@ -1,10 +1,10 @@
#import "fmt.odin" #import "fmt.odin";
#foreign_system_library "Ws2_32" when ODIN_OS == "windows" #foreign_system_library ws2 "Ws2_32.lib" when ODIN_OS == "windows";
SOCKET :: type uint SOCKET :: #type uint;
INVALID_SOCKET :: ~(0 as SOCKET) INVALID_SOCKET :: ~(cast(SOCKET)0);
AF :: enum i32 { AF :: enum i32 {
UNSPEC = 0, // unspecified UNSPEC = 0, // unspecified
@@ -35,111 +35,111 @@ AF :: enum i32 {
SIP = 24, // Simple Internet Protocol SIP = 24, // Simple Internet Protocol
PIP = 25, // Help Identify PIP packets PIP = 25, // Help Identify PIP packets
MAX = 26, MAX = 26,
} };
SOCK_STREAM :: 1 SOCK_STREAM :: 1;
SOCKET_ERROR :: -1 SOCKET_ERROR :: -1;
IPPROTO_TCP :: 6 IPPROTO_TCP :: 6;
AI_PASSIVE :: 0x0020 AI_PASSIVE :: 0x0020;
SOMAXCONN :: 128 SOMAXCONN :: 128;
SD_RECEIVE :: 0 SD_RECEIVE :: 0;
SD_SEND :: 1 SD_SEND :: 1;
SD_BOTH :: 2 SD_BOTH :: 2;
WSADESCRIPTION_LEN :: 256 WSADESCRIPTION_LEN :: 256;
WSASYS_STATUS_LEN :: 128 WSASYS_STATUS_LEN :: 128;
WSADATA :: struct #ordered { WSADATA :: struct #ordered {
version: i16 version: i16,
high_version: i16 high_version: i16,
// NOTE(bill): This is x64 ordering // NOTE(bill): This is x64 ordering
max_sockets: u16 max_sockets: u16,
max_udp_dg: u16 max_udp_dg: u16,
vendor_info: ^byte vendor_info: ^byte,
description: [WSADESCRIPTION_LEN+1]byte description: [WSADESCRIPTION_LEN+1]byte,
system_status: [WSASYS_STATUS_LEN+1]byte system_status: [WSASYS_STATUS_LEN+1]byte,
} }
addrinfo :: struct #ordered { addrinfo :: struct #ordered {
flags: i32 flags: i32,
family: i32 family: i32,
socktype: i32 socktype: i32,
protocol: i32 protocol: i32,
addrlen: uint addrlen: uint,
canonname: ^u8 canonname: ^u8,
addr: ^sockaddr addr: ^sockaddr,
next: ^addrinfo next: ^addrinfo,
} }
sockaddr :: struct #ordered { sockaddr :: struct #ordered {
family: u16 family: u16,
data: [14]byte data: [14]byte,
} }
WSAStartup :: proc(version_requested: i16, data: ^WSADATA) -> i32 #foreign #dll_import WSAStartup :: proc(version_requested: i16, data: ^WSADATA) -> i32 #foreign ws2;
WSACleanup :: proc() -> i32 #foreign #dll_import WSACleanup :: proc() -> i32 #foreign ws2;
getaddrinfo :: proc(node_name, service_name: ^u8, hints: ^addrinfo, result: ^^addrinfo) -> i32 #foreign #dll_import getaddrinfo :: proc(node_name, service_name: ^u8, hints: ^addrinfo, result: ^^addrinfo) -> i32 #foreign ws2;
freeaddrinfo :: proc(ai: ^addrinfo) #foreign #dll_import freeaddrinfo :: proc(ai: ^addrinfo) #foreign ws2;
socket :: proc(af, type_, protocol: i32) -> SOCKET #foreign #dll_import socket :: proc(af, type_, protocol: i32) -> SOCKET #foreign ws2;
closesocket :: proc(s: SOCKET) -> i32 #foreign #dll_import closesocket :: proc(s: SOCKET) -> i32 #foreign ws2;
bind :: proc(s: SOCKET, name: ^sockaddr, name_len: i32) -> i32 #foreign #dll_import bind :: proc(s: SOCKET, name: ^sockaddr, name_len: i32) -> i32 #foreign ws2;
listen :: proc(s: SOCKET, back_log: i32) -> i32 #foreign #dll_import listen :: proc(s: SOCKET, back_log: i32) -> i32 #foreign ws2;
accept :: proc(s: SOCKET, addr: ^sockaddr, addr_len: i32) -> SOCKET #foreign #dll_import accept :: proc(s: SOCKET, addr: ^sockaddr, addr_len: i32) -> SOCKET #foreign ws2;
recv :: proc(s: SOCKET, buf: ^byte, len: i32, flags: i32) -> i32 #foreign #dll_import recv :: proc(s: SOCKET, buf: ^byte, len: i32, flags: i32) -> i32 #foreign ws2;
send :: proc(s: SOCKET, buf: ^byte, len: i32, flags: i32) -> i32 #foreign #dll_import send :: proc(s: SOCKET, buf: ^byte, len: i32, flags: i32) -> i32 #foreign ws2;
shutdown :: proc(s: SOCKET, how: i32) -> i32 #foreign #dll_import shutdown :: proc(s: SOCKET, how: i32) -> i32 #foreign ws2;
WSAGetLastError :: proc() -> i32 #foreign #dll_import WSAGetLastError :: proc() -> i32 #foreign ws2;
to_c_string :: proc(s: string) -> ^byte { to_c_string :: proc(s: string) -> ^byte {
c_str := new_slice(byte, s.count+1) c_str := new_slice(byte, s.count+1);
assert(c_str.data != nil) assert(c_str.data != nil);
copy(c_str, s as []byte) copy(c_str, cast([]byte)s);
c_str[s.count] = 0 c_str[s.count] = 0;
return c_str.data return c_str.data;
} }
run :: proc() { run :: proc() {
wsa: WSADATA wsa: WSADATA;
res: ^addrinfo = nil res: ^addrinfo = nil;
hints: addrinfo hints: addrinfo;
s, client: SOCKET s, client: SOCKET;
if WSAStartup(2 | (2 << 8), ^wsa) != 0 { if WSAStartup(2 | (2 << 8), ^wsa) != 0 {
fmt.println("WSAStartup failed: ", WSAGetLastError()) fmt.println("WSAStartup failed: ", WSAGetLastError());
return return;
} }
defer WSACleanup() defer WSACleanup();
hints.family = AF.INET as i32 hints.family = cast(i32)AF.INET;
hints.socktype = SOCK_STREAM hints.socktype = SOCK_STREAM;
hints.protocol = IPPROTO_TCP hints.protocol = IPPROTO_TCP;
hints.flags = AI_PASSIVE hints.flags = AI_PASSIVE;
if getaddrinfo(nil, to_c_string("8080"), ^hints, ^res) != 0 { if getaddrinfo(nil, to_c_string("8080"), ^hints, ^res) != 0 {
fmt.println("getaddrinfo failed: ", WSAGetLastError()) fmt.println("getaddrinfo failed: ", WSAGetLastError());
return return;
} }
defer freeaddrinfo(res) defer freeaddrinfo(res);
s = socket(res.family, res.socktype, res.protocol) s = socket(res.family, res.socktype, res.protocol);
if s == INVALID_SOCKET { if s == INVALID_SOCKET {
fmt.println("socket failed: ", WSAGetLastError()) fmt.println("socket failed: ", WSAGetLastError());
return return;
} }
defer closesocket(s) defer closesocket(s);
bind(s, res.addr, res.addrlen as i32) bind(s, res.addr, cast(i32)res.addrlen);
listen(s, SOMAXCONN) listen(s, SOMAXCONN);
client = accept(s, nil, 0) client = accept(s, nil, 0);
if client == INVALID_SOCKET { if client == INVALID_SOCKET {
fmt.println("socket failed: ", WSAGetLastError()) fmt.println("socket failed: ", WSAGetLastError());
return return;
} }
defer closesocket(client) defer closesocket(client);
html := html :=
`HTTP/1.1 200 OK `HTTP/1.1 200 OK
@@ -154,27 +154,27 @@ Content-type: text/html
<h1 style="color: orange;">Odin Server Demo</h1> <h1 style="color: orange;">Odin Server Demo</h1>
</body> </body>
</html> </html>
` `;
buf: [1024]byte buf: [1024]byte;
for { for {
bytes := recv(client, ^buf[0], buf.count as i32, 0) bytes := recv(client, ^buf[0], cast(i32)buf.count, 0);
if bytes > 0 { if bytes > 0 {
// fmt.println(buf[:bytes] as string) // fmt.println(buf[:bytes] as string)
bytes_sent := send(client, html.data, (html.count-1) as i32, 0) bytes_sent := send(client, html.data, cast(i32)(html.count-1), 0);
if bytes_sent == SOCKET_ERROR { if bytes_sent == SOCKET_ERROR {
fmt.println("send failed: ", WSAGetLastError()) fmt.println("send failed: ", WSAGetLastError());
return return;
} }
break break;
} else if bytes == 0 { } else if bytes == 0 {
fmt.println("Connection closing...") fmt.println("Connection closing...");
break break;
} else { } else {
fmt.println("recv failed: ", WSAGetLastError()) fmt.println("recv failed: ", WSAGetLastError());
return return;
} }
} }
shutdown(client, SD_SEND) shutdown(client, SD_SEND);
} }
+17 -14
View File
@@ -6,21 +6,24 @@
// #import "punity.odin" as pn; // #import "punity.odin" as pn;
main :: proc() { main :: proc() {
// struct_padding() struct_padding();
// bounds_checking() bounds_checking();
// type_introspection() type_introspection();
// any_type() any_type();
// crazy_introspection() crazy_introspection();
// namespaces_and_files() namespaces_and_files();
// miscellany() miscellany();
// ht.run()
// game.run()
// {
// init :: proc(c: ^pn.Core) {}
// step :: proc(c: ^pn.Core) {}
// pn.run(init, step) /*
// } ht.run();
game.run();
{
init :: proc(c: ^pn.Core) {}
step :: proc(c: ^pn.Core) {}
pn.run(init, step);
}
*/
} }
struct_padding :: proc() { struct_padding :: proc() {
+282
View File
@@ -0,0 +1,282 @@
#import "fmt.odin";
#import "utf8.odin";
// #import "atomic.odin";
// #import "hash.odin";
// #import "math.odin";
// #import "mem.odin";
// #import "opengl.odin";
// #import "os.odin";
// #import "sync.odin";
// #import win32 "sys/windows.odin";
main :: proc() {
// syntax();
procedure_overloading();
}
syntax :: proc() {
// Cyclic type checking
// Uncomment to see the error
// A :: struct {b: B};
// B :: struct {a: A};
x: int;
y := cast(f32)x;
z := transmute(u32)y;
// down_cast, union_cast are similar too
// Basic directives
fmt.printf("Basic directives = %s(%d): %s\n", #file, #line, #procedure);
// NOTE: new and improved `printf`
// TODO: It does need accurate float printing
// record fields use the same syntax a procedure signatures
Thing1 :: struct {
x: f32,
y: int,
z: ^[]int,
};
Thing2 :: struct {x: f32, y: int, z: ^[]int};
// Slice interals are now just a `ptr+count`
slice: []int; compile_assert(size_of_val(slice) == 2*size_of(int));
// Helper type - Help the reader understand what it is quicker
My_Int :: type int;
My_Proc :: type proc(int) -> f32;
// All declarations with : are either variable or constant
// To make these declarations syntactically consistent
v_variable := 123;
c_constant :: 123;
c_type1 :: int;
c_type2 :: []int;
c_proc :: proc() { /* code here */ };
x += 1;
x -= 1;
// ++ and -- have been removed
// x++;
// x--;
// Question: Should they be added again?
// They were removed as they are redundant and statements, not expressions
// like in C/C++
// You can now build files as a `.dll`
// `odin build_dll demo.odin`
// New vector syntax
u, v: [vector 3]f32;
v[0] = 123;
v.x = 123; // valid for all vectors with count 1 to 4
// Next part
prefixes();
}
Prefix_Type :: struct {x: int, y: f32, z: rawptr};
thread_local my_tls: Prefix_Type;
prefixes :: proc() {
using var: Prefix_Type;
immutable const := Prefix_Type{1, 2, nil};
var.x = 123;
x = 123;
// const.x = 123; // const is immutable
foo :: proc(using immutable pt: Prefix_Type, immutable int_ptr: ^int) {
// int_ptr = nil; // Not valid
int_ptr^ = 123; // Is valid
}
// Same as C99's `restrict`
bar :: proc(no_alias a, b: ^int) {
// Assumes a never equals b so it can perform optimizations with that fact
}
when_statements();
}
when_statements :: proc() {
X :: 123 + 12;
Y :: X/5;
COND :: Y > 0;
when COND {
fmt.println("Y > 0");
} else {
fmt.println("Y <= 0");
}
when false {
this_code_does_not_exist(123, 321);
but_its_syntax_is_valid();
x :: ^^^^int;
}
foreign_procedures();
}
#foreign_system_library win32_user "user32.lib" when ODIN_OS == "windows";
// NOTE: This is done on purpose for two reasons:
// * Makes it clear where the platform specific stuff is
// * Removes the need to solve the travelling salesman problem when importing files :P
foreign_procedures :: proc() {
ShowWindow :: proc(hwnd: rawptr, cmd_show: i32) -> i32 #foreign win32_user;
show_window :: proc(hwnd: rawptr, cmd_show: i32) -> i32 #foreign win32_user "ShowWindow";
// NOTE: If that library doesn't get used, it doesn't get linked with
// NOTE: There is not link checking yet to see if that procedure does come from that library
// See sys/windows.odin for more examples
special_expressions();
}
special_expressions :: proc() {
// Block expression
x := {
a: f32 = 123;
b := a-123;
c := b/a;
give c;
}; // semicolon is required as it's an expression
y := if x < 50 {
give x;
} else {
// TODO: Type cohesion is not yet finished
give 123;
}; // semicolon is required as it's an expression
// This is allows for inline blocks of code and will be a useful feature to have when
// macros will be implemented into the language
loops();
}
loops :: proc() {
// The C-style for loop
for i := 0; i < 123; i += 1 {
break;
}
for i := 0; i < 123; {
break;
}
for false {
break;
}
for {
break;
}
for i in 0..<123 { // 123 exclusive
}
for i in 0...122 { // 122 inclusive
}
for val, idx in 12..<16 {
fmt.println(val, idx);
}
primes := [...]int{2, 3, 5, 7, 11, 13, 17, 19};
for p in primes {
fmt.println(p);
}
// Pointers to arrays, slices, or strings are allowed
for _ in ^primes {
// ignore the value and just iterate across it
}
name := "你好,世界";
fmt.println(name);
for r in name {
compile_assert(type_of_val(r) == rune);
fmt.printf("%r\n", r);
}
when false {
for i, size := 0; i < name.count; i += size {
r: rune;
r, size = utf8.decode_rune(name[i:]);
fmt.printf("%r\n", r);
}
}
procedure_overloading();
}
procedure_overloading :: proc() {
THINGF :: 14451.1;
THINGI :: 14451;
foo :: proc() {
fmt.printf("Zero args\n");
}
foo :: proc(i: int) {
fmt.printf("int arg, i=%d\n", i);
}
foo :: proc(f: f64) {
i := cast(int)f;
fmt.printf("f64 arg, f=%d\n", i);
}
foo();
foo(THINGF);
// foo(THINGI); // 14451 is just a number so it could go to either procedures
foo(cast(int)THINGI);
foo :: proc(x: ^i32) -> (int, int) {
fmt.println("^int");
return 123, cast(int)(x^);
}
foo :: proc(x: rawptr) {
fmt.println("rawptr");
}
a: i32 = 123;
b: f32;
c: rawptr;
fmt.println(foo(^a));
foo(^b);
foo(c);
// foo(nil); // nil could go to numerous types thus the ambiguity
f: proc();
f = foo; // The correct `foo` to chosen
f();
// See math.odin and atomic.odin for more examples
}
+1 -2
View File
@@ -398,8 +398,7 @@ run :: proc(user_init, user_step: proc(c: ^Core)) {
ShowWindow(win32_window, SW_SHOW); ShowWindow(win32_window, SW_SHOW);
window_buffer := new_slice(u32, CANVAS_WIDTH * CANVAS_HEIGHT); window_buffer := new_slice(u32, CANVAS_WIDTH * CANVAS_HEIGHT);
assert(window_buffer.data != nil); defer free(window_buffer);
defer free(window_buffer.data);
for i := 0; i < window_buffer.count; i += 1 { for i := 0; i < window_buffer.count; i += 1 {
+3 -3
View File
@@ -5,10 +5,10 @@ thing :: proc() {
}*/ }*/
#import "fmt.odin" as format #import "fmt.odin";
thing :: proc() { main :: proc() {
format.println("Hello2!") fmt.println("hello, world!");
} }
+447 -109
View File
@@ -4,6 +4,7 @@
#import "fmt.odin"; #import "fmt.odin";
#import "mem.odin"; #import "mem.odin";
#import "utf8.odin"; #import "utf8.odin";
#import "hash.odin";
// IMPORTANT NOTE(bill): `type_info` & `type_info_val` cannot be used within a // IMPORTANT NOTE(bill): `type_info` & `type_info_val` cannot be used within a
// #shared_global_scope due to the internals of the compiler. // #shared_global_scope due to the internals of the compiler.
@@ -13,24 +14,11 @@
// IMPORTANT NOTE(bill): Do not change the order of any of this data // IMPORTANT NOTE(bill): Do not change the order of any of this data
// The compiler relies upon this _exact_ order // The compiler relies upon this _exact_ order
Type_Info_Member :: struct #ordered {
name: string, // can be empty if tuple
type_info: ^Type_Info,
offset: int, // offsets are not used in tuples
}
Type_Info_Record :: struct #ordered {
fields: []Type_Info_Member,
size: int, // in bytes
align: int, // in bytes
packed: bool,
ordered: bool,
}
Type_Info_Enum_Value :: raw_union { Type_Info_Enum_Value :: raw_union {
f: f64, f: f64,
i: i64, i: i64,
} }
// NOTE(bill): This must match the compiler's
// NOTE(bill): This much the same as the compiler's
Calling_Convention :: enum { Calling_Convention :: enum {
ODIN = 0, ODIN = 0,
C = 1, C = 1,
@@ -38,69 +26,79 @@ Calling_Convention :: enum {
FAST = 3, 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 { Type_Info :: union {
Named: struct #ordered { Named{name: string, base: ^Type_Info},
name: string, Integer{size: int, signed: bool},
base: ^Type_Info, // This will _not_ be a Type_Info.Named Float{size: int},
}, String{},
Integer: struct #ordered { Boolean{},
size: int, // in bytes Any{},
signed: bool, Pointer{
},
Float: struct #ordered {
size: int, // in bytes
},
Any: struct #ordered {},
String: struct #ordered {},
Boolean: struct #ordered {},
Pointer: struct #ordered {
elem: ^Type_Info, // nil -> rawptr elem: ^Type_Info, // nil -> rawptr
}, },
Maybe: struct #ordered { Procedure{
elem: ^Type_Info,
},
Procedure: struct #ordered {
params: ^Type_Info, // Type_Info.Tuple params: ^Type_Info, // Type_Info.Tuple
results: ^Type_Info, // Type_Info.Tuple results: ^Type_Info, // Type_Info.Tuple
variadic: bool, variadic: bool,
convention: Calling_Convention, convention: Calling_Convention,
}, },
Array: struct #ordered { Array{
elem: ^Type_Info, elem: ^Type_Info,
elem_size: int, elem_size: int,
count: int, count: int,
}, },
Slice: struct #ordered { Dynamic_Array{elem: ^Type_Info, elem_size: int},
elem: ^Type_Info, Slice {elem: ^Type_Info, elem_size: int},
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,
}, },
Vector: struct #ordered { Enum{
elem: ^Type_Info, base: ^Type_Info,
elem_size: int, names: []string,
count: int,
align: int,
},
Tuple: Type_Info_Record,
Struct: Type_Info_Record,
Union: Type_Info_Record,
Raw_Union: Type_Info_Record,
Enum: struct #ordered {
base: ^Type_Info,
names: []string,
values: []Type_Info_Enum_Value, values: []Type_Info_Enum_Value,
}, },
Map{
key: ^Type_Info,
value: ^Type_Info,
generated_struct: ^Type_Info,
count: int, // == 0 if dynamic
},
} }
// // NOTE(bill): only the ones that are needed (not all types)
// // This will be set by the compiler // NOTE(bill): only the ones that are needed (not all types)
// immutable __type_infos: []Type_Info; // This will be set by the compiler
__type_table: []Type_Info;
type_info_base :: proc(info: ^Type_Info) -> ^Type_Info { type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
if info == nil { if info == nil {
return nil; return nil;
} }
base := info; base := info;
match type i in base { match i in base {
case Type_Info.Named: case Type_Info.Named:
base = i.base; base = i.base;
} }
@@ -108,6 +106,21 @@ type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
} }
type_info_base_without_enum :: proc(info: ^Type_Info) -> ^Type_Info {
if info == nil {
return nil;
}
base := info;
match i in base {
case Type_Info.Named:
base = i.base;
case Type_Info.Enum:
base = i.base;
}
return base;
}
assume :: proc(cond: bool) #foreign __llvm_core "llvm.assume"; assume :: proc(cond: bool) #foreign __llvm_core "llvm.assume";
@@ -115,16 +128,22 @@ __debug_trap :: proc() #foreign __llvm_core "llvm.debugtrap";
__trap :: proc() #foreign __llvm_core "llvm.trap"; __trap :: proc() #foreign __llvm_core "llvm.trap";
read_cycle_counter :: proc() -> u64 #foreign __llvm_core "llvm.readcyclecounter"; read_cycle_counter :: proc() -> u64 #foreign __llvm_core "llvm.readcyclecounter";
__cpuid :: proc(level: u32, sig: ^u32) -> i32 #foreign __llvm_core "__get_cpuid";
// IMPORTANT NOTE(bill): Must be in this order (as the compiler relies upon it)
Allocator_Mode :: enum u8 { Allocator_Mode :: enum u8 {
ALLOC, ALLOC,
FREE, FREE,
FREE_ALL, FREE_ALL,
RESIZE, RESIZE,
} }
Allocator_Proc :: type proc(allocator_data: rawptr, mode: Allocator_Mode, Allocator_Proc :: #type proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int, size, alignment: int,
old_memory: rawptr, old_size: int, flags: u64) -> rawptr; old_memory: rawptr, old_size: int, flags: u64) -> rawptr;
Allocator :: struct #ordered { Allocator :: struct #ordered {
procedure: Allocator_Proc, procedure: Allocator_Proc,
data: rawptr, data: rawptr,
@@ -139,7 +158,7 @@ Context :: struct #ordered {
user_index: int, user_index: int,
} }
thread_local __context: Context; #thread_local __context: Context;
DEFAULT_ALIGNMENT :: align_of([vector 4]f32); DEFAULT_ALIGNMENT :: align_of([vector 4]f32);
@@ -164,13 +183,21 @@ alloc_align :: proc(size, alignment: int) -> rawptr #inline {
return a.procedure(a.data, Allocator_Mode.ALLOC, size, alignment, nil, 0, 0); return a.procedure(a.data, Allocator_Mode.ALLOC, size, alignment, nil, 0, 0);
} }
free :: proc(ptr: rawptr) #inline { free_ptr_with_allocator :: proc(a: Allocator, ptr: rawptr) #inline {
__check_context(); if ptr == nil {
a := context.allocator; return;
if ptr != nil {
a.procedure(a.data, Allocator_Mode.FREE, 0, 0, ptr, 0, 0);
} }
if a.procedure == nil {
return;
}
a.procedure(a.data, Allocator_Mode.FREE, 0, 0, ptr, 0, 0);
} }
free_ptr :: proc(ptr: rawptr) #inline {
__check_context();
free_ptr_with_allocator(context.allocator, ptr);
}
free_all :: proc() #inline { free_all :: proc() #inline {
__check_context(); __check_context();
a := context.allocator; a := context.allocator;
@@ -217,46 +244,21 @@ default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
old_memory: rawptr, old_size: int, flags: u64) -> rawptr { old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
using Allocator_Mode; using Allocator_Mode;
when false { match mode {
match mode { case ALLOC:
case ALLOC: return os.heap_alloc(size);
total_size := size + alignment + size_of(mem.AllocationHeader);
ptr := os.heap_alloc(total_size);
header := (^mem.AllocationHeader)(ptr);
ptr = mem.align_forward(header+1, alignment);
mem.allocation_header_fill(header, ptr, size);
return mem.zero(ptr, size);
case FREE: case FREE:
os.heap_free(mem.allocation_header(old_memory)); os.heap_free(old_memory);
return nil; return nil;
case FREE_ALL: case FREE_ALL:
// NOTE(bill): Does nothing // NOTE(bill): Does nothing
case RESIZE: case RESIZE:
total_size := size + alignment + size_of(mem.AllocationHeader); ptr := os.heap_resize(old_memory, size);
ptr := os.heap_resize(mem.allocation_header(old_memory), total_size); assert(ptr != nil);
header := (^mem.AllocationHeader)(ptr); return ptr;
ptr = mem.align_forward(header+1, alignment);
mem.allocation_header_fill(header, ptr, size);
return mem.zero(ptr, size);
}
} else {
match mode {
case ALLOC:
return os.heap_alloc(size);
case FREE:
os.heap_free(old_memory);
return nil;
case FREE_ALL:
// NOTE(bill): Does nothing
case RESIZE:
return os.heap_resize(old_memory, size);
}
} }
return nil; return nil;
@@ -286,11 +288,11 @@ __string_eq :: proc(a, b: string) -> bool {
if a.data == b.data { if a.data == b.data {
return true; return true;
} }
return mem.compare(cast(rawptr)a.data, cast(rawptr)b.data, a.count) == 0; return __string_cmp(a, b) == 0;
} }
__string_cmp :: proc(a, b: string) -> int { __string_cmp :: proc(a, b: string) -> int {
return mem.compare(cast(rawptr)a.data, cast(rawptr)b.data, min(a.count, b.count)); return mem.compare(cast([]byte)a, cast([]byte)b);
} }
__string_ne :: proc(a, b: string) -> bool #inline { return !__string_eq(a, b); } __string_ne :: proc(a, b: string) -> bool #inline { return !__string_eq(a, b); }
@@ -305,34 +307,370 @@ __assert :: proc(file: string, line, column: int, msg: string) #inline {
file, line, column, msg); file, line, column, msg);
__debug_trap(); __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) { __bounds_check_error :: proc(file: string, line, column: int, index, count: int) {
if 0 <= index && index < count { if 0 <= index && index < count {
return; return;
} }
fmt.fprintf(os.stderr, "%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); file, line, column, index, count);
__debug_trap(); __debug_trap();
} }
__slice_expr_error :: proc(file: string, line, column: int, low, high: int) { __slice_expr_error :: proc(file: string, line, column: int, low, high, max: int) {
if 0 <= low && low <= high { if 0 <= low && low <= high && high <= max {
return; return;
} }
fmt.fprintf(os.stderr, "%s(%d:%d) Invalid slice indices: [%d:%d]\n", fmt.fprintf(os.stderr, "%s(%d:%d) Invalid slice indices: [%d..%d..%d]\n",
file, line, column, low, high); file, line, column, low, high, max);
__debug_trap(); __debug_trap();
} }
__substring_expr_error :: proc(file: string, line, column: int, low, high: int) { __substring_expr_error :: proc(file: string, line, column: int, low, high: int) {
if 0 <= low && low <= high { if 0 <= low && low <= high {
return; return;
} }
fmt.fprintf(os.stderr, "%s(%d:%d) Invalid substring indices: [%d:%d]\n", fmt.fprintf(os.stderr, "%s(%d:%d) Invalid substring indices: [%d..%d]\n",
file, line, column, low, high); file, line, column, low, high);
__debug_trap(); __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 { __string_decode_rune :: proc(s: string) -> (rune, int) #inline {
return utf8.decode_rune(s); return utf8.decode_rune(s);
} }
Raw_Any :: struct #ordered {
type_info: ^Type_Info,
data: rawptr,
}
Raw_String :: struct #ordered {
data: ^byte,
count: int,
};
Raw_Slice :: struct #ordered {
data: rawptr,
count: int,
capacity: int,
};
Raw_Dynamic_Array :: struct #ordered {
data: rawptr,
count: int,
capacity: int,
allocator: Allocator,
};
Raw_Dynamic_Map :: struct #ordered {
hashes: [dynamic]int,
entries: Raw_Dynamic_Array,
};
__dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, capacity: int) -> bool {
array := cast(^Raw_Dynamic_Array)array_;
if capacity <= array.capacity {
return true;
}
__check_context();
if array.allocator.procedure == nil {
array.allocator = context.allocator;
}
assert(array.allocator.procedure != nil);
old_size := array.capacity * elem_size;
new_size := capacity * elem_size;
allocator := array.allocator;
new_data := allocator.procedure(allocator.data, Allocator_Mode.RESIZE, new_size, elem_align, array.data, old_size, 0);
if new_data == nil {
return false;
}
array.data = new_data;
array.capacity = capacity;
return true;
}
__dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
items: rawptr, item_count: int) -> int {
array := cast(^Raw_Dynamic_Array)array_;
if item_count <= 0 || items == nil {
return array.count;
}
ok := true;
if array.capacity <= array.count+item_count {
capacity := 2 * array.capacity + max(8, item_count);
ok = __dynamic_array_reserve(array, elem_size, elem_align, capacity);
}
if !ok {
// TODO(bill): Better error handling for failed reservation
return array.count;
}
data := cast(^byte)array.data;
assert(data != nil);
mem.copy(data + (elem_size*array.count), items, elem_size * item_count);
array.count += item_count;
return array.count;
}
__dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: int) -> int {
array := cast(^Raw_Dynamic_Array)array_;
ok := true;
if array.capacity <= array.count+1 {
capacity := 2 * array.capacity + max(8, 1);
ok = __dynamic_array_reserve(array, elem_size, elem_align, capacity);
}
if !ok {
// TODO(bill): Better error handling for failed reservation
return array.count;
}
data := cast(^byte)array.data;
assert(data != nil);
mem.zero(data + (elem_size*array.count), elem_size);
array.count++;
return array.count;
}
__slice_append :: proc(slice_: rawptr, elem_size, elem_align: int,
items: rawptr, item_count: int) -> int {
slice := cast(^Raw_Slice)slice_;
if item_count <= 0 || items == nil {
return slice.count;
}
item_count = min(slice.capacity-slice.count, item_count);
if item_count > 0 {
data := cast(^byte)slice.data;
assert(data != nil);
mem.copy(data + (elem_size*slice.count), items, elem_size * item_count);
slice.count += item_count;
}
return slice.count;
}
// Map stuff
__default_hash :: proc(data: []byte) -> u64 {
return hash.fnv64a(data);
}
__default_hash_string :: proc(s: string) -> u64 {
return __default_hash(cast([]byte)s);
}
__Map_Key :: struct #ordered {
hash: u64,
str: string,
}
__Map_Find_Result :: struct #ordered {
hash_index: int,
entry_prev: int,
entry_index: int,
}
__Map_Entry_Header :: struct #ordered {
key: __Map_Key,
next: int,
/*
value: Value_Type,
*/
}
__Map_Header :: struct #ordered {
m: ^Raw_Dynamic_Map,
is_key_string: bool,
entry_size: int,
entry_align: int,
value_offset: int,
}
__dynamic_map_reserve :: proc(using header: __Map_Header, capacity: int) -> bool {
h := __dynamic_array_reserve(^m.hashes, size_of(int), align_of(int), capacity);
e := __dynamic_array_reserve(^m.entries, entry_size, entry_align, capacity);
return h && e;
}
__dynamic_map_rehash :: proc(using header: __Map_Header, new_count: int) {
new_header := header;
nm: Raw_Dynamic_Map;
new_header.m = ^nm;
reserve(nm.hashes, new_count);
nm.hashes.count = nm.hashes.capacity;
__dynamic_array_reserve(^nm.entries, entry_size, entry_align, m.entries.count);
for _, i in nm.hashes {
nm.hashes[i] = -1;
}
for i := 0; i < nm.entries.count; i++ {
entry_header := __dynamic_map_get_entry(new_header, i);
data := cast(^byte)entry_header;
if nm.hashes.count == 0 {
__dynamic_map_grow(new_header);
}
fr := __dynamic_map_find(new_header, entry_header.key);
j := __dynamic_map_add_entry(new_header, entry_header.key);
if fr.entry_prev < 0 {
nm.hashes[fr.hash_index] = j;
} else {
e := __dynamic_map_get_entry(new_header, fr.entry_prev);
e.next = j;
}
e := __dynamic_map_get_entry(new_header, j);
e.next = fr.entry_index;
ndata := cast(^byte)e;
mem.copy(ndata+value_offset, data+value_offset, entry_size-value_offset);
if __dynamic_map_full(new_header) {
__dynamic_map_grow(new_header);
}
}
free_ptr_with_allocator(header.m.hashes.allocator, header.m.hashes.data);
free_ptr_with_allocator(header.m.entries.allocator, header.m.entries.data);
header.m^ = nm;
}
__dynamic_map_get :: proc(h: __Map_Header, key: __Map_Key) -> rawptr {
index := __dynamic_map_find(h, key).entry_index;
if index >= 0 {
data := cast(^byte)__dynamic_map_get_entry(h, index);
val := data + h.value_offset;
return val;
}
return nil;
}
__dynamic_map_set :: proc(using h: __Map_Header, key: __Map_Key, value: rawptr) {
index: int;
if m.hashes.count == 0 {
__dynamic_map_grow(h);
}
fr := __dynamic_map_find(h, key);
if fr.entry_index >= 0 {
index = fr.entry_index;
} else {
index = __dynamic_map_add_entry(h, key);
if fr.entry_prev >= 0 {
entry := __dynamic_map_get_entry(h, fr.entry_prev);
entry.next = index;
} else {
m.hashes[fr.hash_index] = index;
}
}
{
data := cast(^byte)__dynamic_map_get_entry(h, index);
val := data+value_offset;
mem.copy(val, value, entry_size-value_offset);
}
if __dynamic_map_full(h) {
__dynamic_map_grow(h);
}
}
__dynamic_map_grow :: proc(using h: __Map_Header) {
new_count := 2*m.entries.count + 8;
__dynamic_map_rehash(h, new_count);
}
__dynamic_map_full :: proc(using h: __Map_Header) -> bool {
return cast(int)(0.75 * cast(f64)m.hashes.count) <= m.entries.count;
}
__dynamic_map_hash_equal :: proc(h: __Map_Header, a, b: __Map_Key) -> bool {
if a.hash == b.hash {
if h.is_key_string {
return a.str == b.str;
}
return true;
}
return false;
}
__dynamic_map_find :: proc(using h: __Map_Header, key: __Map_Key) -> __Map_Find_Result {
fr := __Map_Find_Result{-1, -1, -1};
if m.hashes.count > 0 {
fr.hash_index = cast(int)(key.hash % cast(u64)m.hashes.count);
fr.entry_index = m.hashes[fr.hash_index];
for fr.entry_index >= 0 {
entry := __dynamic_map_get_entry(h, fr.entry_index);
if __dynamic_map_hash_equal(h, entry.key, key) {
return fr;
}
fr.entry_prev = fr.entry_index;
fr.entry_index = entry.next;
}
}
return fr;
}
__dynamic_map_add_entry :: proc(using h: __Map_Header, key: __Map_Key) -> int {
prev := m.entries.count;
c := __dynamic_array_append_nothing(^m.entries, entry_size, entry_align);
if c != prev {
end := __dynamic_map_get_entry(h, c-1);
end.key = key;
end.next = -1;
}
return prev;
}
__dynamic_map_delete :: proc(using h: __Map_Header, key: __Map_Key) {
fr := __dynamic_map_find(h, key);
if fr.entry_index >= 0 {
__dynamic_map_erase(h, fr);
}
}
__dynamic_map_get_entry :: proc(using h: __Map_Header, index: int) -> ^__Map_Entry_Header {
data := cast(^byte)m.entries.data + index*entry_size;
return cast(^__Map_Entry_Header)data;
}
__dynamic_map_erase :: proc(using h: __Map_Header, fr: __Map_Find_Result) {
if fr.entry_prev < 0 {
m.hashes[fr.hash_index] = __dynamic_map_get_entry(h, fr.entry_index).next;
} else {
__dynamic_map_get_entry(h, fr.entry_prev).next = __dynamic_map_get_entry(h, fr.entry_index).next;
}
if fr.entry_index == m.entries.count-1 {
m.entries.count--;
}
mem.copy(__dynamic_map_get_entry(h, fr.entry_index), __dynamic_map_get_entry(h, m.entries.count-1), entry_size);
last := __dynamic_map_find(h, __dynamic_map_get_entry(h, fr.entry_index).key);
if last.entry_prev >= 0 {
__dynamic_map_get_entry(h, last.entry_prev).next = fr.entry_index;
} else {
m.hashes[last.hash_index] = fr.entry_index;
}
}
+3 -3
View File
@@ -5,7 +5,7 @@
_ := compile_assert(ODIN_ARCH == "amd64"); // TODO(bill): x86 version _ := compile_assert(ODIN_ARCH == "amd64"); // TODO(bill): x86 version
yield_thread :: proc() { win32._mm_pause(); } yield_thread :: proc() { win32.mm_pause(); }
mfence :: proc() { win32.ReadWriteBarrier(); } mfence :: proc() { win32.ReadWriteBarrier(); }
sfence :: proc() { win32.WriteBarrier(); } sfence :: proc() { win32.WriteBarrier(); }
lfence :: proc() { win32.ReadBarrier(); } lfence :: proc() { win32.ReadBarrier(); }
@@ -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); old_value := compare_exchange(a, 1, 0);
counter := 0; counter := 0;
for old_value != 0 && (time_out < 0 || counter < time_out) { for old_value != 0 && (time_out < 0 || counter < time_out) {
counter += 1; counter++;
yield_thread(); yield_thread();
old_value = compare_exchange(a, 1, 0); old_value = compare_exchange(a, 1, 0);
mfence(); 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); old_value := compare_exchange(a, 1, 0);
counter := 0; counter := 0;
for old_value != 0 && (time_out < 0 || counter < time_out) { for old_value != 0 && (time_out < 0 || counter < time_out) {
counter += 1; counter++;
yield_thread(); yield_thread();
old_value = compare_exchange(a, 1, 0); old_value = compare_exchange(a, 1, 0);
mfence(); 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;
}
+421 -416
View File
File diff suppressed because it is too large Load Diff
+97 -59
View File
@@ -1,77 +1,112 @@
crc32 :: proc(data: rawptr, len: int) -> u32 { crc32 :: proc(data: []byte) -> u32 {
result := ~cast(u32)0; result := ~cast(u32)0;
s := slice_ptr(cast(^u8)data, len); for b in data {
for i in 0..<len { result = result>>8 ~ _crc32_table[(result ~ cast(u32)b) & 0xff];
b := cast(u32)s[i];
result = result>>8 ~ __CRC32_TABLE[(result ~ b) & 0xff];
} }
return ~result; return ~result;
} }
crc64 :: proc(data: rawptr, len: int) -> u64 { crc64 :: proc(data: []byte) -> u64 {
result := ~cast(u64)0; result := ~cast(u64)0;
s := slice_ptr(cast(^u8)data, len); for b in data {
for i in 0..<len { result = result>>8 ~ _crc64_table[(result ~ cast(u64)b) & 0xff];
b := cast(u64)s[i];
result = result>>8 ~ __CRC64_TABLE[(result ~ b) & 0xff];
} }
return ~result; return ~result;
} }
fnv32 :: proc(data: rawptr, len: int) -> u32 { fnv32 :: proc(data: []byte) -> u32 {
s := slice_ptr(cast(^u8)data, len);
h: u32 = 0x811c9dc5; h: u32 = 0x811c9dc5;
for i in 0..<len { for b in data {
h = (h * 0x01000193) ~ cast(u32)s[i]; h = (h * 0x01000193) ~ cast(u32)b;
} }
return h; return h;
} }
fnv64 :: proc(data: rawptr, len: int) -> u64 { fnv64 :: proc(data: []byte) -> u64 {
s := slice_ptr(cast(^u8)data, len);
h: u64 = 0xcbf29ce484222325; h: u64 = 0xcbf29ce484222325;
for i in 0..<len { for b in data {
h = (h * 0x100000001b3) ~ cast(u64)s[i]; h = (h * 0x100000001b3) ~ cast(u64)b;
} }
return h; return h;
} }
fnv32a :: proc(data: rawptr, len: int) -> u32 { fnv32a :: proc(data: []byte) -> u32 {
s := slice_ptr(cast(^u8)data, len);
h: u32 = 0x811c9dc5; h: u32 = 0x811c9dc5;
for i in 0..<len { for b in data {
h = (h ~ cast(u32)s[i]) * 0x01000193; h = (h ~ cast(u32)b) * 0x01000193;
} }
return h; return h;
} }
fnv64a :: proc(data: rawptr, len: int) -> u64 { fnv64a :: proc(data: []byte) -> u64 {
s := slice_ptr(cast(^u8)data, len); h: u64 = 0xcbf29ce484222325;
for b in data {
h :u64 = 0xcbf29ce484222325; h = (h ~ cast(u64)b) * 0x100000001b3;
for i in 0..<len {
h = (h ~ cast(u64)s[i]) * 0x100000001b3;
} }
return h; return h;
} }
murmur32 :: proc(data: []byte) -> u32 {
c1_32: u32 : 0xcc9e2d51;
c2_32: u32 : 0x1b873593;
murmur64 :: proc(data_: rawptr, len: int) -> u64 { h1: u32 = 0;
nblocks := data.count/4;
p := data.data;
p1 := p + 4*nblocks;
for ; p < p1; p += 4 {
k1 := (cast(^u32)p)^;
k1 *= c1_32;
k1 = (k1 << 15) | (k1 >> 17);
k1 *= c2_32;
h1 ~= k1;
h1 = (h1 << 13) | (h1 >> 19);
h1 = h1*5 + 0xe6546b64;
}
tail := data[nblocks*4 ..];
k1: u32;
match tail.count&3 {
case 3:
k1 ~= cast(u32)tail[2] << 16;
fallthrough;
case 2:
k1 ~= cast(u32)tail[2] << 8;
fallthrough;
case 1:
k1 ~= cast(u32)tail[0];
k1 *= c1_32;
k1 = (k1 << 15) | (k1 >> 17) ;
k1 *= c2_32;
h1 ~= k1;
}
h1 ~= cast(u32)data.count;
h1 ~= h1 >> 16;
h1 *= 0x85ebca6b;
h1 ~= h1 >> 13;
h1 *= 0xc2b2ae35;
h1 ~= h1 >> 16;
return h1;
}
murmur64 :: proc(data: []byte) -> u64 {
SEED :: 0x9747b28c; SEED :: 0x9747b28c;
when size_of(int) == 8 { when false && size_of(int) == 8 {
m :: 0xc6a4a7935bd1e995; m :: 0xc6a4a7935bd1e995;
r :: 47; r :: 47;
h: u64 = SEED ~ (cast(u64)len * m); h: u64 = SEED ~ (cast(u64)data.count * m);
data64 := slice_ptr(cast(^u64)^data[0], data.count/size_of(u64));
data := slice_ptr(cast(^u64)data_, len/size_of(u64)); for _, i in data64 {
data2 := slice_ptr(cast(^u8)data_, len); k := data64[i];
for i in 0 ..< data.count {
k := data[i];
k *= m; k *= m;
k ~= k>>r; k ~= k>>r;
@@ -81,15 +116,15 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
h *= m; h *= m;
} }
match len & 7 { match data.count&7 {
case 7: h ~= cast(u64)data2[6] << 48; fallthrough; case 7: h ~= cast(u64)data[6] << 48; fallthrough;
case 6: h ~= cast(u64)data2[5] << 40; fallthrough; case 6: h ~= cast(u64)data[5] << 40; fallthrough;
case 5: h ~= cast(u64)data2[4] << 32; fallthrough; case 5: h ~= cast(u64)data[4] << 32; fallthrough;
case 4: h ~= cast(u64)data2[3] << 24; fallthrough; case 4: h ~= cast(u64)data[3] << 24; fallthrough;
case 3: h ~= cast(u64)data2[2] << 16; fallthrough; case 3: h ~= cast(u64)data[2] << 16; fallthrough;
case 2: h ~= cast(u64)data2[1] << 8; fallthrough; case 2: h ~= cast(u64)data[1] << 8; fallthrough;
case 1: case 1:
h ~= cast(u64)data2[0]; h ~= cast(u64)data[0];
h *= m; h *= m;
} }
@@ -102,15 +137,16 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
m :: 0x5bd1e995; m :: 0x5bd1e995;
r :: 24; r :: 24;
h1: u32 = cast(u32)SEED ~ cast(u32)len; h1: u32 = cast(u32)SEED ~ cast(u32)data.count;
h2: u32 = SEED >> 32; h2: u32 = SEED >> 32;
data := slice_ptr(cast(^u32)data_, len/size_of(u32)); data32 := slice_ptr(cast(^u32)^data[0], data.count/size_of(u32));
len := data.count;
i := 0; i := 0;
for len >= 8 { for len >= 8 {
k1, k2: u32; k1, k2: u32;
k1 = data[i]; i += 1; k1 = data32[i]; i++;
k1 *= m; k1 *= m;
k1 ~= k1>>r; k1 ~= k1>>r;
k1 *= m; k1 *= m;
@@ -118,7 +154,7 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
h1 ~= k1; h1 ~= k1;
len -= 4; len -= 4;
k2 = data[i]; i += 1; k2 = data32[i]; i++;
k2 *= m; k2 *= m;
k2 ~= k2>>r; k2 ~= k2>>r;
k2 *= m; k2 *= m;
@@ -129,7 +165,7 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
if len >= 4 { if len >= 4 {
k1: u32; k1: u32;
k1 = data[i]; i += 1; k1 = data32[i]; i++;
k1 *= m; k1 *= m;
k1 ~= k1>>r; k1 ~= k1>>r;
k1 *= m; k1 *= m;
@@ -138,11 +174,14 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
len -= 4; len -= 4;
} }
data8 := slice_ptr(cast(^u8)(data.data+i), 3); // NOTE(bill): This is unsafe data8 := slice_to_bytes(data32[i..])[..3];
match len { match len {
case 3: h2 ~= cast(u32)data8[2] << 16; fallthrough; case 3:
case 2: h2 ~= cast(u32)data8[1] << 8; fallthrough; h2 ~= cast(u32)data8[2] << 16;
fallthrough;
case 2:
h2 ~= cast(u32)data8[1] << 8;
fallthrough;
case 1: case 1:
h2 ~= cast(u32)data8[0]; h2 ~= cast(u32)data8[0];
h2 *= m; h2 *= m;
@@ -163,8 +202,7 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
} }
immutable _crc32_table := [256]u32{
__CRC32_TABLE := [256]u32{
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
@@ -230,7 +268,7 @@ __CRC32_TABLE := [256]u32{
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
}; };
__CRC64_TABLE := [256]u64{ immutable _crc64_table := [256]u64{
0x0000000000000000, 0x42f0e1eba9ea3693, 0x85e1c3d753d46d26, 0xc711223cfa3e5bb5, 0x0000000000000000, 0x42f0e1eba9ea3693, 0x85e1c3d753d46d26, 0xc711223cfa3e5bb5,
0x493366450e42ecdf, 0x0bc387aea7a8da4c, 0xccd2a5925d9681f9, 0x8e224479f47cb76a, 0x493366450e42ecdf, 0x0bc387aea7a8da4c, 0xccd2a5925d9681f9, 0x8e224479f47cb76a,
0x9266cc8a1c85d9be, 0xd0962d61b56fef2d, 0x17870f5d4f51b498, 0x5577eeb6e6bb820b, 0x9266cc8a1c85d9be, 0xd0962d61b56fef2d, 0x17870f5d4f51b498, 0x5577eeb6e6bb820b,
+4 -8
View File
@@ -46,10 +46,6 @@ bit_reverse :: proc(b: u16) -> u16 #foreign __llvm_core "llvm.bitreverse.i16";
bit_reverse :: proc(b: u32) -> u32 #foreign __llvm_core "llvm.bitreverse.i32"; bit_reverse :: proc(b: u32) -> u32 #foreign __llvm_core "llvm.bitreverse.i32";
bit_reverse :: proc(b: u64) -> u64 #foreign __llvm_core "llvm.bitreverse.i64"; bit_reverse :: proc(b: u64) -> u64 #foreign __llvm_core "llvm.bitreverse.i64";
byte_swap :: proc(b: u16) -> u16 #foreign __llvm_core "llvm.bswap.i16";
byte_swap :: proc(b: u32) -> u32 #foreign __llvm_core "llvm.bswap.i32";
byte_swap :: proc(b: u64) -> u64 #foreign __llvm_core "llvm.bswap.i64";
fmuladd :: proc(a, b, c: f32) -> f32 #foreign __llvm_core "llvm.fmuladd.f32"; fmuladd :: proc(a, b, c: f32) -> f32 #foreign __llvm_core "llvm.fmuladd.f32";
fmuladd :: proc(a, b, c: f64) -> f64 #foreign __llvm_core "llvm.fmuladd.f64"; fmuladd :: proc(a, b, c: f64) -> f64 #foreign __llvm_core "llvm.fmuladd.f64";
@@ -155,8 +151,8 @@ mat4_identity :: proc() -> Mat4 {
} }
mat4_transpose :: proc(m: Mat4) -> Mat4 { mat4_transpose :: proc(m: Mat4) -> Mat4 {
for j in 0..<4 { for j in 0..4 {
for i in 0..<4 { for i in 0..4 {
m[i][j], m[j][i] = m[j][i], m[i][j]; m[i][j], m[j][i] = m[j][i], m[i][j];
} }
} }
@@ -165,8 +161,8 @@ mat4_transpose :: proc(m: Mat4) -> Mat4 {
mul :: proc(a, b: Mat4) -> Mat4 { mul :: proc(a, b: Mat4) -> Mat4 {
c: Mat4; c: Mat4;
for j in 0..<4 { for j in 0..4 {
for i in 0..<4 { for i in 0..4 {
c[j][i] = a[0][i]*b[j][0] + c[j][i] = a[0][i]*b[j][0] +
a[1][i]*b[j][1] + a[1][i]*b[j][1] +
a[2][i]*b[j][2] + a[2][i]*b[j][2] +
+46 -44
View File
@@ -1,6 +1,11 @@
#import "fmt.odin"; #import "fmt.odin";
#import "os.odin"; #import "os.odin";
swap :: proc(b: u16) -> u16 #foreign __llvm_core "llvm.bswap.i16";
swap :: proc(b: u32) -> u32 #foreign __llvm_core "llvm.bswap.i32";
swap :: proc(b: u64) -> u64 #foreign __llvm_core "llvm.bswap.i64";
set :: proc(data: rawptr, value: i32, len: int) -> rawptr #link_name "__mem_set" { set :: proc(data: rawptr, value: i32, len: int) -> rawptr #link_name "__mem_set" {
llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memset.p0i8.i64"; llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memset.p0i8.i64";
llvm_memset_64bit(data, cast(byte)value, len, 1, false); llvm_memset_64bit(data, cast(byte)value, len, 1, false);
@@ -12,23 +17,22 @@ zero :: proc(data: rawptr, len: int) -> rawptr #link_name "__mem_zero" {
} }
copy :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy" { copy :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy" {
// NOTE(bill): This _must_ implemented like C's memmove // NOTE(bill): This _must_ be implemented like C's memmove
llvm_memmove_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memmove.p0i8.p0i8.i64"; llvm_memmove_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memmove.p0i8.p0i8.i64";
llvm_memmove_64bit(dst, src, len, 1, false); llvm_memmove_64bit(dst, src, len, 1, false);
return dst; return dst;
} }
copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy_non_overlapping" { copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy_non_overlapping" {
// NOTE(bill): This _must_ implemented like C's memcpy // NOTE(bill): This _must_ be implemented like C's memcpy
llvm_memcpy_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memcpy.p0i8.p0i8.i64"; llvm_memcpy_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memcpy.p0i8.p0i8.i64";
llvm_memcpy_64bit(dst, src, len, 1, false); llvm_memcpy_64bit(dst, src, len, 1, false);
return dst; return dst;
} }
compare :: proc(dst, src: rawptr, n: int) -> int #link_name "__mem_compare" { compare :: proc(a, b: []byte) -> int #link_name "__mem_compare" {
a := slice_ptr(cast(^byte)dst, n); n := min(a.count, b.count);
b := slice_ptr(cast(^byte)src, n); for i in 0..n {
for i in 0..<n {
match { match {
case a[i] < b[i]: case a[i] < b[i]:
return -1; return -1;
@@ -43,8 +47,8 @@ compare :: proc(dst, src: rawptr, n: int) -> int #link_name "__mem_compare" {
kilobytes :: proc(x: int) -> int #inline { return (x) * 1024; } kilobytes :: proc(x: int) -> int #inline { return (x) * 1024; }
megabytes :: proc(x: int) -> int #inline { return kilobytes(x) * 1024; } megabytes :: proc(x: int) -> int #inline { return kilobytes(x) * 1024; }
gigabytes :: proc(x: int) -> int #inline { return gigabytes(x) * 1024; } gigabytes :: proc(x: int) -> int #inline { return megabytes(x) * 1024; }
terabytes :: proc(x: int) -> int #inline { return terabytes(x) * 1024; } terabytes :: proc(x: int) -> int #inline { return gigabytes(x) * 1024; }
is_power_of_two :: proc(x: int) -> bool { is_power_of_two :: proc(x: int) -> bool {
if x <= 0 { if x <= 0 {
@@ -75,11 +79,14 @@ allocation_header_fill :: proc(header: ^Allocation_Header, data: rawptr, size: i
header.size = size; header.size = size;
ptr := cast(^int)(header+1); 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; (ptr+i)^ = -1;
} }
} }
allocation_header :: proc(data: rawptr) -> ^Allocation_Header { allocation_header :: proc(data: rawptr) -> ^Allocation_Header {
if data == nil {
return nil;
}
p := cast(^int)data; p := cast(^int)data;
for (p-1)^ == -1 { for (p-1)^ == -1 {
p = (p-1); p = (p-1);
@@ -110,7 +117,7 @@ Arena_Temp_Memory :: struct {
init_arena_from_memory :: proc(using a: ^Arena, data: []byte) { init_arena_from_memory :: proc(using a: ^Arena, data: []byte) {
backing = Allocator{}; backing = Allocator{};
memory = data[:0]; memory = data[..0];
temp_count = 0; temp_count = 0;
} }
@@ -123,8 +130,8 @@ init_arena_from_context :: proc(using a: ^Arena, size: int) {
free_arena :: proc(using a: ^Arena) { free_arena :: proc(using a: ^Arena) {
if backing.procedure != nil { if backing.procedure != nil {
push_allocator backing { push_allocator backing {
free(memory.data); free(memory);
memory = memory[0:0]; memory = nil;
offset = 0; offset = 0;
} }
} }
@@ -176,7 +183,7 @@ begin_arena_temp_memory :: proc(a: ^Arena) -> Arena_Temp_Memory {
tmp: Arena_Temp_Memory; tmp: Arena_Temp_Memory;
tmp.arena = a; tmp.arena = a;
tmp.original_count = a.memory.count; tmp.original_count = a.memory.count;
a.temp_count += 1; a.temp_count++;
return tmp; return tmp;
} }
@@ -184,7 +191,7 @@ end_arena_temp_memory :: proc(using tmp: Arena_Temp_Memory) {
assert(arena.memory.count >= original_count); assert(arena.memory.count >= original_count);
assert(arena.temp_count > 0); assert(arena.temp_count > 0);
arena.memory.count = original_count; arena.memory.count = original_count;
arena.temp_count -= 1; arena.temp_count--;
} }
@@ -210,8 +217,7 @@ align_of_type_info :: proc(type_info: ^Type_Info) -> int {
WORD_SIZE :: size_of(int); WORD_SIZE :: size_of(int);
MAX_ALIGN :: size_of([vector 64]f64); // TODO(bill): Should these constants be builtin constants? MAX_ALIGN :: size_of([vector 64]f64); // TODO(bill): Should these constants be builtin constants?
using Type_Info; using Type_Info;
match info in type_info {
match type info in type_info {
case Named: case Named:
return align_of_type_info(info.base); return align_of_type_info(info.base);
case Integer: case Integer:
@@ -222,14 +228,16 @@ align_of_type_info :: proc(type_info: ^Type_Info) -> int {
return WORD_SIZE; return WORD_SIZE;
case Boolean: case Boolean:
return 1; return 1;
case Any:
return WORD_SIZE;
case Pointer: case Pointer:
return WORD_SIZE; return WORD_SIZE;
case Maybe:
return max(align_of_type_info(info.elem), 1);
case Procedure: case Procedure:
return WORD_SIZE; return WORD_SIZE;
case Array: case Array:
return align_of_type_info(info.elem); return align_of_type_info(info.elem);
case Dynamic_Array:
return WORD_SIZE;
case Slice: case Slice:
return WORD_SIZE; return WORD_SIZE;
case Vector: case Vector:
@@ -237,12 +245,18 @@ align_of_type_info :: proc(type_info: ^Type_Info) -> int {
count := cast(int)max(prev_pow2(cast(i64)info.count), 1); count := cast(int)max(prev_pow2(cast(i64)info.count), 1);
total := size * count; total := size * count;
return clamp(total, 1, MAX_ALIGN); return clamp(total, 1, MAX_ALIGN);
case Tuple:
return info.align;
case Struct: case Struct:
return info.align; return info.align;
case Union: case Union:
return info.align; return info.align;
case Raw_Union: case Raw_Union:
return info.align; return info.align;
case Enum:
return align_of_type_info(info.base);
case Map:
return align_of_type_info(info.generated_struct);
} }
return 0; return 0;
@@ -256,23 +270,21 @@ align_formula :: proc(size, align: int) -> int {
size_of_type_info :: proc(type_info: ^Type_Info) -> int { size_of_type_info :: proc(type_info: ^Type_Info) -> int {
WORD_SIZE :: size_of(int); WORD_SIZE :: size_of(int);
using Type_Info; using Type_Info;
match type info in type_info { match info in type_info {
case Named: case Named:
return size_of_type_info(info.base); return size_of_type_info(info.base);
case Integer: case Integer:
return info.size; return info.size;
case Float: case Float:
return info.size; return info.size;
case Any:
return 2*WORD_SIZE;
case String: case String:
return 2*WORD_SIZE; return 2*WORD_SIZE;
case Boolean: case Boolean:
return 1; return 1;
case Any:
return 2*WORD_SIZE;
case Pointer: case Pointer:
return WORD_SIZE; return WORD_SIZE;
case Maybe:
return size_of_type_info(info.elem) + 1;
case Procedure: case Procedure:
return WORD_SIZE; return WORD_SIZE;
case Array: case Array:
@@ -284,39 +296,29 @@ size_of_type_info :: proc(type_info: ^Type_Info) -> int {
align := align_of_type_info(info.elem); align := align_of_type_info(info.elem);
alignment := align_formula(size, align); alignment := align_formula(size, align);
return alignment*(count-1) + size; return alignment*(count-1) + size;
case Dynamic_Array:
return size_of(rawptr) + 2*size_of(int) + size_of(Allocator);
case Slice: case Slice:
return 3*WORD_SIZE; return 2*WORD_SIZE;
case Vector: case Vector:
is_bool :: proc(type_info: ^Type_Info) -> bool {
match type info in type_info {
case Named:
return is_bool(info.base);
case Boolean:
return true;
}
return false;
}
count := info.count; count := info.count;
if count == 0 { if count == 0 {
return 0; return 0;
} }
bit_size := 8*size_of_type_info(info.elem); size := size_of_type_info(info.elem);
if is_bool(info.elem) { align := align_of_type_info(info.elem);
// NOTE(bill): LLVM can store booleans as 1 bit because a boolean _is_ an `i1` alignment := align_formula(size, align);
// Silly LLVM spec return alignment*(count-1) + size;
bit_size = 1;
}
total_size_in_bits := bit_size * count;
total_size := (total_size_in_bits+7)/8;
return total_size;
case Struct: case Struct:
return info.size; return info.size;
case Union: case Union:
return info.size; return info.size;
case Raw_Union: case Raw_Union:
return info.size; return info.size;
case Enum:
return size_of_type_info(info.base);
case Map:
return size_of_type_info(info.generated_struct);
} }
return 0; return 0;
+90 -89
View File
@@ -1,6 +1,7 @@
#foreign_system_library lib "opengl32.lib" when ODIN_OS == "windows"; #foreign_system_library lib "opengl32.lib" when ODIN_OS == "windows";
#import win32 "sys/windows.odin" when ODIN_OS == "windows"; #import win32 "sys/windows.odin" when ODIN_OS == "windows";
#include "opengl_constants.odin"; #import "sys/wgl.odin" when ODIN_OS == "windows";
#load "opengl_constants.odin";
Clear :: proc(mask: u32) #foreign lib "glClear"; Clear :: proc(mask: u32) #foreign lib "glClear";
ClearColor :: proc(r, g, b, a: f32) #foreign lib "glClearColor"; ClearColor :: proc(r, g, b, a: f32) #foreign lib "glClearColor";
@@ -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"; Ortho :: proc(left, right, bottom, top, near, far: f64) #foreign lib "glOrtho";
Color3f :: proc(r, g, b: f32) #foreign lib "glColor3f"; Color3f :: proc(r, g, b: f32) #foreign lib "glColor3f";
Vertex3f :: proc(x, y, z: f32) #foreign lib "glVertex3f"; 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, TexImage2D :: proc(target, level, internal_format,
width, height, border, width, height, border,
format, _type: i32, pixels: rawptr) #foreign lib "glTexImage2D"; 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";
string_data :: proc(s: string) -> ^u8 #inline { return ^s[0]; } 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 { GetProcAddress :: proc(name: string) -> proc() #cc_c {
assert(name[name.count-1] == 0); assert(name[name.count-1] == 0);
res := win32.wglGetProcAddress(name.data); res := wgl.GetProcAddress(name.data);
if res == nil { if res == nil {
res = win32.GetProcAddress(_libgl, name.data); res = win32.GetProcAddress(_libgl, name.data);
} }
return res; return res;
} }
GenBuffers: proc(count: i32, buffers: ^u32) #cc_c; GenBuffers: proc(count: i32, buffers: ^u32) #cc_c;
GenVertexArrays: proc(count: i32, buffers: ^u32) #cc_c; GenVertexArrays: proc(count: i32, buffers: ^u32) #cc_c;
GenSamplers: proc(count: i32, buffers: ^u32) #cc_c; GenSamplers: proc(count: i32, buffers: ^u32) #cc_c;
BindBuffer: proc(target: i32, buffer: u32) #cc_c; BindBuffer: proc(target: i32, buffer: u32) #cc_c;
BindVertexArray: proc(buffer: u32) #cc_c; BindVertexArray: proc(buffer: u32) #cc_c;
BindSampler: proc(position: i32, sampler: u32) #cc_c; BindSampler: proc(position: i32, sampler: u32) #cc_c;
BufferData: proc(target: i32, size: int, data: rawptr, usage: i32) #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; BufferSubData: proc(target: i32, offset, size: int, data: rawptr) #cc_c;
DrawArrays: proc(mode, first: i32, count: u32) #cc_c; DrawArrays: proc(mode, first: i32, count: u32) #cc_c;
DrawElements: proc(mode: i32, count: u32, type_: i32, indices: rawptr) #cc_c; DrawElements: proc(mode: i32, count: u32, type_: i32, indices: rawptr) #cc_c;
MapBuffer: proc(target, access: i32) -> rawptr #cc_c; MapBuffer: proc(target, access: i32) -> rawptr #cc_c;
UnmapBuffer: proc(target: i32) #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; EnableVertexAttribArray: proc(index: u32) #cc_c;
CreateShader: proc(shader_type: i32) -> u32 #cc_c; CreateShader: proc(shader_type: i32) -> u32 #cc_c;
ShaderSource: proc(shader: u32, count: u32, str: ^^byte, length: ^i32) #cc_c; ShaderSource: proc(shader: u32, count: u32, str: ^^byte, length: ^i32) #cc_c;
CompileShader: proc(shader: u32) #cc_c; CompileShader: proc(shader: u32) #cc_c;
CreateProgram: proc() -> u32 #cc_c; CreateProgram: proc() -> u32 #cc_c;
AttachShader: proc(program, shader: u32) #cc_c; AttachShader: proc(program, shader: u32) #cc_c;
DetachShader: proc(program, shader: u32) #cc_c; DetachShader: proc(program, shader: u32) #cc_c;
DeleteShader: proc(shader: u32) #cc_c; DeleteShader: proc(shader: u32) #cc_c;
LinkProgram: proc(program: u32) #cc_c; LinkProgram: proc(program: u32) #cc_c;
UseProgram: proc(program: u32) #cc_c; UseProgram: proc(program: u32) #cc_c;
DeleteProgram: proc(program: u32) #cc_c; DeleteProgram: proc(program: u32) #cc_c;
GetShaderiv: proc(shader: u32, pname: i32, params: ^i32) #cc_c; GetShaderiv: proc(shader: u32, pname: i32, params: ^i32) #cc_c;
GetProgramiv: proc(program: 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; 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; GetProgramInfoLog: proc(program: u32, max_length: u32, length: ^u32, info_long: ^byte) #cc_c;
ActiveTexture: proc(texture: i32) #cc_c; ActiveTexture: proc(texture: i32) #cc_c;
GenerateMipmap: proc(target: i32) #cc_c; GenerateMipmap: proc(target: i32) #cc_c;
SamplerParameteri: proc(sampler: u32, pname: i32, param: i32) #cc_c; SamplerParameteri: proc(sampler: u32, pname: i32, param: i32) #cc_c;
SamplerParameterf: proc(sampler: u32, pname: i32, param: f32) #cc_c; SamplerParameterf: proc(sampler: u32, pname: i32, param: f32) #cc_c;
SamplerParameteriv: proc(sampler: u32, pname: i32, params: ^i32) #cc_c; SamplerParameteriv: proc(sampler: u32, pname: i32, params: ^i32) #cc_c;
SamplerParameterfv: proc(sampler: u32, pname: i32, params: ^f32) #cc_c; SamplerParameterfv: proc(sampler: u32, pname: i32, params: ^f32) #cc_c;
SamplerParameterIiv: proc(sampler: u32, pname: i32, params: ^i32) #cc_c; SamplerParameterIiv: proc(sampler: u32, pname: i32, params: ^i32) #cc_c;
SamplerParameterIuiv: proc(sampler: u32, pname: i32, params: ^u32) #cc_c; SamplerParameterIuiv: proc(sampler: u32, pname: i32, params: ^u32) #cc_c;
Uniform1i: proc(loc: i32, v0: i32) #cc_c; Uniform1i: proc(loc: i32, v0: i32) #cc_c;
Uniform2i: proc(loc: i32, v0, v1: i32) #cc_c; Uniform2i: proc(loc: i32, v0, v1: i32) #cc_c;
Uniform3i: proc(loc: i32, v0, v1, v2: i32) #cc_c; Uniform3i: proc(loc: i32, v0, v1, v2: i32) #cc_c;
Uniform4i: proc(loc: i32, v0, v1, v2, v3: i32) #cc_c; Uniform4i: proc(loc: i32, v0, v1, v2, v3: i32) #cc_c;
Uniform1f: proc(loc: i32, v0: f32) #cc_c; Uniform1f: proc(loc: i32, v0: f32) #cc_c;
Uniform2f: proc(loc: i32, v0, v1: f32) #cc_c; Uniform2f: proc(loc: i32, v0, v1: f32) #cc_c;
Uniform3f: proc(loc: i32, v0, v1, v2: f32) #cc_c; Uniform3f: proc(loc: i32, v0, v1, v2: f32) #cc_c;
Uniform4f: proc(loc: i32, v0, v1, v2, v3: 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; 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() { init :: proc() {
set_proc_address :: proc(p: rawptr, name: string) #inline { (cast(^(proc() #cc_c))p)^ = GetProcAddress(name); } set_proc_address :: proc(p: rawptr, name: string) #inline { (cast(^(proc() #cc_c))p)^ = GetProcAddress(name); }
set_proc_address(^GenBuffers, "glGenBuffers\x00"); set_proc_address(^GenBuffers, "glGenBuffers\x00");
set_proc_address(^GenVertexArrays, "glGenVertexArrays\x00"); set_proc_address(^GenVertexArrays, "glGenVertexArrays\x00");
set_proc_address(^GenSamplers, "glGenSamplers\x00"); set_proc_address(^GenSamplers, "glGenSamplers\x00");
set_proc_address(^BindBuffer, "glBindBuffer\x00"); set_proc_address(^BindBuffer, "glBindBuffer\x00");
set_proc_address(^BindSampler, "glBindSampler\x00"); set_proc_address(^BindSampler, "glBindSampler\x00");
set_proc_address(^BindVertexArray, "glBindVertexArray\x00"); set_proc_address(^BindVertexArray, "glBindVertexArray\x00");
set_proc_address(^BufferData, "glBufferData\x00"); set_proc_address(^BufferData, "glBufferData\x00");
set_proc_address(^BufferSubData, "glBufferSubData\x00"); set_proc_address(^BufferSubData, "glBufferSubData\x00");
set_proc_address(^DrawArrays, "glDrawArrays\x00"); set_proc_address(^DrawArrays, "glDrawArrays\x00");
set_proc_address(^DrawElements, "glDrawElements\x00"); set_proc_address(^DrawElements, "glDrawElements\x00");
set_proc_address(^MapBuffer, "glMapBuffer\x00"); set_proc_address(^MapBuffer, "glMapBuffer\x00");
set_proc_address(^UnmapBuffer, "glUnmapBuffer\x00"); set_proc_address(^UnmapBuffer, "glUnmapBuffer\x00");
set_proc_address(^VertexAttribPointer, "glVertexAttribPointer\x00"); set_proc_address(^VertexAttribPointer, "glVertexAttribPointer\x00");
set_proc_address(^EnableVertexAttribArray, "glEnableVertexAttribArray\x00"); set_proc_address(^EnableVertexAttribArray, "glEnableVertexAttribArray\x00");
set_proc_address(^CreateShader, "glCreateShader\x00"); set_proc_address(^CreateShader, "glCreateShader\x00");
set_proc_address(^ShaderSource, "glShaderSource\x00"); set_proc_address(^ShaderSource, "glShaderSource\x00");
set_proc_address(^CompileShader, "glCompileShader\x00"); set_proc_address(^CompileShader, "glCompileShader\x00");
set_proc_address(^CreateProgram, "glCreateProgram\x00"); set_proc_address(^CreateProgram, "glCreateProgram\x00");
set_proc_address(^AttachShader, "glAttachShader\x00"); set_proc_address(^AttachShader, "glAttachShader\x00");
set_proc_address(^DetachShader, "glDetachShader\x00"); set_proc_address(^DetachShader, "glDetachShader\x00");
set_proc_address(^DeleteShader, "glDeleteShader\x00"); set_proc_address(^DeleteShader, "glDeleteShader\x00");
set_proc_address(^LinkProgram, "glLinkProgram\x00"); set_proc_address(^LinkProgram, "glLinkProgram\x00");
set_proc_address(^UseProgram, "glUseProgram\x00"); set_proc_address(^UseProgram, "glUseProgram\x00");
set_proc_address(^DeleteProgram, "glDeleteProgram\x00"); set_proc_address(^DeleteProgram, "glDeleteProgram\x00");
set_proc_address(^GetShaderiv, "glGetShaderiv\x00"); set_proc_address(^GetShaderiv, "glGetShaderiv\x00");
set_proc_address(^GetProgramiv, "glGetProgramiv\x00"); set_proc_address(^GetProgramiv, "glGetProgramiv\x00");
set_proc_address(^GetShaderInfoLog, "glGetShaderInfoLog\x00"); set_proc_address(^GetShaderInfoLog, "glGetShaderInfoLog\x00");
set_proc_address(^GetProgramInfoLog, "glGetProgramInfoLog\x00"); set_proc_address(^GetProgramInfoLog, "glGetProgramInfoLog\x00");
set_proc_address(^ActiveTexture, "glActiveTexture\x00"); set_proc_address(^ActiveTexture, "glActiveTexture\x00");
set_proc_address(^GenerateMipmap, "glGenerateMipmap\x00"); set_proc_address(^GenerateMipmap, "glGenerateMipmap\x00");
set_proc_address(^Uniform1i, "glUniform1i\x00"); set_proc_address(^Uniform1i, "glUniform1i\x00");
set_proc_address(^UniformMatrix4fv, "glUniformMatrix4fv\x00"); set_proc_address(^UniformMatrix4fv, "glUniformMatrix4fv\x00");
set_proc_address(^GetUniformLocation, "glGetUniformLocation\x00"); set_proc_address(^GetUniformLocation, "glGetUniformLocation\x00");
set_proc_address(^SamplerParameteri, "glSamplerParameteri\x00"); set_proc_address(^SamplerParameteri, "glSamplerParameteri\x00");
set_proc_address(^SamplerParameterf, "glSamplerParameterf\x00"); set_proc_address(^SamplerParameterf, "glSamplerParameterf\x00");
set_proc_address(^SamplerParameteriv, "glSamplerParameteriv\x00"); set_proc_address(^SamplerParameteriv, "glSamplerParameteriv\x00");
set_proc_address(^SamplerParameterfv, "glSamplerParameterfv\x00"); set_proc_address(^SamplerParameterfv, "glSamplerParameterfv\x00");
set_proc_address(^SamplerParameterIiv, "glSamplerParameterIiv\x00"); set_proc_address(^SamplerParameterIiv, "glSamplerParameterIiv\x00");
set_proc_address(^SamplerParameterIuiv, "glSamplerParameterIuiv\x00"); set_proc_address(^SamplerParameterIuiv, "glSamplerParameterIuiv\x00");
} }
+2 -1
View File
@@ -1,2 +1,3 @@
#include "os_windows.odin" when ODIN_OS == "windows" #load "os_windows.odin" when ODIN_OS == "windows";
#load "os_x.odin" when ODIN_OS == "osx";
+15 -4
View File
@@ -95,7 +95,7 @@ open :: proc(path: string, mode: int, perm: u32) -> (Handle, Errno) {
} }
buf: [300]byte; 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); handle := cast(Handle)CreateFileA(^buf[0], access, share_mode, sa, create_mode, FILE_ATTRIBUTE_NORMAL, nil);
if handle != INVALID_HANDLE { if handle != INVALID_HANDLE {
@@ -184,7 +184,7 @@ last_write_time_by_name :: proc(name: string) -> File_Time {
assert(buf.count > name.count); assert(buf.count > name.count);
copy(buf[:], cast([]byte)name); copy(buf[..], cast([]byte)name);
if win32.GetFileAttributesExA(^buf[0], win32.GetFileExInfoStandard, ^data) != 0 { if win32.GetFileAttributesExA(^buf[0], win32.GetFileExInfoStandard, ^data) != 0 {
last_write_time = data.last_write_time; 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) { read_entire_file :: proc(name: string) -> ([]byte, bool) {
buf: [300]byte; buf: [300]byte;
copy(buf[:], cast([]byte)name); copy(buf[..], cast([]byte)name);
fd, err := open(name, O_RDONLY, 0); fd, err := open(name, O_RDONLY, 0);
if err != ERROR_NONE { if err != ERROR_NONE {
@@ -235,7 +235,7 @@ read_entire_file :: proc(name: string) -> ([]byte, bool) {
win32.ReadFile(cast(win32.HANDLE)fd, ^data[total_read], to_read, ^single_read_length, nil); win32.ReadFile(cast(win32.HANDLE)fd, ^data[total_read], to_read, ^single_read_length, nil);
if single_read_length <= 0 { if single_read_length <= 0 {
free(data.data); free(data);
return nil, false; return nil, false;
} }
@@ -248,12 +248,23 @@ read_entire_file :: proc(name: string) -> ([]byte, bool) {
heap_alloc :: proc(size: int) -> rawptr { heap_alloc :: proc(size: int) -> rawptr {
assert(size > 0);
return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, size); return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, size);
} }
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr { heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
if new_size == 0 {
heap_free(ptr);
return nil;
}
if ptr == nil {
return heap_alloc(new_size);
}
return win32.HeapReAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, ptr, new_size); return win32.HeapReAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, ptr, new_size);
} }
heap_free :: proc(ptr: rawptr) { heap_free :: proc(ptr: rawptr) {
if ptr == nil {
return;
}
win32.HeapFree(win32.GetProcessHeap(), 0, ptr); win32.HeapFree(win32.GetProcessHeap(), 0, ptr);
} }
+230
View File
@@ -0,0 +1,230 @@
#import "fmt.odin";
Handle :: i32;
File_Time :: u64;
Errno :: int;
// INVALID_HANDLE: Handle : -1;
O_RDONLY :: 0x00000;
O_WRONLY :: 0x00001;
O_RDWR :: 0x00002;
O_CREAT :: 0x00040;
O_EXCL :: 0x00080;
O_NOCTTY :: 0x00100;
O_TRUNC :: 0x00200;
O_NONBLOCK :: 0x00800;
O_APPEND :: 0x00400;
O_SYNC :: 0x01000;
O_ASYNC :: 0x02000;
O_CLOEXEC :: 0x80000;
// ERROR_NONE: Errno : 0;
// ERROR_FILE_NOT_FOUND: Errno : 2;
// ERROR_PATH_NOT_FOUND: Errno : 3;
// ERROR_ACCESS_DENIED: Errno : 5;
// ERROR_NO_MORE_FILES: Errno : 18;
// ERROR_HANDLE_EOF: Errno : 38;
// ERROR_NETNAME_DELETED: Errno : 64;
// ERROR_FILE_EXISTS: Errno : 80;
// ERROR_BROKEN_PIPE: Errno : 109;
// ERROR_BUFFER_OVERFLOW: Errno : 111;
// ERROR_INSUFFICIENT_BUFFER: Errno : 122;
// ERROR_MOD_NOT_FOUND: Errno : 126;
// ERROR_PROC_NOT_FOUND: Errno : 127;
// ERROR_DIR_NOT_EMPTY: Errno : 145;
// ERROR_ALREADY_EXISTS: Errno : 183;
// ERROR_ENVVAR_NOT_FOUND: Errno : 203;
// ERROR_MORE_DATA: Errno : 234;
// ERROR_OPERATION_ABORTED: Errno : 995;
// ERROR_IO_PENDING: Errno : 997;
// ERROR_NOT_FOUND: Errno : 1168;
// ERROR_PRIVILEGE_NOT_HELD: Errno : 1314;
// WSAEACCES: Errno : 10013;
// WSAECONNRESET: Errno : 10054;
// Windows reserves errors >= 1<<29 for application use
// ERROR_FILE_IS_PIPE: Errno : 1<<29 + 0;
#foreign_system_library libc "c";
unix_open :: proc(path: ^u8, mode: int, perm: u32) -> Handle #foreign libc "open";
unix_close :: proc(handle: Handle) #foreign libc "close";
unix_read :: proc(handle: Handle, buffer: rawptr, count: int) -> int #foreign libc "read";
unix_write :: proc(handle: Handle, buffer: rawptr, count: int) -> int #foreign libc "write";
unix_gettid :: proc() -> u64 #foreign libc "gettid";
unix_malloc :: proc(size: int) -> rawptr #foreign libc "malloc";
unix_free :: proc(ptr: rawptr) #foreign libc "free";
unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr #foreign libc "realloc";
unix_exit :: proc(status: int) #foreign libc "exit";
open :: proc(path: string, mode: int, perm: u32) -> (Handle, Errno) {
return unix_open(path.data, mode, perm), 0;
}
close :: proc(fd: Handle) {
unix_close(fd);
}
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
return unix_write(fd, data.data, data.count), 0;
}
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
return unix_read(fd, data.data, data.count), 0;
}
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
/*
using win32;
w: u32;
match whence {
case 0: w = FILE_BEGIN;
case 1: w = FILE_CURRENT;
case 2: w = FILE_END;
}
hi := cast(i32)(offset>>32);
lo := cast(i32)(offset);
ft := GetFileType(cast(HANDLE)fd);
if ft == FILE_TYPE_PIPE {
return 0, ERROR_FILE_IS_PIPE;
}
dw_ptr := SetFilePointer(cast(HANDLE)fd, lo, ^hi, w);
if dw_ptr == INVALID_SET_FILE_POINTER {
err := GetLastError();
return 0, cast(Errno)err;
}
return cast(i64)hi<<32 + cast(i64)dw_ptr, ERROR_NONE;
*/
return 0, 0;
}
// NOTE(bill): Uses startup to initialize it
stdin: Handle = 0; // get_std_handle(win32.STD_INPUT_HANDLE);
stdout: Handle = 1; // get_std_handle(win32.STD_OUTPUT_HANDLE);
stderr: Handle = 2; // get_std_handle(win32.STD_ERROR_HANDLE);
/*
get_std_handle :: proc(h: int) -> Handle {
fd := win32.GetStdHandle(cast(i32)h);
win32.SetHandleInformation(fd, win32.HANDLE_FLAG_INHERIT, 0);
return cast(Handle)fd;
}
last_write_time :: proc(fd: Handle) -> File_Time {
file_info: win32.BY_HANDLE_FILE_INFORMATION;
win32.GetFileInformationByHandle(cast(win32.HANDLE)fd, ^file_info);
lo := cast(File_Time)file_info.last_write_time.lo;
hi := cast(File_Time)file_info.last_write_time.hi;
return lo | hi << 32;
}
last_write_time_by_name :: proc(name: string) -> File_Time {
last_write_time: win32.FILETIME;
data: win32.FILE_ATTRIBUTE_DATA;
buf: [1024]byte;
assert(buf.count > name.count);
copy(buf[:], cast([]byte)name);
if win32.GetFileAttributesExA(^buf[0], win32.GetFileExInfoStandard, ^data) != 0 {
last_write_time = data.last_write_time;
}
l := cast(File_Time)last_write_time.lo;
h := cast(File_Time)last_write_time.hi;
return l | h << 32;
}
read_entire_file :: proc(name: string) -> ([]byte, bool) {
buf: [300]byte;
copy(buf[:], cast([]byte)name);
fd, err := open(name, O_RDONLY, 0);
if err != ERROR_NONE {
return nil, false;
}
defer close(fd);
length: i64;
file_size_ok := win32.GetFileSizeEx(cast(win32.HANDLE)fd, ^length) != 0;
if !file_size_ok {
return nil, false;
}
data := new_slice(u8, length);
if data.data == nil {
return nil, false;
}
single_read_length: i32;
total_read: i64;
for total_read < length {
remaining := length - total_read;
to_read: u32;
MAX :: 1<<32-1;
if remaining <= MAX {
to_read = cast(u32)remaining;
} else {
to_read = MAX;
}
win32.ReadFile(cast(win32.HANDLE)fd, ^data[total_read], to_read, ^single_read_length, nil);
if single_read_length <= 0 {
free(data);
return nil, false;
}
total_read += cast(i64)single_read_length;
}
return data, true;
}
*/
heap_alloc :: proc(size: int) -> rawptr {
assert(size > 0);
return unix_malloc(size);
}
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
return unix_realloc(ptr, new_size);
}
heap_free :: proc(ptr: rawptr) {
unix_free(ptr);
}
exit :: proc(code: int) {
unix_exit(code);
}
current_thread_id :: proc() -> int {
// return cast(int) unix_gettid();
return 0;
}
+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"; #import "atomic.odin";
Semaphore :: struct { Semaphore :: struct {
handle: win32.HANDLE, _handle: win32.HANDLE,
} }
Mutex :: struct { Mutex :: struct {
semaphore: Semaphore, _semaphore: Semaphore,
counter: i32, _counter: i32,
owner: i32, _owner: i32,
recursion: i32, _recursion: i32,
} }
current_thread_id :: proc() -> i32 { current_thread_id :: proc() -> i32 {
@@ -17,74 +17,74 @@ current_thread_id :: proc() -> i32 {
} }
semaphore_init :: proc(s: ^Semaphore) { 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) { semaphore_destroy :: proc(s: ^Semaphore) {
win32.CloseHandle(s.handle); win32.CloseHandle(s._handle);
} }
semaphore_post :: proc(s: ^Semaphore, count: int) { 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_release :: proc(s: ^Semaphore) #inline { semaphore_post(s, 1); }
semaphore_wait :: proc(s: ^Semaphore) { semaphore_wait :: proc(s: ^Semaphore) {
win32.WaitForSingleObject(s.handle, win32.INFINITE); win32.WaitForSingleObject(s._handle, win32.INFINITE);
} }
mutex_init :: proc(m: ^Mutex) { mutex_init :: proc(m: ^Mutex) {
atomic.store(^m.counter, 0); atomic.store(^m._counter, 0);
atomic.store(^m.owner, current_thread_id()); atomic.store(^m._owner, current_thread_id());
semaphore_init(^m.semaphore); semaphore_init(^m._semaphore);
m.recursion = 0; m._recursion = 0;
} }
mutex_destroy :: proc(m: ^Mutex) { mutex_destroy :: proc(m: ^Mutex) {
semaphore_destroy(^m.semaphore); semaphore_destroy(^m._semaphore);
} }
mutex_lock :: proc(m: ^Mutex) { mutex_lock :: proc(m: ^Mutex) {
thread_id := current_thread_id(); thread_id := current_thread_id();
if atomic.fetch_add(^m.counter, 1) > 0 { if atomic.fetch_add(^m._counter, 1) > 0 {
if thread_id != atomic.load(^m.owner) { if thread_id != atomic.load(^m._owner) {
semaphore_wait(^m.semaphore); semaphore_wait(^m._semaphore);
} }
} }
atomic.store(^m.owner, thread_id); atomic.store(^m._owner, thread_id);
m.recursion += 1; m._recursion++;
} }
mutex_try_lock :: proc(m: ^Mutex) -> bool { mutex_try_lock :: proc(m: ^Mutex) -> bool {
thread_id := current_thread_id(); thread_id := current_thread_id();
if atomic.load(^m.owner) == thread_id { if atomic.load(^m._owner) == thread_id {
atomic.fetch_add(^m.counter, 1); atomic.fetch_add(^m._counter, 1);
} else { } else {
expected: i32 = 0; expected: i32 = 0;
if atomic.load(^m.counter) != 0 { if atomic.load(^m._counter) != 0 {
return false; return false;
} }
if atomic.compare_exchange(^m.counter, expected, 1) == 0 { if atomic.compare_exchange(^m._counter, expected, 1) == 0 {
return false; return false;
} }
atomic.store(^m.owner, thread_id); atomic.store(^m._owner, thread_id);
} }
m.recursion += 1; m._recursion++;
return true; return true;
} }
mutex_unlock :: proc(m: ^Mutex) { mutex_unlock :: proc(m: ^Mutex) {
recursion: i32; recursion: i32;
thread_id := current_thread_id(); thread_id := current_thread_id();
assert(thread_id == atomic.load(^m.owner)); assert(thread_id == atomic.load(^m._owner));
m.recursion -= 1; m._recursion--;
recursion = m.recursion; recursion = m._recursion;
if recursion == 0 { 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 { 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";
+90 -31
View File
@@ -1,8 +1,7 @@
#foreign_system_library "kernel32.lib"; #foreign_system_library "kernel32.lib" when ODIN_OS == "windows";
#foreign_system_library "user32.lib"; #foreign_system_library "user32.lib" when ODIN_OS == "windows";
#foreign_system_library "gdi32.lib"; #foreign_system_library "gdi32.lib" when ODIN_OS == "windows";
#foreign_system_library "winmm.lib"; #foreign_system_library "winmm.lib" when ODIN_OS == "windows";
#foreign_system_library "opengl32.lib";
HANDLE :: rawptr; HANDLE :: rawptr;
HWND :: HANDLE; HWND :: HANDLE;
@@ -19,10 +18,10 @@ LPARAM :: int;
LRESULT :: int; LRESULT :: int;
ATOM :: i16; ATOM :: i16;
BOOL :: i32; BOOL :: i32;
WNDPROC :: type proc(HWND, u32, WPARAM, LPARAM) -> LRESULT #cc_c; WNDPROC :: #type proc(HWND, u32, WPARAM, LPARAM) -> LRESULT #cc_c;
INVALID_HANDLE_VALUE :: cast(HANDLE)(~cast(int)0); INVALID_HANDLE_VALUE :: cast(HANDLE)~cast(int)0;
FALSE: BOOL : 0; FALSE: BOOL : 0;
TRUE: BOOL : 1; TRUE: BOOL : 1;
@@ -41,11 +40,19 @@ WS_CAPTION :: 0x00C00000;
WS_VISIBLE :: 0x10000000; WS_VISIBLE :: 0x10000000;
WS_OVERLAPPEDWINDOW :: WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX; WS_OVERLAPPEDWINDOW :: WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX;
WM_DESTROY :: 0x0002; WM_DESTROY :: 0x0002;
WM_CLOSE :: 0x0010; WM_SIZE :: 0x0005;
WM_QUIT :: 0x0012; WM_CLOSE :: 0x0010;
WM_KEYDOWN :: 0x0100; WM_ACTIVATEAPP :: 0x001C;
WM_KEYUP :: 0x0101; 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; 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; AdjustWindowRect :: proc(rect: ^RECT, style: u32, menu: BOOL) -> BOOL #foreign user32;
GetActiveWindow :: proc() -> HWND #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 { GetQueryPerformanceFrequency :: proc() -> i64 {
r: i64; r: i64;
@@ -288,13 +298,75 @@ InterlockedExchangeAdd64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign ke
InterlockedAnd64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign kernel32; InterlockedAnd64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign kernel32;
InterlockedOr64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign kernel32; InterlockedOr64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign kernel32;
_mm_pause :: proc() #foreign kernel32; mm_pause :: proc() #foreign kernel32 "_mm_pause";
ReadWriteBarrier :: proc() #foreign kernel32; ReadWriteBarrier :: proc() #foreign kernel32;
WriteBarrier :: proc() #foreign kernel32; WriteBarrier :: proc() #foreign kernel32;
ReadBarrier :: proc() #foreign kernel32; ReadBarrier :: proc() #foreign kernel32;
HMONITOR :: HANDLE;
GWL_STYLE :: -16;
HWND_TOP :: cast(HWND)cast(uint)0;
MONITOR_DEFAULTTONULL :: 0x00000000;
MONITOR_DEFAULTTOPRIMARY :: 0x00000001;
MONITOR_DEFAULTTONEAREST :: 0x00000002;
SWP_FRAMECHANGED :: 0x0020;
SWP_NOOWNERZORDER :: 0x0200;
SWP_NOZORDER :: 0x0004;
SWP_NOSIZE :: 0x0001;
SWP_NOMOVE :: 0x0002;
MONITORINFO :: struct #ordered {
size: u32,
monitor: RECT,
work: RECT,
flags: u32,
}
WINDOWPLACEMENT :: struct #ordered {
length: u32,
flags: u32,
show_cmd: u32,
min_pos: POINT,
max_pos: POINT,
normal_pos: RECT,
}
GetMonitorInfoA :: proc(monitor: HMONITOR, mi: ^MONITORINFO) -> BOOL #foreign user32;
MonitorFromWindow :: proc(wnd: HWND, flags : u32) -> HMONITOR #foreign user32;
SetWindowPos :: proc(wnd: HWND, wndInsertAfter: HWND, x, y, width, height: i32, flags: u32) #foreign user32 "SetWindowPos";
GetWindowPlacement :: proc(wnd: HWND, wndpl: ^WINDOWPLACEMENT) -> BOOL #foreign user32;
SetWindowPlacement :: proc(wnd: HWND, wndpl: ^WINDOWPLACEMENT) -> BOOL #foreign user32;
GetWindowLongPtrA :: proc(wnd: HWND, index: i32) -> i64 #foreign user32;
SetWindowLongPtrA :: proc(wnd: HWND, index: i32, new: i64) -> i64 #foreign user32;
GetWindowText :: proc(wnd: HWND, str: ^byte, maxCount: i32) -> i32 #foreign user32;
HIWORD :: proc(wParam: WPARAM) -> u16 { return cast(u16)((cast(u32)wParam >> 16) & 0xffff); }
HIWORD :: proc(lParam: LPARAM) -> u16 { return cast(u16)((cast(u32)lParam >> 16) & 0xffff); }
LOWORD :: proc(wParam: WPARAM) -> u16 { return cast(u16)wParam; }
LOWORD :: proc(lParam: LPARAM) -> u16 { return cast(u16)lParam; }
BITMAPINFOHEADER :: struct #ordered { BITMAPINFOHEADER :: struct #ordered {
size: u32, size: u32,
width, height: i32, width, height: i32,
@@ -357,10 +429,6 @@ PFD_DEPTH_DONTCARE :: 0x20000000;
PFD_DOUBLEBUFFER_DONTCARE :: 0x40000000; PFD_DOUBLEBUFFER_DONTCARE :: 0x40000000;
PFD_STEREO_DONTCARE :: 0x80000000; PFD_STEREO_DONTCARE :: 0x80000000;
HGLRC :: HANDLE;
PROC :: type proc() #cc_c;
wglCreateContextAttribsARBType :: type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC;
PIXELFORMATDESCRIPTOR :: struct #ordered { PIXELFORMATDESCRIPTOR :: struct #ordered {
size, size,
@@ -393,23 +461,14 @@ PIXELFORMATDESCRIPTOR :: struct #ordered {
damage_mask: u32, damage_mask: u32,
} }
GetDC :: proc(h: HANDLE) -> HDC #foreign user32; GetDC :: proc(h: HWND) -> HDC #foreign user32;
SetPixelFormat :: proc(hdc: HDC, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR ) -> BOOL #foreign user32; SetPixelFormat :: proc(hdc: HDC, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR) -> BOOL #foreign gdi32;
ChoosePixelFormat :: proc(hdc: HDC, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign user32; ChoosePixelFormat :: proc(hdc: HDC, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign gdi32;
SwapBuffers :: proc(hdc: HDC) -> BOOL #foreign user32; SwapBuffers :: proc(hdc: HDC) -> BOOL #foreign gdi32;
ReleaseDC :: proc(wnd: HWND, hdc: HDC) -> i32 #foreign user32; 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; GetKeyState :: proc(v_key: i32) -> i16 #foreign user32;
+146
View File
@@ -0,0 +1,146 @@
is_signed :: proc(info: ^Type_Info) -> bool {
if is_integer(info) {
i := union_cast(^Type_Info.Integer)info;
return i.signed;
}
if is_float(info) {
return true;
}
return false;
}
is_integer :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Integer: return true;
}
return false;
}
is_float :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Float: return true;
}
return false;
}
is_any :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Any: return true;
}
return false;
}
is_string :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.String: return true;
}
return false;
}
is_boolean :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Boolean: return true;
}
return false;
}
is_pointer :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Pointer: return true;
}
return false;
}
is_procedure :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Procedure: return true;
}
return false;
}
is_array :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Array: return true;
}
return false;
}
is_dynamic_array :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Dynamic_Array: return true;
}
return false;
}
is_dynamic_map :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Map: return i.count == 0;
}
return false;
}
is_slice :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Slice: return true;
}
return false;
}
is_vector :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Vector: return true;
}
return false;
}
is_tuple :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Tuple: return true;
}
return false;
}
is_struct :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Struct: return true;
}
return false;
}
is_union :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Union: return true;
}
return false;
}
is_raw_union :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Raw_Union: return true;
}
return false;
}
is_enum :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Enum: return true;
}
return false;
}
+51 -7
View File
@@ -92,7 +92,8 @@ encode_rune :: proc(r: rune) -> ([4]byte, int) {
return buf, 4; return buf, 4;
} }
decode_rune :: proc(s: string) -> (rune, int) { decode_rune :: proc(s: string) -> (rune, int) #inline { return decode_rune(cast([]byte)s); }
decode_rune :: proc(s: []byte) -> (rune, int) {
n := s.count; n := s.count;
if n < 1 { if n < 1 {
return RUNE_ERROR, 0; 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 { valid_rune :: proc(r: rune) -> bool {
if r < 0 { if r < 0 {
return false; return false;
@@ -146,7 +187,7 @@ valid_string :: proc(s: string) -> bool {
for i := 0; i < n; { for i := 0; i < n; {
si := s[i]; si := s[i];
if si < RUNE_SELF { // ascii if si < RUNE_SELF { // ascii
i += 1; i++;
continue; continue;
} }
x := accept_sizes[si]; x := accept_sizes[si];
@@ -174,25 +215,28 @@ valid_string :: proc(s: string) -> bool {
return true; 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; count := 0;
n := s.count; n := s.count;
for i := 0; i < n; { for i := 0; i < n; {
defer count += 1; defer count++;
si := s[i]; si := s[i];
if si < RUNE_SELF { // ascii if si < RUNE_SELF { // ascii
i += 1; i++;
continue; continue;
} }
x := accept_sizes[si]; x := accept_sizes[si];
if x == 0xf1 { if x == 0xf1 {
i += 1; i++;
continue; continue;
} }
size := cast(int)(x & 7); size := cast(int)(x & 7);
if i+size > n { if i+size > n {
i += 1; i++;
continue; continue;
} }
ar := accept_ranges[x>>4]; ar := accept_ranges[x>>4];
+90 -24
View File
@@ -1,17 +1,27 @@
// This stores the information for the specify architecture of this build
typedef struct BuildContext { typedef struct BuildContext {
// Constants
String ODIN_OS; // target operating system String ODIN_OS; // target operating system
String ODIN_ARCH; // target architecture String ODIN_ARCH; // target architecture
String ODIN_ENDIAN; // target endian
String ODIN_VENDOR; // compiler vendor String ODIN_VENDOR; // compiler vendor
String ODIN_VERSION; // compiler version String ODIN_VERSION; // compiler version
String ODIN_ROOT; // Odin ROOT String ODIN_ROOT; // Odin ROOT
i64 word_size; // In bytes
i64 max_align; 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 llc_flags;
String link_flags; String link_flags;
bool is_dll; bool is_dll;
} BuildContext; } BuildContext;
gb_global BuildContext build_context = {0};
// TODO(bill): OS dependent versions for the BuildContext // TODO(bill): OS dependent versions for the BuildContext
// join_path // join_path
// is_dir // is_dir
@@ -22,6 +32,7 @@ typedef struct BuildContext {
String const WIN32_SEPARATOR_STRING = {cast(u8 *)"\\", 1}; String const WIN32_SEPARATOR_STRING = {cast(u8 *)"\\", 1};
String const NIX_SEPARATOR_STRING = {cast(u8 *)"/", 1}; String const NIX_SEPARATOR_STRING = {cast(u8 *)"/", 1};
#if defined(GB_SYSTEM_WINDOWS)
String odin_root_dir(void) { String odin_root_dir(void) {
String path = global_module_path; String path = global_module_path;
Array(wchar_t) path_buf; Array(wchar_t) path_buf;
@@ -71,6 +82,64 @@ String odin_root_dir(void) {
return path; return path;
} }
#elif defined(GB_SYSTEM_OSX)
#include <mach-o/dyld.h>
String odin_root_dir(void) {
String path = global_module_path;
Array(char) path_buf;
isize len, i;
gbTempArenaMemory tmp;
wchar_t *text;
if (global_module_path_set) {
return global_module_path;
}
array_init_count(&path_buf, heap_allocator(), 300);
len = 0;
for (;;) {
int sz = path_buf.count;
int res = _NSGetExecutablePath(&path_buf.e[0], &sz);
if(res == 0) {
len = sz;
break;
} else {
array_resize(&path_buf, sz + 1);
}
}
tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
text = gb_alloc_array(string_buffer_allocator, u8, len + 1);
gb_memmove(text, &path_buf.e[0], len);
path = make_string(text, len);
for (i = path.len-1; i >= 0; i--) {
u8 c = path.text[i];
if (c == '/' || c == '\\') {
break;
}
path.len--;
}
global_module_path = path;
global_module_path_set = true;
gb_temp_arena_memory_end(tmp);
// array_free(&path_buf);
return path;
}
#else
#error Implement system
#endif
#if defined(GB_SYSTEM_WINDOWS)
String path_to_fullpath(gbAllocator a, String s) { String path_to_fullpath(gbAllocator a, String s) {
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&string_buffer_arena); gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
String16 string16 = string_to_string16(string_buffer_allocator, s); String16 string16 = string_to_string16(string_buffer_allocator, s);
@@ -86,6 +155,17 @@ String path_to_fullpath(gbAllocator a, String s) {
gb_temp_arena_memory_end(tmp); gb_temp_arena_memory_end(tmp);
return result; return result;
} }
#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
String path_to_fullpath(gbAllocator a, String s) {
char* p = realpath(s.text, 0);
// GB_ASSERT(p && "file does not exist");
if(!p) return make_string_c("");
return make_string(p, strlen(p));
}
#else
#error Implement system
#endif
String get_fullpath_relative(gbAllocator a, String base_dir, String path) { String get_fullpath_relative(gbAllocator a, String base_dir, String path) {
@@ -123,37 +203,23 @@ String get_fullpath_core(gbAllocator a, String path) {
return res; return res;
} }
String get_filepath_extension(String path) {
isize dot = 0;
bool seen_slash = false;
for (isize i = path.len-1; i >= 0; i--) {
u8 c = path.text[i];
if (c == '/' || c == '\\') {
seen_slash = true;
}
if (c == '.') {
if (seen_slash) {
return str_lit("");
}
dot = i;
break;
}
}
return make_string(path.text, dot);
}
void init_build_context(BuildContext *bc) { void init_build_context(void) {
BuildContext *bc = &build_context;
bc->ODIN_VENDOR = str_lit("odin"); bc->ODIN_VENDOR = str_lit("odin");
bc->ODIN_VERSION = str_lit("0.0.5e"); bc->ODIN_VERSION = str_lit("0.1.1");
bc->ODIN_ROOT = odin_root_dir(); bc->ODIN_ROOT = odin_root_dir();
#if defined(GB_SYSTEM_WINDOWS) #if defined(GB_SYSTEM_WINDOWS)
bc->ODIN_OS = str_lit("windows"); bc->ODIN_OS = str_lit("windows");
bc->ODIN_ARCH = str_lit("amd64"); bc->ODIN_ARCH = str_lit("amd64");
bc->ODIN_ENDIAN = str_lit("little");
#elif defined(GB_SYSTEM_OSX)
bc->ODIN_OS = str_lit("osx");
bc->ODIN_ARCH = str_lit("amd64");
bc->ODIN_ENDIAN = str_lit("little");
#else #else
#error Implement system #error Implement system
#endif #endif
+4 -30
View File
@@ -61,24 +61,9 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArra
// NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be // NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
// an extra allocation // an extra allocation
Array(Operand) operands; ArrayOperand operands = {0};
array_init_reserve(&operands, c->tmp_allocator, 2*lhs_count); array_init_reserve(&operands, c->tmp_allocator, 2*lhs_count);
check_unpack_arguments(c, lhs_count, &operands, inits, true);
// TODO(bill): Allow for type hints from the entities
for_array(i, inits) {
AstNode *rhs = inits.e[i];
Operand o = {0};
check_multi_expr(c, &o, rhs);
if (o.type->kind != Type_Tuple) {
array_add(&operands, o);
} else {
TypeTuple *tuple = &o.type->Tuple;
for (isize j = 0; j < tuple->variable_count; j++) {
o.type = tuple->variables[j]->type;
array_add(&operands, o);
}
}
}
isize rhs_count = operands.count; isize rhs_count = operands.count;
for_array(i, operands) { for_array(i, operands) {
@@ -87,25 +72,14 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArra
} }
} }
isize max = gb_min(lhs_count, rhs_count); isize max = gb_min(lhs_count, rhs_count);
for (isize i = 0; i < max; i++) { for (isize i = 0; i < max; i++) {
check_init_variable(c, lhs[i], &operands.e[i], context_name); check_init_variable(c, lhs[i], &operands.e[i], context_name);
} }
if (rhs_count > 0 && lhs_count != rhs_count) { if (rhs_count > 0 && lhs_count != rhs_count) {
error(lhs[0]->token, "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count); error(lhs[0]->token, "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
} }
#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); gb_temp_arena_memory_end(tmp);
} }
@@ -315,7 +289,7 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
} }
if (is_foreign) { if (is_foreign) {
MapEntity *fp = &c->info.foreign_procs; MapEntity *fp = &c->info.foreigns;
String name = e->token.string; String name = e->token.string;
if (pd->foreign_name.len > 0) { if (pd->foreign_name.len > 0) {
name = pd->foreign_name; name = pd->foreign_name;
@@ -370,7 +344,7 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
} }
if (is_link_name || is_export) { if (is_link_name || is_export) {
MapEntity *fp = &c->info.foreign_procs; MapEntity *fp = &c->info.foreigns;
e->Procedure.link_name = name; e->Procedure.link_name = name;
+1188 -719
View File
File diff suppressed because it is too large Load Diff
+177 -88
View File
@@ -30,11 +30,6 @@ void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) {
case AstNode_ReturnStmt: case AstNode_ReturnStmt:
error_node(n, "Statements after this `return` are never executed"); error_node(n, "Statements after this `return` are never executed");
break; 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; return false;
} }
Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) { Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
if (op_a->mode == Addressing_Invalid || if (rhs->mode == Addressing_Invalid ||
(op_a->type == t_invalid && op_a->mode != Addressing_Overload)) { (rhs->type == t_invalid && rhs->mode != Addressing_Overload)) {
return NULL; return NULL;
} }
AstNode *node = unparen_expr(lhs); AstNode *node = unparen_expr(lhs_node);
// NOTE(bill): Ignore assignments to `_` // NOTE(bill): Ignore assignments to `_`
if (node->kind == AstNode_Ident && if (node->kind == AstNode_Ident &&
str_eq(node->Ident.string, str_lit("_"))) { str_eq(node->Ident.string, str_lit("_"))) {
add_entity_definition(&c->info, node, NULL); add_entity_definition(&c->info, node, NULL);
check_assignment(c, op_a, NULL, str_lit("assignment to `_` identifier")); check_assignment(c, rhs, NULL, str_lit("assignment to `_` identifier"));
if (op_a->mode == Addressing_Invalid) { if (rhs->mode == Addressing_Invalid) {
return NULL; return NULL;
} }
return op_a->type; return rhs->type;
} }
Entity *e = NULL; Entity *e = NULL;
bool used = false; bool used = false;
Operand op_b = {Addressing_Invalid}; Operand lhs = {Addressing_Invalid};
check_expr(c, &op_b, lhs); check_expr(c, &lhs, lhs_node);
if (op_b.mode == Addressing_Invalid || if (lhs.mode == Addressing_Invalid ||
op_b.type == t_invalid) { lhs.type == t_invalid) {
return NULL; return NULL;
} }
if (op_a->mode == Addressing_Overload) { if (rhs->mode == Addressing_Overload) {
isize overload_count = op_a->overload_count; isize overload_count = rhs->overload_count;
Entity **procs = op_a->overload_entities; Entity **procs = rhs->overload_entities;
GB_ASSERT(procs != NULL && overload_count > 0); GB_ASSERT(procs != NULL && overload_count > 0);
// NOTE(bill): These should be done // NOTE(bill): These should be done
@@ -227,19 +222,19 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
Operand x = {0}; Operand x = {0};
x.mode = Addressing_Value; x.mode = Addressing_Value;
x.type = t; 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]; e = procs[i];
add_entity_use(c, op_a->expr, e); add_entity_use(c, rhs->expr, e);
break; break;
} }
} }
if (e != NULL) { if (e != NULL) {
// HACK TODO(bill): Should the entities be freed as it's technically a leak // HACK TODO(bill): Should the entities be freed as it's technically a leak
op_a->mode = Addressing_Value; rhs->mode = Addressing_Value;
op_a->type = e->type; rhs->type = e->type;
op_a->overload_count = 0; rhs->overload_count = 0;
op_a->overload_entities = NULL; rhs->overload_entities = NULL;
} }
} else { } else {
if (node->kind == AstNode_Ident) { if (node->kind == AstNode_Ident) {
@@ -256,35 +251,60 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
e->flags |= EntityFlag_Used; e->flags |= EntityFlag_Used;
} }
switch (op_b.mode) { Type *assignment_type = lhs.type;
switch (lhs.mode) {
case Addressing_Invalid: case Addressing_Invalid:
return NULL; return NULL;
case Addressing_Variable: case Addressing_Variable:
break; 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: { default: {
if (op_b.expr->kind == AstNode_SelectorExpr) { if (lhs.expr->kind == AstNode_SelectorExpr) {
// NOTE(bill): Extra error checks // NOTE(bill): Extra error checks
Operand op_c = {Addressing_Invalid}; 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); check_expr(c, &op_c, se->expr);
if (op_c.mode == Addressing_MapIndex) {
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); gbString str = expr_to_string(lhs.expr);
if (e != NULL && e->kind == Entity_Variable && e->Variable.is_immutable) { if (lhs.mode == Addressing_Immutable) {
error_node(op_b.expr, "Cannot assign to an immutable: `%s`", str); error_node(lhs.expr, "Cannot assign to an immutable: `%s`", str);
} else { } else {
error_node(op_b.expr, "Cannot assign to `%s`", str); error_node(lhs.expr, "Cannot assign to `%s`", str);
} }
gb_string_free(str); gb_string_free(str);
} break; } break;
} }
check_assignment(c, op_a, op_b.type, str_lit("assignment")); check_assignment(c, rhs, assignment_type, str_lit("assignment"));
if (op_a->mode == Addressing_Invalid) { if (rhs->mode == Addressing_Invalid) {
return NULL; return NULL;
} }
return op_a->type; return rhs->type;
} }
bool check_valid_type_match_type(Type *type, bool *is_union_ptr, bool *is_any) { bool check_valid_type_match_type(Type *type, bool *is_union_ptr, bool *is_any) {
@@ -388,12 +408,6 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
if (operand.expr->kind == AstNode_CallExpr) { if (operand.expr->kind == AstNode_CallExpr) {
return; 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); gbString expr_str = expr_to_string(operand.expr);
error_node(node, "Expression is not used: `%s`", expr_str); error_node(node, "Expression is not used: `%s`", expr_str);
gb_string_free(expr_str); gb_string_free(expr_str);
@@ -407,44 +421,81 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
check_stmt(c, ts->stmt, flags); check_stmt(c, ts->stmt, flags);
case_end; 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); case_ast_node(as, AssignStmt, node);
switch (as->op.kind) { switch (as->op.kind) {
case Token_Eq: { case Token_Eq: {
// a, b, c = 1, 2, 3; // Multisided // 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"); error(as->op, "Missing lhs in assignment statement");
return; 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); 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 // NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
// an extra allocation // an extra allocation
Array(Operand) operands; ArrayOperand operands = {0};
array_init_reserve(&operands, c->tmp_allocator, 2 * as->lhs.count); 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) { isize rhs_count = operands.count;
AstNode *rhs = as->rhs.e[i]; for_array(i, operands) {
Operand o = {0}; if (operands.e[i].mode == Addressing_Invalid) {
check_multi_expr(c, &o, rhs); rhs_count--;
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 lhs_count = as->lhs.count; isize max = gb_min(lhs_count, rhs_count);
isize rhs_count = operands.count; for (isize i = 0; i < max; i++) {
check_assignment_variable(c, &operands.e[i], as->lhs.e[i]);
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);
} }
if (lhs_count != rhs_count) { if (lhs_count != rhs_count) {
error_node(as->lhs.e[0], "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count); error_node(as->lhs.e[0], "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
@@ -583,8 +634,9 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
if (fs->post != NULL) { if (fs->post != NULL) {
check_stmt(c, fs->post, 0); check_stmt(c, fs->post, 0);
if (fs->post->kind != AstNode_AssignStmt) { if (fs->post->kind != AstNode_AssignStmt &&
error_node(fs->post, "`for` statement post statement must be an assignment"); 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); check_stmt(c, fs->body, new_flags);
@@ -663,8 +715,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
TokenKind op = Token_Lt; TokenKind op = Token_Lt;
switch (ie->op.kind) { switch (ie->op.kind) {
case Token_HalfOpenRange: op = Token_Lt; break; case Token_Ellipsis: op = Token_Lt; break;
case Token_Ellipsis: op = Token_LtEq; break;
default: error(ie->op, "Invalid range operator"); break; default: error(ie->op, "Invalid range operator"); break;
} }
bool ok = compare_exact_values(Token_Lt, a, b); bool ok = compare_exact_values(Token_Lt, a, b);
@@ -693,15 +744,29 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
} }
break; break;
case Type_Array: case Type_Array:
// val = make_type_pointer(c->allocator, t->Array.elem);
val = t->Array.elem; val = t->Array.elem;
idx = t_int; idx = t_int;
break; break;
case Type_DynamicArray:
val = t->DynamicArray.elem;
idx = t_int;
break;
case Type_Slice: case Type_Slice:
// val = make_type_pointer(c->allocator, t->Slice.elem);
val = t->Slice.elem; val = t->Slice.elem;
idx = t_int; idx = t_int;
break; break;
case Type_Vector:
val = t->Vector.elem;
idx = t_int;
break;
case Type_Map:
val = t->Map.value;
idx = t->Map.key;
break;
} }
} }
@@ -714,7 +779,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
} }
} }
skip_expr: skip_expr:; // NOTE(zhiayang): again, declaring a variable immediately after a label... weird.
AstNode *lhs[2] = {rs->value, rs->index}; AstNode *lhs[2] = {rs->value, rs->index};
Type * rhs[2] = {val, idx}; Type * rhs[2] = {val, idx};
@@ -790,7 +855,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
Token token = {0}; Token token = {0};
token.pos = ast_node_token(ms->body).pos; token.pos = ast_node_token(ms->body).pos;
token.string = str_lit("true"); token.string = str_lit("true");
x.expr = make_ident(c->curr_ast_file, token); x.expr = ast_ident(c->curr_ast_file, token);
} }
// NOTE(bill): Check for multiple defaults // NOTE(bill): Check for multiple defaults
@@ -920,7 +985,25 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
bool is_union_ptr = false; bool is_union_ptr = false;
bool is_any = false; bool is_any = false;
check_expr(c, &x, ms->tag); if (ms->tag->kind != AstNode_AssignStmt) {
error_node(ms->tag, "Expected an `in` assignment for this type match statement");
break;
}
ast_node(as, AssignStmt, ms->tag);
Token as_token = ast_node_token(ms->tag);
if (as->lhs.count != 1) {
syntax_error(as_token, "Expected 1 name before `in`");
break;
}
if (as->rhs.count != 1) {
syntax_error(as_token, "Expected 1 expression after `in`");
break;
}
AstNode *lhs = as->lhs.e[0];
AstNode *rhs = as->rhs.e[0];
check_expr(c, &x, rhs);
check_assignment(c, &x, NULL, str_lit("type match expression")); check_assignment(c, &x, NULL, str_lit("type match expression"));
if (!check_valid_type_match_type(x.type, &is_union_ptr, &is_any)) { if (!check_valid_type_match_type(x.type, &is_union_ptr, &is_any)) {
gbString str = type_to_string(x.type); gbString str = type_to_string(x.type);
@@ -958,7 +1041,9 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
} }
} }
if (ms->var->kind != AstNode_Ident) {
if (lhs->kind != AstNode_Ident) {
error_node(rhs, "Expected an identifier, got `%.*s`", LIT(ast_node_strings[rhs->kind]));
break; break;
} }
@@ -987,8 +1072,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
if (is_union_ptr) { if (is_union_ptr) {
GB_ASSERT(is_type_union(bt)); GB_ASSERT(is_type_union(bt));
bool tag_type_found = false; bool tag_type_found = false;
for (isize i = 0; i < bt->Record.field_count; i++) { for (isize i = 0; i < bt->Record.variant_count; i++) {
Entity *f = bt->Record.fields[i]; Entity *f = bt->Record.variants[i];
if (are_types_identical(f->type, y.type)) { if (are_types_identical(f->type, y.type)) {
tag_type_found = true; tag_type_found = true;
break; break;
@@ -996,8 +1081,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
} }
if (!tag_type_found) { if (!tag_type_found) {
gbString type_str = type_to_string(y.type); gbString type_str = type_to_string(y.type);
error_node(y.expr, error_node(y.expr, "Unknown tag type, got `%s`", type_str);
"Unknown tag type, got `%s`", type_str);
gb_string_free(type_str); gb_string_free(type_str);
continue; continue;
} }
@@ -1025,19 +1109,27 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
} }
check_open_scope(c, stmt); check_open_scope(c, stmt);
if (case_type != NULL) { if (case_type == NULL) {
add_type_info_type(c, case_type); if (is_union_ptr) {
case_type = type_deref(x.type);
} else {
case_type = x.type;
}
}
add_type_info_type(c, case_type);
{
// NOTE(bill): Dummy type // NOTE(bill): Dummy type
Type *tt = case_type; Type *tt = case_type;
if (is_union_ptr) { if (is_union_ptr) {
tt = make_type_pointer(c->allocator, case_type); tt = make_type_pointer(c->allocator, case_type);
add_type_info_type(c, tt); add_type_info_type(c, tt);
} }
Entity *tag_var = make_entity_variable(c->allocator, c->context.scope, ms->var->Ident, tt, true); Entity *tag_var = make_entity_variable(c->allocator, c->context.scope, lhs->Ident, tt, true);
tag_var->flags |= EntityFlag_Used; tag_var->flags |= EntityFlag_Used;
add_entity(c, c->context.scope, ms->var, tag_var); add_entity(c, c->context.scope, lhs, tag_var);
add_entity_use(c, ms->var, tag_var); add_entity_use(c, lhs, tag_var);
} }
check_stmt_list(c, cc->stmts, mod_flags); check_stmt_list(c, cc->stmts, mod_flags);
check_close_scope(c); check_close_scope(c);
@@ -1113,8 +1205,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
case Entity_TypeName: { case Entity_TypeName: {
Type *t = base_type(e->type); Type *t = base_type(e->type);
if (is_type_union(t)) { if (is_type_union(t)) {
for (isize i = 0; i < t->Record.field_count; i++) { for (isize i = 0; i < t->Record.variant_count; i++) {
Entity *f = t->Record.fields[i]; Entity *f = t->Record.variants[i];
Entity *found = scope_insert_entity(c->context.scope, f); Entity *found = scope_insert_entity(c->context.scope, f);
if (found != NULL) { if (found != NULL) {
gbString expr_str = expr_to_string(expr); gbString expr_str = expr_to_string(expr);
@@ -1166,6 +1258,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
case Entity_Variable: { case Entity_Variable: {
Type *t = base_type(type_deref(e->type)); Type *t = base_type(type_deref(e->type));
if (is_type_struct(t) || is_type_raw_union(t)) { if (is_type_struct(t) || is_type_raw_union(t)) {
// TODO(bill): Make it work for unions too
Scope **found = map_scope_get(&c->info.scopes, hash_pointer(t->Record.node)); Scope **found = map_scope_get(&c->info.scopes, hash_pointer(t->Record.node));
GB_ASSERT(found != NULL); GB_ASSERT(found != NULL);
for_array(i, (*found)->elements.entries) { for_array(i, (*found)->elements.entries) {
@@ -1199,10 +1292,6 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
error(us->token, "`using` cannot be applied to a procedure"); error(us->token, "`using` cannot be applied to a procedure");
break; break;
case Entity_ImplicitValue:
error(us->token, "`using` cannot be applied to an implicit value");
break;
case Entity_Nil: case Entity_Nil:
error(us->token, "`using` cannot be applied to `nil`"); error(us->token, "`using` cannot be applied to `nil`");
break; break;
+323 -250
View File
@@ -1,110 +1,6 @@
#include "exact_value.c" #include "exact_value.c"
#include "entity.c" #include "entity.c"
typedef enum AddressingMode {
Addressing_Invalid,
Addressing_NoValue,
Addressing_Value, // R-value
Addressing_Variable, // L-value
Addressing_Constant,
Addressing_Type,
Addressing_Builtin,
Addressing_Overload,
Addressing_Count,
} AddressingMode;
#include "types.c"
#define MAP_TYPE Entity *
#define MAP_PROC map_entity_
#define MAP_NAME MapEntity
#include "map.c"
typedef struct Operand {
AddressingMode mode;
Type * type;
ExactValue value;
AstNode * expr;
BuiltinProcId builtin_id;
isize overload_count;
Entity ** overload_entities;
} Operand;
typedef struct TypeAndValue {
AddressingMode mode;
Type * type;
ExactValue value;
} TypeAndValue;
bool is_operand_value(Operand o) {
switch (o.mode) {
case Addressing_Value:
case Addressing_Variable:
case Addressing_Constant:
return true;
}
return false;
}
bool is_operand_nil(Operand o) {
return o.mode == Addressing_Value && o.type == t_untyped_nil;
}
typedef struct DeclInfo {
Scope *scope;
Entity **entities;
isize entity_count;
AstNode *type_expr;
AstNode *init_expr;
AstNode *proc_lit; // AstNode_ProcLit
MapBool deps; // Key: Entity *
} DeclInfo;
typedef struct ExprInfo {
bool is_lhs; // Debug info
AddressingMode mode;
Type * type; // Type_Basic
ExactValue value;
} ExprInfo;
ExprInfo make_expr_info(bool is_lhs, AddressingMode mode, Type *type, ExactValue value) {
ExprInfo ei = {is_lhs, mode, type, value};
return ei;
}
typedef struct ProcedureInfo {
AstFile * file;
Token token;
DeclInfo *decl;
Type * type; // Type_Procedure
AstNode * body; // AstNode_BlockStmt
u32 tags;
} ProcedureInfo;
typedef struct Scope {
Scope * parent;
Scope * prev, *next;
Scope * first_child;
Scope * last_child;
MapEntity elements; // Key: String
MapBool implicit; // Key: Entity *
Array(Scope *) shared;
Array(Scope *) imported;
bool is_proc;
bool is_global;
bool is_file;
bool is_init;
AstFile * file;
} Scope;
gb_global Scope *universal_scope = NULL;
typedef enum ExprKind { typedef enum ExprKind {
Expr_Expr, Expr_Expr,
Expr_Stmt, Expr_Stmt,
@@ -118,11 +14,23 @@ typedef enum StmtFlag {
Stmt_GiveAllowed = 1<<3, Stmt_GiveAllowed = 1<<3,
} StmtFlag; } StmtFlag;
typedef struct BuiltinProc {
String name;
isize arg_count;
bool variadic;
ExprKind kind;
} BuiltinProc;
typedef enum BuiltinProcId { typedef enum BuiltinProcId {
BuiltinProc_Invalid, BuiltinProc_Invalid,
BuiltinProc_new, BuiltinProc_new,
BuiltinProc_new_slice, BuiltinProc_new_slice,
BuiltinProc_free,
BuiltinProc_reserve,
BuiltinProc_clear,
BuiltinProc_append,
BuiltinProc_delete,
BuiltinProc_size_of, BuiltinProc_size_of,
BuiltinProc_size_of_val, BuiltinProc_size_of_val,
@@ -147,6 +55,7 @@ typedef enum BuiltinProcId {
// BuiltinProc_ptr_offset, // BuiltinProc_ptr_offset,
// BuiltinProc_ptr_sub, // BuiltinProc_ptr_sub,
BuiltinProc_slice_ptr, BuiltinProc_slice_ptr,
BuiltinProc_slice_to_bytes,
BuiltinProc_min, BuiltinProc_min,
BuiltinProc_max, BuiltinProc_max,
@@ -155,17 +64,17 @@ typedef enum BuiltinProcId {
BuiltinProc_Count, BuiltinProc_Count,
} BuiltinProcId; } BuiltinProcId;
typedef struct BuiltinProc {
String name;
isize arg_count;
bool variadic;
ExprKind kind;
} BuiltinProc;
gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = { gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
{STR_LIT(""), 0, false, Expr_Stmt}, {STR_LIT(""), 0, false, Expr_Stmt},
{STR_LIT("new"), 1, false, Expr_Expr}, {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"), 1, false, Expr_Expr},
{STR_LIT("size_of_val"), 1, false, Expr_Expr}, {STR_LIT("size_of_val"), 1, false, Expr_Expr},
@@ -190,6 +99,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
// {STR_LIT("ptr_offset"), 2, false, Expr_Expr}, // {STR_LIT("ptr_offset"), 2, false, Expr_Expr},
// {STR_LIT("ptr_sub"), 2, false, Expr_Expr}, // {STR_LIT("ptr_sub"), 2, false, Expr_Expr},
{STR_LIT("slice_ptr"), 2, false, Expr_Expr}, {STR_LIT("slice_ptr"), 2, false, Expr_Expr},
{STR_LIT("slice_to_bytes"), 1, false, Expr_Stmt},
{STR_LIT("min"), 2, false, Expr_Expr}, {STR_LIT("min"), 2, false, Expr_Expr},
{STR_LIT("max"), 2, false, Expr_Expr}, {STR_LIT("max"), 2, false, Expr_Expr},
@@ -197,20 +107,124 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
{STR_LIT("clamp"), 3, false, Expr_Expr}, {STR_LIT("clamp"), 3, false, Expr_Expr},
}; };
typedef enum ImplicitValueId {
ImplicitValue_Invalid,
ImplicitValue_context, #include "types.c"
ImplicitValue_Count, typedef enum AddressingMode {
} ImplicitValueId; Addressing_Invalid, // invalid addressing mode
typedef struct ImplicitValueInfo { Addressing_NoValue, // no value (void in C)
String name; Addressing_Value, // computed value (rvalue)
String backing_name; Addressing_Immutable, // immutable computed value (const rvalue)
Type * type; Addressing_Variable, // addressable variable (lvalue)
} ImplicitValueInfo; Addressing_Constant, // constant & type will be a of Type_Basic (stripping Type_Named)
// NOTE(bill): This is initialized later Addressing_Type, // type
gb_global ImplicitValueInfo implicit_value_infos[ImplicitValue_Count] = {0}; 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;
ExactValue value;
AstNode * expr;
BuiltinProcId builtin_id;
isize overload_count;
Entity ** overload_entities;
} Operand;
typedef struct TypeAndValue {
AddressingMode mode;
Type * type;
ExactValue value;
} TypeAndValue;
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;
}
bool is_operand_nil(Operand o) {
return o.mode == Addressing_Value && o.type == t_untyped_nil;
}
// DeclInfo is used to store information of certain declarations to allow for "any order" usage
typedef struct DeclInfo {
Scope *scope;
Entity **entities;
isize entity_count;
AstNode *type_expr;
AstNode *init_expr;
AstNode *proc_lit; // AstNode_ProcLit
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;
Type * type; // Type_Basic
ExactValue value;
} ExprInfo;
ExprInfo make_expr_info(bool is_lhs, AddressingMode mode, Type *type, ExactValue value) {
ExprInfo ei = {is_lhs, mode, type, value};
return ei;
}
#define MAP_TYPE Entity *
#define MAP_PROC map_entity_
#define MAP_NAME MapEntity
#include "map.c"
typedef struct Scope {
Scope * parent;
Scope * prev, *next;
Scope * first_child;
Scope * last_child;
MapEntity elements; // Key: String
MapBool implicit; // Key: Entity *
Array(Scope *) shared;
Array(Scope *) imported;
bool is_proc;
bool is_global;
bool is_file;
bool is_init;
bool has_been_imported; // This is only applicable to file scopes
AstFile * file;
} Scope;
gb_global Scope *universal_scope = NULL;
@@ -247,6 +261,7 @@ typedef struct DelayedDecl {
} DelayedDecl; } DelayedDecl;
typedef struct CheckerContext { typedef struct CheckerContext {
Scope * file_scope;
Scope * scope; Scope * scope;
DeclInfo * decl; DeclInfo * decl;
u32 stmt_state_flags; u32 stmt_state_flags;
@@ -255,7 +270,7 @@ typedef struct CheckerContext {
Type * type_hint; Type * type_hint;
} CheckerContext; } CheckerContext;
// NOTE(bill): Symbol tables // CheckerInfo stores all the symbol information for a type-checked program
typedef struct CheckerInfo { typedef struct CheckerInfo {
MapTypeAndValue types; // Key: AstNode * | Expression -> Type (and value) MapTypeAndValue types; // Key: AstNode * | Expression -> Type (and value)
MapEntity definitions; // Key: AstNode * | Identifier -> Entity MapEntity definitions; // Key: AstNode * | Identifier -> Entity
@@ -263,11 +278,10 @@ typedef struct CheckerInfo {
MapScope scopes; // Key: AstNode * | Node -> Scope MapScope scopes; // Key: AstNode * | Node -> Scope
MapExprInfo untyped; // Key: AstNode * | Expression -> ExprInfo MapExprInfo untyped; // Key: AstNode * | Expression -> ExprInfo
MapDeclInfo entities; // Key: Entity * MapDeclInfo entities; // Key: Entity *
MapEntity foreign_procs; // Key: String MapEntity foreigns; // Key: String
MapAstFile files; // Key: String (full path) MapAstFile files; // Key: String (full path)
MapIsize type_info_map; // Key: Type * MapIsize type_info_map; // Key: Type *
isize type_info_count; isize type_info_count;
Entity * implicit_values[ImplicitValue_Count];
} CheckerInfo; } CheckerInfo;
typedef struct Checker { typedef struct Checker {
@@ -275,13 +289,11 @@ typedef struct Checker {
CheckerInfo info; CheckerInfo info;
AstFile * curr_ast_file; AstFile * curr_ast_file;
BaseTypeSizes sizes;
Scope * global_scope; Scope * global_scope;
Array(ProcedureInfo) procs; // NOTE(bill): Procedures to check Array(ProcedureInfo) procs; // NOTE(bill): Procedures to check
Array(DelayedDecl) delayed_imports; Array(DelayedDecl) delayed_imports;
Array(DelayedDecl) delayed_foreign_libraries; Array(DelayedDecl) delayed_foreign_libraries;
gbArena arena; gbArena arena;
gbArena tmp_arena; gbArena tmp_arena;
gbAllocator allocator; gbAllocator allocator;
@@ -391,9 +403,7 @@ void check_open_scope(Checker *c, AstNode *node) {
node = unparen_expr(node); node = unparen_expr(node);
GB_ASSERT(node->kind == AstNode_Invalid || GB_ASSERT(node->kind == AstNode_Invalid ||
is_ast_node_stmt(node) || is_ast_node_stmt(node) ||
is_ast_node_type(node) || is_ast_node_type(node));
node->kind == AstNode_BlockExpr ||
node->kind == AstNode_IfExpr );
Scope *scope = make_scope(c->context.scope, c->allocator); Scope *scope = make_scope(c->context.scope, c->allocator);
add_scope(c, node, scope); add_scope(c, node, scope);
if (node->kind == AstNode_ProcType) { 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 // NOTE(bill): No need to free these
gbAllocator a = heap_allocator(); gbAllocator a = heap_allocator();
universal_scope = make_scope(NULL, a); universal_scope = make_scope(NULL, a);
@@ -616,6 +627,7 @@ void init_universal_scope(BuildContext *bc) {
// TODO(bill): Set through flags in the compiler // TODO(bill): Set through flags in the compiler
add_global_string_constant(a, str_lit("ODIN_OS"), bc->ODIN_OS); add_global_string_constant(a, str_lit("ODIN_OS"), bc->ODIN_OS);
add_global_string_constant(a, str_lit("ODIN_ARCH"), bc->ODIN_ARCH); add_global_string_constant(a, str_lit("ODIN_ARCH"), bc->ODIN_ARCH);
add_global_string_constant(a, str_lit("ODIN_ENDIAN"), bc->ODIN_ENDIAN);
add_global_string_constant(a, str_lit("ODIN_VENDOR"), bc->ODIN_VENDOR); add_global_string_constant(a, str_lit("ODIN_VENDOR"), bc->ODIN_VENDOR);
add_global_string_constant(a, str_lit("ODIN_VERSION"), bc->ODIN_VERSION); add_global_string_constant(a, str_lit("ODIN_VERSION"), bc->ODIN_VERSION);
add_global_string_constant(a, str_lit("ODIN_ROOT"), bc->ODIN_ROOT); add_global_string_constant(a, str_lit("ODIN_ROOT"), bc->ODIN_ROOT);
@@ -630,10 +642,12 @@ void init_universal_scope(BuildContext *bc) {
} }
t_u8_ptr = make_type_pointer(a, t_u8); t_u8_ptr = make_type_pointer(a, t_u8);
t_int_ptr = make_type_pointer(a, t_int); t_int_ptr = make_type_pointer(a, t_int);
t_i64_ptr = make_type_pointer(a, t_i64); t_i64_ptr = make_type_pointer(a, t_i64);
t_f64_ptr = make_type_pointer(a, t_f64); t_f64_ptr = make_type_pointer(a, t_f64);
t_byte_slice = make_type_slice(a, t_byte);
t_string_slice = make_type_slice(a, t_string);
} }
@@ -647,7 +661,7 @@ void init_checker_info(CheckerInfo *i) {
map_scope_init(&i->scopes, a); map_scope_init(&i->scopes, a);
map_decl_info_init(&i->entities, a); map_decl_info_init(&i->entities, a);
map_expr_info_init(&i->untyped, 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_isize_init(&i->type_info_map, a);
map_ast_file_init(&i->files, a); map_ast_file_init(&i->files, a);
i->type_info_count = 0; i->type_info_count = 0;
@@ -661,7 +675,7 @@ void destroy_checker_info(CheckerInfo *i) {
map_scope_destroy(&i->scopes); map_scope_destroy(&i->scopes);
map_decl_info_destroy(&i->entities); map_decl_info_destroy(&i->entities);
map_expr_info_destroy(&i->untyped); 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_isize_destroy(&i->type_info_map);
map_ast_file_destroy(&i->files); map_ast_file_destroy(&i->files);
} }
@@ -672,8 +686,6 @@ void init_checker(Checker *c, Parser *parser, BuildContext *bc) {
c->parser = parser; c->parser = parser;
init_checker_info(&c->info); 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->proc_stack, a);
array_init(&c->procs, a); array_init(&c->procs, a);
@@ -910,11 +922,6 @@ void add_type_info_type(Checker *c, Type *t) {
} }
} break; } break;
case Type_Maybe:
add_type_info_type(c, bt->Maybe.elem);
add_type_info_type(c, t_bool);
break;
case Type_Pointer: case Type_Pointer:
add_type_info_type(c, bt->Pointer.elem); add_type_info_type(c, bt->Pointer.elem);
break; break;
@@ -924,6 +931,12 @@ void add_type_info_type(Checker *c, Type *t) {
add_type_info_type(c, make_type_pointer(c->allocator, bt->Array.elem)); add_type_info_type(c, make_type_pointer(c->allocator, bt->Array.elem));
add_type_info_type(c, t_int); add_type_info_type(c, t_int);
break; break;
case Type_DynamicArray:
add_type_info_type(c, bt->DynamicArray.elem);
add_type_info_type(c, make_type_pointer(c->allocator, bt->DynamicArray.elem));
add_type_info_type(c, t_int);
add_type_info_type(c, t_allocator);
break;
case Type_Slice: case Type_Slice:
add_type_info_type(c, bt->Slice.elem); add_type_info_type(c, bt->Slice.elem);
add_type_info_type(c, make_type_pointer(c->allocator, bt->Slice.elem)); add_type_info_type(c, make_type_pointer(c->allocator, bt->Slice.elem));
@@ -941,6 +954,10 @@ void add_type_info_type(Checker *c, Type *t) {
break; break;
case TypeRecord_Union: case TypeRecord_Union:
add_type_info_type(c, t_int); 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 */ /* fallthrough */
default: default:
for (isize i = 0; i < bt->Record.field_count; i++) { for (isize i = 0; i < bt->Record.field_count; i++) {
@@ -951,6 +968,12 @@ void add_type_info_type(Checker *c, Type *t) {
} }
} break; } break;
case Type_Map: {
add_type_info_type(c, bt->Map.key);
add_type_info_type(c, bt->Map.value);
add_type_info_type(c, bt->Map.generated_struct_type);
} break;
case Type_Tuple: case Type_Tuple:
for (isize i = 0; i < bt->Tuple.variable_count; i++) { for (isize i = 0; i < bt->Tuple.variable_count; i++) {
Entity *var = bt->Tuple.variables[i]; Entity *var = bt->Tuple.variables[i];
@@ -1000,6 +1023,7 @@ void add_curr_ast_file(Checker *c, AstFile *file) {
c->curr_ast_file = file; c->curr_ast_file = file;
c->context.decl = file->decl_info; c->context.decl = file->decl_info;
c->context.scope = file->scope; c->context.scope = file->scope;
c->context.file_scope = file->scope;
} }
} }
@@ -1053,109 +1077,107 @@ MapEntity generate_minimum_dependency_map(CheckerInfo *info, Entity *start) {
} }
void add_implicit_value(Checker *c, ImplicitValueId id, String name, String backing_name, Type *type) { Entity *find_core_entity(Checker *c, String name) {
ImplicitValueInfo info = {name, backing_name, type}; Entity *e = current_scope_lookup_entity(c->global_scope, name);
Entity *value = make_entity_implicit_value(c->allocator, info.name, info.type, id); if (e == NULL) {
Entity *prev = scope_insert_entity(c->global_scope, value); compiler_error("Could not find type declaration for `%.*s`\n"
GB_ASSERT(prev == NULL); "Is `_preload.odin` missing from the `core` directory relative to odin.exe?", LIT(name));
implicit_value_infos[id] = info; // NOTE(bill): This will exit the program as it's cannot continue without it!
c->info.implicit_values[id] = value; }
return e;
} }
void init_preload(Checker *c) { void init_preload(Checker *c) {
if (c->done_preload) { if (c->done_preload) {
return; return;
} }
if (t_type_info == NULL) { if (t_type_info == NULL) {
Entity *type_info_entity = current_scope_lookup_entity(c->global_scope, str_lit("Type_Info")); Entity *type_info_entity = find_core_entity(c, str_lit("Type_Info"));
if (type_info_entity == NULL) {
compiler_error("Could not find type declaration for `Type_Info`\n"
"Is `runtime.odin` missing from the `core` directory relative to odin.exe?");
}
Entity *type_info_member_entity = current_scope_lookup_entity(c->global_scope, str_lit("Type_Info_Member"));
if (type_info_entity == NULL) {
compiler_error("Could not find type declaration for `Type_Info_Member`\n"
"Is `runtime.odin` missing from the `core` directory relative to odin.exe?");
}
Entity *type_info_enum_value_entity = current_scope_lookup_entity(c->global_scope, str_lit("Type_Info_Enum_Value"));
if (type_info_entity == NULL) {
compiler_error("Could not find type declaration for `Type_Info_Enum_Value`\n"
"Is `runtime.odin` missing from the `core` directory relative to odin.exe?");
}
t_type_info = type_info_entity->type; t_type_info = type_info_entity->type;
t_type_info_ptr = make_type_pointer(c->allocator, t_type_info); t_type_info_ptr = make_type_pointer(c->allocator, t_type_info);
GB_ASSERT(is_type_union(type_info_entity->type)); GB_ASSERT(is_type_union(type_info_entity->type));
TypeRecord *record = &base_type(type_info_entity->type)->Record; TypeRecord *record = &base_type(type_info_entity->type)->Record;
t_type_info_member = type_info_member_entity->type; t_type_info_record = find_core_entity(c, str_lit("Type_Info_Record"))->type;
t_type_info_member_ptr = make_type_pointer(c->allocator, t_type_info_member); 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 = type_info_enum_value_entity->type;
t_type_info_enum_value_ptr = make_type_pointer(c->allocator, t_type_info_enum_value); t_type_info_enum_value_ptr = make_type_pointer(c->allocator, t_type_info_enum_value);
if (record->field_count != 18) {
if (record->variant_count != 19) {
compiler_error("Invalid `Type_Info` layout"); compiler_error("Invalid `Type_Info` layout");
} }
t_type_info_named = record->fields[ 1]->type; t_type_info_named = record->variants[ 1]->type;
t_type_info_integer = record->fields[ 2]->type; t_type_info_integer = record->variants[ 2]->type;
t_type_info_float = record->fields[ 3]->type; t_type_info_float = record->variants[ 3]->type;
t_type_info_any = record->fields[ 4]->type; t_type_info_string = record->variants[ 4]->type;
t_type_info_string = record->fields[ 5]->type; t_type_info_boolean = record->variants[ 5]->type;
t_type_info_boolean = record->fields[ 6]->type; t_type_info_any = record->variants[ 6]->type;
t_type_info_pointer = record->fields[ 7]->type; t_type_info_pointer = record->variants[ 7]->type;
t_type_info_maybe = record->fields[ 8]->type; t_type_info_procedure = record->variants[ 8]->type;
t_type_info_procedure = record->fields[ 9]->type; t_type_info_array = record->variants[ 9]->type;
t_type_info_array = record->fields[10]->type; t_type_info_dynamic_array = record->variants[10]->type;
t_type_info_slice = record->fields[11]->type; t_type_info_slice = record->variants[11]->type;
t_type_info_vector = record->fields[12]->type; t_type_info_vector = record->variants[12]->type;
t_type_info_tuple = record->fields[13]->type; t_type_info_tuple = record->variants[13]->type;
t_type_info_struct = record->fields[14]->type; t_type_info_struct = record->variants[14]->type;
t_type_info_union = record->fields[15]->type; t_type_info_raw_union = record->variants[15]->type;
t_type_info_raw_union = record->fields[16]->type; t_type_info_union = record->variants[16]->type;
t_type_info_enum = record->fields[17]->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(heap_allocator(), t_type_info_named); t_type_info_named_ptr = make_type_pointer(c->allocator, t_type_info_named);
t_type_info_integer_ptr = make_type_pointer(heap_allocator(), t_type_info_integer); t_type_info_integer_ptr = make_type_pointer(c->allocator, t_type_info_integer);
t_type_info_float_ptr = make_type_pointer(heap_allocator(), t_type_info_float); t_type_info_float_ptr = make_type_pointer(c->allocator, t_type_info_float);
t_type_info_any_ptr = make_type_pointer(heap_allocator(), t_type_info_any); t_type_info_string_ptr = make_type_pointer(c->allocator, t_type_info_string);
t_type_info_string_ptr = make_type_pointer(heap_allocator(), t_type_info_string); t_type_info_boolean_ptr = make_type_pointer(c->allocator, t_type_info_boolean);
t_type_info_boolean_ptr = make_type_pointer(heap_allocator(), t_type_info_boolean); t_type_info_any_ptr = make_type_pointer(c->allocator, t_type_info_any);
t_type_info_pointer_ptr = make_type_pointer(heap_allocator(), t_type_info_pointer); t_type_info_pointer_ptr = make_type_pointer(c->allocator, t_type_info_pointer);
t_type_info_maybe_ptr = make_type_pointer(heap_allocator(), t_type_info_maybe); t_type_info_procedure_ptr = make_type_pointer(c->allocator, t_type_info_procedure);
t_type_info_procedure_ptr = make_type_pointer(heap_allocator(), t_type_info_procedure); t_type_info_array_ptr = make_type_pointer(c->allocator, t_type_info_array);
t_type_info_array_ptr = make_type_pointer(heap_allocator(), t_type_info_array); t_type_info_dynamic_array_ptr = make_type_pointer(c->allocator, t_type_info_dynamic_array);
t_type_info_slice_ptr = make_type_pointer(heap_allocator(), t_type_info_slice); t_type_info_slice_ptr = make_type_pointer(c->allocator, t_type_info_slice);
t_type_info_vector_ptr = make_type_pointer(heap_allocator(), t_type_info_vector); t_type_info_vector_ptr = make_type_pointer(c->allocator, t_type_info_vector);
t_type_info_tuple_ptr = make_type_pointer(heap_allocator(), t_type_info_tuple); t_type_info_tuple_ptr = make_type_pointer(c->allocator, t_type_info_tuple);
t_type_info_struct_ptr = make_type_pointer(heap_allocator(), t_type_info_struct); t_type_info_struct_ptr = make_type_pointer(c->allocator, t_type_info_struct);
t_type_info_union_ptr = make_type_pointer(heap_allocator(), t_type_info_union); t_type_info_raw_union_ptr = make_type_pointer(c->allocator, t_type_info_raw_union);
t_type_info_raw_union_ptr = make_type_pointer(heap_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(heap_allocator(), t_type_info_enum); 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);
} }
if (t_allocator == NULL) { if (t_allocator == NULL) {
Entity *e = current_scope_lookup_entity(c->global_scope, str_lit("Allocator")); Entity *e = find_core_entity(c, str_lit("Allocator"));
if (e == NULL) {
compiler_error("Could not find type declaration for `Allocator`\n"
"Is `runtime.odin` missing from the `core` directory relative to odin.exe?");
}
t_allocator = e->type; t_allocator = e->type;
t_allocator_ptr = make_type_pointer(c->allocator, t_allocator); t_allocator_ptr = make_type_pointer(c->allocator, t_allocator);
} }
if (t_context == NULL) { if (t_context == NULL) {
Entity *e = current_scope_lookup_entity(c->global_scope, str_lit("Context")); Entity *e = find_core_entity(c, str_lit("Context"));
if (e == NULL) { e_context = e;
compiler_error("Could not find type declaration for `Context`\n"
"Is `runtime.odin` missing from the `core` directory relative to odin.exe?");
}
t_context = e->type; t_context = e->type;
t_context_ptr = make_type_pointer(c->allocator, t_context); t_context_ptr = make_type_pointer(c->allocator, t_context);
} }
if (t_raw_dynamic_array == NULL) {
Entity *e = find_core_entity(c, str_lit("Raw_Dynamic_Array"));
t_raw_dynamic_array = e->type;
t_raw_dynamic_array = make_type_pointer(c->allocator, t_raw_dynamic_array);
}
if (t_map_key == NULL) {
Entity *e = find_core_entity(c, str_lit("__Map_Key"));
t_map_key = e->type;
}
if (t_map_header == NULL) {
Entity *e = find_core_entity(c, str_lit("__Map_Header"));
t_map_header = e->type;
}
c->done_preload = true; c->done_preload = true;
} }
@@ -1228,6 +1250,9 @@ void check_procedure_overloading(Checker *c, Entity *e) {
ProcTypeOverloadKind kind = are_proc_types_overload_safe(p->type, q->type); ProcTypeOverloadKind kind = are_proc_types_overload_safe(p->type, q->type);
switch (kind) { switch (kind) {
case ProcOverload_Identical: 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: case ProcOverload_CallingConvention:
error(p->token, "Overloaded procedure `%.*s` as the same type as another procedure in this scope", LIT(name)); error(p->token, "Overloaded procedure `%.*s` as the same type as another procedure in this scope", LIT(name));
is_invalid = true; is_invalid = true;
@@ -1376,8 +1401,14 @@ void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope)
di->entities = entities; di->entities = entities;
di->type_expr = vd->type; di->type_expr = vd->type;
di->init_expr = vd->values.e[0]; 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) { for_array(i, vd->names) {
AstNode *name = vd->names.e[i]; AstNode *name = vd->names.e[i];
AstNode *value = NULL; AstNode *value = NULL;
@@ -1389,8 +1420,9 @@ void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope)
continue; continue;
} }
Entity *e = make_entity_variable(c->allocator, c->context.scope, name->Ident, NULL, vd->flags & VarDeclFlag_immutable); 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; e->identifier = name;
if (vd->flags & VarDeclFlag_using) { if (vd->flags & VarDeclFlag_using) {
vd->flags &= ~VarDeclFlag_using; // NOTE(bill): This error will be only caught once vd->flags &= ~VarDeclFlag_using; // NOTE(bill): This error will be only caught once
error_node(name, "`using` is not allowed at the file scope"); error_node(name, "`using` is not allowed at the file scope");
@@ -1459,7 +1491,7 @@ void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope)
if (id->is_import) { if (id->is_import) {
error_node(decl, "#import declarations are only allowed in the file scope"); error_node(decl, "#import declarations are only allowed in the file scope");
} else { } else {
error_node(decl, "#include declarations are only allowed in the file scope"); error_node(decl, "#load declarations are only allowed in the file scope");
} }
// NOTE(bill): _Should_ be caught by the parser // NOTE(bill): _Should_ be caught by the parser
// TODO(bill): Better error handling if it isn't // TODO(bill): Better error handling if it isn't
@@ -1519,6 +1551,12 @@ void check_all_global_entities(Checker *c) {
} }
add_curr_ast_file(c, d->scope->file); add_curr_ast_file(c, d->scope->file);
if (!d->scope->has_been_imported) {
// NOTE(bill): All of these unchecked entities could mean a lot of unused allocations
// TODO(bill): Should this be worried about?
continue;
}
if (e->kind != Entity_Procedure && str_eq(e->token.string, str_lit("main"))) { if (e->kind != Entity_Procedure && str_eq(e->token.string, str_lit("main"))) {
if (e->scope->is_init) { if (e->scope->is_init) {
error(e->token, "`main` is reserved as the entry point procedure in the initial scope"); error(e->token, "`main` is reserved as the entry point procedure in the initial scope");
@@ -1552,6 +1590,30 @@ void check_all_global_entities(Checker *c) {
} }
bool is_string_an_identifier(String s) {
isize offset = 0;
if (s.len < 1) {
return false;
}
while (offset < s.len) {
bool ok = false;
Rune r = -1;
isize size = gb_utf8_decode(s.text+offset, s.len-offset, &r);
if (offset == 0) {
ok = rune_is_letter(r);
} else {
ok = rune_is_letter(r) || rune_is_digit(r);
}
if (!ok) {
return false;
}
offset += size;
}
return offset == s.len;
}
String path_to_entity_name(String name, String fullpath) { String path_to_entity_name(String name, String fullpath) {
if (name.len != 0) { if (name.len != 0) {
return name; return name;
@@ -1596,6 +1658,12 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
ast_node(id, ImportDecl, decl); ast_node(id, ImportDecl, decl);
Token token = id->relpath; Token token = id->relpath;
GB_ASSERT(parent_scope->is_file);
if (!parent_scope->has_been_imported) {
continue;
}
HashKey key = hash_string(id->fullpath); HashKey key = hash_string(id->fullpath);
Scope **found = map_scope_get(file_scopes, key); Scope **found = map_scope_get(file_scopes, key);
if (found == NULL) { if (found == NULL) {
@@ -1639,9 +1707,11 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
if (!previously_added) { if (!previously_added) {
array_add(&parent_scope->imported, scope); array_add(&parent_scope->imported, scope);
} else { } else {
warning(token, "Multiple #import of the same file within this scope"); warning(token, "Multiple import of the same file within this scope");
} }
scope->has_been_imported = true;
if (str_eq(id->import_name.string, str_lit("."))) { if (str_eq(id->import_name.string, str_lit("."))) {
// NOTE(bill): Add imported entities to this file's scope // NOTE(bill): Add imported entities to this file's scope
for_array(elem_index, scope->elements.entries) { for_array(elem_index, scope->elements.entries) {
@@ -1649,16 +1719,19 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
if (e->scope == parent_scope) { if (e->scope == parent_scope) {
continue; continue;
} }
switch (e->kind) { if (!is_entity_kind_exported(e->kind)) {
case Entity_ImportName: continue;
case Entity_LibraryName: }
break; if (id->is_import) {
default: { if (is_entity_exported(e)) {
bool ok = add_entity(c, parent_scope, NULL, e); // TODO(bill): Should these entities be imported but cause an error when used?
if (ok && id->is_import) { // `#import`ed entities don't get exported bool ok = add_entity(c, parent_scope, NULL, e);
map_bool_set(&parent_scope->implicit, hash_pointer(e), true); if (ok) {
map_bool_set(&parent_scope->implicit, hash_pointer(e), true);
}
} }
} break; } else {
add_entity(c, parent_scope, NULL, e);
} }
} }
} else { } else {
@@ -1671,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, Entity *e = make_entity_import_name(c->allocator, parent_scope, id->import_name, t_invalid,
id->fullpath, id->import_name.string, id->fullpath, id->import_name.string,
scope); scope);
add_entity(c, parent_scope, NULL, e); add_entity(c, parent_scope, NULL, e);
} }
} }
@@ -1698,6 +1773,20 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
file_str = import_file; file_str = import_file;
} }
if (fl->cond != NULL) {
Operand operand = {Addressing_Invalid};
check_expr(c, &operand, fl->cond);
if (operand.mode != Addressing_Constant || !is_type_boolean(operand.type)) {
error_node(fl->cond, "Non-constant boolean `when` condition");
continue;
}
if (operand.value.kind == ExactValue_Bool &&
!operand.value.value_bool) {
continue;
}
}
String library_name = path_to_entity_name(fl->library_name.string, file_str); String library_name = path_to_entity_name(fl->library_name.string, file_str);
if (str_eq(library_name, str_lit("_"))) { if (str_eq(library_name, str_lit("_"))) {
error(fl->token, "File name, %.*s, cannot be as a library name as it is not a valid identifier", LIT(fl->library_name.string)); error(fl->token, "File name, %.*s, cannot be as a library name as it is not a valid identifier", LIT(fl->library_name.string));
@@ -1732,6 +1821,10 @@ void check_parsed_files(Checker *c) {
array_add(&c->global_scope->shared, scope); array_add(&c->global_scope->shared, scope);
} }
if (scope->is_init || scope->is_global) {
scope->has_been_imported = true;
}
f->scope = scope; f->scope = scope;
f->decl_info = make_declaration_info(c->allocator, f->scope); f->decl_info = make_declaration_info(c->allocator, f->scope);
HashKey key = hash_string(f->tokenizer.fullpath); HashKey key = hash_string(f->tokenizer.fullpath);
@@ -1752,26 +1845,6 @@ void check_parsed_files(Checker *c) {
check_all_global_entities(c); check_all_global_entities(c);
init_preload(c); // NOTE(bill): This could be setup previously through the use of `type_info(_of_val)` init_preload(c); // NOTE(bill): This could be setup previously through the use of `type_info(_of_val)`
// NOTE(bill): Nothing in the global scope _should_ depend on this implicit value as implicit
// values are only useful within procedures
add_implicit_value(c, ImplicitValue_context, str_lit("context"), str_lit("__context"), t_context);
// Initialize implicit values with backing variables
// TODO(bill): Are implicit values "too implicit"?
for (isize i = 1; i < ImplicitValue_Count; i++) {
// NOTE(bill): 0th is invalid
Entity *e = c->info.implicit_values[i];
GB_ASSERT(e->kind == Entity_ImplicitValue);
ImplicitValueInfo *ivi = &implicit_value_infos[i];
Entity *backing = scope_lookup_entity(e->scope, ivi->backing_name);
// GB_ASSERT(backing != NULL);
if (backing == NULL) {
gb_exit(1);
}
e->ImplicitValue.backing = backing;
}
// Check procedure bodies // Check procedure bodies
// NOTE(bill): Nested procedures bodies will be added to this "queue" // NOTE(bill): Nested procedures bodies will be added to this "queue"
@@ -1836,7 +1909,7 @@ void check_parsed_files(Checker *c) {
if (e->kind == Entity_TypeName) { if (e->kind == Entity_TypeName) {
if (e->type != NULL) { if (e->type != NULL) {
// i64 size = type_size_of(c->sizes, c->allocator, e->type); // 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);
} }
} }
} }
+4
View File
@@ -6,6 +6,7 @@ gbAllocator heap_allocator(void) {
return gb_heap_allocator(); return gb_heap_allocator();
} }
#include "unicode.c"
#include "string.c" #include "string.c"
#include "array.c" #include "array.c"
@@ -130,6 +131,9 @@ i16 f32_to_f16(f32 value) {
// //
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
typedef Array(i32) Array_i32;
typedef Array(isize) Array_isize;
#define MAP_TYPE String #define MAP_TYPE String
#define MAP_PROC map_string_ #define MAP_PROC map_string_
+38 -21
View File
@@ -1,8 +1,8 @@
typedef struct Scope Scope; typedef struct Scope Scope;
typedef struct Checker Checker; typedef struct Checker Checker;
typedef struct Type Type; typedef struct Type Type;
typedef enum BuiltinProcId BuiltinProcId; // typedef enum BuiltinProcId BuiltinProcId;
typedef enum ImplicitValueId ImplicitValueId;
#define ENTITY_KINDS \ #define ENTITY_KINDS \
ENTITY_KIND(Invalid) \ ENTITY_KIND(Invalid) \
@@ -14,7 +14,6 @@ typedef enum ImplicitValueId ImplicitValueId;
ENTITY_KIND(ImportName) \ ENTITY_KIND(ImportName) \
ENTITY_KIND(LibraryName) \ ENTITY_KIND(LibraryName) \
ENTITY_KIND(Nil) \ ENTITY_KIND(Nil) \
ENTITY_KIND(ImplicitValue) \
ENTITY_KIND(Count) ENTITY_KIND(Count)
typedef enum EntityKind { typedef enum EntityKind {
@@ -38,14 +37,18 @@ typedef enum EntityFlag {
EntityFlag_VectorElem = 1<<5, EntityFlag_VectorElem = 1<<5,
EntityFlag_Ellipsis = 1<<6, EntityFlag_Ellipsis = 1<<6,
EntityFlag_NoAlias = 1<<7, EntityFlag_NoAlias = 1<<7,
EntityFlag_TypeField = 1<<8,
} EntityFlag; } EntityFlag;
// Zero value means the overloading process is not yet done
typedef enum OverloadKind { typedef enum OverloadKind {
Overload_No = -1, Overload_Unknown,
Overload_Unknown = 0, Overload_No,
Overload_Yes = +1, Overload_Yes,
} OverloadKind; } OverloadKind;
// An Entity is a named "thing" in the language
typedef struct Entity Entity; typedef struct Entity Entity;
struct Entity { struct Entity {
EntityKind kind; EntityKind kind;
@@ -79,7 +82,7 @@ struct Entity {
OverloadKind overload_kind; OverloadKind overload_kind;
} Procedure; } Procedure;
struct { struct {
BuiltinProcId id; i32 id;
} Builtin; } Builtin;
struct { struct {
String path; String path;
@@ -93,14 +96,36 @@ struct Entity {
bool used; bool used;
} LibraryName; } LibraryName;
i32 Nil; i32 Nil;
struct {
// TODO(bill): Should this be a user-level construct rather than compiler-level?
ImplicitValueId id;
Entity * backing;
} ImplicitValue;
}; };
}; };
gb_global Entity *e_context = NULL;
bool is_entity_kind_exported(EntityKind kind) {
switch (kind) {
case Entity_Builtin:
case Entity_ImportName:
case Entity_LibraryName:
case Entity_Nil:
return false;
}
return true;
}
bool is_entity_exported(Entity *e) {
// TODO(bill): Determine the actual exportation rules for imports of entities
GB_ASSERT(e != NULL);
if (!is_entity_kind_exported(e->kind)) {
return false;
}
String name = e->token.string;
if (name.len == 0) {
return false;
}
return name.text[0] != '_';
}
Entity *alloc_entity(gbAllocator a, EntityKind kind, Scope *scope, Token token, Type *type) { Entity *alloc_entity(gbAllocator a, EntityKind kind, Scope *scope, Token token, Type *type) {
Entity *entity = gb_alloc_item(a, Entity); Entity *entity = gb_alloc_item(a, Entity);
@@ -170,7 +195,7 @@ Entity *make_entity_procedure(gbAllocator a, Scope *scope, Token token, Type *si
return entity; return entity;
} }
Entity *make_entity_builtin(gbAllocator a, Scope *scope, Token token, Type *type, BuiltinProcId id) { Entity *make_entity_builtin(gbAllocator a, Scope *scope, Token token, Type *type, i32 id) {
Entity *entity = alloc_entity(a, Entity_Builtin, scope, token, type); Entity *entity = alloc_entity(a, Entity_Builtin, scope, token, type);
entity->Builtin.id = id; entity->Builtin.id = id;
return entity; return entity;
@@ -199,14 +224,6 @@ Entity *make_entity_nil(gbAllocator a, String name, Type *type) {
return entity; return entity;
} }
Entity *make_entity_implicit_value(gbAllocator a, String name, Type *type, ImplicitValueId id) {
Token token = make_token_ident(name);
Entity *entity = alloc_entity(a, Entity_ImplicitValue, NULL, token, type);
entity->ImplicitValue.id = id;
return entity;
}
Entity *make_entity_dummy_variable(gbAllocator a, Scope *scope, Token token) { Entity *make_entity_dummy_variable(gbAllocator a, Scope *scope, Token token) {
token.string = str_lit("_"); token.string = str_lit("_");
return make_entity_variable(a, scope, token, NULL, false); return make_entity_variable(a, scope, token, NULL, false);
+85 -18
View File
@@ -60,6 +60,19 @@ ExactValue make_exact_value_integer(i64 i) {
return result; return result;
} }
ExactValue make_exact_value_float(f64 f) {
ExactValue result = {ExactValue_Float};
result.value_float = f;
return result;
}
ExactValue make_exact_value_pointer(i64 ptr) {
ExactValue result = {ExactValue_Pointer};
result.value_pointer = ptr;
return result;
}
ExactValue make_exact_value_integer_from_string(String string) { ExactValue make_exact_value_integer_from_string(String string) {
// TODO(bill): Allow for numbers with underscores in them // TODO(bill): Allow for numbers with underscores in them
i32 base = 10; i32 base = 10;
@@ -106,23 +119,75 @@ ExactValue make_exact_value_integer_from_string(String string) {
ExactValue make_exact_value_float_from_string(String string) { ExactValue make_exact_value_float_from_string(String string) {
// TODO(bill): Allow for numbers with underscores in them isize i = 0;
ExactValue result = {ExactValue_Float}; u8 *str = string.text;
result.value_float = gb_str_to_f64(cast(char *)string.text, NULL); isize len = string.len;
return result;
f64 sign = 1.0;
if (str[i] == '-') {
sign = -1.0;
i++;
} else if (*str == '+') {
i++;
}
f64 value = 0.0;
for (; i < len; i++) {
Rune r = cast(Rune)str[i];
if (r == '_') {
continue;
}
if (!gb_char_is_digit(r)) {
break;
}
i64 v = r - '0';
value *= 10.0;
value += v;
}
if (str[i] == '.') {
f64 pow10 = 10.0;
i++;
for (; i < string.len; i++) {
Rune r = cast(Rune)str[i];
if (r == '_') {
continue;
}
if (!gb_char_is_digit(r)) {
break;
}
value += (r-'0')/pow10;
pow10 *= 10.0;
}
}
f64 frac = 0;
f64 scale = 1.0;
if ((str[i] == 'e') || (str[i] == 'E')) {
i++;
if (str[i] == '-') {
frac = 1;
i++;
} else if (str[i] == '+') {
i++;
}
u32 exp;
for (exp = 0; gb_char_is_digit(str[i]); i++) {
exp = exp * 10 + (str[i]-'0');
}
if (exp > 308) exp = 308;
while (exp >= 50) { scale *= 1e50; exp -= 50; }
while (exp >= 8) { scale *= 1e8; exp -= 8; }
while (exp > 0) { scale *= 10.0; exp -= 1; }
}
f64 result = sign * (frac ? (value / scale) : (value * scale));
return make_exact_value_float(result);
} }
ExactValue make_exact_value_float(f64 f) {
ExactValue result = {ExactValue_Float};
result.value_float = f;
return result;
}
ExactValue make_exact_value_pointer(i64 ptr) {
ExactValue result = {ExactValue_Pointer};
result.value_pointer = ptr;
return result;
}
ExactValue make_exact_value_from_basic_literal(Token token) { ExactValue make_exact_value_from_basic_literal(Token token) {
switch (token.kind) { switch (token.kind) {
@@ -209,8 +274,7 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
case ExactValue_Invalid: case ExactValue_Invalid:
return v; return v;
case ExactValue_Integer: case ExactValue_Integer:
i = v.value_integer; i = ~v.value_integer;
i = ~i;
break; break;
default: default:
goto failure; goto failure;
@@ -218,8 +282,10 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
// NOTE(bill): unsigned integers will be negative and will need to be // NOTE(bill): unsigned integers will be negative and will need to be
// limited to the types precision // limited to the types precision
if (precision > 0) // IMPORTANT NOTE(bill): Max precision is 64 bits as that's how integers are stored
if (0 < precision && precision < 64) {
i &= ~((~0ll)<<precision); i &= ~((~0ll)<<precision);
}
return make_exact_value_integer(i); return make_exact_value_integer(i);
} break; } break;
@@ -351,6 +417,7 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
} }
error: error:
; // MSVC accepts this??? apparently you cannot declare variables immediately after labels...
ExactValue error_value = {0}; ExactValue error_value = {0};
// gb_printf_err("Invalid binary operation: %s\n", token_kind_to_string(op)); // gb_printf_err("Invalid binary operation: %s\n", token_kind_to_string(op));
return error_value; return error_value;
+118 -23
View File
@@ -1,4 +1,4 @@
/* gb.h - v0.26d - Ginger Bill's C Helper Library - public domain /* gb.h - v0.27 - Ginger Bill's C Helper Library - public domain
- no warranty implied; use at your own risk - no warranty implied; use at your own risk
This is a single header file with a bunch of useful stuff This is a single header file with a bunch of useful stuff
@@ -58,6 +58,7 @@ TODOS
- More date & time functions - More date & time functions
VERSION HISTORY VERSION HISTORY
0.27 - OSX fixes and Linux gbAffinity
0.26d - Minor changes to how gbFile works 0.26d - Minor changes to how gbFile works
0.26c - gb_str_to_f* fix 0.26c - gb_str_to_f* fix
0.26b - Minor fixes 0.26b - Minor fixes
@@ -276,6 +277,8 @@ extern "C" {
#include <stdarg.h> #include <stdarg.h>
#include <stddef.h> #include <stddef.h>
#if defined(GB_SYSTEM_WINDOWS) #if defined(GB_SYSTEM_WINDOWS)
#if !defined(GB_NO_WINDOWS_H) #if !defined(GB_NO_WINDOWS_H)
#define NOMINMAX 1 #define NOMINMAX 1
@@ -296,6 +299,9 @@ extern "C" {
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <pthread.h> #include <pthread.h>
#ifndef _IOSC11_SOURCE
#define _IOSC11_SOURCE
#endif
#include <stdlib.h> // NOTE(bill): malloc on linux #include <stdlib.h> // NOTE(bill): malloc on linux
#include <sys/mman.h> #include <sys/mman.h>
#if !defined(GB_SYSTEM_OSX) #if !defined(GB_SYSTEM_OSX)
@@ -309,18 +315,18 @@ extern "C" {
#endif #endif
#if defined(GB_SYSTEM_OSX) #if defined(GB_SYSTEM_OSX)
#include <mach/mach.h> #include <mach/mach.h>
#include <mach/mach_init.h> #include <mach/mach_init.h>
#include <mach/mach_time.h> #include <mach/mach_time.h>
#include <mach/thread_act.h> #include <mach/thread_act.h>
#include <mach/thread_policy.h> #include <mach/thread_policy.h>
#include <sys/sysctl.h> #include <sys/sysctl.h>
#include <copyfile.h> #include <copyfile.h>
#include <mach/clock.h> #include <mach/clock.h>
#endif #endif
#if defined(GB_SYSTEM_UNIX) #if defined(GB_SYSTEM_UNIX)
#include <semaphore.h> #include <semaphore.h>
#endif #endif
@@ -699,7 +705,7 @@ extern "C++" {
#endif #endif
#ifndef gb_is_between #ifndef gb_is_between
#define gb_is_between(x, lower, upper) (((x) >= (lower)) && ((x) <= (upper))) #define gb_is_between(x, lower, upper) (((lower) <= (x)) && ((x) <= (upper)))
#endif #endif
#ifndef gb_abs #ifndef gb_abs
@@ -1003,7 +1009,12 @@ typedef struct gbAffinity {
} gbAffinity; } gbAffinity;
#elif defined(GB_SYSTEM_LINUX) #elif defined(GB_SYSTEM_LINUX)
#error TODO(bill): Implement gbAffinity for linux typedef struct gbAffinity {
b32 is_accurate;
isize core_count;
isize thread_count;
isize threads_per_core;
} gbAffinity;
#else #else
#error TODO(bill): Unknown system #error TODO(bill): Unknown system
#endif #endif
@@ -4819,18 +4830,15 @@ GB_ALLOCATOR_PROC(gb_heap_allocator_proc) {
#else #else
// TODO(bill): *nix version that's decent // TODO(bill): *nix version that's decent
case gbAllocation_Alloc: { case gbAllocation_Alloc: {
gbAllocationHeader *header; posix_memalign(&ptr, alignment, size);
isize total_size = size + alignment + gb_size_of(gbAllocationHeader);
ptr = malloc(total_size); if (flags & gbAllocatorFlag_ClearToZero) {
header = cast(gbAllocationHeader *)ptr;
ptr = gb_align_forward(header+1, alignment);
gb_allocation_header_fill(header, ptr, size);
if (flags & gbAllocatorFlag_ClearToZero)
gb_zero_size(ptr, size); gb_zero_size(ptr, size);
}
} break; } break;
case gbAllocation_Free: { case gbAllocation_Free: {
free(gb_allocation_header(old_memory)); free(old_memory);
} break; } break;
case gbAllocation_Resize: { case gbAllocation_Resize: {
@@ -4927,7 +4935,7 @@ isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) {
void gb_affinity_init(gbAffinity *a) { void gb_affinity_init(gbAffinity *a) {
usize count, count_size = gb_size_of(count); usize count, count_size = gb_size_of(count);
a->is_accurate = false; a->is_accurate = false;
a->thread_count = 1; a->thread_count = 1;
a->core_count = 1; a->core_count = 1;
a->threads_per_core = 1; a->threads_per_core = 1;
@@ -4977,7 +4985,83 @@ isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) {
} }
#elif defined(GB_SYSTEM_LINUX) #elif defined(GB_SYSTEM_LINUX)
#error TODO(bill): Implement gbAffinity for linux // IMPORTANT TODO(bill): This gbAffinity stuff for linux needs be improved a lot!
// NOTE(zangent): I have to read /proc/cpuinfo to get the number of threads per core.
#include <stdio.h>
void gb_affinity_init(gbAffinity *a) {
b32 accurate = true;
isize threads = 0;
a->thread_count = 1;
a->core_count = sysconf(_SC_NPROCESSORS_ONLN);
a->threads_per_core = 1;
if(a->core_count <= 0) {
a->core_count = 1;
accurate = false;
}
// Parsing /proc/cpuinfo to get the number of threads per core.
// NOTE(zangent): This calls the CPU's threads "cores", although the wording
// is kind of weird. This should be right, though.
if (fopen("/proc/cpuinfo", "r") != NULL) {
for (;;) {
// The 'temporary char'. Everything goes into this char,
// so that we can check against EOF at the end of this loop.
char c;
#define AF__CHECK(letter) ((c = getc(cpu_info)) == letter)
if (AF__CHECK('c') && AF__CHECK('p') && AF__CHECK('u') && AF__CHECK(' ') &&
AF__CHECK('c') && AF__CHECK('o') && AF__CHECK('r') && AF__CHECK('e') && AF__CHECK('s')) {
// We're on a CPU info line.
while (!AF__CHECK(EOF)) {
if (c == '\n') {
break;
} else if (c < '0' || '9' > c) {
continue;
}
threads = threads * 10 + (c - '0');
}
break;
} else {
while (!AF__CHECK('\n')) {
if (c==EOF) {
break;
}
}
}
if (c == EOF) {
break;
}
#undef AF__CHECK
}
}
if (threads == 0) {
threads = 1;
accurate = false;
}
a->threads_per_core = threads;
a->thread_count = a->threads_per_core * a->core_count;
a->is_accurate = accurate;
}
void gb_affinity_destroy(gbAffinity *a) {
gb_unused(a);
}
b32 gb_affinity_set(gbAffinity *a, isize core, isize thread_index) {
return true;
}
isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) {
GB_ASSERT(0 <= core && core < a->core_count);
return a->threads_per_core;
}
#else #else
#error TODO(bill): Unknown system #error TODO(bill): Unknown system
#endif #endif
@@ -7758,7 +7842,18 @@ char *gb_path_get_full_name(gbAllocator a, char const *path) {
return gb_alloc_str_len(a, buf, len+1); return gb_alloc_str_len(a, buf, len+1);
#else #else
// TODO(bill): Make work on *nix, etc. // TODO(bill): Make work on *nix, etc.
return gb_alloc_str_len(a, path, gb_strlen(path)); char* p = realpath(path, 0);
GB_ASSERT(p && "file does not exist");
isize len = gb_strlen(p);
// bill... gb_alloc_str_len refused to work for this...
char* ret = gb_alloc(a, sizeof(char) * len + 1);
gb_memmove(ret, p, len);
ret[len] = 0;
free(p);
return ret;
#endif #endif
} }
+1875 -985
View File
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -66,18 +66,18 @@ void ir_opt_add_operands(irValueArray *ops, irInstr *i) {
array_add(ops, i->Call.args[j]); array_add(ops, i->Call.args[j]);
} }
break; break;
case irInstr_VectorExtractElement: // case irInstr_VectorExtractElement:
array_add(ops, i->VectorExtractElement.vector); // array_add(ops, i->VectorExtractElement.vector);
array_add(ops, i->VectorExtractElement.index); // array_add(ops, i->VectorExtractElement.index);
break; // break;
case irInstr_VectorInsertElement: // case irInstr_VectorInsertElement:
array_add(ops, i->VectorInsertElement.vector); // array_add(ops, i->VectorInsertElement.vector);
array_add(ops, i->VectorInsertElement.elem); // array_add(ops, i->VectorInsertElement.elem);
array_add(ops, i->VectorInsertElement.index); // array_add(ops, i->VectorInsertElement.index);
break; // break;
case irInstr_VectorShuffle: // case irInstr_VectorShuffle:
array_add(ops, i->VectorShuffle.vector); // array_add(ops, i->VectorShuffle.vector);
break; // break;
case irInstr_StartupRuntime: case irInstr_StartupRuntime:
break; break;
case irInstr_BoundsCheck: case irInstr_BoundsCheck:
@@ -258,7 +258,7 @@ void ir_opt_blocks(irProcedure *proc) {
if (b == NULL) { if (b == NULL) {
continue; continue;
} }
GB_ASSERT(b->index == i); GB_ASSERT_MSG(b->index == i, "%d, %td", b->index, i);
if (ir_opt_block_fusion(proc, b)) { if (ir_opt_block_fusion(proc, b)) {
changed = true; changed = true;
@@ -467,7 +467,7 @@ void ir_opt_tree(irGen *s) {
} }
ir_opt_blocks(proc); ir_opt_blocks(proc);
#if 1 #if 0
ir_opt_build_referrers(proc); ir_opt_build_referrers(proc);
ir_opt_build_dom_tree(proc); ir_opt_build_dom_tree(proc);
+188 -112
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) { void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
BaseTypeSizes s = m->sizes; i64 word_bits = 8*build_context.word_size;
i64 word_bits = 8*s.word_size;
GB_ASSERT_NOT_NULL(t); GB_ASSERT_NOT_NULL(t);
t = default_type(t); t = default_type(t);
GB_ASSERT(is_type_typed(t)); GB_ASSERT(is_type_typed(t));
@@ -172,35 +171,48 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
ir_print_type(f, m, t->Pointer.elem); ir_print_type(f, m, t->Pointer.elem);
ir_fprintf(f, "*"); ir_fprintf(f, "*");
return; return;
case Type_Maybe:
ir_fprintf(f, "{");
ir_print_type(f, m, t->Maybe.elem);
ir_fprintf(f, ", ");
ir_print_type(f, m, t_bool);
ir_fprintf(f, "}");
return;
case Type_Array: case Type_Array:
ir_fprintf(f, "[%lld x ", t->Array.count); ir_fprintf(f, "[%lld x ", t->Array.count);
ir_print_type(f, m, t->Array.elem); ir_print_type(f, m, t->Array.elem);
ir_fprintf(f, "]"); ir_fprintf(f, "]");
return; return;
case Type_Vector: case Type_Vector: {
ir_fprintf(f, "<%lld x ", t->Vector.count); i64 align = type_align_of(heap_allocator(), t);
i64 count = t->Vector.count;
ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x ", align, count);
ir_print_type(f, m, t->Vector.elem);
ir_fprintf(f, "]}");
return;
}
/* ir_fprintf(f, "<%lld x ", t->Vector.count);
ir_print_type(f, m, t->Vector.elem); ir_print_type(f, m, t->Vector.elem);
ir_fprintf(f, ">"); ir_fprintf(f, ">");
return; return; */
case Type_Slice: case Type_Slice:
ir_fprintf(f, "{"); ir_fprintf(f, "{");
ir_print_type(f, m, t->Slice.elem); ir_print_type(f, m, t->Slice.elem);
ir_fprintf(f, "*, i%lld, i%lld}", word_bits, word_bits); ir_fprintf(f, "*, i%lld, i%lld}", word_bits, word_bits);
return; return;
case Type_DynamicArray:
ir_fprintf(f, "{");
ir_print_type(f, m, t->DynamicArray.elem);
ir_fprintf(f, "*, i%lld, i%lld,", word_bits, word_bits);
ir_print_type(f, m, t_allocator);
ir_fprintf(f, "}");
return;
case Type_Record: { case Type_Record: {
switch (t->Record.kind) { switch (t->Record.kind) {
case TypeRecord_Struct: case TypeRecord_Struct:
if (t->Record.struct_is_packed) { if (t->Record.is_packed) {
ir_fprintf(f, "<"); ir_fprintf(f, "<");
} }
ir_fprintf(f, "{"); ir_fprintf(f, "{");
if (t->Record.custom_align > 0) {
ir_fprintf(f, "[0 x <%lld x i8>]", t->Record.custom_align);
if (t->Record.field_count > 0) {
ir_fprintf(f, ", ");
}
}
for (isize i = 0; i < t->Record.field_count; i++) { for (isize i = 0; i < t->Record.field_count; i++) {
if (i > 0) { if (i > 0) {
ir_fprintf(f, ", "); ir_fprintf(f, ", ");
@@ -208,22 +220,22 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
ir_print_type(f, m, t->Record.fields[i]->type); ir_print_type(f, m, t->Record.fields[i]->type);
} }
ir_fprintf(f, "}"); ir_fprintf(f, "}");
if (t->Record.struct_is_packed) { if (t->Record.is_packed) {
ir_fprintf(f, ">"); ir_fprintf(f, ">");
} }
return; return;
case TypeRecord_Union: { case TypeRecord_Union: {
// NOTE(bill): The zero size array is used to fix the alignment used in a structure as // 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) // 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 size_of_union = type_size_of(heap_allocator(), t) - build_context.word_size;
i64 align_of_union = type_align_of(s, heap_allocator(), t); 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); ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8], i%lld}", align_of_union, size_of_union, word_bits);
} return; } return;
case TypeRecord_RawUnion: { case TypeRecord_RawUnion: {
// NOTE(bill): The zero size array is used to fix the alignment used in a structure as // 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) // 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 size_of_union = type_size_of(heap_allocator(), t);
i64 align_of_union = type_align_of(s, 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); ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8]}", align_of_union, size_of_union);
} return; } return;
case TypeRecord_Enum: case TypeRecord_Enum:
@@ -272,6 +284,11 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
} }
ir_fprintf(f, ")*"); ir_fprintf(f, ")*");
} return; } return;
case Type_Map: {
GB_ASSERT(t->Map.generated_struct_type != NULL);
ir_print_type(f, m, t->Map.generated_struct_type);
} break;
} }
} }
@@ -281,25 +298,11 @@ void ir_print_compound_element(irFileBuffer *f, irModule *m, ExactValue v, Type
ir_print_type(f, m, elem_type); ir_print_type(f, m, elem_type);
ir_fprintf(f, " "); ir_fprintf(f, " ");
if (v.kind != ExactValue_Invalid && is_type_maybe(elem_type)) {
Type *t = base_type(elem_type)->Maybe.elem;
ir_fprintf(f, "{");
ir_print_type(f, m, t);
ir_fprintf(f, " ");
}
if (v.kind == ExactValue_Invalid || base_type(elem_type) == t_any) { if (v.kind == ExactValue_Invalid || base_type(elem_type) == t_any) {
ir_fprintf(f, "zeroinitializer"); ir_fprintf(f, "zeroinitializer");
} else { } else {
ir_print_exact_value(f, m, v, elem_type); ir_print_exact_value(f, m, v, elem_type);
} }
if (v.kind != ExactValue_Invalid && is_type_maybe(elem_type)) {
ir_fprintf(f, ", ");
ir_print_type(f, m, t_bool);
ir_fprintf(f, " ");
ir_fprintf(f, "true}");
}
} }
void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *type) { void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *type) {
@@ -451,9 +454,14 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
break; break;
} }
ir_fprintf(f, "<"); i64 align = type_align_of(m->allocator, type);
i64 count = type->Vector.count;
Type *elem_type = type->Vector.elem; Type *elem_type = type->Vector.elem;
ir_fprintf(f, "{[0 x <%lld x i8>] zeroinitializer, [%lld x ", align, count);
ir_print_type(f, m, elem_type);
ir_fprintf(f, "][");
if (elem_count == 1 && type->Vector.count > 1) { if (elem_count == 1 && type->Vector.count > 1) {
TypeAndValue *tav = type_and_value_of_expression(m->info, cl->elems.e[0]); TypeAndValue *tav = type_and_value_of_expression(m->info, cl->elems.e[0]);
GB_ASSERT(tav != NULL); GB_ASSERT(tav != NULL);
@@ -475,7 +483,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
} }
} }
ir_fprintf(f, ">"); ir_fprintf(f, "]}");
} else if (is_type_struct(type)) { } else if (is_type_struct(type)) {
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&m->tmp_arena); gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&m->tmp_arena);
@@ -518,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, "<");
} }
ir_fprintf(f, "{"); ir_fprintf(f, "{");
@@ -535,7 +543,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
ir_fprintf(f, "}"); ir_fprintf(f, "}");
if (type->Record.struct_is_packed) { if (type->Record.is_packed) {
ir_fprintf(f, ">"); ir_fprintf(f, ">");
} }
@@ -608,8 +616,6 @@ void ir_print_value(irFileBuffer *f, irModule *m, irValue *value, Type *type_hin
ir_print_type(f, m, t_int); ir_print_type(f, m, t_int);
ir_fprintf(f, " 0, i32 0), "); ir_fprintf(f, " 0, i32 0), ");
ir_print_type(f, m, t_int); 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); ir_fprintf(f, " %lld}", cs->count);
} }
} break; } break;
@@ -658,6 +664,11 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_fprintf(f, "\t"); ir_fprintf(f, "\t");
switch (instr->kind) { 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: { case irInstr_StartupRuntime: {
ir_fprintf(f, "call void "); ir_fprintf(f, "call void ");
ir_print_encoded_global(f, str_lit(IR_STARTUP_RUNTIME_PROC_NAME), false); ir_print_encoded_global(f, str_lit(IR_STARTUP_RUNTIME_PROC_NAME), false);
@@ -672,7 +683,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
Type *type = instr->Local.entity->type; Type *type = instr->Local.entity->type;
ir_fprintf(f, "%%%d = alloca ", value->index); ir_fprintf(f, "%%%d = alloca ", value->index);
ir_print_type(f, m, type); 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; } break;
case irInstr_ZeroInit: { case irInstr_ZeroInit: {
@@ -705,7 +716,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_print_type(f, m, type); ir_print_type(f, m, type);
ir_fprintf(f, "* "); ir_fprintf(f, "* ");
ir_print_value(f, m, instr->Load.address, type); 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; } break;
case irInstr_ArrayElementPtr: { case irInstr_ArrayElementPtr: {
@@ -720,6 +731,10 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_fprintf(f, ", "); ir_fprintf(f, ", ");
ir_print_type(f, m, t_int); ir_print_type(f, m, t_int);
ir_fprintf(f, " 0, "); ir_fprintf(f, " 0, ");
if (is_type_vector(type_deref(et))) {
ir_print_type(f, m, t_i32);
ir_fprintf(f, " 1, ");
}
irValue *index =instr->ArrayElementPtr.elem_index; irValue *index =instr->ArrayElementPtr.elem_index;
Type *t = ir_type(index); Type *t = ir_type(index);
@@ -732,6 +747,13 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
case irInstr_StructElementPtr: { case irInstr_StructElementPtr: {
Type *et = ir_type(instr->StructElementPtr.address); Type *et = ir_type(instr->StructElementPtr.address);
ir_fprintf(f, "%%%d = getelementptr inbounds ", value->index); ir_fprintf(f, "%%%d = getelementptr inbounds ", value->index);
i32 index = instr->StructElementPtr.elem_index;
Type *st = base_type(type_deref(et));
if (is_type_struct(st)) {
if (st->Record.custom_align > 0) {
index += 1;
}
}
ir_print_type(f, m, type_deref(et)); ir_print_type(f, m, type_deref(et));
ir_fprintf(f, ", "); ir_fprintf(f, ", ");
@@ -742,7 +764,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_print_type(f, m, t_int); ir_print_type(f, m, t_int);
ir_fprintf(f, " 0, "); ir_fprintf(f, " 0, ");
ir_print_type(f, m, t_i32); ir_print_type(f, m, t_i32);
ir_fprintf(f, " %d", instr->StructElementPtr.elem_index); ir_fprintf(f, " %d", index);
ir_fprintf(f, "\n"); ir_fprintf(f, "\n");
} break; } break;
@@ -793,11 +815,19 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
case irInstr_StructExtractValue: { case irInstr_StructExtractValue: {
Type *et = ir_type(instr->StructExtractValue.address); Type *et = ir_type(instr->StructExtractValue.address);
ir_fprintf(f, "%%%d = extractvalue ", value->index); ir_fprintf(f, "%%%d = extractvalue ", value->index);
i32 index = instr->StructExtractValue.index;
Type *st = base_type(et);
if (is_type_struct(st)) {
if (st->Record.custom_align > 0) {
index += 1;
}
}
ir_print_type(f, m, et); ir_print_type(f, m, et);
ir_fprintf(f, " "); ir_fprintf(f, " ");
ir_print_value(f, m, instr->StructExtractValue.address, et); ir_print_value(f, m, instr->StructExtractValue.address, et);
ir_fprintf(f, ", %d\n", instr->StructExtractValue.index); ir_fprintf(f, ", %d\n", index);
} break; } break;
case irInstr_UnionTagPtr: { case irInstr_UnionTagPtr: {
@@ -814,6 +844,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_fprintf(f, " 0, "); ir_fprintf(f, " 0, ");
ir_print_type(f, m, t_i32); ir_print_type(f, m, t_i32);
ir_fprintf(f, " %d", 2); ir_fprintf(f, " %d", 2);
ir_fprintf(f, " ; UnionTagPtr");
ir_fprintf(f, "\n"); ir_fprintf(f, "\n");
} break; } break;
@@ -824,7 +855,9 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_print_type(f, m, et); ir_print_type(f, m, et);
ir_fprintf(f, " "); ir_fprintf(f, " ");
ir_print_value(f, m, instr->UnionTagValue.address, et); 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; } break;
case irInstr_Jump: {; case irInstr_Jump: {;
@@ -929,6 +962,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
irInstrBinaryOp *bo = &value->Instr.BinaryOp; irInstrBinaryOp *bo = &value->Instr.BinaryOp;
Type *type = base_type(ir_type(bo->left)); Type *type = base_type(ir_type(bo->left));
Type *elem_type = type; Type *elem_type = type;
GB_ASSERT(!is_type_vector(elem_type));
while (elem_type->kind == Type_Vector) { while (elem_type->kind == Type_Vector) {
elem_type = base_type(elem_type->Vector.elem); elem_type = base_type(elem_type->Vector.elem);
} }
@@ -1095,68 +1129,68 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_fprintf(f, "\n"); ir_fprintf(f, "\n");
} break; } break;
case irInstr_VectorExtractElement: { // case irInstr_VectorExtractElement: {
Type *vt = ir_type(instr->VectorExtractElement.vector); // Type *vt = ir_type(instr->VectorExtractElement.vector);
Type *it = ir_type(instr->VectorExtractElement.index); // Type *it = ir_type(instr->VectorExtractElement.index);
ir_fprintf(f, "%%%d = extractelement ", value->index); // ir_fprintf(f, "%%%d = extractelement ", value->index);
ir_print_type(f, m, vt); // ir_print_type(f, m, vt);
ir_fprintf(f, " "); // ir_fprintf(f, " ");
ir_print_value(f, m, instr->VectorExtractElement.vector, vt); // ir_print_value(f, m, instr->VectorExtractElement.vector, vt);
ir_fprintf(f, ", "); // ir_fprintf(f, ", ");
ir_print_type(f, m, it); // ir_print_type(f, m, it);
ir_fprintf(f, " "); // ir_fprintf(f, " ");
ir_print_value(f, m, instr->VectorExtractElement.index, it); // ir_print_value(f, m, instr->VectorExtractElement.index, it);
ir_fprintf(f, "\n"); // ir_fprintf(f, "\n");
} break; // } break;
case irInstr_VectorInsertElement: { // case irInstr_VectorInsertElement: {
irInstrVectorInsertElement *ie = &instr->VectorInsertElement; // irInstrVectorInsertElement *ie = &instr->VectorInsertElement;
Type *vt = ir_type(ie->vector); // Type *vt = ir_type(ie->vector);
ir_fprintf(f, "%%%d = insertelement ", value->index); // ir_fprintf(f, "%%%d = insertelement ", value->index);
ir_print_type(f, m, vt); // ir_print_type(f, m, vt);
ir_fprintf(f, " "); // ir_fprintf(f, " ");
ir_print_value(f, m, ie->vector, vt); // ir_print_value(f, m, ie->vector, vt);
ir_fprintf(f, ", "); // ir_fprintf(f, ", ");
ir_print_type(f, m, ir_type(ie->elem)); // ir_print_type(f, m, ir_type(ie->elem));
ir_fprintf(f, " "); // ir_fprintf(f, " ");
ir_print_value(f, m, ie->elem, ir_type(ie->elem)); // ir_print_value(f, m, ie->elem, ir_type(ie->elem));
ir_fprintf(f, ", "); // ir_fprintf(f, ", ");
ir_print_type(f, m, ir_type(ie->index)); // ir_print_type(f, m, ir_type(ie->index));
ir_fprintf(f, " "); // ir_fprintf(f, " ");
ir_print_value(f, m, ie->index, ir_type(ie->index)); // ir_print_value(f, m, ie->index, ir_type(ie->index));
ir_fprintf(f, "\n"); // ir_fprintf(f, "\n");
} break; // } break;
case irInstr_VectorShuffle: { // case irInstr_VectorShuffle: {
irInstrVectorShuffle *sv = &instr->VectorShuffle; // irInstrVectorShuffle *sv = &instr->VectorShuffle;
Type *vt = ir_type(sv->vector); // Type *vt = ir_type(sv->vector);
ir_fprintf(f, "%%%d = shufflevector ", value->index); // ir_fprintf(f, "%%%d = shufflevector ", value->index);
ir_print_type(f, m, vt); // ir_print_type(f, m, vt);
ir_fprintf(f, " "); // ir_fprintf(f, " ");
ir_print_value(f, m, sv->vector, vt); // ir_print_value(f, m, sv->vector, vt);
ir_fprintf(f, ", "); // ir_fprintf(f, ", ");
ir_print_type(f, m, vt); // ir_print_type(f, m, vt);
ir_fprintf(f, " "); // ir_fprintf(f, " ");
ir_print_value(f, m, sv->vector, vt); // ir_print_value(f, m, sv->vector, vt);
ir_fprintf(f, ", "); // ir_fprintf(f, ", ");
ir_fprintf(f, "<%td x i32> <", sv->index_count); // ir_fprintf(f, "<%td x i32> <", sv->index_count);
for (isize i = 0; i < sv->index_count; i++) { // for (isize i = 0; i < sv->index_count; i++) {
if (i > 0) { // if (i > 0) {
ir_fprintf(f, ", "); // ir_fprintf(f, ", ");
} // }
ir_fprintf(f, "i32 %d", sv->indices[i]); // ir_fprintf(f, "i32 %d", sv->indices[i]);
} // }
ir_fprintf(f, ">"); // ir_fprintf(f, ">");
ir_fprintf(f, "\n"); // ir_fprintf(f, "\n");
} break; // } break;
case irInstr_BoundsCheck: { case irInstr_BoundsCheck: {
irInstrBoundsCheck *bc = &instr->BoundsCheck; irInstrBoundsCheck *bc = &instr->BoundsCheck;
@@ -1220,13 +1254,37 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_fprintf(f, " "); ir_fprintf(f, " ");
ir_print_value(f, m, bc->high, t_int); 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"); ir_fprintf(f, ")\n");
} break; } 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: { ir_fprintf(f, "\n"); */
GB_PANIC("<unknown instr> %d\n", instr->kind);
ir_fprintf(f, "; <unknown instr> %d\n", instr->kind);
} break; } break;
} }
} }
@@ -1241,7 +1299,7 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
} else { } else {
ir_fprintf(f, "\n"); ir_fprintf(f, "\n");
ir_fprintf(f, "define "); 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|ProcTag_dll_export)) {
if (proc->tags & (ProcTag_export)) { if (proc->tags & (ProcTag_export)) {
ir_fprintf(f, "dllexport "); ir_fprintf(f, "dllexport ");
@@ -1295,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) { if (proc->body != NULL) {
irDebugInfo *di = *map_ir_debug_info_get(&proc->module->debug_info, hash_pointer(proc->entity)); irDebugInfo **di_ = map_ir_debug_info_get(&proc->module->debug_info, hash_pointer(proc->entity));
GB_ASSERT(di->kind == irDebugInfo_Proc); if (di_ != NULL) {
ir_fprintf(f, "!dbg !%d ", di->id); irDebugInfo *di = *di_;
GB_ASSERT(di->kind == irDebugInfo_Proc);
// ir_fprintf(f, "!dbg !%d ", di->id);
}
} }
} }
@@ -1365,6 +1426,8 @@ void print_llvm_ir(irGen *ir) {
ir_print_type(f, m, t_rawptr); ir_print_type(f, m, t_rawptr);
ir_fprintf(f, "} ; Basic_any\n"); 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) { for_array(member_index, m->members.entries) {
MapIrValueEntry *entry = &m->members.entries.e[member_index]; MapIrValueEntry *entry = &m->members.entries.e[member_index];
@@ -1417,6 +1480,9 @@ void print_llvm_ir(irGen *ir) {
} }
ir_print_encoded_global(f, g->entity->token.string, in_global_scope); ir_print_encoded_global(f, g->entity->token.string, in_global_scope);
ir_fprintf(f, " = "); ir_fprintf(f, " = ");
if (g->is_foreign) {
ir_fprintf(f, "external ");
}
if (g->is_thread_local) { if (g->is_thread_local) {
ir_fprintf(f, "thread_local "); ir_fprintf(f, "thread_local ");
} }
@@ -1436,19 +1502,30 @@ void print_llvm_ir(irGen *ir) {
ir_print_type(f, m, g->entity->type); ir_print_type(f, m, g->entity->type);
ir_fprintf(f, " "); ir_fprintf(f, " ");
if (g->value != NULL) { if (!g->is_foreign) {
ir_print_value(f, m, g->value, g->entity->type); if (g->value != NULL) {
} else { ir_print_value(f, m, g->value, g->entity->type);
ir_fprintf(f, "zeroinitializer"); } else {
ir_fprintf(f, "zeroinitializer");
}
} }
ir_fprintf(f, "\n"); ir_fprintf(f, "\n");
} }
#if 0 #if 0
if (m->generate_debug_info) { // if (m->generate_debug_info) {
{
ir_fprintf(f, "\n"); ir_fprintf(f, "\n");
i32 diec = m->debug_info.entries.count;
ir_fprintf(f, "!llvm.dbg.cu = !{!0}\n"); 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) { for_array(di_index, m->debug_info.entries) {
MapIrDebugInfoEntry *entry = &m->debug_info.entries.e[di_index]; MapIrDebugInfoEntry *entry = &m->debug_info.entries.e[di_index];
@@ -1457,19 +1534,18 @@ void print_llvm_ir(irGen *ir) {
switch (di->kind) { switch (di->kind) {
case irDebugInfo_CompileUnit: { case irDebugInfo_CompileUnit: {
auto *cu = &di->CompileUnit; irDebugInfo *file = *map_ir_debug_info_get(&m->debug_info, hash_pointer(di->CompileUnit.file));
irDebugInfo *file = *map_ir_debug_info_get(&m->debug_info, hash_pointer(cu->file));
ir_fprintf(f, ir_fprintf(f,
"distinct !DICompileUnit(" "distinct !DICompileUnit("
"language: DW_LANG_Go, " // Is this good enough? "language: DW_LANG_Go, " // Is this good enough?
"file: !%d, " "file: !%d, "
"producer: \"%.*s\", " "producer: \"clang version 3.9.0 (branches/release_39)\", "
"flags: \"\", " "flags: \"\", "
"runtimeVersion: 0, " "runtimeVersion: 0, "
"isOptimized: false, " "isOptimized: false, "
"emissionKind: FullDebug" "emissionKind: FullDebug"
")", ")",
file->id, LIT(cu->producer)); file->id);
} break; } break;
case irDebugInfo_File: case irDebugInfo_File:
+68 -18
View File
@@ -2,10 +2,10 @@
extern "C" { extern "C" {
#endif #endif
#include "common.c" #include "common.c"
#include "timings.c" #include "timings.c"
#include "unicode.c" #include "build_settings.c"
#include "build.c"
#include "tokenizer.c" #include "tokenizer.c"
#include "parser.c" #include "parser.c"
// #include "printer.c" // #include "printer.c"
@@ -16,8 +16,9 @@ extern "C" {
#include "ir_print.c" #include "ir_print.c"
// #include "vm.c" // #include "vm.c"
#if defined(GB_SYSTEM_WINDOWS)
// NOTE(bill): `name` is used in debugging and profiling modes // NOTE(bill): `name` is used in debugging and profiling modes
i32 win32_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) { i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
STARTUPINFOW start_info = {gb_size_of(STARTUPINFOW)}; STARTUPINFOW start_info = {gb_size_of(STARTUPINFOW)};
PROCESS_INFORMATION pi = {0}; PROCESS_INFORMATION pi = {0};
char cmd_line[4096] = {0}; char cmd_line[4096] = {0};
@@ -59,6 +60,54 @@ i32 win32_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
gb_temp_arena_memory_end(tmp); gb_temp_arena_memory_end(tmp);
return exit_code; return exit_code;
} }
#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
char cmd_line[4096] = {0};
isize cmd_len;
va_list va;
String cmd;
i32 exit_code = 0;
va_start(va, fmt);
cmd_len = gb_snprintf_va(cmd_line, gb_size_of(cmd_line), fmt, va);
va_end(va);
cmd = make_string(cast(u8 *)&cmd_line, cmd_len-1);
exit_code = system(&cmd_line[0]);
// pid_t pid = fork();
// int status = 0;
// if(pid == 0) {
// // in child, pid == 0.
// int ret = execvp(cmd.text, (char* const*) cmd.text);
// if(ret == -1) {
// gb_printf_err("Failed to execute command:\n\t%s\n", cmd_line);
// // we're in the child, so returning won't do us any good -- just quit.
// exit(-1);
// }
// // unreachable
// abort();
// } else {
// // wait for child to finish, then we can continue cleanup
// int s = 0;
// waitpid(pid, &s, 0);
// status = WEXITSTATUS(s);
// }
// exit_code = status;
}
#endif
void print_usage_line(i32 indent, char *fmt, ...) { void print_usage_line(i32 indent, char *fmt, ...) {
while (indent --> 0) { while (indent --> 0) {
@@ -97,10 +146,9 @@ int main(int argc, char **argv) {
#if 1 #if 1
BuildContext build_context = {0}; init_build_context();
init_build_context(&build_context);
init_universal_scope(&build_context); init_universal_scope();
char *init_filename = NULL; char *init_filename = NULL;
bool run_output = false; bool run_output = false;
@@ -169,12 +217,12 @@ int main(int argc, char **argv) {
return 1; return 1;
} }
ssa_generate(&checker.info, &build_context); if (!ssa_generate(&checker.info)) {
#endif return 1;
#if 1 }
#else
irGen ir_gen = {0}; irGen ir_gen = {0};
if (!ir_gen_init(&ir_gen, &checker, &build_context)) { if (!ir_gen_init(&ir_gen, &checker)) {
return 1; return 1;
} }
// defer (ssa_gen_destroy(&ir_gen)); // defer (ssa_gen_destroy(&ir_gen));
@@ -190,7 +238,7 @@ int main(int argc, char **argv) {
// prof_print_all(); // prof_print_all();
#if 1 #if 1
timings_start_section(&timings, str_lit("llvm-opt")); timings_start_section(&timings, str_lit("llvm-opt"));
char const *output_name = ir_gen.output_file.filename; char const *output_name = ir_gen.output_file.filename;
@@ -202,7 +250,7 @@ int main(int argc, char **argv) {
i32 exit_code = 0; i32 exit_code = 0;
// For more passes arguments: http://llvm.org/docs/Passes.html // For more passes arguments: http://llvm.org/docs/Passes.html
exit_code = win32_exec_command_line_app("llvm-opt", false, exit_code = system_exec_command_line_app("llvm-opt", false,
"\"%.*sbin/opt\" \"%s\" -o \"%.*s\".bc " "\"%.*sbin/opt\" \"%s\" -o \"%.*s\".bc "
"-mem2reg " "-mem2reg "
"-memcpyopt " "-memcpyopt "
@@ -217,10 +265,10 @@ int main(int argc, char **argv) {
return exit_code; return exit_code;
} }
#if 1 #if defined(GB_SYSTEM_WINDOWS)
timings_start_section(&timings, str_lit("llvm-llc")); timings_start_section(&timings, str_lit("llvm-llc"));
// For more arguments: http://llvm.org/docs/CommandGuide/llc.html // For more arguments: http://llvm.org/docs/CommandGuide/llc.html
exit_code = win32_exec_command_line_app("llvm-llc", false, exit_code = system_exec_command_line_app("llvm-llc", false,
"\"%.*sbin/llc\" \"%.*s.bc\" -filetype=obj -O%d " "\"%.*sbin/llc\" \"%.*s.bc\" -filetype=obj -O%d "
"%.*s " "%.*s "
// "-debug-pass=Arguments " // "-debug-pass=Arguments "
@@ -255,7 +303,7 @@ int main(int argc, char **argv) {
link_settings = "/ENTRY:mainCRTStartup"; link_settings = "/ENTRY:mainCRTStartup";
} }
exit_code = win32_exec_command_line_app("msvc-link", true, exit_code = system_exec_command_line_app("msvc-link", true,
"link \"%.*s\".obj -OUT:\"%.*s.%s\" %s " "link \"%.*s\".obj -OUT:\"%.*s.%s\" %s "
"/defaultlib:libcmt " "/defaultlib:libcmt "
"/nologo /incremental:no /opt:ref /subsystem:CONSOLE " "/nologo /incremental:no /opt:ref /subsystem:CONSOLE "
@@ -273,14 +321,16 @@ int main(int argc, char **argv) {
// timings_print_all(&timings); // timings_print_all(&timings);
if (run_output) { if (run_output) {
win32_exec_command_line_app("odin run", false, "%.*s.exe", cast(int)base_name_len, output_name); system_exec_command_line_app("odin run", false, "%.*s.exe", cast(int)base_name_len, output_name);
} }
#else
#error Implement build stuff for this platform
#endif #endif
#endif #endif
#endif #endif
#endif #endif
return 0; return 0;
} }
+3
View File
@@ -6,6 +6,9 @@
#define MAP_NAME MapString #define MAP_NAME MapString
#include "map.c" #include "map.c"
*/ */
// A `Map` is an unordered hash table which can allow for a key to point to multiple values
// with the use of the `multi_*` procedures.
// TODO(bill): I should probably allow the `multi_*` stuff to be #ifdefed out
#ifndef MAP_UTIL_STUFF #ifndef MAP_UTIL_STUFF
#define MAP_UTIL_STUFF #define MAP_UTIL_STUFF
+831 -786
View File
File diff suppressed because it is too large Load Diff
+76 -17
View File
@@ -15,8 +15,11 @@ typedef struct String {
} String; } String;
// NOTE(bill): used for printf style arguments // NOTE(bill): used for printf style arguments
#define LIT(x) ((int)(x).len), (x).text #define LIT(x) ((int)(x).len), (x).text
#define STR_LIT(c_str) {cast(u8 *)c_str, gb_size_of(c_str)-1}
#define str_lit(c_str) (String){cast(u8 *)c_str, gb_size_of(c_str)-1}
// NOTE(bill): String16 is only used for Windows due to its file directories
typedef struct String16 { typedef struct String16 {
wchar_t *text; wchar_t *text;
isize len; isize len;
@@ -46,7 +49,6 @@ gb_inline String make_string_c(char *text) {
return make_string(cast(u8 *)cast(void *)text, gb_strlen(text)); return make_string(cast(u8 *)cast(void *)text, gb_strlen(text));
} }
#define str_lit(c_str) (String){cast(u8 *)c_str, gb_size_of(c_str)-1}
@@ -144,16 +146,37 @@ gb_inline isize string_extension_position(String str) {
return dot_pos; return dot_pos;
} }
String string_trim_whitespace(String str) {
while (str.len > 0 && rune_is_whitespace(str.text[str.len-1])) {
str.len--;
}
while (str.len > 0 && rune_is_whitespace(str.text[0])) {
str.text++;
str.len--;
}
return str;
}
gb_inline bool string_has_extension(String str, String ext) { gb_inline bool string_has_extension(String str, String ext) {
if (str.len > ext.len+1) { str = string_trim_whitespace(str);
u8 *s = str.text+str.len - ext.len-1; if (str.len <= ext.len+1) {
if (s[0] == '.') {
s++;
return gb_memcompare(s, ext.text, ext.len) == 0;
}
return false; return false;
} }
return false; isize len = str.len;
for (isize i = len-1; i >= 0; i--) {
if (str.text[i] == '.') {
break;
}
len--;
}
if (len == 0) {
return false;
}
u8 *s = str.text + len;
return gb_memcompare(s, ext.text, ext.len) == 0;
} }
bool string_contains_char(String s, u8 c) { bool string_contains_char(String s, u8 c) {
@@ -165,6 +188,47 @@ bool string_contains_char(String s, u8 c) {
return false; return false;
} }
#if defined(GB_SYSTEM_WINDOWS)
int convert_multibyte_to_widechar(char *multibyte_input, int input_length, wchar_t *output, int output_size) {
return MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, multibyte_input, input_length, output, output_size);
}
int convert_widechar_to_multibyte(wchar_t *widechar_input, int input_length, char *output, int output_size) {
return WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, widechar_input, input_length, output, output_size, NULL, NULL);
}
#elif defined(GB_SYSTEM_UNIX) || defined(GB_SYSTEM_OSX)
#include <iconv.h>
int convert_multibyte_to_widechar(char *multibyte_input, int input_length, wchar_t *output, int output_size) {
iconv_t conv = iconv_open("WCHAR_T", "UTF-8");
size_t result = iconv(conv, cast(char **)&multibyte_input, &input_length, cast(char **)&output, &output_size);
iconv_close(conv);
return (int) result;
}
int convert_widechar_to_multibyte(wchar_t* widechar_input, int input_length, char* output, int output_size) {
iconv_t conv = iconv_open("UTF-8", "WCHAR_T");
size_t result = iconv(conv, (char**) &widechar_input, &input_length, (char**) &output, &output_size);
iconv_close(conv);
return (int) result;
}
#else
#error Implement system
#endif
// TODO(bill): Make this non-windows specific // TODO(bill): Make this non-windows specific
String16 string_to_string16(gbAllocator a, String s) { String16 string_to_string16(gbAllocator a, String s) {
int len, len1; int len, len1;
@@ -174,16 +238,14 @@ String16 string_to_string16(gbAllocator a, String s) {
return make_string16(NULL, 0); return make_string16(NULL, 0);
} }
len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, len = convert_multibyte_to_widechar(cast(char *)s.text, s.len, NULL, 0);
cast(char *)s.text, s.len, NULL, 0);
if (len == 0) { if (len == 0) {
return make_string16(NULL, 0); return make_string16(NULL, 0);
} }
text = gb_alloc_array(a, wchar_t, len+1); text = gb_alloc_array(a, wchar_t, len+1);
len1 = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, len1 = convert_multibyte_to_widechar(cast(char *)s.text, s.len, text, len);
cast(char *)s.text, s.len, text, len);
if (len1 == 0) { if (len1 == 0) {
gb_free(a, text); gb_free(a, text);
return make_string16(NULL, 0); return make_string16(NULL, 0);
@@ -201,16 +263,14 @@ String string16_to_string(gbAllocator a, String16 s) {
return make_string(NULL, 0); return make_string(NULL, 0);
} }
len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, len = convert_widechar_to_multibyte(s.text, s.len, NULL, 0);
s.text, s.len, NULL, 0, NULL, NULL);
if (len == 0) { if (len == 0) {
return make_string(NULL, 0); return make_string(NULL, 0);
} }
text = gb_alloc_array(a, u8, len+1); text = gb_alloc_array(a, u8, len+1);
len1 = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, len1 = convert_widechar_to_multibyte(s.text, s.len, cast(char *)text, len);
s.text, s.len, cast(char *)text, len, NULL, NULL);
if (len1 == 0) { if (len1 == 0) {
gb_free(a, text); gb_free(a, text);
return make_string(NULL, 0); return make_string(NULL, 0);
@@ -236,7 +296,6 @@ String string16_to_string(gbAllocator a, String16 s) {
bool unquote_char(String s, u8 quote, Rune *rune, bool *multiple_bytes, String *tail_string) { bool unquote_char(String s, u8 quote, Rune *rune, bool *multiple_bytes, String *tail_string) {
u8 c; u8 c;
+38
View File
@@ -11,6 +11,7 @@ typedef struct Timings {
} Timings; } Timings;
#if defined(GB_SYSTEM_WINDOWS)
u64 win32_time_stamp_time_now(void) { u64 win32_time_stamp_time_now(void) {
LARGE_INTEGER counter; LARGE_INTEGER counter;
QueryPerformanceCounter(&counter); QueryPerformanceCounter(&counter);
@@ -27,9 +28,44 @@ u64 win32_time_stamp__freq(void) {
return win32_perf_count_freq.QuadPart; return win32_perf_count_freq.QuadPart;
} }
#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
#include <time.h>
u64 unix_time_stamp_time_now(void) {
struct timespec ts;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
return (ts.tv_sec * 1000000000) + ts.tv_nsec;
}
u64 unix_time_stamp__freq(void) {
gb_local_persist u64 freq = 0;
if (freq == 0) {
struct timespec ts;
clock_getres(CLOCK_PROCESS_CPUTIME_ID, &ts);
// that would be an absurd resolution (or lack thereof)
GB_ASSERT(ts.tv_sec == 0);
freq = cast(u64) ((1.0 / ts.tv_nsec) * 1000000000.0);
GB_ASSERT(freq != 0);
}
return freq;
}
#else
#error Implement system
#endif
u64 time_stamp_time_now(void) { u64 time_stamp_time_now(void) {
#if defined(GB_SYSTEM_WINDOWS) #if defined(GB_SYSTEM_WINDOWS)
return win32_time_stamp_time_now(); return win32_time_stamp_time_now();
#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
return unix_time_stamp_time_now();
#else #else
#error time_stamp_time_now #error time_stamp_time_now
#endif #endif
@@ -38,6 +74,8 @@ u64 time_stamp_time_now(void) {
u64 time_stamp__freq(void) { u64 time_stamp__freq(void) {
#if defined(GB_SYSTEM_WINDOWS) #if defined(GB_SYSTEM_WINDOWS)
return win32_time_stamp__freq(); return win32_time_stamp__freq();
#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
return unix_time_stamp__freq();
#else #else
#error time_stamp__freq #error time_stamp__freq
#endif #endif
+120 -140
View File
@@ -12,28 +12,24 @@ TOKEN_KIND(Token__LiteralBegin, "_LiteralBegin"), \
TOKEN_KIND(Token__LiteralEnd, "_LiteralEnd"), \ TOKEN_KIND(Token__LiteralEnd, "_LiteralEnd"), \
\ \
TOKEN_KIND(Token__OperatorBegin, "_OperatorBegin"), \ TOKEN_KIND(Token__OperatorBegin, "_OperatorBegin"), \
TOKEN_KIND(Token_Eq, "="), \ TOKEN_KIND(Token_Eq, "="), \
TOKEN_KIND(Token_Not, "!"), \ TOKEN_KIND(Token_Not, "!"), \
TOKEN_KIND(Token_Hash, "#"), \ TOKEN_KIND(Token_Hash, "#"), \
TOKEN_KIND(Token_At, "@"), \ TOKEN_KIND(Token_At, "@"), \
TOKEN_KIND(Token_Pointer, "^"), \ TOKEN_KIND(Token_Dollar, "$"), \
TOKEN_KIND(Token_Maybe, "?"), \ TOKEN_KIND(Token_Pointer, "^"), \
TOKEN_KIND(Token_Add, "+"), \ TOKEN_KIND(Token_Question, "?"), \
TOKEN_KIND(Token_Sub, "-"), \ TOKEN_KIND(Token_Add, "+"), \
TOKEN_KIND(Token_Mul, "*"), \ TOKEN_KIND(Token_Sub, "-"), \
TOKEN_KIND(Token_Quo, "/"), \ TOKEN_KIND(Token_Mul, "*"), \
TOKEN_KIND(Token_Mod, "%"), \ TOKEN_KIND(Token_Quo, "/"), \
TOKEN_KIND(Token_And, "&"), \ TOKEN_KIND(Token_Mod, "%"), \
TOKEN_KIND(Token_Or, "|"), \ TOKEN_KIND(Token_And, "&"), \
TOKEN_KIND(Token_Xor, "~"), \ TOKEN_KIND(Token_Or, "|"), \
TOKEN_KIND(Token_AndNot, "&~"), \ TOKEN_KIND(Token_Xor, "~"), \
TOKEN_KIND(Token_Shl, "<<"), \ TOKEN_KIND(Token_AndNot, "&~"), \
TOKEN_KIND(Token_Shr, ">>"), \ TOKEN_KIND(Token_Shl, "<<"), \
\ TOKEN_KIND(Token_Shr, ">>"), \
/*TOKEN_KIND(Token_as, "as"), */\
/*TOKEN_KIND(Token_transmute, "transmute"), */\
/*TOKEN_KIND(Token_down_cast, "down_cast"), */\
/*TOKEN_KIND(Token_union_cast, "union_cast"), */\
\ \
TOKEN_KIND(Token_CmpAnd, "&&"), \ TOKEN_KIND(Token_CmpAnd, "&&"), \
TOKEN_KIND(Token_CmpOr, "||"), \ TOKEN_KIND(Token_CmpOr, "||"), \
@@ -55,6 +51,8 @@ TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \
TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \ TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \
TOKEN_KIND(Token_ArrowRight, "->"), \ TOKEN_KIND(Token_ArrowRight, "->"), \
TOKEN_KIND(Token_ArrowLeft, "<-"), \ TOKEN_KIND(Token_ArrowLeft, "<-"), \
TOKEN_KIND(Token_Inc, "++"), \
TOKEN_KIND(Token_Dec, "--"), \
\ \
TOKEN_KIND(Token__ComparisonBegin, "_ComparisonBegin"), \ TOKEN_KIND(Token__ComparisonBegin, "_ComparisonBegin"), \
TOKEN_KIND(Token_CmpEq, "=="), \ TOKEN_KIND(Token_CmpEq, "=="), \
@@ -76,45 +74,45 @@ TOKEN_KIND(Token__ComparisonEnd, "_ComparisonEnd"), \
TOKEN_KIND(Token_Period, "."), \ TOKEN_KIND(Token_Period, "."), \
TOKEN_KIND(Token_Comma, ","), \ TOKEN_KIND(Token_Comma, ","), \
TOKEN_KIND(Token_Ellipsis, ".."), \ TOKEN_KIND(Token_Ellipsis, ".."), \
TOKEN_KIND(Token_HalfOpenRange, "..<"), \ /* TOKEN_KIND(Token_HalfOpenRange, "..<"), */ \
TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \ TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \
\ \
TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
TOKEN_KIND(Token_type, "type"), \ TOKEN_KIND(Token_when, "when"), \
TOKEN_KIND(Token_proc, "proc"), \ TOKEN_KIND(Token_if, "if"), \
TOKEN_KIND(Token_macro, "macro"), \ TOKEN_KIND(Token_else, "else"), \
TOKEN_KIND(Token_match, "match"), \ TOKEN_KIND(Token_for, "for"), \
TOKEN_KIND(Token_break, "break"), \ TOKEN_KIND(Token_in, "in"), \
TOKEN_KIND(Token_continue, "continue"), \ TOKEN_KIND(Token_match, "match"), \
TOKEN_KIND(Token_fallthrough, "fallthrough"), \ TOKEN_KIND(Token_default, "default"), \
TOKEN_KIND(Token_case, "case"), \ TOKEN_KIND(Token_case, "case"), \
TOKEN_KIND(Token_default, "default"), \ TOKEN_KIND(Token_break, "break"), \
TOKEN_KIND(Token_then, "then"), \ TOKEN_KIND(Token_continue, "continue"), \
TOKEN_KIND(Token_if, "if"), \ TOKEN_KIND(Token_fallthrough, "fallthrough"), \
TOKEN_KIND(Token_else, "else"), \ TOKEN_KIND(Token_defer, "defer"), \
TOKEN_KIND(Token_for, "for"), \ TOKEN_KIND(Token_return, "return"), \
TOKEN_KIND(Token_in, "in"), \ TOKEN_KIND(Token_give, "give"), \
TOKEN_KIND(Token_when, "when"), \ TOKEN_KIND(Token_proc, "proc"), \
TOKEN_KIND(Token_range, "range"), \ TOKEN_KIND(Token_macro, "macro"), \
TOKEN_KIND(Token_defer, "defer"), \ TOKEN_KIND(Token_struct, "struct"), \
TOKEN_KIND(Token_return, "return"), \ TOKEN_KIND(Token_union, "union"), \
TOKEN_KIND(Token_give, "give"), \ TOKEN_KIND(Token_raw_union, "raw_union"), \
TOKEN_KIND(Token_struct, "struct"), \ TOKEN_KIND(Token_enum, "enum"), \
TOKEN_KIND(Token_union, "union"), \ TOKEN_KIND(Token_vector, "vector"), \
TOKEN_KIND(Token_raw_union, "raw_union"), \ TOKEN_KIND(Token_static, "static"), \
TOKEN_KIND(Token_enum, "enum"), \ TOKEN_KIND(Token_dynamic, "dynamic"), \
TOKEN_KIND(Token_vector, "vector"), \ TOKEN_KIND(Token_map, "map"), \
TOKEN_KIND(Token_using, "using"), \ TOKEN_KIND(Token_using, "using"), \
TOKEN_KIND(Token_no_alias, "no_alias"), \ TOKEN_KIND(Token_no_alias, "no_alias"), \
TOKEN_KIND(Token_immutable, "immutable"), \ TOKEN_KIND(Token_immutable, "immutable"), \
TOKEN_KIND(Token_thread_local, "thread_local"), \ TOKEN_KIND(Token_cast, "cast"), \
TOKEN_KIND(Token_asm, "asm"), \ TOKEN_KIND(Token_transmute, "transmute"), \
TOKEN_KIND(Token_push_allocator, "push_allocator"), \ TOKEN_KIND(Token_down_cast, "down_cast"), \
TOKEN_KIND(Token_push_context, "push_context"), \ TOKEN_KIND(Token_union_cast, "union_cast"), \
TOKEN_KIND(Token_cast, "cast"), \ TOKEN_KIND(Token_context, "context"), \
TOKEN_KIND(Token_transmute, "transmute"), \ TOKEN_KIND(Token_push_context, "push_context"), \
TOKEN_KIND(Token_down_cast, "down_cast"), \ TOKEN_KIND(Token_push_allocator, "push_allocator"), \
TOKEN_KIND(Token_union_cast, "union_cast"), \ TOKEN_KIND(Token_asm, "asm"), \
TOKEN_KIND(Token__KeywordEnd, "_KeywordEnd"), \ TOKEN_KIND(Token__KeywordEnd, "_KeywordEnd"), \
TOKEN_KIND(Token_Count, "") TOKEN_KIND(Token_Count, "")
@@ -227,6 +225,23 @@ void syntax_error_va(Token token, char *fmt, va_list va) {
gb_mutex_unlock(&global_error_collector.mutex); gb_mutex_unlock(&global_error_collector.mutex);
} }
void syntax_warning_va(Token token, char *fmt, va_list va) {
gb_mutex_lock(&global_error_collector.mutex);
global_error_collector.warning_count++;
// NOTE(bill): Duplicate error, skip it
if (!token_pos_eq(global_error_collector.prev, token.pos)) {
global_error_collector.prev = token.pos;
gb_printf_err("%.*s(%td:%td) Syntax Warning: %s\n",
LIT(token.pos.file), token.pos.line, token.pos.column,
gb_bprintf_va(fmt, va));
} else if (token.pos.line == 0) {
gb_printf_err("Warning: %s\n", gb_bprintf_va(fmt, va));
}
gb_mutex_unlock(&global_error_collector.mutex);
}
void warning(Token token, char *fmt, ...) { void warning(Token token, char *fmt, ...) {
va_list va; va_list va;
@@ -249,6 +264,13 @@ void syntax_error(Token token, char *fmt, ...) {
va_end(va); va_end(va);
} }
void syntax_warning(Token token, char *fmt, ...) {
va_list va;
va_start(va, fmt);
syntax_warning_va(token, fmt, va);
va_end(va);
}
void compiler_error(char *fmt, ...) { void compiler_error(char *fmt, ...) {
va_list va; va_list va;
@@ -264,20 +286,20 @@ void compiler_error(char *fmt, ...) {
gb_inline bool token_is_literal(Token t) { gb_inline bool token_is_literal(TokenKind t) {
return gb_is_between(t.kind, Token__LiteralBegin+1, Token__LiteralEnd-1); return gb_is_between(t, Token__LiteralBegin+1, Token__LiteralEnd-1);
} }
gb_inline bool token_is_operator(Token t) { gb_inline bool token_is_operator(TokenKind t) {
return gb_is_between(t.kind, Token__OperatorBegin+1, Token__OperatorEnd-1); return gb_is_between(t, Token__OperatorBegin+1, Token__OperatorEnd-1);
} }
gb_inline bool token_is_keyword(Token t) { gb_inline bool token_is_keyword(TokenKind t) {
return gb_is_between(t.kind, Token__KeywordBegin+1, Token__KeywordEnd-1); return gb_is_between(t, Token__KeywordBegin+1, Token__KeywordEnd-1);
} }
gb_inline bool token_is_comparison(Token t) { gb_inline bool token_is_comparison(TokenKind t) {
return gb_is_between(t.kind, Token__ComparisonBegin+1, Token__ComparisonEnd-1); return gb_is_between(t, Token__ComparisonBegin+1, Token__ComparisonEnd-1);
} }
gb_inline bool token_is_shift(Token t) { gb_inline bool token_is_shift(TokenKind t) {
return t.kind == Token_Shl || t.kind == Token_Shr; return t == Token_Shl || t == Token_Shr;
} }
gb_inline void print_token(Token t) { gb_printf("%.*s\n", LIT(t.string)); } gb_inline void print_token(Token t) { gb_printf("%.*s\n", LIT(t.string)); }
@@ -474,7 +496,6 @@ gb_inline void scan_mantissa(Tokenizer *t, i32 base, bool allow_underscore) {
} }
} }
Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) { Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) {
Token token = {0}; Token token = {0};
token.kind = Token_Integer; token.kind = Token_Integer;
@@ -730,20 +751,10 @@ Token tokenizer_get_token(Tokenizer *t) {
// NOTE(bill): All keywords are > 1 // NOTE(bill): All keywords are > 1
if (token.string.len > 1) { if (token.string.len > 1) {
/* if (str_eq(token.string, token_strings[Token_as])) { for (i32 k = Token__KeywordBegin+1; k < Token__KeywordEnd; k++) {
token.kind = Token_as; if (str_eq(token.string, token_strings[k])) {
} else if (str_eq(token.string, token_strings[Token_transmute])) { token.kind = cast(TokenKind)k;
token.kind = Token_transmute; break;
} else if (str_eq(token.string, token_strings[Token_down_cast])) {
token.kind = Token_down_cast;
} else if (str_eq(token.string, token_strings[Token_union_cast])) {
token.kind = Token_union_cast;
} else */{
for (i32 k = Token__KeywordBegin+1; k < Token__KeywordEnd; k++) {
if (str_eq(token.string, token_strings[k])) {
token.kind = cast(TokenKind)k;
break;
}
} }
} }
} }
@@ -848,64 +859,35 @@ Token tokenizer_get_token(Tokenizer *t) {
if (t->curr_rune == '.') { // Could be an ellipsis if (t->curr_rune == '.') { // Could be an ellipsis
advance_to_next_rune(t); advance_to_next_rune(t);
token.kind = Token_Ellipsis; token.kind = Token_Ellipsis;
if (t->curr_rune == '<') { // if (t->curr_rune == '<') {
advance_to_next_rune(t); // advance_to_next_rune(t);
token.kind = Token_HalfOpenRange; // token.kind = Token_HalfOpenRange;
} // }
} }
break; break;
case '#': case '#': token.kind = Token_Hash; break;
token.kind = Token_Hash; case '@': token.kind = Token_At; break;
break; case '$': token.kind = Token_Dollar; break;
case '@': case '?': token.kind = Token_Question; break;
token.kind = Token_At; case '^': token.kind = Token_Pointer; break;
break; case ';': token.kind = Token_Semicolon; break;
case '^': case ',': token.kind = Token_Comma; break;
token.kind = Token_Pointer; case ':': token.kind = Token_Colon; break;
break; case '(': token.kind = Token_OpenParen; break;
case '?': case ')': token.kind = Token_CloseParen; break;
token.kind = Token_Maybe; case '[': token.kind = Token_OpenBracket; break;
break; case ']': token.kind = Token_CloseBracket; break;
case ';': case '{': token.kind = Token_OpenBrace; break;
token.kind = Token_Semicolon; case '}': token.kind = Token_CloseBrace; break;
break;
case ',':
token.kind = Token_Comma;
break;
case ':':
token.kind = Token_Colon;
break;
case '(':
token.kind = Token_OpenParen;
break;
case ')':
token.kind = Token_CloseParen;
break;
case '[':
token.kind = Token_OpenBracket;
break;
case ']':
token.kind = Token_CloseBracket;
break;
case '{':
token.kind = Token_OpenBrace;
break;
case '}':
token.kind = Token_CloseBrace;
break;
case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq); break; case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq); break;
case '%': token.kind = token_kind_variant2(t, Token_Mod, Token_ModEq); break; case '%': token.kind = token_kind_variant2(t, Token_Mod, Token_ModEq); break;
case '=': token.kind = token_kind_variant2(t, Token_Eq, Token_CmpEq); break; case '=': token.kind = token_kind_variant2(t, Token_Eq, Token_CmpEq); break;
case '~': token.kind = token_kind_variant2(t, Token_Xor, Token_XorEq); break; case '~': token.kind = token_kind_variant2(t, Token_Xor, Token_XorEq); break;
case '!': token.kind = token_kind_variant2(t, Token_Not, Token_NotEq); break; case '!': token.kind = token_kind_variant2(t, Token_Not, Token_NotEq); break;
case '+': case '+': token.kind = token_kind_variant3(t, Token_Add, Token_AddEq, '+', Token_Inc); break;
token.kind = token_kind_variant2(t, Token_Add, Token_AddEq); case '-': token.kind = token_kind_variant4(t, Token_Sub, Token_SubEq, '-', Token_Dec, '>', Token_ArrowRight); break;
break;
case '-':
token.kind = token_kind_variant3(t, Token_Sub, Token_SubEq, '>', Token_ArrowRight);
break;
case '/': { case '/': {
if (t->curr_rune == '/') { if (t->curr_rune == '/') {
while (t->curr_rune != '\n' && t->curr_rune != GB_RUNE_EOF) { while (t->curr_rune != '\n' && t->curr_rune != GB_RUNE_EOF) {
@@ -945,9 +927,7 @@ Token tokenizer_get_token(Tokenizer *t) {
token.kind = token_kind_dub_eq(t, '<', Token_Lt, Token_LtEq, Token_Shl, Token_ShlEq); token.kind = token_kind_dub_eq(t, '<', Token_Lt, Token_LtEq, Token_Shl, Token_ShlEq);
} }
break; break;
case '>': case '>': token.kind = token_kind_dub_eq(t, '>', Token_Gt, Token_GtEq, Token_Shr, Token_ShrEq); break;
token.kind = token_kind_dub_eq(t, '>', Token_Gt, Token_GtEq, Token_Shr, Token_ShrEq);
break;
case '&': case '&':
token.kind = Token_And; token.kind = Token_And;
+563 -253
View File
File diff suppressed because it is too large Load Diff
+1 -25
View File
@@ -6,6 +6,7 @@
#pragma warning(pop) #pragma warning(pop)
bool rune_is_letter(Rune r) { bool rune_is_letter(Rune r) {
if ((r < 0x80 && gb_char_is_alpha(cast(char)r)) || if ((r < 0x80 && gb_char_is_alpha(cast(char)r)) ||
r == '_') { r == '_') {
@@ -39,28 +40,3 @@ bool rune_is_whitespace(Rune r) {
} }
return false; return false;
} }
bool is_string_an_identifier(String s) {
isize offset = 0;
if (s.len < 1) {
return false;
}
while (offset < s.len) {
bool ok = false;
Rune r = -1;
isize size = gb_utf8_decode(s.text+offset, s.len-offset, &r);
if (offset == 0) {
ok = rune_is_letter(r);
} else {
ok = rune_is_letter(r) || rune_is_digit(r);
}
if (!ok) {
return false;
}
offset += size;
}
return offset == s.len;
}
+66 -44
View File
@@ -166,24 +166,24 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_encode_char(utf8proc_int32_t uc, ut
if (uc < 0x00) { if (uc < 0x00) {
return 0; return 0;
} else if (uc < 0x80) { } else if (uc < 0x80) {
dst[0] = uc; dst[0] = (utf8proc_uint8_t) uc;
return 1; return 1;
} else if (uc < 0x800) { } else if (uc < 0x800) {
dst[0] = 0xC0 + (uc >> 6); dst[0] = (utf8proc_uint8_t)(0xC0 + (uc >> 6));
dst[1] = 0x80 + (uc & 0x3F); dst[1] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
return 2; return 2;
// Note: we allow encoding 0xd800-0xdfff here, so as not to change // Note: we allow encoding 0xd800-0xdfff here, so as not to change
// the API, however, these are actually invalid in UTF-8 // the API, however, these are actually invalid in UTF-8
} else if (uc < 0x10000) { } else if (uc < 0x10000) {
dst[0] = 0xE0 + (uc >> 12); dst[0] = (utf8proc_uint8_t)(0xE0 + (uc >> 12));
dst[1] = 0x80 + ((uc >> 6) & 0x3F); dst[1] = (utf8proc_uint8_t)(0x80 + ((uc >> 6) & 0x3F));
dst[2] = 0x80 + (uc & 0x3F); dst[2] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
return 3; return 3;
} else if (uc < 0x110000) { } else if (uc < 0x110000) {
dst[0] = 0xF0 + (uc >> 18); dst[0] = (utf8proc_uint8_t)(0xF0 + (uc >> 18));
dst[1] = 0x80 + ((uc >> 12) & 0x3F); dst[1] = (utf8proc_uint8_t)(0x80 + ((uc >> 12) & 0x3F));
dst[2] = 0x80 + ((uc >> 6) & 0x3F); dst[2] = (utf8proc_uint8_t)(0x80 + ((uc >> 6) & 0x3F));
dst[3] = 0x80 + (uc & 0x3F); dst[3] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
return 4; return 4;
} else return 0; } else return 0;
} }
@@ -193,28 +193,28 @@ static utf8proc_ssize_t unsafe_encode_char(utf8proc_int32_t uc, utf8proc_uint8_t
if (uc < 0x00) { if (uc < 0x00) {
return 0; return 0;
} else if (uc < 0x80) { } else if (uc < 0x80) {
dst[0] = uc; dst[0] = (utf8proc_uint8_t)uc;
return 1; return 1;
} else if (uc < 0x800) { } else if (uc < 0x800) {
dst[0] = 0xC0 + (uc >> 6); dst[0] = (utf8proc_uint8_t)(0xC0 + (uc >> 6));
dst[1] = 0x80 + (uc & 0x3F); dst[1] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
return 2; return 2;
} else if (uc == 0xFFFF) { } else if (uc == 0xFFFF) {
dst[0] = 0xFF; dst[0] = (utf8proc_uint8_t)0xFF;
return 1; return 1;
} else if (uc == 0xFFFE) { } else if (uc == 0xFFFE) {
dst[0] = 0xFE; dst[0] = (utf8proc_uint8_t)0xFE;
return 1; return 1;
} else if (uc < 0x10000) { } else if (uc < 0x10000) {
dst[0] = 0xE0 + (uc >> 12); dst[0] = (utf8proc_uint8_t)(0xE0 + (uc >> 12));
dst[1] = 0x80 + ((uc >> 6) & 0x3F); dst[1] = (utf8proc_uint8_t)(0x80 + ((uc >> 6) & 0x3F));
dst[2] = 0x80 + (uc & 0x3F); dst[2] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
return 3; return 3;
} else if (uc < 0x110000) { } else if (uc < 0x110000) {
dst[0] = 0xF0 + (uc >> 18); dst[0] = (utf8proc_uint8_t)(0xF0 + (uc >> 18));
dst[1] = 0x80 + ((uc >> 12) & 0x3F); dst[1] = (utf8proc_uint8_t)(0x80 + ((uc >> 12) & 0x3F));
dst[2] = 0x80 + ((uc >> 6) & 0x3F); dst[2] = (utf8proc_uint8_t)(0x80 + ((uc >> 6) & 0x3F));
dst[3] = 0x80 + (uc & 0x3F); dst[3] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
return 4; return 4;
} else return 0; } else return 0;
} }
@@ -383,7 +383,7 @@ UTF8PROC_DLLEXPORT int utf8proc_charwidth(utf8proc_int32_t c) {
} }
UTF8PROC_DLLEXPORT utf8proc_category_t utf8proc_category(utf8proc_int32_t c) { UTF8PROC_DLLEXPORT utf8proc_category_t utf8proc_category(utf8proc_int32_t c) {
return (utf8proc_category_t)utf8proc_get_property(c)->category; return utf8proc_get_property(c)->category;
} }
UTF8PROC_DLLEXPORT const char *utf8proc_category_string(utf8proc_int32_t c) { UTF8PROC_DLLEXPORT const char *utf8proc_category_string(utf8proc_int32_t c) {
@@ -391,11 +391,9 @@ UTF8PROC_DLLEXPORT const char *utf8proc_category_string(utf8proc_int32_t c) {
return s[utf8proc_category(c)]; return s[utf8proc_category(c)];
} }
#define utf8proc_decompose_lump(replacement_uc) \ #define utf8proc_decompose_lump(replacement_uc) \
return utf8proc_decompose_char((utf8proc_int32_t)(replacement_uc), dst, bufsize, \ return utf8proc_decompose_char((replacement_uc), dst, bufsize, \
(utf8proc_option_t)((utf8proc_int32_t)options & ~UTF8PROC_LUMP), last_boundclass) options & ~UTF8PROC_LUMP, last_boundclass)
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_char(utf8proc_int32_t uc, utf8proc_int32_t *dst, utf8proc_ssize_t bufsize, utf8proc_option_t options, int *last_boundclass) { UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_char(utf8proc_int32_t uc, utf8proc_int32_t *dst, utf8proc_ssize_t bufsize, utf8proc_option_t options, int *last_boundclass) {
const utf8proc_property_t *property; const utf8proc_property_t *property;
@@ -458,12 +456,12 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_char(utf8proc_int32_t uc,
category == UTF8PROC_CATEGORY_ME) return 0; category == UTF8PROC_CATEGORY_ME) return 0;
} }
if (options & UTF8PROC_CASEFOLD) { if (options & UTF8PROC_CASEFOLD) {
if ((utf8proc_int16_t)property->casefold_seqindex != UINT16_MAX) { if (property->casefold_seqindex != UINT16_MAX) {
return seqindex_write_char_decomposed(property->casefold_seqindex, dst, bufsize, options, last_boundclass); return seqindex_write_char_decomposed(property->casefold_seqindex, dst, bufsize, options, last_boundclass);
} }
} }
if (options & (UTF8PROC_COMPOSE|UTF8PROC_DECOMPOSE)) { if (options & (UTF8PROC_COMPOSE|UTF8PROC_DECOMPOSE)) {
if ((utf8proc_int16_t)property->decomp_seqindex != UINT16_MAX && if (property->decomp_seqindex != UINT16_MAX &&
(!property->decomp_type || (options & UTF8PROC_COMPAT))) { (!property->decomp_type || (options & UTF8PROC_COMPAT))) {
return seqindex_write_char_decomposed(property->decomp_seqindex, dst, bufsize, options, last_boundclass); return seqindex_write_char_decomposed(property->decomp_seqindex, dst, bufsize, options, last_boundclass);
} }
@@ -485,6 +483,14 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_char(utf8proc_int32_t uc,
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose( UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose(
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, const utf8proc_uint8_t *str, utf8proc_ssize_t strlen,
utf8proc_int32_t *buffer, utf8proc_ssize_t bufsize, utf8proc_option_t options utf8proc_int32_t *buffer, utf8proc_ssize_t bufsize, utf8proc_option_t options
) {
return utf8proc_decompose_custom(str, strlen, buffer, bufsize, options, NULL, NULL);
}
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_custom(
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen,
utf8proc_int32_t *buffer, utf8proc_ssize_t bufsize, utf8proc_option_t options,
utf8proc_custom_func custom_func, void *custom_data
) { ) {
/* strlen will be ignored, if UTF8PROC_NULLTERM is set in options */ /* strlen will be ignored, if UTF8PROC_NULLTERM is set in options */
utf8proc_ssize_t wpos = 0; utf8proc_ssize_t wpos = 0;
@@ -511,6 +517,9 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose(
rpos += utf8proc_iterate(str + rpos, strlen - rpos, &uc); rpos += utf8proc_iterate(str + rpos, strlen - rpos, &uc);
if (uc < 0) return UTF8PROC_ERROR_INVALIDUTF8; if (uc < 0) return UTF8PROC_ERROR_INVALIDUTF8;
} }
if (custom_func != NULL) {
uc = custom_func(uc, custom_data); /* user-specified custom mapping */
}
decomp_result = utf8proc_decompose_char( decomp_result = utf8proc_decompose_char(
uc, buffer + wpos, (bufsize > wpos) ? (bufsize - wpos) : 0, options, uc, buffer + wpos, (bufsize > wpos) ? (bufsize - wpos) : 0, options,
&boundclass &boundclass
@@ -545,9 +554,8 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose(
return wpos; return wpos;
} }
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_reencode(utf8proc_int32_t *buffer, utf8proc_ssize_t length, utf8proc_option_t options) { UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_normalize_utf32(utf8proc_int32_t *buffer, utf8proc_ssize_t length, utf8proc_option_t options) {
/* UTF8PROC_NULLTERM option will be ignored, 'length' is never ignored /* UTF8PROC_NULLTERM option will be ignored, 'length' is never ignored */
ASSERT: 'buffer' has one spare byte of free space at the end! */
if (options & (UTF8PROC_NLF2LS | UTF8PROC_NLF2PS | UTF8PROC_STRIPCC)) { if (options & (UTF8PROC_NLF2LS | UTF8PROC_NLF2PS | UTF8PROC_STRIPCC)) {
utf8proc_ssize_t rpos; utf8proc_ssize_t rpos;
utf8proc_ssize_t wpos = 0; utf8proc_ssize_t wpos = 0;
@@ -621,7 +629,7 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_reencode(utf8proc_int32_t *buffer,
starter_property = unsafe_get_property(*starter); starter_property = unsafe_get_property(*starter);
} }
if (starter_property->comb_index < 0x8000 && if (starter_property->comb_index < 0x8000 &&
(utf8proc_int16_t)current_property->comb_index != UINT16_MAX && current_property->comb_index != UINT16_MAX &&
current_property->comb_index >= 0x8000) { current_property->comb_index >= 0x8000) {
int sidx = starter_property->comb_index; int sidx = starter_property->comb_index;
int idx = (current_property->comb_index & 0x3FFF) - utf8proc_combinations[sidx]; int idx = (current_property->comb_index & 0x3FFF) - utf8proc_combinations[sidx];
@@ -655,6 +663,14 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_reencode(utf8proc_int32_t *buffer,
} }
length = wpos; length = wpos;
} }
return length;
}
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_reencode(utf8proc_int32_t *buffer, utf8proc_ssize_t length, utf8proc_option_t options) {
/* UTF8PROC_NULLTERM option will be ignored, 'length' is never ignored
ASSERT: 'buffer' has one spare byte of free space at the end! */
length = utf8proc_normalize_utf32(buffer, length, options);
if (length < 0) return length;
{ {
utf8proc_ssize_t rpos, wpos = 0; utf8proc_ssize_t rpos, wpos = 0;
utf8proc_int32_t uc; utf8proc_int32_t uc;
@@ -676,15 +692,22 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_reencode(utf8proc_int32_t *buffer,
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map( UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map(
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options
) {
return utf8proc_map_custom(str, strlen, dstptr, options, NULL, NULL);
}
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map_custom(
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options,
utf8proc_custom_func custom_func, void *custom_data
) { ) {
utf8proc_int32_t *buffer; utf8proc_int32_t *buffer;
utf8proc_ssize_t result; utf8proc_ssize_t result;
*dstptr = NULL; *dstptr = NULL;
result = utf8proc_decompose(str, strlen, NULL, 0, options); result = utf8proc_decompose_custom(str, strlen, NULL, 0, options, custom_func, custom_data);
if (result < 0) return result; if (result < 0) return result;
buffer = (utf8proc_int32_t *) malloc(result * sizeof(utf8proc_int32_t) + 1); buffer = (utf8proc_int32_t *) malloc(result * sizeof(utf8proc_int32_t) + 1);
if (!buffer) return UTF8PROC_ERROR_NOMEM; if (!buffer) return UTF8PROC_ERROR_NOMEM;
result = utf8proc_decompose(str, strlen, buffer, result, options); result = utf8proc_decompose_custom(str, strlen, buffer, result, options, custom_func, custom_data);
if (result < 0) { if (result < 0) {
free(buffer); free(buffer);
return result; return result;
@@ -705,29 +728,28 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map(
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFD(const utf8proc_uint8_t *str) { UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFD(const utf8proc_uint8_t *str) {
utf8proc_uint8_t *retval; utf8proc_uint8_t *retval;
utf8proc_map(str, 0, &retval, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE | utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE |
UTF8PROC_DECOMPOSE)); UTF8PROC_DECOMPOSE);
return retval; return retval;
} }
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFC(const utf8proc_uint8_t *str) { UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFC(const utf8proc_uint8_t *str) {
utf8proc_uint8_t *retval; utf8proc_uint8_t *retval;
utf8proc_map(str, 0, &retval, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE | utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE |
UTF8PROC_COMPOSE)); UTF8PROC_COMPOSE);
return retval; return retval;
} }
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKD(const utf8proc_uint8_t *str) { UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKD(const utf8proc_uint8_t *str) {
utf8proc_uint8_t *retval; utf8proc_uint8_t *retval;
utf8proc_map(str, 0, &retval, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE | utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE |
UTF8PROC_DECOMPOSE | UTF8PROC_COMPAT)); UTF8PROC_DECOMPOSE | UTF8PROC_COMPAT);
return retval; return retval;
} }
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC(const utf8proc_uint8_t *str) { UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC(const utf8proc_uint8_t *str) {
utf8proc_uint8_t *retval; utf8proc_uint8_t *retval;
utf8proc_map(str, 0, &retval, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE | utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE |
UTF8PROC_COMPOSE | UTF8PROC_COMPAT)); UTF8PROC_COMPOSE | UTF8PROC_COMPAT);
return retval; return retval;
} }
+81 -25
View File
@@ -71,14 +71,15 @@
/** The MAJOR version number (increased when backwards API compatibility is broken). */ /** The MAJOR version number (increased when backwards API compatibility is broken). */
#define UTF8PROC_VERSION_MAJOR 2 #define UTF8PROC_VERSION_MAJOR 2
/** The MINOR version number (increased when new functionality is added in a backwards-compatible manner). */ /** The MINOR version number (increased when new functionality is added in a backwards-compatible manner). */
#define UTF8PROC_VERSION_MINOR 0 #define UTF8PROC_VERSION_MINOR 1
/** The PATCH version (increased for fixes that do not change the API). */ /** The PATCH version (increased for fixes that do not change the API). */
#define UTF8PROC_VERSION_PATCH 2 #define UTF8PROC_VERSION_PATCH 0
/** @} */ /** @} */
#include <stdlib.h> #include <stdlib.h>
#include <sys/types.h>
#ifdef _MSC_VER #if defined(_MSC_VER) && _MSC_VER < 1800
// MSVC prior to 2013 lacked stdbool.h and inttypes.h
typedef signed char utf8proc_int8_t; typedef signed char utf8proc_int8_t;
typedef unsigned char utf8proc_uint8_t; typedef unsigned char utf8proc_uint8_t;
typedef short utf8proc_int16_t; typedef short utf8proc_int16_t;
@@ -93,12 +94,18 @@ typedef int utf8proc_ssize_t;
typedef unsigned int utf8proc_size_t; typedef unsigned int utf8proc_size_t;
# endif # endif
# ifndef __cplusplus # ifndef __cplusplus
// emulate C99 bool
typedef unsigned char utf8proc_bool; typedef unsigned char utf8proc_bool;
// enum {false, true}; # ifndef __bool_true_false_are_defined
# define false 0
# define true 1
# define __bool_true_false_are_defined 1
# endif
# else # else
typedef bool utf8proc_bool; typedef bool utf8proc_bool;
# endif # endif
#else #else
# include <stddef.h>
# include <stdbool.h> # include <stdbool.h>
# include <inttypes.h> # include <inttypes.h>
typedef int8_t utf8proc_int8_t; typedef int8_t utf8proc_int8_t;
@@ -108,22 +115,12 @@ typedef uint16_t utf8proc_uint16_t;
typedef int32_t utf8proc_int32_t; typedef int32_t utf8proc_int32_t;
typedef uint32_t utf8proc_uint32_t; typedef uint32_t utf8proc_uint32_t;
typedef size_t utf8proc_size_t; typedef size_t utf8proc_size_t;
typedef ssize_t utf8proc_ssize_t; typedef ptrdiff_t utf8proc_ssize_t;
typedef bool utf8proc_bool; typedef bool utf8proc_bool;
#endif #endif
#include <limits.h> #include <limits.h>
#ifdef _WIN32 #define UTF8PROC_DLLEXPORT
# ifdef UTF8PROC_EXPORTS
# define UTF8PROC_DLLEXPORT __declspec(dllexport)
# else
# define UTF8PROC_DLLEXPORT /*__declspec(dllimport)*/
# endif
#elif __GNUC__ >= 4
# define UTF8PROC_DLLEXPORT __attribute__ ((visibility("default")))
#else
# define UTF8PROC_DLLEXPORT
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -134,7 +131,7 @@ extern "C" {
#endif #endif
#ifndef UINT16_MAX #ifndef UINT16_MAX
# define UINT16_MAX ~(utf8proc_uint16_t)0 # define UINT16_MAX 65535U
#endif #endif
/** /**
@@ -373,6 +370,13 @@ typedef enum {
UTF8PROC_BOUNDCLASS_E_BASE_GAZ = 18, /**< E_BASE + GLUE_AFTER_ZJW */ UTF8PROC_BOUNDCLASS_E_BASE_GAZ = 18, /**< E_BASE + GLUE_AFTER_ZJW */
} utf8proc_boundclass_t; } utf8proc_boundclass_t;
/**
* Function pointer type passed to @ref utf8proc_map_custom and
* @ref utf8proc_decompose_custom, which is used to specify a user-defined
* mapping of codepoints to be applied in conjunction with other mappings.
*/
typedef utf8proc_int32_t (*utf8proc_custom_func)(utf8proc_int32_t codepoint, void *data);
/** /**
* Array containing the byte lengths of a UTF-8 encoded codepoint based * Array containing the byte lengths of a UTF-8 encoded codepoint based
* on the first byte. * on the first byte.
@@ -480,6 +484,7 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_char(
* `buffer` (which must contain at least `bufsize` entries). In case of * `buffer` (which must contain at least `bufsize` entries). In case of
* success, the number of codepoints written is returned; in case of an * success, the number of codepoints written is returned; in case of an
* error, a negative error code is returned (@ref utf8proc_errmsg). * error, a negative error code is returned (@ref utf8proc_errmsg).
* See @ref utf8proc_decompose_custom to supply additional transformations.
* *
* If the number of written codepoints would be bigger than `bufsize`, the * If the number of written codepoints would be bigger than `bufsize`, the
* required buffer size is returned, while the buffer will be overwritten with * required buffer size is returned, while the buffer will be overwritten with
@@ -491,8 +496,20 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose(
); );
/** /**
* Reencodes the sequence of `length` codepoints pointed to by `buffer` * The same as @ref utf8proc_decompose, but also takes a `custom_func` mapping function
* UTF-8 data in-place (i.e., the result is also stored in `buffer`). * that is called on each codepoint in `str` before any other transformations
* (along with a `custom_data` pointer that is passed through to `custom_func`).
* The `custom_func` argument is ignored if it is `NULL`. See also @ref utf8proc_map_custom.
*/
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_custom(
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen,
utf8proc_int32_t *buffer, utf8proc_ssize_t bufsize, utf8proc_option_t options,
utf8proc_custom_func custom_func, void *custom_data
);
/**
* Normalizes the sequence of `length` codepoints pointed to by `buffer`
* in-place (i.e., the result is also stored in `buffer`).
* *
* @param buffer the (native-endian UTF-32) unicode codepoints to re-encode. * @param buffer the (native-endian UTF-32) unicode codepoints to re-encode.
* @param length the length (in codepoints) of the buffer. * @param length the length (in codepoints) of the buffer.
@@ -507,9 +524,37 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose(
* the unicode versioning stability * the unicode versioning stability
* *
* @return * @return
* In case of success, the length (in bytes) of the resulting UTF-8 string is * In case of success, the length (in codepoints) of the normalized UTF-32 string is
* returned; otherwise, a negative error code is returned (@ref utf8proc_errmsg). * returned; otherwise, a negative error code is returned (@ref utf8proc_errmsg).
* *
* @warning The entries of the array pointed to by `str` have to be in the
* range `0x0000` to `0x10FFFF`. Otherwise, the program might crash!
*/
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_normalize_utf32(utf8proc_int32_t *buffer, utf8proc_ssize_t length, utf8proc_option_t options);
/**
* Reencodes the sequence of `length` codepoints pointed to by `buffer`
* UTF-8 data in-place (i.e., the result is also stored in `buffer`).
* Can optionally normalize the UTF-32 sequence prior to UTF-8 conversion.
*
* @param buffer the (native-endian UTF-32) unicode codepoints to re-encode.
* @param length the length (in codepoints) of the buffer.
* @param options a bitwise or (`|`) of one or more of the following flags:
* - @ref UTF8PROC_NLF2LS - convert LF, CRLF, CR and NEL into LS
* - @ref UTF8PROC_NLF2PS - convert LF, CRLF, CR and NEL into PS
* - @ref UTF8PROC_NLF2LF - convert LF, CRLF, CR and NEL into LF
* - @ref UTF8PROC_STRIPCC - strip or convert all non-affected control characters
* - @ref UTF8PROC_COMPOSE - try to combine decomposed codepoints into composite
* codepoints
* - @ref UTF8PROC_STABLE - prohibit combining characters that would violate
* the unicode versioning stability
* - @ref UTF8PROC_CHARBOUND - insert 0xFF bytes before each grapheme cluster
*
* @return
* In case of success, the length (in bytes) of the resulting nul-terminated
* UTF-8 string is returned; otherwise, a negative error code is returned
* (@ref utf8proc_errmsg).
*
* @warning The amount of free space pointed to by `buffer` must * @warning The amount of free space pointed to by `buffer` must
* exceed the amount of the input data by one byte, and the * exceed the amount of the input data by one byte, and the
* entries of the array pointed to by `str` have to be in the * entries of the array pointed to by `str` have to be in the
@@ -595,7 +640,8 @@ UTF8PROC_DLLEXPORT const char *utf8proc_category_string(utf8proc_int32_t codepoi
* in any case the result will be NULL terminated (though it might * in any case the result will be NULL terminated (though it might
* contain NULL characters with the string if `str` contained NULL * contain NULL characters with the string if `str` contained NULL
* characters). Other flags in the `options` field are passed to the * characters). Other flags in the `options` field are passed to the
* functions defined above, and regarded as described. * functions defined above, and regarded as described. See also
* @ref utfproc_map_custom to supply a custom codepoint transformation.
* *
* In case of success the length of the new string is returned, * In case of success the length of the new string is returned,
* otherwise a negative error code is returned. * otherwise a negative error code is returned.
@@ -607,6 +653,17 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map(
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options
); );
/**
* Like @ref utf8proc_map, but also takes a `custom_func` mapping function
* that is called on each codepoint in `str` before any other transformations
* (along with a `custom_data` pointer that is passed through to `custom_func`).
* The `custom_func` argument is ignored if it is `NULL`.
*/
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map_custom(
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options,
utf8proc_custom_func custom_func, void *custom_data
);
/** @name Unicode normalization /** @name Unicode normalization
* *
* Returns a pointer to newly allocated memory of a NFD, NFC, NFKD or NFKC * Returns a pointer to newly allocated memory of a NFD, NFC, NFKD or NFKC
@@ -619,9 +676,9 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map(
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFD(const utf8proc_uint8_t *str); UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFD(const utf8proc_uint8_t *str);
/** NFC normalization (@ref UTF8PROC_COMPOSE). */ /** NFC normalization (@ref UTF8PROC_COMPOSE). */
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFC(const utf8proc_uint8_t *str); UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFC(const utf8proc_uint8_t *str);
/** NFD normalization (@ref UTF8PROC_DECOMPOSE and @ref UTF8PROC_COMPAT). */ /** NFKD normalization (@ref UTF8PROC_DECOMPOSE and @ref UTF8PROC_COMPAT). */
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKD(const utf8proc_uint8_t *str); UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKD(const utf8proc_uint8_t *str);
/** NFD normalization (@ref UTF8PROC_COMPOSE and @ref UTF8PROC_COMPAT). */ /** NFKC normalization (@ref UTF8PROC_COMPOSE and @ref UTF8PROC_COMPAT). */
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC(const utf8proc_uint8_t *str); UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC(const utf8proc_uint8_t *str);
/** @} */ /** @} */
@@ -630,4 +687,3 @@ UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC(const utf8proc_uint8_t *str);
#endif #endif
#endif #endif
+10 -15
View File
@@ -1,7 +1,4 @@
#pragma warning(push) static const utf8proc_uint16_t utf8proc_sequences[] = {
#pragma warning(disable: 4838)
const utf8proc_uint16_t utf8proc_sequences[] = {
97, 98, 99, 100, 101, 102, 103, 97, 98, 99, 100, 101, 102, 103,
104, 105, 106, 107, 108, 109, 110, 111, 104, 105, 106, 107, 108, 109, 110, 111,
112, 113, 114, 115, 116, 117, 118, 119, 112, 113, 114, 115, 116, 117, 118, 119,
@@ -1179,7 +1176,7 @@ const utf8proc_uint16_t utf8proc_sequences[] = {
56603, 55354, 56604, 55354, 56605, 55354, 56606, 55354, 56603, 55354, 56604, 55354, 56605, 55354, 56606, 55354,
56607, 55354, 56608, 55354, 56609, }; 56607, 55354, 56608, 55354, 56609, };
const utf8proc_uint16_t utf8proc_stage1table[] = { static const utf8proc_uint16_t utf8proc_stage1table[] = {
0, 256, 512, 768, 1024, 1280, 1536, 0, 256, 512, 768, 1024, 1280, 1536,
1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584, 1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584,
3840, 4096, 4352, 4608, 4864, 5120, 5376, 5632, 3840, 4096, 4352, 4608, 4864, 5120, 5376, 5632,
@@ -1726,7 +1723,7 @@ const utf8proc_uint16_t utf8proc_stage1table[] = {
18432, 18432, 18432, 18432, 18432, 18432, 18432, 18432, 18432, 18432, 18432, 18432, 18432, 18432, 18432, 18432,
38656, }; 38656, };
const utf8proc_uint16_t utf8proc_stage2table[] = { static const utf8proc_uint16_t utf8proc_stage2table[] = {
1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2,
2, 2, 3, 4, 3, 5, 6, 2, 2, 2, 3, 4, 3, 5, 6, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
@@ -5899,7 +5896,7 @@ const utf8proc_uint16_t utf8proc_stage2table[] = {
540, 540, 540, 1180, 0, 0, 0, 0, 540, 540, 540, 1180, 0, 0, 0, 0,
0, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 0, 1154, 1154, 1154, 1154, 1154, 1154, 1154,
1154, 1154, 1154, 0, 0, 0, 0, 1103, 1154, 1154, 1154, 0, 0, 0, 0, 1103,
1158, 0, 0, 0, 0, 0, 0, 0, 1103, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -6593,7 +6590,7 @@ const utf8proc_uint16_t utf8proc_stage2table[] = {
3984, 3984, 3984, 3984, 3984, 3984, 3984, 0, 3984, 3984, 3984, 3984, 3984, 3984, 3984, 0,
0, }; 0, };
const utf8proc_property_t utf8proc_properties[] = { static const utf8proc_property_t utf8proc_properties[] = {
{0, 0, 0, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false,false,false,false, 0, 0, UTF8PROC_BOUNDCLASS_OTHER}, {0, 0, 0, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false,false,false,false, 0, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_BN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL}, {UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_BN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL},
{UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_BN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL}, {UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_BN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL},
@@ -7850,7 +7847,7 @@ const utf8proc_property_t utf8proc_properties[] = {
{UTF8PROC_CATEGORY_MN, 122, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 122, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND},
{UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 9523, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 9523, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 9525, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 9525, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NOBREAK, 1335, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NOBREAK, 1335, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_MN, 216, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 216, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND},
{UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
@@ -10478,7 +10475,7 @@ const utf8proc_property_t utf8proc_properties[] = {
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1470, UINT16_MAX, 1470, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1470, UINT16_MAX, 1470, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1478, UINT16_MAX, 1478, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1478, UINT16_MAX, 1478, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5132, UINT16_MAX, 5132, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5132, UINT16_MAX, 5132, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1480, UINT16_MAX, 1480, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1480, UINT16_MAX, 1480, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5133, UINT16_MAX, 5133, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5133, UINT16_MAX, 5133, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5134, UINT16_MAX, 5134, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5134, UINT16_MAX, 5134, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1482, UINT16_MAX, 1482, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1482, UINT16_MAX, 1482, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
@@ -12168,7 +12165,7 @@ const utf8proc_property_t utf8proc_properties[] = {
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6787, UINT16_MAX, 6787, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6787, UINT16_MAX, 6787, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6789, UINT16_MAX, 6789, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6789, UINT16_MAX, 6789, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6791, UINT16_MAX, 6791, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6791, UINT16_MAX, 6791, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6793, UINT16_MAX, 6793, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6793, UINT16_MAX, 6793, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6795, UINT16_MAX, 6795, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6795, UINT16_MAX, 6795, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6797, UINT16_MAX, 6797, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6797, UINT16_MAX, 6797, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6799, UINT16_MAX, 6799, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6799, UINT16_MAX, 6799, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
@@ -12204,7 +12201,7 @@ const utf8proc_property_t utf8proc_properties[] = {
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9104, UINT16_MAX, 9104, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9104, UINT16_MAX, 9104, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9106, UINT16_MAX, 9106, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9106, UINT16_MAX, 9106, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9108, UINT16_MAX, 9108, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9108, UINT16_MAX, 9108, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9110, UINT16_MAX, 9110, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9110, UINT16_MAX, 9110, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9112, UINT16_MAX, 9112, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9112, UINT16_MAX, 9112, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9114, UINT16_MAX, 9114, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9114, UINT16_MAX, 9114, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9116, UINT16_MAX, 9116, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9116, UINT16_MAX, 9116, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
@@ -13423,7 +13420,7 @@ const utf8proc_property_t utf8proc_properties[] = {
{UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7975, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7975, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
}; };
const utf8proc_uint16_t utf8proc_combinations[] = { static const utf8proc_uint16_t utf8proc_combinations[] = {
0, 46, 192, 193, 194, 195, 196, 197, 0, 0, 46, 192, 193, 194, 195, 196, 197, 0,
256, 258, 260, 550, 461, 0, 0, 512, 256, 258, 260, 550, 461, 0, 0, 512,
514, 0, 0, 0, 0, 0, 0, 0, 514, 0, 0, 0, 0, 0, 0, 0,
@@ -14386,5 +14383,3 @@ const utf8proc_uint16_t utf8proc_combinations[] = {
72, 75, 72, 75,
1, 53694, 1, 53696, 1, 53694, 1, 53696,
}; };
#pragma warning(pop)