Browse Source

Merge branch 'master' of https://github.com/odin-lang/Odin

gingerBill 1 year ago
parent
commit
97e2d8916a

+ 3 - 2
base/runtime/core.odin

@@ -597,8 +597,9 @@ type_info_core :: proc "contextless" (info: ^Type_Info) -> ^Type_Info {
 	base := info
 	base := info
 	loop: for {
 	loop: for {
 		#partial switch i in base.variant {
 		#partial switch i in base.variant {
-		case Type_Info_Named:  base = i.base
-		case Type_Info_Enum:   base = i.base
+		case Type_Info_Named:     base = i.base
+		case Type_Info_Enum:      base = i.base
+		case Type_Info_Bit_Field: base = i.backing_type
 		case: break loop
 		case: break loop
 		}
 		}
 	}
 	}

+ 21 - 1
core/odin/ast/ast.odin

@@ -617,7 +617,7 @@ field_flag_strings := [Field_Flag]string{
 	.Any_Int            = "#any_int",
 	.Any_Int            = "#any_int",
 	.Subtype            = "#subtype",
 	.Subtype            = "#subtype",
 	.By_Ptr             = "#by_ptr",
 	.By_Ptr             = "#by_ptr",
-	.No_Broadcast       ="#no_broadcast",
+	.No_Broadcast       = "#no_broadcast",
 
 
 	.Results            = "results",
 	.Results            = "results",
 	.Tags               = "field tag",
 	.Tags               = "field tag",
@@ -842,6 +842,23 @@ Matrix_Type :: struct {
 	elem:         ^Expr,
 	elem:         ^Expr,
 }
 }
 
 
+Bit_Field_Type :: struct {
+	using node:   Expr,
+	tok_pos:      tokenizer.Pos,
+	backing_type: ^Expr,
+	open:         tokenizer.Pos,
+	fields:       []^Bit_Field_Field,
+	close:        tokenizer.Pos,
+}
+
+Bit_Field_Field :: struct {
+	using node: Node,
+	docs:       ^Comment_Group,
+	name:       ^Expr,
+	type:       ^Expr,
+	bit_size:   ^Expr,
+	comments:   ^Comment_Group,
+}
 
 
 Any_Node :: union {
 Any_Node :: union {
 	^Package,
 	^Package,
@@ -898,6 +915,7 @@ Any_Node :: union {
 	^Map_Type,
 	^Map_Type,
 	^Relative_Type,
 	^Relative_Type,
 	^Matrix_Type,
 	^Matrix_Type,
+	^Bit_Field_Type,
 
 
 	^Bad_Stmt,
 	^Bad_Stmt,
 	^Empty_Stmt,
 	^Empty_Stmt,
@@ -928,6 +946,7 @@ Any_Node :: union {
 	^Attribute,
 	^Attribute,
 	^Field,
 	^Field,
 	^Field_List,
 	^Field_List,
+	^Bit_Field_Field,
 }
 }
 
 
 
 
@@ -982,6 +1001,7 @@ Any_Expr :: union {
 	^Map_Type,
 	^Map_Type,
 	^Relative_Type,
 	^Relative_Type,
 	^Matrix_Type,
 	^Matrix_Type,
+	^Bit_Field_Type,
 }
 }
 
 
 
 

+ 7 - 0
core/odin/ast/clone.odin

@@ -336,6 +336,13 @@ clone_node :: proc(node: ^Node) -> ^Node {
 		case ^Relative_Type:
 		case ^Relative_Type:
 			r.tag = clone(r.tag)
 			r.tag = clone(r.tag)
 			r.type = clone(r.type)
 			r.type = clone(r.type)
+		case ^Bit_Field_Type:
+			r.backing_type = clone(r.backing_type)
+			r.fields       = auto_cast clone(r.fields)
+		case ^Bit_Field_Field:
+			r.name     = clone(r.name)
+			r.type     = clone(r.type)
+			r.bit_size = clone(r.bit_size)
 		case:
 		case:
 			fmt.panicf("Unhandled node kind: %v", r)
 			fmt.panicf("Unhandled node kind: %v", r)
 		}
 		}

