Browse Source

Use semicolons as field delimiters in records

Ginger Bill 8 years ago
parent
commit
66e4aaffc5
15 changed files with 467 additions and 350 deletions
  1. 24 24
      code/demo.odin
  2. 89 89
      core/_preload.odin
  3. 4 4
      core/_soft_numbers.odin
  4. 4 4
      core/decimal.odin
  5. 18 18
      core/fmt.odin
  6. 7 7
      core/mem.odin
  7. 21 21
      core/os_linux.odin
  8. 22 22
      core/os_x.odin
  9. 13 13
      core/raw.odin
  10. 13 13
      core/strconv.odin
  11. 5 5
      core/sync_linux.odin
  12. 6 6
      core/sync_windows.odin
  13. 30 32
      core/sys/wgl.odin
  14. 82 82
      core/sys/windows.odin
  15. 129 10
      src/parser.cpp

+ 24 - 24
code/demo.odin

@@ -42,9 +42,9 @@ general_stuff :: proc() {
 
 
 	Foo :: struct {
-		x: int,
-		y: f32,
-		z: string,
+		x: int;
+		y: f32;
+		z: string;
 	}
 	foo := Foo{123, 0.513, "A string"};
 	x, y, z := expand_to_tuple(foo);
@@ -176,8 +176,8 @@ default_return_values :: proc() {
 	};
 
 	Entity :: struct {
-		name: string,
-		id:   u32,
+		name: string;
+		id:   u32;
 	}
 
 	some_thing :: proc(input: int) -> (result: ^Entity = nil, err := Error.None) {
@@ -256,39 +256,39 @@ explicit_parametric_polymorphic_procedures :: proc() {
 	Vector2 :: struct {x, y: f32};
 
 	Entity :: struct {
-		using position: Vector2,
-		flags:          u64,
-		id:             u64,
-		batch_index:    u32,
-		slot_index:     u32,
-		portable_id:    u32,
-		derived:        any,
+		using position: Vector2;
+		flags:          u64;
+		id:             u64;
+		batch_index:    u32;
+		slot_index:     u32;
+		portable_id:    u32;
+		derived:        any;
 	}
 
 	Rock :: struct {
-		using entity: ^Entity,
-		heavy: bool,
+		using entity: ^Entity;
+		heavy: bool;
 	}
 	Door :: struct {
-		using entity: ^Entity,
-		open:         bool,
+		using entity: ^Entity;
+		open:         bool;
 	}
 	Monster :: struct {
-		using entity: ^Entity,
-		is_robot:     bool,
-		is_zombie:    bool,
+		using entity: ^Entity;
+		is_robot:     bool;
+		is_zombie:    bool;
 	}
 
 	EntityManager :: struct {
-		batches: [dynamic]^EntityBatch,
-		next_portable_id: u32,
+		batches: [dynamic]^EntityBatch;
+		next_portable_id: u32;
 	}
 
 	ENTITIES_PER_BATCH :: 16;
 	EntityBatch :: struct {
-		data:        [ENTITIES_PER_BATCH]Entity,
-		occupied:    [ENTITIES_PER_BATCH]bool,
-		batch_index: u32,
+		data:        [ENTITIES_PER_BATCH]Entity;
+		occupied:    [ENTITIES_PER_BATCH]bool;
+		batch_index: u32;
 	}
 
 	use_empty_slot :: proc(manager: ^EntityManager, batch: ^EntityBatch) -> ^Entity {

+ 89 - 89
core/_preload.odin

@@ -23,12 +23,6 @@ import (
 // implemented within the compiler rather than in this "preload" file
 
 
-// IMPORTANT NOTE(bill): Do not change the order of any of this data
-// The compiler relies upon this _exact_ order
-TypeInfoEnumValue :: raw_union {
-	f: f64,
-	i: i128,
-}
 // NOTE(bill): This must match the compiler's
 CallingConvention :: enum {
 	Invalid         = 0,
@@ -38,75 +32,81 @@ CallingConvention :: enum {
 	Std             = 4,
 	Fast            = 5,
 }
+// IMPORTANT NOTE(bill): Do not change the order of any of this data
+// The compiler relies upon this _exact_ order
+TypeInfoEnumValue :: raw_union {
+	f: f64;
+	i: i128;
+}
 
 TypeInfoRecord :: struct #ordered {
-	types:        []^TypeInfo,
-	names:        []string,
-	offsets:      []int,  // offsets may not be used in tuples
-	usings:       []bool, // usings may not be used in tuples
-	packed:       bool,
-	ordered:      bool,
-	custom_align: bool,
+	types:        []^TypeInfo;
+	names:        []string;
+	offsets:      []int;  // offsets may not be used in tuples
+	usings:       []bool; // usings may not be used in tuples
+	packed:       bool;
+	ordered:      bool;
+	custom_align: bool;
 }
 
 TypeInfo :: union {
-	size:  int,
-	align: int,
-
-	Named{name: string, base: ^TypeInfo},
-	Integer{signed: bool},
-	Rune{},
-	Float{},
-	Complex{},
-	String{},
-	Boolean{},
-	Any{},
+	size:  int;
+	align: int;
+
+	Named{name: string; base: ^TypeInfo};
+	Integer{signed: bool};
+	Rune{};
+	Float{};
+	Complex{};
+	String{};
+	Boolean{};
+	Any{};
 	Pointer{
-		elem: ^TypeInfo, // nil -> rawptr
-	},
-	Atomic{elem: ^TypeInfo},
+		elem: ^TypeInfo; // nil -> rawptr
+	};
+	Atomic{elem: ^TypeInfo};
 	Procedure{
-		params:     ^TypeInfo, // TypeInfo.Tuple
-		results:    ^TypeInfo, // TypeInfo.Tuple
-		variadic:   bool,
-		convention: CallingConvention,
-	},
+		params:     ^TypeInfo; // TypeInfo.Tuple
+		results:    ^TypeInfo; // TypeInfo.Tuple
+		variadic:   bool;
+		convention: CallingConvention;
+	};
 	Array{
-		elem:      ^TypeInfo,
-		elem_size: int,
-		count:     int,
-	},
-	DynamicArray{elem: ^TypeInfo, elem_size: int},
-	Slice       {elem: ^TypeInfo, elem_size: int},
-	Vector      {elem: ^TypeInfo, elem_size, count: int},
-	Tuple       {using record: TypeInfoRecord}, // Only really used for procedures
-	Struct      {using record: TypeInfoRecord},
-	RawUnion    {using record: TypeInfoRecord},
+		elem:      ^TypeInfo;
+		elem_size: int;
+		count:     int;
+	};
+	DynamicArray{elem: ^TypeInfo; elem_size: int};
+	Slice       {elem: ^TypeInfo; elem_size: int};
+	Vector      {elem: ^TypeInfo; elem_size, count: int};
+	Tuple       {using record: TypeInfoRecord}; // Only really used for procedures
+	Struct      {using record: TypeInfoRecord};
+	RawUnion    {using record: TypeInfoRecord};
 	Union{
 		common_fields: struct {
-			types:     []^TypeInfo,
-			names:     []string,
-			offsets:   []int,    // offsets may not be used in tuples
-		},
-		variant_names: []string,
-		variant_types: []^TypeInfo,
-	},
+			types:     []^TypeInfo;
+			names:     []string;
+			offsets:   []int;    // offsets may not be used in tuples
+		};
+		variant_names: []string;
+		variant_types: []^TypeInfo;
+	};
 	Enum{
-		base:   ^TypeInfo,
-		names:  []string,
-		values: []TypeInfoEnumValue,
-	},
+		base:   ^TypeInfo;
+		names:  []string;
+		values: []TypeInfoEnumValue;
+	};
 	Map{
-		key:              ^TypeInfo,
-		value:            ^TypeInfo,
-		generated_struct: ^TypeInfo,
-		count:            int, // == 0 if dynamic
-	},
+		key:              ^TypeInfo;
+		value:            ^TypeInfo;
+		generated_struct: ^TypeInfo;
+		count:            int; // == 0 if dynamic
+	};
 	BitField{
-		names:   []string,
-		bits:    []i32,
-		offsets: []i32,
-	},
+		names:   []string;
+		bits:    []i32;
+		offsets: []i32;
+	};
 }
 
 // NOTE(bill): only the ones that are needed (not all types)
