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/opt.exe
builds
bin
+18 -19
View File
@@ -2,7 +2,7 @@
# The Odin Programming Language
Odin is fast, concise, readable, pragmatic and open sourced. It is designed with the intent of replacing C with the following goals:
The Odin programming language is fast, concise, readable, pragmatic and open sourced. It is designed with the intent of replacing C with the following goals:
* simplicity
* high performance
* built for modern systems
@@ -18,6 +18,7 @@ Odin is fast, concise, readable, pragmatic and open sourced. It is designed with
* [Composition & Refactorability](https://www.youtube.com/watch?v=n1wemZfcbXM)
* [Introspection, Modules, and Record Layout](https://www.youtube.com/watch?v=UFq8rhWhx4s)
* [push_allocator & Minimal Dependency Building](https://www.youtube.com/watch?v=f_LGVOAMb78)
* [when, for, & procedure overloading](https://www.youtube.com/watch?v=OzeOekzyZK8)
## Requirements to build and run
@@ -30,27 +31,25 @@ Odin is fast, concise, readable, pragmatic and open sourced. It is designed with
## Warnings
* This is still highly in development and the language's design is quite volatile.
* Syntax is definitely not fixed
* Syntax is not fixed.
## Roadmap
Not in any particular order
Not in any particular order and not be implemented
* Custom backend to replace LLVM
- Improve SSA design to accommodate for lowering to a "bytecode"
- SSA optimizations
- COFF generation
- linker
* Type safe "macros"
* Documentation generator for "Entities"
* Multiple architecture support
* Inline assembly
* Linking options
- Executable
- Static/Dynamic Library
* Debug information
* Compile Time Execution (CTE)
- More metaprogramming madness
- Compiler as a library
- AST inspection and modification
* CTE-based build system
* Replace LLVM backend with my own custom backend
* Improve SSA design to accommodate for lowering to a "bytecode"
* SSA optimizations
* Documentation Generator for "Entities"
* Multiple Architecture support
* Debug Information
- pdb format too
* Command line tooling
* Compiler internals:
* Command Line Tooling
* Compiler Internals:
- Big numbers library
- Multithreading for performance increase
-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" ^
/link %linker_settings% -OUT:%exe_name% ^
&& odin run code/demo.odin
rem && odin build code/Jaze/src/main.odin
rem && odin build_dll code/example.odin ^
rem odin run code/punity.odin
rem odin run code/demo.odin
rem pushd src\asm
rem nasm hellope.asm -fwin64 -o hellope.obj ^
+146 -258
View File
@@ -1,279 +1,167 @@
#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";
#import "atomic.odin";
#import "hash.odin";
#import "math.odin";
#import "mem.odin";
#import "opengl.odin";
#import "os.odin";
#import "strconv.odin";
#import "sync.odin";
main :: proc() {
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() {
// 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 as similar too
s := new_slice(int, 0, 10);
append(s, 1, 2, 6, 3, 6, 5, 5, 5, 5, 1, 2);
fmt.println(s);
when false {
/*
Version 0.1.1
// 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
Added:
* Dynamic Arrays `[dynamic]Type`
* Dynamic Maps `map[Key]Value`
* Dynamic array and map literals
* Custom struct alignemnt `struct #align 8 { bar: i8 }`
* Allow `_` in numbers
* Variadic `append`
* fmt.sprint*
* Entities prefixes with an underscore do not get exported on imports
* Overloaded `free` for pointers, slices, strings, dynamic arrays, and dynamic maps
* enum types have an implict `names` field, a []string of all the names in that enum
* immutable variables are "completely immutable" - rules need a full explanation
* `slice_to_bytes` - convert any slice to a slice of bytes
* `union_cast` allows for optional ok check
* Record type field `names` (struct/raw_union/enum)
* ?: ternary operator
* Unions with variants and common fields
* New built-in procedures
- `delete` to delete map entries `delete(m, key)`
- `clear` to clear dynamic maps and arrays `clear(map_or_array)`
- `reserve` to reserve space for the dynamic maps and arrays `reserve(map_or_array)`
* Unexported entities and fields using an underscore prefix
Removed:
* Maybe/option types
* Remove `type` keyword and other "reserved" keywords
* `compile_assert` and `assert`return the value of the condition for semantic reasons
Changed:
* thread_local -> #thread_local
* #include -> #load
* Files only get checked if they are actually used
* match x in y {} // For type match statements
* Version numbering now starts from 0.1.0 and uses the convention:
- major.minor.patch
* Core library additions to Windows specific stuff
// 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};
Fixes:
* Many fmt.* fixes
* Overloading bug due to comparison of named types
* Overloading bug due to `#import .` collision
* disallow a `cast` from pointers of unions
* Minor bugs in generated IR code for slices
// Slice interals are now just a `ptr+count`
slice: []int; compile_assert(size_of_val(slice) == 2*size_of(int));
To come very Soon:
* 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
}
// 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);
{
Fruit :: enum {
APPLE,
BANANA,
COCONUT,
}
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
INVALID_SOCKET :: ~(0 as SOCKET)
SOCKET :: #type uint;
INVALID_SOCKET :: ~(cast(SOCKET)0);
AF :: enum i32 {
UNSPEC = 0, // unspecified
@@ -35,111 +35,111 @@ AF :: enum i32 {
SIP = 24, // Simple Internet Protocol
PIP = 25, // Help Identify PIP packets
MAX = 26,
}
};
SOCK_STREAM :: 1
SOCKET_ERROR :: -1
IPPROTO_TCP :: 6
AI_PASSIVE :: 0x0020
SOMAXCONN :: 128
SOCK_STREAM :: 1;
SOCKET_ERROR :: -1;
IPPROTO_TCP :: 6;
AI_PASSIVE :: 0x0020;
SOMAXCONN :: 128;
SD_RECEIVE :: 0
SD_SEND :: 1
SD_BOTH :: 2
SD_RECEIVE :: 0;
SD_SEND :: 1;
SD_BOTH :: 2;
WSADESCRIPTION_LEN :: 256
WSASYS_STATUS_LEN :: 128
WSADESCRIPTION_LEN :: 256;
WSASYS_STATUS_LEN :: 128;
WSADATA :: struct #ordered {
version: i16
high_version: i16
version: i16,
high_version: i16,
// NOTE(bill): This is x64 ordering
max_sockets: u16
max_udp_dg: u16
vendor_info: ^byte
description: [WSADESCRIPTION_LEN+1]byte
system_status: [WSASYS_STATUS_LEN+1]byte
max_sockets: u16,
max_udp_dg: u16,
vendor_info: ^byte,
description: [WSADESCRIPTION_LEN+1]byte,
system_status: [WSASYS_STATUS_LEN+1]byte,
}
addrinfo :: struct #ordered {
flags: i32
family: i32
socktype: i32
protocol: i32
addrlen: uint
canonname: ^u8
addr: ^sockaddr
next: ^addrinfo
flags: i32,
family: i32,
socktype: i32,
protocol: i32,
addrlen: uint,
canonname: ^u8,
addr: ^sockaddr,
next: ^addrinfo,
}
sockaddr :: struct #ordered {
family: u16
data: [14]byte
family: u16,
data: [14]byte,
}
WSAStartup :: proc(version_requested: i16, data: ^WSADATA) -> i32 #foreign #dll_import
WSACleanup :: proc() -> i32 #foreign #dll_import
getaddrinfo :: proc(node_name, service_name: ^u8, hints: ^addrinfo, result: ^^addrinfo) -> i32 #foreign #dll_import
freeaddrinfo :: proc(ai: ^addrinfo) #foreign #dll_import
socket :: proc(af, type_, protocol: i32) -> SOCKET #foreign #dll_import
closesocket :: proc(s: SOCKET) -> i32 #foreign #dll_import
bind :: proc(s: SOCKET, name: ^sockaddr, name_len: i32) -> i32 #foreign #dll_import
listen :: proc(s: SOCKET, back_log: i32) -> i32 #foreign #dll_import
accept :: proc(s: SOCKET, addr: ^sockaddr, addr_len: i32) -> SOCKET #foreign #dll_import
recv :: proc(s: SOCKET, buf: ^byte, len: i32, flags: i32) -> i32 #foreign #dll_import
send :: proc(s: SOCKET, buf: ^byte, len: i32, flags: i32) -> i32 #foreign #dll_import
shutdown :: proc(s: SOCKET, how: i32) -> i32 #foreign #dll_import
WSAGetLastError :: proc() -> i32 #foreign #dll_import
WSAStartup :: proc(version_requested: i16, data: ^WSADATA) -> i32 #foreign ws2;
WSACleanup :: proc() -> i32 #foreign ws2;
getaddrinfo :: proc(node_name, service_name: ^u8, hints: ^addrinfo, result: ^^addrinfo) -> i32 #foreign ws2;
freeaddrinfo :: proc(ai: ^addrinfo) #foreign ws2;
socket :: proc(af, type_, protocol: i32) -> SOCKET #foreign ws2;
closesocket :: proc(s: SOCKET) -> i32 #foreign ws2;
bind :: proc(s: SOCKET, name: ^sockaddr, name_len: i32) -> i32 #foreign ws2;
listen :: proc(s: SOCKET, back_log: i32) -> i32 #foreign ws2;
accept :: proc(s: SOCKET, addr: ^sockaddr, addr_len: i32) -> SOCKET #foreign ws2;
recv :: proc(s: SOCKET, buf: ^byte, len: i32, flags: i32) -> i32 #foreign ws2;
send :: proc(s: SOCKET, buf: ^byte, len: i32, flags: i32) -> i32 #foreign ws2;
shutdown :: proc(s: SOCKET, how: i32) -> i32 #foreign ws2;
WSAGetLastError :: proc() -> i32 #foreign ws2;
to_c_string :: proc(s: string) -> ^byte {
c_str := new_slice(byte, s.count+1)
assert(c_str.data != nil)
copy(c_str, s as []byte)
c_str[s.count] = 0
return c_str.data
c_str := new_slice(byte, s.count+1);
assert(c_str.data != nil);
copy(c_str, cast([]byte)s);
c_str[s.count] = 0;
return c_str.data;
}
run :: proc() {
wsa: WSADATA
res: ^addrinfo = nil
hints: addrinfo
s, client: SOCKET
wsa: WSADATA;
res: ^addrinfo = nil;
hints: addrinfo;
s, client: SOCKET;
if WSAStartup(2 | (2 << 8), ^wsa) != 0 {
fmt.println("WSAStartup failed: ", WSAGetLastError())
return
fmt.println("WSAStartup failed: ", WSAGetLastError());
return;
}
defer WSACleanup()
defer WSACleanup();
hints.family = AF.INET as i32
hints.socktype = SOCK_STREAM
hints.protocol = IPPROTO_TCP
hints.flags = AI_PASSIVE
hints.family = cast(i32)AF.INET;
hints.socktype = SOCK_STREAM;
hints.protocol = IPPROTO_TCP;
hints.flags = AI_PASSIVE;
if getaddrinfo(nil, to_c_string("8080"), ^hints, ^res) != 0 {
fmt.println("getaddrinfo failed: ", WSAGetLastError())
return
fmt.println("getaddrinfo failed: ", WSAGetLastError());
return;
}
defer freeaddrinfo(res)
defer freeaddrinfo(res);
s = socket(res.family, res.socktype, res.protocol)
s = socket(res.family, res.socktype, res.protocol);
if s == INVALID_SOCKET {
fmt.println("socket failed: ", WSAGetLastError())
return
fmt.println("socket failed: ", WSAGetLastError());
return;
}
defer closesocket(s)
defer closesocket(s);
bind(s, res.addr, res.addrlen as i32)
listen(s, SOMAXCONN)
bind(s, res.addr, cast(i32)res.addrlen);
listen(s, SOMAXCONN);
client = accept(s, nil, 0)
client = accept(s, nil, 0);
if client == INVALID_SOCKET {
fmt.println("socket failed: ", WSAGetLastError())
return
fmt.println("socket failed: ", WSAGetLastError());
return;
}
defer closesocket(client)
defer closesocket(client);
html :=
`HTTP/1.1 200 OK
@@ -154,27 +154,27 @@ Content-type: text/html
<h1 style="color: orange;">Odin Server Demo</h1>
</body>
</html>
`
`;
buf: [1024]byte
buf: [1024]byte;
for {
bytes := recv(client, ^buf[0], buf.count as i32, 0)
bytes := recv(client, ^buf[0], cast(i32)buf.count, 0);
if bytes > 0 {
// fmt.println(buf[:bytes] as string)
bytes_sent := send(client, html.data, (html.count-1) as i32, 0)
bytes_sent := send(client, html.data, cast(i32)(html.count-1), 0);
if bytes_sent == SOCKET_ERROR {
fmt.println("send failed: ", WSAGetLastError())
return
fmt.println("send failed: ", WSAGetLastError());
return;
}
break
break;
} else if bytes == 0 {
fmt.println("Connection closing...")
break
fmt.println("Connection closing...");
break;
} else {
fmt.println("recv failed: ", WSAGetLastError())
return
fmt.println("recv failed: ", WSAGetLastError());
return;
}
}
shutdown(client, SD_SEND)
shutdown(client, SD_SEND);
}
+17 -14
View File
@@ -6,21 +6,24 @@
// #import "punity.odin" as pn;
main :: proc() {
// struct_padding()
// bounds_checking()
// type_introspection()
// any_type()
// crazy_introspection()
// namespaces_and_files()
// miscellany()
// ht.run()
// game.run()
// {
// init :: proc(c: ^pn.Core) {}
// step :: proc(c: ^pn.Core) {}
struct_padding();
bounds_checking();
type_introspection();
any_type();
crazy_introspection();
namespaces_and_files();
miscellany();
// pn.run(init, step)
// }
/*
ht.run();
game.run();
{
init :: proc(c: ^pn.Core) {}
step :: proc(c: ^pn.Core) {}
pn.run(init, step);
}
*/
}
struct_padding :: proc() {
+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);
window_buffer := new_slice(u32, CANVAS_WIDTH * CANVAS_HEIGHT);
assert(window_buffer.data != nil);
defer free(window_buffer.data);
defer free(window_buffer);
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() {
format.println("Hello2!")
main :: proc() {
fmt.println("hello, world!");
}
+447 -109
View File
@@ -4,6 +4,7 @@
#import "fmt.odin";
#import "mem.odin";
#import "utf8.odin";
#import "hash.odin";
// IMPORTANT NOTE(bill): `type_info` & `type_info_val` cannot be used within a
// #shared_global_scope due to the internals of the compiler.
@@ -13,24 +14,11 @@
// IMPORTANT NOTE(bill): Do not change the order of any of this data
// The compiler relies upon this _exact_ order
Type_Info_Member :: struct #ordered {
name: string, // can be empty if tuple
type_info: ^Type_Info,
offset: int, // offsets 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 {
f: f64,
i: i64,
}
// NOTE(bill): This much the same as the compiler's
// NOTE(bill): This must match the compiler's
Calling_Convention :: enum {
ODIN = 0,
C = 1,
@@ -38,69 +26,79 @@ Calling_Convention :: enum {
FAST = 3,
}
Type_Info_Record :: struct #ordered {
types: []^Type_Info,
names: []string,
offsets: []int, // offsets may not be used in tuples
size: int, // in bytes
align: int, // in bytes
packed: bool,
ordered: bool,
custom_align: bool,
}
Type_Info :: union {
Named: struct #ordered {
name: string,
base: ^Type_Info, // This will _not_ be a Type_Info.Named
},
Integer: struct #ordered {
size: int, // in bytes
signed: bool,
},
Float: struct #ordered {
size: int, // in bytes
},
Any: struct #ordered {},
String: struct #ordered {},
Boolean: struct #ordered {},
Pointer: struct #ordered {
Named{name: string, base: ^Type_Info},
Integer{size: int, signed: bool},
Float{size: int},
String{},
Boolean{},
Any{},
Pointer{
elem: ^Type_Info, // nil -> rawptr
},
Maybe: struct #ordered {
elem: ^Type_Info,
},
Procedure: struct #ordered {
Procedure{
params: ^Type_Info, // Type_Info.Tuple
results: ^Type_Info, // Type_Info.Tuple
variadic: bool,
convention: Calling_Convention,
},
Array: struct #ordered {
Array{
elem: ^Type_Info,
elem_size: int,
count: int,
},
Slice: struct #ordered {
elem: ^Type_Info,
elem_size: int,
Dynamic_Array{elem: ^Type_Info, elem_size: int},
Slice {elem: ^Type_Info, elem_size: int},
Vector {elem: ^Type_Info, elem_size, count, align: int},
Tuple {using record: Type_Info_Record}, // Only really used for procedures
Struct {using record: Type_Info_Record},
Raw_Union {using record: Type_Info_Record},
Union{
common_fields: struct {
types: []^Type_Info,
names: []string,
offsets: []int, // offsets may not be used in tuples
},
variant_names: []string,
variant_types: []^Type_Info,
size: int,
align: int,
},
Vector: struct #ordered {
elem: ^Type_Info,
elem_size: int,
count: int,
align: int,
},
Tuple: Type_Info_Record,
Struct: Type_Info_Record,
Union: Type_Info_Record,
Raw_Union: Type_Info_Record,
Enum: struct #ordered {
base: ^Type_Info,
names: []string,
Enum{
base: ^Type_Info,
names: []string,
values: []Type_Info_Enum_Value,
},
Map{
key: ^Type_Info,
value: ^Type_Info,
generated_struct: ^Type_Info,
count: int, // == 0 if dynamic
},
}
// // NOTE(bill): only the ones that are needed (not all types)
// // This will be set by the compiler
// immutable __type_infos: []Type_Info;
// NOTE(bill): only the ones that are needed (not all types)
// This will be set by the compiler
__type_table: []Type_Info;
type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
if info == nil {
return nil;
}
base := info;
match type i in base {
match i in base {
case Type_Info.Named:
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";
@@ -115,16 +128,22 @@ __debug_trap :: proc() #foreign __llvm_core "llvm.debugtrap";
__trap :: proc() #foreign __llvm_core "llvm.trap";
read_cycle_counter :: proc() -> u64 #foreign __llvm_core "llvm.readcyclecounter";
__cpuid :: proc(level: u32, sig: ^u32) -> i32 #foreign __llvm_core "__get_cpuid";
// IMPORTANT NOTE(bill): Must be in this order (as the compiler relies upon it)
Allocator_Mode :: enum u8 {
ALLOC,
FREE,
FREE_ALL,
RESIZE,
}
Allocator_Proc :: type proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, flags: u64) -> rawptr;
Allocator_Proc :: #type proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, flags: u64) -> rawptr;
Allocator :: struct #ordered {
procedure: Allocator_Proc,
data: rawptr,
@@ -139,7 +158,7 @@ Context :: struct #ordered {
user_index: int,
}
thread_local __context: Context;
#thread_local __context: Context;
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);
}
free :: proc(ptr: rawptr) #inline {
__check_context();
a := context.allocator;
if ptr != nil {
a.procedure(a.data, Allocator_Mode.FREE, 0, 0, ptr, 0, 0);
free_ptr_with_allocator :: proc(a: Allocator, ptr: rawptr) #inline {
if ptr == nil {
return;
}
if a.procedure == nil {
return;
}
a.procedure(a.data, Allocator_Mode.FREE, 0, 0, ptr, 0, 0);
}
free_ptr :: proc(ptr: rawptr) #inline {
__check_context();
free_ptr_with_allocator(context.allocator, ptr);
}
free_all :: proc() #inline {
__check_context();
a := context.allocator;
@@ -217,46 +244,21 @@ default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
using Allocator_Mode;
when false {
match mode {
case ALLOC:
total_size := size + alignment + size_of(mem.AllocationHeader);
ptr := os.heap_alloc(total_size);
header := (^mem.AllocationHeader)(ptr);
ptr = mem.align_forward(header+1, alignment);
mem.allocation_header_fill(header, ptr, size);
return mem.zero(ptr, size);
match mode {
case ALLOC:
return os.heap_alloc(size);
case FREE:
os.heap_free(mem.allocation_header(old_memory));
return nil;
case FREE:
os.heap_free(old_memory);
return nil;
case FREE_ALL:
// NOTE(bill): Does nothing
case FREE_ALL:
// NOTE(bill): Does nothing
case RESIZE:
total_size := size + alignment + size_of(mem.AllocationHeader);
ptr := os.heap_resize(mem.allocation_header(old_memory), total_size);
header := (^mem.AllocationHeader)(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);
}
case RESIZE:
ptr := os.heap_resize(old_memory, size);
assert(ptr != nil);
return ptr;
}
return nil;
@@ -286,11 +288,11 @@ __string_eq :: proc(a, b: string) -> bool {
if a.data == b.data {
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 {
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); }
@@ -305,34 +307,370 @@ __assert :: proc(file: string, line, column: int, msg: string) #inline {
file, line, column, msg);
__debug_trap();
}
__panic :: proc(file: string, line, column: int, msg: string) #inline {
fmt.fprintf(os.stderr, "%s(%d:%d) Panic: %s\n",
file, line, column, msg);
__debug_trap();
}
__bounds_check_error :: proc(file: string, line, column: int, index, count: int) {
if 0 <= index && index < count {
return;
}
fmt.fprintf(os.stderr, "%s(%d:%d) Index %d is out of bounds range 0..<%d\n",
fmt.fprintf(os.stderr, "%s(%d:%d) Index %d is out of bounds range 0..%d\n",
file, line, column, index, count);
__debug_trap();
}
__slice_expr_error :: proc(file: string, line, column: int, low, high: int) {
if 0 <= low && low <= high {
__slice_expr_error :: proc(file: string, line, column: int, low, high, max: int) {
if 0 <= low && low <= high && high <= max {
return;
}
fmt.fprintf(os.stderr, "%s(%d:%d) Invalid slice indices: [%d:%d]\n",
file, line, column, low, high);
fmt.fprintf(os.stderr, "%s(%d:%d) Invalid slice indices: [%d..%d..%d]\n",
file, line, column, low, high, max);
__debug_trap();
}
__substring_expr_error :: proc(file: string, line, column: int, low, high: int) {
if 0 <= low && low <= high {
return;
}
fmt.fprintf(os.stderr, "%s(%d:%d) Invalid substring indices: [%d:%d]\n",
fmt.fprintf(os.stderr, "%s(%d:%d) Invalid substring indices: [%d..%d]\n",
file, line, column, low, high);
__debug_trap();
}
__union_cast_check :: proc(ok: bool, file: string, line, column: int, from, to: ^Type_Info) {
if !ok {
fmt.fprintf(os.stderr, "%s(%d:%d) Invalid `union_cast` from %T to %T\n",
file, line, column, from, to);
__debug_trap();
}
}
__string_decode_rune :: proc(s: string) -> (rune, int) #inline {
return utf8.decode_rune(s);
}
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
yield_thread :: proc() { win32._mm_pause(); }
yield_thread :: proc() { win32.mm_pause(); }
mfence :: proc() { win32.ReadWriteBarrier(); }
sfence :: proc() { win32.WriteBarrier(); }
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);
counter := 0;
for old_value != 0 && (time_out < 0 || counter < time_out) {
counter += 1;
counter++;
yield_thread();
old_value = compare_exchange(a, 1, 0);
mfence();
@@ -81,7 +81,7 @@ spin_lock :: proc(a: ^i64, time_out: int) -> bool { // NOTE(bill) time_out = -1
old_value := compare_exchange(a, 1, 0);
counter := 0;
for old_value != 0 && (time_out < 0 || counter < time_out) {
counter += 1;
counter++;
yield_thread();
old_value = compare_exchange(a, 1, 0);
mfence();
+257
View File
@@ -0,0 +1,257 @@
// #import "fmt.odin";
// Multiple precision decimal numbers
// NOTE: This is only for floating point printing and nothing else
Decimal :: struct {
digits: [384]byte, // big-endian digits
count: int,
decimal_point: int,
neg, trunc: bool,
}
decimal_to_string :: proc(buf: []byte, a: ^Decimal) -> string {
digit_zero :: proc(buf: []byte) -> int {
for _, i in buf {
buf[i] = '0';
}
return buf.count;
}
n := 10 + a.count + abs(a.decimal_point);
// TODO(bill): make this work with a buffer that's not big enough
assert(buf.count >= n);
buf = buf[..n];
if a.count == 0 {
buf[0] = '0';
return cast(string)buf[0..1];
}
w := 0;
if a.decimal_point <= 0 {
buf[w] = '0'; w++;
buf[w] = '.'; w++;
w += digit_zero(buf[w .. w-a.decimal_point]);
w += copy(buf[w..], a.digits[0..a.count]);
} else if a.decimal_point < a.count {
w += copy(buf[w..], a.digits[0..a.decimal_point]);
buf[w] = '.'; w++;
w += copy(buf[w..], a.digits[a.decimal_point .. a.count]);
} else {
w += copy(buf[w..], a.digits[0..a.count]);
w += digit_zero(buf[w .. w+a.decimal_point-a.count]);
}
return cast(string)buf[0..w];
}
// trim trailing zeros
trim :: proc(a: ^Decimal) {
for a.count > 0 && a.digits[a.count-1] == '0' {
a.count--;
}
if a.count == 0 {
a.decimal_point = 0;
}
}
assign :: proc(a: ^Decimal, i: u64) {
buf: [32]byte;
n := 0;
for i > 0 {
j := i/10;
i -= 10*j;
buf[n] = cast(byte)('0'+i);
n++;
i = j;
}
a.count = 0;
for n--; n >= 0; n-- {
a.digits[a.count] = buf[n];
a.count++;
}
a.decimal_point = a.count;
trim(a);
}
uint_size :: 8*size_of(uint);
max_shift :: uint_size-4;
shift_right :: proc(a: ^Decimal, k: uint) {
r := 0; // read index
w := 0; // write index
n: uint;
for ; n>>k == 0; r++ {
if r >= a.count {
if n == 0 {
// Just in case
a.count = 0;
return;
}
for n>>k == 0 {
n = n * 10;
r++;
}
break;
}
c := cast(uint)a.digits[r];
n = n*10 + c - '0';
}
a.decimal_point -= r-1;
mask: uint = (1<<k) - 1;
for ; r < a.count; r++ {
c := cast(uint)a.digits[r];
dig := n>>k;
n &= mask;
a.digits[w] = cast(byte)('0' + dig);
w++;
n = n*10 + c - '0';
}
for n > 0 {
dig := n>>k;
n &= mask;
if w < a.digits.count {
a.digits[w] = cast(byte)('0' + dig);
w++;
} else if dig > 0 {
a.trunc = true;
}
n *= 10;
}
a.count = w;
trim(a);
}
shift_left :: proc(a: ^Decimal, k: uint) {
delta := cast(int)(k/4);
r := a.count; // read index
w := a.count+delta; // write index
n: uint;
for r--; r >= 0; r-- {
n += (cast(uint)a.digits[r] - '0') << k;
quo := n/10;
rem := n - 10*quo;
w--;
if w < a.digits.count {
a.digits[w] = cast(byte)('0' + rem);
} else if rem != 0 {
a.trunc = true;
}
n = quo;
}
for n > 0 {
quo := n/10;
rem := n - 10*quo;
w--;
if w < a.digits.count {
a.digits[w] = cast(byte)('0' + rem);
} else if rem != 0 {
a.trunc = true;
}
n = quo;
}
a.count += delta;
a.count = min(a.count, a.digits.count);
a.decimal_point += delta;
trim(a);
}
shift :: proc(a: ^Decimal, k: int) {
match {
case a.count == 0:
// no need to update
case k > 0:
for k > max_shift {
shift_left(a, max_shift);
k -= max_shift;
}
shift_left(a, cast(uint)k);
case k < 0:
for k < -max_shift {
shift_right(a, max_shift);
k += max_shift;
}
shift_right(a, cast(uint)-k);
}
}
can_round_up :: proc(a: ^Decimal, nd: int) -> bool {
if nd < 0 || nd >= a.count { return false ; }
if a.digits[nd] == '5' && nd+1 == a.count {
if a.trunc {
return true;
}
return nd > 0 && (a.digits[nd-1]-'0')%2 != 0;
}
return a.digits[nd] >= '5';
}
round :: proc(a: ^Decimal, nd: int) {
if nd < 0 || nd >= a.count { return; }
if can_round_up(a, nd) {
round_up(a, nd);
} else {
round_down(a, nd);
}
}
round_up :: proc(a: ^Decimal, nd: int) {
if nd < 0 || nd >= a.count { return; }
for i := nd-1; i >= 0; i-- {
if c := a.digits[i]; c < '9' {
a.digits[i]++;
a.count = i+1;
return;
}
}
// Number is just 9s
a.digits[0] = '1';
a.count = 1;
a.decimal_point++;
}
round_down :: proc(a: ^Decimal, nd: int) {
if nd < 0 || nd >= a.count { return; }
a.count = nd;
trim(a);
}
// Extract integer part, rounded appropriately. There are no guarantees about overflow.
rounded_integer :: proc(a: ^Decimal) -> u64 {
if a.decimal_point > 20 {
return 0xffff_ffff_ffff_ffff;
}
i: int;
n: u64 = 0;
m := min(a.decimal_point, a.count);
for i = 0; i < m; i++ {
n = n*10 + cast(u64)(a.digits[i]-'0');
}
for ; i < a.decimal_point; i++ {
n *= 10;
}
if can_round_up(a, a.decimal_point) {
n++;
}
return n;
}
+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;
s := slice_ptr(cast(^u8)data, len);
for i in 0..<len {
b := cast(u32)s[i];
result = result>>8 ~ __CRC32_TABLE[(result ~ b) & 0xff];
for b in data {
result = result>>8 ~ _crc32_table[(result ~ cast(u32)b) & 0xff];
}
return ~result;
}
crc64 :: proc(data: rawptr, len: int) -> u64 {
crc64 :: proc(data: []byte) -> u64 {
result := ~cast(u64)0;
s := slice_ptr(cast(^u8)data, len);
for i in 0..<len {
b := cast(u64)s[i];
result = result>>8 ~ __CRC64_TABLE[(result ~ b) & 0xff];
for b in data {
result = result>>8 ~ _crc64_table[(result ~ cast(u64)b) & 0xff];
}
return ~result;
}
fnv32 :: proc(data: rawptr, len: int) -> u32 {
s := slice_ptr(cast(^u8)data, len);
fnv32 :: proc(data: []byte) -> u32 {
h: u32 = 0x811c9dc5;
for i in 0..<len {
h = (h * 0x01000193) ~ cast(u32)s[i];
for b in data {
h = (h * 0x01000193) ~ cast(u32)b;
}
return h;
}
fnv64 :: proc(data: rawptr, len: int) -> u64 {
s := slice_ptr(cast(^u8)data, len);
fnv64 :: proc(data: []byte) -> u64 {
h: u64 = 0xcbf29ce484222325;
for i in 0..<len {
h = (h * 0x100000001b3) ~ cast(u64)s[i];
for b in data {
h = (h * 0x100000001b3) ~ cast(u64)b;
}
return h;
}
fnv32a :: proc(data: rawptr, len: int) -> u32 {
s := slice_ptr(cast(^u8)data, len);
fnv32a :: proc(data: []byte) -> u32 {
h: u32 = 0x811c9dc5;
for i in 0..<len {
h = (h ~ cast(u32)s[i]) * 0x01000193;
for b in data {
h = (h ~ cast(u32)b) * 0x01000193;
}
return h;
}
fnv64a :: proc(data: rawptr, len: int) -> u64 {
s := slice_ptr(cast(^u8)data, len);
h :u64 = 0xcbf29ce484222325;
for i in 0..<len {
h = (h ~ cast(u64)s[i]) * 0x100000001b3;
fnv64a :: proc(data: []byte) -> u64 {
h: u64 = 0xcbf29ce484222325;
for b in data {
h = (h ~ cast(u64)b) * 0x100000001b3;
}
return h;
}
murmur32 :: proc(data: []byte) -> u32 {
c1_32: u32 : 0xcc9e2d51;
c2_32: u32 : 0x1b873593;
murmur64 :: proc(data_: rawptr, len: int) -> u64 {
h1: u32 = 0;
nblocks := data.count/4;
p := data.data;
p1 := p + 4*nblocks;
for ; p < p1; p += 4 {
k1 := (cast(^u32)p)^;
k1 *= c1_32;
k1 = (k1 << 15) | (k1 >> 17);
k1 *= c2_32;
h1 ~= k1;
h1 = (h1 << 13) | (h1 >> 19);
h1 = h1*5 + 0xe6546b64;
}
tail := data[nblocks*4 ..];
k1: u32;
match tail.count&3 {
case 3:
k1 ~= cast(u32)tail[2] << 16;
fallthrough;
case 2:
k1 ~= cast(u32)tail[2] << 8;
fallthrough;
case 1:
k1 ~= cast(u32)tail[0];
k1 *= c1_32;
k1 = (k1 << 15) | (k1 >> 17) ;
k1 *= c2_32;
h1 ~= k1;
}
h1 ~= cast(u32)data.count;
h1 ~= h1 >> 16;
h1 *= 0x85ebca6b;
h1 ~= h1 >> 13;
h1 *= 0xc2b2ae35;
h1 ~= h1 >> 16;
return h1;
}
murmur64 :: proc(data: []byte) -> u64 {
SEED :: 0x9747b28c;
when size_of(int) == 8 {
when false && size_of(int) == 8 {
m :: 0xc6a4a7935bd1e995;
r :: 47;
h: u64 = SEED ~ (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));
data2 := slice_ptr(cast(^u8)data_, len);
for i in 0 ..< data.count {
k := data[i];
for _, i in data64 {
k := data64[i];
k *= m;
k ~= k>>r;
@@ -81,15 +116,15 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
h *= m;
}
match len & 7 {
case 7: h ~= cast(u64)data2[6] << 48; fallthrough;
case 6: h ~= cast(u64)data2[5] << 40; fallthrough;
case 5: h ~= cast(u64)data2[4] << 32; fallthrough;
case 4: h ~= cast(u64)data2[3] << 24; fallthrough;
case 3: h ~= cast(u64)data2[2] << 16; fallthrough;
case 2: h ~= cast(u64)data2[1] << 8; fallthrough;
match data.count&7 {
case 7: h ~= cast(u64)data[6] << 48; fallthrough;
case 6: h ~= cast(u64)data[5] << 40; fallthrough;
case 5: h ~= cast(u64)data[4] << 32; fallthrough;
case 4: h ~= cast(u64)data[3] << 24; fallthrough;
case 3: h ~= cast(u64)data[2] << 16; fallthrough;
case 2: h ~= cast(u64)data[1] << 8; fallthrough;
case 1:
h ~= cast(u64)data2[0];
h ~= cast(u64)data[0];
h *= m;
}
@@ -102,15 +137,16 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
m :: 0x5bd1e995;
r :: 24;
h1: u32 = cast(u32)SEED ~ cast(u32)len;
h1: u32 = cast(u32)SEED ~ cast(u32)data.count;
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;
for len >= 8 {
k1, k2: u32;
k1 = data[i]; i += 1;
k1 = data32[i]; i++;
k1 *= m;
k1 ~= k1>>r;
k1 *= m;
@@ -118,7 +154,7 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
h1 ~= k1;
len -= 4;
k2 = data[i]; i += 1;
k2 = data32[i]; i++;
k2 *= m;
k2 ~= k2>>r;
k2 *= m;
@@ -129,7 +165,7 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
if len >= 4 {
k1: u32;
k1 = data[i]; i += 1;
k1 = data32[i]; i++;
k1 *= m;
k1 ~= k1>>r;
k1 *= m;
@@ -138,11 +174,14 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
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 {
case 3: h2 ~= cast(u32)data8[2] << 16; fallthrough;
case 2: h2 ~= cast(u32)data8[1] << 8; fallthrough;
case 3:
h2 ~= cast(u32)data8[2] << 16;
fallthrough;
case 2:
h2 ~= cast(u32)data8[1] << 8;
fallthrough;
case 1:
h2 ~= cast(u32)data8[0];
h2 *= m;
@@ -163,8 +202,7 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
}
__CRC32_TABLE := [256]u32{
immutable _crc32_table := [256]u32{
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
@@ -230,7 +268,7 @@ __CRC32_TABLE := [256]u32{
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
};
__CRC64_TABLE := [256]u64{
immutable _crc64_table := [256]u64{
0x0000000000000000, 0x42f0e1eba9ea3693, 0x85e1c3d753d46d26, 0xc711223cfa3e5bb5,
0x493366450e42ecdf, 0x0bc387aea7a8da4c, 0xccd2a5925d9681f9, 0x8e224479f47cb76a,
0x9266cc8a1c85d9be, 0xd0962d61b56fef2d, 0x17870f5d4f51b498, 0x5577eeb6e6bb820b,
+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: 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: f64) -> f64 #foreign __llvm_core "llvm.fmuladd.f64";
@@ -155,8 +151,8 @@ mat4_identity :: proc() -> Mat4 {
}
mat4_transpose :: proc(m: Mat4) -> Mat4 {
for j in 0..<4 {
for i in 0..<4 {
for j in 0..4 {
for i in 0..4 {
m[i][j], m[j][i] = m[j][i], m[i][j];
}
}
@@ -165,8 +161,8 @@ mat4_transpose :: proc(m: Mat4) -> Mat4 {
mul :: proc(a, b: Mat4) -> Mat4 {
c: Mat4;
for j in 0..<4 {
for i in 0..<4 {
for j in 0..4 {
for i in 0..4 {
c[j][i] = a[0][i]*b[j][0] +
a[1][i]*b[j][1] +
a[2][i]*b[j][2] +
+46 -44
View File
@@ -1,6 +1,11 @@
#import "fmt.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" {
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);
@@ -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" {
// 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(dst, src, len, 1, false);
return dst;
}
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(dst, src, len, 1, false);
return dst;
}
compare :: proc(dst, src: rawptr, n: int) -> int #link_name "__mem_compare" {
a := slice_ptr(cast(^byte)dst, n);
b := slice_ptr(cast(^byte)src, n);
for i in 0..<n {
compare :: proc(a, b: []byte) -> int #link_name "__mem_compare" {
n := min(a.count, b.count);
for i in 0..n {
match {
case a[i] < b[i]:
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; }
megabytes :: proc(x: int) -> int #inline { return kilobytes(x) * 1024; }
gigabytes :: proc(x: int) -> int #inline { return gigabytes(x) * 1024; }
terabytes :: proc(x: int) -> int #inline { return terabytes(x) * 1024; }
gigabytes :: proc(x: int) -> int #inline { return megabytes(x) * 1024; }
terabytes :: proc(x: int) -> int #inline { return gigabytes(x) * 1024; }
is_power_of_two :: proc(x: int) -> bool {
if x <= 0 {
@@ -75,11 +79,14 @@ allocation_header_fill :: proc(header: ^Allocation_Header, data: rawptr, size: i
header.size = size;
ptr := cast(^int)(header+1);
for i := 0; cast(rawptr)ptr < data; i += 1 {
for i := 0; cast(rawptr)ptr < data; i++ {
(ptr+i)^ = -1;
}
}
allocation_header :: proc(data: rawptr) -> ^Allocation_Header {
if data == nil {
return nil;
}
p := cast(^int)data;
for (p-1)^ == -1 {
p = (p-1);
@@ -110,7 +117,7 @@ Arena_Temp_Memory :: struct {
init_arena_from_memory :: proc(using a: ^Arena, data: []byte) {
backing = Allocator{};
memory = data[:0];
memory = data[..0];
temp_count = 0;
}
@@ -123,8 +130,8 @@ init_arena_from_context :: proc(using a: ^Arena, size: int) {
free_arena :: proc(using a: ^Arena) {
if backing.procedure != nil {
push_allocator backing {
free(memory.data);
memory = memory[0:0];
free(memory);
memory = nil;
offset = 0;
}
}
@@ -176,7 +183,7 @@ begin_arena_temp_memory :: proc(a: ^Arena) -> Arena_Temp_Memory {
tmp: Arena_Temp_Memory;
tmp.arena = a;
tmp.original_count = a.memory.count;
a.temp_count += 1;
a.temp_count++;
return tmp;
}
@@ -184,7 +191,7 @@ end_arena_temp_memory :: proc(using tmp: Arena_Temp_Memory) {
assert(arena.memory.count >= original_count);
assert(arena.temp_count > 0);
arena.memory.count = original_count;
arena.temp_count -= 1;
arena.temp_count--;
}
@@ -210,8 +217,7 @@ align_of_type_info :: proc(type_info: ^Type_Info) -> int {
WORD_SIZE :: size_of(int);
MAX_ALIGN :: size_of([vector 64]f64); // TODO(bill): Should these constants be builtin constants?
using Type_Info;
match type info in type_info {
match info in type_info {
case Named:
return align_of_type_info(info.base);
case Integer:
@@ -222,14 +228,16 @@ align_of_type_info :: proc(type_info: ^Type_Info) -> int {
return WORD_SIZE;
case Boolean:
return 1;
case Any:
return WORD_SIZE;
case Pointer:
return WORD_SIZE;
case Maybe:
return max(align_of_type_info(info.elem), 1);
case Procedure:
return WORD_SIZE;
case Array:
return align_of_type_info(info.elem);
case Dynamic_Array:
return WORD_SIZE;
case Slice:
return WORD_SIZE;
case Vector:
@@ -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);
total := size * count;
return clamp(total, 1, MAX_ALIGN);
case Tuple:
return info.align;
case Struct:
return info.align;
case Union:
return info.align;
case Raw_Union:
return info.align;
case Enum:
return align_of_type_info(info.base);
case Map:
return align_of_type_info(info.generated_struct);
}
return 0;
@@ -256,23 +270,21 @@ align_formula :: proc(size, align: int) -> int {
size_of_type_info :: proc(type_info: ^Type_Info) -> int {
WORD_SIZE :: size_of(int);
using Type_Info;
match type info in type_info {
match info in type_info {
case Named:
return size_of_type_info(info.base);
case Integer:
return info.size;
case Float:
return info.size;
case Any:
return 2*WORD_SIZE;
case String:
return 2*WORD_SIZE;
case Boolean:
return 1;
case Any:
return 2*WORD_SIZE;
case Pointer:
return WORD_SIZE;
case Maybe:
return size_of_type_info(info.elem) + 1;
case Procedure:
return WORD_SIZE;
case Array:
@@ -284,39 +296,29 @@ size_of_type_info :: proc(type_info: ^Type_Info) -> int {
align := align_of_type_info(info.elem);
alignment := align_formula(size, align);
return alignment*(count-1) + size;
case Dynamic_Array:
return size_of(rawptr) + 2*size_of(int) + size_of(Allocator);
case Slice:
return 3*WORD_SIZE;
return 2*WORD_SIZE;
case Vector:
is_bool :: proc(type_info: ^Type_Info) -> bool {
match type info in type_info {
case Named:
return is_bool(info.base);
case Boolean:
return true;
}
return false;
}
count := info.count;
if count == 0 {
return 0;
}
bit_size := 8*size_of_type_info(info.elem);
if is_bool(info.elem) {
// NOTE(bill): LLVM can store booleans as 1 bit because a boolean _is_ an `i1`
// Silly LLVM spec
bit_size = 1;
}
total_size_in_bits := bit_size * count;
total_size := (total_size_in_bits+7)/8;
return total_size;
size := size_of_type_info(info.elem);
align := align_of_type_info(info.elem);
alignment := align_formula(size, align);
return alignment*(count-1) + size;
case Struct:
return info.size;
case Union:
return info.size;
case Raw_Union:
return info.size;
case Enum:
return size_of_type_info(info.base);
case Map:
return size_of_type_info(info.generated_struct);
}
return 0;
+90 -89
View File
@@ -1,6 +1,7 @@
#foreign_system_library lib "opengl32.lib" when ODIN_OS == "windows";
#import win32 "sys/windows.odin" when ODIN_OS == "windows";
#include "opengl_constants.odin";
#import "sys/wgl.odin" when ODIN_OS == "windows";
#load "opengl_constants.odin";
Clear :: proc(mask: u32) #foreign lib "glClear";
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";
Color3f :: proc(r, g, b: f32) #foreign lib "glColor3f";
Vertex3f :: proc(x, y, z: f32) #foreign lib "glVertex3f";
GetError :: proc() -> i32 #foreign lib "glGetError";
GetString :: proc(name: i32) -> ^byte #foreign lib "glGetString";
GetIntegerv :: proc(name: i32, v: ^i32) #foreign lib "glGetIntegerv";
TexCoord2f :: proc(x, y: f32) #foreign lib "glTexCoord2f";
TexImage2D :: proc(target, level, internal_format,
width, height, border,
format, _type: i32, pixels: rawptr) #foreign lib "glTexImage2D";
GetError :: proc() -> i32 #foreign lib "glGetError";
GetString :: proc(name: i32) -> ^byte #foreign lib "glGetString";
GetIntegerv :: proc(name: i32, v: ^i32) #foreign lib "glGetIntegerv";
format, type: i32, pixels: rawptr) #foreign lib "glTexImage2D";
string_data :: proc(s: string) -> ^u8 #inline { return ^s[0]; }
@@ -35,121 +36,121 @@ _libgl := win32.LoadLibraryA(string_data("opengl32.dll\x00"));
GetProcAddress :: proc(name: string) -> proc() #cc_c {
assert(name[name.count-1] == 0);
res := win32.wglGetProcAddress(name.data);
res := wgl.GetProcAddress(name.data);
if res == nil {
res = win32.GetProcAddress(_libgl, name.data);
}
return res;
}
GenBuffers: proc(count: i32, buffers: ^u32) #cc_c;
GenVertexArrays: proc(count: i32, buffers: ^u32) #cc_c;
GenSamplers: proc(count: i32, buffers: ^u32) #cc_c;
BindBuffer: proc(target: i32, buffer: u32) #cc_c;
BindVertexArray: proc(buffer: u32) #cc_c;
BindSampler: proc(position: i32, sampler: u32) #cc_c;
BufferData: proc(target: i32, size: int, data: rawptr, usage: i32) #cc_c;
BufferSubData: proc(target: i32, offset, size: int, data: rawptr) #cc_c;
GenBuffers: proc(count: i32, buffers: ^u32) #cc_c;
GenVertexArrays: proc(count: i32, buffers: ^u32) #cc_c;
GenSamplers: proc(count: i32, buffers: ^u32) #cc_c;
BindBuffer: proc(target: i32, buffer: u32) #cc_c;
BindVertexArray: proc(buffer: u32) #cc_c;
BindSampler: proc(position: i32, sampler: u32) #cc_c;
BufferData: proc(target: i32, size: int, data: rawptr, usage: i32) #cc_c;
BufferSubData: proc(target: i32, offset, size: int, data: rawptr) #cc_c;
DrawArrays: proc(mode, first: i32, count: u32) #cc_c;
DrawElements: proc(mode: i32, count: u32, type_: i32, indices: rawptr) #cc_c;
DrawArrays: proc(mode, first: i32, count: u32) #cc_c;
DrawElements: proc(mode: i32, count: u32, type_: i32, indices: rawptr) #cc_c;
MapBuffer: proc(target, access: i32) -> rawptr #cc_c;
UnmapBuffer: proc(target: i32) #cc_c;
MapBuffer: proc(target, access: i32) -> rawptr #cc_c;
UnmapBuffer: proc(target: i32) #cc_c;
VertexAttribPointer: proc(index: u32, size, type_: i32, normalized: i32, stride: u32, pointer: rawptr) #cc_c;
VertexAttribPointer: proc(index: u32, size, type_: i32, normalized: i32, stride: u32, pointer: rawptr) #cc_c;
EnableVertexAttribArray: proc(index: u32) #cc_c;
CreateShader: proc(shader_type: i32) -> u32 #cc_c;
ShaderSource: proc(shader: u32, count: u32, str: ^^byte, length: ^i32) #cc_c;
CompileShader: proc(shader: u32) #cc_c;
CreateProgram: proc() -> u32 #cc_c;
AttachShader: proc(program, shader: u32) #cc_c;
DetachShader: proc(program, shader: u32) #cc_c;
DeleteShader: proc(shader: u32) #cc_c;
LinkProgram: proc(program: u32) #cc_c;
UseProgram: proc(program: u32) #cc_c;
DeleteProgram: proc(program: u32) #cc_c;
CreateShader: proc(shader_type: i32) -> u32 #cc_c;
ShaderSource: proc(shader: u32, count: u32, str: ^^byte, length: ^i32) #cc_c;
CompileShader: proc(shader: u32) #cc_c;
CreateProgram: proc() -> u32 #cc_c;
AttachShader: proc(program, shader: u32) #cc_c;
DetachShader: proc(program, shader: u32) #cc_c;
DeleteShader: proc(shader: u32) #cc_c;
LinkProgram: proc(program: u32) #cc_c;
UseProgram: proc(program: u32) #cc_c;
DeleteProgram: proc(program: u32) #cc_c;
GetShaderiv: proc(shader: u32, pname: i32, params: ^i32) #cc_c;
GetProgramiv: proc(program: u32, pname: i32, params: ^i32) #cc_c;
GetShaderInfoLog: proc(shader: u32, max_length: u32, length: ^u32, info_long: ^byte) #cc_c;
GetProgramInfoLog: proc(program: u32, max_length: u32, length: ^u32, info_long: ^byte) #cc_c;
GetShaderiv: proc(shader: u32, pname: i32, params: ^i32) #cc_c;
GetProgramiv: proc(program: u32, pname: i32, params: ^i32) #cc_c;
GetShaderInfoLog: proc(shader: u32, max_length: u32, length: ^u32, info_long: ^byte) #cc_c;
GetProgramInfoLog: proc(program: u32, max_length: u32, length: ^u32, info_long: ^byte) #cc_c;
ActiveTexture: proc(texture: i32) #cc_c;
GenerateMipmap: proc(target: i32) #cc_c;
ActiveTexture: proc(texture: i32) #cc_c;
GenerateMipmap: proc(target: i32) #cc_c;
SamplerParameteri: proc(sampler: u32, pname: i32, param: i32) #cc_c;
SamplerParameterf: proc(sampler: u32, pname: i32, param: f32) #cc_c;
SamplerParameteriv: proc(sampler: u32, pname: i32, params: ^i32) #cc_c;
SamplerParameterfv: proc(sampler: u32, pname: i32, params: ^f32) #cc_c;
SamplerParameterIiv: proc(sampler: u32, pname: i32, params: ^i32) #cc_c;
SamplerParameterIuiv: proc(sampler: u32, pname: i32, params: ^u32) #cc_c;
SamplerParameteri: proc(sampler: u32, pname: i32, param: i32) #cc_c;
SamplerParameterf: proc(sampler: u32, pname: i32, param: f32) #cc_c;
SamplerParameteriv: proc(sampler: u32, pname: i32, params: ^i32) #cc_c;
SamplerParameterfv: proc(sampler: u32, pname: i32, params: ^f32) #cc_c;
SamplerParameterIiv: proc(sampler: u32, pname: i32, params: ^i32) #cc_c;
SamplerParameterIuiv: proc(sampler: u32, pname: i32, params: ^u32) #cc_c;
Uniform1i: proc(loc: i32, v0: i32) #cc_c;
Uniform2i: proc(loc: i32, v0, v1: i32) #cc_c;
Uniform3i: proc(loc: i32, v0, v1, v2: i32) #cc_c;
Uniform4i: proc(loc: i32, v0, v1, v2, v3: i32) #cc_c;
Uniform1f: proc(loc: i32, v0: f32) #cc_c;
Uniform2f: proc(loc: i32, v0, v1: f32) #cc_c;
Uniform3f: proc(loc: i32, v0, v1, v2: f32) #cc_c;
Uniform4f: proc(loc: i32, v0, v1, v2, v3: f32) #cc_c;
UniformMatrix4fv: proc(loc: i32, count: u32, transpose: i32, value: ^f32) #cc_c;
Uniform1i: proc(loc: i32, v0: i32) #cc_c;
Uniform2i: proc(loc: i32, v0, v1: i32) #cc_c;
Uniform3i: proc(loc: i32, v0, v1, v2: i32) #cc_c;
Uniform4i: proc(loc: i32, v0, v1, v2, v3: i32) #cc_c;
Uniform1f: proc(loc: i32, v0: f32) #cc_c;
Uniform2f: proc(loc: i32, v0, v1: f32) #cc_c;
Uniform3f: proc(loc: i32, v0, v1, v2: f32) #cc_c;
Uniform4f: proc(loc: i32, v0, v1, v2, v3: f32) #cc_c;
UniformMatrix4fv: proc(loc: i32, count: u32, transpose: i32, value: ^f32) #cc_c;
GetUniformLocation: proc(program: u32, name: ^byte) -> i32 #cc_c;
GetUniformLocation: proc(program: u32, name: ^byte) -> i32 #cc_c;
init :: proc() {
set_proc_address :: proc(p: rawptr, name: string) #inline { (cast(^(proc() #cc_c))p)^ = GetProcAddress(name); }
set_proc_address(^GenBuffers, "glGenBuffers\x00");
set_proc_address(^GenVertexArrays, "glGenVertexArrays\x00");
set_proc_address(^GenSamplers, "glGenSamplers\x00");
set_proc_address(^BindBuffer, "glBindBuffer\x00");
set_proc_address(^BindSampler, "glBindSampler\x00");
set_proc_address(^BindVertexArray, "glBindVertexArray\x00");
set_proc_address(^BufferData, "glBufferData\x00");
set_proc_address(^BufferSubData, "glBufferSubData\x00");
set_proc_address(^GenBuffers, "glGenBuffers\x00");
set_proc_address(^GenVertexArrays, "glGenVertexArrays\x00");
set_proc_address(^GenSamplers, "glGenSamplers\x00");
set_proc_address(^BindBuffer, "glBindBuffer\x00");
set_proc_address(^BindSampler, "glBindSampler\x00");
set_proc_address(^BindVertexArray, "glBindVertexArray\x00");
set_proc_address(^BufferData, "glBufferData\x00");
set_proc_address(^BufferSubData, "glBufferSubData\x00");
set_proc_address(^DrawArrays, "glDrawArrays\x00");
set_proc_address(^DrawElements, "glDrawElements\x00");
set_proc_address(^DrawArrays, "glDrawArrays\x00");
set_proc_address(^DrawElements, "glDrawElements\x00");
set_proc_address(^MapBuffer, "glMapBuffer\x00");
set_proc_address(^UnmapBuffer, "glUnmapBuffer\x00");
set_proc_address(^MapBuffer, "glMapBuffer\x00");
set_proc_address(^UnmapBuffer, "glUnmapBuffer\x00");
set_proc_address(^VertexAttribPointer, "glVertexAttribPointer\x00");
set_proc_address(^EnableVertexAttribArray, "glEnableVertexAttribArray\x00");
set_proc_address(^CreateShader, "glCreateShader\x00");
set_proc_address(^ShaderSource, "glShaderSource\x00");
set_proc_address(^CompileShader, "glCompileShader\x00");
set_proc_address(^CreateProgram, "glCreateProgram\x00");
set_proc_address(^AttachShader, "glAttachShader\x00");
set_proc_address(^DetachShader, "glDetachShader\x00");
set_proc_address(^DeleteShader, "glDeleteShader\x00");
set_proc_address(^LinkProgram, "glLinkProgram\x00");
set_proc_address(^UseProgram, "glUseProgram\x00");
set_proc_address(^DeleteProgram, "glDeleteProgram\x00");
set_proc_address(^CreateShader, "glCreateShader\x00");
set_proc_address(^ShaderSource, "glShaderSource\x00");
set_proc_address(^CompileShader, "glCompileShader\x00");
set_proc_address(^CreateProgram, "glCreateProgram\x00");
set_proc_address(^AttachShader, "glAttachShader\x00");
set_proc_address(^DetachShader, "glDetachShader\x00");
set_proc_address(^DeleteShader, "glDeleteShader\x00");
set_proc_address(^LinkProgram, "glLinkProgram\x00");
set_proc_address(^UseProgram, "glUseProgram\x00");
set_proc_address(^DeleteProgram, "glDeleteProgram\x00");
set_proc_address(^GetShaderiv, "glGetShaderiv\x00");
set_proc_address(^GetProgramiv, "glGetProgramiv\x00");
set_proc_address(^GetShaderInfoLog, "glGetShaderInfoLog\x00");
set_proc_address(^GetProgramInfoLog, "glGetProgramInfoLog\x00");
set_proc_address(^GetShaderiv, "glGetShaderiv\x00");
set_proc_address(^GetProgramiv, "glGetProgramiv\x00");
set_proc_address(^GetShaderInfoLog, "glGetShaderInfoLog\x00");
set_proc_address(^GetProgramInfoLog, "glGetProgramInfoLog\x00");
set_proc_address(^ActiveTexture, "glActiveTexture\x00");
set_proc_address(^GenerateMipmap, "glGenerateMipmap\x00");
set_proc_address(^ActiveTexture, "glActiveTexture\x00");
set_proc_address(^GenerateMipmap, "glGenerateMipmap\x00");
set_proc_address(^Uniform1i, "glUniform1i\x00");
set_proc_address(^UniformMatrix4fv, "glUniformMatrix4fv\x00");
set_proc_address(^Uniform1i, "glUniform1i\x00");
set_proc_address(^UniformMatrix4fv, "glUniformMatrix4fv\x00");
set_proc_address(^GetUniformLocation, "glGetUniformLocation\x00");
set_proc_address(^GetUniformLocation, "glGetUniformLocation\x00");
set_proc_address(^SamplerParameteri, "glSamplerParameteri\x00");
set_proc_address(^SamplerParameterf, "glSamplerParameterf\x00");
set_proc_address(^SamplerParameteriv, "glSamplerParameteriv\x00");
set_proc_address(^SamplerParameterfv, "glSamplerParameterfv\x00");
set_proc_address(^SamplerParameterIiv, "glSamplerParameterIiv\x00");
set_proc_address(^SamplerParameterIuiv, "glSamplerParameterIuiv\x00");
set_proc_address(^SamplerParameteri, "glSamplerParameteri\x00");
set_proc_address(^SamplerParameterf, "glSamplerParameterf\x00");
set_proc_address(^SamplerParameteriv, "glSamplerParameteriv\x00");
set_proc_address(^SamplerParameterfv, "glSamplerParameterfv\x00");
set_proc_address(^SamplerParameterIiv, "glSamplerParameterIiv\x00");
set_proc_address(^SamplerParameterIuiv, "glSamplerParameterIuiv\x00");
}
+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;
copy(buf[:], cast([]byte)path);
copy(buf[..], cast([]byte)path);
handle := cast(Handle)CreateFileA(^buf[0], access, share_mode, sa, create_mode, FILE_ATTRIBUTE_NORMAL, nil);
if handle != INVALID_HANDLE {
@@ -184,7 +184,7 @@ last_write_time_by_name :: proc(name: string) -> File_Time {
assert(buf.count > name.count);
copy(buf[:], cast([]byte)name);
copy(buf[..], cast([]byte)name);
if win32.GetFileAttributesExA(^buf[0], win32.GetFileExInfoStandard, ^data) != 0 {
last_write_time = data.last_write_time;
@@ -201,7 +201,7 @@ last_write_time_by_name :: proc(name: string) -> File_Time {
read_entire_file :: proc(name: string) -> ([]byte, bool) {
buf: [300]byte;
copy(buf[:], cast([]byte)name);
copy(buf[..], cast([]byte)name);
fd, err := open(name, O_RDONLY, 0);
if err != ERROR_NONE {
@@ -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);
if single_read_length <= 0 {
free(data.data);
free(data);
return nil, false;
}
@@ -248,12 +248,23 @@ read_entire_file :: proc(name: string) -> ([]byte, bool) {
heap_alloc :: proc(size: int) -> rawptr {
assert(size > 0);
return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, size);
}
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
if new_size == 0 {
heap_free(ptr);
return nil;
}
if ptr == nil {
return heap_alloc(new_size);
}
return win32.HeapReAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, ptr, new_size);
}
heap_free :: proc(ptr: rawptr) {
if ptr == nil {
return;
}
win32.HeapFree(win32.GetProcessHeap(), 0, ptr);
}
+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";
Semaphore :: struct {
handle: win32.HANDLE,
_handle: win32.HANDLE,
}
Mutex :: struct {
semaphore: Semaphore,
counter: i32,
owner: i32,
recursion: i32,
_semaphore: Semaphore,
_counter: i32,
_owner: i32,
_recursion: i32,
}
current_thread_id :: proc() -> i32 {
@@ -17,74 +17,74 @@ current_thread_id :: proc() -> i32 {
}
semaphore_init :: proc(s: ^Semaphore) {
s.handle = win32.CreateSemaphoreA(nil, 0, 1<<31-1, nil);
s._handle = win32.CreateSemaphoreA(nil, 0, 1<<31-1, nil);
}
semaphore_destroy :: proc(s: ^Semaphore) {
win32.CloseHandle(s.handle);
win32.CloseHandle(s._handle);
}
semaphore_post :: proc(s: ^Semaphore, count: int) {
win32.ReleaseSemaphore(s.handle, cast(i32)count, nil);
win32.ReleaseSemaphore(s._handle, cast(i32)count, nil);
}
semaphore_release :: proc(s: ^Semaphore) #inline { semaphore_post(s, 1); }
semaphore_wait :: proc(s: ^Semaphore) {
win32.WaitForSingleObject(s.handle, win32.INFINITE);
win32.WaitForSingleObject(s._handle, win32.INFINITE);
}
mutex_init :: proc(m: ^Mutex) {
atomic.store(^m.counter, 0);
atomic.store(^m.owner, current_thread_id());
semaphore_init(^m.semaphore);
m.recursion = 0;
atomic.store(^m._counter, 0);
atomic.store(^m._owner, current_thread_id());
semaphore_init(^m._semaphore);
m._recursion = 0;
}
mutex_destroy :: proc(m: ^Mutex) {
semaphore_destroy(^m.semaphore);
semaphore_destroy(^m._semaphore);
}
mutex_lock :: proc(m: ^Mutex) {
thread_id := current_thread_id();
if atomic.fetch_add(^m.counter, 1) > 0 {
if thread_id != atomic.load(^m.owner) {
semaphore_wait(^m.semaphore);
if atomic.fetch_add(^m._counter, 1) > 0 {
if thread_id != atomic.load(^m._owner) {
semaphore_wait(^m._semaphore);
}
}
atomic.store(^m.owner, thread_id);
m.recursion += 1;
atomic.store(^m._owner, thread_id);
m._recursion++;
}
mutex_try_lock :: proc(m: ^Mutex) -> bool {
thread_id := current_thread_id();
if atomic.load(^m.owner) == thread_id {
atomic.fetch_add(^m.counter, 1);
if atomic.load(^m._owner) == thread_id {
atomic.fetch_add(^m._counter, 1);
} else {
expected: i32 = 0;
if atomic.load(^m.counter) != 0 {
if atomic.load(^m._counter) != 0 {
return false;
}
if atomic.compare_exchange(^m.counter, expected, 1) == 0 {
if atomic.compare_exchange(^m._counter, expected, 1) == 0 {
return false;
}
atomic.store(^m.owner, thread_id);
atomic.store(^m._owner, thread_id);
}
m.recursion += 1;
m._recursion++;
return true;
}
mutex_unlock :: proc(m: ^Mutex) {
recursion: i32;
thread_id := current_thread_id();
assert(thread_id == atomic.load(^m.owner));
assert(thread_id == atomic.load(^m._owner));
m.recursion -= 1;
recursion = m.recursion;
m._recursion--;
recursion = m._recursion;
if recursion == 0 {
atomic.store(^m.owner, thread_id);
atomic.store(^m._owner, thread_id);
}
if atomic.fetch_add(^m.counter, -1) > 1 {
if atomic.fetch_add(^m._counter, -1) > 1 {
if recursion == 0 {
semaphore_release(^m.semaphore);
semaphore_release(^m._semaphore);
}
}
}
+72
View File
@@ -0,0 +1,72 @@
#foreign_system_library "opengl32.lib" when ODIN_OS == "windows";
#import . "windows.odin";
CONTEXT_MAJOR_VERSION_ARB :: 0x2091;
CONTEXT_MINOR_VERSION_ARB :: 0x2092;
CONTEXT_FLAGS_ARB :: 0x2094;
CONTEXT_PROFILE_MASK_ARB :: 0x9126;
CONTEXT_FORWARD_COMPATIBLE_BIT_ARB :: 0x0002;
CONTEXT_CORE_PROFILE_BIT_ARB :: 0x00000001;
HGLRC :: HANDLE;
COLORREF :: u32;
LAYERPLANEDESCRIPTOR :: struct #ordered {
size: u16,
version: u16,
flags: u32,
pixel_type: byte,
color_bits: byte,
red_bits: byte,
red_shift: byte,
green_bits: byte,
green_shift: byte,
blue_bits: byte,
blue_shift: byte,
alpha_bits: byte,
alpha_shift: byte,
accum_bits: byte,
accum_red_bits: byte,
accum_green_bits: byte,
accum_blue_bits: byte,
accum_alpha_bits: byte,
depth_bits: byte,
stencil_bits: byte,
aux_buffers: byte,
layer_type: byte,
reserved: byte,
transparent: COLORREF,
}
POINTFLOAT :: struct #ordered {
x, y: f32,
}
GLYPHMETRICSFLOAT :: struct #ordered {
black_box_x: f32,
black_box_y: f32,
glyph_origin: POINTFLOAT,
cell_inc_x: f32,
cell_inc_y: f32,
}
CreateContextAttribsARBType :: #type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC;
ChoosePixelFormatARBType :: #type proc(hdc: HDC, attrib_i_list: ^i32, attrib_f_list: ^f32, max_formats: u32, formats: ^i32, num_formats : ^u32) -> BOOL #cc_c;
CreateContext :: proc(hdc: HDC) -> HGLRC #foreign opengl32 "wglCreateContext";
MakeCurrent :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign opengl32 "wglMakeCurrent";
GetProcAddress :: proc(c_str: ^u8) -> PROC #foreign opengl32 "wglGetProcAddress";
DeleteContext :: proc(hglrc: HGLRC) -> BOOL #foreign opengl32 "wglDeleteContext";
CopyContext :: proc(src, dst: HGLRC, mask: u32) -> BOOL #foreign opengl32 "wglCopyContext";
CreateLayerContext :: proc(hdc: HDC, layer_plane: i32) -> HGLRC #foreign opengl32 "wglCreateLayerContext";
DescribeLayerPlane :: proc(hdc: HDC, pixel_format, layer_plane: i32, bytes: u32, pd: ^LAYERPLANEDESCRIPTOR) -> BOOL #foreign opengl32 "wglDescribeLayerPlane";
GetCurrentContext :: proc() -> HGLRC #foreign opengl32 "wglGetCurrentContext";
GetCurrentDC :: proc() -> HDC #foreign opengl32 "wglGetCurrentDC";
GetLayerPaletteEntries :: proc(hdc: HDC, layer_plane, start, entries: i32, cr: ^COLORREF) -> i32 #foreign opengl32 "wglGetLayerPaletteEntries";
RealizeLayerPalette :: proc(hdc: HDC, layer_plane: i32, realize: BOOL) -> BOOL #foreign opengl32 "wglRealizeLayerPalette";
SetLayerPaletteEntries :: proc(hdc: HDC, layer_plane, start, entries: i32, cr: ^COLORREF) -> i32 #foreign opengl32 "wglSetLayerPaletteEntries";
ShareLists :: proc(hglrc1, hglrc2: HGLRC) -> BOOL #foreign opengl32 "wglShareLists";
SwapLayerBuffers :: proc(hdc: HDC, planes: u32) -> BOOL #foreign opengl32 "wglSwapLayerBuffers";
UseFontBitmaps :: proc(hdc: HDC, first, count, list_base: u32) -> BOOL #foreign opengl32 "wglUseFontBitmaps";
UseFontOutlines :: proc(hdc: HDC, first, count, list_base: u32, deviation, extrusion: f32, format: i32, gmf: ^GLYPHMETRICSFLOAT) -> BOOL #foreign opengl32 "wglUseFontOutlines";
+90 -31
View File
@@ -1,8 +1,7 @@
#foreign_system_library "kernel32.lib";
#foreign_system_library "user32.lib";
#foreign_system_library "gdi32.lib";
#foreign_system_library "winmm.lib";
#foreign_system_library "opengl32.lib";
#foreign_system_library "kernel32.lib" when ODIN_OS == "windows";
#foreign_system_library "user32.lib" when ODIN_OS == "windows";
#foreign_system_library "gdi32.lib" when ODIN_OS == "windows";
#foreign_system_library "winmm.lib" when ODIN_OS == "windows";
HANDLE :: rawptr;
HWND :: HANDLE;
@@ -19,10 +18,10 @@ LPARAM :: int;
LRESULT :: int;
ATOM :: i16;
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;
TRUE: BOOL : 1;
@@ -41,11 +40,19 @@ WS_CAPTION :: 0x00C00000;
WS_VISIBLE :: 0x10000000;
WS_OVERLAPPEDWINDOW :: WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX;
WM_DESTROY :: 0x0002;
WM_CLOSE :: 0x0010;
WM_QUIT :: 0x0012;
WM_KEYDOWN :: 0x0100;
WM_KEYUP :: 0x0101;
WM_DESTROY :: 0x0002;
WM_SIZE :: 0x0005;
WM_CLOSE :: 0x0010;
WM_ACTIVATEAPP :: 0x001C;
WM_QUIT :: 0x0012;
WM_KEYDOWN :: 0x0100;
WM_KEYUP :: 0x0101;
WM_SIZING :: 0x0214;
WM_MOUSEWHEEL :: 0x020A;
WM_SYSKEYDOWN :: 0x0104;
WM_WINDOWPOSCHANGED :: 0x0047;
WM_SETCURSOR :: 0x0020;
WM_CHAR :: 0x0102;
PM_REMOVE :: 1;
@@ -165,6 +172,9 @@ DefWindowProcA :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) ->
AdjustWindowRect :: proc(rect: ^RECT, style: u32, menu: BOOL) -> BOOL #foreign user32;
GetActiveWindow :: proc() -> HWND #foreign user32;
DestroyWindow :: proc(wnd: HWND) -> BOOL #foreign user32;
DescribePixelFormat :: proc(dc: HDC, pixel_format: i32, bytes : u32, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign user32;
GetQueryPerformanceFrequency :: proc() -> i64 {
r: i64;
@@ -288,13 +298,75 @@ InterlockedExchangeAdd64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign ke
InterlockedAnd64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign kernel32;
InterlockedOr64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign kernel32;
_mm_pause :: proc() #foreign kernel32;
mm_pause :: proc() #foreign kernel32 "_mm_pause";
ReadWriteBarrier :: proc() #foreign kernel32;
WriteBarrier :: proc() #foreign kernel32;
ReadBarrier :: proc() #foreign kernel32;
HMONITOR :: HANDLE;
GWL_STYLE :: -16;
HWND_TOP :: cast(HWND)cast(uint)0;
MONITOR_DEFAULTTONULL :: 0x00000000;
MONITOR_DEFAULTTOPRIMARY :: 0x00000001;
MONITOR_DEFAULTTONEAREST :: 0x00000002;
SWP_FRAMECHANGED :: 0x0020;
SWP_NOOWNERZORDER :: 0x0200;
SWP_NOZORDER :: 0x0004;
SWP_NOSIZE :: 0x0001;
SWP_NOMOVE :: 0x0002;
MONITORINFO :: struct #ordered {
size: u32,
monitor: RECT,
work: RECT,
flags: u32,
}
WINDOWPLACEMENT :: struct #ordered {
length: u32,
flags: u32,
show_cmd: u32,
min_pos: POINT,
max_pos: POINT,
normal_pos: RECT,
}
GetMonitorInfoA :: proc(monitor: HMONITOR, mi: ^MONITORINFO) -> BOOL #foreign user32;
MonitorFromWindow :: proc(wnd: HWND, flags : u32) -> HMONITOR #foreign user32;
SetWindowPos :: proc(wnd: HWND, wndInsertAfter: HWND, x, y, width, height: i32, flags: u32) #foreign user32 "SetWindowPos";
GetWindowPlacement :: proc(wnd: HWND, wndpl: ^WINDOWPLACEMENT) -> BOOL #foreign user32;
SetWindowPlacement :: proc(wnd: HWND, wndpl: ^WINDOWPLACEMENT) -> BOOL #foreign user32;
GetWindowLongPtrA :: proc(wnd: HWND, index: i32) -> i64 #foreign user32;
SetWindowLongPtrA :: proc(wnd: HWND, index: i32, new: i64) -> i64 #foreign user32;
GetWindowText :: proc(wnd: HWND, str: ^byte, maxCount: i32) -> i32 #foreign user32;
HIWORD :: proc(wParam: WPARAM) -> u16 { return cast(u16)((cast(u32)wParam >> 16) & 0xffff); }
HIWORD :: proc(lParam: LPARAM) -> u16 { return cast(u16)((cast(u32)lParam >> 16) & 0xffff); }
LOWORD :: proc(wParam: WPARAM) -> u16 { return cast(u16)wParam; }
LOWORD :: proc(lParam: LPARAM) -> u16 { return cast(u16)lParam; }
BITMAPINFOHEADER :: struct #ordered {
size: u32,
width, height: i32,
@@ -357,10 +429,6 @@ PFD_DEPTH_DONTCARE :: 0x20000000;
PFD_DOUBLEBUFFER_DONTCARE :: 0x40000000;
PFD_STEREO_DONTCARE :: 0x80000000;
HGLRC :: HANDLE;
PROC :: type proc() #cc_c;
wglCreateContextAttribsARBType :: type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC;
PIXELFORMATDESCRIPTOR :: struct #ordered {
size,
@@ -393,23 +461,14 @@ PIXELFORMATDESCRIPTOR :: struct #ordered {
damage_mask: u32,
}
GetDC :: proc(h: HANDLE) -> HDC #foreign user32;
SetPixelFormat :: proc(hdc: HDC, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR ) -> BOOL #foreign user32;
ChoosePixelFormat :: proc(hdc: HDC, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign user32;
SwapBuffers :: proc(hdc: HDC) -> BOOL #foreign user32;
GetDC :: proc(h: HWND) -> HDC #foreign user32;
SetPixelFormat :: proc(hdc: HDC, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR) -> BOOL #foreign gdi32;
ChoosePixelFormat :: proc(hdc: HDC, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign gdi32;
SwapBuffers :: proc(hdc: HDC) -> BOOL #foreign gdi32;
ReleaseDC :: proc(wnd: HWND, hdc: HDC) -> i32 #foreign user32;
WGL_CONTEXT_MAJOR_VERSION_ARB :: 0x2091;
WGL_CONTEXT_MINOR_VERSION_ARB :: 0x2092;
WGL_CONTEXT_PROFILE_MASK_ARB :: 0x9126;
WGL_CONTEXT_CORE_PROFILE_BIT_ARB :: 0x0001;
WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x0002;
wglCreateContext :: proc(hdc: HDC) -> HGLRC #foreign opengl32;
wglMakeCurrent :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign opengl32;
wglGetProcAddress :: proc(c_str: ^u8) -> PROC #foreign opengl32;
wglDeleteContext :: proc(hglrc: HGLRC) -> BOOL #foreign opengl32;
PROC :: #type proc() #cc_c;
GetKeyState :: proc(v_key: i32) -> i16 #foreign user32;
+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;
}
decode_rune :: proc(s: string) -> (rune, int) {
decode_rune :: proc(s: string) -> (rune, int) #inline { return decode_rune(cast([]byte)s); }
decode_rune :: proc(s: []byte) -> (rune, int) {
n := s.count;
if n < 1 {
return RUNE_ERROR, 0;
@@ -130,6 +131,46 @@ decode_rune :: proc(s: string) -> (rune, int) {
}
decode_last_rune :: proc(s: string) -> (rune, int) #inline { return decode_last_rune(cast([]byte)s); }
decode_last_rune :: proc(s: []byte) -> (rune, int) {
r: rune;
size: int;
start, end, limit: int;
end = s.count;
if end == 0 {
return RUNE_ERROR, 0;
}
start = end-1;
r = cast(rune)s[start];
if r < RUNE_SELF {
return r, 1;
}
limit = max(end - UTF_MAX, 0);
start--;
for start >= limit {
if rune_start(s[start]) {
break;
}
start--;
}
start = max(start, 0);
r, size = decode_rune(s[start..end]);
if start+size != end {
return RUNE_ERROR, 1;
}
return r, size;
}
valid_rune :: proc(r: rune) -> bool {
if r < 0 {
return false;
@@ -146,7 +187,7 @@ valid_string :: proc(s: string) -> bool {
for i := 0; i < n; {
si := s[i];
if si < RUNE_SELF { // ascii
i += 1;
i++;
continue;
}
x := accept_sizes[si];
@@ -174,25 +215,28 @@ valid_string :: proc(s: string) -> bool {
return true;
}
rune_count :: proc(s: string) -> int {
rune_start :: proc(b: byte) -> bool #inline { return b&0xc0 != 0x80; }
rune_count :: proc(s: string) -> int #inline { return rune_count(cast([]byte)s); }
rune_count :: proc(s: []byte) -> int {
count := 0;
n := s.count;
for i := 0; i < n; {
defer count += 1;
defer count++;
si := s[i];
if si < RUNE_SELF { // ascii
i += 1;
i++;
continue;
}
x := accept_sizes[si];
if x == 0xf1 {
i += 1;
i++;
continue;
}
size := cast(int)(x & 7);
if i+size > n {
i += 1;
i++;
continue;
}
ar := accept_ranges[x>>4];
+90 -24
View File
@@ -1,17 +1,27 @@
// This stores the information for the specify architecture of this build
typedef struct BuildContext {
// Constants
String ODIN_OS; // target operating system
String ODIN_ARCH; // target architecture
String ODIN_ENDIAN; // target endian
String ODIN_VENDOR; // compiler vendor
String ODIN_VERSION; // compiler version
String ODIN_ROOT; // Odin ROOT
i64 word_size;
i64 max_align;
// In bytes
i64 word_size; // Size of a pointer, must be >= 4
i64 max_align; // max alignment, must be >= 1 (and typically >= word_size)
String llc_flags;
String link_flags;
bool is_dll;
} BuildContext;
gb_global BuildContext build_context = {0};
// TODO(bill): OS dependent versions for the BuildContext
// join_path
// is_dir
@@ -22,6 +32,7 @@ typedef struct BuildContext {
String const WIN32_SEPARATOR_STRING = {cast(u8 *)"\\", 1};
String const NIX_SEPARATOR_STRING = {cast(u8 *)"/", 1};
#if defined(GB_SYSTEM_WINDOWS)
String odin_root_dir(void) {
String path = global_module_path;
Array(wchar_t) path_buf;
@@ -71,6 +82,64 @@ String odin_root_dir(void) {
return path;
}
#elif defined(GB_SYSTEM_OSX)
#include <mach-o/dyld.h>
String odin_root_dir(void) {
String path = global_module_path;
Array(char) path_buf;
isize len, i;
gbTempArenaMemory tmp;
wchar_t *text;
if (global_module_path_set) {
return global_module_path;
}
array_init_count(&path_buf, heap_allocator(), 300);
len = 0;
for (;;) {
int sz = path_buf.count;
int res = _NSGetExecutablePath(&path_buf.e[0], &sz);
if(res == 0) {
len = sz;
break;
} else {
array_resize(&path_buf, sz + 1);
}
}
tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
text = gb_alloc_array(string_buffer_allocator, u8, len + 1);
gb_memmove(text, &path_buf.e[0], len);
path = make_string(text, len);
for (i = path.len-1; i >= 0; i--) {
u8 c = path.text[i];
if (c == '/' || c == '\\') {
break;
}
path.len--;
}
global_module_path = path;
global_module_path_set = true;
gb_temp_arena_memory_end(tmp);
// array_free(&path_buf);
return path;
}
#else
#error Implement system
#endif
#if defined(GB_SYSTEM_WINDOWS)
String path_to_fullpath(gbAllocator a, String s) {
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
String16 string16 = string_to_string16(string_buffer_allocator, s);
@@ -86,6 +155,17 @@ String path_to_fullpath(gbAllocator a, String s) {
gb_temp_arena_memory_end(tmp);
return result;
}
#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
String path_to_fullpath(gbAllocator a, String s) {
char* p = realpath(s.text, 0);
// GB_ASSERT(p && "file does not exist");
if(!p) return make_string_c("");
return make_string(p, strlen(p));
}
#else
#error Implement system
#endif
String get_fullpath_relative(gbAllocator a, String base_dir, String path) {
@@ -123,37 +203,23 @@ String get_fullpath_core(gbAllocator a, String path) {
return res;
}
String get_filepath_extension(String path) {
isize dot = 0;
bool seen_slash = false;
for (isize i = path.len-1; i >= 0; i--) {
u8 c = path.text[i];
if (c == '/' || c == '\\') {
seen_slash = true;
}
if (c == '.') {
if (seen_slash) {
return str_lit("");
}
dot = i;
break;
}
}
return make_string(path.text, dot);
}
void init_build_context(BuildContext *bc) {
void init_build_context(void) {
BuildContext *bc = &build_context;
bc->ODIN_VENDOR = str_lit("odin");
bc->ODIN_VERSION = str_lit("0.0.5e");
bc->ODIN_VERSION = str_lit("0.1.1");
bc->ODIN_ROOT = odin_root_dir();
#if defined(GB_SYSTEM_WINDOWS)
bc->ODIN_OS = str_lit("windows");
bc->ODIN_ARCH = str_lit("amd64");
bc->ODIN_ENDIAN = str_lit("little");
#elif defined(GB_SYSTEM_OSX)
bc->ODIN_OS = str_lit("osx");
bc->ODIN_ARCH = str_lit("amd64");
bc->ODIN_ENDIAN = str_lit("little");
#else
#error Implement system
#endif
+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
// an extra allocation
Array(Operand) operands;
ArrayOperand operands = {0};
array_init_reserve(&operands, c->tmp_allocator, 2*lhs_count);
// 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);
}
}
}
check_unpack_arguments(c, lhs_count, &operands, inits, true);
isize rhs_count = operands.count;
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);
for (isize i = 0; i < max; i++) {
check_init_variable(c, lhs[i], &operands.e[i], context_name);
}
if (rhs_count > 0 && lhs_count != rhs_count) {
error(lhs[0]->token, "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
}
#if 0
if (lhs[0]->kind == Entity_Variable &&
lhs[0]->Variable.is_let) {
if (lhs_count != rhs_count) {
error(lhs[0]->token, "`let` variables must be initialized, `%td` = `%td`", lhs_count, rhs_count);
}
}
#endif
gb_temp_arena_memory_end(tmp);
}
@@ -315,7 +289,7 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
}
if (is_foreign) {
MapEntity *fp = &c->info.foreign_procs;
MapEntity *fp = &c->info.foreigns;
String name = e->token.string;
if (pd->foreign_name.len > 0) {
name = pd->foreign_name;
@@ -370,7 +344,7 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
}
if (is_link_name || is_export) {
MapEntity *fp = &c->info.foreign_procs;
MapEntity *fp = &c->info.foreigns;
e->Procedure.link_name = name;
+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:
error_node(n, "Statements after this `return` are never executed");
break;
case AstNode_ExprStmt:
if (n->ExprStmt.expr->kind == AstNode_GiveExpr) {
error_node(n, "A `give` must be the last statement in a block");
}
break;
}
}
@@ -182,40 +177,40 @@ bool check_is_terminating(AstNode *node) {
return false;
}
Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
if (op_a->mode == Addressing_Invalid ||
(op_a->type == t_invalid && op_a->mode != Addressing_Overload)) {
Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
if (rhs->mode == Addressing_Invalid ||
(rhs->type == t_invalid && rhs->mode != Addressing_Overload)) {
return NULL;
}
AstNode *node = unparen_expr(lhs);
AstNode *node = unparen_expr(lhs_node);
// NOTE(bill): Ignore assignments to `_`
if (node->kind == AstNode_Ident &&
str_eq(node->Ident.string, str_lit("_"))) {
add_entity_definition(&c->info, node, NULL);
check_assignment(c, op_a, NULL, str_lit("assignment to `_` identifier"));
if (op_a->mode == Addressing_Invalid) {
check_assignment(c, rhs, NULL, str_lit("assignment to `_` identifier"));
if (rhs->mode == Addressing_Invalid) {
return NULL;
}
return op_a->type;
return rhs->type;
}
Entity *e = NULL;
bool used = false;
Operand op_b = {Addressing_Invalid};
Operand lhs = {Addressing_Invalid};
check_expr(c, &op_b, lhs);
if (op_b.mode == Addressing_Invalid ||
op_b.type == t_invalid) {
check_expr(c, &lhs, lhs_node);
if (lhs.mode == Addressing_Invalid ||
lhs.type == t_invalid) {
return NULL;
}
if (op_a->mode == Addressing_Overload) {
isize overload_count = op_a->overload_count;
Entity **procs = op_a->overload_entities;
if (rhs->mode == Addressing_Overload) {
isize overload_count = rhs->overload_count;
Entity **procs = rhs->overload_entities;
GB_ASSERT(procs != NULL && overload_count > 0);
// NOTE(bill): These should be done
@@ -227,19 +222,19 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
Operand x = {0};
x.mode = Addressing_Value;
x.type = t;
if (check_is_assignable_to(c, &x, op_b.type)) {
if (check_is_assignable_to(c, &x, lhs.type)) {
e = procs[i];
add_entity_use(c, op_a->expr, e);
add_entity_use(c, rhs->expr, e);
break;
}
}
if (e != NULL) {
// HACK TODO(bill): Should the entities be freed as it's technically a leak
op_a->mode = Addressing_Value;
op_a->type = e->type;
op_a->overload_count = 0;
op_a->overload_entities = NULL;
rhs->mode = Addressing_Value;
rhs->type = e->type;
rhs->overload_count = 0;
rhs->overload_entities = NULL;
}
} else {
if (node->kind == AstNode_Ident) {
@@ -256,35 +251,60 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
e->flags |= EntityFlag_Used;
}
switch (op_b.mode) {
Type *assignment_type = lhs.type;
switch (lhs.mode) {
case Addressing_Invalid:
return NULL;
case Addressing_Variable:
break;
case Addressing_MapIndex: {
AstNode *ln = unparen_expr(lhs_node);
if (ln->kind == AstNode_IndexExpr) {
AstNode *x = ln->IndexExpr.expr;
TypeAndValue *tav = type_and_value_of_expression(&c->info, x);
GB_ASSERT(tav != NULL);
if (tav->mode != Addressing_Variable) {
if (!is_type_pointer(tav->type)) {
gbString str = expr_to_string(lhs.expr);
error_node(lhs.expr, "Cannot assign to the value of a map `%s`", str);
gb_string_free(str);
return NULL;
}
}
}
} break;
default: {
if (op_b.expr->kind == AstNode_SelectorExpr) {
if (lhs.expr->kind == AstNode_SelectorExpr) {
// NOTE(bill): Extra error checks
Operand op_c = {Addressing_Invalid};
ast_node(se, SelectorExpr, op_b.expr);
ast_node(se, SelectorExpr, lhs.expr);
check_expr(c, &op_c, se->expr);
if (op_c.mode == Addressing_MapIndex) {
gbString str = expr_to_string(lhs.expr);
error_node(lhs.expr, "Cannot assign to record field `%s` in map", str);
gb_string_free(str);
return NULL;
}
}
gbString str = expr_to_string(op_b.expr);
if (e != NULL && e->kind == Entity_Variable && e->Variable.is_immutable) {
error_node(op_b.expr, "Cannot assign to an immutable: `%s`", str);
gbString str = expr_to_string(lhs.expr);
if (lhs.mode == Addressing_Immutable) {
error_node(lhs.expr, "Cannot assign to an immutable: `%s`", str);
} else {
error_node(op_b.expr, "Cannot assign to `%s`", str);
error_node(lhs.expr, "Cannot assign to `%s`", str);
}
gb_string_free(str);
} break;
}
check_assignment(c, op_a, op_b.type, str_lit("assignment"));
if (op_a->mode == Addressing_Invalid) {
check_assignment(c, rhs, assignment_type, str_lit("assignment"));
if (rhs->mode == Addressing_Invalid) {
return NULL;
}
return op_a->type;
return rhs->type;
}
bool check_valid_type_match_type(Type *type, bool *is_union_ptr, bool *is_any) {
@@ -388,12 +408,6 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
if (operand.expr->kind == AstNode_CallExpr) {
return;
}
if (operand.expr->kind == AstNode_GiveExpr) {
if ((flags&Stmt_GiveAllowed) != 0) {
return;
}
error_node(node, "Illegal use of `give`");
}
gbString expr_str = expr_to_string(operand.expr);
error_node(node, "Expression is not used: `%s`", expr_str);
gb_string_free(expr_str);
@@ -407,44 +421,81 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
check_stmt(c, ts->stmt, flags);
case_end;
case_ast_node(s, IncDecStmt, node);
TokenKind op = s->op.kind;
switch (op) {
case Token_Inc: op = Token_Add; break;
case Token_Dec: op = Token_Sub; break;
default:
error_node(node, "Invalid inc/dec operation");
return;
}
Operand x = {0};
check_expr(c, &x, s->expr);
if (x.mode == Addressing_Invalid) {
return;
}
if (!is_type_integer(x.type) && !is_type_float(x.type)) {
gbString e = expr_to_string(s->expr);
gbString t = type_to_string(x.type);
error_node(node, "%s%.*s used on non-numeric type %s", e, LIT(s->op.string), t);
gb_string_free(t);
gb_string_free(e);
return;
}
AstNode *left = s->expr;
AstNode *right = gb_alloc_item(c->allocator, AstNode);
right->kind = AstNode_BasicLit;
right->BasicLit.pos = s->op.pos;
right->BasicLit.kind = Token_Integer;
right->BasicLit.string = str_lit("1");
AstNode *be = gb_alloc_item(c->allocator, AstNode);
be->kind = AstNode_BinaryExpr;
be->BinaryExpr.op = s->op;
be->BinaryExpr.op.kind = op;
be->BinaryExpr.left = left;
be->BinaryExpr.right = right;
check_binary_expr(c, &x, be);
if (x.mode == Addressing_Invalid) {
return;
}
check_assignment_variable(c, &x, left);
case_end;
case_ast_node(as, AssignStmt, node);
switch (as->op.kind) {
case Token_Eq: {
// a, b, c = 1, 2, 3; // Multisided
if (as->lhs.count == 0) {
isize lhs_count = as->lhs.count;
if (lhs_count == 0) {
error(as->op, "Missing lhs in assignment statement");
return;
}
// TODO(bill): This is a very similar to check_init_variables, should I merge the two some how or just
// leave it?
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
// NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
// an extra allocation
Array(Operand) operands;
array_init_reserve(&operands, c->tmp_allocator, 2 * as->lhs.count);
ArrayOperand operands = {0};
array_init_reserve(&operands, c->tmp_allocator, 2 * lhs_count);
check_unpack_arguments(c, lhs_count, &operands, as->rhs, true);
for_array(i, as->rhs) {
AstNode *rhs = as->rhs.e[i];
Operand o = {0};
check_multi_expr(c, &o, rhs);
if (o.type->kind != Type_Tuple) {
array_add(&operands, o);
} else {
TypeTuple *tuple = &o.type->Tuple;
for (isize j = 0; j < tuple->variable_count; j++) {
o.type = tuple->variables[j]->type;
array_add(&operands, o);
}
isize rhs_count = operands.count;
for_array(i, operands) {
if (operands.e[i].mode == Addressing_Invalid) {
rhs_count--;
}
}
isize lhs_count = as->lhs.count;
isize rhs_count = operands.count;
isize operand_count = gb_min(as->lhs.count, operands.count);
for (isize i = 0; i < operand_count; i++) {
AstNode *lhs = as->lhs.e[i];
check_assignment_variable(c, &operands.e[i], lhs);
isize max = gb_min(lhs_count, rhs_count);
for (isize i = 0; i < max; i++) {
check_assignment_variable(c, &operands.e[i], as->lhs.e[i]);
}
if (lhs_count != rhs_count) {
error_node(as->lhs.e[0], "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
@@ -583,8 +634,9 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
if (fs->post != NULL) {
check_stmt(c, fs->post, 0);
if (fs->post->kind != AstNode_AssignStmt) {
error_node(fs->post, "`for` statement post statement must be an assignment");
if (fs->post->kind != AstNode_AssignStmt &&
fs->post->kind != AstNode_IncDecStmt) {
error_node(fs->post, "`for` statement post statement must be a simple statement");
}
}
check_stmt(c, fs->body, new_flags);
@@ -663,8 +715,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
TokenKind op = Token_Lt;
switch (ie->op.kind) {
case Token_HalfOpenRange: op = Token_Lt; break;
case Token_Ellipsis: op = Token_LtEq; break;
case Token_Ellipsis: op = Token_Lt; break;
default: error(ie->op, "Invalid range operator"); break;
}
bool ok = compare_exact_values(Token_Lt, a, b);
@@ -693,15 +744,29 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
}
break;
case Type_Array:
// val = make_type_pointer(c->allocator, t->Array.elem);
val = t->Array.elem;
idx = t_int;
break;
case Type_DynamicArray:
val = t->DynamicArray.elem;
idx = t_int;
break;
case Type_Slice:
// val = make_type_pointer(c->allocator, t->Slice.elem);
val = t->Slice.elem;
idx = t_int;
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};
Type * rhs[2] = {val, idx};
@@ -790,7 +855,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
Token token = {0};
token.pos = ast_node_token(ms->body).pos;
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
@@ -920,7 +985,25 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
bool is_union_ptr = 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"));
if (!check_valid_type_match_type(x.type, &is_union_ptr, &is_any)) {
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;
}
@@ -987,8 +1072,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
if (is_union_ptr) {
GB_ASSERT(is_type_union(bt));
bool tag_type_found = false;
for (isize i = 0; i < bt->Record.field_count; i++) {
Entity *f = bt->Record.fields[i];
for (isize i = 0; i < bt->Record.variant_count; i++) {
Entity *f = bt->Record.variants[i];
if (are_types_identical(f->type, y.type)) {
tag_type_found = true;
break;
@@ -996,8 +1081,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
}
if (!tag_type_found) {
gbString type_str = type_to_string(y.type);
error_node(y.expr,
"Unknown tag type, got `%s`", type_str);
error_node(y.expr, "Unknown tag type, got `%s`", type_str);
gb_string_free(type_str);
continue;
}
@@ -1025,19 +1109,27 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
}
check_open_scope(c, stmt);
if (case_type != NULL) {
add_type_info_type(c, case_type);
if (case_type == NULL) {
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
Type *tt = case_type;
if (is_union_ptr) {
tt = make_type_pointer(c->allocator, case_type);
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;
add_entity(c, c->context.scope, ms->var, tag_var);
add_entity_use(c, ms->var, tag_var);
add_entity(c, c->context.scope, lhs, tag_var);
add_entity_use(c, lhs, tag_var);
}
check_stmt_list(c, cc->stmts, mod_flags);
check_close_scope(c);
@@ -1113,8 +1205,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
case Entity_TypeName: {
Type *t = base_type(e->type);
if (is_type_union(t)) {
for (isize i = 0; i < t->Record.field_count; i++) {
Entity *f = t->Record.fields[i];
for (isize i = 0; i < t->Record.variant_count; i++) {
Entity *f = t->Record.variants[i];
Entity *found = scope_insert_entity(c->context.scope, f);
if (found != NULL) {
gbString expr_str = expr_to_string(expr);
@@ -1166,6 +1258,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
case Entity_Variable: {
Type *t = base_type(type_deref(e->type));
if (is_type_struct(t) || is_type_raw_union(t)) {
// TODO(bill): Make it work for unions too
Scope **found = map_scope_get(&c->info.scopes, hash_pointer(t->Record.node));
GB_ASSERT(found != NULL);
for_array(i, (*found)->elements.entries) {
@@ -1199,10 +1292,6 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
error(us->token, "`using` cannot be applied to a procedure");
break;
case Entity_ImplicitValue:
error(us->token, "`using` cannot be applied to an implicit value");
break;
case Entity_Nil:
error(us->token, "`using` cannot be applied to `nil`");
break;
+323 -250
View File
@@ -1,110 +1,6 @@
#include "exact_value.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 {
Expr_Expr,
Expr_Stmt,
@@ -118,11 +14,23 @@ typedef enum StmtFlag {
Stmt_GiveAllowed = 1<<3,
} StmtFlag;
typedef struct BuiltinProc {
String name;
isize arg_count;
bool variadic;
ExprKind kind;
} BuiltinProc;
typedef enum BuiltinProcId {
BuiltinProc_Invalid,
BuiltinProc_new,
BuiltinProc_new_slice,
BuiltinProc_free,
BuiltinProc_reserve,
BuiltinProc_clear,
BuiltinProc_append,
BuiltinProc_delete,
BuiltinProc_size_of,
BuiltinProc_size_of_val,
@@ -147,6 +55,7 @@ typedef enum BuiltinProcId {
// BuiltinProc_ptr_offset,
// BuiltinProc_ptr_sub,
BuiltinProc_slice_ptr,
BuiltinProc_slice_to_bytes,
BuiltinProc_min,
BuiltinProc_max,
@@ -155,17 +64,17 @@ typedef enum BuiltinProcId {
BuiltinProc_Count,
} BuiltinProcId;
typedef struct BuiltinProc {
String name;
isize arg_count;
bool variadic;
ExprKind kind;
} BuiltinProc;
gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
{STR_LIT(""), 0, false, Expr_Stmt},
{STR_LIT("new"), 1, false, Expr_Expr},
{STR_LIT("new_slice"), 2, false, Expr_Expr},
{STR_LIT("new_slice"), 2, true, Expr_Expr},
{STR_LIT("free"), 1, false, Expr_Stmt},
{STR_LIT("reserve"), 2, false, Expr_Stmt},
{STR_LIT("clear"), 1, false, Expr_Stmt},
{STR_LIT("append"), 1, true, Expr_Expr},
{STR_LIT("delete"), 2, false, Expr_Stmt},
{STR_LIT("size_of"), 1, false, Expr_Expr},
{STR_LIT("size_of_val"), 1, false, Expr_Expr},
@@ -190,6 +99,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
// {STR_LIT("ptr_offset"), 2, false, Expr_Expr},
// {STR_LIT("ptr_sub"), 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("max"), 2, false, Expr_Expr},
@@ -197,20 +107,124 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
{STR_LIT("clamp"), 3, false, Expr_Expr},
};
typedef enum ImplicitValueId {
ImplicitValue_Invalid,
ImplicitValue_context,
#include "types.c"
ImplicitValue_Count,
} ImplicitValueId;
typedef struct ImplicitValueInfo {
String name;
String backing_name;
Type * type;
} ImplicitValueInfo;
// NOTE(bill): This is initialized later
gb_global ImplicitValueInfo implicit_value_infos[ImplicitValue_Count] = {0};
typedef enum AddressingMode {
Addressing_Invalid, // invalid addressing mode
Addressing_NoValue, // no value (void in C)
Addressing_Value, // computed value (rvalue)
Addressing_Immutable, // immutable computed value (const rvalue)
Addressing_Variable, // addressable variable (lvalue)
Addressing_Constant, // constant & type will be a of Type_Basic (stripping Type_Named)
Addressing_Type, // type
Addressing_Builtin, // built in procedure
Addressing_Overload, // overloaded procedure
Addressing_MapIndex, // map index expression -
// lhs: acts like a Variable
// rhs: acts like OptionalOk
Addressing_OptionalOk, // rhs: acts like a value with an optional boolean part (for existence check)
} AddressingMode;
// Operand is used as an intermediate value whilst checking
// Operands store an addressing mode, the expression being evaluated,
// its type and node, and other specific information for certain
// addressing modes
// Its zero-value is a valid "invalid operand"
typedef struct Operand {
AddressingMode mode;
Type * type;
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;
typedef struct CheckerContext {
Scope * file_scope;
Scope * scope;
DeclInfo * decl;
u32 stmt_state_flags;
@@ -255,7 +270,7 @@ typedef struct CheckerContext {
Type * type_hint;
} CheckerContext;
// NOTE(bill): Symbol tables
// CheckerInfo stores all the symbol information for a type-checked program
typedef struct CheckerInfo {
MapTypeAndValue types; // Key: AstNode * | Expression -> Type (and value)
MapEntity definitions; // Key: AstNode * | Identifier -> Entity
@@ -263,11 +278,10 @@ typedef struct CheckerInfo {
MapScope scopes; // Key: AstNode * | Node -> Scope
MapExprInfo untyped; // Key: AstNode * | Expression -> ExprInfo
MapDeclInfo entities; // Key: Entity *
MapEntity foreign_procs; // Key: String
MapEntity foreigns; // Key: String
MapAstFile files; // Key: String (full path)
MapIsize type_info_map; // Key: Type *
isize type_info_count;
Entity * implicit_values[ImplicitValue_Count];
} CheckerInfo;
typedef struct Checker {
@@ -275,13 +289,11 @@ typedef struct Checker {
CheckerInfo info;
AstFile * curr_ast_file;
BaseTypeSizes sizes;
Scope * global_scope;
Array(ProcedureInfo) procs; // NOTE(bill): Procedures to check
Array(DelayedDecl) delayed_imports;
Array(DelayedDecl) delayed_foreign_libraries;
gbArena arena;
gbArena tmp_arena;
gbAllocator allocator;
@@ -391,9 +403,7 @@ void check_open_scope(Checker *c, AstNode *node) {
node = unparen_expr(node);
GB_ASSERT(node->kind == AstNode_Invalid ||
is_ast_node_stmt(node) ||
is_ast_node_type(node) ||
node->kind == AstNode_BlockExpr ||
node->kind == AstNode_IfExpr );
is_ast_node_type(node));
Scope *scope = make_scope(c->context.scope, c->allocator);
add_scope(c, node, scope);
if (node->kind == AstNode_ProcType) {
@@ -591,7 +601,8 @@ void add_global_string_constant(gbAllocator a, String name, String value) {
}
void init_universal_scope(BuildContext *bc) {
void init_universal_scope(void) {
BuildContext *bc = &build_context;
// NOTE(bill): No need to free these
gbAllocator a = heap_allocator();
universal_scope = make_scope(NULL, a);
@@ -616,6 +627,7 @@ void init_universal_scope(BuildContext *bc) {
// 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_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_VERSION"), bc->ODIN_VERSION);
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_int_ptr = make_type_pointer(a, t_int);
t_i64_ptr = make_type_pointer(a, t_i64);
t_f64_ptr = make_type_pointer(a, t_f64);
t_u8_ptr = make_type_pointer(a, t_u8);
t_int_ptr = make_type_pointer(a, t_int);
t_i64_ptr = make_type_pointer(a, t_i64);
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_decl_info_init(&i->entities, a);
map_expr_info_init(&i->untyped, a);
map_entity_init(&i->foreign_procs, a);
map_entity_init(&i->foreigns, a);
map_isize_init(&i->type_info_map, a);
map_ast_file_init(&i->files, a);
i->type_info_count = 0;
@@ -661,7 +675,7 @@ void destroy_checker_info(CheckerInfo *i) {
map_scope_destroy(&i->scopes);
map_decl_info_destroy(&i->entities);
map_expr_info_destroy(&i->untyped);
map_entity_destroy(&i->foreign_procs);
map_entity_destroy(&i->foreigns);
map_isize_destroy(&i->type_info_map);
map_ast_file_destroy(&i->files);
}
@@ -672,8 +686,6 @@ void init_checker(Checker *c, Parser *parser, BuildContext *bc) {
c->parser = parser;
init_checker_info(&c->info);
c->sizes.word_size = bc->word_size;
c->sizes.max_align = bc->max_align;
array_init(&c->proc_stack, a);
array_init(&c->procs, a);
@@ -910,11 +922,6 @@ void add_type_info_type(Checker *c, Type *t) {
}
} break;
case Type_Maybe:
add_type_info_type(c, bt->Maybe.elem);
add_type_info_type(c, t_bool);
break;
case Type_Pointer:
add_type_info_type(c, bt->Pointer.elem);
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, t_int);
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:
add_type_info_type(c, 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;
case TypeRecord_Union:
add_type_info_type(c, t_int);
for (isize i = 0; i < bt->Record.variant_count; i++) {
Entity *f = bt->Record.variants[i];
add_type_info_type(c, f->type);
}
/* fallthrough */
default:
for (isize i = 0; i < bt->Record.field_count; i++) {
@@ -951,6 +968,12 @@ void add_type_info_type(Checker *c, Type *t) {
}
} 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:
for (isize i = 0; i < bt->Tuple.variable_count; 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->context.decl = file->decl_info;
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) {
ImplicitValueInfo info = {name, backing_name, type};
Entity *value = make_entity_implicit_value(c->allocator, info.name, info.type, id);
Entity *prev = scope_insert_entity(c->global_scope, value);
GB_ASSERT(prev == NULL);
implicit_value_infos[id] = info;
c->info.implicit_values[id] = value;
Entity *find_core_entity(Checker *c, String name) {
Entity *e = current_scope_lookup_entity(c->global_scope, name);
if (e == NULL) {
compiler_error("Could not find type declaration for `%.*s`\n"
"Is `_preload.odin` missing from the `core` directory relative to odin.exe?", LIT(name));
// NOTE(bill): This will exit the program as it's cannot continue without it!
}
return e;
}
void init_preload(Checker *c) {
if (c->done_preload) {
return;
}
if (t_type_info == NULL) {
Entity *type_info_entity = current_scope_lookup_entity(c->global_scope, 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?");
}
Entity *type_info_entity = find_core_entity(c, str_lit("Type_Info"));
t_type_info = type_info_entity->type;
t_type_info_ptr = make_type_pointer(c->allocator, t_type_info);
GB_ASSERT(is_type_union(type_info_entity->type));
TypeRecord *record = &base_type(type_info_entity->type)->Record;
t_type_info_member = type_info_member_entity->type;
t_type_info_member_ptr = make_type_pointer(c->allocator, t_type_info_member);
t_type_info_enum_value = type_info_enum_value_entity->type;
t_type_info_record = find_core_entity(c, str_lit("Type_Info_Record"))->type;
t_type_info_record_ptr = make_type_pointer(c->allocator, t_type_info_record);
t_type_info_enum_value = find_core_entity(c, str_lit("Type_Info_Enum_Value"))->type;
t_type_info_enum_value_ptr = make_type_pointer(c->allocator, t_type_info_enum_value);
if (record->field_count != 18) {
if (record->variant_count != 19) {
compiler_error("Invalid `Type_Info` layout");
}
t_type_info_named = record->fields[ 1]->type;
t_type_info_integer = record->fields[ 2]->type;
t_type_info_float = record->fields[ 3]->type;
t_type_info_any = record->fields[ 4]->type;
t_type_info_string = record->fields[ 5]->type;
t_type_info_boolean = record->fields[ 6]->type;
t_type_info_pointer = record->fields[ 7]->type;
t_type_info_maybe = record->fields[ 8]->type;
t_type_info_procedure = record->fields[ 9]->type;
t_type_info_array = record->fields[10]->type;
t_type_info_slice = record->fields[11]->type;
t_type_info_vector = record->fields[12]->type;
t_type_info_tuple = record->fields[13]->type;
t_type_info_struct = record->fields[14]->type;
t_type_info_union = record->fields[15]->type;
t_type_info_raw_union = record->fields[16]->type;
t_type_info_enum = record->fields[17]->type;
t_type_info_named = record->variants[ 1]->type;
t_type_info_integer = record->variants[ 2]->type;
t_type_info_float = record->variants[ 3]->type;
t_type_info_string = record->variants[ 4]->type;
t_type_info_boolean = record->variants[ 5]->type;
t_type_info_any = record->variants[ 6]->type;
t_type_info_pointer = record->variants[ 7]->type;
t_type_info_procedure = record->variants[ 8]->type;
t_type_info_array = record->variants[ 9]->type;
t_type_info_dynamic_array = record->variants[10]->type;
t_type_info_slice = record->variants[11]->type;
t_type_info_vector = record->variants[12]->type;
t_type_info_tuple = record->variants[13]->type;
t_type_info_struct = record->variants[14]->type;
t_type_info_raw_union = record->variants[15]->type;
t_type_info_union = record->variants[16]->type;
t_type_info_enum = record->variants[17]->type;
t_type_info_map = record->variants[18]->type;
t_type_info_named_ptr = make_type_pointer(heap_allocator(), t_type_info_named);
t_type_info_integer_ptr = make_type_pointer(heap_allocator(), t_type_info_integer);
t_type_info_float_ptr = make_type_pointer(heap_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(heap_allocator(), t_type_info_string);
t_type_info_boolean_ptr = make_type_pointer(heap_allocator(), t_type_info_boolean);
t_type_info_pointer_ptr = make_type_pointer(heap_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(heap_allocator(), t_type_info_procedure);
t_type_info_array_ptr = make_type_pointer(heap_allocator(), t_type_info_array);
t_type_info_slice_ptr = make_type_pointer(heap_allocator(), t_type_info_slice);
t_type_info_vector_ptr = make_type_pointer(heap_allocator(), t_type_info_vector);
t_type_info_tuple_ptr = make_type_pointer(heap_allocator(), t_type_info_tuple);
t_type_info_struct_ptr = make_type_pointer(heap_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(heap_allocator(), t_type_info_raw_union);
t_type_info_enum_ptr = make_type_pointer(heap_allocator(), t_type_info_enum);
t_type_info_named_ptr = make_type_pointer(c->allocator, t_type_info_named);
t_type_info_integer_ptr = make_type_pointer(c->allocator, t_type_info_integer);
t_type_info_float_ptr = make_type_pointer(c->allocator, t_type_info_float);
t_type_info_string_ptr = make_type_pointer(c->allocator, t_type_info_string);
t_type_info_boolean_ptr = make_type_pointer(c->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(c->allocator, t_type_info_pointer);
t_type_info_procedure_ptr = make_type_pointer(c->allocator, t_type_info_procedure);
t_type_info_array_ptr = make_type_pointer(c->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(c->allocator, t_type_info_slice);
t_type_info_vector_ptr = make_type_pointer(c->allocator, t_type_info_vector);
t_type_info_tuple_ptr = make_type_pointer(c->allocator, t_type_info_tuple);
t_type_info_struct_ptr = make_type_pointer(c->allocator, t_type_info_struct);
t_type_info_raw_union_ptr = make_type_pointer(c->allocator, t_type_info_raw_union);
t_type_info_union_ptr = make_type_pointer(c->allocator, t_type_info_union);
t_type_info_enum_ptr = make_type_pointer(c->allocator, t_type_info_enum);
t_type_info_map_ptr = make_type_pointer(c->allocator, t_type_info_map);
}
if (t_allocator == NULL) {
Entity *e = current_scope_lookup_entity(c->global_scope, 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?");
}
Entity *e = find_core_entity(c, str_lit("Allocator"));
t_allocator = e->type;
t_allocator_ptr = make_type_pointer(c->allocator, t_allocator);
}
if (t_context == NULL) {
Entity *e = current_scope_lookup_entity(c->global_scope, str_lit("Context"));
if (e == NULL) {
compiler_error("Could not find type declaration for `Context`\n"
"Is `runtime.odin` missing from the `core` directory relative to odin.exe?");
}
Entity *e = find_core_entity(c, str_lit("Context"));
e_context = e;
t_context = e->type;
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;
}
@@ -1228,6 +1250,9 @@ void check_procedure_overloading(Checker *c, Entity *e) {
ProcTypeOverloadKind kind = are_proc_types_overload_safe(p->type, q->type);
switch (kind) {
case ProcOverload_Identical:
error(p->token, "Overloaded procedure `%.*s` as the same type as another procedure in this scope", LIT(name));
is_invalid = true;
break;
case ProcOverload_CallingConvention:
error(p->token, "Overloaded procedure `%.*s` as the same type as another procedure in this scope", LIT(name));
is_invalid = true;
@@ -1376,8 +1401,14 @@ void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope)
di->entities = entities;
di->type_expr = vd->type;
di->init_expr = vd->values.e[0];
if (vd->flags & VarDeclFlag_thread_local) {
error_node(decl, "#thread_local variable declarations cannot have initialization values");
}
}
for_array(i, vd->names) {
AstNode *name = vd->names.e[i];
AstNode *value = NULL;
@@ -1389,8 +1420,9 @@ void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope)
continue;
}
Entity *e = make_entity_variable(c->allocator, c->context.scope, name->Ident, NULL, vd->flags & VarDeclFlag_immutable);
e->Variable.is_thread_local = vd->flags & VarDeclFlag_thread_local;
e->Variable.is_thread_local = (vd->flags & VarDeclFlag_thread_local) != 0;
e->identifier = name;
if (vd->flags & VarDeclFlag_using) {
vd->flags &= ~VarDeclFlag_using; // NOTE(bill): This error will be only caught once
error_node(name, "`using` is not allowed at the file scope");
@@ -1459,7 +1491,7 @@ void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope)
if (id->is_import) {
error_node(decl, "#import declarations are only allowed in the file scope");
} 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
// 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);
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->scope->is_init) {
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) {
if (name.len != 0) {
return name;
@@ -1596,6 +1658,12 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
ast_node(id, ImportDecl, decl);
Token token = id->relpath;
GB_ASSERT(parent_scope->is_file);
if (!parent_scope->has_been_imported) {
continue;
}
HashKey key = hash_string(id->fullpath);
Scope **found = map_scope_get(file_scopes, key);
if (found == NULL) {
@@ -1639,9 +1707,11 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
if (!previously_added) {
array_add(&parent_scope->imported, scope);
} 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("."))) {
// NOTE(bill): Add imported entities to this file's scope
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) {
continue;
}
switch (e->kind) {
case Entity_ImportName:
case Entity_LibraryName:
break;
default: {
bool ok = add_entity(c, parent_scope, NULL, e);
if (ok && id->is_import) { // `#import`ed entities don't get exported
map_bool_set(&parent_scope->implicit, hash_pointer(e), true);
if (!is_entity_kind_exported(e->kind)) {
continue;
}
if (id->is_import) {
if (is_entity_exported(e)) {
// TODO(bill): Should these entities be imported but cause an error when used?
bool ok = add_entity(c, parent_scope, NULL, e);
if (ok) {
map_bool_set(&parent_scope->implicit, hash_pointer(e), true);
}
}
} break;
} else {
add_entity(c, parent_scope, NULL, e);
}
}
} 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,
id->fullpath, id->import_name.string,
scope);
add_entity(c, parent_scope, NULL, e);
}
}
@@ -1698,6 +1773,20 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
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);
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));
@@ -1732,6 +1821,10 @@ void check_parsed_files(Checker *c) {
array_add(&c->global_scope->shared, scope);
}
if (scope->is_init || scope->is_global) {
scope->has_been_imported = true;
}
f->scope = scope;
f->decl_info = make_declaration_info(c->allocator, f->scope);
HashKey key = hash_string(f->tokenizer.fullpath);
@@ -1752,26 +1845,6 @@ void check_parsed_files(Checker *c) {
check_all_global_entities(c);
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
// 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->type != NULL) {
// i64 size = type_size_of(c->sizes, c->allocator, e->type);
i64 align = type_align_of(c->sizes, c->allocator, e->type);
i64 align = type_align_of(c->allocator, e->type);
}
}
}
+4
View File
@@ -6,6 +6,7 @@ gbAllocator heap_allocator(void) {
return gb_heap_allocator();
}
#include "unicode.c"
#include "string.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_PROC map_string_
+38 -21
View File
@@ -1,8 +1,8 @@
typedef struct Scope Scope;
typedef struct Checker Checker;
typedef struct Type Type;
typedef enum BuiltinProcId BuiltinProcId;
typedef enum ImplicitValueId ImplicitValueId;
// typedef enum BuiltinProcId BuiltinProcId;
#define ENTITY_KINDS \
ENTITY_KIND(Invalid) \
@@ -14,7 +14,6 @@ typedef enum ImplicitValueId ImplicitValueId;
ENTITY_KIND(ImportName) \
ENTITY_KIND(LibraryName) \
ENTITY_KIND(Nil) \
ENTITY_KIND(ImplicitValue) \
ENTITY_KIND(Count)
typedef enum EntityKind {
@@ -38,14 +37,18 @@ typedef enum EntityFlag {
EntityFlag_VectorElem = 1<<5,
EntityFlag_Ellipsis = 1<<6,
EntityFlag_NoAlias = 1<<7,
EntityFlag_TypeField = 1<<8,
} EntityFlag;
// Zero value means the overloading process is not yet done
typedef enum OverloadKind {
Overload_No = -1,
Overload_Unknown = 0,
Overload_Yes = +1,
Overload_Unknown,
Overload_No,
Overload_Yes,
} OverloadKind;
// An Entity is a named "thing" in the language
typedef struct Entity Entity;
struct Entity {
EntityKind kind;
@@ -79,7 +82,7 @@ struct Entity {
OverloadKind overload_kind;
} Procedure;
struct {
BuiltinProcId id;
i32 id;
} Builtin;
struct {
String path;
@@ -93,14 +96,36 @@ struct Entity {
bool used;
} LibraryName;
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 *entity = gb_alloc_item(a, Entity);
@@ -170,7 +195,7 @@ Entity *make_entity_procedure(gbAllocator a, Scope *scope, Token token, Type *si
return entity;
}
Entity *make_entity_builtin(gbAllocator a, Scope *scope, Token token, Type *type, BuiltinProcId id) {
Entity *make_entity_builtin(gbAllocator a, Scope *scope, Token token, Type *type, i32 id) {
Entity *entity = alloc_entity(a, Entity_Builtin, scope, token, type);
entity->Builtin.id = id;
return entity;
@@ -199,14 +224,6 @@ Entity *make_entity_nil(gbAllocator a, String name, Type *type) {
return entity;
}
Entity *make_entity_implicit_value(gbAllocator a, String name, Type *type, ImplicitValueId id) {
Token token = make_token_ident(name);
Entity *entity = alloc_entity(a, Entity_ImplicitValue, NULL, token, type);
entity->ImplicitValue.id = id;
return entity;
}
Entity *make_entity_dummy_variable(gbAllocator a, Scope *scope, Token token) {
token.string = str_lit("_");
return make_entity_variable(a, scope, token, NULL, false);
+85 -18
View File
@@ -60,6 +60,19 @@ ExactValue make_exact_value_integer(i64 i) {
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) {
// TODO(bill): Allow for numbers with underscores in them
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) {
// TODO(bill): Allow for numbers with underscores in them
ExactValue result = {ExactValue_Float};
result.value_float = gb_str_to_f64(cast(char *)string.text, NULL);
return result;
isize i = 0;
u8 *str = string.text;
isize len = string.len;
f64 sign = 1.0;
if (str[i] == '-') {
sign = -1.0;
i++;
} else if (*str == '+') {
i++;
}
f64 value = 0.0;
for (; i < len; i++) {
Rune r = cast(Rune)str[i];
if (r == '_') {
continue;
}
if (!gb_char_is_digit(r)) {
break;
}
i64 v = r - '0';
value *= 10.0;
value += v;
}
if (str[i] == '.') {
f64 pow10 = 10.0;
i++;
for (; i < string.len; i++) {
Rune r = cast(Rune)str[i];
if (r == '_') {
continue;
}
if (!gb_char_is_digit(r)) {
break;
}
value += (r-'0')/pow10;
pow10 *= 10.0;
}
}
f64 frac = 0;
f64 scale = 1.0;
if ((str[i] == 'e') || (str[i] == 'E')) {
i++;
if (str[i] == '-') {
frac = 1;
i++;
} else if (str[i] == '+') {
i++;
}
u32 exp;
for (exp = 0; gb_char_is_digit(str[i]); i++) {
exp = exp * 10 + (str[i]-'0');
}
if (exp > 308) exp = 308;
while (exp >= 50) { scale *= 1e50; exp -= 50; }
while (exp >= 8) { scale *= 1e8; exp -= 8; }
while (exp > 0) { scale *= 10.0; exp -= 1; }
}
f64 result = sign * (frac ? (value / scale) : (value * scale));
return make_exact_value_float(result);
}
ExactValue make_exact_value_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) {
switch (token.kind) {
@@ -209,8 +274,7 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
case ExactValue_Invalid:
return v;
case ExactValue_Integer:
i = v.value_integer;
i = ~i;
i = ~v.value_integer;
break;
default:
goto failure;
@@ -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
// limited to the types precision
if (precision > 0)
// IMPORTANT NOTE(bill): Max precision is 64 bits as that's how integers are stored
if (0 < precision && precision < 64) {
i &= ~((~0ll)<<precision);
}
return make_exact_value_integer(i);
} break;
@@ -351,6 +417,7 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
}
error:
; // MSVC accepts this??? apparently you cannot declare variables immediately after labels...
ExactValue error_value = {0};
// gb_printf_err("Invalid binary operation: %s\n", token_kind_to_string(op));
return error_value;
+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
This is a single header file with a bunch of useful stuff
@@ -58,6 +58,7 @@ TODOS
- More date & time functions
VERSION HISTORY
0.27 - OSX fixes and Linux gbAffinity
0.26d - Minor changes to how gbFile works
0.26c - gb_str_to_f* fix
0.26b - Minor fixes
@@ -276,6 +277,8 @@ extern "C" {
#include <stdarg.h>
#include <stddef.h>
#if defined(GB_SYSTEM_WINDOWS)
#if !defined(GB_NO_WINDOWS_H)
#define NOMINMAX 1
@@ -296,6 +299,9 @@ extern "C" {
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#ifndef _IOSC11_SOURCE
#define _IOSC11_SOURCE
#endif
#include <stdlib.h> // NOTE(bill): malloc on linux
#include <sys/mman.h>
#if !defined(GB_SYSTEM_OSX)
@@ -309,18 +315,18 @@ extern "C" {
#endif
#if defined(GB_SYSTEM_OSX)
#include <mach/mach.h>
#include <mach/mach_init.h>
#include <mach/mach_time.h>
#include <mach/thread_act.h>
#include <mach/thread_policy.h>
#include <sys/sysctl.h>
#include <copyfile.h>
#include <mach/clock.h>
#include <mach/mach.h>
#include <mach/mach_init.h>
#include <mach/mach_time.h>
#include <mach/thread_act.h>
#include <mach/thread_policy.h>
#include <sys/sysctl.h>
#include <copyfile.h>
#include <mach/clock.h>
#endif
#if defined(GB_SYSTEM_UNIX)
#include <semaphore.h>
#include <semaphore.h>
#endif
@@ -699,7 +705,7 @@ extern "C++" {
#endif
#ifndef gb_is_between
#define gb_is_between(x, lower, upper) (((x) >= (lower)) && ((x) <= (upper)))
#define gb_is_between(x, lower, upper) (((lower) <= (x)) && ((x) <= (upper)))
#endif
#ifndef gb_abs
@@ -1003,7 +1009,12 @@ typedef struct gbAffinity {
} gbAffinity;
#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
#error TODO(bill): Unknown system
#endif
@@ -4819,18 +4830,15 @@ GB_ALLOCATOR_PROC(gb_heap_allocator_proc) {
#else
// TODO(bill): *nix version that's decent
case gbAllocation_Alloc: {
gbAllocationHeader *header;
isize total_size = size + alignment + gb_size_of(gbAllocationHeader);
ptr = malloc(total_size);
header = cast(gbAllocationHeader *)ptr;
ptr = gb_align_forward(header+1, alignment);
gb_allocation_header_fill(header, ptr, size);
if (flags & gbAllocatorFlag_ClearToZero)
posix_memalign(&ptr, alignment, size);
if (flags & gbAllocatorFlag_ClearToZero) {
gb_zero_size(ptr, size);
}
} break;
case gbAllocation_Free: {
free(gb_allocation_header(old_memory));
free(old_memory);
} break;
case gbAllocation_Resize: {
@@ -4927,7 +4935,7 @@ isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) {
void gb_affinity_init(gbAffinity *a) {
usize count, count_size = gb_size_of(count);
a->is_accurate = false;
a->is_accurate = false;
a->thread_count = 1;
a->core_count = 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)
#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
#error TODO(bill): Unknown system
#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);
#else
// 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
}
+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]);
}
break;
case irInstr_VectorExtractElement:
array_add(ops, i->VectorExtractElement.vector);
array_add(ops, i->VectorExtractElement.index);
break;
case irInstr_VectorInsertElement:
array_add(ops, i->VectorInsertElement.vector);
array_add(ops, i->VectorInsertElement.elem);
array_add(ops, i->VectorInsertElement.index);
break;
case irInstr_VectorShuffle:
array_add(ops, i->VectorShuffle.vector);
break;
// case irInstr_VectorExtractElement:
// array_add(ops, i->VectorExtractElement.vector);
// array_add(ops, i->VectorExtractElement.index);
// break;
// case irInstr_VectorInsertElement:
// array_add(ops, i->VectorInsertElement.vector);
// array_add(ops, i->VectorInsertElement.elem);
// array_add(ops, i->VectorInsertElement.index);
// break;
// case irInstr_VectorShuffle:
// array_add(ops, i->VectorShuffle.vector);
// break;
case irInstr_StartupRuntime:
break;
case irInstr_BoundsCheck:
@@ -258,7 +258,7 @@ void ir_opt_blocks(irProcedure *proc) {
if (b == NULL) {
continue;
}
GB_ASSERT(b->index == i);
GB_ASSERT_MSG(b->index == i, "%d, %td", b->index, i);
if (ir_opt_block_fusion(proc, b)) {
changed = true;
@@ -467,7 +467,7 @@ void ir_opt_tree(irGen *s) {
}
ir_opt_blocks(proc);
#if 1
#if 0
ir_opt_build_referrers(proc);
ir_opt_build_dom_tree(proc);
+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) {
BaseTypeSizes s = m->sizes;
i64 word_bits = 8*s.word_size;
i64 word_bits = 8*build_context.word_size;
GB_ASSERT_NOT_NULL(t);
t = default_type(t);
GB_ASSERT(is_type_typed(t));
@@ -172,35 +171,48 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
ir_print_type(f, m, t->Pointer.elem);
ir_fprintf(f, "*");
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:
ir_fprintf(f, "[%lld x ", t->Array.count);
ir_print_type(f, m, t->Array.elem);
ir_fprintf(f, "]");
return;
case Type_Vector:
ir_fprintf(f, "<%lld x ", t->Vector.count);
case Type_Vector: {
i64 align = type_align_of(heap_allocator(), t);
i64 count = t->Vector.count;
ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x ", align, count);
ir_print_type(f, m, t->Vector.elem);
ir_fprintf(f, "]}");
return;
}
/* ir_fprintf(f, "<%lld x ", t->Vector.count);
ir_print_type(f, m, t->Vector.elem);
ir_fprintf(f, ">");
return;
return; */
case Type_Slice:
ir_fprintf(f, "{");
ir_print_type(f, m, t->Slice.elem);
ir_fprintf(f, "*, i%lld, i%lld}", word_bits, word_bits);
return;
case Type_DynamicArray:
ir_fprintf(f, "{");
ir_print_type(f, m, t->DynamicArray.elem);
ir_fprintf(f, "*, i%lld, i%lld,", word_bits, word_bits);
ir_print_type(f, m, t_allocator);
ir_fprintf(f, "}");
return;
case Type_Record: {
switch (t->Record.kind) {
case TypeRecord_Struct:
if (t->Record.struct_is_packed) {
if (t->Record.is_packed) {
ir_fprintf(f, "<");
}
ir_fprintf(f, "{");
if (t->Record.custom_align > 0) {
ir_fprintf(f, "[0 x <%lld x i8>]", t->Record.custom_align);
if (t->Record.field_count > 0) {
ir_fprintf(f, ", ");
}
}
for (isize i = 0; i < t->Record.field_count; i++) {
if (i > 0) {
ir_fprintf(f, ", ");
@@ -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_fprintf(f, "}");
if (t->Record.struct_is_packed) {
if (t->Record.is_packed) {
ir_fprintf(f, ">");
}
return;
case TypeRecord_Union: {
// NOTE(bill): The zero size array is used to fix the alignment used in a structure as
// LLVM takes the first element's alignment as the entire alignment (like C)
i64 size_of_union = type_size_of(s, heap_allocator(), t) - s.word_size;
i64 align_of_union = type_align_of(s, heap_allocator(), t);
i64 size_of_union = type_size_of(heap_allocator(), t) - build_context.word_size;
i64 align_of_union = type_align_of(heap_allocator(), t);
ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8], i%lld}", align_of_union, size_of_union, word_bits);
} return;
case TypeRecord_RawUnion: {
// NOTE(bill): The zero size array is used to fix the alignment used in a structure as
// LLVM takes the first element's alignment as the entire alignment (like C)
i64 size_of_union = type_size_of(s, heap_allocator(), t);
i64 align_of_union = type_align_of(s, heap_allocator(), t);
i64 size_of_union = type_size_of(heap_allocator(), t);
i64 align_of_union = type_align_of(heap_allocator(), t);
ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8]}", align_of_union, size_of_union);
} return;
case TypeRecord_Enum:
@@ -272,6 +284,11 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
}
ir_fprintf(f, ")*");
} return;
case Type_Map: {
GB_ASSERT(t->Map.generated_struct_type != NULL);
ir_print_type(f, m, t->Map.generated_struct_type);
} break;
}
}
@@ -281,25 +298,11 @@ void ir_print_compound_element(irFileBuffer *f, irModule *m, ExactValue v, Type
ir_print_type(f, m, elem_type);
ir_fprintf(f, " ");
if (v.kind != ExactValue_Invalid && is_type_maybe(elem_type)) {
Type *t = base_type(elem_type)->Maybe.elem;
ir_fprintf(f, "{");
ir_print_type(f, m, t);
ir_fprintf(f, " ");
}
if (v.kind == ExactValue_Invalid || base_type(elem_type) == t_any) {
ir_fprintf(f, "zeroinitializer");
} else {
ir_print_exact_value(f, m, v, elem_type);
}
if (v.kind != ExactValue_Invalid && is_type_maybe(elem_type)) {
ir_fprintf(f, ", ");
ir_print_type(f, m, t_bool);
ir_fprintf(f, " ");
ir_fprintf(f, "true}");
}
}
void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *type) {
@@ -451,9 +454,14 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
break;
}
ir_fprintf(f, "<");
i64 align = type_align_of(m->allocator, type);
i64 count = type->Vector.count;
Type *elem_type = type->Vector.elem;
ir_fprintf(f, "{[0 x <%lld x i8>] zeroinitializer, [%lld x ", align, count);
ir_print_type(f, m, elem_type);
ir_fprintf(f, "][");
if (elem_count == 1 && type->Vector.count > 1) {
TypeAndValue *tav = type_and_value_of_expression(m->info, cl->elems.e[0]);
GB_ASSERT(tav != NULL);
@@ -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)) {
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, "{");
@@ -535,7 +543,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
ir_fprintf(f, "}");
if (type->Record.struct_is_packed) {
if (type->Record.is_packed) {
ir_fprintf(f, ">");
}
@@ -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_fprintf(f, " 0, i32 0), ");
ir_print_type(f, m, t_int);
ir_fprintf(f, " %lld, ", cs->count);
ir_print_type(f, m, t_int);
ir_fprintf(f, " %lld}", cs->count);
}
} break;
@@ -658,6 +664,11 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_fprintf(f, "\t");
switch (instr->kind) {
default: {
GB_PANIC("<unknown instr> %d\n", instr->kind);
ir_fprintf(f, "; <unknown instr> %d\n", instr->kind);
} break;
case irInstr_StartupRuntime: {
ir_fprintf(f, "call void ");
ir_print_encoded_global(f, str_lit(IR_STARTUP_RUNTIME_PROC_NAME), false);
@@ -672,7 +683,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
Type *type = instr->Local.entity->type;
ir_fprintf(f, "%%%d = alloca ", value->index);
ir_print_type(f, m, type);
ir_fprintf(f, ", align %lld\n", type_align_of(m->sizes, m->allocator, type));
ir_fprintf(f, ", align %lld\n", type_align_of(m->allocator, type));
} break;
case irInstr_ZeroInit: {
@@ -705,7 +716,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_print_type(f, m, type);
ir_fprintf(f, "* ");
ir_print_value(f, m, instr->Load.address, type);
ir_fprintf(f, ", align %lld\n", type_align_of(m->sizes, m->allocator, type));
ir_fprintf(f, ", align %lld\n", type_align_of(m->allocator, type));
} break;
case irInstr_ArrayElementPtr: {
@@ -720,6 +731,10 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_fprintf(f, ", ");
ir_print_type(f, m, t_int);
ir_fprintf(f, " 0, ");
if (is_type_vector(type_deref(et))) {
ir_print_type(f, m, t_i32);
ir_fprintf(f, " 1, ");
}
irValue *index =instr->ArrayElementPtr.elem_index;
Type *t = ir_type(index);
@@ -732,6 +747,13 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
case irInstr_StructElementPtr: {
Type *et = ir_type(instr->StructElementPtr.address);
ir_fprintf(f, "%%%d = getelementptr inbounds ", value->index);
i32 index = instr->StructElementPtr.elem_index;
Type *st = base_type(type_deref(et));
if (is_type_struct(st)) {
if (st->Record.custom_align > 0) {
index += 1;
}
}
ir_print_type(f, m, type_deref(et));
ir_fprintf(f, ", ");
@@ -742,7 +764,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_print_type(f, m, t_int);
ir_fprintf(f, " 0, ");
ir_print_type(f, m, t_i32);
ir_fprintf(f, " %d", instr->StructElementPtr.elem_index);
ir_fprintf(f, " %d", index);
ir_fprintf(f, "\n");
} break;
@@ -793,11 +815,19 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
case irInstr_StructExtractValue: {
Type *et = ir_type(instr->StructExtractValue.address);
ir_fprintf(f, "%%%d = extractvalue ", value->index);
i32 index = instr->StructExtractValue.index;
Type *st = base_type(et);
if (is_type_struct(st)) {
if (st->Record.custom_align > 0) {
index += 1;
}
}
ir_print_type(f, m, et);
ir_fprintf(f, " ");
ir_print_value(f, m, instr->StructExtractValue.address, et);
ir_fprintf(f, ", %d\n", instr->StructExtractValue.index);
ir_fprintf(f, ", %d\n", index);
} break;
case irInstr_UnionTagPtr: {
@@ -814,6 +844,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_fprintf(f, " 0, ");
ir_print_type(f, m, t_i32);
ir_fprintf(f, " %d", 2);
ir_fprintf(f, " ; UnionTagPtr");
ir_fprintf(f, "\n");
} break;
@@ -824,7 +855,9 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_print_type(f, m, et);
ir_fprintf(f, " ");
ir_print_value(f, m, instr->UnionTagValue.address, et);
ir_fprintf(f, ", %d\n", 2);
ir_fprintf(f, ", %d", 2);
ir_fprintf(f, " ; UnionTagValue");
ir_fprintf(f, "\n");
} break;
case irInstr_Jump: {;
@@ -929,6 +962,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
irInstrBinaryOp *bo = &value->Instr.BinaryOp;
Type *type = base_type(ir_type(bo->left));
Type *elem_type = type;
GB_ASSERT(!is_type_vector(elem_type));
while (elem_type->kind == Type_Vector) {
elem_type = base_type(elem_type->Vector.elem);
}
@@ -1095,68 +1129,68 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_fprintf(f, "\n");
} break;
case irInstr_VectorExtractElement: {
Type *vt = ir_type(instr->VectorExtractElement.vector);
Type *it = ir_type(instr->VectorExtractElement.index);
ir_fprintf(f, "%%%d = extractelement ", value->index);
// case irInstr_VectorExtractElement: {
// Type *vt = ir_type(instr->VectorExtractElement.vector);
// Type *it = ir_type(instr->VectorExtractElement.index);
// ir_fprintf(f, "%%%d = extractelement ", value->index);
ir_print_type(f, m, vt);
ir_fprintf(f, " ");
ir_print_value(f, m, instr->VectorExtractElement.vector, vt);
ir_fprintf(f, ", ");
ir_print_type(f, m, it);
ir_fprintf(f, " ");
ir_print_value(f, m, instr->VectorExtractElement.index, it);
ir_fprintf(f, "\n");
} break;
// ir_print_type(f, m, vt);
// ir_fprintf(f, " ");
// ir_print_value(f, m, instr->VectorExtractElement.vector, vt);
// ir_fprintf(f, ", ");
// ir_print_type(f, m, it);
// ir_fprintf(f, " ");
// ir_print_value(f, m, instr->VectorExtractElement.index, it);
// ir_fprintf(f, "\n");
// } break;
case irInstr_VectorInsertElement: {
irInstrVectorInsertElement *ie = &instr->VectorInsertElement;
Type *vt = ir_type(ie->vector);
ir_fprintf(f, "%%%d = insertelement ", value->index);
// case irInstr_VectorInsertElement: {
// irInstrVectorInsertElement *ie = &instr->VectorInsertElement;
// Type *vt = ir_type(ie->vector);
// ir_fprintf(f, "%%%d = insertelement ", value->index);
ir_print_type(f, m, vt);
ir_fprintf(f, " ");
ir_print_value(f, m, ie->vector, vt);
ir_fprintf(f, ", ");
// ir_print_type(f, m, vt);
// ir_fprintf(f, " ");
// ir_print_value(f, m, ie->vector, vt);
// ir_fprintf(f, ", ");
ir_print_type(f, m, ir_type(ie->elem));
ir_fprintf(f, " ");
ir_print_value(f, m, ie->elem, ir_type(ie->elem));
ir_fprintf(f, ", ");
// ir_print_type(f, m, ir_type(ie->elem));
// ir_fprintf(f, " ");
// ir_print_value(f, m, ie->elem, ir_type(ie->elem));
// ir_fprintf(f, ", ");
ir_print_type(f, m, ir_type(ie->index));
ir_fprintf(f, " ");
ir_print_value(f, m, ie->index, ir_type(ie->index));
// ir_print_type(f, m, ir_type(ie->index));
// ir_fprintf(f, " ");
// ir_print_value(f, m, ie->index, ir_type(ie->index));
ir_fprintf(f, "\n");
} break;
// ir_fprintf(f, "\n");
// } break;
case irInstr_VectorShuffle: {
irInstrVectorShuffle *sv = &instr->VectorShuffle;
Type *vt = ir_type(sv->vector);
ir_fprintf(f, "%%%d = shufflevector ", value->index);
// case irInstr_VectorShuffle: {
// irInstrVectorShuffle *sv = &instr->VectorShuffle;
// Type *vt = ir_type(sv->vector);
// ir_fprintf(f, "%%%d = shufflevector ", value->index);
ir_print_type(f, m, vt);
ir_fprintf(f, " ");
ir_print_value(f, m, sv->vector, vt);
ir_fprintf(f, ", ");
// ir_print_type(f, m, vt);
// ir_fprintf(f, " ");
// ir_print_value(f, m, sv->vector, vt);
// ir_fprintf(f, ", ");
ir_print_type(f, m, vt);
ir_fprintf(f, " ");
ir_print_value(f, m, sv->vector, vt);
ir_fprintf(f, ", ");
// ir_print_type(f, m, vt);
// ir_fprintf(f, " ");
// ir_print_value(f, m, sv->vector, vt);
// ir_fprintf(f, ", ");
ir_fprintf(f, "<%td x i32> <", sv->index_count);
for (isize i = 0; i < sv->index_count; i++) {
if (i > 0) {
ir_fprintf(f, ", ");
}
ir_fprintf(f, "i32 %d", sv->indices[i]);
}
ir_fprintf(f, ">");
ir_fprintf(f, "\n");
} break;
// ir_fprintf(f, "<%td x i32> <", sv->index_count);
// for (isize i = 0; i < sv->index_count; i++) {
// if (i > 0) {
// ir_fprintf(f, ", ");
// }
// ir_fprintf(f, "i32 %d", sv->indices[i]);
// }
// ir_fprintf(f, ">");
// ir_fprintf(f, "\n");
// } break;
case irInstr_BoundsCheck: {
irInstrBoundsCheck *bc = &instr->BoundsCheck;
@@ -1220,13 +1254,37 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_fprintf(f, " ");
ir_print_value(f, m, bc->high, t_int);
if (!bc->is_substring) {
ir_fprintf(f, ", ");
ir_print_type(f, m, t_int);
ir_fprintf(f, " ");
ir_print_value(f, m, bc->max, t_int);
}
ir_fprintf(f, ")\n");
} break;
case irInstr_DebugDeclare: {
/* irInstrDebugDeclare *dd = &instr->DebugDeclare;
Type *vt = ir_type(dd->value);
irDebugInfo *di = dd->debug_info;
Entity *e = dd->entity;
String name = e->token.string;
TokenPos pos = e->token.pos;
// gb_printf("debug_declare %.*s\n", LIT(dd->entity->token.string));
ir_fprintf(f, "call void @llvm.dbg.declare(");
ir_fprintf(f, "metadata ");
ir_print_type(f, m, vt);
ir_fprintf(f, " ");
ir_print_value(f, m, dd->value, vt);
ir_fprintf(f, ", metadata !DILocalVariable(name: \"");
ir_print_escape_string(f, name, false);
ir_fprintf(f, "\", scope: !%d, line: %td)", di->id, pos.line);
ir_fprintf(f, ", metadata !DIExpression()");
ir_fprintf(f, ")");
ir_fprintf(f, ", !dbg !DILocation(line: %td, column: %td, scope: !%d)", pos.line, pos.column, di->id);
default: {
GB_PANIC("<unknown instr> %d\n", instr->kind);
ir_fprintf(f, "; <unknown instr> %d\n", instr->kind);
ir_fprintf(f, "\n"); */
} break;
}
}
@@ -1241,7 +1299,7 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
} else {
ir_fprintf(f, "\n");
ir_fprintf(f, "define ");
if (m->build_context->is_dll) {
if (build_context.is_dll) {
// if (proc->tags & (ProcTag_export|ProcTag_dll_export)) {
if (proc->tags & (ProcTag_export)) {
ir_fprintf(f, "dllexport ");
@@ -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) {
irDebugInfo *di = *map_ir_debug_info_get(&proc->module->debug_info, hash_pointer(proc->entity));
GB_ASSERT(di->kind == irDebugInfo_Proc);
ir_fprintf(f, "!dbg !%d ", di->id);
irDebugInfo **di_ = map_ir_debug_info_get(&proc->module->debug_info, hash_pointer(proc->entity));
if (di_ != NULL) {
irDebugInfo *di = *di_;
GB_ASSERT(di->kind == irDebugInfo_Proc);
// ir_fprintf(f, "!dbg !%d ", di->id);
}
}
}
@@ -1365,6 +1426,8 @@ void print_llvm_ir(irGen *ir) {
ir_print_type(f, m, t_rawptr);
ir_fprintf(f, "} ; Basic_any\n");
ir_fprintf(f, "declare void @llvm.dbg.declare(metadata, metadata, metadata) nounwind readnone \n");
for_array(member_index, m->members.entries) {
MapIrValueEntry *entry = &m->members.entries.e[member_index];
@@ -1417,6 +1480,9 @@ void print_llvm_ir(irGen *ir) {
}
ir_print_encoded_global(f, g->entity->token.string, in_global_scope);
ir_fprintf(f, " = ");
if (g->is_foreign) {
ir_fprintf(f, "external ");
}
if (g->is_thread_local) {
ir_fprintf(f, "thread_local ");
}
@@ -1436,19 +1502,30 @@ void print_llvm_ir(irGen *ir) {
ir_print_type(f, m, g->entity->type);
ir_fprintf(f, " ");
if (g->value != NULL) {
ir_print_value(f, m, g->value, g->entity->type);
} else {
ir_fprintf(f, "zeroinitializer");
if (!g->is_foreign) {
if (g->value != NULL) {
ir_print_value(f, m, g->value, g->entity->type);
} else {
ir_fprintf(f, "zeroinitializer");
}
}
ir_fprintf(f, "\n");
}
#if 0
if (m->generate_debug_info) {
// if (m->generate_debug_info) {
{
ir_fprintf(f, "\n");
i32 diec = m->debug_info.entries.count;
ir_fprintf(f, "!llvm.dbg.cu = !{!0}\n");
ir_fprintf(f, "!llvm.ident = !{!%d}\n", diec+3);
ir_fprintf(f, "!%d = !{i32 2, !\"Dwarf Version\", i32 4}\n", diec+0);
ir_fprintf(f, "!%d = !{i32 2, !\"Debug Info Version\", i32 3}\n", diec+1);
ir_fprintf(f, "!%d = !{i32 1, !\"PIC Level\", i32 2}\n", diec+2);
ir_fprintf(f, "!%d = !{!\"clang version 3.9.0 (branches/release_39)\"}\n", diec+3);
for_array(di_index, m->debug_info.entries) {
MapIrDebugInfoEntry *entry = &m->debug_info.entries.e[di_index];
@@ -1457,19 +1534,18 @@ void print_llvm_ir(irGen *ir) {
switch (di->kind) {
case irDebugInfo_CompileUnit: {
auto *cu = &di->CompileUnit;
irDebugInfo *file = *map_ir_debug_info_get(&m->debug_info, hash_pointer(cu->file));
irDebugInfo *file = *map_ir_debug_info_get(&m->debug_info, hash_pointer(di->CompileUnit.file));
ir_fprintf(f,
"distinct !DICompileUnit("
"language: DW_LANG_Go, " // Is this good enough?
"file: !%d, "
"producer: \"%.*s\", "
"producer: \"clang version 3.9.0 (branches/release_39)\", "
"flags: \"\", "
"runtimeVersion: 0, "
"isOptimized: false, "
"emissionKind: FullDebug"
")",
file->id, LIT(cu->producer));
file->id);
} break;
case irDebugInfo_File:
+68 -18
View File
@@ -2,10 +2,10 @@
extern "C" {
#endif
#include "common.c"
#include "timings.c"
#include "unicode.c"
#include "build.c"
#include "build_settings.c"
#include "tokenizer.c"
#include "parser.c"
// #include "printer.c"
@@ -16,8 +16,9 @@ extern "C" {
#include "ir_print.c"
// #include "vm.c"
#if defined(GB_SYSTEM_WINDOWS)
// NOTE(bill): `name` is used in debugging and profiling modes
i32 win32_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
STARTUPINFOW start_info = {gb_size_of(STARTUPINFOW)};
PROCESS_INFORMATION pi = {0};
char cmd_line[4096] = {0};
@@ -59,6 +60,54 @@ i32 win32_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
gb_temp_arena_memory_end(tmp);
return exit_code;
}
#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
char cmd_line[4096] = {0};
isize cmd_len;
va_list va;
String cmd;
i32 exit_code = 0;
va_start(va, fmt);
cmd_len = gb_snprintf_va(cmd_line, gb_size_of(cmd_line), fmt, va);
va_end(va);
cmd = make_string(cast(u8 *)&cmd_line, cmd_len-1);
exit_code = system(&cmd_line[0]);
// pid_t pid = fork();
// int status = 0;
// if(pid == 0) {
// // in child, pid == 0.
// int ret = execvp(cmd.text, (char* const*) cmd.text);
// if(ret == -1) {
// gb_printf_err("Failed to execute command:\n\t%s\n", cmd_line);
// // we're in the child, so returning won't do us any good -- just quit.
// exit(-1);
// }
// // unreachable
// abort();
// } else {
// // wait for child to finish, then we can continue cleanup
// int s = 0;
// waitpid(pid, &s, 0);
// status = WEXITSTATUS(s);
// }
// exit_code = status;
}
#endif
void print_usage_line(i32 indent, char *fmt, ...) {
while (indent --> 0) {
@@ -97,10 +146,9 @@ int main(int argc, char **argv) {
#if 1
BuildContext build_context = {0};
init_build_context(&build_context);
init_build_context();
init_universal_scope(&build_context);
init_universal_scope();
char *init_filename = NULL;
bool run_output = false;
@@ -169,12 +217,12 @@ int main(int argc, char **argv) {
return 1;
}
ssa_generate(&checker.info, &build_context);
#endif
#if 1
if (!ssa_generate(&checker.info)) {
return 1;
}
#else
irGen ir_gen = {0};
if (!ir_gen_init(&ir_gen, &checker, &build_context)) {
if (!ir_gen_init(&ir_gen, &checker)) {
return 1;
}
// defer (ssa_gen_destroy(&ir_gen));
@@ -190,7 +238,7 @@ int main(int argc, char **argv) {
// prof_print_all();
#if 1
#if 1
timings_start_section(&timings, str_lit("llvm-opt"));
char const *output_name = ir_gen.output_file.filename;
@@ -202,7 +250,7 @@ int main(int argc, char **argv) {
i32 exit_code = 0;
// For more passes arguments: http://llvm.org/docs/Passes.html
exit_code = win32_exec_command_line_app("llvm-opt", false,
exit_code = system_exec_command_line_app("llvm-opt", false,
"\"%.*sbin/opt\" \"%s\" -o \"%.*s\".bc "
"-mem2reg "
"-memcpyopt "
@@ -217,10 +265,10 @@ int main(int argc, char **argv) {
return exit_code;
}
#if 1
#if defined(GB_SYSTEM_WINDOWS)
timings_start_section(&timings, str_lit("llvm-llc"));
// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
exit_code = win32_exec_command_line_app("llvm-llc", false,
exit_code = system_exec_command_line_app("llvm-llc", false,
"\"%.*sbin/llc\" \"%.*s.bc\" -filetype=obj -O%d "
"%.*s "
// "-debug-pass=Arguments "
@@ -255,7 +303,7 @@ int main(int argc, char **argv) {
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 "
"/defaultlib:libcmt "
"/nologo /incremental:no /opt:ref /subsystem:CONSOLE "
@@ -273,14 +321,16 @@ int main(int argc, char **argv) {
// timings_print_all(&timings);
if (run_output) {
win32_exec_command_line_app("odin run", false, "%.*s.exe", cast(int)base_name_len, output_name);
system_exec_command_line_app("odin run", false, "%.*s.exe", cast(int)base_name_len, output_name);
}
#else
#error Implement build stuff for this platform
#endif
#endif
#endif
#endif
return 0;
}
+3
View File
@@ -6,6 +6,9 @@
#define MAP_NAME MapString
#include "map.c"
*/
// A `Map` is an unordered hash table which can allow for a key to point to multiple values
// with the use of the `multi_*` procedures.
// TODO(bill): I should probably allow the `multi_*` stuff to be #ifdefed out
#ifndef MAP_UTIL_STUFF
#define MAP_UTIL_STUFF
+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;
// NOTE(bill): used for printf style arguments
#define LIT(x) ((int)(x).len), (x).text
#define STR_LIT(c_str) {cast(u8 *)c_str, gb_size_of(c_str)-1}
#define str_lit(c_str) (String){cast(u8 *)c_str, gb_size_of(c_str)-1}
// NOTE(bill): String16 is only used for Windows due to its file directories
typedef struct String16 {
wchar_t *text;
isize len;
@@ -46,7 +49,6 @@ gb_inline String make_string_c(char *text) {
return make_string(cast(u8 *)cast(void *)text, gb_strlen(text));
}
#define str_lit(c_str) (String){cast(u8 *)c_str, gb_size_of(c_str)-1}
@@ -144,16 +146,37 @@ gb_inline isize string_extension_position(String str) {
return dot_pos;
}
String string_trim_whitespace(String str) {
while (str.len > 0 && rune_is_whitespace(str.text[str.len-1])) {
str.len--;
}
while (str.len > 0 && rune_is_whitespace(str.text[0])) {
str.text++;
str.len--;
}
return str;
}
gb_inline bool string_has_extension(String str, String ext) {
if (str.len > ext.len+1) {
u8 *s = str.text+str.len - ext.len-1;
if (s[0] == '.') {
s++;
return gb_memcompare(s, ext.text, ext.len) == 0;
}
str = string_trim_whitespace(str);
if (str.len <= ext.len+1) {
return false;
}
return false;
isize len = str.len;
for (isize i = len-1; i >= 0; i--) {
if (str.text[i] == '.') {
break;
}
len--;
}
if (len == 0) {
return false;
}
u8 *s = str.text + len;
return gb_memcompare(s, ext.text, ext.len) == 0;
}
bool string_contains_char(String s, u8 c) {
@@ -165,6 +188,47 @@ bool string_contains_char(String s, u8 c) {
return false;
}
#if defined(GB_SYSTEM_WINDOWS)
int convert_multibyte_to_widechar(char *multibyte_input, int input_length, wchar_t *output, int output_size) {
return MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, multibyte_input, input_length, output, output_size);
}
int convert_widechar_to_multibyte(wchar_t *widechar_input, int input_length, char *output, int output_size) {
return WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, widechar_input, input_length, output, output_size, NULL, NULL);
}
#elif defined(GB_SYSTEM_UNIX) || defined(GB_SYSTEM_OSX)
#include <iconv.h>
int convert_multibyte_to_widechar(char *multibyte_input, int input_length, wchar_t *output, int output_size) {
iconv_t conv = iconv_open("WCHAR_T", "UTF-8");
size_t result = iconv(conv, cast(char **)&multibyte_input, &input_length, cast(char **)&output, &output_size);
iconv_close(conv);
return (int) result;
}
int convert_widechar_to_multibyte(wchar_t* widechar_input, int input_length, char* output, int output_size) {
iconv_t conv = iconv_open("UTF-8", "WCHAR_T");
size_t result = iconv(conv, (char**) &widechar_input, &input_length, (char**) &output, &output_size);
iconv_close(conv);
return (int) result;
}
#else
#error Implement system
#endif
// TODO(bill): Make this non-windows specific
String16 string_to_string16(gbAllocator a, String s) {
int len, len1;
@@ -174,16 +238,14 @@ String16 string_to_string16(gbAllocator a, String s) {
return make_string16(NULL, 0);
}
len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
cast(char *)s.text, s.len, NULL, 0);
len = convert_multibyte_to_widechar(cast(char *)s.text, s.len, NULL, 0);
if (len == 0) {
return make_string16(NULL, 0);
}
text = gb_alloc_array(a, wchar_t, len+1);
len1 = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
cast(char *)s.text, s.len, text, len);
len1 = convert_multibyte_to_widechar(cast(char *)s.text, s.len, text, len);
if (len1 == 0) {
gb_free(a, text);
return make_string16(NULL, 0);
@@ -201,16 +263,14 @@ String string16_to_string(gbAllocator a, String16 s) {
return make_string(NULL, 0);
}
len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
s.text, s.len, NULL, 0, NULL, NULL);
len = convert_widechar_to_multibyte(s.text, s.len, NULL, 0);
if (len == 0) {
return make_string(NULL, 0);
}
text = gb_alloc_array(a, u8, len+1);
len1 = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
s.text, s.len, cast(char *)text, len, NULL, NULL);
len1 = convert_widechar_to_multibyte(s.text, s.len, cast(char *)text, len);
if (len1 == 0) {
gb_free(a, text);
return make_string(NULL, 0);
@@ -236,7 +296,6 @@ String string16_to_string(gbAllocator a, String16 s) {
bool unquote_char(String s, u8 quote, Rune *rune, bool *multiple_bytes, String *tail_string) {
u8 c;
+38
View File
@@ -11,6 +11,7 @@ typedef struct Timings {
} Timings;
#if defined(GB_SYSTEM_WINDOWS)
u64 win32_time_stamp_time_now(void) {
LARGE_INTEGER counter;
QueryPerformanceCounter(&counter);
@@ -27,9 +28,44 @@ u64 win32_time_stamp__freq(void) {
return win32_perf_count_freq.QuadPart;
}
#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
#include <time.h>
u64 unix_time_stamp_time_now(void) {
struct timespec ts;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
return (ts.tv_sec * 1000000000) + ts.tv_nsec;
}
u64 unix_time_stamp__freq(void) {
gb_local_persist u64 freq = 0;
if (freq == 0) {
struct timespec ts;
clock_getres(CLOCK_PROCESS_CPUTIME_ID, &ts);
// that would be an absurd resolution (or lack thereof)
GB_ASSERT(ts.tv_sec == 0);
freq = cast(u64) ((1.0 / ts.tv_nsec) * 1000000000.0);
GB_ASSERT(freq != 0);
}
return freq;
}
#else
#error Implement system
#endif
u64 time_stamp_time_now(void) {
#if defined(GB_SYSTEM_WINDOWS)
return win32_time_stamp_time_now();
#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
return unix_time_stamp_time_now();
#else
#error time_stamp_time_now
#endif
@@ -38,6 +74,8 @@ u64 time_stamp_time_now(void) {
u64 time_stamp__freq(void) {
#if defined(GB_SYSTEM_WINDOWS)
return win32_time_stamp__freq();
#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
return unix_time_stamp__freq();
#else
#error time_stamp__freq
#endif
+120 -140
View File
@@ -12,28 +12,24 @@ TOKEN_KIND(Token__LiteralBegin, "_LiteralBegin"), \
TOKEN_KIND(Token__LiteralEnd, "_LiteralEnd"), \
\
TOKEN_KIND(Token__OperatorBegin, "_OperatorBegin"), \
TOKEN_KIND(Token_Eq, "="), \
TOKEN_KIND(Token_Not, "!"), \
TOKEN_KIND(Token_Hash, "#"), \
TOKEN_KIND(Token_At, "@"), \
TOKEN_KIND(Token_Pointer, "^"), \
TOKEN_KIND(Token_Maybe, "?"), \
TOKEN_KIND(Token_Add, "+"), \
TOKEN_KIND(Token_Sub, "-"), \
TOKEN_KIND(Token_Mul, "*"), \
TOKEN_KIND(Token_Quo, "/"), \
TOKEN_KIND(Token_Mod, "%"), \
TOKEN_KIND(Token_And, "&"), \
TOKEN_KIND(Token_Or, "|"), \
TOKEN_KIND(Token_Xor, "~"), \
TOKEN_KIND(Token_AndNot, "&~"), \
TOKEN_KIND(Token_Shl, "<<"), \
TOKEN_KIND(Token_Shr, ">>"), \
\
/*TOKEN_KIND(Token_as, "as"), */\
/*TOKEN_KIND(Token_transmute, "transmute"), */\
/*TOKEN_KIND(Token_down_cast, "down_cast"), */\
/*TOKEN_KIND(Token_union_cast, "union_cast"), */\
TOKEN_KIND(Token_Eq, "="), \
TOKEN_KIND(Token_Not, "!"), \
TOKEN_KIND(Token_Hash, "#"), \
TOKEN_KIND(Token_At, "@"), \
TOKEN_KIND(Token_Dollar, "$"), \
TOKEN_KIND(Token_Pointer, "^"), \
TOKEN_KIND(Token_Question, "?"), \
TOKEN_KIND(Token_Add, "+"), \
TOKEN_KIND(Token_Sub, "-"), \
TOKEN_KIND(Token_Mul, "*"), \
TOKEN_KIND(Token_Quo, "/"), \
TOKEN_KIND(Token_Mod, "%"), \
TOKEN_KIND(Token_And, "&"), \
TOKEN_KIND(Token_Or, "|"), \
TOKEN_KIND(Token_Xor, "~"), \
TOKEN_KIND(Token_AndNot, "&~"), \
TOKEN_KIND(Token_Shl, "<<"), \
TOKEN_KIND(Token_Shr, ">>"), \
\
TOKEN_KIND(Token_CmpAnd, "&&"), \
TOKEN_KIND(Token_CmpOr, "||"), \
@@ -55,6 +51,8 @@ TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \
TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \
TOKEN_KIND(Token_ArrowRight, "->"), \
TOKEN_KIND(Token_ArrowLeft, "<-"), \
TOKEN_KIND(Token_Inc, "++"), \
TOKEN_KIND(Token_Dec, "--"), \
\
TOKEN_KIND(Token__ComparisonBegin, "_ComparisonBegin"), \
TOKEN_KIND(Token_CmpEq, "=="), \
@@ -76,45 +74,45 @@ TOKEN_KIND(Token__ComparisonEnd, "_ComparisonEnd"), \
TOKEN_KIND(Token_Period, "."), \
TOKEN_KIND(Token_Comma, ","), \
TOKEN_KIND(Token_Ellipsis, ".."), \
TOKEN_KIND(Token_HalfOpenRange, "..<"), \
/* TOKEN_KIND(Token_HalfOpenRange, "..<"), */ \
TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \
\
TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
TOKEN_KIND(Token_type, "type"), \
TOKEN_KIND(Token_proc, "proc"), \
TOKEN_KIND(Token_macro, "macro"), \
TOKEN_KIND(Token_match, "match"), \
TOKEN_KIND(Token_break, "break"), \
TOKEN_KIND(Token_continue, "continue"), \
TOKEN_KIND(Token_fallthrough, "fallthrough"), \
TOKEN_KIND(Token_case, "case"), \
TOKEN_KIND(Token_default, "default"), \
TOKEN_KIND(Token_then, "then"), \
TOKEN_KIND(Token_if, "if"), \
TOKEN_KIND(Token_else, "else"), \
TOKEN_KIND(Token_for, "for"), \
TOKEN_KIND(Token_in, "in"), \
TOKEN_KIND(Token_when, "when"), \
TOKEN_KIND(Token_range, "range"), \
TOKEN_KIND(Token_defer, "defer"), \
TOKEN_KIND(Token_return, "return"), \
TOKEN_KIND(Token_give, "give"), \
TOKEN_KIND(Token_struct, "struct"), \
TOKEN_KIND(Token_union, "union"), \
TOKEN_KIND(Token_raw_union, "raw_union"), \
TOKEN_KIND(Token_enum, "enum"), \
TOKEN_KIND(Token_vector, "vector"), \
TOKEN_KIND(Token_using, "using"), \
TOKEN_KIND(Token_no_alias, "no_alias"), \
TOKEN_KIND(Token_immutable, "immutable"), \
TOKEN_KIND(Token_thread_local, "thread_local"), \
TOKEN_KIND(Token_asm, "asm"), \
TOKEN_KIND(Token_push_allocator, "push_allocator"), \
TOKEN_KIND(Token_push_context, "push_context"), \
TOKEN_KIND(Token_cast, "cast"), \
TOKEN_KIND(Token_transmute, "transmute"), \
TOKEN_KIND(Token_down_cast, "down_cast"), \
TOKEN_KIND(Token_union_cast, "union_cast"), \
TOKEN_KIND(Token_when, "when"), \
TOKEN_KIND(Token_if, "if"), \
TOKEN_KIND(Token_else, "else"), \
TOKEN_KIND(Token_for, "for"), \
TOKEN_KIND(Token_in, "in"), \
TOKEN_KIND(Token_match, "match"), \
TOKEN_KIND(Token_default, "default"), \
TOKEN_KIND(Token_case, "case"), \
TOKEN_KIND(Token_break, "break"), \
TOKEN_KIND(Token_continue, "continue"), \
TOKEN_KIND(Token_fallthrough, "fallthrough"), \
TOKEN_KIND(Token_defer, "defer"), \
TOKEN_KIND(Token_return, "return"), \
TOKEN_KIND(Token_give, "give"), \
TOKEN_KIND(Token_proc, "proc"), \
TOKEN_KIND(Token_macro, "macro"), \
TOKEN_KIND(Token_struct, "struct"), \
TOKEN_KIND(Token_union, "union"), \
TOKEN_KIND(Token_raw_union, "raw_union"), \
TOKEN_KIND(Token_enum, "enum"), \
TOKEN_KIND(Token_vector, "vector"), \
TOKEN_KIND(Token_static, "static"), \
TOKEN_KIND(Token_dynamic, "dynamic"), \
TOKEN_KIND(Token_map, "map"), \
TOKEN_KIND(Token_using, "using"), \
TOKEN_KIND(Token_no_alias, "no_alias"), \
TOKEN_KIND(Token_immutable, "immutable"), \
TOKEN_KIND(Token_cast, "cast"), \
TOKEN_KIND(Token_transmute, "transmute"), \
TOKEN_KIND(Token_down_cast, "down_cast"), \
TOKEN_KIND(Token_union_cast, "union_cast"), \
TOKEN_KIND(Token_context, "context"), \
TOKEN_KIND(Token_push_context, "push_context"), \
TOKEN_KIND(Token_push_allocator, "push_allocator"), \
TOKEN_KIND(Token_asm, "asm"), \
TOKEN_KIND(Token__KeywordEnd, "_KeywordEnd"), \
TOKEN_KIND(Token_Count, "")
@@ -227,6 +225,23 @@ void syntax_error_va(Token token, char *fmt, va_list va) {
gb_mutex_unlock(&global_error_collector.mutex);
}
void syntax_warning_va(Token token, char *fmt, va_list va) {
gb_mutex_lock(&global_error_collector.mutex);
global_error_collector.warning_count++;
// NOTE(bill): Duplicate error, skip it
if (!token_pos_eq(global_error_collector.prev, token.pos)) {
global_error_collector.prev = token.pos;
gb_printf_err("%.*s(%td:%td) Syntax Warning: %s\n",
LIT(token.pos.file), token.pos.line, token.pos.column,
gb_bprintf_va(fmt, va));
} else if (token.pos.line == 0) {
gb_printf_err("Warning: %s\n", gb_bprintf_va(fmt, va));
}
gb_mutex_unlock(&global_error_collector.mutex);
}
void warning(Token token, char *fmt, ...) {
va_list va;
@@ -249,6 +264,13 @@ void syntax_error(Token token, char *fmt, ...) {
va_end(va);
}
void syntax_warning(Token token, char *fmt, ...) {
va_list va;
va_start(va, fmt);
syntax_warning_va(token, fmt, va);
va_end(va);
}
void compiler_error(char *fmt, ...) {
va_list va;
@@ -264,20 +286,20 @@ void compiler_error(char *fmt, ...) {
gb_inline bool token_is_literal(Token t) {
return gb_is_between(t.kind, Token__LiteralBegin+1, Token__LiteralEnd-1);
gb_inline bool token_is_literal(TokenKind t) {
return gb_is_between(t, Token__LiteralBegin+1, Token__LiteralEnd-1);
}
gb_inline bool token_is_operator(Token t) {
return gb_is_between(t.kind, Token__OperatorBegin+1, Token__OperatorEnd-1);
gb_inline bool token_is_operator(TokenKind t) {
return gb_is_between(t, Token__OperatorBegin+1, Token__OperatorEnd-1);
}
gb_inline bool token_is_keyword(Token t) {
return gb_is_between(t.kind, Token__KeywordBegin+1, Token__KeywordEnd-1);
gb_inline bool token_is_keyword(TokenKind t) {
return gb_is_between(t, Token__KeywordBegin+1, Token__KeywordEnd-1);
}
gb_inline bool token_is_comparison(Token t) {
return gb_is_between(t.kind, Token__ComparisonBegin+1, Token__ComparisonEnd-1);
gb_inline bool token_is_comparison(TokenKind t) {
return gb_is_between(t, Token__ComparisonBegin+1, Token__ComparisonEnd-1);
}
gb_inline bool token_is_shift(Token t) {
return t.kind == Token_Shl || t.kind == Token_Shr;
gb_inline bool token_is_shift(TokenKind t) {
return t == Token_Shl || t == Token_Shr;
}
gb_inline void print_token(Token t) { gb_printf("%.*s\n", LIT(t.string)); }
@@ -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 token = {0};
token.kind = Token_Integer;
@@ -730,20 +751,10 @@ Token tokenizer_get_token(Tokenizer *t) {
// NOTE(bill): All keywords are > 1
if (token.string.len > 1) {
/* if (str_eq(token.string, token_strings[Token_as])) {
token.kind = Token_as;
} else if (str_eq(token.string, token_strings[Token_transmute])) {
token.kind = Token_transmute;
} else if (str_eq(token.string, token_strings[Token_down_cast])) {
token.kind = Token_down_cast;
} else if (str_eq(token.string, token_strings[Token_union_cast])) {
token.kind = Token_union_cast;
} else */{
for (i32 k = Token__KeywordBegin+1; k < Token__KeywordEnd; k++) {
if (str_eq(token.string, token_strings[k])) {
token.kind = cast(TokenKind)k;
break;
}
for (i32 k = Token__KeywordBegin+1; k < Token__KeywordEnd; k++) {
if (str_eq(token.string, token_strings[k])) {
token.kind = cast(TokenKind)k;
break;
}
}
}
@@ -848,64 +859,35 @@ Token tokenizer_get_token(Tokenizer *t) {
if (t->curr_rune == '.') { // Could be an ellipsis
advance_to_next_rune(t);
token.kind = Token_Ellipsis;
if (t->curr_rune == '<') {
advance_to_next_rune(t);
token.kind = Token_HalfOpenRange;
}
// if (t->curr_rune == '<') {
// advance_to_next_rune(t);
// token.kind = Token_HalfOpenRange;
// }
}
break;
case '#':
token.kind = Token_Hash;
break;
case '@':
token.kind = Token_At;
break;
case '^':
token.kind = Token_Pointer;
break;
case '?':
token.kind = Token_Maybe;
break;
case ';':
token.kind = Token_Semicolon;
break;
case ',':
token.kind = Token_Comma;
break;
case ':':
token.kind = Token_Colon;
break;
case '(':
token.kind = Token_OpenParen;
break;
case ')':
token.kind = Token_CloseParen;
break;
case '[':
token.kind = Token_OpenBracket;
break;
case ']':
token.kind = Token_CloseBracket;
break;
case '{':
token.kind = Token_OpenBrace;
break;
case '}':
token.kind = Token_CloseBrace;
break;
case '#': token.kind = Token_Hash; break;
case '@': token.kind = Token_At; break;
case '$': token.kind = Token_Dollar; break;
case '?': token.kind = Token_Question; break;
case '^': token.kind = Token_Pointer; break;
case ';': token.kind = Token_Semicolon; break;
case ',': token.kind = Token_Comma; break;
case ':': token.kind = Token_Colon; break;
case '(': token.kind = Token_OpenParen; break;
case ')': token.kind = Token_CloseParen; break;
case '[': token.kind = Token_OpenBracket; break;
case ']': token.kind = Token_CloseBracket; break;
case '{': token.kind = Token_OpenBrace; break;
case '}': token.kind = Token_CloseBrace; break;
case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq); break;
case '%': token.kind = token_kind_variant2(t, Token_Mod, Token_ModEq); break;
case '=': token.kind = token_kind_variant2(t, Token_Eq, Token_CmpEq); break;
case '~': token.kind = token_kind_variant2(t, Token_Xor, Token_XorEq); break;
case '!': token.kind = token_kind_variant2(t, Token_Not, Token_NotEq); break;
case '+':
token.kind = token_kind_variant2(t, Token_Add, Token_AddEq);
break;
case '-':
token.kind = token_kind_variant3(t, Token_Sub, Token_SubEq, '>', Token_ArrowRight);
break;
case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq); break;
case '%': token.kind = token_kind_variant2(t, Token_Mod, Token_ModEq); break;
case '=': token.kind = token_kind_variant2(t, Token_Eq, Token_CmpEq); break;
case '~': token.kind = token_kind_variant2(t, Token_Xor, Token_XorEq); break;
case '!': token.kind = token_kind_variant2(t, Token_Not, Token_NotEq); break;
case '+': token.kind = token_kind_variant3(t, Token_Add, Token_AddEq, '+', Token_Inc); break;
case '-': token.kind = token_kind_variant4(t, Token_Sub, Token_SubEq, '-', Token_Dec, '>', Token_ArrowRight); break;
case '/': {
if (t->curr_rune == '/') {
while (t->curr_rune != '\n' && t->curr_rune != GB_RUNE_EOF) {
@@ -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);
}
break;
case '>':
token.kind = token_kind_dub_eq(t, '>', Token_Gt, Token_GtEq, Token_Shr, Token_ShrEq);
break;
case '>': token.kind = token_kind_dub_eq(t, '>', Token_Gt, Token_GtEq, Token_Shr, Token_ShrEq); break;
case '&':
token.kind = Token_And;
+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)
bool rune_is_letter(Rune r) {
if ((r < 0x80 && gb_char_is_alpha(cast(char)r)) ||
r == '_') {
@@ -39,28 +40,3 @@ bool rune_is_whitespace(Rune r) {
}
return false;
}
bool is_string_an_identifier(String s) {
isize offset = 0;
if (s.len < 1) {
return false;
}
while (offset < s.len) {
bool ok = false;
Rune r = -1;
isize size = gb_utf8_decode(s.text+offset, s.len-offset, &r);
if (offset == 0) {
ok = rune_is_letter(r);
} else {
ok = rune_is_letter(r) || rune_is_digit(r);
}
if (!ok) {
return false;
}
offset += size;
}
return offset == s.len;
}
+66 -44
View File
@@ -166,24 +166,24 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_encode_char(utf8proc_int32_t uc, ut
if (uc < 0x00) {
return 0;
} else if (uc < 0x80) {
dst[0] = uc;
dst[0] = (utf8proc_uint8_t) uc;
return 1;
} else if (uc < 0x800) {
dst[0] = 0xC0 + (uc >> 6);
dst[1] = 0x80 + (uc & 0x3F);
dst[0] = (utf8proc_uint8_t)(0xC0 + (uc >> 6));
dst[1] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
return 2;
// Note: we allow encoding 0xd800-0xdfff here, so as not to change
// the API, however, these are actually invalid in UTF-8
} else if (uc < 0x10000) {
dst[0] = 0xE0 + (uc >> 12);
dst[1] = 0x80 + ((uc >> 6) & 0x3F);
dst[2] = 0x80 + (uc & 0x3F);
dst[0] = (utf8proc_uint8_t)(0xE0 + (uc >> 12));
dst[1] = (utf8proc_uint8_t)(0x80 + ((uc >> 6) & 0x3F));
dst[2] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
return 3;
} else if (uc < 0x110000) {
dst[0] = 0xF0 + (uc >> 18);
dst[1] = 0x80 + ((uc >> 12) & 0x3F);
dst[2] = 0x80 + ((uc >> 6) & 0x3F);
dst[3] = 0x80 + (uc & 0x3F);
dst[0] = (utf8proc_uint8_t)(0xF0 + (uc >> 18));
dst[1] = (utf8proc_uint8_t)(0x80 + ((uc >> 12) & 0x3F));
dst[2] = (utf8proc_uint8_t)(0x80 + ((uc >> 6) & 0x3F));
dst[3] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
return 4;
} else return 0;
}
@@ -193,28 +193,28 @@ static utf8proc_ssize_t unsafe_encode_char(utf8proc_int32_t uc, utf8proc_uint8_t
if (uc < 0x00) {
return 0;
} else if (uc < 0x80) {
dst[0] = uc;
dst[0] = (utf8proc_uint8_t)uc;
return 1;
} else if (uc < 0x800) {
dst[0] = 0xC0 + (uc >> 6);
dst[1] = 0x80 + (uc & 0x3F);
dst[0] = (utf8proc_uint8_t)(0xC0 + (uc >> 6));
dst[1] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
return 2;
} else if (uc == 0xFFFF) {
dst[0] = 0xFF;
dst[0] = (utf8proc_uint8_t)0xFF;
return 1;
} else if (uc == 0xFFFE) {
dst[0] = 0xFE;
dst[0] = (utf8proc_uint8_t)0xFE;
return 1;
} else if (uc < 0x10000) {
dst[0] = 0xE0 + (uc >> 12);
dst[1] = 0x80 + ((uc >> 6) & 0x3F);
dst[2] = 0x80 + (uc & 0x3F);
dst[0] = (utf8proc_uint8_t)(0xE0 + (uc >> 12));
dst[1] = (utf8proc_uint8_t)(0x80 + ((uc >> 6) & 0x3F));
dst[2] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
return 3;
} else if (uc < 0x110000) {
dst[0] = 0xF0 + (uc >> 18);
dst[1] = 0x80 + ((uc >> 12) & 0x3F);
dst[2] = 0x80 + ((uc >> 6) & 0x3F);
dst[3] = 0x80 + (uc & 0x3F);
dst[0] = (utf8proc_uint8_t)(0xF0 + (uc >> 18));
dst[1] = (utf8proc_uint8_t)(0x80 + ((uc >> 12) & 0x3F));
dst[2] = (utf8proc_uint8_t)(0x80 + ((uc >> 6) & 0x3F));
dst[3] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
return 4;
} else return 0;
}
@@ -383,7 +383,7 @@ UTF8PROC_DLLEXPORT int utf8proc_charwidth(utf8proc_int32_t c) {
}
UTF8PROC_DLLEXPORT utf8proc_category_t utf8proc_category(utf8proc_int32_t c) {
return (utf8proc_category_t)utf8proc_get_property(c)->category;
return utf8proc_get_property(c)->category;
}
UTF8PROC_DLLEXPORT const char *utf8proc_category_string(utf8proc_int32_t c) {
@@ -391,11 +391,9 @@ UTF8PROC_DLLEXPORT const char *utf8proc_category_string(utf8proc_int32_t c) {
return s[utf8proc_category(c)];
}
#define utf8proc_decompose_lump(replacement_uc) \
return utf8proc_decompose_char((utf8proc_int32_t)(replacement_uc), dst, bufsize, \
(utf8proc_option_t)((utf8proc_int32_t)options & ~UTF8PROC_LUMP), last_boundclass)
return utf8proc_decompose_char((replacement_uc), dst, bufsize, \
options & ~UTF8PROC_LUMP, last_boundclass)
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_char(utf8proc_int32_t uc, utf8proc_int32_t *dst, utf8proc_ssize_t bufsize, utf8proc_option_t options, int *last_boundclass) {
const utf8proc_property_t *property;
@@ -458,12 +456,12 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_char(utf8proc_int32_t uc,
category == UTF8PROC_CATEGORY_ME) return 0;
}
if (options & UTF8PROC_CASEFOLD) {
if ((utf8proc_int16_t)property->casefold_seqindex != UINT16_MAX) {
if (property->casefold_seqindex != UINT16_MAX) {
return seqindex_write_char_decomposed(property->casefold_seqindex, dst, bufsize, options, last_boundclass);
}
}
if (options & (UTF8PROC_COMPOSE|UTF8PROC_DECOMPOSE)) {
if ((utf8proc_int16_t)property->decomp_seqindex != UINT16_MAX &&
if (property->decomp_seqindex != UINT16_MAX &&
(!property->decomp_type || (options & UTF8PROC_COMPAT))) {
return seqindex_write_char_decomposed(property->decomp_seqindex, dst, bufsize, options, last_boundclass);
}
@@ -485,6 +483,14 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_char(utf8proc_int32_t uc,
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose(
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen,
utf8proc_int32_t *buffer, utf8proc_ssize_t bufsize, utf8proc_option_t options
) {
return utf8proc_decompose_custom(str, strlen, buffer, bufsize, options, NULL, NULL);
}
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_custom(
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen,
utf8proc_int32_t *buffer, utf8proc_ssize_t bufsize, utf8proc_option_t options,
utf8proc_custom_func custom_func, void *custom_data
) {
/* strlen will be ignored, if UTF8PROC_NULLTERM is set in options */
utf8proc_ssize_t wpos = 0;
@@ -511,6 +517,9 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose(
rpos += utf8proc_iterate(str + rpos, strlen - rpos, &uc);
if (uc < 0) return UTF8PROC_ERROR_INVALIDUTF8;
}
if (custom_func != NULL) {
uc = custom_func(uc, custom_data); /* user-specified custom mapping */
}
decomp_result = utf8proc_decompose_char(
uc, buffer + wpos, (bufsize > wpos) ? (bufsize - wpos) : 0, options,
&boundclass
@@ -545,9 +554,8 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose(
return wpos;
}
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_reencode(utf8proc_int32_t *buffer, utf8proc_ssize_t length, utf8proc_option_t options) {
/* UTF8PROC_NULLTERM option will be ignored, 'length' is never ignored
ASSERT: 'buffer' has one spare byte of free space at the end! */
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_normalize_utf32(utf8proc_int32_t *buffer, utf8proc_ssize_t length, utf8proc_option_t options) {
/* UTF8PROC_NULLTERM option will be ignored, 'length' is never ignored */
if (options & (UTF8PROC_NLF2LS | UTF8PROC_NLF2PS | UTF8PROC_STRIPCC)) {
utf8proc_ssize_t rpos;
utf8proc_ssize_t wpos = 0;
@@ -621,7 +629,7 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_reencode(utf8proc_int32_t *buffer,
starter_property = unsafe_get_property(*starter);
}
if (starter_property->comb_index < 0x8000 &&
(utf8proc_int16_t)current_property->comb_index != UINT16_MAX &&
current_property->comb_index != UINT16_MAX &&
current_property->comb_index >= 0x8000) {
int sidx = starter_property->comb_index;
int idx = (current_property->comb_index & 0x3FFF) - utf8proc_combinations[sidx];
@@ -655,6 +663,14 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_reencode(utf8proc_int32_t *buffer,
}
length = wpos;
}
return length;
}
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_reencode(utf8proc_int32_t *buffer, utf8proc_ssize_t length, utf8proc_option_t options) {
/* UTF8PROC_NULLTERM option will be ignored, 'length' is never ignored
ASSERT: 'buffer' has one spare byte of free space at the end! */
length = utf8proc_normalize_utf32(buffer, length, options);
if (length < 0) return length;
{
utf8proc_ssize_t rpos, wpos = 0;
utf8proc_int32_t uc;
@@ -676,15 +692,22 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_reencode(utf8proc_int32_t *buffer,
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map(
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options
) {
return utf8proc_map_custom(str, strlen, dstptr, options, NULL, NULL);
}
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map_custom(
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options,
utf8proc_custom_func custom_func, void *custom_data
) {
utf8proc_int32_t *buffer;
utf8proc_ssize_t result;
*dstptr = NULL;
result = utf8proc_decompose(str, strlen, NULL, 0, options);
result = utf8proc_decompose_custom(str, strlen, NULL, 0, options, custom_func, custom_data);
if (result < 0) return result;
buffer = (utf8proc_int32_t *) malloc(result * sizeof(utf8proc_int32_t) + 1);
if (!buffer) return UTF8PROC_ERROR_NOMEM;
result = utf8proc_decompose(str, strlen, buffer, result, options);
result = utf8proc_decompose_custom(str, strlen, buffer, result, options, custom_func, custom_data);
if (result < 0) {
free(buffer);
return result;
@@ -705,29 +728,28 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map(
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFD(const utf8proc_uint8_t *str) {
utf8proc_uint8_t *retval;
utf8proc_map(str, 0, &retval, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE |
UTF8PROC_DECOMPOSE));
utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE |
UTF8PROC_DECOMPOSE);
return retval;
}
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFC(const utf8proc_uint8_t *str) {
utf8proc_uint8_t *retval;
utf8proc_map(str, 0, &retval, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE |
UTF8PROC_COMPOSE));
utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE |
UTF8PROC_COMPOSE);
return retval;
}
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKD(const utf8proc_uint8_t *str) {
utf8proc_uint8_t *retval;
utf8proc_map(str, 0, &retval, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE |
UTF8PROC_DECOMPOSE | UTF8PROC_COMPAT));
utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE |
UTF8PROC_DECOMPOSE | UTF8PROC_COMPAT);
return retval;
}
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC(const utf8proc_uint8_t *str) {
utf8proc_uint8_t *retval;
utf8proc_map(str, 0, &retval, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE |
UTF8PROC_COMPOSE | UTF8PROC_COMPAT));
utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE |
UTF8PROC_COMPOSE | UTF8PROC_COMPAT);
return retval;
}
+81 -25
View File
@@ -71,14 +71,15 @@
/** The MAJOR version number (increased when backwards API compatibility is broken). */
#define UTF8PROC_VERSION_MAJOR 2
/** The MINOR version number (increased when new functionality is added in a backwards-compatible manner). */
#define UTF8PROC_VERSION_MINOR 0
#define UTF8PROC_VERSION_MINOR 1
/** The PATCH version (increased for fixes that do not change the API). */
#define UTF8PROC_VERSION_PATCH 2
#define UTF8PROC_VERSION_PATCH 0
/** @} */
#include <stdlib.h>
#include <sys/types.h>
#ifdef _MSC_VER
#if defined(_MSC_VER) && _MSC_VER < 1800
// MSVC prior to 2013 lacked stdbool.h and inttypes.h
typedef signed char utf8proc_int8_t;
typedef unsigned char utf8proc_uint8_t;
typedef short utf8proc_int16_t;
@@ -93,12 +94,18 @@ typedef int utf8proc_ssize_t;
typedef unsigned int utf8proc_size_t;
# endif
# ifndef __cplusplus
// emulate C99 bool
typedef unsigned char utf8proc_bool;
// enum {false, true};
# ifndef __bool_true_false_are_defined
# define false 0
# define true 1
# define __bool_true_false_are_defined 1
# endif
# else
typedef bool utf8proc_bool;
# endif
#else
# include <stddef.h>
# include <stdbool.h>
# include <inttypes.h>
typedef int8_t utf8proc_int8_t;
@@ -108,22 +115,12 @@ typedef uint16_t utf8proc_uint16_t;
typedef int32_t utf8proc_int32_t;
typedef uint32_t utf8proc_uint32_t;
typedef size_t utf8proc_size_t;
typedef ssize_t utf8proc_ssize_t;
typedef ptrdiff_t utf8proc_ssize_t;
typedef bool utf8proc_bool;
#endif
#include <limits.h>
#ifdef _WIN32
# ifdef UTF8PROC_EXPORTS
# define UTF8PROC_DLLEXPORT __declspec(dllexport)
# else
# define UTF8PROC_DLLEXPORT /*__declspec(dllimport)*/
# endif
#elif __GNUC__ >= 4
# define UTF8PROC_DLLEXPORT __attribute__ ((visibility("default")))
#else
# define UTF8PROC_DLLEXPORT
#endif
#define UTF8PROC_DLLEXPORT
#ifdef __cplusplus
extern "C" {
@@ -134,7 +131,7 @@ extern "C" {
#endif
#ifndef UINT16_MAX
# define UINT16_MAX ~(utf8proc_uint16_t)0
# define UINT16_MAX 65535U
#endif
/**
@@ -373,6 +370,13 @@ typedef enum {
UTF8PROC_BOUNDCLASS_E_BASE_GAZ = 18, /**< E_BASE + GLUE_AFTER_ZJW */
} utf8proc_boundclass_t;
/**
* Function pointer type passed to @ref utf8proc_map_custom and
* @ref utf8proc_decompose_custom, which is used to specify a user-defined
* mapping of codepoints to be applied in conjunction with other mappings.
*/
typedef utf8proc_int32_t (*utf8proc_custom_func)(utf8proc_int32_t codepoint, void *data);
/**
* Array containing the byte lengths of a UTF-8 encoded codepoint based
* on the first byte.
@@ -480,6 +484,7 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_char(
* `buffer` (which must contain at least `bufsize` entries). In case of
* success, the number of codepoints written is returned; in case of an
* error, a negative error code is returned (@ref utf8proc_errmsg).
* See @ref utf8proc_decompose_custom to supply additional transformations.
*
* If the number of written codepoints would be bigger than `bufsize`, the
* required buffer size is returned, while the buffer will be overwritten with
@@ -491,8 +496,20 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose(
);
/**
* Reencodes the sequence of `length` codepoints pointed to by `buffer`
* UTF-8 data in-place (i.e., the result is also stored in `buffer`).
* The same as @ref utf8proc_decompose, but also takes a `custom_func` mapping function
* that is called on each codepoint in `str` before any other transformations
* (along with a `custom_data` pointer that is passed through to `custom_func`).
* The `custom_func` argument is ignored if it is `NULL`. See also @ref utf8proc_map_custom.
*/
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_custom(
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen,
utf8proc_int32_t *buffer, utf8proc_ssize_t bufsize, utf8proc_option_t options,
utf8proc_custom_func custom_func, void *custom_data
);
/**
* Normalizes the sequence of `length` codepoints pointed to by `buffer`
* in-place (i.e., the result is also stored in `buffer`).
*
* @param buffer the (native-endian UTF-32) unicode codepoints to re-encode.
* @param length the length (in codepoints) of the buffer.
@@ -507,9 +524,37 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose(
* the unicode versioning stability
*
* @return
* In case of success, the length (in bytes) of the resulting UTF-8 string is
* In case of success, the length (in codepoints) of the normalized UTF-32 string is
* returned; otherwise, a negative error code is returned (@ref utf8proc_errmsg).
*
* @warning The entries of the array pointed to by `str` have to be in the
* range `0x0000` to `0x10FFFF`. Otherwise, the program might crash!
*/
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_normalize_utf32(utf8proc_int32_t *buffer, utf8proc_ssize_t length, utf8proc_option_t options);
/**
* Reencodes the sequence of `length` codepoints pointed to by `buffer`
* UTF-8 data in-place (i.e., the result is also stored in `buffer`).
* Can optionally normalize the UTF-32 sequence prior to UTF-8 conversion.
*
* @param buffer the (native-endian UTF-32) unicode codepoints to re-encode.
* @param length the length (in codepoints) of the buffer.
* @param options a bitwise or (`|`) of one or more of the following flags:
* - @ref UTF8PROC_NLF2LS - convert LF, CRLF, CR and NEL into LS
* - @ref UTF8PROC_NLF2PS - convert LF, CRLF, CR and NEL into PS
* - @ref UTF8PROC_NLF2LF - convert LF, CRLF, CR and NEL into LF
* - @ref UTF8PROC_STRIPCC - strip or convert all non-affected control characters
* - @ref UTF8PROC_COMPOSE - try to combine decomposed codepoints into composite
* codepoints
* - @ref UTF8PROC_STABLE - prohibit combining characters that would violate
* the unicode versioning stability
* - @ref UTF8PROC_CHARBOUND - insert 0xFF bytes before each grapheme cluster
*
* @return
* In case of success, the length (in bytes) of the resulting nul-terminated
* UTF-8 string is returned; otherwise, a negative error code is returned
* (@ref utf8proc_errmsg).
*
* @warning The amount of free space pointed to by `buffer` must
* exceed the amount of the input data by one byte, and the
* entries of the array pointed to by `str` have to be in the
@@ -595,7 +640,8 @@ UTF8PROC_DLLEXPORT const char *utf8proc_category_string(utf8proc_int32_t codepoi
* in any case the result will be NULL terminated (though it might
* contain NULL characters with the string if `str` contained NULL
* characters). Other flags in the `options` field are passed to the
* functions defined above, and regarded as described.
* functions defined above, and regarded as described. See also
* @ref utfproc_map_custom to supply a custom codepoint transformation.
*
* In case of success the length of the new string is returned,
* otherwise a negative error code is returned.
@@ -607,6 +653,17 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map(
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options
);
/**
* Like @ref utf8proc_map, but also takes a `custom_func` mapping function
* that is called on each codepoint in `str` before any other transformations
* (along with a `custom_data` pointer that is passed through to `custom_func`).
* The `custom_func` argument is ignored if it is `NULL`.
*/
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map_custom(
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options,
utf8proc_custom_func custom_func, void *custom_data
);
/** @name Unicode normalization
*
* Returns a pointer to newly allocated memory of a NFD, NFC, NFKD or NFKC
@@ -619,9 +676,9 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map(
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFD(const utf8proc_uint8_t *str);
/** NFC normalization (@ref UTF8PROC_COMPOSE). */
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFC(const utf8proc_uint8_t *str);
/** NFD normalization (@ref UTF8PROC_DECOMPOSE and @ref UTF8PROC_COMPAT). */
/** NFKD normalization (@ref UTF8PROC_DECOMPOSE and @ref UTF8PROC_COMPAT). */
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKD(const utf8proc_uint8_t *str);
/** NFD normalization (@ref UTF8PROC_COMPOSE and @ref UTF8PROC_COMPAT). */
/** NFKC normalization (@ref UTF8PROC_COMPOSE and @ref UTF8PROC_COMPAT). */
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC(const utf8proc_uint8_t *str);
/** @} */
@@ -630,4 +687,3 @@ UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC(const utf8proc_uint8_t *str);
#endif
#endif
+10 -15
View File
@@ -1,7 +1,4 @@
#pragma warning(push)
#pragma warning(disable: 4838)
const utf8proc_uint16_t utf8proc_sequences[] = {
static const utf8proc_uint16_t utf8proc_sequences[] = {
97, 98, 99, 100, 101, 102, 103,
104, 105, 106, 107, 108, 109, 110, 111,
112, 113, 114, 115, 116, 117, 118, 119,
@@ -1179,7 +1176,7 @@ const utf8proc_uint16_t utf8proc_sequences[] = {
56603, 55354, 56604, 55354, 56605, 55354, 56606, 55354,
56607, 55354, 56608, 55354, 56609, };
const utf8proc_uint16_t utf8proc_stage1table[] = {
static const utf8proc_uint16_t utf8proc_stage1table[] = {
0, 256, 512, 768, 1024, 1280, 1536,
1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584,
3840, 4096, 4352, 4608, 4864, 5120, 5376, 5632,
@@ -1726,7 +1723,7 @@ const utf8proc_uint16_t utf8proc_stage1table[] = {
18432, 18432, 18432, 18432, 18432, 18432, 18432, 18432,
38656, };
const utf8proc_uint16_t utf8proc_stage2table[] = {
static const utf8proc_uint16_t utf8proc_stage2table[] = {
1, 2, 2, 2, 2, 2, 2,
2, 2, 3, 4, 3, 5, 6, 2,
2, 2, 2, 2, 2, 2, 2, 2,
@@ -5899,7 +5896,7 @@ const utf8proc_uint16_t utf8proc_stage2table[] = {
540, 540, 540, 1180, 0, 0, 0, 0,
0, 1154, 1154, 1154, 1154, 1154, 1154, 1154,
1154, 1154, 1154, 0, 0, 0, 0, 1103,
1158, 0, 0, 0, 0, 0, 0, 0,
1103, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
@@ -6593,7 +6590,7 @@ const utf8proc_uint16_t utf8proc_stage2table[] = {
3984, 3984, 3984, 3984, 3984, 3984, 3984, 0,
0, };
const utf8proc_property_t utf8proc_properties[] = {
static const utf8proc_property_t utf8proc_properties[] = {
{0, 0, 0, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false,false,false,false, 0, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_BN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL},
{UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_BN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL},
@@ -7850,7 +7847,7 @@ const utf8proc_property_t utf8proc_properties[] = {
{UTF8PROC_CATEGORY_MN, 122, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND},
{UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 9523, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 9525, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NOBREAK, 1335, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NOBREAK, 1335, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_MN, 216, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND},
{UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
@@ -10478,7 +10475,7 @@ const utf8proc_property_t utf8proc_properties[] = {
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1470, UINT16_MAX, 1470, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1478, UINT16_MAX, 1478, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5132, UINT16_MAX, 5132, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1480, UINT16_MAX, 1480, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1480, UINT16_MAX, 1480, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5133, UINT16_MAX, 5133, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5134, UINT16_MAX, 5134, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1482, UINT16_MAX, 1482, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
@@ -12168,7 +12165,7 @@ const utf8proc_property_t utf8proc_properties[] = {
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6787, UINT16_MAX, 6787, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6789, UINT16_MAX, 6789, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6791, UINT16_MAX, 6791, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6793, UINT16_MAX, 6793, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6793, UINT16_MAX, 6793, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6795, UINT16_MAX, 6795, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6797, UINT16_MAX, 6797, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6799, UINT16_MAX, 6799, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
@@ -12204,7 +12201,7 @@ const utf8proc_property_t utf8proc_properties[] = {
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9104, UINT16_MAX, 9104, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9106, UINT16_MAX, 9106, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9108, UINT16_MAX, 9108, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9110, UINT16_MAX, 9110, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9110, UINT16_MAX, 9110, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9112, UINT16_MAX, 9112, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9114, UINT16_MAX, 9114, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9116, UINT16_MAX, 9116, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
@@ -13423,7 +13420,7 @@ const utf8proc_property_t utf8proc_properties[] = {
{UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7975, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
};
const utf8proc_uint16_t utf8proc_combinations[] = {
static const utf8proc_uint16_t utf8proc_combinations[] = {
0, 46, 192, 193, 194, 195, 196, 197, 0,
256, 258, 260, 550, 461, 0, 0, 512,
514, 0, 0, 0, 0, 0, 0, 0,
@@ -14386,5 +14383,3 @@ const utf8proc_uint16_t utf8proc_combinations[] = {
72, 75,
1, 53694, 1, 53696,
};
#pragma warning(pop)