+ 9 - 1
core/odin/ast/walk.odin

@@ -414,7 +414,15 @@ walk :: proc(v: ^Visitor, node: ^Node) {
 		walk(v, n.row_count)
 		walk(v, n.row_count)
 		walk(v, n.column_count)
 		walk(v, n.column_count)
 		walk(v, n.elem)
 		walk(v, n.elem)
-
+	case ^Bit_Field_Type:
+		walk(v, n.backing_type)
+		for f in n.fields {
+			walk(v, f)
+		}
+	case ^Bit_Field_Field:
+		walk(v, n.name)
+		walk(v, n.type)
+		walk(v, n.bit_size)
 	case:
 	case:
 		fmt.panicf("ast.walk: unexpected node type %T", n)
 		fmt.panicf("ast.walk: unexpected node type %T", n)
 	}
 	}

+ 45 - 2
core/odin/parser/parser.odin

@@ -531,7 +531,7 @@ is_semicolon_optional_for_node :: proc(p: ^Parser, node: ^ast.Node) -> bool {
 		return is_semicolon_optional_for_node(p, n.type)
 		return is_semicolon_optional_for_node(p, n.type)
 	case ^ast.Pointer_Type:
 	case ^ast.Pointer_Type:
 		return is_semicolon_optional_for_node(p, n.elem)
 		return is_semicolon_optional_for_node(p, n.elem)
-	case ^ast.Struct_Type, ^ast.Union_Type, ^ast.Enum_Type:
+	case ^ast.Struct_Type, ^ast.Union_Type, ^ast.Enum_Type, ^ast.Bit_Set_Type, ^ast.Bit_Field_Type:
 		// Require semicolon within a procedure body
 		// Require semicolon within a procedure body
 		return p.curr_proc == nil
 		return p.curr_proc == nil
 	case ^ast.Proc_Lit:
 	case ^ast.Proc_Lit:
@@ -2790,6 +2790,48 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
 		mt.column_count = column_count
 		mt.column_count = column_count
 		mt.elem = elem
 		mt.elem = elem
 		return mt
 		return mt
+	
+	case .Bit_Field:
+		tok := expect_token(p, .Bit_Field)
+
+		backing_type := parse_type_or_ident(p)
+		if backing_type == nil {
+			token := advance_token(p)
+			error(p, token.pos, "Expected a backing type for a 'bit_field'")
+		}
+
+		skip_possible_newline_for_literal(p)
+		open := expect_token_after(p, .Open_Brace, "bit_field")
+
+		fields: [dynamic]^ast.Bit_Field_Field
+		for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .EOF {
+			name := parse_ident(p)
+			expect_token(p, .Colon)
+			type := parse_type(p)
+			expect_token(p, .Or)
+			bit_size := parse_expr(p, true)
+
+			field := ast.new(ast.Bit_Field_Field, name.pos, bit_size)
+
+			field.name     = name
+			field.type     = type
+			field.bit_size = bit_size
+
+			append(&fields, field)
+
+			allow_token(p, .Comma) or_break
+		}
+
+		close := expect_closing_brace_of_field_list(p)
+
+		bf := ast.new(ast.Bit_Field_Type, tok.pos, close.pos)
+
+		bf.tok_pos      = tok.pos
+		bf.backing_type = backing_type
+		bf.open         = open.pos
+		bf.fields       = fields[:]
+		bf.close        = close.pos
+		return bf
 
 
 	case .Asm:
 	case .Asm:
 		tok := expect_token(p, .Asm)
 		tok := expect_token(p, .Asm)
@@ -2897,7 +2939,8 @@ is_literal_type :: proc(expr: ^ast.Expr) -> bool {
 		^ast.Map_Type,
 		^ast.Map_Type,
 		^ast.Bit_Set_Type,
 		^ast.Bit_Set_Type,
 		^ast.Matrix_Type,
 		^ast.Matrix_Type,
-		^ast.Call_Expr:
+		^ast.Call_Expr,
+		^ast.Bit_Field_Type:
 		return true
 		return true
 	}
 	}
 	return false
 	return false