@@ -127,58 +127,58 @@ AllocatorProc :: proc(allocator_data: rawptr, mode: AllocatorMode,
                       size, alignment: int,
                       old_memory: rawptr, old_size: int, flags: u64 = 0) -> rawptr;
 Allocator :: struct #ordered {
-	procedure: AllocatorProc,
-	data:      rawptr,
+	procedure: AllocatorProc;
+	data:      rawptr;
 }
 
 
 Context :: struct #ordered {
-	thread_guid:  int,
-	thread_index: int,
+	thread_guid:  int;
+	thread_index: int;
 
-	allocator:  Allocator,
+	allocator:  Allocator;
 
-	user_data:  rawptr,
-	user_index: int,
+	user_data:  rawptr;
+	user_index: int;
 }
 
 DEFAULT_ALIGNMENT :: align_of([vector 4]f32);
 
 SourceCodeLocation :: struct {
-	fully_pathed_filename: string,
-	line, column:          i64,
-	procedure:             string,
+	fully_pathed_filename: string;
+	line, column:          i64;
+	procedure:             string;
 }
 
 
 __INITIAL_MAP_CAP :: 16;
 
 __MapKey :: struct #ordered {
-	hash: u128,
-	str:  string,
+	hash: u128;
+	str:  string;
 }
 
 __MapFindResult :: struct #ordered {
