Browse Source

Prefix `type` and `let` to replace `immutable`

Ginger Bill 8 years ago
parent
commit
0c05fc1432

+ 14 - 14
core/_preload.odin

@@ -24,19 +24,19 @@
 
 // IMPORTANT NOTE(bill): Do not change the order of any of this data
 // The compiler relies upon this _exact_ order
-const TypeInfoEnumValue = raw_union {
+type TypeInfoEnumValue raw_union {
 	f: f64,
 	i: i128,
 }
 // NOTE(bill): This must match the compiler's
-const CallingConvention = enum {
+type CallingConvention enum {
 	Odin = 0,
 	C    = 1,
 	Std  = 2,
 	Fast = 3,
 }
 
-const TypeInfoRecord = struct #ordered {
+type TypeInfoRecord struct #ordered {
 	types:        []^TypeInfo,
 	names:        []string,
 	offsets:      []int,  // offsets may not be used in tuples
@@ -46,7 +46,7 @@ const TypeInfoRecord = struct #ordered {
 	custom_align: bool,
 }
 
-const TypeInfo = union {
+type TypeInfo union {
 	size:  int,
 	align: int,
 
@@ -151,22 +151,22 @@ proc read_cycle_counter() -> u64 #foreign __llvm_core "llvm.readcyclecounter";
 
 
 // IMPORTANT NOTE(bill): Must be in this order (as the compiler relies upon it)
-const AllocatorMode = enum u8 {
+type AllocatorMode enum u8 {
 	Alloc,
 	Free,
 	FreeAll,
 	Resize,
 }
-const AllocatorProc = type proc(allocator_data: rawptr, mode: AllocatorMode,
-                           size, alignment: int,
-                           old_memory: rawptr, old_size: int, flags: u64) -> rawptr;
-const Allocator = struct #ordered {
+type AllocatorProc proc(allocator_data: rawptr, mode: AllocatorMode,
+                        size, alignment: int,
+                        old_memory: rawptr, old_size: int, flags: u64) -> rawptr;
+type Allocator struct #ordered {
 	procedure: AllocatorProc,
 	data:      rawptr,
 }
 
 
-const Context = struct #ordered {
+type Context struct #ordered {
 	thread_id: int,
 
 	allocator: Allocator,
@@ -553,18 +553,18 @@ proc __default_hash_string(s: string) -> u128 {
 
 const __INITIAL_MAP_CAP = 16;
 
-const __MapKey = struct #ordered {
+type __MapKey struct #ordered {
 	hash: u128,
 	str:  string,
 }
 
-const __MapFindResult = struct #ordered {
+type __MapFindResult struct #ordered {
 	hash_index:  int,
 	entry_prev:  int,
 	entry_index: int,
 }
 
-const __MapEntryHeader = struct #ordered {
+type __MapEntryHeader struct #ordered {
 	key:  __MapKey,
 	next: int,
 /*
@@ -572,7 +572,7 @@ const __MapEntryHeader = struct #ordered {
 */
 }
 
-const __MapHeader = struct #ordered {
+type __MapHeader struct #ordered {
 	m:             ^raw.DynamicMap,
 	is_key_string: bool,
 	entry_size:    int,

+ 1 - 1
core/decimal.odin

@@ -2,7 +2,7 @@
 // Multiple precision decimal numbers
 // NOTE: This is only for floating point printing and nothing else
 
-const Decimal = struct {
+type Decimal struct {
 	digits:        [384]u8, // big-endian digits
 	count:         int,
 	decimal_point: int,

+ 4 - 4
core/fmt.odin

@@ -8,12 +8,12 @@
 
 const _BUFFER_SIZE = 1<<12;
 
-const StringBuffer = union {
+type StringBuffer union {
 	Static {buf: []u8},
 	Dynamic{buf: [dynamic]u8},
 }
 
-const FmtInfo = struct {
+type FmtInfo struct {
 	minus:     bool,
 	plus:      bool,
 	space:     bool,
@@ -582,8 +582,8 @@ proc _fmt_int(fi: ^FmtInfo, u: u128, base: int, is_signed: bool, bit_size: int,
 	_pad(fi, s);
 }
 
-immutable var __DIGITS_LOWER = "0123456789abcdefx";
-immutable var __DIGITS_UPPER = "0123456789ABCDEFX";
+let __DIGITS_LOWER = "0123456789abcdefx";
+let __DIGITS_UPPER = "0123456789ABCDEFX";
 
 proc fmt_rune(fi: ^FmtInfo, r: rune, verb: rune) {
 	match verb {

+ 7 - 7
core/math.odin

@@ -16,16 +16,16 @@ const EPSILON      = 1.19209290e-7;
 const τ = TAU;
 const π = PI;
 
-const Vec2 = [vector 2]f32;
-const Vec3 = [vector 3]f32;
-const Vec4 = [vector 4]f32;
+type Vec2 [vector 2]f32;
+type Vec3 [vector 3]f32;
+type Vec4 [vector 4]f32;
 
 // Column major
-const Mat2 = [2][2]f32;
-const Mat3 = [3][3]f32;
-const Mat4 = [4][4]f32;
+type Mat2 [2][2]f32;
+type Mat3 [3][3]f32;
+type Mat4 [4][4]f32;
 
-const Complex = complex64;
+type Complex complex64;
 
 proc sqrt(x: f32) -> f32 #foreign __llvm_core "llvm.sqrt.f32";
 proc sqrt(x: f64) -> f64 #foreign __llvm_core "llvm.sqrt.f64";

+ 3 - 3
core/mem.odin

@@ -50,7 +50,7 @@ proc align_forward(ptr: rawptr, align: int) -> rawptr {
 
 
 
-const AllocationHeader = struct {
+type AllocationHeader struct {
 	size: int,
 }
 
@@ -78,14 +78,14 @@ proc allocation_header(data: rawptr) -> ^AllocationHeader {
 
 
 // Custom allocators
-const Arena = struct {
+type Arena struct {
 	backing:    Allocator,
 	offset:     int,
 	memory:     []u8,
 	temp_count: int,
 }
 
-const ArenaTempMemory = struct {
+type ArenaTempMemory struct {
 	arena:          ^Arena,
 	original_count: int,
 }

+ 6 - 6
core/os_linux.odin

@@ -1,9 +1,9 @@
 // #import "fmt.odin";
 #import "strings.odin";
 
-const Handle    = i32;
-const FileTime  = u64;
-const Errno     = i32;
+type Handle   i32;
+type FileTime u64;
+type Errno    i32;
 
 // INVALID_HANDLE: Handle : -1;
 
@@ -34,9 +34,9 @@ const RTLD_BINDING_MASK = 0x3;
 const RTLD_GLOBAL       = 0x100;
 
 // "Argv" arguments converted to Odin strings
-immutable var args = _alloc_command_line_arguments();
+let args = _alloc_command_line_arguments();
 
-const _FileTime = struct #ordered {
+type _FileTime struct #ordered {
 	seconds:     i64,
 	nanoseconds: i32,
 	reserved:    i32,
@@ -46,7 +46,7 @@ const _FileTime = struct #ordered {
 //  https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6/+/jb-dev/sysroot/usr/include/bits/stat.h
 // Validity is not guaranteed.
 
-const Stat = struct #ordered {
+type Stat struct #ordered {
 	device_id:     u64, // ID of device containing file
 	serial:        u64, // File serial number
 	nlink:         u32, // Number of hard links

+ 4 - 4
core/os_windows.odin

@@ -1,8 +1,8 @@
 #import win32 "sys/windows.odin";
 
-const Handle    = int;
-const FileTime  = u64;
-const Errno     = int;
+type Handle   int;
+type FileTime u64;
+type Errno    int;
 
 const INVALID_HANDLE: Handle = -1;
 
@@ -49,7 +49,7 @@ const ERROR_FILE_IS_PIPE: Errno = 1<<29 + 0;
 
 
 // "Argv" arguments converted to Odin strings
-immutable var args = _alloc_command_line_arguments();
+let args = _alloc_command_line_arguments();
 
 
 proc open(path: string, mode: int, perm: u32) -> (Handle, Errno) {

+ 6 - 6
core/os_x.odin

@@ -1,12 +1,12 @@
 #import "fmt.odin";
 #import "strings.odin";
 
-const Handle    = i32;
-const FileTime  = u64;
-const Errno     = int;
+type Handle    i32;
+type FileTime  u64;
+type Errno     int;
 
 // TODO(zangent): Find out how to make this work on x64 and x32.
-const AddressSize = i64;
+type AddressSize i64;
 
 // INVALID_HANDLE: Handle : -1;
 
@@ -41,12 +41,12 @@ const RTLD_FIRST    = 0x100;
 
 var args: [dynamic]string;
 
-const _FileTime = struct #ordered {
+type _FileTime struct #ordered {
 	seconds: i64,
 	nanoseconds: i64
 }
 
-const Stat = struct #ordered {
+type Stat struct #ordered {
 	device_id : i32, // ID of device containing file
 	mode      : u16, // Mode of the file
 	nlink     : u16, // Number of hard links

+ 6 - 6
core/raw.odin

@@ -1,27 +1,27 @@
-const Any = struct #ordered {
+type Any struct #ordered {
 	data:      rawptr,
 	type_info: ^TypeInfo,
-}
+};
 
-const String = struct #ordered {
+type String struct #ordered {
 	data: ^u8,
 	len:  int,
 };
 
-const Slice = struct #ordered {
+type Slice struct #ordered {
 	data: rawptr,
 	len:  int,
 	cap:  int,
 };
 
-const DynamicArray = struct #ordered {
+type DynamicArray struct #ordered {
 	data:      rawptr,
 	len:       int,
 	cap:       int,
 	allocator: Allocator,
 };
 
-const DynamicMap = struct #ordered {
+type DynamicMap struct #ordered {
 	hashes:  [dynamic]int,
 	entries: DynamicArray,
 };

+ 4 - 4
core/strconv.odin

@@ -1,6 +1,6 @@
 #import . "decimal.odin";
 
-const IntFlag = enum {
+type IntFlag enum {
 	Prefix = 1<<0,
 	Plus   = 1<<1,
 	Space  = 1<<2,
@@ -210,14 +210,14 @@ proc append_float(buf: []u8, f: f64, fmt: u8, prec, bit_size: int) -> string {
 
 
 
-const DecimalSlice = struct {
+type DecimalSlice struct {
 	digits:        []u8,
 	count:         int,
 	decimal_point: int,
 	neg:           bool,
 }
 
-const Float_Info = struct {
+type Float_Info struct {
 	mantbits: uint,
 	expbits:  uint,
 	bias:     int,
@@ -415,7 +415,7 @@ proc round_shortest(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) {
 }
 
 const MAX_BASE = 32;
-immutable var digits = "0123456789abcdefghijklmnopqrstuvwxyz";
+let digits = "0123456789abcdefghijklmnopqrstuvwxyz";
 
 
 proc is_integer_negative(u: u128, is_signed: bool, bit_size: int) -> (unsigned: u128, neg: bool) {

+ 2 - 2
core/sync_linux.odin

@@ -1,11 +1,11 @@
 #import "atomics.odin";
 #import "os.odin";
 
-const Semaphore = struct {
+type Semaphore struct {
 	// _handle: win32.Handle,
 }
 
-const Mutex = struct {
+type Mutex struct {
 	_semaphore: Semaphore,
 	_counter:   i32,
 	_owner:     i32,

+ 2 - 2
core/sync_windows.odin

@@ -1,11 +1,11 @@
 #import win32 "sys/windows.odin" when ODIN_OS == "windows";
 #import "atomics.odin";
 
-const Semaphore = struct {
+type Semaphore struct {
 	_handle: win32.Handle,
 }
 
-const Mutex = struct {
+type Mutex struct {
 	_semaphore: Semaphore,
 	_counter:   i32,
 	_owner:     i32,

+ 9 - 9
core/sys/wgl.odin

@@ -9,10 +9,10 @@ const CONTEXT_FORWARD_COMPATIBLE_BIT_ARB = 0x0002;
 const CONTEXT_CORE_PROFILE_BIT_ARB       = 0x00000001;
 const CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB = 0x00000002;
 
-const Hglrc = Handle;
-const ColorRef = u32;
+type Hglrc    Handle;
+type ColorRef u32;
 
-const LayerPlaneDescriptor = struct {
+type LayerPlaneDescriptor struct {
 	size:             u16,
 	version:          u16,
 	flags:            u32,
@@ -39,11 +39,11 @@ const LayerPlaneDescriptor = struct {
 	transparent:      ColorRef,
 }
 
-const PointFloat = struct {
+type PointFloat struct {
 	x, y: f32,
 }
 
-const Glyph_MetricsFloat = struct {
+type Glyph_MetricsFloat struct {
 	black_box_x:  f32,
 	black_box_y:  f32,
 	glyph_origin: PointFloat,
@@ -51,10 +51,10 @@ const Glyph_MetricsFloat = struct {
 	cell_inc_y:   f32,
 }
 
-const CreateContextAttribsARBType = type proc(hdc: Hdc, h_share_context: rawptr, attribList: ^i32) -> Hglrc;
-const ChoosePixelFormatARBType    = type proc(hdc: Hdc, attrib_i_list: ^i32, attrib_f_list: ^f32, max_formats: u32, formats: ^i32, num_formats : ^u32) -> Bool #cc_c;
-const SwapIntervalEXTType         = type proc(interval: i32) -> bool #cc_c;
-const GetExtensionsStringARBType  = type proc(Hdc) -> ^u8 #cc_c;
+type CreateContextAttribsARBType proc(hdc: Hdc, h_share_context: rawptr, attribList: ^i32) -> Hglrc;
+type ChoosePixelFormatARBType    proc(hdc: Hdc, attrib_i_list: ^i32, attrib_f_list: ^f32, max_formats: u32, formats: ^i32, num_formats : ^u32) -> Bool #cc_c;
+type SwapIntervalEXTType         proc(interval: i32) -> bool #cc_c;
+type GetExtensionsStringARBType  proc(Hdc) -> ^u8 #cc_c;
 
 
 var create_context_attribs_arb: CreateContextAttribsARBType;

+ 35 - 35
core/sys/windows.odin

@@ -4,21 +4,21 @@
 #foreign_system_library "winmm.lib"    when ODIN_OS == "windows";
 #foreign_system_library "shell32.lib"  when ODIN_OS == "windows";
 
-const Handle    = rawptr;
-const Hwnd      = Handle;
-const Hdc       = Handle;
-const Hinstance = Handle;
-const Hicon     = Handle;
-const Hcursor   = Handle;
-const Hmenu     = Handle;
-const Hbrush    = Handle;
-const Hgdiobj   = Handle;
-const Hmodule   = Handle;
-const Wparam    = uint;
-const Lparam    = int;
-const Lresult   = int;
-const Bool      = i32;
-const WndProc  = type proc(Hwnd, u32, Wparam, Lparam) -> Lresult #cc_c;
+type Handle    rawptr;
+type Hwnd      Handle;
+type Hdc       Handle;
+type Hinstance Handle;
+type Hicon     Handle;
+type Hcursor   Handle;
+type Hmenu     Handle;
+type Hbrush    Handle;
+type Hgdiobj   Handle;
+type Hmodule   Handle;
+type Wparam    uint;
+type Lparam    int;
+type Lresult   int;
+type Bool      i32;
+type WndProc   proc(Hwnd, u32, Wparam, Lparam) -> Lresult #cc_c;
 
 
 const INVALID_HANDLE = Handle(~int(0));
@@ -86,11 +86,11 @@ const SM_CYSCREEN = 1;
 const SW_SHOW = 5;
 
 
-const Point = struct #ordered {
+type Point struct #ordered {
 	x, y: i32,
 }
 
-const WndClassExA = struct #ordered {
+type WndClassExA struct #ordered {
 	size, style:           u32,
 	wnd_proc:              WndProc,
 	cls_extra, wnd_extra:  i32,
@@ -102,7 +102,7 @@ const WndClassExA = struct #ordered {
 	sm:                    Hicon,
 }
 
-const Msg = struct #ordered {
+type Msg struct #ordered {
 	hwnd:    Hwnd,
 	message: u32,
 	wparam:  Wparam,
@@ -111,24 +111,24 @@ const Msg = struct #ordered {
 	pt:      Point,
 }
 
-const Rect = struct #ordered {
+type Rect struct #ordered {
 	left:   i32,
 	top:    i32,
 	right:  i32,
 	bottom: i32,
 }
 
-const Filetime = struct #ordered {
+type Filetime struct #ordered {
 	lo, hi: u32,
 }
 
-const Systemtime = struct #ordered {
+type Systemtime struct #ordered {
 	year, month: u16,
 	day_of_week, day: u16,
 	hour, minute, second, millisecond: u16,
 }
 
-const ByHandleFileInformation = struct #ordered {
+type ByHandleFileInformation struct #ordered {
 	file_attributes:      u32,
 	creation_time,
 	last_access_time,
@@ -141,7 +141,7 @@ const ByHandleFileInformation = struct #ordered {
 	file_index_low:       u32,
 }
 
-const FileAttributeData = struct #ordered {
+type FileAttributeData struct #ordered {
 	file_attributes:  u32,
 	creation_time,
 	last_access_time,
@@ -150,7 +150,7 @@ const FileAttributeData = struct #ordered {
 	file_size_low:    u32,
 }
 
-const FindData = struct #ordered {
+type FindData struct #ordered {
     file_attributes     : u32,
     creation_time       : Filetime,
     last_access_time    : Filetime,
@@ -164,7 +164,7 @@ const FindData = struct #ordered {
 }
 
 
-const GET_FILEEX_INFO_LEVELS = i32;
+type GET_FILEEX_INFO_LEVELS i32;
 
 const GetFileExInfoStandard: GET_FILEEX_INFO_LEVELS = 0;
 const GetFileExMaxInfoLevel: GET_FILEEX_INFO_LEVELS = 1;
@@ -323,7 +323,7 @@ const HEAP_ZERO_MEMORY = 0x00000008;
 
 // Synchronization
 
-const Security_Attributes = struct #ordered {
+type Security_Attributes struct #ordered {
 	length:              u32,
 	security_descriptor: rawptr,
 	inherit_handle:      Bool,
@@ -357,7 +357,7 @@ proc read_barrier      () #foreign kernel32 "ReadBarrier";
 
 
 
-const Hmonitor = Handle;
+type Hmonitor Handle;
 
 const GWL_STYLE = -16;
 
@@ -374,14 +374,14 @@ const SWP_NOSIZE        = 0x0001;
 const SWP_NOMOVE        = 0x0002;
 
 
-const MonitorInfo = struct #ordered {
+type MonitorInfo struct #ordered {
 	size:      u32,
 	monitor:   Rect,
 	work:      Rect,
 	flags:     u32,
 }
 
-const WindowPlacement = struct #ordered {
+type WindowPlacement struct #ordered {
 	length:     u32,
 	flags:      u32,
 	show_cmd:   u32,
@@ -418,7 +418,7 @@ proc LOWORD(lParam: Lparam) -> u16 { return u16(lParam); }
 
 
 
-const BitmapInfoHeader = struct #ordered {
+type BitmapInfoHeader struct #ordered {
 	size:              u32,
 	width, height:     i32,
 	planes, bit_count: i16,
@@ -429,13 +429,13 @@ const BitmapInfoHeader = struct #ordered {
 	clr_used:          u32,
 	clr_important:     u32,
 }
-const BitmapInfo = struct #ordered {
+type BitmapInfo struct #ordered {
 	using header: BitmapInfoHeader,
 	colors:       [1]RgbQuad,
 }
 
 
-const RgbQuad = struct #ordered { blue, green, red, reserved: u8 }
+type RgbQuad struct #ordered { blue, green, red, reserved: u8 }
 
 const BI_RGB         = 0;
 const DIB_RGB_COLORS = 0x00;
@@ -481,7 +481,7 @@ const PFD_DOUBLEBUFFER_DONTCARE = 0x40000000;
 const PFD_STEREO_DONTCARE       = 0x80000000;
 
 
-const PixelFormatDescriptor = struct #ordered {
+type PixelFormatDescriptor struct #ordered {
 	size,
 	version,
 	flags: u32,
@@ -519,7 +519,7 @@ proc swap_buffers       (hdc: Hdc) -> Bool
 proc release_dc         (wnd: Hwnd, hdc: Hdc) -> i32                                       #foreign user32 "ReleaseDC";
 
 
-const Proc  = type proc() #cc_c;
+type Proc proc() #cc_c;
 
 const MAPVK_VK_TO_CHAR   = 2;
 const MAPVK_VK_TO_VSC    = 0;
@@ -533,7 +533,7 @@ proc get_async_key_state(v_key: i32) -> i16 #foreign user32 "GetAsyncKeyState";
 
 proc is_key_down(key: KeyCode) -> bool #inline { return get_async_key_state(i32(key)) < 0; }
 
-const KeyCode = enum i32 {
+type KeyCode enum i32 {
 	Lbutton    = 0x01,
 	Rbutton    = 0x02,
 	Cancel     = 0x03,

+ 3 - 3
core/utf8.odin

@@ -28,9 +28,9 @@ const RUNE3_MAX = 1<<16 - 1;
 const LOCB = 0b1000_0000;
 const HICB = 0b1011_1111;
 
-const AcceptRange = struct { lo, hi: u8 }
+type AcceptRange struct { lo, hi: u8 }
 
-immutable var accept_ranges = [5]AcceptRange{
+let accept_ranges = [5]AcceptRange{
 	{0x80, 0xbf},
 	{0xa0, 0xbf},
 	{0x80, 0x9f},
@@ -38,7 +38,7 @@ immutable var accept_ranges = [5]AcceptRange{
 	{0x80, 0x8f},
 };
 
-immutable var accept_sizes = [256]u8{
+let accept_sizes = [256]u8{
 	0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f
 	0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1f
 	0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f

+ 2 - 0
src/check_decl.cpp

@@ -178,6 +178,7 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
 	if (init != NULL) {
 		check_expr_or_type(c, &operand, init);
 	}
+#if 0
 	if (operand.mode == Addressing_Type) {
 		e->kind = Entity_TypeName;
 
@@ -186,6 +187,7 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
 		check_type_decl(c, e, d->type_expr, named_type);
 		return;
 	}
+#endif
 
 	check_init_constant(c, e, &operand);
 

+ 1 - 1
src/check_stmt.cpp

@@ -1538,7 +1538,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 
 	case_ast_node(vd, ValueDecl, node);
 		GB_ASSERT(!c->context.scope->is_file);
-		if (vd->token.kind != Token_var) {
+		if (vd->token.kind == Token_const) {
 			// NOTE(bill): Handled elsewhere
 		} else {
 			Entity **entities = gb_alloc_array(c->allocator, Entity *, vd->names.count);

+ 43 - 22
src/checker.cpp

@@ -1451,7 +1451,7 @@ void check_collect_entities(Checker *c, Array<AstNode *> nodes, bool is_file_sco
 		case_end;
 
 		case_ast_node(vd, ValueDecl, decl);
-			if (vd->token.kind == Token_var) {
+			if (vd->token.kind != Token_const) {
 				if (!c->context.scope->is_file) {
 					// NOTE(bill): local scope -> handle later and in order
 					break;
@@ -1527,30 +1527,30 @@ void check_collect_entities(Checker *c, Array<AstNode *> nodes, bool is_file_sco
 					Entity *e = NULL;
 
 					AstNode *up_init = unparen_expr(init);
-					if (up_init != NULL && is_ast_node_type(up_init)) {
-						AstNode *type = up_init;
-						e = make_entity_type_name(c->allocator, d->scope, name->Ident, NULL);
-						// TODO(bill): What if vd->type != NULL??? How to handle this case?
-						d->type_expr = type;
-						d->init_expr = type;
-					} else if (up_init != NULL && up_init->kind == AstNode_Alias) {
-					#if 1
-						error_node(up_init, "#alias declarations are not yet supported");
-						continue;
-					#else
-						e = make_entity_alias(c->allocator, d->scope, name->Ident, NULL, EntityAlias_Invalid, NULL);
-						d->type_expr = vd->type;
-						d->init_expr = up_init->Alias.expr;
-					#endif
-					// } else if (init != NULL && up_init->kind == AstNode_ProcLit) {
-						// e = make_entity_procedure(c->allocator, d->scope, name->Ident, NULL, up_init->ProcLit.tags);
-						// d->proc_lit = up_init;
-						// d->type_expr = vd->type;
-					} else {
+					// if (up_init != NULL && is_ast_node_type(up_init)) {
+					// 	AstNode *type = up_init;
+					// 	e = make_entity_type_name(c->allocator, d->scope, name->Ident, NULL);
+					// 	// TODO(bill): What if vd->type != NULL??? How to handle this case?
+					// 	d->type_expr = type;
+					// 	d->init_expr = type;
+					// } else if (up_init != NULL && up_init->kind == AstNode_Alias) {
+					// #if 1
+					// 	error_node(up_init, "#alias declarations are not yet supported");
+					// 	continue;
+					// #else
+					// 	e = make_entity_alias(c->allocator, d->scope, name->Ident, NULL, EntityAlias_Invalid, NULL);
+					// 	d->type_expr = vd->type;
+					// 	d->init_expr = up_init->Alias.expr;
+					// #endif
+					// // } else if (init != NULL && up_init->kind == AstNode_ProcLit) {
+					// 	// e = make_entity_procedure(c->allocator, d->scope, name->Ident, NULL, up_init->ProcLit.tags);
+					// 	// d->proc_lit = up_init;
+					// 	// d->type_expr = vd->type;
+					// } else {
 						e = make_entity_constant(c->allocator, d->scope, name->Ident, NULL, empty_exact_value);
 						d->type_expr = vd->type;
 						d->init_expr = init;
-					}
+					// }
 					GB_ASSERT(e != NULL);
 					e->identifier = name;
 
@@ -1579,6 +1579,27 @@ void check_collect_entities(Checker *c, Array<AstNode *> nodes, bool is_file_sco
 			add_entity_and_decl_info(c, name, e, d);
 		case_end;
 
+		case_ast_node(td, TypeDecl, decl);
+			AstNode *name = td->name;
+			if (name->kind != AstNode_Ident) {
+				error_node(name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[name->kind]));
+				break;
+			}
+
+
+			DeclInfo *d = make_declaration_info(c->allocator, c->context.scope, c->context.decl);
+			Entity *e = NULL;
+
+			AstNode *type = unparen_expr(td->type);
+			e = make_entity_type_name(c->allocator, d->scope, name->Ident, NULL);
+			// TODO(bill): What if vd->type != NULL??? How to handle this case?
+			d->type_expr = type;
+			d->init_expr = type;
+
+			e->identifier = name;
+			add_entity_and_decl_info(c, name, e, d);
+		case_end;
+
 		case_ast_node(id, ImportDecl, decl);
 			if (!c->context.scope->is_file) {
 				if (id->is_import) {

+ 23 - 25
src/ir.cpp

@@ -5813,7 +5813,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
 	case_end;
 
 	case_ast_node(vd, ValueDecl, node);
-		if (vd->token.kind == Token_var) {
+		if (vd->token.kind != Token_const) {
 			irModule *m = proc->module;
 			gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&m->tmp_arena);
 
@@ -5862,30 +5862,6 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
 			}
 
 			gb_temp_arena_memory_end(tmp);
-		} else {
-			for_array(i, vd->names) {
-				AstNode *ident = vd->names[i];
-				GB_ASSERT(ident->kind == AstNode_Ident);
-				Entity *e = entity_of_ident(proc->module->info, ident);
-				GB_ASSERT(e != NULL);
-				switch (e->kind) {
-				case Entity_TypeName: {
-					// NOTE(bill): Generate a new name
-					// parent_proc.name-guid
-					String ts_name = e->token.string;
-					isize name_len = proc->name.len + 1 + ts_name.len + 1 + 10 + 1;
-					u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len);
-					i32 guid = cast(i32)proc->module->members.entries.count;
-					name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s.%.*s-%d", LIT(proc->name), LIT(ts_name), guid);
-					String name = make_string(name_text, name_len-1);
-
-					irValue *value = ir_value_type_name(proc->module->allocator,
-					                                           name, e->type);
-					map_set(&proc->module->entity_names, hash_pointer(e), name);
-					ir_gen_global_type_name(proc->module, e, name);
-				} break;
-				}
-			}
 		}
 	case_end;
 
@@ -5960,6 +5936,28 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
 		}
 	case_end;
 
+	case_ast_node(td, TypeDecl, node);
+		AstNode *ident = td->name;
+		GB_ASSERT(ident->kind == AstNode_Ident);
+		Entity *e = entity_of_ident(proc->module->info, ident);
+		GB_ASSERT(e != NULL);
+		if (e->kind == Entity_TypeName) {
+			// NOTE(bill): Generate a new name
+			// parent_proc.name-guid
+			String ts_name = e->token.string;
+			isize name_len = proc->name.len + 1 + ts_name.len + 1 + 10 + 1;
+			u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len);
+			i32 guid = cast(i32)proc->module->members.entries.count;
+			name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s.%.*s-%d", LIT(proc->name), LIT(ts_name), guid);
+			String name = make_string(name_text, name_len-1);
+
+			irValue *value = ir_value_type_name(proc->module->allocator,
+			                                           name, e->type);
+			map_set(&proc->module->entity_names, hash_pointer(e), name);
+			ir_gen_global_type_name(proc->module, e, name);
+		}
+	case_end;
+
 	case_ast_node(as, AssignStmt, node);
 		ir_emit_comment(proc, str_lit("AssignStmt"));
 

+ 66 - 27
src/parser.cpp

@@ -314,6 +314,11 @@ AST_NODE_KIND(_DeclBegin,      "", i32) \
 		String   foreign_name;    \
 		String   link_name;       \
 	}) \
+	AST_NODE_KIND(TypeDecl, "type declaration", struct { \
+		Token    token; \
+		AstNode *name;  \
+		AstNode *type;  \
+	}) \
 	AST_NODE_KIND(ImportDecl, "import declaration", struct { \
 		Token     token;        \
 		bool      is_import;    \
@@ -1446,6 +1451,14 @@ AstNode *ast_proc_decl(AstFile *f, Token token, AstNode *name, AstNode *type, As
 	return result;
 }
 
+AstNode *ast_type_decl(AstFile *f, Token token, AstNode *name, AstNode *type) {
+	AstNode *result = make_ast_node(f, AstNode_TypeDecl);
+	result->TypeDecl.token = token;
+	result->TypeDecl.name  = name;
+	result->TypeDecl.type  = type;
+	return result;
+}
+
 
 AstNode *ast_import_decl(AstFile *f, Token token, bool is_import, Token relpath, Token import_name, AstNode *cond) {
 	AstNode *result = make_ast_node(f, AstNode_ImportDecl);
@@ -1590,6 +1603,11 @@ void fix_advance_to_next_stmt(AstFile *f) {
 		case Token_Semicolon:
 			return;
 
+		case Token_var:
+		case Token_const:
+		case Token_let:
+		case Token_type:
+
 		case Token_if:
 		case Token_when:
 		case Token_return:
@@ -1597,7 +1615,6 @@ void fix_advance_to_next_stmt(AstFile *f) {
 		case Token_defer:
 		case Token_asm:
 		case Token_using:
-		case Token_immutable:
 		// case Token_thread_local:
 		// case Token_no_alias:
 
@@ -1671,9 +1688,12 @@ bool is_semicolon_optional_for_node(AstFile *f, AstNode *s) {
 		return s->ProcLit.body != NULL;
 	case AstNode_ProcDecl:
 		return s->ProcDecl.body != NULL;
+	case AstNode_TypeDecl:
+		return is_semicolon_optional_for_node(f, s->TypeDecl.type);
+
 
 	case AstNode_ValueDecl:
-		if (s->ValueDecl.token.kind != Token_var) {
+		if (s->ValueDecl.token.kind != Token_const) {
 			if (s->ValueDecl.values.count > 0) {
 				AstNode *last = s->ValueDecl.values[s->ValueDecl.values.count-1];
 				return is_semicolon_optional_for_node(f, last);
@@ -2511,7 +2531,7 @@ AstNode *parse_value_decl(AstFile *f, Token token) {
 	Array<AstNode *> lhs = parse_lhs_expr_list(f);
 	AstNode *type = NULL;
 	Array<AstNode *> values = {};
-	bool is_mutable = token.kind == Token_var;
+	bool is_mutable = token.kind != Token_const;
 
 	if (allow_token(f, Token_Colon)) {
 		type = parse_type(f);
@@ -2551,12 +2571,14 @@ AstNode *parse_value_decl(AstFile *f, Token token) {
 		values = make_ast_node_array(f);
 	}
 
+
 	Array<AstNode *> specs = {};
 	array_init(&specs, heap_allocator(), 1);
-	// Token token = ast_node_token(lhs[0]);
-	// token.kind = is_mutable ? Token_var : Token_const;
-	// token.string = is_mutable ? str_lit("var") : str_lit("const");
-	return ast_value_decl(f, token, lhs, type, values);
+	AstNode *decl =  ast_value_decl(f, token, lhs, type, values);
+	if (token.kind == Token_let) {
+		decl->ValueDecl.flags |= VarDeclFlag_immutable;
+	}
+	return decl;
 }
 
 AstNode *parse_proc_decl(AstFile *f) {
@@ -2583,6 +2605,13 @@ AstNode *parse_proc_decl(AstFile *f) {
 	return ast_proc_decl(f, token, name, type, body, tags, foreign_library, foreign_name, link_name);
 }
 
+AstNode *parse_type_decl(AstFile *f) {
+	Token token = expect_token(f, Token_type);
+	AstNode *name = parse_ident(f);
+	AstNode *type = parse_type(f);
+	return ast_type_decl(f, token, name, type);
+}
+
 
 
 AstNode *parse_simple_stmt(AstFile *f, StmtAllowFlag flags) {
@@ -2590,6 +2619,7 @@ AstNode *parse_simple_stmt(AstFile *f, StmtAllowFlag flags) {
 	switch (f->curr_token.kind) {
 	case Token_var:
 	case Token_const:
+	case Token_let:
 		next_token(f);
 		return parse_value_decl(f, token);
 	}
@@ -2783,7 +2813,7 @@ FieldPrefixKind is_token_field_prefix(AstFile *f) {
 	case Token_using:
 		return FieldPrefix_Using;
 
-	case Token_immutable:
+	case Token_let:
 		return FieldPrefix_Immutable;
 
 	case Token_Hash: {
@@ -3686,6 +3716,7 @@ AstNode *parse_stmt(AstFile *f) {
 
 	case Token_var:
 	case Token_const:
+	case Token_let:
 		s = parse_simple_stmt(f, StmtAllowFlag_None);
 		expect_semicolon(f, s);
 		return s;
@@ -3695,6 +3726,11 @@ AstNode *parse_stmt(AstFile *f) {
 		expect_semicolon(f, s);
 		return s;
 
+	case Token_type:
+		s = parse_type_decl(f);
+		expect_semicolon(f, s);
+		return s;
+
 
 	case Token_if:     return parse_if_stmt(f);
 	case Token_when:   return parse_when_stmt(f);
@@ -3722,27 +3758,30 @@ AstNode *parse_stmt(AstFile *f) {
 	case Token_using: {
 		// TODO(bill): Make using statements better
 		Token token = expect_token(f, Token_using);
-		Array<AstNode *> list = parse_lhs_expr_list(f);
-		if (list.count == 0) {
-			syntax_error(token, "Illegal use of `using` statement");
-			expect_semicolon(f, NULL);
-			return ast_bad_stmt(f, token, f->curr_token);
-		}
+		AstNode *decl = NULL;
+		if (f->curr_token.kind == Token_var ||
+		    f->curr_token.kind == Token_let) {
+			Token var = f->curr_token; next_token(f);
+			decl = parse_value_decl(f, var);
+			expect_semicolon(f, decl);
+		} else {
+			Array<AstNode *> list = parse_lhs_expr_list(f);
+			if (list.count == 0) {
+				syntax_error(token, "Illegal use of `using` statement");
+				expect_semicolon(f, NULL);
+				return ast_bad_stmt(f, token, f->curr_token);
+			}
 
-		if (f->curr_token.kind != Token_Colon) {
-			expect_semicolon(f, list[list.count-1]);
-			return ast_using_stmt(f, token, list);
+			if (f->curr_token.kind != Token_Colon) {
+				expect_semicolon(f, list[list.count-1]);
+				return ast_using_stmt(f, token, list);
+			}
 		}
 
-		Token var = ast_node_token(list[0]);
-		var.kind = Token_var;
-		var.string = str_lit("var");
-		AstNode *decl = parse_value_decl(f, var);
-		expect_semicolon(f, decl);
 
-		if (decl->kind == AstNode_ValueDecl) {
+		if (decl != NULL && decl->kind == AstNode_ValueDecl) {
 			#if 1
-			if (decl->ValueDecl.token.kind != Token_var) {
+			if (decl->ValueDecl.token.kind == Token_const) {
 				syntax_error(token, "`using` may not be applied to constant declarations");
 				return decl;
 			}
@@ -3761,13 +3800,13 @@ AstNode *parse_stmt(AstFile *f) {
 		return ast_bad_stmt(f, token, f->curr_token);
 	} break;
 
-#if 1
+#if 0
 	case Token_immutable: {
 		Token token = expect_token(f, Token_immutable);
 		AstNode *node = parse_stmt(f);
 
 		if (node->kind == AstNode_ValueDecl) {
-			if (node->ValueDecl.token.kind != Token_var) {
+			if (node->ValueDecl.token.kind == Token_const) {
 				syntax_error(token, "`immutable` may not be applied to constant declarations");
 			} else {
 				node->ValueDecl.flags |= VarDeclFlag_immutable;
@@ -3939,7 +3978,7 @@ AstNode *parse_stmt(AstFile *f) {
 			AstNode *s = parse_stmt(f);
 
 			if (s->kind == AstNode_ValueDecl) {
-				if (s->ValueDecl.token.kind != Token_var) {
+				if (s->ValueDecl.token.kind == Token_const) {
 					syntax_error(token, "`thread_local` may not be applied to constant declarations");
 				}
 				if (f->curr_proc != NULL) {

+ 1 - 1
src/ssa.cpp

@@ -1969,7 +1969,7 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
 	case_end;
 
 	case_ast_node(vd, ValueDecl, node);
-		if (vd->token.kind == Token_var) {
+		if (vd->token.kind != Token_const) {
 			ssaModule *m = p->module;
 			gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&m->tmp_arena);
 			if (vd->values.count == 0) {

+ 1 - 1
src/tokenizer.cpp

@@ -83,6 +83,7 @@ TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \
 \
 TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
 	TOKEN_KIND(Token_var,            "var"),                 \
+	TOKEN_KIND(Token_let,            "let"),                 \
 	TOKEN_KIND(Token_const,          "const"),               \
 	TOKEN_KIND(Token_type,           "type"),                \
 	TOKEN_KIND(Token_when,           "when"),                \
@@ -109,7 +110,6 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
 	TOKEN_KIND(Token_dynamic,        "dynamic"),             \
 	TOKEN_KIND(Token_map,            "map"),                 \
 	TOKEN_KIND(Token_using,          "using"),               \
-	TOKEN_KIND(Token_immutable,      "immutable"),           \
 	TOKEN_KIND(Token_context,        "context"),             \
 	TOKEN_KIND(Token_push_context,   "push_context"),        \
 	TOKEN_KIND(Token_push_allocator, "push_allocator"),      \