+ 51 - 1
core/odin/printer/visit.odin

@@ -445,7 +445,7 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) {
 
 
 		for value in v.values {
 		for value in v.values {
 			#partial switch a in value.derived {
 			#partial switch a in value.derived {
-			case ^ast.Union_Type, ^ast.Enum_Type, ^ast.Struct_Type:
+			case ^ast.Union_Type, ^ast.Enum_Type, ^ast.Struct_Type, ^ast.Bit_Field_Type:
 				add_semicolon = false || called_in_stmt
 				add_semicolon = false || called_in_stmt
 			case ^ast.Proc_Lit:
 			case ^ast.Proc_Lit:
 				add_semicolon = false
 				add_semicolon = false
@@ -488,6 +488,37 @@ visit_exprs :: proc(p: ^Printer, list: []^ast.Expr, options := List_Options{}) {
 	}
 	}
 }
 }
 
 
+@(private)
+visit_bit_field_fields :: proc(p: ^Printer, list: []^ast.Bit_Field_Field, options := List_Options{}) {
+	if len(list) == 0 {
+		return
+	}
+
+	// we have to newline the expressions to respect the source
+	for v, i in list {
+		// Don't move the first expression, it looks bad
+		if i != 0 && .Enforce_Newline in options {
+			newline_position(p, 1)
+		} else if i != 0 {
+			move_line_limit(p, v.pos, 1)
+		}
+
+		visit_expr(p, v.name, options)
+		push_generic_token(p, .Colon, 0)
+		visit_expr(p, v.type, options)
+		push_generic_token(p, .Or, 1)
+		visit_expr(p, v.bit_size, options)
+
+		if (i != len(list) - 1 || .Trailing in options) && .Add_Comma in options {
+			push_generic_token(p, .Comma, 0)
+		}
+	}
+
+	if len(list) > 1 && .Enforce_Newline in options {
+		newline_position(p, 1)
+	}
+}
+
 @(private)
 @(private)
 visit_attributes :: proc(p: ^Printer, attributes: [dynamic]^ast.Attribute) {
 visit_attributes :: proc(p: ^Printer, attributes: [dynamic]^ast.Attribute) {
 	if len(attributes) == 0 {
 	if len(attributes) == 0 {
@@ -1293,6 +1324,25 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
 		visit_expr(p, v.column_count)
 		visit_expr(p, v.column_count)
 		push_generic_token(p, .Close_Bracket, 0)
 		push_generic_token(p, .Close_Bracket, 0)
 		visit_expr(p, v.elem)
 		visit_expr(p, v.elem)
+	case ^ast.Bit_Field_Type:
+		push_generic_token(p, .Bit_Field, 1)
+
+		visit_expr(p, v.backing_type)
+
+		if len(v.fields) == 0 || v.pos.line == v.close.line {
+			push_generic_token(p, .Open_Brace, 1)
+			visit_bit_field_fields(p, v.fields, {.Add_Comma})
+			push_generic_token(p, .Close_Brace, 0)
+		} else {
+			visit_begin_brace(p, v.pos, .Generic, len(v.fields))
+			newline_position(p, 1)
+			set_source_position(p, v.fields[0].pos)
+			visit_bit_field_fields(p, v.fields, {.Add_Comma, .Trailing, .Enforce_Newline})
+			set_source_position(p, v.close)
+			visit_end_brace(p, v.close)
+		}
+
+		set_source_position(p, v.close)
 	case:
 	case:
 		panic(fmt.aprint(expr.derived))
 		panic(fmt.aprint(expr.derived))
 	}
 	}

+ 7 - 1
core/sys/windows/types.odin

@@ -2074,7 +2074,13 @@ SRWLOCK_INIT :: SRWLOCK{}
 STARTF_USESTDHANDLES: DWORD : 0x00000100
 STARTF_USESTDHANDLES: DWORD : 0x00000100
 
 
 VOLUME_NAME_DOS: DWORD : 0x0
 VOLUME_NAME_DOS: DWORD : 0x0
-MOVEFILE_REPLACE_EXISTING: DWORD : 1
+
+MOVEFILE_COPY_ALLOWED: DWORD: 0x2
+MOVEFILE_CREATE_HARDLINK: DWORD: 0x10
+MOVEFILE_DELAY_UNTIL_REBOOT: DWORD: 0x4
+MOVEFILE_FAIL_IF_NOT_TRACKABLE: DWORD: 0x20
+MOVEFILE_REPLACE_EXISTING: DWORD : 0x1
+MOVEFILE_WRITE_THROUGH: DWORD: 0x8
 
 
 FILE_BEGIN: DWORD : 0
 FILE_BEGIN: DWORD : 0
 FILE_CURRENT: DWORD : 1
 FILE_CURRENT: DWORD : 1

+ 4 - 4
core/time/datetime/validation.odin

@@ -56,9 +56,9 @@ validate_hour_minute_second :: proc "contextless" (#any_int hour, #any_int minut
 	return .None
 	return .None
 }
 }
 
 
-validate_datetime :: proc "contextless" (using datetime: DateTime) -> (err: Error) {
-	validate(date) or_return
-	validate(time) or_return
+validate_datetime :: proc "contextless" (datetime: DateTime) -> (err: Error) {
+	validate(datetime.date) or_return
+	validate(datetime.time) or_return
 	return .None
 	return .None
 }
 }
 
 
@@ -69,4 +69,4 @@ validate :: proc{
 	validate_hour_minute_second,
 	validate_hour_minute_second,
 	validate_time,
 	validate_time,
 	validate_datetime,
 	validate_datetime,
-}
+}