-	hash_index:  int,
-	entry_prev:  int,
-	entry_index: int,
+	hash_index:  int;
+	entry_prev:  int;
+	entry_index: int;
 }
 
 __MapEntryHeader :: struct #ordered {
-	key:  __MapKey,
-	next: int,
+	key:  __MapKey;
+	next: int;
 /*
-	value: Value_Type,
+	value: Value_Type;
 */
 }
 
 __MapHeader :: struct #ordered {
-	m:             ^raw.DynamicMap,
-	is_key_string: bool,
-	entry_size:    int,
-	entry_align:   int,
-	value_offset:  int,
-	value_size:    int,
+	m:             ^raw.DynamicMap;
+	is_key_string: bool;
+	entry_size:    int;
+	entry_align:   int;
+	value_offset:  int;
+	value_size:    int;
 }
 
 
@@ -387,9 +387,9 @@ reserve :: proc(array: ^[dynamic]$T, capacity: int) -> bool {
 __get_map_header :: proc(m: ^map[$K]$V) -> __MapHeader #cc_contextless {
 	header := __MapHeader{m = ^raw.DynamicMap(m)};
 	Entry :: struct {
-		key:   __MapKey,
-		next:  int,
-		value: V,
+		key:   __MapKey;
+		next:  int;
+		value: V;
 	}
 
 	_, is_string := type_info_base(type_info(K)).(^TypeInfo.String);

+ 4 - 4
core/_soft_numbers.odin

@@ -7,13 +7,13 @@ __multi3 :: proc(a, b: u128) -> u128 #cc_c #link_name "__multi3" {
 
 	when ODIN_ENDIAN == "bit" {
 		TWords :: raw_union {
-			all: u128,
-			using _: struct {lo, hi: u64},
+			all: u128;
+			using _: struct {lo, hi: u64};
 		};
 	} else {
 		TWords :: raw_union {
-			all: u128,
-			using _: struct {hi, lo: u64},
+			all: u128;
+			using _: struct {hi, lo: u64};
 		};
 	}
 

+ 4 - 4
core/decimal.odin

@@ -3,10 +3,10 @@
 // NOTE: This is only for floating point printing and nothing else
 
 Decimal :: struct {
-	digits:        [384]u8, // big-endian digits
-	count:         int,
-	decimal_point: int,
-	neg, trunc:    bool,
+	digits:        [384]u8; // big-endian digits
+	count:         int;
+	decimal_point: int;
+	neg, trunc:    bool;
 }
 
 decimal_to_string :: proc(buf: []u8, a: ^Decimal) -> string {

+ 18 - 18
core/fmt.odin

@@ -10,27 +10,27 @@ import (
 _BUFFER_SIZE :: 1<<12;
 
 StringBuffer :: union {
-	Static {buf: []u8},
-	Dynamic{buf: [dynamic]u8},
+	Static {buf: []u8};
+	Dynamic{buf: [dynamic]u8};
 }
 
 FmtInfo :: struct {
-	minus:     bool,
-	plus:      bool,
-	space:     bool,
-	zero:      bool,
-	hash:      bool,
-	width_set: bool,
-	prec_set:  bool,
-
-	width:     int,
-	prec:      int,
-
-	reordered:      bool,
-	good_arg_index: bool,
-
-	buf: ^StringBuffer,
-	arg: any, // Temporary
+	minus:     bool;
+	plus:      bool;
+	space:     bool;
+	zero:      bool;
+	hash:      bool;
+	width_set: bool;
+	prec_set:  bool;
+
+	width:     int;
+	prec:      int;
+
+	reordered:      bool;
+	good_arg_index: bool;
+
+	buf: ^StringBuffer;
+	arg: any; // Temporary
 }
 
 

+ 7 - 7
core/mem.odin

@@ -68,7 +68,7 @@ align_forward :: proc(ptr: rawptr, align: int) -> rawptr {
 
 
 AllocationHeader :: struct {
-	size: int,
+	size: int;
 }
 
 allocation_header_fill :: proc(header: ^AllocationHeader, data: rawptr, size: int) {
@@ -93,15 +93,15 @@ allocation_header :: proc(data: rawptr) -> ^AllocationHeader {
 // Custom allocators
 
 Arena :: struct {
-	backing:    Allocator,
-	offset:     int,
-	memory:     []u8,
-	temp_count: int,
+	backing:    Allocator;
+	offset:     int;
+	memory:     []u8;
+	temp_count: int;
 }
 
 ArenaTempMemory :: struct {
-	arena:          ^Arena,
-	original_count: int,
+	arena:          ^Arena;
+	original_count: int;
 }
 
 

+ 21 - 21
core/os_linux.odin

@@ -41,9 +41,9 @@ RTLD_GLOBAL       :: 0x100;
 args := _alloc_command_line_arguments();
 
 _FileTime :: struct #ordered {
-	seconds:     i64,
-	nanoseconds: i32,
-	reserved:    i32,
+	seconds:     i64;
+	nanoseconds: i32;
+	reserved:    i32;
 }
 
 // Translated from
@@ -51,27 +51,27 @@ _FileTime :: struct #ordered {
 // Validity is not guaranteed.
 
 Stat :: struct #ordered {
-	device_id:     u64, // ID of device containing file
-	serial:        u64, // File serial number
-	nlink:         u32, // Number of hard links
-	mode:          u32, // Mode of the file
-	uid:           u32, // User ID of the file's owner
-	gid:           u32, // Group ID of the file's group
-	_padding:      i32, // 32 bits of padding
-	rdev:          u64, // Device ID, if device
-	size:          i64, // Size of the file, in bytes
-	block_size:    i64, // Optimal bllocksize for I/O
-	blocks:        i64, // Number of 512-byte blocks allocated
-
-	last_access:   _FileTime, // Time of last access
-	modified:      _FileTime, // Time of last modification
-	status_change: _FileTime, // Time of last status change
+	device_id:     u64; // ID of device containing file
+	serial:        u64; // File serial number
+	nlink:         u32; // Number of hard links
+	mode:          u32; // Mode of the file
+	uid:           u32; // User ID of the file's owner
+	gid:           u32; // Group ID of the file's group
+	_padding:      i32; // 32 bits of padding
+	rdev:          u64; // Device ID, if device
+	size:          i64; // Size of the file, in bytes
+	block_size:    i64; // Optimal bllocksize for I/O
+	blocks:        i64; // Number of 512-byte blocks allocated
+
+	last_access:   _FileTime; // Time of last access
+	modified:      _FileTime; // Time of last modification
+	status_change: _FileTime; // Time of last status change
 
 	_reserve1,
 	_reserve2,
-	_reserve3:     i64,
-	serial_numbe:  u64, // File serial number...? Maybe.
-	_reserve4:     i64,
+	_reserve3:     i64;
+	serial_numbe:  u64; // File serial number...? Maybe.
+	_reserve4:     i64;
 };
 
 // File type

+ 22 - 22
core/os_x.odin

@@ -47,32 +47,32 @@ RTLD_FIRST    :: 0x100;
 args: [dynamic]string;
 
 _FileTime :: struct #ordered {
-	seconds: i64,
-	nanoseconds: i64
+	seconds: i64;
+	nanoseconds: i64;
 }
 
 Stat :: struct #ordered {
-	device_id : i32, // ID of device containing file
-	mode      : u16, // Mode of the file
-	nlink     : u16, // Number of hard links
-	serial    : u64, // File serial number
-	uid       : u32, // User ID of the file's owner
-	gid       : u32, // Group ID of the file's group
-	rdev      : i32, // Device ID, if device
-
-	last_access   : FileTime, // Time of last access
-	modified      : FileTime, // Time of last modification
-	status_change : FileTime, // Time of last status change
-	created       : FileTime, // Time of creation
-
-	size      : i64,  // Size of the file, in bytes
-	blocks    : i64,  // Number of blocks allocated for the file
-	block_size: i32,  // Optimal blocksize for I/O
-	flags     : u32,  // User-defined flags for the file
-	gen_num   : u32,  // File generation number ...?
-	_spare    : i32,  // RESERVED
+	device_id:     i32; // ID of device containing file
+	mode:          u16; // Mode of the file
+	nlink:         u16; // Number of hard links
+	serial:        u64; // File serial number
+	uid:           u32; // User ID of the file's owner
+	gid:           u32; // Group ID of the file's group
+	rdev:          i32; // Device ID, if device
+
+	last_access:   FileTime; // Time of last access
+	modified:      FileTime; // Time of last modification
+	status_change: FileTime; // Time of last status change
+	created:       FileTime; // Time of creation
+
+	size:          i64;  // Size of the file, in bytes
+	blocks:        i64;  // Number of blocks allocated for the file
+	block_size:    i32;  // Optimal blocksize for I/O
+	flags:         u32;  // User-defined flags for the file
+	gen_num:       u32;  // File generation number ...?
+	_spare:        i32;  // RESERVED
 	_reserve1,
-	_reserve2 : i64,  // RESERVED
+	_reserve2:     i64;  // RESERVED
 };
 
 // File type

+ 13 - 13
core/raw.odin

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

+ 13 - 13
core/strconv.odin

@@ -211,27 +211,27 @@ append_float :: proc(buf: []u8, f: f64, fmt: u8, prec, bit_size: int) -> string
 
 
 DecimalSlice :: struct {
-	digits:        []u8,
-	count:         int,
-	decimal_point: int,
-	neg:           bool,
+	digits:        []u8;
+	count:         int;
+	decimal_point: int;
+	neg:           bool;
 }
 
-Float_Info :: struct {
-	mantbits: uint,
-	expbits:  uint,
-	bias:     int,
+FloatInfo :: struct {
+	mantbits: uint;
+	expbits:  uint;
+	bias:     int;
 }
 
 
-_f16_info := Float_Info{10, 5,   -15};
-_f32_info := Float_Info{23, 8,  -127};
-_f64_info := Float_Info{52, 11, -1023};
+_f16_info := FloatInfo{10, 5,   -15};
+_f32_info := FloatInfo{23, 8,  -127};
+_f64_info := FloatInfo{52, 11, -1023};
 
 
 generic_ftoa :: proc(buf: []u8, val: f64, fmt: u8, prec, bit_size: int) -> []u8 {
 	bits: u64;
-	flt: ^Float_Info;
+	flt: ^FloatInfo;
 	match bit_size {
 	case 32:
 		bits = u64(transmute(u32, f32(val)));
@@ -346,7 +346,7 @@ format_digits :: proc(buf: []u8, shortest: bool, neg: bool, digs: DecimalSlice,
 	return buf;
 }
 
-round_shortest :: proc(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) {
+round_shortest :: proc(d: ^Decimal, mant: u64, exp: int, flt: ^FloatInfo) {
 	if mant == 0 { // If mantissa is zero, the number is zero
 		d.count = 0;
 		return;

+ 5 - 5
core/sync_linux.odin

@@ -4,14 +4,14 @@ import (
 )
 
 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 {

+ 6 - 6
core/sync_windows.odin

@@ -4,20 +4,20 @@ import (
 )
 
 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;
 }
 */
 
 Mutex :: struct {
-	_critical_section: win32.CriticalSection,
+	_critical_section: win32.CriticalSection;
 }
 
 current_thread_id :: proc() -> i32 {

+ 30 - 32
core/sys/wgl.odin

@@ -14,42 +14,40 @@ Hglrc    :: Handle;
 ColorRef :: u32;
 
 LayerPlaneDescriptor :: struct {
-	size:             u16,
-	version:          u16,
-	flags:            u32,
-	pixel_type:       u8,
-	color_bits:       u8,
-	red_bits:         u8,
-	red_shift:        u8,
-	green_bits:       u8,
-	green_shift:      u8,
-	blue_bits:        u8,
-	blue_shift:       u8,
-	alpha_bits:       u8,
-	alpha_shift:      u8,
-	accum_bits:       u8,
-	accum_red_bits:   u8,
-	accum_green_bits: u8,
-	accum_blue_bits:  u8,
-	accum_alpha_bits: u8,
-	depth_bits:       u8,
-	stencil_bits:     u8,
-	aux_buffers:      u8,
-	layer_type:       u8,
-	reserved:         u8,
-	transparent:      ColorRef,
+	size:             u16;
+	version:          u16;
+	flags:            u32;
+	pixel_type:       u8;
+	color_bits:       u8;
+	red_bits:         u8;
+	red_shift:        u8;
+	green_bits:       u8;
+	green_shift:      u8;
+	blue_bits:        u8;
+	blue_shift:       u8;
+	alpha_bits:       u8;
+	alpha_shift:      u8;
+	accum_bits:       u8;
+	accum_red_bits:   u8;
+	accum_green_bits: u8;
+	accum_blue_bits:  u8;
+	accum_alpha_bits: u8;
+	depth_bits:       u8;
+	stencil_bits:     u8;
+	aux_buffers:      u8;
+	layer_type:       u8;
+	reserved:         u8;
+	transparent:      ColorRef;
 }
 
-PointFloat :: struct {
-	x, y: f32,
-}
+PointFloat :: struct {x, y: f32};
 
 Glyph_MetricsFloat :: struct {
-	black_box_x:  f32,
-	black_box_y:  f32,
-	glyph_origin: PointFloat,
-	cell_inc_x:   f32,
-	cell_inc_y:   f32,
+	black_box_x:  f32;
+	black_box_y:  f32;
+	glyph_origin: PointFloat;
+	cell_inc_x:   f32;
+	cell_inc_y:   f32;
 }
 
 CreateContextAttribsARBType :: proc(hdc: Hdc, h_share_context: rawptr, attribList: ^i32) -> Hglrc;

+ 82 - 82
core/sys/windows.odin

@@ -27,86 +27,86 @@ FALSE: Bool : 0;
 TRUE:  Bool : 1;
 
 Point :: struct #ordered {
-	x, y: i32,
+	x, y: i32;
 }
 
 WndClassExA :: struct #ordered {
-	size, style:           u32,
-	wnd_proc:              WndProc,
-	cls_extra, wnd_extra:  i32,
-	instance:              Hinstance,
-	icon:                  Hicon,
-	cursor:                Hcursor,
-	background:            Hbrush,
-	menu_name, class_name: ^u8,
-	sm:                    Hicon,
+	size, style:           u32;
+	wnd_proc:              WndProc;
+	cls_extra, wnd_extra:  i32;
+	instance:              Hinstance;
+	icon:                  Hicon;
+	cursor:                Hcursor;
+	background:            Hbrush;
+	menu_name, class_name: ^u8;
+	sm:                    Hicon;
 }
 
 Msg :: struct #ordered {
-	hwnd:    Hwnd,
-	message: u32,
-	wparam:  Wparam,
-	lparam:  Lparam,
-	time:    u32,
-	pt:      Point,
+	hwnd:    Hwnd;
+	message: u32;
+	wparam:  Wparam;
+	lparam:  Lparam;
+	time:    u32;
+	pt:      Point;
 }
 
 Rect :: struct #ordered {
-	left:   i32,
-	top:    i32,
-	right:  i32,
-	bottom: i32,
+	left:   i32;
+	top:    i32;
+	right:  i32;
+	bottom: i32;
 }
 
 Filetime :: struct #ordered {
-	lo, hi: u32,
+	lo, hi: u32;
 }
 
 Systemtime :: struct #ordered {
-	year, month: u16,
-	day_of_week, day: u16,
-	hour, minute, second, millisecond: u16,
+	year, month: u16;
+	day_of_week, day: u16;
+	hour, minute, second, millisecond: u16;
 }
 
 ByHandleFileInformation :: struct #ordered {
-	file_attributes:      u32,
+	file_attributes:      u32;
 	creation_time,
 	last_access_time,
-	last_write_time:      Filetime,
+	last_write_time:      Filetime;
 	volume_serial_number,
 	file_size_high,
 	file_size_low,
 	number_of_links,
 	file_index_high,
-	file_index_low:       u32,
+	file_index_low:       u32;
 }
 
 FileAttributeData :: struct #ordered {
-	file_attributes:  u32,
+	file_attributes:  u32;
 	creation_time,
 	last_access_time,
-	last_write_time:  Filetime,
+	last_write_time:  Filetime;
 	file_size_high,
-	file_size_low:    u32,
+	file_size_low:    u32;
 }
 
 FindData :: struct #ordered {
-    file_attributes:     u32,
-    creation_time:       Filetime,
-    last_access_time:    Filetime,
-    last_write_time:     Filetime,
-    file_size_high:      u32,
-    file_size_low:       u32,
-    reserved0:           u32,
-    reserved1:           u32,
-    file_name:           [MAX_PATH]u8,
-    alternate_file_name: [14]u8,
+    file_attributes:     u32;
+    creation_time:       Filetime;
+    last_access_time:    Filetime;
+    last_write_time:     Filetime;
+    file_size_high:      u32;
+    file_size_low:       u32;
+    reserved0:           u32;
+    reserved1:           u32;
+    file_name:           [MAX_PATH]u8;
+    alternate_file_name: [14]u8;
 }
 
 SecurityAttributes :: struct #ordered {
