This commit is contained in:
gingerBill
2024-04-10 12:32:32 +01:00
12 changed files with 200 additions and 21 deletions

View File

@@ -597,8 +597,9 @@ type_info_core :: proc "contextless" (info: ^Type_Info) -> ^Type_Info {
base := info
loop: for {
#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
}
}

View File

@@ -617,7 +617,7 @@ field_flag_strings := [Field_Flag]string{
.Any_Int = "#any_int",
.Subtype = "#subtype",
.By_Ptr = "#by_ptr",
.No_Broadcast ="#no_broadcast",
.No_Broadcast = "#no_broadcast",
.Results = "results",
.Tags = "field tag",
@@ -842,6 +842,23 @@ Matrix_Type :: struct {
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 {
^Package,
@@ -898,6 +915,7 @@ Any_Node :: union {
^Map_Type,
^Relative_Type,
^Matrix_Type,
^Bit_Field_Type,
^Bad_Stmt,
^Empty_Stmt,
@@ -928,6 +946,7 @@ Any_Node :: union {
^Attribute,
^Field,
^Field_List,
^Bit_Field_Field,
}
@@ -982,6 +1001,7 @@ Any_Expr :: union {
^Map_Type,
^Relative_Type,
^Matrix_Type,
^Bit_Field_Type,
}

View File

@@ -336,6 +336,13 @@ clone_node :: proc(node: ^Node) -> ^Node {
case ^Relative_Type:
r.tag = clone(r.tag)
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:
fmt.panicf("Unhandled node kind: %v", r)
}

View File

@@ -414,7 +414,15 @@ walk :: proc(v: ^Visitor, node: ^Node) {
walk(v, n.row_count)
walk(v, n.column_count)
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:
fmt.panicf("ast.walk: unexpected node type %T", n)
}

View File

@@ -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)
case ^ast.Pointer_Type:
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
return p.curr_proc == nil
case ^ast.Proc_Lit:
@@ -2790,6 +2790,48 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
mt.column_count = column_count
mt.elem = elem
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:
tok := expect_token(p, .Asm)
@@ -2897,7 +2939,8 @@ is_literal_type :: proc(expr: ^ast.Expr) -> bool {
^ast.Map_Type,
^ast.Bit_Set_Type,
^ast.Matrix_Type,
^ast.Call_Expr:
^ast.Call_Expr,
^ast.Bit_Field_Type:
return true
}
return false

View File

@@ -445,7 +445,7 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) {
for value in v.values {
#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
case ^ast.Proc_Lit:
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)
visit_attributes :: proc(p: ^Printer, attributes: [dynamic]^ast.Attribute) {
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)
push_generic_token(p, .Close_Bracket, 0)
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:
panic(fmt.aprint(expr.derived))
}

View File

@@ -2074,7 +2074,13 @@ SRWLOCK_INIT :: SRWLOCK{}
STARTF_USESTDHANDLES: DWORD : 0x00000100
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_CURRENT: DWORD : 1

View File

@@ -56,9 +56,9 @@ validate_hour_minute_second :: proc "contextless" (#any_int hour, #any_int minut
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
}
@@ -69,4 +69,4 @@ validate :: proc{
validate_hour_minute_second,
validate_time,
validate_datetime,
}
}

View File

@@ -1689,7 +1689,7 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para
bool is_using = (p->flags&FieldFlag_using) != 0;
if ((check_vet_flags(param) & VetFlag_UsingParam) && is_using) {
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");
}

View File

@@ -384,7 +384,7 @@ gb_internal i32 linker_stage(LinkerData *gen) {
LIT(obj_file),
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));
return result;
}

View File

@@ -1,9 +1,12 @@
package test_core_odin_parser
import "core:testing"
import "core:fmt"
import "core:os"
import "core:odin/ast"
import "core:odin/parser"
import "core:odin/printer"
import "core:os"
import "core:strings"
import "core:testing"
TEST_count := 0
@@ -30,6 +33,7 @@ when ODIN_TEST {
main :: proc() {
t := testing.T{}
test_parse_demo(&t)
test_parse_bitfield(&t)
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
if TEST_fail > 0 {
@@ -47,4 +51,44 @@ test_parse_demo :: proc(t: ^testing.T) {
for key, value in pkg.files {
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))
}

View File

@@ -787,8 +787,8 @@ when !GL_DEBUG {
fmt.printf(" call: gl%s(", loc.procedure)
{
// 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 err == .INVALID_ENUM {
@@ -806,8 +806,8 @@ when !GL_DEBUG {
fmt.printf(") -> %v \n", args[0])
} else if num_ret > 1 {
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(")\n")