+ 1 - 1
src/check_type.cpp

@@ -1689,7 +1689,7 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para
 		bool is_using = (p->flags&FieldFlag_using) != 0;
 		bool is_using = (p->flags&FieldFlag_using) != 0;
 		if ((check_vet_flags(param) & VetFlag_UsingParam) && is_using) {
 		if ((check_vet_flags(param) & VetFlag_UsingParam) && is_using) {
 			ERROR_BLOCK();
 			ERROR_BLOCK();
-			error(param, "'using' on a procedure parameter is now allowed when '-vet' or '-vet-using-param' is applied");
+			error(param, "'using' on a procedure parameter is not allowed when '-vet' or '-vet-using-param' is applied");
 			error_line("\t'using' is considered bad practice to use as a statement/procedure parameter outside of immediate refactoring\n");
 			error_line("\t'using' is considered bad practice to use as a statement/procedure parameter outside of immediate refactoring\n");
 
 
 		}
 		}

+ 1 - 1
src/linker.cpp

@@ -384,7 +384,7 @@ gb_internal i32 linker_stage(LinkerData *gen) {
 								LIT(obj_file),
 								LIT(obj_file),
 								LIT(build_context.extra_assembler_flags)
 								LIT(build_context.extra_assembler_flags)
 							);						
 							);						
-							if (!result) {
+							if (result) {
 								gb_printf_err("executing `nasm` to assemble foreing import of %.*s failed.\n\tSuggestion: `nasm` does not ship with the compiler and should be installed with your system's package manager.\n", LIT(asm_file));
 								gb_printf_err("executing `nasm` to assemble foreing import of %.*s failed.\n\tSuggestion: `nasm` does not ship with the compiler and should be installed with your system's package manager.\n", LIT(asm_file));
 								return result;
 								return result;
 							}
 							}

+ 47 - 3
tests/core/odin/test_parser.odin

@@ -1,9 +1,12 @@
 package test_core_odin_parser
 package test_core_odin_parser
 
 