-	length:              u32,
-	security_descriptor: rawptr,
-	inherit_handle:      Bool,
+	length:              u32;
+	security_descriptor: rawptr;
+	inherit_handle:      Bool;
 }
 
 
@@ -114,7 +114,7 @@ SecurityAttributes :: struct #ordered {
 PixelFormatDescriptor :: struct #ordered {
 	size,
 	version,
-	flags: u32,
+	flags: u32;
 
 	pixel_type,
 	color_bits,
@@ -135,33 +135,33 @@ PixelFormatDescriptor :: struct #ordered {
 	stencil_bits,
 	aux_buffers,
 	layer_type,
-	reserved: u8,
+	reserved: u8;
 
 	layer_mask,
 	visible_mask,
-	damage_mask: u32,
+	damage_mask: u32;
 }
 
 CriticalSection :: struct #ordered {
-	debug_info:      ^CriticalSectionDebug,
+	debug_info:      ^CriticalSectionDebug;
 
-	lock_count:      i32,
-	recursion_count: i32,
-	owning_thread:   Handle,
-	lock_semaphore:  Handle,
-	spin_count:      ^u32,
+	lock_count:      i32;
+	recursion_count: i32;
+	owning_thread:   Handle;
+	lock_semaphore:  Handle;
+	spin_count:      ^u32;
 }
 
 CriticalSectionDebug :: struct #ordered {
