mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-31 11:50:07 +00:00
Merge branch 'master' of https://github.com/odin-lang/Odin
This commit is contained in:
@@ -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_Named: base = i.base
|
||||||
case Type_Info_Enum: 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
@@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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_datetime :: proc "contextless" (datetime: DateTime) -> (err: Error) {
|
||||||
validate(date) or_return
|
validate(datetime.date) or_return
|
||||||
validate(time) 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
@@ -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
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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))
|
||||||
|
}
|
||||||
|
|||||||
Vendored
+4
-4
@@ -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:] {
|
for arg, arg_index in args[num_ret:] {
|
||||||
if i > 0 { fmt.printf(", ") }
|
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] {
|
for arg, arg_index in args[1:num_ret] {
|
||||||
if i > 0 { fmt.printf(", ") }
|
if arg_index > 0 { fmt.printf(", ") }
|
||||||
fmt.printf("%v", arg)
|
fmt.printf("%v", arg)
|
||||||
}
|
}
|
||||||
fmt.printf(")\n")
|
fmt.printf(")\n")
|
||||||
|
|||||||
Reference in New Issue
Block a user