-import "core:testing"
 import "core:fmt"
 import "core:fmt"
-import "core:os"
+import "core:odin/ast"
 import "core:odin/parser"
 import "core:odin/parser"
+import "core:odin/printer"
+import "core:os"
+import "core:strings"
+import "core:testing"
 
 
 
 
 TEST_count := 0
 TEST_count := 0
@@ -30,6 +33,7 @@ when ODIN_TEST {
 main :: proc() {
 main :: proc() {
 	t := testing.T{}
 	t := testing.T{}
 	test_parse_demo(&t)
 	test_parse_demo(&t)
+	test_parse_bitfield(&t)
 
 
 	fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
 	fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
 	if TEST_fail > 0 {
 	if TEST_fail > 0 {
@@ -47,4 +51,44 @@ test_parse_demo :: proc(t: ^testing.T) {
 	for key, value in pkg.files {
 	for key, value in pkg.files {
 		expect(t, value.syntax_error_count == 0, fmt.tprintf("%v should contain zero errors", key))
 		expect(t, value.syntax_error_count == 0, fmt.tprintf("%v should contain zero errors", key))
 	}
 	}
-}
+}
+
+@test
+test_parse_bitfield :: proc(t: ^testing.T) {
+	file := ast.File{
+		fullpath = "test.odin",
+		src = `
+package main
+
+Foo :: bit_field uint {}
+
+Foo :: bit_field uint {hello: bool | 1}
+
+Foo :: bit_field uint {
+	hello: bool | 1,
+	hello: bool | 5,
+}
+
+// Hellope 1.
+Foo :: bit_field uint {
+	// Hellope 2.
+	hello: bool | 1,
+	hello: bool | 5, // Hellope 3.
+}
+		`,
+	}
+
+	p := parser.default_parser()
+	ok := parser.parse_file(&p, &file)
+	expect(t, ok == true, "bad parse")
+
+	cfg := printer.default_style
+	cfg.newline_style = .LF
+	print := printer.make_printer(cfg)
+	out := printer.print(&print, &file)
+
+	tsrc := strings.trim_space(file.src)
+	tout := strings.trim_space(out)
+
+	expect(t, tsrc == tout, fmt.tprintf("\n%s\n!=\n%s", tsrc, tout))
+}

+ 4 - 4
vendor/OpenGL/wrappers.odin

@@ -787,8 +787,8 @@ when !GL_DEBUG {
 			fmt.printf("   call: gl%s(", loc.procedure)
 			fmt.printf("   call: gl%s(", loc.procedure)
 			{
 			{
 				// add input arguments
 				// add input arguments
-				for arg, i in args[num_ret:] {
-				if i > 0 { fmt.printf(", ") }
+				for arg, arg_index in args[num_ret:] {
+				if arg_index > 0 { fmt.printf(", ") }
 
 
 				if v, ok := arg.(u32); ok { // TODO: Assumes all u32 are GLenum (they're not, GLbitfield and GLuint are also mapped to u32), fix later by better typing
 				if v, ok := arg.(u32); ok { // TODO: Assumes all u32 are GLenum (they're not, GLbitfield and GLuint are also mapped to u32), fix later by better typing
 					if err == .INVALID_ENUM {
 					if err == .INVALID_ENUM {
@@ -806,8 +806,8 @@ when !GL_DEBUG {
 					fmt.printf(") -> %v \n", args[0])
 					fmt.printf(") -> %v \n", args[0])
 				} else if num_ret > 1 {
 				} else if num_ret > 1 {
 					fmt.printf(") -> (")
 					fmt.printf(") -> (")
-					for arg, i in args[1:num_ret] {
-						if i > 0 { fmt.printf(", ") }
+					for arg, arg_index in args[1:num_ret] {
+						if arg_index > 0 { fmt.printf(", ") }
 						fmt.printf("%v", arg)
 						fmt.printf("%v", arg)
 					}
 					}
 					fmt.printf(")\n")
 					fmt.printf(")\n")