-	typ:                           u16,
-	creator_back_trace_index:      u16,
-	critical_section:              ^CriticalSection,
-	process_locks_list:            ^ListEntry,
-	entry_count:                   u32,
-	contention_count:              u32,
-	flags:                         u32,
-	creator_back_trace_index_high: u16,
-	spare_word:                    u16,
+	typ:                           u16;
+	creator_back_trace_index:      u16;
+	critical_section:              ^CriticalSection;
+	process_locks_list:            ^ListEntry;
+	entry_count:                   u32;
+	contention_count:              u32;
+	flags:                         u32;
+	creator_back_trace_index_high: u16;
+	spare_word:                    u16;
 }
 
 ListEntry :: struct #ordered {flink, blink: ^ListEntry};
@@ -546,35 +546,35 @@ FILE_TYPE_PIPE :: 0x0003;
 
 
 MonitorInfo :: struct #ordered {
-	size:      u32,
-	monitor:   Rect,
-	work:      Rect,
-	flags:     u32,
+	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,
+	length:     u32;
+	flags:      u32;
+	show_cmd:   u32;
+	min_pos:    Point;
+	max_pos:    Point;
+	normal_pos: Rect;
 }
 
 BitmapInfoHeader :: struct #ordered {
-	size:              u32,
-	width, height:     i32,
-	planes, bit_count: i16,
-	compression:       u32,
-	size_image:        u32,
-	x_pels_per_meter:  i32,
-	y_pels_per_meter:  i32,
-	clr_used:          u32,
-	clr_important:     u32,
+	size:              u32;
+	width, height:     i32;
+	planes, bit_count: i16;
+	compression:       u32;
+	size_image:        u32;
+	x_pels_per_meter:  i32;
+	y_pels_per_meter:  i32;
+	clr_used:          u32;
+	clr_important:     u32;
 }
 BitmapInfo :: struct #ordered {
-	using header: BitmapInfoHeader,
-	colors:       [1]RgbQuad,
+	using header: BitmapInfoHeader;
+	colors:       [1]RgbQuad;
 }
 
 

+ 129 - 10
src/parser.cpp

@@ -3354,6 +3354,123 @@ bool parse_expect_field_separator(AstFile *f, AstNode *param) {
 	return false;
 }
 
+bool parse_expect_struct_separator(AstFile *f, AstNode *param) {
+	Token token = f->curr_token;
+	if (allow_token(f, Token_Semicolon)) {
+		return true;
+	}
+
+	if (token.kind == Token_Colon) {
+		next_token(f);
+		error(f->curr_token, "Expected a semicolon, got a comma");
+		return true;
+	}
+
+	if (token.kind == Token_CloseBrace) {
+		if (token.pos.line == f->prev_token.pos.line) {
+			return true;
+		}
+	}
+	expect_token_after(f, Token_Semicolon, "field list");
+
+	return false;
+}
+
+
+AstNode *parse_struct_field_list(AstFile *f, isize *name_count_) {
+	CommentGroup docs = f->lead_comment;
+	Token start_token = f->curr_token;
+
+	Array<AstNode *> params = make_ast_node_array(f);
+	Array<AstNodeAndFlags> list = {}; array_init(&list, heap_allocator());
+	defer (array_free(&list));
+
+	isize total_name_count = 0;
+
+	while (f->curr_token.kind != Token_CloseBrace &&
+	       f->curr_token.kind != Token_Colon &&
+	       f->curr_token.kind != Token_EOF) {
+		u32 flags = parse_field_prefixes(f);
+		AstNode *param = parse_var_type(f, false, false);
+		AstNodeAndFlags naf = {param, flags};
+		array_add(&list, naf);
+		if (f->curr_token.kind != Token_Comma) {
+			break;
+		}
+		next_token(f);
+	}
+
+	if (f->curr_token.kind == Token_Colon) {
+		Array<AstNode *> names = convert_to_ident_list(f, list, true); // Copy for semantic reasons
+		if (names.count == 0) {
+			syntax_error(f->curr_token, "Empty field declaration");
+		}
+		u32 set_flags = 0;
+		if (list.count > 0) {
+			set_flags = list[0].flags;
+		}
+		set_flags = check_field_prefixes(f, names.count, FieldFlag_using, set_flags);
+		total_name_count += names.count;
+
+		AstNode *type = nullptr;
+
+		expect_token_after(f, Token_Colon, "field list");
+		type = parse_var_type(f, false, false);
+
+		parse_expect_struct_separator(f, type);
+		AstNode *param = ast_field(f, names, type, nullptr, set_flags, docs, f->line_comment);
+		array_add(&params, param);
+
+
+		while (f->curr_token.kind != Token_CloseBrace &&
+		       f->curr_token.kind != Token_EOF) {
+			CommentGroup docs = f->lead_comment;
+
+			u32 set_flags = parse_field_prefixes(f);
+			Array<AstNode *> names = parse_ident_list(f);
+			if (names.count == 0) {
+				syntax_error(f->curr_token, "Empty field declaration");
+				break;
+			}
+			set_flags = check_field_prefixes(f, names.count, FieldFlag_using, set_flags);
+			total_name_count += names.count;
+
+			AstNode *type = nullptr;
+
+			expect_token_after(f, Token_Colon, "field list");
+			type = parse_var_type(f, false, false);
+
+			bool ok = parse_expect_struct_separator(f, param);
+			AstNode *param = ast_field(f, names, type, nullptr, set_flags, docs, f->line_comment);
+			array_add(&params, param);
+
+			if (!ok) {
+				break;
+			}
+		}
+
+		if (name_count_) *name_count_ = total_name_count;
+		return ast_field_list(f, start_token, params);
+	}
+
+	for_array(i, list) {
+		Array<AstNode *> names = {};
+		AstNode *type = list[i].node;
+		Token token = blank_token;
+
+		array_init_count(&names, heap_allocator(), 1);
+		token.pos = ast_node_token(type).pos;
+		names[0] = ast_ident(f, token);
+		u32 flags = check_field_prefixes(f, list.count, FieldFlag_using, list[i].flags);
+
+		AstNode *param = ast_field(f, names, list[i].node, nullptr, flags, docs, f->line_comment);
+		array_add(&params, param);
+	}
+
+	if (name_count_) *name_count_ = total_name_count;
+	return ast_field_list(f, start_token, params);
+}
+
 AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow, bool allow_default_parameters) {
 	TokenKind separator = Token_Comma;
 	Token start_token = f->curr_token;
@@ -3629,9 +3746,10 @@ AstNode *parse_type_or_ident(AstFile *f) {
 		}
 
 		Token open = expect_token_after(f, Token_OpenBrace, "struct");
-		isize decl_count = 0;
-		AstNode *fields = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("struct"));
-		Token close = expect_token(f, Token_CloseBrace);
+
+		isize    name_count = 0;
+		AstNode *fields     = parse_struct_field_list(f, &name_count);
+		Token    close      = expect_token(f, Token_CloseBrace);
 
 		Array<AstNode *> decls = {};
 		if (fields != nullptr) {
@@ -3639,7 +3757,7 @@ AstNode *parse_type_or_ident(AstFile *f) {
 			decls = fields->FieldList.list;
 		}
 
-		return ast_struct_type(f, token, decls, decl_count, is_packed, is_ordered, align);
+		return ast_struct_type(f, token, decls, name_count, is_packed, is_ordered, align);
 	} break;
 
 	case Token_union: {
@@ -3678,16 +3796,16 @@ AstNode *parse_type_or_ident(AstFile *f) {
 					AstNode *name  = names[0];
 					Token    open  = expect_token(f, Token_OpenBrace);
 					isize decl_count = 0;
-					AstNode *list  = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("union"));
+					AstNode *list = parse_struct_field_list(f, &decl_count);
+					// AstNode *list  = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("union"));
 					Token    close = expect_token(f, Token_CloseBrace);
 
 					array_add(&variants, ast_union_field(f, name, list));
 				}
 			}
-			if (f->curr_token.kind != Token_Comma) {
+			if (!parse_expect_struct_separator(f, nullptr)) {
 				break;
 			}
-			next_token(f);
 		}
 
 		Token close = expect_token(f, Token_CloseBrace);
@@ -3699,9 +3817,10 @@ AstNode *parse_type_or_ident(AstFile *f) {
 	case Token_raw_union: {
 		Token token = expect_token(f, Token_raw_union);
 		Token open = expect_token_after(f, Token_OpenBrace, "raw_union");
-		isize decl_count = 0;
-		AstNode *fields = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("raw_union"));
-		Token close = expect_token(f, Token_CloseBrace);
+
+		isize    decl_count = 0;
+		AstNode *fields     = parse_struct_field_list(f, &decl_count);
+		Token    close      = expect_token(f, Token_CloseBrace);
 
 		Array<AstNode *> decls = {};
 		if (fields != nullptr) {